Class cast, fill array and interface exception support.

This change uses the deliver exception mechanism to implement support
for a number of runtime exceptions. It also tidies up code in the
compiler and allocates a singular callee save method in the image.

Also adds a fix for JNI internal test where we weren't passing
Thread::Current() and that this value is now being used in generated code.

Change-Id: I57eefd9afe40e92fa3a7e737f1a2ed7e1094b5c1
diff --git a/src/asm_support.h b/src/asm_support.h
index 097ab7a..17a29cf 100644
--- a/src/asm_support.h
+++ b/src/asm_support.h
@@ -8,9 +8,12 @@
 #define rSELF r9
 #define rLR r14
 #define SUSPEND_CHECK_INTERVAL (1000)
-#endif
+// Offset of field Thread::top_of_managed_stack_ verified in InitCpu
+#define THREAD_TOP_OF_MANAGED_STACK_OFFSET 333
+// Offset of field Thread::top_of_managed_stack_pc_ verified in InitCpu
+#define THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET 337
 
-#if defined(__i386__)
+#elif defined(__i386__)
 // Offset of field Thread::self_ verified in InitCpu
 #define THREAD_SELF_OFFSET 0x165
 #endif
diff --git a/src/class_linker.h b/src/class_linker.h
index 939fa55..78be84b 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -191,9 +191,6 @@
   DexCache* AllocDexCache(const DexFile& dex_file);
   Field* AllocField();
 
-  // TODO: have no friends, we need this currently to create a special method
-  // to describe callee save registers for throwing exceptions
-  friend class Thread;
   Method* AllocMethod();
 
   CodeAndDirectMethods* AllocCodeAndDirectMethods(size_t length);
diff --git a/src/common_test.h b/src/common_test.h
index 127cad6..844fa00 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -113,9 +113,11 @@
 
 #if defined(__i386__)
     runtime_->SetJniStubArray(JniCompiler::CreateJniStub(kX86));
+    runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kX86));
     compiler_.reset(new Compiler(kX86));
 #elif defined(__arm__)
     runtime_->SetJniStubArray(JniCompiler::CreateJniStub(kThumb2));
+    runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kThumb2));
     compiler_.reset(new Compiler(kThumb2));
 #endif
 
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 41053a2..58cd53b 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -37,7 +37,7 @@
     loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
     loadConstant(cUnit, r0, mir->dalvikInsn.vC);  // arg0 <- type_id
     loadValueDirectFixed(cUnit, rlSrc, r2);       // arg2 <- count
-    callUnwindableHelper(cUnit, rLR);
+    callRuntimeHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     RegLocation rlResult = oatGetReturn(cUnit);
     storeValue(cUnit, rlDest, rlResult);
@@ -60,7 +60,7 @@
     loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
     loadConstant(cUnit, r0, typeId);              // arg0 <- type_id
     loadConstant(cUnit, r2, elems);               // arg2 <- count
-    callUnwindableHelper(cUnit, rLR);
+    callRuntimeHelper(cUnit, rLR);
     /*
      * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
      * return region.  Because AllocFromCode placed the new array
@@ -181,7 +181,7 @@
         loadConstant(cUnit, r0, mir->dalvikInsn.vB);
         loadCurrMethodDirect(cUnit, r1);
         loadValueDirect(cUnit, rlSrc, r2);
-        callUnwindableHelper(cUnit, rLR);
+        callRuntimeHelper(cUnit, rLR);
         oatClobberCallRegs(cUnit);
     } else {
         // fast path
@@ -202,7 +202,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
         loadConstant(cUnit, r0, typeIdx);
-        callUnwindableHelper(cUnit, rLR);
+        callRuntimeHelper(cUnit, rLR);
         ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
         skipTarget->defMask = ENCODE_ALL;
         branchOver->generic.target = (LIR*)skipTarget;
@@ -234,7 +234,7 @@
         loadConstant(cUnit, r0, mir->dalvikInsn.vB);
         loadCurrMethodDirect(cUnit, r1);
         loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
-        callUnwindableHelper(cUnit, rLR);
+        callRuntimeHelper(cUnit, rLR);
         oatClobberCallRegs(cUnit);
     } else {
         // fast path
@@ -255,7 +255,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
         loadConstant(cUnit, r0, typeIdx);
-        callUnwindableHelper(cUnit, rLR);
+        callRuntimeHelper(cUnit, rLR);
         ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
         skipTarget->defMask = ENCODE_ALL;
         branchOver->generic.target = (LIR*)skipTarget;
@@ -286,7 +286,7 @@
         loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
         loadConstant(cUnit, r0, mir->dalvikInsn.vB);
         loadCurrMethodDirect(cUnit, r1);
-        callUnwindableHelper(cUnit, rLR);
+        callRuntimeHelper(cUnit, rLR);
         RegLocation rlResult = oatGetReturnWide(cUnit);
         storeValueWide(cUnit, rlDest, rlResult);
     } else {
@@ -308,7 +308,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
         loadConstant(cUnit, r0, typeIdx);
-        callUnwindableHelper(cUnit, rLR);
+        callRuntimeHelper(cUnit, rLR);
         ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
         skipTarget->defMask = ENCODE_ALL;
         branchOver->generic.target = (LIR*)skipTarget;
@@ -344,7 +344,7 @@
         loadWordDisp(cUnit, rSELF, funcOffset, rLR);
         loadConstant(cUnit, r0, mir->dalvikInsn.vB);
         loadCurrMethodDirect(cUnit, r1);
-        callUnwindableHelper(cUnit, rLR);
+        callRuntimeHelper(cUnit, rLR);
         RegLocation rlResult = oatGetReturn(cUnit);
         storeValue(cUnit, rlDest, rlResult);
     } else {
@@ -366,7 +366,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
         loadConstant(cUnit, r0, typeIdx);
-        callUnwindableHelper(cUnit, rLR);
+        callRuntimeHelper(cUnit, rLR);
         ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
         skipTarget->defMask = ENCODE_ALL;
         branchOver->generic.target = (LIR*)skipTarget;
@@ -497,7 +497,7 @@
             loadWordDisp(cUnit, rSELF,
                          OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
             loadConstant(cUnit, r1, dInsn->vB);
-            callUnwindableHelper(cUnit, rLR);
+            callRuntimeHelper(cUnit, rLR);
             genUnconditionalBranch(cUnit, rollback);
             // Resume normal slow path
             skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -664,7 +664,7 @@
             loadWordDisp(cUnit, rSELF,
                          OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
             loadConstant(cUnit, r1, dInsn->vB);
-            callUnwindableHelper(cUnit, rLR);
+            callRuntimeHelper(cUnit, rLR);
             genUnconditionalBranch(cUnit, rollback);
             // Resume normal slow path
             skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -848,7 +848,7 @@
         opRegRegImm(cUnit, kOpAdd, r1, rSP, startOffset);
         loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
         loadConstant(cUnit, r2, (numArgs - 3) * 4);
-        callNoUnwindHelper(cUnit, rLR);
+        callRuntimeHelper(cUnit, rLR);
         // Restore Method*
         loadCurrMethodDirect(cUnit, r0);
     } else {
@@ -1237,7 +1237,7 @@
                 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
             loadConstant(cUnit, r0, mir->dalvikInsn.vA);
             loadConstant(cUnit, r1, mir->dalvikInsn.vB);
-            callUnwindableHelper(cUnit, rLR);
+            callRuntimeHelper(cUnit, rLR);
             break;
 
         case OP_ARRAY_LENGTH:
@@ -2092,7 +2092,7 @@
                 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
         }
         loadWordDisp(cUnit, rSELF, funcOffset, rLR);
-        callUnwindableHelper(cUnit, rLR);
+        callRuntimeHelper(cUnit, rLR);
     }
 }
 
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 76d8b45..8f83cbb 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -55,19 +55,7 @@
 }
 #endif
 
-/*
- * If a helper routine might need to unwind, let it know the top
- * of the managed stack.
- */
-static ArmLIR* callUnwindableHelper(CompilationUnit* cUnit, int reg)
-{
-    // Starting point for managed traceback if we throw
-    storeWordDisp(cUnit, rSELF,
-                  art::Thread::TopOfManagedStackOffset().Int32Value(), rSP);
-    return opReg(cUnit, kOpBlx, reg);
-}
-
-static ArmLIR* callNoUnwindHelper(CompilationUnit* cUnit, int reg)
+static ArmLIR* callRuntimeHelper(CompilationUnit* cUnit, int reg)
 {
     return opReg(cUnit, kOpBlx, reg);
 }
@@ -384,7 +372,7 @@
                  OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
     // Materialize a pointer to the fill data image
     newLIR3(cUnit, kThumb2Adr, r1, 0, (intptr_t)tabRec);
-    callUnwindableHelper(cUnit, rLR);
+    callRuntimeHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
 }
 
@@ -437,7 +425,7 @@
     loadWordDisp(cUnit, rSELF,
                  OFFSETOF_MEMBER(Thread, pFindInstanceFieldFromCode), rLR);
     loadConstant(cUnit, r0, fieldIdx);
-    callUnwindableHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
+    callRuntimeHelper(cUnit, rLR);  // resolveTypeFromCode(idx, method)
     ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
     target->defMask = ENCODE_ALL;
 #ifndef EXERCISE_SLOWEST_FIELD_PATH
@@ -632,7 +620,7 @@
                      OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
         genRegCopy(cUnit, r1, mReg);
         loadConstant(cUnit, r0, mir->dalvikInsn.vB);
-        callUnwindableHelper(cUnit, rLR);
+        callRuntimeHelper(cUnit, rLR);
         oatClobberCallRegs(cUnit);
         RegLocation rlResult = oatGetReturn(cUnit);
         storeValue(cUnit, rlDest, rlResult);
@@ -674,7 +662,7 @@
                  OFFSETOF_MEMBER(Thread, pAllocObjectFromCode), rLR);
     loadCurrMethodDirect(cUnit, r1);              // arg1 <= Method*
     loadConstant(cUnit, r0, mir->dalvikInsn.vB);  // arg0 <- type_id
-    callUnwindableHelper(cUnit, rLR);
+    callRuntimeHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     RegLocation rlResult = oatGetReturn(cUnit);
     storeValue(cUnit, rlDest, rlResult);
@@ -685,7 +673,7 @@
     loadWordDisp(cUnit, rSELF,
                  OFFSETOF_MEMBER(Thread, pDeliverException), rLR);
     loadValueDirectFixed(cUnit, rlSrc, r0);  // Get exception object
-    callNoUnwindHelper(cUnit, rLR);  // art_deliver_exception(exception);
+    callRuntimeHelper(cUnit, rLR);  // art_deliver_exception(exception);
 }
 
 static void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
@@ -709,7 +697,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
         loadConstant(cUnit, r0, mir->dalvikInsn.vC);
-        callUnwindableHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
+        callRuntimeHelper(cUnit, rLR);  // resolveTypeFromCode(idx, method)
         genRegCopy(cUnit, r2, r0); // Align usage with fast path
         // Rejoin code paths
         ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -731,7 +719,7 @@
     ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq);
     genRegCopy(cUnit, r0, r3);
     genRegCopy(cUnit, r1, r2);
-    callUnwindableHelper(cUnit, rLR);
+    callRuntimeHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     /* branch target here */
     ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -762,7 +750,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
         loadConstant(cUnit, r0, mir->dalvikInsn.vB);
-        callUnwindableHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
+        callRuntimeHelper(cUnit, rLR);  // resolveTypeFromCode(idx, method)
         genRegCopy(cUnit, r2, r0); // Align usage with fast path
         // Rejoin code paths
         ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -783,7 +771,7 @@
     ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq); /* If equal, trivial yes */
     genRegCopy(cUnit, r0, r1);
     genRegCopy(cUnit, r1, r2);
-    callUnwindableHelper(cUnit, rLR);
+    callRuntimeHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     /* branch target here */
     ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -948,7 +936,7 @@
     loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
                  rLR);
     genRegCopy(cUnit, r0, rSELF);
-    callUnwindableHelper(cUnit, rLR);
+    callRuntimeHelper(cUnit, rLR);
 
     // Resume here
     target = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -996,7 +984,7 @@
     loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
                  rLR);
     genRegCopy(cUnit, r0, rSELF);
-    callUnwindableHelper(cUnit, rLR);
+    callRuntimeHelper(cUnit, rLR);
 
     // Resume here
     target = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -1084,7 +1072,7 @@
         rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
         loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
     }
-    callNoUnwindHelper(cUnit, rLR);
+    callRuntimeHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     if (tgtSize == 1) {
         RegLocation rlResult;
@@ -1139,7 +1127,7 @@
     loadWordDisp(cUnit, rSELF, funcOffset, rLR);
     loadValueDirectFixed(cUnit, rlSrc1, r0);
     loadValueDirectFixed(cUnit, rlSrc2, r1);
-    callUnwindableHelper(cUnit, rLR);
+    callRuntimeHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     rlResult = oatGetReturn(cUnit);
     storeValue(cUnit, rlDest, rlResult);
@@ -1185,7 +1173,7 @@
     loadWordDisp(cUnit, rSELF, funcOffset, rLR);
     loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
     loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
-    callUnwindableHelper(cUnit, rLR);
+    callRuntimeHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     rlResult = oatGetReturnWide(cUnit);
     storeValueWide(cUnit, rlDest, rlResult);
@@ -1265,7 +1253,7 @@
                  OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode), rLR);
     /* Get the array's clazz */
     loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), r1);
-    callUnwindableHelper(cUnit, rLR);
+    callRuntimeHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
 
     // Now, redo loadValues in case they didn't survive the call
@@ -1455,7 +1443,7 @@
     loadWordDisp(cUnit, rSELF, funcOffset, rLR);
     loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
     loadValueDirect(cUnit, rlShift, r2);
-    callNoUnwindHelper(cUnit, rLR);
+    callRuntimeHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     RegLocation rlResult = oatGetReturnWide(cUnit);
     storeValueWide(cUnit, rlDest, rlResult);
@@ -1550,7 +1538,7 @@
         loadWordDisp(cUnit, rSELF, funcOffset, rLR);
         loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
         loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
-        callUnwindableHelper(cUnit, rLR);
+        callRuntimeHelper(cUnit, rLR);
         oatClobberCallRegs(cUnit);
         if (retReg == r0)
             rlResult = oatGetReturnWide(cUnit);
@@ -1672,7 +1660,7 @@
         if (checkZero) {
             genImmedCheck(cUnit, kArmCondEq, r1, 0, mir, kArmThrowDivZero);
         }
-        callUnwindableHelper(cUnit, rLR);
+        callRuntimeHelper(cUnit, rLR);
         oatClobberCallRegs(cUnit);
         if (retReg == r0)
             rlResult = oatGetReturn(cUnit);
@@ -1732,7 +1720,7 @@
     callUnwindableHelper(cUnit, rLR); // CheckSuspendFromCode(self)
 #else
     ArmLIR* branch = opCondBranch(cUnit, kArmCondEq);
-    callUnwindableHelper(cUnit, rLR); // CheckSuspendFromCode(self)
+    callRuntimeHelper(cUnit, rLR); // CheckSuspendFromCode(self)
     ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
     target->defMask = ENCODE_ALL;
     branch->generic.target = (LIR*)target;
@@ -1960,7 +1948,7 @@
             }
             loadWordDisp(cUnit, rSELF, funcOffset, rLR);
             loadConstant(cUnit, r1, lit);
-            callUnwindableHelper(cUnit, rLR);
+            callRuntimeHelper(cUnit, rLR);
             oatClobberCallRegs(cUnit);
             if (isDiv)
                 rlResult = oatGetReturn(cUnit);
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 053575a..6c967ed 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -189,7 +189,10 @@
   if (!runtime->HasJniStubArray()) {
     runtime->SetJniStubArray(JniCompiler::CreateJniStub(kThumb2));
   }
-
+  // similarly for the callee save method
+  if (!runtime->HasCalleeSaveMethod()) {
+    runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(kThumb2));
+  }
   Compiler compiler(kThumb2);
   if (method_names.empty()) {
     compiler.CompileAll(class_loader);
diff --git a/src/image.h b/src/image.h
index e3fa35d..fdf6443 100644
--- a/src/image.h
+++ b/src/image.h
@@ -42,6 +42,7 @@
 
   enum ImageRoot {
     kJniStubArray,
+    kCalleeSaveMethod,
     kImageRootsMax,
   };
 
diff --git a/src/image_writer.cc b/src/image_writer.cc
index ae6c1c8..23bc6cf 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -107,6 +107,7 @@
   ObjectArray<Object>* image_roots = ObjectArray<Object>::Alloc(object_array_class,
                                                                 ImageHeader::kImageRootsMax);
   image_roots->Set(ImageHeader::kJniStubArray, runtime->GetJniStubArray());
+  image_roots->Set(ImageHeader::kCalleeSaveMethod, runtime->GetCalleeSaveMethod());
   return image_roots;
 }
 
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index b3e5c79..725d9aa 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -836,7 +836,7 @@
 
   Object* arg = NULL;
 
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), NULL);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), NULL);
 }
 
 TEST_F(JniInternalTest, StaticNopMethod) {
@@ -851,7 +851,7 @@
 
   Method::InvokeStub* stub = method->GetInvokeStub();
 
-  (*stub)(method, NULL, NULL, NULL, NULL);
+  (*stub)(method, NULL, Thread::Current(), NULL, NULL);
 }
 
 TEST_F(JniInternalTest, StaticIdentityByteMethod) {
@@ -871,22 +871,22 @@
 
   arg = 0;
   result.b = -1;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
   EXPECT_EQ(0, result.b);
 
   arg = -1;
   result.b = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
   EXPECT_EQ(-1, result.b);
 
   arg = SCHAR_MAX;
   result.b = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
   EXPECT_EQ(SCHAR_MAX, result.b);
 
   arg = SCHAR_MIN;
   result.b = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
   EXPECT_EQ(SCHAR_MIN, result.b);
 }
 
@@ -907,22 +907,22 @@
 
   arg = 0;
   result.i = -1;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
   EXPECT_EQ(0, result.i);
 
   arg = -1;
   result.i = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
   EXPECT_EQ(-1, result.i);
 
   arg = INT_MAX;
   result.i = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
   EXPECT_EQ(INT_MAX, result.i);
 
   arg = INT_MIN;
   result.i = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
   EXPECT_EQ(INT_MIN, result.i);
 }
 
@@ -943,22 +943,22 @@
 
   arg = 0.0;
   result.d = -1.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
   EXPECT_EQ(0.0, result.d);
 
   arg = -1.0;
   result.d = 0.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
   EXPECT_EQ(-1.0, result.d);
 
   arg = DBL_MAX;
   result.d = 0.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
   EXPECT_EQ(DBL_MAX, result.d);
 
   arg = DBL_MIN;
   result.d = 0.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(&arg), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(&arg), &result);
   EXPECT_EQ(DBL_MIN, result.d);
 }
 
@@ -980,31 +980,31 @@
   args[0] = 0;
   args[1] = 0;
   result.i = -1;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(0, result.i);
 
   args[0] = 1;
   args[1] = 2;
   result.i = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(3, result.i);
 
   args[0] = -2;
   args[1] = 5;
   result.i = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(3, result.i);
 
   args[0] = INT_MAX;
   args[1] = INT_MIN;
   result.i = 1234;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(-1, result.i);
 
   args[0] = INT_MAX;
   args[1] = INT_MAX;
   result.i = INT_MIN;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(-2, result.i);
 }
 
@@ -1027,35 +1027,35 @@
   args[1] = 0;
   args[2] = 0;
   result.i = -1;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(0, result.i);
 
   args[0] = 1;
   args[1] = 2;
   args[2] = 3;
   result.i = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(6, result.i);
 
   args[0] = -1;
   args[1] = 2;
   args[2] = -3;
   result.i = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(-2, result.i);
 
   args[0] = INT_MAX;
   args[1] = INT_MIN;
   args[2] = INT_MAX;
   result.i = 1234;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(2147483646, result.i);
 
   args[0] = INT_MAX;
   args[1] = INT_MAX;
   args[2] = INT_MAX;
   result.i = INT_MIN;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(2147483645, result.i);
 }
 
@@ -1079,7 +1079,7 @@
   args[2] = 0;
   args[3] = 0;
   result.i = -1;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(0, result.i);
 
   args[0] = 1;
@@ -1087,7 +1087,7 @@
   args[2] = 3;
   args[3] = 4;
   result.i = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(10, result.i);
 
   args[0] = -1;
@@ -1095,7 +1095,7 @@
   args[2] = -3;
   args[3] = 4;
   result.i = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(2, result.i);
 
   args[0] = INT_MAX;
@@ -1103,7 +1103,7 @@
   args[2] = INT_MAX;
   args[3] = INT_MIN;
   result.i = 1234;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(-2, result.i);
 
   args[0] = INT_MAX;
@@ -1111,7 +1111,7 @@
   args[2] = INT_MAX;
   args[3] = INT_MAX;
   result.i = INT_MIN;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(-4, result.i);
 }
 
@@ -1136,7 +1136,7 @@
   args[3] = 0;
   args[4] = 0;
   result.i = -1.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(0, result.i);
 
   args[0] = 1;
@@ -1145,7 +1145,7 @@
   args[3] = 4;
   args[4] = 5;
   result.i = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(15, result.i);
 
   args[0] = -1;
@@ -1154,7 +1154,7 @@
   args[3] = 4;
   args[4] = -5;
   result.i = 0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(-3, result.i);
 
   args[0] = INT_MAX;
@@ -1163,7 +1163,7 @@
   args[3] = INT_MIN;
   args[4] = INT_MAX;
   result.i = 1234;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(2147483645, result.i);
 
   args[0] = INT_MAX;
@@ -1172,7 +1172,7 @@
   args[3] = INT_MAX;
   args[4] = INT_MAX;
   result.i = INT_MIN;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(2147483643, result.i);
 }
 
@@ -1194,31 +1194,31 @@
   args[0] = 0.0;
   args[1] = 0.0;
   result.d = -1.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(0.0, result.d);
 
   args[0] = 1.0;
   args[1] = 2.0;
   result.d = 0.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(3.0, result.d);
 
   args[0] = 1.0;
   args[1] = -2.0;
   result.d = 0.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(-1.0, result.d);
 
   args[0] = DBL_MAX;
   args[1] = DBL_MIN;
   result.d = 0.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(1.7976931348623157e308, result.d);
 
   args[0] = DBL_MAX;
   args[1] = DBL_MAX;
   result.d = 0.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(INFINITY, result.d);
 }
 
@@ -1241,21 +1241,21 @@
   args[1] = 0.0;
   args[2] = 0.0;
   result.d = -1.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(0.0, result.d);
 
   args[0] = 1.0;
   args[1] = 2.0;
   args[2] = 3.0;
   result.d = 0.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(6.0, result.d);
 
   args[0] = 1.0;
   args[1] = -2.0;
   args[2] = 3.0;
   result.d = 0.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(2.0, result.d);
 }
 
@@ -1279,7 +1279,7 @@
   args[2] = 0.0;
   args[3] = 0.0;
   result.d = -1.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(0.0, result.d);
 
   args[0] = 1.0;
@@ -1287,7 +1287,7 @@
   args[2] = 3.0;
   args[3] = 4.0;
   result.d = 0.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(10.0, result.d);
 
   args[0] = 1.0;
@@ -1295,7 +1295,7 @@
   args[2] = 3.0;
   args[3] = -4.0;
   result.d = 0.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(-2.0, result.d);
 }
 
@@ -1320,7 +1320,7 @@
   args[3] = 0.0;
   args[4] = 0.0;
   result.d = -1.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(0.0, result.d);
 
   args[0] = 1.0;
@@ -1329,7 +1329,7 @@
   args[3] = 4.0;
   args[4] = 5.0;
   result.d = 0.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(15.0, result.d);
 
   args[0] = 1.0;
@@ -1338,7 +1338,7 @@
   args[3] = -4.0;
   args[4] = 5.0;
   result.d = 0.0;
-  (*stub)(method, NULL, NULL, reinterpret_cast<byte*>(args), &result);
+  (*stub)(method, NULL, Thread::Current(), reinterpret_cast<byte*>(args), &result);
   EXPECT_EQ(3.0, result.d);
 }
 #endif  // __arm__
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 52cddb5..9d4b283 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -54,8 +54,9 @@
   exit(EXIT_FAILURE);
 }
 
-const char* image_roots_descriptions_[ImageHeader::kImageRootsMax] = {
+const char* image_roots_descriptions_[] = {
   "kJniStubArray",
+  "kCalleeSaveMethod"
 };
 
 class OatDump {
@@ -66,6 +67,7 @@
     os << image_header.GetMagic() << "\n\n";
 
     os << "ROOTS:\n";
+    CHECK(sizeof(image_roots_descriptions_)/(sizeof(char*)) == ImageHeader::kImageRootsMax);
     for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
       ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
       os << StringPrintf("%s: %p\n",
@@ -82,7 +84,7 @@
 
  private:
 
-  OatDump(const Space& dump_space, std::ostream& os) : dump_space_(dump_space_), os_(os) {}
+  OatDump(const Space& dump_space, std::ostream& os) : dump_space_(dump_space), os_(os) {}
 
   static void Callback(Object* obj, void* arg) {
     DCHECK(obj != NULL);
@@ -118,9 +120,14 @@
     if (obj->IsMethod()) {
       Method* method = obj->AsMethod();
       const ByteArray* code = method->GetCodeArray();
-      StringAppendF(&summary, "\tCODE     %p-%p\n", code->GetData(), code->GetData() + code->GetLength());
-      const ByteArray* invoke = method->GetInvokeStubArray();
-      StringAppendF(&summary, "\tJNI STUB %p-%p\n", invoke->GetData(), invoke->GetData() + invoke->GetLength());
+      if (method->IsPhony()) {
+        CHECK(code == NULL);
+        StringAppendF(&summary, "\tPHONY\n");
+      } else {
+        StringAppendF(&summary, "\tCODE     %p-%p\n", code->GetData(), code->GetData() + code->GetLength());
+        const ByteArray* invoke = method->GetInvokeStubArray();
+        StringAppendF(&summary, "\tJNI STUB %p-%p\n", invoke->GetData(), invoke->GetData() + invoke->GetLength());
+      }
       if (method->IsNative()) {
         if (method->IsRegistered()) {
          StringAppendF(&summary, "\tNATIVE REGISTERED %p\n", method->GetNativeMethod());
diff --git a/src/object.cc b/src/object.cc
index 40bc2e2..e92c8c7 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -62,8 +62,8 @@
   Monitor::MonitorEnter(thread, this);
 }
 
-void Object::MonitorExit(Thread* thread) {
-  Monitor::MonitorExit(thread, this);
+bool Object::MonitorExit(Thread* thread) {
+  return Monitor::MonitorExit(thread, this);
 }
 
 void Object::Notify() {
@@ -604,15 +604,15 @@
     // Set the low-order bit so a BLX will switch to Thumb mode
     address |= 0x1;
   }
-  SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_), reinterpret_cast<const void*>(address), false);
+  SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_),
+                           reinterpret_cast<const void*>(address), false);
 }
 
 bool Method::IsWithinCode(uintptr_t pc) const {
-  if (GetCode() == NULL) {
-    return false;
-  }
   if (pc == 0) {
-    // assume that this is some initial value that will always lie in code
+    // PC of 0 represents the beginning of a stack trace either a native or where we have a callee
+    // save method that has no code
+    DCHECK(IsNative() || IsPhony());
     return true;
   } else {
 #if defined(__arm__)
diff --git a/src/object.h b/src/object.h
index e0a13ca..a562999 100644
--- a/src/object.h
+++ b/src/object.h
@@ -228,7 +228,7 @@
 
   void MonitorEnter(Thread* thread);
 
-  void MonitorExit(Thread* thread);
+  bool MonitorExit(Thread* thread);
 
   void Notify();
 
@@ -927,8 +927,7 @@
 
   // Is this a hand crafted method used for something like describing callee saves?
   bool IsPhony() const {
-    bool result =
-        NULL == GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Method, declaring_class_), false);
+    bool result = this == Runtime::Current()->GetCalleeSaveMethod();
     // Check that if we do think it is phony it looks like the callee save method
     DCHECK(!result || GetCoreSpillMask() != 0);
     return result;
@@ -951,6 +950,7 @@
   }
 
   static void SetClass(Class* java_lang_reflect_Method);
+  static Class* GetMethodClass() { return java_lang_reflect_Method_; }
   static void ResetClass();
 
  private:
diff --git a/src/runtime.cc b/src/runtime.cc
index 790a700..e9b7fdc 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -31,6 +31,7 @@
       signal_catcher_(NULL),
       java_vm_(NULL),
       jni_stub_array_(NULL),
+      callee_save_method_(NULL),
       started_(false),
       vfprintf_(NULL),
       exit_(NULL),
@@ -579,12 +580,50 @@
   thread_list_->Unregister();
 }
 
+Method* Runtime::CreateCalleeSaveMethod(InstructionSet insns) {
+  Class* method_class = Method::GetMethodClass();
+  Method* method = down_cast<Method*>(method_class->AllocObject());
+  method->SetDeclaringClass(method_class);
+  method->SetName(intern_table_->InternStrong("$$$callee_save_method$$$"));
+  method->SetSignature(intern_table_->InternStrong("()V"));
+  method->SetCode(NULL, insns, NULL);
+  if ((insns == kThumb2) || (insns == kArm)) {
+    method->SetFrameSizeInBytes(64);
+    method->SetReturnPcOffsetInBytes(60);
+    method->SetCoreSpillMask((1 << art::arm::R1) |
+                             (1 << art::arm::R2) |
+                             (1 << art::arm::R3) |
+                             (1 << art::arm::R4) |
+                             (1 << art::arm::R5) |
+                             (1 << art::arm::R6) |
+                             (1 << art::arm::R7) |
+                             (1 << art::arm::R8) |
+                             (1 << art::arm::R9) |
+                             (1 << art::arm::R10) |
+                             (1 << art::arm::R11) |
+                             (1 << art::arm::LR));
+    method->SetFpSpillMask(0);
+  } else if (insns == kX86) {
+    method->SetFrameSizeInBytes(32);
+    method->SetReturnPcOffsetInBytes(28);
+    method->SetCoreSpillMask((1 << art::x86::EBX) |
+                             (1 << art::x86::EBP) |
+                             (1 << art::x86::ESI) |
+                             (1 << art::x86::EDI));
+    method->SetFpSpillMask(0);
+  } else {
+    UNIMPLEMENTED(FATAL);
+  }
+  return method;
+}
+
 void Runtime::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
   class_linker_->VisitRoots(visitor, arg);
   intern_table_->VisitRoots(visitor, arg);
   java_vm_->VisitRoots(visitor, arg);
   thread_list_->VisitRoots(visitor, arg);
   visitor(jni_stub_array_, arg);
+  visitor(callee_save_method_, arg);
 
   //(*visitor)(&gDvm.outOfMemoryObj, 0, ROOT_VM_INTERNAL, arg);
   //(*visitor)(&gDvm.internalErrorObj, 0, ROOT_VM_INTERNAL, arg);
diff --git a/src/runtime.h b/src/runtime.h
index b3d3ebf..ee5f524 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -12,6 +12,7 @@
 
 #include <jni.h>
 
+#include "constants.h"
 #include "heap.h"
 #include "globals.h"
 #include "macros.h"
@@ -28,6 +29,7 @@
 class Heap;
 class InternTable;
 class JavaVMExt;
+class Method;
 class SignalCatcher;
 class String;
 class ThreadList;
@@ -154,6 +156,21 @@
     jni_stub_array_ = jni_stub_array;
   }
 
+  Method* CreateCalleeSaveMethod(InstructionSet insns);
+
+  bool HasCalleeSaveMethod() const {
+    return callee_save_method_ != NULL;
+  }
+
+  // Returns a special method that describes all callee saves being spilled to the stack.
+  Method* GetCalleeSaveMethod() const {
+    return callee_save_method_;
+  }
+
+  void SetCalleeSaveMethod(Method* method) {
+    callee_save_method_ = method;
+  }
+
   int32_t GetStat(int kind);
 
   RuntimeStats* GetStats();
@@ -198,6 +215,8 @@
 
   ByteArray* jni_stub_array_;
 
+  Method* callee_save_method_;
+
   bool started_;
 
   // Hooks supported by JNI_CreateJavaVM
diff --git a/src/runtime_support.S b/src/runtime_support.S
index 6522243..5746059 100644
--- a/src/runtime_support.S
+++ b/src/runtime_support.S
@@ -4,92 +4,161 @@
 
     .balign 4
 
-    .global art_deliver_exception
-    .extern artDeliverExceptionHelper
+    /* Deliver the given exception */
+    .extern artDeliverExceptionFromCode
+    /* Deliver an exception pending on a thread */
+    .extern artDeliverPendingException
+
+    .global art_deliver_exception_from_code
     /*
-     * Called by managed code, saves mosts registers (forms basis of long jump context).
-     * artThrowExceptionHelper will place a mock Method* at the bottom of the thread.
-     * r0 holds Throwable
+     * Called by managed code, saves mosts registers (forms basis of long jump context) and passes
+     * the bottom of the stack. artDeliverExceptionFromCode will place the callee save Method* at
+     * the bottom of the thread. On entry r0 holds Throwable*
      */
-art_deliver_exception:
+art_deliver_exception_from_code:
     stmdb  sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
-    sub sp, #16                  @ 4 words of space, bottom word will hold Method*
-    mov r1, r9                   @ pass Thread::Current
-    mov r2, sp                   @ pass SP
-    b artDeliverExceptionHelper  @ artDeliverExceptionHelper(Throwable*, Thread*, SP)
+    sub sp, #16                     @ 4 words of space, bottom word will hold Method*
+    mov r1, r9                      @ pass Thread::Current
+    mov r2, sp                      @ pass SP
+    b   artDeliverExceptionFromCode @ artDeliverExceptionFromCode(Throwable*, Thread*, SP)
 
     .global art_throw_null_pointer_exception_from_code
-    .extern artThrowNullPointerExceptionFromCodeHelper
+    .extern artThrowNullPointerExceptionFromCode
     /*
-     * Create NPE and deliver
+     * Called by managed code to create and deliver a NullPointerException
      */
 art_throw_null_pointer_exception_from_code:
     stmdb  sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
-    sub sp, #16                  @ 4 words of space, bottom word will hold Method*
-    mov r0, r9                   @ pass Thread::Current
-    mov r1, sp                   @ pass SP
-    b artThrowNullPointerExceptionFromCodeHelper @ artThrowNullPointerExceptionFromCodeHelper(Thread*, SP)
+    sub sp, #16                              @ 4 words of space, bottom word will hold Method*
+    mov r0, r9                               @ pass Thread::Current
+    mov r1, sp                               @ pass SP
+    b   artThrowNullPointerExceptionFromCode @ artThrowNullPointerExceptionFromCode(Thread*, SP)
 
     .global art_throw_div_zero_from_code
-    .extern artThrowDivZeroFromCodeHelper
+    .extern artThrowDivZeroFromCode
     /*
-     * Create ArithmeticException and deliver
+     * Called by managed code to create and deliver an ArithmeticException
      */
 art_throw_div_zero_from_code:
     stmdb  sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
-    sub sp, #16                  @ 4 words of space, bottom word will hold Method*
-    mov r0, r9                   @ pass Thread::Current
-    mov r1, sp                   @ pass SP
-    b artThrowDivZeroFromCodeHelper @ artThrowDivZeroFromCodeHelper(Thread*, SP)
+    sub sp, #16                 @ 4 words of space, bottom word will hold Method*
+    mov r0, r9                  @ pass Thread::Current
+    mov r1, sp                  @ pass SP
+    b   artThrowDivZeroFromCode @ artThrowDivZeroFromCode(Thread*, SP)
 
     .global art_throw_array_bounds_from_code
-    .extern artThrowArrayBoundsFromCodeHelper
+    .extern artThrowArrayBoundsFromCode
     /*
-     * Create ArrayIndexOutOfBoundsException and deliver
+     * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException
      */
 art_throw_array_bounds_from_code:
     stmdb  sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
-    sub sp, #16                  @ 4 words of space, bottom word will hold Method*
-    mov r2, r9                   @ pass Thread::Current
-    mov r3, sp                   @ pass SP
-    b artThrowArrayBoundsFromCodeHelper @ artThrowArrayBoundsFromCodeHelper(index, limit, Thread*, SP)
+    sub sp, #16                     @ 4 words of space, bottom word will hold Method*
+    mov r2, r9                      @ pass Thread::Current
+    mov r3, sp                      @ pass SP
+    b   artThrowArrayBoundsFromCode @ artThrowArrayBoundsFromCode(index, limit, Thread*, SP)
 
     .global art_invoke_interface_trampoline
-    .extern artFindInterfaceMethodInCache
-    .extern artFailedInvokeInterface
-art_invoke_interface_trampoline:
+    .extern artFindInterfaceMethodInCacheFromCode
     /*
-     * All generated callsites for interface invokes will load arguments
-     * as usual - except instead of loading arg0/r0 with the target
-     * Method*, arg0/r0 will contain the method_idx.  This wrapper will
-     * save arg1-arg3, load the caller's Method*, align the stack and
-     * call the helper artFindInterfaceMethodInCache(idx, this, method);
-     * NOTE: "this" is first visable argument of the target, and so can be
-     * found in arg1/r1.
+     * All generated callsites for interface invokes will load arguments as usual - except instead
+     * of loading arg0/r0 with the target Method*, arg0/r0 will contain the method_idx.  This
+     * wrapper will save arg1-arg3, load the caller's Method*, align the stack and call the helper
+     * artFindInterfaceMethodInCacheFromCode(idx, this, method);
+     * NOTE: "this" is first visable argument of the target, and so can be found in arg1/r1.
      *
-     * artFindInterfaceMethodInCache will attempt to locate the target
-     * and return a 64-bit result in r0/r1 consisting of the target
-     * Method* in r0 and method->code_ in r1.
+     * artFindInterfaceMethodInCacheFromCode will attempt to locate the target and return a 64-bit
+     * result in r0/r1 consisting of the target Method* in r0 and method->code_ in r1.
      *
-     * If unsuccessful, artFindInterfaceMethodInCache will return
-     * NULL/NULL.  This is somewhat different than the usual
-     * mechanism of helper routines performing the unwind & throw.
-     * The reason is that this trampoline is not unwindable.  In the
-     * event artFindInterfaceMethodInCache fails to resolve, the wrapper
-     * will prepare an unwindable environment and jump to another helper
-     * to do unwind/throw.
+     * If unsuccessful, artFindInterfaceMethodInCacheFromCode will return NULL/NULL. There will be
+     * a pending exception in the thread and we branch to another stub to deliver it.
      *
-     * On success this wrapper will restore arguments and *jump* to the
-     * target, leaving the lr pointing back to the original caller.
+     * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
+     * pointing back to the original caller.
      */
+art_invoke_interface_trampoline:
+    str    sp, [R9, #THREAD_TOP_OF_MANAGED_STACK_OFFSET]    @ record top of stack and pc in case of
+    str    lr, [R9, #THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET] @ walking stack
     stmdb  sp!, {r1, r2, r3, lr}
-    ldr    r2, [sp, #16]                 @ load caller's Method*
-    bl     artFindInterfaceMethodInCache @ (method_idx, this, callerMethod)
-    mov    r12, r1                       @ save r0->code_
-    ldmia  sp!, {r1, r2, r3, lr}         @ restore arguments
-    cmp    r0, #0                        @ did we find the target?
-    bxne   r12                           @ tail call to target if so
-    b      artFailedInvokeInterface      @ Will appear as if called directly
+    ldr    r2, [sp, #16]                         @ load caller's Method*
+    bl     artFindInterfaceMethodInCacheFromCode @ (method_idx, this, callerMethod)
+    mov    r12, r1                               @ save r0->code_
+    ldmia  sp!, {r1, r2, r3, lr}                 @ restore arguments
+    cmp    r0, #0                                @ did we find the target?
+    bxne   r12                                   @ tail call to target if so
+                                                 @ set up for throwing exception
+    stmdb  sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
+    sub    sp, #16                               @ 4 words of space, bottom word will hold Method*
+    mov    r0, r9                                @ pass Thread::Current
+    mov    r1, sp                                @ pass SP
+    b      artDeliverPendingExceptionFromCode    @ artDeliverPendingExceptionFromCode(Thread*, SP)
+
+    .global art_handle_fill_data_from_code
+    .extern artHandleFillArrayDataFromCode
+    /*
+     * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
+     * failure.
+     */
+art_handle_fill_data_from_code:
+    str    sp, [R9, #THREAD_TOP_OF_MANAGED_STACK_OFFSET]    @ record top of stack and pc in case of
+    str    lr, [R9, #THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET] @ walking stack
+    stmdb  sp!, {lr}                          @ Save LR
+    sub    sp, #12                            @ Align stack
+    bl     artHandleFillArrayDataFromCode     @ (Array* array, const uint16_t* table)
+    add    sp, #12
+    ldmia  sp!, {lr}                          @ restore LR
+    cmp    r0, #0                             @ success?
+    moveq  pc, lr                             @ return on success
+                                              @ set up for throwing exception
+    stmdb  sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
+    sub    sp, #16                            @ 4 words of space, bottom word will hold Method*
+    mov    r0, r9                             @ pass Thread::Current
+    mov    r1, sp                             @ pass SP
+    b      artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
+
+    .global art_unlock_object_from_code
+    .extern artUnlockObjectFromCode
+    /*
+     * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
+     */
+art_unlock_object_from_code:
+    str    sp, [R9, #THREAD_TOP_OF_MANAGED_STACK_OFFSET]    @ record top of stack and pc in case of
+    str    lr, [R9, #THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET] @ walking stack
+    stmdb  sp!, {lr}                          @ Save LR
+    sub    sp, #12                            @ Align stack
+    bl     artUnlockObjectFromCode            @ (Thread* thread, Object* obj)
+    add    sp, #12
+    ldmia  sp!, {lr}                          @ restore LR
+    cmp    r0, #0                             @ success?
+    moveq  pc, lr                             @ return on success
+                                              @ set up for throwing exception
+    stmdb  sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
+    sub    sp, #16                            @ 4 words of space, bottom word will hold Method*
+    mov    r0, r9                             @ pass Thread::Current
+    mov    r1, sp                             @ pass SP
+    b      artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
+
+    .global art_check_cast_from_code
+    .extern artCheckCastFromCode
+    /*
+     * Entry from managed code that calls artCheckCastFromCode and delivers exception on failure.
+     */
+art_check_cast_from_code:
+    str    sp, [R9, #THREAD_TOP_OF_MANAGED_STACK_OFFSET]    @ record top of stack and pc in case of
+    str    lr, [R9, #THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET] @ walking stack
+    stmdb  sp!, {lr}                          @ Save LR
+    sub    sp, #12                            @ Align stack
+    bl     artCheckCastFromCode               @ (Class* a, Class* b)
+    add    sp, #12
+    ldmia  sp!, {lr}                          @ restore LR
+    cmp    r0, #0                             @ success?
+    moveq  pc, lr                             @ return on success
+                                              @ set up for throwing exception
+    stmdb  sp!, {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
+    sub    sp, #16                            @ 4 words of space, bottom word will hold Method*
+    mov    r0, r9                             @ pass Thread::Current
+    mov    r1, sp                             @ pass SP
+    b      artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
 
     .global art_shl_long
 art_shl_long:
@@ -180,14 +249,14 @@
 
 #if defined(__i386__)
 
-    .global art_deliver_exception
-    .extern artDeliverExceptionHelper
+    .global art_deliver_exception_from_code
+    .extern artDeliverExceptionFromCode
     /*
-     * Called by managed code, saves callee saves and then calls artThrowExceptionHelper
+     * Called by managed code, saves callee saves and then calls artThrowException
      * that will place a mock Method* at the bottom of the stack.
      * EAX holds the exception.
      */
-art_deliver_exception:
+art_deliver_exception_from_code:
     // Create frame
     pushl %edi  // Save callee saves
     pushl %esi
@@ -198,11 +267,11 @@
     pushl $0   // Will be clobbered to be Method*
     mov %esp, %ecx
     // Outgoing argument set up
-    pushl $0    // Alignment padding
-    pushl %ecx                      // pass SP
-    pushl %fs:THREAD_SELF_OFFSET    // pass fs:offsetof(Thread,self_)
-    pushl %eax                      // pass Throwable*
-    call artDeliverExceptionHelper  // artDeliverExceptionHelper(Throwable*, Thread*, SP)
+    pushl $0  // Alignment padding
+    pushl %ecx                        // pass SP
+    pushl %fs:THREAD_SELF_OFFSET      // pass fs:offsetof(Thread,self_)
+    pushl %eax                        // pass Throwable*
+    call artDeliverExceptionFromCode  // artDeliverExceptionFromCode(Throwable*, Thread*, SP)
     int3
 
 #endif
diff --git a/src/runtime_support.h b/src/runtime_support.h
index ed047c9..e7aeb74 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -4,10 +4,17 @@
 #define ART_SRC_RUNTIME_SUPPORT_H_
 
 /* Helper for both JNI and regular compiled code */
-extern "C" void art_deliver_exception(void*);
+extern "C" void art_deliver_exception_from_code(void*);
 
 #if defined(__arm__)
   /* Compiler helpers */
+  extern "C" void art_check_cast_from_code(void*, void*);
+  extern "C" void art_handle_fill_data_from_code(void*, void*);
+  extern "C" void art_invoke_interface_trampoline(void*, void*, void*, void*);
+  extern "C" void art_throw_array_bounds_from_code(int32_t index, int32_t limit);
+  extern "C" void art_throw_div_zero_from_code();
+  extern "C" void art_throw_null_pointer_exception_from_code();
+  extern "C" void art_unlock_object_from_code(void*, void*);
   extern "C" uint64_t art_shl_long(uint64_t, uint32_t);
   extern "C" uint64_t art_shr_long(uint64_t, uint32_t);
   extern "C" uint64_t art_ushr_long(uint64_t, uint32_t);
@@ -45,9 +52,9 @@
   extern "C" int __aeabi_idivmod(int op1, int op2);  // OP_REM_INT[_2ADDR|_LIT8|_LIT16]
   extern "C" int __aeabi_idiv(int op1, int op2);     // OP_DIV_INT[_2ADDR|_LIT8|_LIT16]
 
-/* Long long arithmetics - OP_REM_LONG[_2ADDR] & OP_DIV_LONG[_2ADDR] */
-extern "C" long long __aeabi_ldivmod(long long op1, long long op2);
-extern "C" long long __aeabi_lmul(long long op1, long long op2);
+  /* Long long arithmetics - OP_REM_LONG[_2ADDR] & OP_DIV_LONG[_2ADDR] */
+  extern "C" long long __aeabi_ldivmod(long long op1, long long op2);
+  extern "C" long long __aeabi_lmul(long long op1, long long op2);
 
 #endif
 
diff --git a/src/space.cc b/src/space.cc
index 38c5720..57983d5 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -117,6 +117,9 @@
   Object* jni_stub_array = image_header.GetImageRoot(ImageHeader::kJniStubArray);
   Runtime::Current()->SetJniStubArray(down_cast<ByteArray*>(jni_stub_array));
 
+  Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
+  Runtime::Current()->SetCalleeSaveMethod(down_cast<Method*>(callee_save_method));
+
   Init(map.release());
   return true;
 }
diff --git a/src/stub_arm.cc b/src/stub_arm.cc
index 986d2b0..79a581d 100644
--- a/src/stub_arm.cc
+++ b/src/stub_arm.cc
@@ -14,11 +14,15 @@
 ByteArray* CreateAbstractMethodErrorStub() {
   UniquePtr<ArmAssembler> assembler( static_cast<ArmAssembler*>(Assembler::Create(kArm)) );
 
-  // R0 is the Method* already.
+  // Save callee saves and ready frame for exception delivery
+  RegList save = (1 << R1) | (1 << R2) | (1 << R3) | (1 << R4) | (1 << R5) | (1 << R6) | (1 << R7) |
+                 (1 << R8) | (1 << R9) | (1 << R10) | (1 << R11) | (1 << LR);
+  __ PushList(save);
+  __ IncreaseFrameSize(16);  // 4 words of space, bottom word will hold callee save Method*
 
-  // Pass Thread::Current() in R1
-  __ mov(R1, ShifterOperand(R9));
-
+  // R0 is the Method* already
+  __ mov(R1, ShifterOperand(R9));  // Pass Thread::Current() in R1
+  __ mov(R2, ShifterOperand(SP));  // Pass SP in R2
   // Call to throw AbstractMethodError
   __ LoadFromOffset(kLoadWord, R12, TR, OFFSETOF_MEMBER(Thread, pThrowAbstractMethodErrorFromCode));
   // Leaf call to routine that never returns
diff --git a/src/thread.cc b/src/thread.cc
index 8ab10af..857d44d 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -63,12 +63,8 @@
   LOG(INFO) << "Info: " << info;
 }
 
-}  // namespace art
-
 // Called by generated call to throw an exception
-extern "C" void artDeliverExceptionHelper(art::Throwable* exception,
-                                          art::Thread* thread,
-                                          art::Method** sp) {
+extern "C" void artDeliverExceptionFromCode(Throwable* exception, Thread* thread, Method** sp) {
   /*
    * exception may be NULL, in which case this routine should
    * throw NPE.  NOTE: this is a convenience for generated code,
@@ -77,51 +73,94 @@
    * exception_ in thread and delivering the exception.
    */
   // Place a special frame at the TOS that will save all callee saves
-  *sp = thread->CalleeSaveMethod();
+  *sp = Runtime::Current()->GetCalleeSaveMethod();
   thread->SetTopOfStack(sp, 0);
   if (exception == NULL) {
     thread->ThrowNewException("Ljava/lang/NullPointerException;", "throw with null exception");
-    exception = thread->GetException();
+  } else {
+    thread->SetException(exception);
   }
-  thread->DeliverException(exception);
+  thread->DeliverException();
+}
+
+// Deliver an exception that's pending on thread helping set up a callee save frame on the way
+extern "C" void artDeliverPendingExceptionFromCode(Thread* thread, Method** sp) {
+  *sp = Runtime::Current()->GetCalleeSaveMethod();
+  thread->SetTopOfStack(sp, 0);
+  thread->DeliverException();
 }
 
 // Called by generated call to throw a NPE exception
-extern "C" void artThrowNullPointerExceptionFromCodeHelper(art::Thread* thread,
-                                                           art::Method** sp) {
+extern "C" void artThrowNullPointerExceptionFromCode(Thread* thread, Method** sp) {
   // Place a special frame at the TOS that will save all callee saves
-  *sp = thread->CalleeSaveMethod();
+  *sp = Runtime::Current()->GetCalleeSaveMethod();
   thread->SetTopOfStack(sp, 0);
   thread->ThrowNewException("Ljava/lang/NullPointerException;", "unexpected null reference");
-  art::Throwable* exception = thread->GetException();
-  thread->DeliverException(exception);
+  thread->DeliverException();
 }
 
 // Called by generated call to throw an arithmetic divide by zero exception
-extern "C" void artThrowDivZeroFromCodeHelper(art::Thread* thread,
-                                              art::Method** sp) {
+extern "C" void artThrowDivZeroFromCode(Thread* thread, Method** sp) {
   // Place a special frame at the TOS that will save all callee saves
-  *sp = thread->CalleeSaveMethod();
+  *sp = Runtime::Current()->GetCalleeSaveMethod();
   thread->SetTopOfStack(sp, 0);
   thread->ThrowNewException("Ljava/lang/ArithmeticException;", "divide by zero");
-  art::Throwable* exception = thread->GetException();
-  thread->DeliverException(exception);
+  thread->DeliverException();
 }
 
 // Called by generated call to throw an arithmetic divide by zero exception
-extern "C" void artThrowArrayBoundsFromCodeHelper(int index, int limit,
-                                                  art::Thread* thread,
-                                                  art::Method** sp) {
+extern "C" void artThrowArrayBoundsFromCode(int index, int limit, Thread* thread, Method** sp) {
   // Place a special frame at the TOS that will save all callee saves
-  *sp = thread->CalleeSaveMethod();
+  *sp = Runtime::Current()->GetCalleeSaveMethod();
   thread->SetTopOfStack(sp, 0);
   thread->ThrowNewException("Ljava/lang/ArrayIndexOutOfBoundsException;",
                             "length=%d; index=%d", limit, index);
-  art::Throwable* exception = thread->GetException();
-  thread->DeliverException(exception);
+  thread->DeliverException();
 }
 
-namespace art {
+// Called by the AbstractMethodError stub (not runtime support)
+void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp) {
+  *sp = Runtime::Current()->GetCalleeSaveMethod();
+  thread->SetTopOfStack(sp, 0);
+  thread->ThrowNewException("Ljava/lang/AbstractMethodError",
+                            "abstract method \"%s\"",
+                            PrettyMethod(method).c_str());
+  thread->DeliverException();
+}
+
+// TODO: placeholder
+void StackOverflowFromCode(Method* method) {
+  Thread::Current()->SetTopOfStackPC(reinterpret_cast<uintptr_t>(__builtin_return_address(0)));
+  Thread::Current()->Dump(std::cerr);
+  //NOTE: to save code space, this handler needs to look up its own Thread*
+  UNIMPLEMENTED(FATAL) << "Stack overflow: " << PrettyMethod(method);
+}
+
+// TODO: placeholder
+void ThrowVerificationErrorFromCode(int32_t src1, int32_t ref) {
+    UNIMPLEMENTED(FATAL) << "Verification error, src1: " << src1 <<
+        " ref: " << ref;
+}
+
+// TODO: placeholder
+void ThrowNegArraySizeFromCode(int32_t index) {
+    UNIMPLEMENTED(FATAL) << "Negative array size: " << index;
+}
+
+// TODO: placeholder
+void ThrowInternalErrorFromCode(int32_t errnum) {
+    UNIMPLEMENTED(FATAL) << "Internal error: " << errnum;
+}
+
+// TODO: placeholder
+void ThrowRuntimeExceptionFromCode(int32_t errnum) {
+    UNIMPLEMENTED(FATAL) << "Internal error: " << errnum;
+}
+
+// TODO: placeholder
+void ThrowNoSuchMethodFromCode(int32_t method_idx) {
+    UNIMPLEMENTED(FATAL) << "No such method, idx: " << method_idx;
+}
 
 // TODO: placeholder.  Helper function to type
 Class* InitializeTypeFromCode(uint32_t type_idx, Method* method) {
@@ -158,95 +197,39 @@
 }
 
 // TODO: placeholder (throw on failure)
-void CheckCastFromCode(const Class* a, const Class* b) {
+extern "C" int artCheckCastFromCode(const Class* a, const Class* b) {
   DCHECK(a->IsClass());
   DCHECK(b->IsClass());
   if (b->IsAssignableFrom(a)) {
-    return;
+    return 0;  // Success
+  } else {
+    Thread::Current()->ThrowNewException("Ljava/lang/ClassCastException;",
+                                         "%s cannot be cast to %s",
+                                         PrettyClass(b).c_str(), PrettyClass(a).c_str());
+    return -1;  // Failure
   }
-  UNIMPLEMENTED(FATAL);
 }
 
-void UnlockObjectFromCode(Thread* thread, Object* obj) {
-  // TODO: throw and unwind if lock not held
-  // TODO: throw and unwind on NPE
-  obj->MonitorExit(thread);
+extern "C" int artUnlockObjectFromCode(Thread* thread, Object* obj) {
+  DCHECK(obj != NULL);  // Assumed to have been checked before entry
+  return obj->MonitorExit(thread) ? 0 /* Success */ : -1 /* Failure */;
 }
 
 void LockObjectFromCode(Thread* thread, Object* obj) {
+  DCHECK(obj != NULL);  // Assumed to have been checked before entry
   obj->MonitorEnter(thread);
-  // TODO: throw and unwind on failure.
+  DCHECK(thread->HoldsLock(obj));
+  // Only possible exception is NPE and is handled before entry
+  DCHECK(thread->GetException() == NULL);
 }
 
 extern "C" void artCheckSuspendFromCode(Thread* thread) {
   Runtime::Current()->GetThreadList()->FullSuspendCheck(thread);
 }
 
-// TODO: placeholder
-void StackOverflowFromCode(Method* method) {
-  Thread::Current()->SetTopOfStackPC(reinterpret_cast<uintptr_t>(__builtin_return_address(0)));
-  Thread::Current()->Dump(std::cerr);
-  //NOTE: to save code space, this handler needs to look up its own Thread*
-  UNIMPLEMENTED(FATAL) << "Stack overflow: " << PrettyMethod(method);
-}
-
-// TODO: placeholder
-void ThrowNullPointerFromCode() {
-  Thread::Current()->SetTopOfStackPC(reinterpret_cast<uintptr_t>(__builtin_return_address(0)));
-  Thread::Current()->Dump(std::cerr);
-  //NOTE: to save code space, this handler must look up caller's Method*
-  UNIMPLEMENTED(FATAL) << "Null pointer exception";
-}
-
-// TODO: placeholder
-void ThrowDivZeroFromCode() {
-  UNIMPLEMENTED(FATAL) << "Divide by zero";
-}
-
-// TODO: placeholder
-void ThrowArrayBoundsFromCode(int32_t index, int32_t limit) {
-  UNIMPLEMENTED(FATAL) << "Bound check exception, idx: " << index << ", limit: " << limit;
-}
-
-// TODO: placeholder
-void ThrowVerificationErrorFromCode(int32_t src1, int32_t ref) {
-    UNIMPLEMENTED(FATAL) << "Verification error, src1: " << src1 <<
-        " ref: " << ref;
-}
-
-// TODO: placeholder
-void ThrowNegArraySizeFromCode(int32_t index) {
-    UNIMPLEMENTED(FATAL) << "Negative array size: " << index;
-}
-
-// TODO: placeholder
-void ThrowInternalErrorFromCode(int32_t errnum) {
-    UNIMPLEMENTED(FATAL) << "Internal error: " << errnum;
-}
-
-// TODO: placeholder
-void ThrowRuntimeExceptionFromCode(int32_t errnum) {
-    UNIMPLEMENTED(FATAL) << "Internal error: " << errnum;
-}
-
-// TODO: placeholder
-void ThrowNoSuchMethodFromCode(int32_t method_idx) {
-    UNIMPLEMENTED(FATAL) << "No such method, idx: " << method_idx;
-}
-
-void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread) {
-  thread->ThrowNewException("Ljava/lang/AbstractMethodError",
-                            "abstract method \"%s\"",
-                            PrettyMethod(method).c_str());
-  thread->DeliverException(thread->GetException());
-}
-
-
 /*
- * Temporary placeholder.  Should include run-time checks for size
- * of fill data <= size of array.  If not, throw arrayOutOfBoundsException.
- * As with other new "FromCode" routines, this should return to the caller
- * only if no exception has been thrown.
+ * Fill the array with predefined constant values, throwing exceptions if the array is null or
+ * not of sufficient length.
  *
  * NOTE: When dealing with a raw dex file, the data to be copied uses
  * little-endian ordering.  Require that oat2dex do any required swapping
@@ -259,38 +242,43 @@
  *  ubyte  data[size*width] table of data values (may contain a single-byte
  *                          padding at the end)
  */
-void HandleFillArrayDataFromCode(Array* array, const uint16_t* table) {
-    uint32_t size = (uint32_t)table[2] | (((uint32_t)table[3]) << 16);
-    uint32_t size_in_bytes = size * table[1];
-    if (static_cast<int32_t>(size) > array->GetLength()) {
-      ThrowArrayBoundsFromCode(array->GetLength(), size);
-    }
-    memcpy((char*)array + art::Array::DataOffset().Int32Value(),
-           (char*)&table[4], size_in_bytes);
-}
-
-/*
- * TODO: placeholder for a method that can be called by the
- * invoke-interface trampoline to unwind and handle exception.  The
- * trampoline will arrange it so that the caller appears to be the
- * callsite of the failed invoke-interface.  See comments in
- * runtime_support.S
- */
-extern "C" void artFailedInvokeInterface() {
-    UNIMPLEMENTED(FATAL) << "Unimplemented exception throw";
+extern "C" int artHandleFillArrayDataFromCode(Array* array, const uint16_t* table) {
+  DCHECK_EQ(table[0], 0x0300);
+  if (array == NULL) {
+    Thread::Current()->ThrowNewException("Ljava/lang/NullPointerException;",
+                                         "null array in fill array");
+    return -1;  // Error
+  }
+  DCHECK(array->IsArrayInstance() && !array->IsObjectArray());
+  uint32_t size = (uint32_t)table[2] | (((uint32_t)table[3]) << 16);
+  if (static_cast<int32_t>(size) > array->GetLength()) {
+    Thread::Current()->ThrowNewException("Ljava/lang/ArrayIndexOutOfBoundsException;",
+                                         "failed array fill. length=%d; index=%d",
+                                         array->GetLength(), size);
+    return -1;  // Error
+  }
+  uint16_t width = table[1];
+  uint32_t size_in_bytes = size * width;
+  memcpy((char*)array + Array::DataOffset().Int32Value(), (char*)&table[4], size_in_bytes);
+  return 0;  // Success
 }
 
 // See comments in runtime_support.S
-extern "C" uint64_t artFindInterfaceMethodInCache(uint32_t method_idx,
-     Object* this_object , Method* caller_method)
-{
+extern "C" uint64_t artFindInterfaceMethodInCacheFromCode(uint32_t method_idx,
+                                                          Object* this_object ,
+                                                          Method* caller_method) {
+  Thread* thread = Thread::Current();
   if (this_object == NULL) {
-    ThrowNullPointerFromCode();
+    thread->ThrowNewException("Ljava/lang/NullPointerException;",
+                              "null receiver during interface dispatch");
+    return 0;
   }
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Method* interface_method = class_linker->ResolveMethod(method_idx, caller_method, false);
   if (interface_method == NULL) {
-    UNIMPLEMENTED(FATAL) << "Could not resolve interface method. Throw error and unwind";
+    // Could not resolve interface method. Throw error and unwind
+    CHECK(thread->GetException() != NULL);
+    return 0;
   }
   Method* method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method);
   const void* code = method->GetCode();
@@ -363,20 +351,22 @@
   pFmod = fmod;
   pLdivmod = __aeabi_ldivmod;
   pLmul = __aeabi_lmul;
-  pThrowNullPointerFromCode = art_throw_null_pointer_exception_from_code;
-  pThrowArrayBoundsFromCode = art_throw_array_bounds_from_code;
-  pThrowDivZeroFromCode = art_throw_div_zero_from_code;
+  pCheckCastFromCode = art_check_cast_from_code;
+  pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
   pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
   pTestSuspendFromCode = art_test_suspend;
+  pThrowArrayBoundsFromCode = art_throw_array_bounds_from_code;
+  pThrowDivZeroFromCode = art_throw_div_zero_from_code;
+  pThrowNullPointerFromCode = art_throw_null_pointer_exception_from_code;
+  pUnlockObjectFromCode = art_unlock_object_from_code;
 #endif
-  pDeliverException = art_deliver_exception;
+  pDeliverException = art_deliver_exception_from_code;
   pF2l = F2L;
   pD2l = D2L;
   pAllocFromCode = Array::AllocFromCode;
   pCheckAndAllocFromCode = CheckAndAllocFromCode;
   pAllocObjectFromCode = Class::AllocObjectFromCode;
   pMemcpy = memcpy;
-  pHandleFillArrayDataFromCode = HandleFillArrayDataFromCode;
   pGet32Static = Field::Get32StaticFromCode;
   pSet32Static = Field::Set32StaticFromCode;
   pGet64Static = Field::Get64StaticFromCode;
@@ -388,9 +378,7 @@
   pResolveMethodFromCode = ResolveMethodFromCode;
   pInitializeStaticStorage = ClassLinker::InitializeStaticStorageFromCode;
   pInstanceofNonTrivialFromCode = Object::InstanceOf;
-  pCheckCastFromCode = CheckCastFromCode;
   pLockObjectFromCode = LockObjectFromCode;
-  pUnlockObjectFromCode = UnlockObjectFromCode;
   pFindInstanceFieldFromCode = Field::FindInstanceFieldFromCode;
   pCheckSuspendFromCode = artCheckSuspendFromCode;
   pStackOverflowFromCode = StackOverflowFromCode;
@@ -409,11 +397,11 @@
   size_t frame_size = GetMethod()->GetFrameSizeInBytes();
   DCHECK_NE(frame_size, 0u);
   DCHECK_LT(frame_size, 1024u);
-  byte* next_sp = reinterpret_cast<byte*>(sp_) +
-      frame_size;
+  byte* next_sp = reinterpret_cast<byte*>(sp_) + frame_size;
   sp_ = reinterpret_cast<Method**>(next_sp);
-  DCHECK(*sp_ == NULL ||
-         (*sp_)->GetClass()->GetDescriptor()->Equals("Ljava/lang/reflect/Method;"));
+  if(*sp_ != NULL) {
+    DCHECK_EQ((*sp_)->GetClass(), Method::GetMethodClass());
+  }
 }
 
 bool Frame::HasMethod() const {
@@ -421,8 +409,7 @@
 }
 
 uintptr_t Frame::GetReturnPC() const {
-  byte* pc_addr = reinterpret_cast<byte*>(sp_) +
-      GetMethod()->GetReturnPcOffsetInBytes();
+  byte* pc_addr = reinterpret_cast<byte*>(sp_) + GetMethod()->GetReturnPcOffsetInBytes();
   return *reinterpret_cast<uintptr_t*>(pc_addr);
 }
 
@@ -431,8 +418,7 @@
   Method* method = GetMethod();
   DCHECK(method != NULL);
   size_t frame_size = method->GetFrameSizeInBytes();
-  byte* save_addr = reinterpret_cast<byte*>(sp_) + frame_size -
-                    ((num + 1) * kPointerSize);
+  byte* save_addr = reinterpret_cast<byte*>(sp_) + frame_size - ((num + 1) * kPointerSize);
 #if defined(__i386__)
   save_addr -= kPointerSize;  // account for return address
 #endif
@@ -1187,7 +1173,7 @@
       break;
     }
     // last_tos should return Frame instead of sp?
-    frame.SetSP(reinterpret_cast<art::Method**>(record->last_top_of_managed_stack_));
+    frame.SetSP(reinterpret_cast<Method**>(record->last_top_of_managed_stack_));
     pc = record->last_top_of_managed_stack_pc_;
     record = record->link_;
   }
@@ -1312,41 +1298,6 @@
   UNIMPLEMENTED(FATAL);
 }
 
-Method* Thread::CalleeSaveMethod() const {
-  // TODO: we should only allocate this once
-  Method* method = Runtime::Current()->GetClassLinker()->AllocMethod();
-#if defined(__arm__)
-  method->SetCode(NULL, art::kThumb2, NULL);
-  method->SetFrameSizeInBytes(64);
-  method->SetReturnPcOffsetInBytes(60);
-  method->SetCoreSpillMask((1 << art::arm::R1) |
-                           (1 << art::arm::R2) |
-                           (1 << art::arm::R3) |
-                           (1 << art::arm::R4) |
-                           (1 << art::arm::R5) |
-                           (1 << art::arm::R6) |
-                           (1 << art::arm::R7) |
-                           (1 << art::arm::R8) |
-                           (1 << art::arm::R9) |
-                           (1 << art::arm::R10) |
-                           (1 << art::arm::R11) |
-                           (1 << art::arm::LR));
-  method->SetFpSpillMask(0);
-#elif defined(__i386__)
-  method->SetCode(NULL, art::kX86, NULL);
-  method->SetFrameSizeInBytes(32);
-  method->SetReturnPcOffsetInBytes(28);
-  method->SetCoreSpillMask((1 << art::x86::EBX) |
-                           (1 << art::x86::EBP) |
-                           (1 << art::x86::ESI) |
-                           (1 << art::x86::EDI));
-  method->SetFpSpillMask(0);
-#else
-  UNIMPLEMENTED(FATAL);
-#endif
-  return method;
-}
-
 class CatchBlockStackVisitor : public Thread::StackVisitor {
  public:
   CatchBlockStackVisitor(Class* to_find, Context* ljc)
@@ -1409,8 +1360,9 @@
   uint32_t native_method_count_;
 };
 
-void Thread::DeliverException(Throwable* exception) {
-  SetException(exception);  // Set exception on thread
+void Thread::DeliverException() {
+  Throwable *exception = GetException();  // Set exception on thread
+  CHECK(exception != NULL);
 
   Context* long_jump_context = GetLongJumpContext();
   CatchBlockStackVisitor catch_finder(exception->GetClass(), long_jump_context);
diff --git a/src/thread.h b/src/thread.h
index 212abdc..e198d9a 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -212,12 +212,12 @@
   void (*pSetObjStatic)(uint32_t, const Method*, Object*);
   void (*pCanPutArrayElementFromCode)(const Object*, const Class*);
   bool (*pInstanceofNonTrivialFromCode) (const Object*, const Class*);
-  void (*pCheckCastFromCode) (const Class*, const Class*);
+  void (*pCheckCastFromCode) (void*, void*);
   Method* (*pFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, struct DvmDex*);
-  void (*pUnlockObjectFromCode)(Thread*, Object*);
+  void (*pUnlockObjectFromCode)(void*, void*);
   void (*pLockObjectFromCode)(Thread*, Object*);
   void (*pDeliverException)(void*);
-  void (*pHandleFillArrayDataFromCode)(Array*, const uint16_t*);
+  void (*pHandleFillArrayDataFromCode)(void*, void*);
   Class* (*pInitializeTypeFromCode)(uint32_t, Method*);
   void (*pResolveMethodFromCode)(Method*, uint32_t);
   void (*pInvokeInterfaceTrampoline)(void*, void*, void*, void*);
@@ -234,7 +234,7 @@
   void (*pThrowRuntimeExceptionFromCode)(int32_t);
   void (*pThrowInternalErrorFromCode)(int32_t);
   void (*pThrowNoSuchMethodFromCode)(int32_t);
-  void (*pThrowAbstractMethodErrorFromCode)(Method* method, Thread* thread);
+  void (*pThrowAbstractMethodErrorFromCode)(Method* method, Thread* thread, Method** sp);
   void* (*pFindNativeMethod)(Thread* thread);
   Object* (*pDecodeJObjectInThread)(Thread* thread, jobject obj);
 
@@ -339,7 +339,7 @@
   }
 
   // Find catch block and perform long jump to appropriate exception handle
-  void DeliverException(Throwable* exception);
+  void DeliverException();
 
   Context* GetLongJumpContext();
 
@@ -358,10 +358,6 @@
     top_of_managed_stack_pc_ = pc;
   }
 
-  // Returns a special method that describes all callee saves being spilt to the
-  // stack.
-  Method* CalleeSaveMethod() const;
-
   void ThrowNewException(const char* exception_class_descriptor, const char* fmt, ...)
       __attribute__ ((format(printf, 3, 4)));
 
diff --git a/src/thread_arm.cc b/src/thread_arm.cc
index 8b0d9a4..52f1b20 100644
--- a/src/thread_arm.cc
+++ b/src/thread_arm.cc
@@ -1,11 +1,16 @@
 // Copyright 2011 Google Inc. All Rights Reserved.
 
-#include "macros.h"
 #include "thread.h"
 
+#include "asm_support.h"
+#include "macros.h"
+
 namespace art {
 
 void Thread::InitCpu() {
+  CHECK_EQ(THREAD_TOP_OF_MANAGED_STACK_OFFSET, OFFSETOF_MEMBER(Thread, top_of_managed_stack_));
+  CHECK_EQ(THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET,
+           OFFSETOF_MEMBER(Thread, top_of_managed_stack_pc_));
 }
 
 }  // namespace art