Various bug fixes and new tests.
Amusingly realized that many tests believed to be passing were in fact not
running at all. The test harness returned 0 if the test wasn't run, but some
of the tests used 0 as a success code. Will change the tests later.
Most were failing only because the function pointer table in Thread wasn't
fully initialized with the math helper functions.
Change-Id: If2e42f06139f219a423eef475b599258ccfc82d4
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc
index bf87c1e..cf606a3 100644
--- a/src/compiler/codegen/arm/ArchFactory.cc
+++ b/src/compiler/codegen/arm/ArchFactory.cc
@@ -53,6 +53,8 @@
int dOffset, TGT_LIR* pcrLabel)
{
/* This particular Dalvik register has been null-checked */
+ UNIMPLEMENTED(WARNING) << "Need null check & throw support";
+ return pcrLabel;
if (oatIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
return pcrLabel;
}
diff --git a/src/compiler/codegen/arm/Assemble.cc b/src/compiler/codegen/arm/Assemble.cc
index 19b9445..d9dd8c4 100644
--- a/src/compiler/codegen/arm/Assemble.cc
+++ b/src/compiler/codegen/arm/Assemble.cc
@@ -1194,13 +1194,18 @@
} else if (lir->opcode == kThumbBCond ||
lir->opcode == kThumb2BCond) {
ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
- intptr_t pc = lir->generic.offset + 4;
- intptr_t target = targetLIR->generic.offset;
- int delta = target - pc;
- if ((lir->opcode == kThumbBCond) && (delta > 254 || delta < -256)) {
- lir->opcode = kThumb2BCond;
- oatSetupResourceMasks(lir);
- res = kRetryAll;
+ int delta = 0;
+ if (targetLIR == NULL) {
+ UNIMPLEMENTED(WARNING) << "Throw targets unimplemented";
+ } else {
+ intptr_t pc = lir->generic.offset + 4;
+ intptr_t target = targetLIR->generic.offset;
+ delta = target - pc;
+ if ((lir->opcode == kThumbBCond) && (delta > 254 || delta < -256)) {
+ lir->opcode = kThumb2BCond;
+ oatSetupResourceMasks(lir);
+ res = kRetryAll;
+ }
}
lir->operands[0] = delta >> 1;
} else if (lir->opcode == kThumb2BUncond) {
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 6e2f285..f7194f1 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -428,6 +428,66 @@
return state + 1;
}
+// Slow path sequence for virtual calls
+static int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+ DecodedInstruction* dInsn, int state)
+{
+ RegLocation rlArg;
+ switch(state) {
+ case 0: // Get the current Method* [sets r0]
+ loadBaseDisp(cUnit, mir, rSP, 0, r0, kWord, INVALID_SREG);
+ break;
+ case 1: // Get the current Method->DeclaringClass() [uses/sets r0]
+ loadBaseDisp(cUnit, mir, r0,
+ OFFSETOF_MEMBER(art::Method, declaring_class_),
+ r0, kWord, INVALID_SREG);
+ break;
+ case 2: // Method->DeclaringClass()->GetDexCache() [uses/sets r0]
+ loadBaseDisp(cUnit, mir, r0,
+ OFFSETOF_MEMBER(art::Class, dex_cache_), r0, kWord,
+ INVALID_SREG);
+ break;
+ case 3: // ...()->GetDexCache()->methodsObjectArr [uses/sets r0]
+ loadBaseDisp(cUnit, mir, r0,
+ art::DexCache::MethodsOffset().Int32Value(), r0,
+ kWord, INVALID_SREG);
+ // Load "this" [set r1]
+ rlArg = oatGetSrc(cUnit, mir, 0);
+ loadValueDirectFixed(cUnit, rlArg, r1);
+ // Skip past the object header
+ opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
+ break;
+ case 4:
+ // Is "this" null? [use r1]
+ genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
+ // get this->clazz [use r1, set rLR]
+ loadBaseDisp(cUnit, mir, r1, OFFSETOF_MEMBER(Object, klass_), rLR,
+ kWord, INVALID_SREG);
+ // Get the base Method* [uses r0, sets r0]
+ loadBaseDisp(cUnit, mir, r0, dInsn->vB * 4, r0,
+ kWord, INVALID_SREG);
+ // get this->clazz->vtable [use rLR, set rLR]
+ loadBaseDisp(cUnit, mir, rLR,
+ OFFSETOF_MEMBER(Class, vtable_), rLR, kWord,
+ INVALID_SREG);
+ // Get the method index [use r0, set r12]
+ loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, method_index_),
+ r12, kUnsignedHalf, INVALID_SREG);
+ // Skip past the object header
+ opRegImm(cUnit, kOpAdd, rLR, art::Array::DataOffset().Int32Value());
+ // Get target Method*
+ loadBaseIndexed(cUnit, rLR, r12, r0, 2, kWord);
+ break;
+ case 5: // Get the target compiled code address [uses r0, sets rLR]
+ loadBaseDisp(cUnit, mir, r0, art::Method::GetCodeOffset(), rLR,
+ kWord, INVALID_SREG);
+ break;
+ default:
+ return -1;
+ }
+ return state + 1;
+}
+
/* Load up to 3 arguments in r1..r3 */
static int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
DecodedInstruction* dInsn, int callState,
@@ -702,12 +762,6 @@
{
DecodedInstruction* dInsn = &mir->dalvikInsn;
int callState = 0;
- /*
- * TODO: check for/force resolution of target method
- * note to bdc: you can find the method index in
- * dInsn->vB. If you need it, the calling method's
- * Method* is cUnit->method.
- */
int fastPath = false; // TODO: set based on resolution results
NextCallInsn nextCallInsn = fastPath ? nextSDCallInsn : nextSDCallInsnSP;
@@ -731,15 +785,18 @@
DecodedInstruction* dInsn = &mir->dalvikInsn;
int callState = 0;
ArmLIR* nullCk;
+ int fastPath = false; // TODO: set based on resolution results
+
+ NextCallInsn nextCallInsn = fastPath ? nextSDCallInsn : nextSDCallInsnSP;
if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT)
callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
- false, nextSDCallInsn);
+ false, nextCallInsn);
else
callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
- nextSDCallInsn);
+ nextCallInsn);
// Finish up any of the call sequence not interleaved in arg loading
while (callState >= 0) {
- callState = nextSDCallInsn(cUnit, mir, dInsn, callState);
+ callState = nextCallInsn(cUnit, mir, dInsn, callState);
}
newLIR1(cUnit, kThumbBlxR, rLR);
}
@@ -788,16 +845,19 @@
DecodedInstruction* dInsn = &mir->dalvikInsn;
int callState = 0;
ArmLIR* nullCk;
-// FIXME - redundantly loading arg0/r1 ("this")
+ int fastPath = false; // TODO: set based on resolution results
+
+ NextCallInsn nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
+ // TODO - redundantly loading arg0/r1 ("this")
if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
- false, nextVCallInsn);
+ false, nextCallInsn);
else
callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
- nextVCallInsn);
+ nextCallInsn);
// Finish up any of the call sequence not interleaved in arg loading
while (callState >= 0) {
- callState = nextVCallInsn(cUnit, mir, dInsn, callState);
+ callState = nextCallInsn(cUnit, mir, dInsn, callState);
}
newLIR1(cUnit, kThumbBlxR, rLR);
}
@@ -956,7 +1016,7 @@
rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
0, mir->dalvikInsn.vB << 16);
- storeValue(cUnit, rlDest, rlResult);
+ storeValueWide(cUnit, rlDest, rlResult);
break;
case OP_MONITOR_ENTER:
@@ -986,6 +1046,7 @@
case OP_ARRAY_LENGTH:
int lenOffset;
lenOffset = Array::LengthOffset().Int32Value();
+ rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg,
mir->offset, NULL);
rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index e06910d..2239bd9 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -1358,6 +1358,11 @@
oatFlushAllRegs(cUnit); /* Send everything to home location */
loadWordDisp(cUnit, rSELF, funcOffset, rLR);
loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+ if (rlShift.wide) {
+ LOG(WARNING) << "Invalid RegLocation size - dataflow problem";
+ LOG(WARNING) << " sReg[" << rlShift.sRegLow << "]";
+ rlShift.wide = false;
+ }
loadValueDirect(cUnit, rlShift, r2);
opReg(cUnit, kOpBlx, rLR);
oatClobberCallRegs(cUnit);