Emit volatile field access instructions.
Easier said than done. The trick is that we need to ensure that the
instruction replacement happens even if the verifier and optimizer
are not enabled in dexopt.
We're currently doing the -wide-volatile replacement during
verification, but that's not so great, since we collapse things like
iget-byte and iget-char into a single iget-volatile, losing the field
width. We could recover it from the field declaration, but doing it
during verification is really just sort of wrong to begin with.
The substitution isn't technically an "optimization", but it's easiest
to do it during the opt pass, and we already have a convenient "is
optimized" flag that helps ensure that we do the replacement pass
exactly once.
Optimizing at run time means making a private copy of shared pages,
because the pages are mapped shared/read-only out of the DEX file.
We could use up a lot of physical memory if we applied all possible
optimizations, so we need a notion of "essential" and "non-essential"
optimizations. If we're not running in dexopt, we only do the
essential ones, which should leave most methods untouched.
Replacement of 32-bit instructions is only strictly necessary when
we're building for SMP. On a uniprocessor, the 32-bit operations
are inherently atomic, and memory barriers aren't required. However,
the JIT may benefit from having volatile accesses identified by opcode.
Since the current branch doesn't support any SMP products, I'm enabling
the instruction generation for all platforms so that we can give it
some exercise.
While making this change I noticed that the exclusion mechanism for
breakpoints and optimization/verification was only serving to avoid
a data race (e.g. breakpoint being overwritten by an instruction
rewrite). It wasn't guaranteed to prevent races when two threads
toggled pages between read-write and read-only while making an update,
since a 4K page can hold code for more than one class. This has been
corrected by adding a mutex.
This change:
- Introduces the notion of essential vs. non-essential optimizations.
- Adds generation of 32-bit *-volatile instructions for all platforms.
- Moves generation of *-wide-volatile from the verifier to the optimizer.
- Allows the optimizer to modify code at run time.
- Tweaks optimizeMethod() for "best effort" rather than "fail early".
- Adds a DEX-granularity mutex to the bytecode update functions.
This also begins the removal of PROFILE_FIELD_ACCESS, which hasn't been
used for much and is mostly just in the way.
Change-Id: I4ac9fa5e1ac5f9a1d106c662c3deee90d62895aa
diff --git a/vm/analysis/CodeVerify.c b/vm/analysis/CodeVerify.c
index 4310a06..3c7be11 100644
--- a/vm/analysis/CodeVerify.c
+++ b/vm/analysis/CodeVerify.c
@@ -2946,6 +2946,9 @@
u2 oldInsn = *oldInsns;
bool result = false;
+ if (gDvm.optimizing)
+ LOGD("Weird: RFI during dexopt?");
+
//LOGD(" was 0x%04x\n", oldInsn);
u2* newInsns = (u2*) meth->insns + insnIdx;
@@ -3045,50 +3048,6 @@
return result;
}
-/*
- * Replace {iget,iput,sget,sput}-wide with the -wide-volatile form.
- *
- * If this is called during dexopt, we can modify the instruction in
- * place. If this happens during just-in-time verification, we need to
- * use the DEX read/write page feature.
- *
- * NOTE:
- * This shouldn't really be tied to verification. It ought to be a
- * separate pass that is run before or after the verifier. However, that
- * requires a bunch of extra code, and the only advantage of doing so is
- * that the feature isn't disabled when verification is turned off. At
- * some point we may need to revisit this choice.
- */
-static void replaceVolatileInstruction(const Method* meth, InsnFlags* insnFlags,
- int insnIdx)
-{
- u2* oldInsns = (u2*)meth->insns + insnIdx;
- u2 oldInsn = *oldInsns;
- u2 newVal;
-
- switch (oldInsn & 0xff) {
- case OP_IGET_WIDE: newVal = OP_IGET_WIDE_VOLATILE; break;
- case OP_IPUT_WIDE: newVal = OP_IPUT_WIDE_VOLATILE; break;
- case OP_SGET_WIDE: newVal = OP_SGET_WIDE_VOLATILE; break;
- case OP_SPUT_WIDE: newVal = OP_SPUT_WIDE_VOLATILE; break;
- default:
- LOGE("wide-volatile op mismatch (0x%x)\n", oldInsn);
- dvmAbort();
- return; // in-lieu-of noreturn attribute
- }
-
- /* merge new opcode into 16-bit code unit */
- newVal |= (oldInsn & 0xff00);
-
- if (gDvm.optimizing) {
- /* dexopt time, alter the output */
- *oldInsns = newVal;
- } else {
- /* runtime, make the page read/write */
- dvmDexChangeDex2(meth->clazz->pDvmDex, oldInsns, newVal);
- }
-}
-
/*
* ===========================================================================
@@ -4539,13 +4498,6 @@
setRegisterType(workRegs, insnRegCount, decInsn.vA,
dstType, &failure);
}
- if (VERIFY_OK(failure)) {
- if (decInsn.opCode != OP_IGET_WIDE_VOLATILE &&
- dvmIsVolatileField(&instField->field))
- {
- replaceVolatileInstruction(meth, insnFlags, insnIdx);
- }
- }
}
break;
case OP_IGET_OBJECT:
@@ -4680,13 +4632,6 @@
failure = VERIFY_ERROR_GENERIC;
break;
}
- if (VERIFY_OK(failure)) {
- if (decInsn.opCode != OP_IPUT_WIDE_VOLATILE &&
- dvmIsVolatileField(&instField->field))
- {
- replaceVolatileInstruction(meth, insnFlags, insnIdx);
- }
- }
}
break;
case OP_IPUT_OBJECT:
@@ -4826,13 +4771,6 @@
setRegisterType(workRegs, insnRegCount, decInsn.vA,
dstType, &failure);
}
- if (VERIFY_OK(failure)) {
- if (decInsn.opCode != OP_SGET_WIDE_VOLATILE &&
- dvmIsVolatileField(&staticField->field))
- {
- replaceVolatileInstruction(meth, insnFlags, insnIdx);
- }
- }
}
break;
case OP_SGET_OBJECT:
@@ -4955,13 +4893,6 @@
failure = VERIFY_ERROR_GENERIC;
break;
}
- if (VERIFY_OK(failure)) {
- if (decInsn.opCode != OP_SPUT_WIDE_VOLATILE &&
- dvmIsVolatileField(&staticField->field))
- {
- replaceVolatileInstruction(meth, insnFlags, insnIdx);
- }
- }
}
break;
case OP_SPUT_OBJECT: