diff options
author | Bill Buzbee <buzbee@google.com> | 2010-02-02 11:04:33 -0800 |
---|---|---|
committer | Bill Buzbee <buzbee@google.com> | 2010-02-03 14:47:49 -0800 |
commit | f5ceaebfe5633a16b11a7073d2bf36b5bb0c9945 (patch) | |
tree | 5502cdcbf8742846adeb33c060e57e9baa12ec44 /vm/compiler/codegen | |
parent | 5043da6f678448f6111d1a0dcc584f5adf01b526 (diff) | |
download | android_dalvik-f5ceaebfe5633a16b11a7073d2bf36b5bb0c9945.tar.gz android_dalvik-f5ceaebfe5633a16b11a7073d2bf36b5bb0c9945.tar.bz2 android_dalvik-f5ceaebfe5633a16b11a7073d2bf36b5bb0c9945.zip |
Jit: Rework monitor enter/exit to simplify thread suspension
The Jit must stop all threads in order to flush the translation cache (and
other tables). Threads which are blocked in a monitor wait cause some
headache here because they effectively hold a references to the translation
cache (though the return address on the native stack). The new model
introduced in this CL is that for the fast path of monitor enter, control
is allowed to resume in the translation cache. However, if we need to do a
heavyweight lock (which may cause us to block) control does not return to the
translation cache but instead bails out to the interpreter. This allows us to
safely clear the code cache even if some threads are in THREAD_MONITOR state.
Diffstat (limited to 'vm/compiler/codegen')
-rw-r--r-- | vm/compiler/codegen/arm/CodegenDriver.c | 53 | ||||
-rw-r--r-- | vm/compiler/codegen/arm/Thumb2/Gen.c | 32 |
2 files changed, 42 insertions, 43 deletions
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c index 648d8f4d6..5be07aa3d 100644 --- a/vm/compiler/codegen/arm/CodegenDriver.c +++ b/vm/compiler/codegen/arm/CodegenDriver.c @@ -1693,46 +1693,41 @@ static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir) opReg(cUnit, kOpBlx, r2); } +/* + * To prevent a thread in a monitor wait from blocking the Jit from + * resetting the code cache, heavyweight monitor lock will not + * be allowed to return to an existing translation. Instead, we will + * handle them by branching to a handler, which will in turn call the + * runtime lock routine and then branch directly back to the + * interpreter main loop. Given the high cost of the heavyweight + * lock operation, this additional cost should be slight (especially when + * considering that we expect the vast majority of lock operations to + * use the fast-path thin lock bypass). + */ static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir) { bool isEnter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER); - flushAllRegs(cUnit); /* Send everything to home location */ genExportPC(cUnit, mir); + flushAllRegs(cUnit); /* Send everything to home location */ RegLocation rlSrc = getSrcLoc(cUnit, mir, 0); loadValueDirectFixed(cUnit, rlSrc, r1); loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0); + genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL); if (isEnter) { - loadConstant(cUnit, r2, (int)dvmLockObject); + /* Get dPC of next insn */ + loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset + + dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_ENTER))); +#if defined(WITH_DEADLOCK_PREDICTION) + genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER_DEBUG); +#else + genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER); +#endif } else { loadConstant(cUnit, r2, (int)dvmUnlockObject); + /* Do the call */ + opReg(cUnit, kOpBlx, r2); + clobberCallRegs(cUnit); } - genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL); - /* Do the call */ - opReg(cUnit, kOpBlx, r2); - /* - * Refresh Jit's on/off status, which may have changed if we were - * sent to VM_MONITOR state above. - * TUNING: pointer chase, but must reload following call - */ - loadWordDisp(cUnit, rGLUE, offsetof(InterpState, ppJitProfTable), r0); - loadWordDisp(cUnit, r0, 0, r0); - storeWordDisp(cUnit, rGLUE, offsetof(InterpState, pJitProfTable), r0); -#if defined(WITH_DEADLOCK_PREDICTION) - if (isEnter) { - loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0); - loadWordDisp(cUnit, r0, offsetof(Thread, exception), r1); - opRegImm(cUnit, kOpCmp, r1, 0); - ArmLIR *branchOver = opCondBranch(cUnit, kArmCondEq); - loadConstant(cUnit, r0, - (int) (cUnit->method->insns + mir->offset)); - genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON); - /* noreturn */ - ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel); - target->defMask = ENCODE_ALL; - branchOver->generic.target = (LIR *) target; - } -#endif - clobberCallRegs(cUnit); } /* diff --git a/vm/compiler/codegen/arm/Thumb2/Gen.c b/vm/compiler/codegen/arm/Thumb2/Gen.c index 5f2a6a259..1f947c2ad 100644 --- a/vm/compiler/codegen/arm/Thumb2/Gen.c +++ b/vm/compiler/codegen/arm/Thumb2/Gen.c @@ -231,26 +231,30 @@ static void genMonitor(CompilationUnit *cUnit, MIR *mir) offsetof(Object, lock) >> 2); } // Note: end of IT block - branch = newLIR2(cUnit, kThumb2Cbz, r2, 0); + // Export PC (part 1) + loadConstant(cUnit, r3, (int) (cUnit->method->insns + mir->offset)); + if (enter) { - loadConstant(cUnit, r7, (int)dvmLockObject); + /* Get dPC of next insn */ + loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset + + dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_ENTER))); + // Export PC (part 2) + newLIR3(cUnit, kThumb2StrRRI8Predec, r3, rFP, + sizeof(StackSaveArea) - + offsetof(StackSaveArea, xtra.currentPc)); + /* Call template, and don't return */ + genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER); } else { loadConstant(cUnit, r7, (int)dvmUnlockObject); + // Export PC (part 2) + newLIR3(cUnit, kThumb2StrRRI8Predec, r3, rFP, + sizeof(StackSaveArea) - + offsetof(StackSaveArea, xtra.currentPc)); + opReg(cUnit, kOpBlx, r7); + clobberCallRegs(cUnit); } - genExportPC(cUnit, mir); - opReg(cUnit, kOpBlx, r7); - /* - * Refresh Jit's on/off status, which may have changed if we were - * sent to VM_MONITOR state above. - * TUNING: pointer chase, but must refresh following return from call - */ - loadWordDisp(cUnit, rGLUE, offsetof(InterpState, ppJitProfTable), r0); - loadWordDisp(cUnit, r0, 0, r0); - storeWordDisp(cUnit, rGLUE, offsetof(InterpState, pJitProfTable), r0); - - clobberCallRegs(cUnit); // Resume here target = newLIR0(cUnit, kArmPseudoTargetLabel); |