Complete compiler portion of exception handling

Will still need much testing once the runtime portions are in place.

Change-Id: I90fc7c1fd89bfae89dfd19a6e422024b6b5454ec
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index c7c15cf..a9d77ec 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -438,7 +438,7 @@
             loadValueDirectFixed(cUnit, rlArg, r1);
             break;
         case 1: // Is "this" null? [use r1]
-            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
+            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
             // get this->klass_ [use r1, set rLR]
             loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
             break;
@@ -507,7 +507,7 @@
             break;
         case 4:
             // Is "this" null? [use r1]
-            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
+            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
             // get this->clazz [use r1, set rLR]
             loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
             break;
@@ -601,8 +601,7 @@
             loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
                          rLR);
             // Is "this" null? [use r1]
-            genNullCheck(cUnit, oatSSASrc(mir,0), r1,
-                           mir->offset, NULL);
+            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
             break;
         case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
             loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
@@ -676,7 +675,7 @@
             loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
                          r0);
             // Null this?
-            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
+            genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
             // Get method->declaring_class_->super_class [usr r0, set r0]
             loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
             break;
@@ -687,7 +686,7 @@
                 tReg = oatAllocTemp(cUnit);
                 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
                              tReg);
-                genBoundsCheck(cUnit, tReg, rLR, mir->offset, NULL);
+                genBoundsCheck(cUnit, tReg, rLR, mir, kArmThrowNoSuchMethod);
                 oatFreeTemp(cUnit, tReg);
             }
             // Adjust vtable_ base past object header
@@ -761,8 +760,7 @@
     //TODO: better to move this into CallInsn lists
     // Load direct & need a "this" null check?
     if (pcrLabel) {
-        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1,
-                                 mir->offset, NULL);
+        *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
     }
     return callState;
 }
@@ -1215,12 +1213,19 @@
             genThrow(cUnit, mir, rlSrc[0]);
             break;
 
+        case OP_THROW_VERIFICATION_ERROR:
+            loadWordDisp(cUnit, rSELF,
+                OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
+            loadConstant(cUnit, r0, mir->dalvikInsn.vA);
+            loadConstant(cUnit, r1, mir->dalvikInsn.vB);
+            opReg(cUnit, kOpBlx, rLR);
+            break;
+
         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);
+            genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
             rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
             loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
                          rlResult.lowReg);
@@ -1986,6 +1991,77 @@
     }
 }
 
+static void handleThrowLaunchpads(CompilationUnit *cUnit)
+{
+    ArmLIR** throwLabel =
+        (ArmLIR **) cUnit->throwLaunchpads.elemList;
+    int numElems = cUnit->throwLaunchpads.numUsed;
+    int i;
+
+    for (i = 0; i < numElems; i++) {
+        ArmLIR* lab = throwLabel[i];
+        cUnit->currentDalvikOffset = lab->operands[1];
+        oatAppendLIR(cUnit, (LIR *)lab);
+        int funcOffset = 0;
+        int v1 = lab->operands[2];
+        int v2 = lab->operands[3];
+        switch(lab->operands[0]) {
+            case kArmThrowNullPointer:
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
+                break;
+            case kArmThrowArrayBounds:
+                if (v2 != r0) {
+                    genRegCopy(cUnit, r0, v1);
+                    genRegCopy(cUnit, r1, v2);
+                } else {
+                    if (v1 == r1) {
+                        genRegCopy(cUnit, r12, v1);
+                        genRegCopy(cUnit, r1, v2);
+                        genRegCopy(cUnit, r0, r12);
+                    } else {
+                        genRegCopy(cUnit, r1, v2);
+                        genRegCopy(cUnit, r0, v1);
+                    }
+                }
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
+                break;
+            case kArmThrowDivZero:
+                funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
+                break;
+            case kArmThrowVerificationError:
+                loadConstant(cUnit, r0, v1);
+                loadConstant(cUnit, r1, v2);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
+                break;
+            case kArmThrowNegArraySize:
+                genRegCopy(cUnit, r0, v1);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
+                break;
+            case kArmThrowInternalError:
+                genRegCopy(cUnit, r0, v1);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowInternalErrorFromCode);
+                break;
+            case kArmThrowRuntimeException:
+                genRegCopy(cUnit, r0, v1);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowRuntimeExceptionFromCode);
+                break;
+            case kArmThrowNoSuchMethod:
+                genRegCopy(cUnit, r0, v1);
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
+                break;
+            default:
+                LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
+        }
+        loadWordDisp(cUnit, rSELF, funcOffset, rLR);
+        opReg(cUnit, kOpBlx, rLR);
+    }
+}
+
 void oatMethodMIR2LIR(CompilationUnit* cUnit)
 {
     /* Used to hold the labels of each block */
@@ -1995,6 +2071,8 @@
     oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
                                   kPreOrderDFSTraversal, false /* Iterative */);
     removeRedundantBranches(cUnit);
+
+    handleThrowLaunchpads(cUnit);
 }
 
 /* Common initialization routine for an architecture family */