Home | History | Annotate | Download | only in mterp
      1 Interpreter Notes
      2 
      3 
      4 ==== Thread suspension and GC points ====
      5 
      6 The interpreter is expected to use a safe-point mechanism to allow thread
      7 suspension for garbage collection and the debugger.  This typically
      8 means an explicit check of the thread-suspend flag on backward branches
      9 (including self-branches on certain instructions), exception throws,
     10 and method returns.  The interpreter must also be prepared to switch in
     11 and out of the "debug" interpreter at these points.
     12 
     13 There are other ways for a thread to be stopped when a GC happens, notably:
     14 
     15  - object allocation (either while executing an instruction that performs
     16    allocation, or indirectly by allocating an exception when something
     17    goes wrong)
     18  - transitions to native code or indefinite wait (e.g. monitor-enter)
     19 
     20 (A debugger can in theory cause the interpreter to advance one instruction
     21 at a time, but since that only happens in the "debug" interpreter it's not
     22 necessary for authors of platform-specific code to worry about it.)
     23 
     24 For the most part the implementation does not need to worry about these
     25 things, but they matter when considering the contents of Dalvik's virtual
     26 registers for "precise" garbage collection.  So, all opcode handlers must
     27 follow this rule:
     28 
     29  * Do not modify the contents of a virtual register before executing
     30    code that can pause the thread.
     31 
     32 This should be fairly hard to violate given the nature of essentially all
     33 instructions, which will compute a result and then finish by storing that
     34 result into the specified destination register.  Using a virtual register
     35 to hold a partial or temporary result is not allowed.  Virtual registers
     36 must not be modified if we abort the instruction with an exception.
     37 
     38 
     39 ==== Method results and GC ====
     40 
     41 The return value from a method is held in local storage (on the native
     42 stack for the portable interpreter, and in glue->retval for asm).  It's not
     43 accessible to a GC.  In practice this isn't a problem, because if the
     44 following instruction is not a "move-result" then the result is ignored,
     45 and none of the move-result* instructions are GC points.
     46 
     47 (This is potentially an issue when debugging, since we can theoretically
     48 single-step by individual bytecodes, but in practice we always step by
     49 source lines and move-result is grouped with the method invoke.)
     50 
     51 This suggests a rule:
     52 
     53  * Don't do anything that can cause a GC in the invoke-* handler after
     54    a method returns successfully.
     55 
     56 Unsuccessful returns, such as a native method call that returns with an
     57 exception pending, are not interesting because the return value is ignored.
     58 
     59 If it's not possible to obey this rule, then we need to track the value
     60 used in a return-object instruction for a brief period.  The easiest way
     61 to accomplish this is to store it in the interpreted stack where the GC
     62 can find it, and use a live-precise GC to ignore the value.
     63 
     64 The "trackref" functions can also be used, but they add overhead to method
     65 calls returning objects, and ensuring that we stop tracking the reference
     66 when it's no longer needed can be awkward.
     67 
     68 Any solution must work correctly when returning into or returning from native
     69 code.  JNI handles returns from interp->native by adding the value to the
     70 local references table, but returns from native->interp are simply stored
     71 in the usual "retval".
     72