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