Add run-time resolution paths for iget/iput.
Change-Id: I1bd26286a39d057aebbb0d847bc58ecd656af458
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 44cbc0e..cf1ad04 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -14,9 +14,6 @@
* limitations under the License.
*/
-#define FORCE_SLOW 0
-#define DISPLAY_MISSING_TARGETS
-
static const RegLocation badLoc = {kLocDalvikFrame, 0, 0, INVALID_REG,
INVALID_REG, INVALID_SREG, 0,
kLocDalvikFrame, INVALID_REG, INVALID_REG,
@@ -146,6 +143,8 @@
Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
if (field == NULL) {
// Slow path
+ LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
+ << " unresolved at compile time";
int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pSetObjStatic)
: OFFSETOF_MEMBER(Thread, pSet32Static);
oatFlushAllRegs(cUnit);
@@ -203,7 +202,9 @@
{
int fieldIdx = mir->dalvikInsn.vB;
Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
- if (FORCE_SLOW || field == NULL) {
+ if (SLOW_FIELD_PATH || field == NULL) {
+ LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
+ << " unresolved at compile time";
oatFlushAllRegs(cUnit);
loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pSet64Static), rLR);
loadConstant(cUnit, r0, mir->dalvikInsn.vB);
@@ -259,7 +260,9 @@
{
int fieldIdx = mir->dalvikInsn.vB;
Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
- if (FORCE_SLOW || field == NULL) {
+ if (SLOW_FIELD_PATH || field == NULL) {
+ LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
+ << " unresolved at compile time";
oatFlushAllRegs(cUnit);
loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
loadConstant(cUnit, r0, mir->dalvikInsn.vB);
@@ -317,7 +320,9 @@
Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
(mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
- if (FORCE_SLOW || field == NULL) {
+ if (SLOW_FIELD_PATH || field == NULL) {
+ LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
+ << " unresolved at compile time";
// Slow path
int funcOffset = isObject ? OFFSETOF_MEMBER(Thread, pGetObjStatic)
: OFFSETOF_MEMBER(Thread, pGet32Static);
@@ -950,7 +955,7 @@
// Explicit register usage
oatLockCallTemps(cUnit);
- if (FORCE_SLOW || baseMethod == NULL) {
+ if (SLOW_INVOKE_PATH || baseMethod == NULL) {
fastPath = false;
} else {
Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
@@ -1001,7 +1006,7 @@
// Explicit register usage
oatLockCallTemps(cUnit);
- if (FORCE_SLOW || method == NULL) {
+ if (SLOW_INVOKE_PATH || method == NULL) {
// Slow path
nextCallInsn = nextVCallInsnSP;
// If we need a slow-path callout, we'll restart here
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index dbaf9ea..4ae254b 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -22,6 +22,22 @@
*
*/
+#define SLOW_FIELD_PATH 0
+#define SLOW_INVOKE_PATH 0
+#define DISPLAY_MISSING_TARGETS
+//#define EXERCISE_SLOWEST_FIELD_PATH
+
+std::string fieldNameFromIndex(const Method* method, uint32_t fieldIdx)
+{
+ art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
+ const art::DexFile& dex_file = class_linker->FindDexFile(
+ method->GetDeclaringClass()->GetDexCache());
+ const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
+ std::string class_name = dex_file.dexStringById(field_id.class_idx_);
+ std::string field_name = dex_file.dexStringById(field_id.name_idx_);
+ return class_name + "." + field_name;
+}
+
/*
* Construct an s4 from two consecutive half-words of switch data.
* This needs to check endianness because the DEX optimizer only swaps
@@ -380,33 +396,80 @@
#endif
}
+/*
+ * Helper function for Iget/put when field not resolved at compile time.
+ * Will trash call temps and return with the field offset in r0.
+ */
+static void getFieldOffset(CompilationUnit* cUnit, MIR* mir)
+{
+ int fieldIdx = mir->dalvikInsn.vC;
+ LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
+ << " unresolved at compile time";
+ oatLockCallTemps(cUnit); // Explicit register usage
+ loadCurrMethodDirect(cUnit, r1); // arg1 <= Method*
+ loadWordDisp(cUnit, r1,
+ Method::DexCacheResolvedFieldsOffset().Int32Value(), r0);
+ loadWordDisp(cUnit, r0, art::Array::DataOffset().Int32Value() +
+ sizeof(int32_t*)* fieldIdx, r0);
+ /*
+ * For testing, omit the test for run-time resolution. This will
+ * force all accesses to go through the runtime resolution path.
+ */
+#ifndef EXERCISE_SLOWEST_FIELD_PATH
+ ArmLIR* branchOver = genCmpImmBranch(cUnit, kArmCondNe, r0, 0);
+#endif
+ // Resolve
+ loadWordDisp(cUnit, rSELF,
+ OFFSETOF_MEMBER(Thread, pFindFieldFromCode), rLR);
+ loadConstant(cUnit, r0, fieldIdx);
+ opReg(cUnit, kOpBlx, rLR); // resolveTypeFromCode(idx, method)
+ ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
+ target->defMask = ENCODE_ALL;
+#ifndef EXERCISE_SLOWEST_FIELD_PATH
+ branchOver->generic.target = (LIR*)target;
+#endif
+ // Free temps (except for r0)
+ oatFreeTemp(cUnit, r1);
+ oatFreeTemp(cUnit, r2);
+ oatFreeTemp(cUnit, r3);
+ loadWordDisp(cUnit, r0, art::Field::OffsetOffset().Int32Value(), r0);
+}
+
static void genIGetX(CompilationUnit* cUnit, MIR* mir, OpSize size,
RegLocation rlDest, RegLocation rlObj)
{
Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
GetResolvedField(mir->dalvikInsn.vC);
- if (fieldPtr == NULL) {
- UNIMPLEMENTED(FATAL) << "Need to handle unresolved field";
- }
-#if ANDROID_SMP != 0
- bool isVolatile = dvmIsVolatileField(fieldPtr);
-#else
- bool isVolatile = false;
-#endif
- int fieldOffset = fieldPtr->GetOffset().Int32Value();
RegLocation rlResult;
RegisterClass regClass = oatRegClassBySize(size);
- rlObj = loadValue(cUnit, rlObj, kCoreReg);
- rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
- NULL);/* null object? */
- loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
- size, rlObj.sRegLow);
- if (isVolatile) {
+ if (SLOW_FIELD_PATH || fieldPtr == NULL) {
+ getFieldOffset(cUnit, mir);
+ // Field offset in r0
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+ NULL);/* null object? */
+ loadBaseIndexed(cUnit, rlObj.lowReg, r0, rlResult.lowReg, 0, size);
oatGenMemBarrier(cUnit, kSY);
+ storeValue(cUnit, rlDest, rlResult);
+ } else {
+#if ANDROID_SMP != 0
+ bool isVolatile = dvmIsVolatileField(fieldPtr);
+#else
+ bool isVolatile = false;
+#endif
+ int fieldOffset = fieldPtr->GetOffset().Int32Value();
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+ NULL);/* null object? */
+ loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
+ size, rlObj.sRegLow);
+ if (isVolatile) {
+ oatGenMemBarrier(cUnit, kSY);
+ }
+ storeValue(cUnit, rlDest, rlResult);
}
-
- storeValue(cUnit, rlDest, rlResult);
}
static void genIPutX(CompilationUnit* cUnit, MIR* mir, OpSize size,
@@ -414,25 +477,33 @@
{
Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
GetResolvedField(mir->dalvikInsn.vC);
- if (fieldPtr == NULL) {
- UNIMPLEMENTED(FATAL) << "Need to handle unresolved field";
- }
-#if ANDROID_SMP != 0
- bool isVolatile = dvmIsVolatileField(fieldPtr);
-#else
- bool isVolatile = false;
-#endif
- int fieldOffset = fieldPtr->GetOffset().Int32Value();
RegisterClass regClass = oatRegClassBySize(size);
- rlObj = loadValue(cUnit, rlObj, kCoreReg);
- rlSrc = loadValue(cUnit, rlSrc, regClass);
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
- NULL);/* null object? */
-
- if (isVolatile) {
+ if (SLOW_FIELD_PATH || fieldPtr == NULL) {
+ getFieldOffset(cUnit, mir);
+ // Field offset in r0
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ rlSrc = loadValue(cUnit, rlSrc, regClass);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+ NULL);/* null object? */
oatGenMemBarrier(cUnit, kSY);
+ storeBaseIndexed(cUnit, rlObj.lowReg, r0, rlSrc.lowReg, 0, size);
+ } else {
+#if ANDROID_SMP != 0
+ bool isVolatile = dvmIsVolatileField(fieldPtr);
+#else
+ bool isVolatile = false;
+#endif
+ int fieldOffset = fieldPtr->GetOffset().Int32Value();
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ rlSrc = loadValue(cUnit, rlSrc, regClass);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+ NULL);/* null object? */
+
+ if (isVolatile) {
+ oatGenMemBarrier(cUnit, kSY);
+ }
+ storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
}
- storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
if (isObject) {
/* NOTE: marking card based on object head */
markGCCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
@@ -444,34 +515,44 @@
{
Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
GetResolvedField(mir->dalvikInsn.vC);
- if (fieldPtr == NULL) {
- UNIMPLEMENTED(FATAL) << "Need to handle unresolved field";
- }
-#if ANDROID_SMP != 0
- bool isVolatile = dvmIsVolatileField(fieldPtr);
-#else
- bool isVolatile = false;
-#endif
- int fieldOffset = fieldPtr->GetOffset().Int32Value();
RegLocation rlResult;
- rlObj = loadValue(cUnit, rlObj, kCoreReg);
- int regPtr = oatAllocTemp(cUnit);
-
- assert(rlDest.wide);
-
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
- NULL);/* null object? */
- opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
- rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
-
- loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
-
- if (isVolatile) {
+ if (fieldPtr == NULL) {
+ getFieldOffset(cUnit, mir);
+ // Field offset in r0
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+ NULL);/* null object? */
+ opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
+ loadPair(cUnit, r0, rlResult.lowReg, rlResult.highReg);
oatGenMemBarrier(cUnit, kSY);
- }
+ storeValue(cUnit, rlDest, rlResult);
+ } else {
+#if ANDROID_SMP != 0
+ bool isVolatile = dvmIsVolatileField(fieldPtr);
+#else
+ bool isVolatile = false;
+#endif
+ int fieldOffset = fieldPtr->GetOffset().Int32Value();
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ int regPtr = oatAllocTemp(cUnit);
- oatFreeTemp(cUnit, regPtr);
- storeValueWide(cUnit, rlDest, rlResult);
+ assert(rlDest.wide);
+
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+ NULL);/* null object? */
+ opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
+ rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
+
+ loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
+
+ if (isVolatile) {
+ oatGenMemBarrier(cUnit, kSY);
+ }
+
+ oatFreeTemp(cUnit, regPtr);
+ storeValueWide(cUnit, rlDest, rlResult);
+ }
}
static void genIPutWideX(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc,
@@ -480,29 +561,38 @@
Field* fieldPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
GetResolvedField(mir->dalvikInsn.vC);
if (fieldPtr == NULL) {
- UNIMPLEMENTED(FATAL) << "Need to handle unresolved field";
- }
-#if ANDROID_SMP != 0
- bool isVolatile = dvmIsVolatileField(fieldPtr);
-#else
- bool isVolatile = false;
-#endif
- int fieldOffset = fieldPtr->GetOffset().Int32Value();
-
- rlObj = loadValue(cUnit, rlObj, kCoreReg);
- int regPtr;
- rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
- NULL);/* null object? */
- regPtr = oatAllocTemp(cUnit);
- opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
-
- if (isVolatile) {
+ getFieldOffset(cUnit, mir);
+ // Field offset in r0
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+ NULL);/* null object? */
+ opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
oatGenMemBarrier(cUnit, kSY);
- }
- storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
+ storePair(cUnit, r0, rlSrc.lowReg, rlSrc.highReg);
+ } else {
+#if ANDROID_SMP != 0
+ bool isVolatile = dvmIsVolatileField(fieldPtr);
+#else
+ bool isVolatile = false;
+#endif
+ int fieldOffset = fieldPtr->GetOffset().Int32Value();
- oatFreeTemp(cUnit, regPtr);
+ rlObj = loadValue(cUnit, rlObj, kCoreReg);
+ int regPtr;
+ rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
+ NULL);/* null object? */
+ regPtr = oatAllocTemp(cUnit);
+ opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
+
+ if (isVolatile) {
+ oatGenMemBarrier(cUnit, kSY);
+ }
+ storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
+
+ oatFreeTemp(cUnit, regPtr);
+ }
}
static void genConstClass(CompilationUnit* cUnit, MIR* mir,