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/Frontend.cc b/src/compiler/Frontend.cc
index 1775375..272cb08 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -700,13 +700,7 @@
     if (!method->IsStatic() ||
         (method->GetName()->ToModifiedUtf8().find("foo") != std::string::npos) ||
         (method->GetName()->ToModifiedUtf8().find("init>") != std::string::npos) ||
-        (method->GetName()->ToModifiedUtf8().find("intOperTest") != std::string::npos) ||
-        (method->GetName()->ToModifiedUtf8().find("intShiftTest") != std::string::npos) ||
-        (method->GetName()->ToModifiedUtf8().find("lit16Test") != std::string::npos) ||
-        (method->GetName()->ToModifiedUtf8().find("lit8Test") != std::string::npos) ||
         (method->GetName()->ToModifiedUtf8().find("longOperTest") != std::string::npos) ||
-        (method->GetName()->ToModifiedUtf8().find("longShiftTest") != std::string::npos) ||
-        (method->GetName()->ToModifiedUtf8().find("shiftTest1") != std::string::npos) ||
         (method->GetName()->ToModifiedUtf8().find("main") != std::string::npos)) {
         LOG(INFO) << "not compiling " << PrettyMethod(method, true);
         return false;
diff --git a/src/compiler/RuntimeUtilities.cc b/src/compiler/RuntimeUtilities.cc
index d40f097..b18e4da 100644
--- a/src/compiler/RuntimeUtilities.cc
+++ b/src/compiler/RuntimeUtilities.cc
@@ -23,7 +23,7 @@
  * Float/double conversion requires clamping to min and max of integer form.  If
  * target doesn't support this normally, use these.
  */
-s8 artD2L(double d)
+int64_t artD2L(double d)
 {
     static const double kMaxLong = (double)(s8)0x7fffffffffffffffULL;
     static const double kMinLong = (double)(s8)0x8000000000000000ULL;
@@ -37,7 +37,7 @@
         return (s8)d;
 }
 
-s8 artF2L(float f)
+int64_t artF2L(float f)
 {
     static const float kMaxLong = (float)(s8)0x7fffffffffffffffULL;
     static const float kMinLong = (float)(s8)0x8000000000000000ULL;
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);