summaryrefslogtreecommitdiffstats
path: root/vm/compiler
diff options
context:
space:
mode:
authorCarl Shapiro <cshapiro@google.com>2010-03-05 17:34:05 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2010-03-05 17:34:05 -0800
commit164d1279b67ec13061e473cb453b1ff24189e0e0 (patch)
tree53b2c969d71f4a322b90e72ab457c5b214b95cbf /vm/compiler
parentf8069e844054d29f320a9ece29fc638a884bbf69 (diff)
parent5d4bac4cf4474d789258e1a0d7d8aec80ea27ec5 (diff)
downloadandroid_dalvik-164d1279b67ec13061e473cb453b1ff24189e0e0.tar.gz
android_dalvik-164d1279b67ec13061e473cb453b1ff24189e0e0.tar.bz2
android_dalvik-164d1279b67ec13061e473cb453b1ff24189e0e0.zip
Merge "Jit: Fix for issue 2487769, Simplify in-line thin lock release"
Diffstat (limited to 'vm/compiler')
-rw-r--r--vm/compiler/codegen/arm/Thumb2/Gen.c143
1 files changed, 92 insertions, 51 deletions
diff --git a/vm/compiler/codegen/arm/Thumb2/Gen.c b/vm/compiler/codegen/arm/Thumb2/Gen.c
index 1a505efe2..b51cdd4bb 100644
--- a/vm/compiler/codegen/arm/Thumb2/Gen.c
+++ b/vm/compiler/codegen/arm/Thumb2/Gen.c
@@ -190,12 +190,14 @@ static ArmLIR *genExportPC(CompilationUnit *cUnit, MIR *mir)
* preserved.
*
*/
-static void genMonitor(CompilationUnit *cUnit, MIR *mir)
+static void genMonitorEnter(CompilationUnit *cUnit, MIR *mir)
{
RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
bool enter = (mir->dalvikInsn.opCode == OP_MONITOR_ENTER);
ArmLIR *target;
+ ArmLIR *hopTarget;
ArmLIR *branch;
+ ArmLIR *hopBranch;
assert(LW_SHAPE_THIN == 0);
loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj
@@ -208,67 +210,106 @@ static void genMonitor(CompilationUnit *cUnit, MIR *mir)
offsetof(Object, lock) >> 2); // Get object->lock
opRegImm(cUnit, kOpLsl, r3, LW_LOCK_OWNER_SHIFT); // Align owner
// Is lock unheld on lock or held by us (==threadId) on unlock?
- if (enter) {
- newLIR4(cUnit, kThumb2Bfi, r3, r2, 0, LW_LOCK_OWNER_SHIFT - 1);
- newLIR3(cUnit, kThumb2Bfc, r2, LW_HASH_STATE_SHIFT,
- LW_LOCK_OWNER_SHIFT - 1);
- opRegImm(cUnit, kOpCmp, r2, 0);
- } else {
- opRegRegImm(cUnit, kOpAnd, r7, r2,
- (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
- newLIR3(cUnit, kThumb2Bfc, r2, LW_HASH_STATE_SHIFT,
- LW_LOCK_OWNER_SHIFT - 1);
- opRegReg(cUnit, kOpSub, r2, r3);
- }
- // Note: start of IT block. If last sub result != clear, else strex
- genIT(cUnit, kArmCondNe, "E");
- newLIR0(cUnit, kThumb2Clrex);
- if (enter) {
- newLIR4(cUnit, kThumb2Strex, r2, r3, r1,
- offsetof(Object, lock) >> 2);
- } else {
- newLIR4(cUnit, kThumb2Strex, r2, r7, r1,
- offsetof(Object, lock) >> 2);
- }
- // Note: end of IT block
+ newLIR4(cUnit, kThumb2Bfi, r3, r2, 0, LW_LOCK_OWNER_SHIFT - 1);
+ newLIR3(cUnit, kThumb2Bfc, r2, LW_HASH_STATE_SHIFT,
+ LW_LOCK_OWNER_SHIFT - 1);
+ hopBranch = newLIR2(cUnit, kThumb2Cbnz, r2, 0);
+ newLIR4(cUnit, kThumb2Strex, r2, r3, r1, offsetof(Object, lock) >> 2);
branch = newLIR2(cUnit, kThumb2Cbz, r2, 0);
+ hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
+ hopTarget->defMask = ENCODE_ALL;
+ hopBranch->generic.target = (LIR *)hopTarget;
+
+ // Clear the lock
+ ArmLIR *inst = newLIR0(cUnit, kThumb2Clrex);
+ // ...and make it a scheduling barrier
+ inst->defMask = ENCODE_ALL;
+
// Export PC (part 1)
loadConstant(cUnit, r3, (int) (cUnit->method->insns + mir->offset));
- if (enter) {
- /* Get dPC of next insn */
- loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset +
+ /* 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);
- opRegImm(cUnit, kOpCmp, r0, 0); /* Did we throw? */
- ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
- loadConstant(cUnit, r0,
- (int) (cUnit->method->insns + mir->offset +
- dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_EXIT)));
- genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
- ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
- target->defMask = ENCODE_ALL;
- branchOver->generic.target = (LIR *) target;
- dvmCompilerClobberCallRegs(cUnit);
- }
+ // 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);
+ // Resume here
+ target = newLIR0(cUnit, kArmPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+ branch->generic.target = (LIR *)target;
+}
+
+/*
+ * For monitor unlock, we don't have to use ldrex/strex. Once
+ * we've determined that the lock is thin and that we own it with
+ * a zero recursion count, it's safe to punch it back to the
+ * initial, unlock thin state with a store word.
+ */
+static void genMonitorExit(CompilationUnit *cUnit, MIR *mir)
+{
+ RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
+ ArmLIR *target;
+ ArmLIR *branch;
+ ArmLIR *hopTarget;
+ ArmLIR *hopBranch;
+
+ assert(LW_SHAPE_THIN == 0);
+ loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj
+ dvmCompilerLockAllTemps(cUnit); // Prepare for explicit register usage
+ dvmCompilerFreeTemp(cUnit, r4PC); // Free up r4 for general use
+ loadWordDisp(cUnit, rGLUE, offsetof(InterpState, self), r0); // Get self
+ genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
+ loadWordDisp(cUnit, r1, offsetof(Object, lock), r2); // Get object->lock
+ loadWordDisp(cUnit, r0, offsetof(Thread, threadId), r3); // Get threadId
+ // Is lock unheld on lock or held by us (==threadId) on unlock?
+ opRegRegImm(cUnit, kOpAnd, r7, r2,
+ (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
+ opRegImm(cUnit, kOpLsl, r3, LW_LOCK_OWNER_SHIFT); // Align owner
+ newLIR3(cUnit, kThumb2Bfc, r2, LW_HASH_STATE_SHIFT,
+ LW_LOCK_OWNER_SHIFT - 1);
+ opRegReg(cUnit, kOpSub, r2, r3);
+ hopBranch = opCondBranch(cUnit, kArmCondNe);
+ storeWordDisp(cUnit, r1, offsetof(Object, lock), r7);
+ branch = opNone(cUnit, kOpUncondBr);
+
+ hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
+ hopTarget->defMask = ENCODE_ALL;
+ hopBranch->generic.target = (LIR *)hopTarget;
+
+ // Export PC (part 1)
+ loadConstant(cUnit, r3, (int) (cUnit->method->insns + mir->offset));
+
+ loadConstant(cUnit, r7, (int)dvmUnlockObject);
+ // Export PC (part 2)
+ newLIR3(cUnit, kThumb2StrRRI8Predec, r3, rFP,
+ sizeof(StackSaveArea) -
+ offsetof(StackSaveArea, xtra.currentPc));
+ opReg(cUnit, kOpBlx, r7);
+ opRegImm(cUnit, kOpCmp, r0, 0); /* Did we throw? */
+ ArmLIR *branchOver = opCondBranch(cUnit, kArmCondNe);
+ loadConstant(cUnit, r0,
+ (int) (cUnit->method->insns + mir->offset +
+ dexGetInstrWidthAbs(gDvm.instrWidth, OP_MONITOR_EXIT)));
+ genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
// Resume here
target = newLIR0(cUnit, kArmPseudoTargetLabel);
target->defMask = ENCODE_ALL;
branch->generic.target = (LIR *)target;
+ branchOver->generic.target = (LIR *) target;
+}
+
+static void genMonitor(CompilationUnit *cUnit, MIR *mir)
+{
+ if (mir->dalvikInsn.opCode == OP_MONITOR_ENTER)
+ genMonitorEnter(cUnit, mir);
+ else
+ genMonitorExit(cUnit, mir);
}
/*