On Mon, Sep 20, 2010 at 3:16 PM, Talin <span dir="ltr"><<a href="mailto:viridia@gmail.com">viridia@gmail.com</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

So I've managed to get my stack crawler working and passing its unit tests - this is the one I've been working on as an alternative to shadow-stack: it uses only static constant data structures (no global variables or thread-local data), which means that it's fully compatible with a multi-threaded environment.<div>


<br></div><div>One question that has arisen, however, is what to do about function parameters that may be stack roots. You can't call llvm.gcroot() on a function parameter. The only thing I can think of is to copy any function parameter that is a pointer, or which contains a pointer, into a local variable. This seems complicated and inefficient to me (for one thing, it means that every stack frame just got 8 bytes bigger due to the need to store the 'this' pointer locally)  - is there a better way?<br clear="all">

</div></blockquote><div><br></div><div>Anyone?</div><div><br></div><div>Here's some examples of what I am talking about (I'll use Java for the examples):</div><div><br></div><div>Example 1: </div><div><br></div><div>

<font class="Apple-style-span" face="'courier new', monospace">  class Foo {</font></div><div><font class="Apple-style-span" face="'courier new', monospace">    static String st = "Hello";</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">    void f1() {</font></div><div><font class="Apple-style-span" face="'courier new', monospace">       f2(st);</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">    }</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">    void f2(String s) {</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">      st = null; // Destroy static root</font></div><div><font class="Apple-style-span" face="'courier new', monospace">      // Now allocate something, which might trigger</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">      // a garbage collection.</font></div><div><font class="Apple-style-span" face="'courier new', monospace">      StringBuffer sb = new StringBuffer();</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">      // Is 's' still live? It's not stored in any</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">      // alloca, or in any global variable. It only</font></div><div><font class="Apple-style-span" face="'courier new', monospace">      // exists as a function parameter, which cannot</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">      // be declared as a root via llvm.gcroot.</font></div><div><font class="Apple-style-span" face="'courier new', monospace">      sb.append(s);</font></div>

<div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">    }</span></div><div><font class="Apple-style-span" face="'courier new', monospace">  }</font></div><div><br></div><div>

<div>Example 2: </div></div><div><br></div><div><font class="Apple-style-span" face="'courier new', monospace">  class Foo {</font></div><div><font class="Apple-style-span" face="'courier new', monospace">    static void f1() {</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">      // Create a new 'Foo' but don't store it</font></div><div><font class="Apple-style-span" face="'courier new', monospace">      // anywhere.</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">      new Foo().f2();</font></div><div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">    }</span></div>
<div>
<font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">    void f2() {</font></div><div><font class="Apple-style-span" face="'courier new', monospace">      // Possibly trigger a collection</font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">      StringBuffer sb = new StringBuffer();</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div>

<div><font class="Apple-style-span" face="'courier new', monospace">      // Is 'this' still live at this point?</font></div><div><font class="Apple-style-span" face="'courier new', monospace">      sb.append(toString());</font></div>

<div><span class="Apple-style-span" style="font-family: 'courier new', monospace; ">    }</span></div><div><font class="Apple-style-span" face="'courier new', monospace">  }</font></div></div><div><br></div>

<div>Now, I know that the LLVM "Accurate GC" document says that any "intermediate values" must be declared as a GC root. My question is, does merely _loading_ a global variable - or any mutable, non-strictly-local variable for that matter - count as an "intermediate" value in this case?</div>

<div><br></div><div>My problem is that I can't see how to address this without generating horribly bloated and inefficient code. Pretty much every function argument that isn't a simple integer or float will have to be copied to a hidden local variable before every function call - in addition to copying it to the stack to create the call frame. Even local variables are not immune if you allow closures in your language. Under this scenario, calling conventions that pass arguments in registers are utterly futile and save nothing, because everything has to get copied to the stack anyway.</div>

<div><br></div><div>I really wish I could simply declare function arguments as llvm.gcroots. For arguments that are not in registers, it would treat it just like an alloca, since they both represent stack slots. For arguments that are passed in registers, LLVM should automatically lower it to a non-register argument, making a copy if needed. (I can't do this myself, since I'm not supposed to *know* which arguments are passed in registers or not - that depends on the target and the code generators and such).</div>

<div><br></div><div>That still leaves me with the problem of declaring as roots function arguments that are the result of complex calculations, but those are far fewer - declaring temporary vars for those won't bloat the code so badly. But having to copy every single load of a non-local variable into a temporary is a nightmare.</div>

<div><br></div>-- <br>-- Talin<br>