Complete OP_CONST_STRING, OP_CONST_CLASS

Added dummy ThrowException & ResolveTypeFromCode routines.  Fix
OP_CONST_STRING and OP_CONST_CLASS to be position independent.  Misc.
bug fixes.

Created a dummy ThrowException compiler run-time helper function.  It
should be replaced with the real version.

Change-Id: Iba6a11cf110d3da4fa36ca434fe1b2675b68434d
diff --git a/src/compiler/RuntimeUtilities.cc b/src/compiler/RuntimeUtilities.cc
index 53bd20e..298cef1 100644
--- a/src/compiler/RuntimeUtilities.cc
+++ b/src/compiler/RuntimeUtilities.cc
@@ -17,13 +17,14 @@
 #include "Dalvik.h"
 #include "CompilerInternals.h"
 
+namespace art {
 /* FIXME - codegen helper functions, move to art runtime proper */
 
 /*
  * Float/double conversion requires clamping to min and max of integer form.  If
  * target doesn't support this normally, use these.
  */
-int64_t artD2L(double d)
+int64_t D2L(double d)
 {
     static const double kMaxLong = (double)(s8)0x7fffffffffffffffULL;
     static const double kMinLong = (double)(s8)0x8000000000000000ULL;
@@ -37,7 +38,7 @@
         return (s8)d;
 }
 
-int64_t artF2L(float f)
+int64_t F2L(float f)
 {
     static const float kMaxLong = (float)(s8)0x7fffffffffffffffULL;
     static const float kMinLong = (float)(s8)0x8000000000000000ULL;
@@ -54,7 +55,7 @@
 /*
  * Temporary placeholder.  Should include run-time checks for size
  * of fill data <= size of array.  If not, throw arrayOutOfBoundsException.
- * As with other new "NoThrow" routines, this should return to the caller
+ * As with other new "FromCode" routines, this should return to the caller
  * only if no exception has been thrown.
  *
  * NOTE: When dealing with a raw dex file, the data to be copied uses
@@ -68,7 +69,7 @@
  *  ubyte  data[size*width] table of data values (may contain a single-byte
  *                          padding at the end)
  */
-void artHandleFillArrayDataNoThrow(Array* array, const uint16_t* table)
+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];
@@ -76,3 +77,5 @@
     memcpy((char*)array + art::Array::DataOffset().Int32Value(),
            (char*)&table[4], size_in_bytes);
 }
+
+} // namespace art
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc
index c8c7e34..2438719 100644
--- a/src/compiler/codegen/arm/ArchFactory.cc
+++ b/src/compiler/codegen/arm/ArchFactory.cc
@@ -36,6 +36,17 @@
 #endif
 }
 
+static int loadCurrMethod(CompilationUnit *cUnit)
+{
+#if defined(METHOD_IN_REG)
+    return rMETHOD;
+#else
+    int mReg = oatAllocTemp(cUnit);
+    loadCurrMethodDirect(cUnit, mReg);
+    return mReg;
+#endif
+}
+
 /*
  * Perform a "reg cmp imm" operation and jump to the PCR region if condition
  * satisfies.
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index c4b30b2..c69a27e 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -559,6 +559,8 @@
     for (int i = 0; i < 3; i++) {
         if (args[i] != INVALID_REG) {
             RegLocation rlArg = oatGetSrc(cUnit, mir, i);
+            // Arguments are treated as a series of untyped 32-bit values.
+            rlArg.wide = false;
             loadValueDirectFixed(cUnit, rlArg, r1 + i);
             callState = nextCallInsn(cUnit, mir, dInsn, callState);
         }
@@ -579,7 +581,7 @@
 static int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir,
                                  DecodedInstruction* dInsn, int state)
 {
-    UNIMPLEMENTED(FATAL) << "Update with new cache model";
+    UNIMPLEMENTED(FATAL) << "Need findInterfaceMethodInCache";
 #if 0
     RegLocation rlArg;
     switch(state) {
@@ -628,7 +630,7 @@
 static int nextSuperCallInsn(CompilationUnit* cUnit, MIR* mir,
                              DecodedInstruction* dInsn, int state)
 {
-    UNIMPLEMENTED(FATAL) << "Update with new cache model";
+    UNIMPLEMENTED(FATAL) << "Need INVOKE_SUPER implementation";
 #if 0
     RegLocation rlArg;
     switch(state) {
@@ -763,10 +765,10 @@
      * Make sure range list doesn't span the break between in normal
      * Dalvik vRegs and the ins.
      */
-    int highestVreg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
-    if (highestVreg >= cUnit->method->num_registers_ -
-        cUnit->method->num_ins_) {
-        LOG(FATAL) << "Wide argument spanned locals & args";
+    int highestArg = oatGetSrc(cUnit, mir, numArgs-1).sRegLow;
+    int boundaryReg = cUnit->method->num_registers_ - cUnit->method->num_ins_;
+    if ((firstArg < boundaryReg) && (highestArg >= boundaryReg)) {
+        LOG(FATAL) << "Argument list spanned locals & args";
     }
 
     /*
@@ -777,11 +779,21 @@
      */
     // Scan the rest of the args - if in physReg flush to memory
     for (int i = 4; i < numArgs; i++) {
-        RegLocation loc = oatUpdateLoc(cUnit,
-            oatGetSrc(cUnit, mir, i));
-        if (loc.location == kLocPhysReg) {  // TUNING: if dirty?
-            storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
-            callState = nextCallInsn(cUnit, mir, dInsn, callState);
+        RegLocation loc = oatGetSrc(cUnit, mir, i);
+        //TODO: generic loc flushing routine
+        if (loc.wide) {
+            loc = oatUpdateLocWide(cUnit, loc);
+            if (loc.location == kLocPhysReg) {  // TUNING: if dirty?
+                storeBaseDispWide(cUnit, rSP, loc.spOffset, loc.lowReg,
+                                  loc.highReg);
+                callState = nextCallInsn(cUnit, mir, dInsn, callState);
+            }
+        } else {
+            loc = oatUpdateLoc(cUnit, loc);
+            if (loc.location == kLocPhysReg) {  // TUNING: if dirty?
+                storeBaseDisp(cUnit, rSP, loc.spOffset, loc.lowReg, kWord);
+                callState = nextCallInsn(cUnit, mir, dInsn, callState);
+            }
         }
     }
 
@@ -799,11 +811,11 @@
         int regsLeft = std::min(numArgs - 3, 16);
         callState = nextCallInsn(cUnit, mir, dInsn, callState);
         opRegRegImm(cUnit, kOpAdd, r3, rSP, startOffset);
-        newLIR3(cUnit, kThumb2Vldms, r3, fr0 & FP_REG_MASK, regsLeft);
+        newLIR3(cUnit, kThumb2Vldms, r3, fr0, regsLeft);
         callState = nextCallInsn(cUnit, mir, dInsn, callState);
         opRegRegImm(cUnit, kOpAdd, r3, rSP, 4 /* Method* */ + (3 * 4));
         callState = nextCallInsn(cUnit, mir, dInsn, callState);
-        newLIR3(cUnit, kThumb2Vstms, r3, fr0 & FP_REG_MASK, regsLeft);
+        newLIR3(cUnit, kThumb2Vstms, r3, fr0, regsLeft);
         callState = nextCallInsn(cUnit, mir, dInsn, callState);
     }
 
@@ -1287,7 +1299,7 @@
             genArrayPut(cUnit, mir, kWord, rlSrc[1], rlSrc[2], rlSrc[0], 2);
             break;
         case OP_APUT_OBJECT:
-            genArrayPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
+            genArrayObjPut(cUnit, mir, rlSrc[1], rlSrc[2], rlSrc[0], 2);
             break;
         case OP_APUT_SHORT:
         case OP_APUT_CHAR:
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 258b57b..11146f7 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -40,6 +40,14 @@
 }
 #endif
 
+/* Generate unconditional branch instructions */
+static ArmLIR* genUnconditionalBranch(CompilationUnit* cUnit, ArmLIR* target)
+{
+    ArmLIR* branch = opNone(cUnit, kOpUncondBr);
+    branch->generic.target = (LIR*) target;
+    return branch;
+}
+
 /*
  * Generate a Thumb2 IT instruction, which can nullify up to
  * four subsequent instructions based on a condition and its
@@ -341,7 +349,7 @@
     oatFlushAllRegs(cUnit);   /* Everything to home location */
     loadValueDirectFixed(cUnit, rlSrc, r0);
     loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pArtHandleFillArrayDataNoThrow), rLR);
+                 OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
     // Materialize a pointer to the fill data image
     newLIR3(cUnit, kThumb2AdrST, r1, 0, (intptr_t)tabRec);
     opReg(cUnit, kOpBlx, rLR);
@@ -496,33 +504,60 @@
 static void genConstClass(CompilationUnit* cUnit, MIR* mir,
                           RegLocation rlDest, RegLocation rlSrc)
 {
-    Class* classPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
-        GetResolvedType(mir->dalvikInsn.vB);
-
-    if (classPtr == NULL) {
-        LOG(FATAL) << "Unexpected null class pointer";
-    }
-
-    UNIMPLEMENTED(WARNING) << "Not position independent.  Fix";
+    art::Class* classPtr = cUnit->method->dex_cache_resolved_types_->
+        Get(mir->dalvikInsn.vB);
+    int mReg = loadCurrMethod(cUnit);
+    int resReg = oatAllocTemp(cUnit);
     RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-    loadConstantNoClobber(cUnit, rlResult.lowReg, (int) classPtr );
-    storeValue(cUnit, rlDest, rlResult);
+    loadWordDisp(cUnit, mReg, OFFSETOF_MEMBER(Method, dex_cache_strings_),
+                 resReg);
+    loadWordDisp(cUnit, resReg, Array::DataOffset().Int32Value() +
+                 (sizeof(String*) * mir->dalvikInsn.vB), rlResult.lowReg);
+    if (classPtr != NULL) {
+        // Fast path, we're done - just store result
+        storeValue(cUnit, rlDest, rlResult);
+    } else {
+        // Slow path.  Must test at runtime
+        ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, rlResult.lowReg,
+                                          0);
+        // Resolved, store and hop over following code
+        storeValue(cUnit, rlDest, rlResult);
+        ArmLIR* branch2 = genUnconditionalBranch(cUnit,0);
+        // TUNING: move slow path to end & remove unconditional branch
+        ArmLIR* target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
+        target1->defMask = ENCODE_ALL;
+        // Call out to helper, which will return resolved type in r0
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
+        genRegCopy(cUnit, r1, mReg);
+        loadConstant(cUnit, r0, mir->dalvikInsn.vB);
+        opReg(cUnit, kOpBlx, rLR); // resolveTypeFromCode(idx, method)
+        oatClobberCallRegs(cUnit);
+        RegLocation rlResult = oatGetReturn(cUnit);
+        storeValue(cUnit, rlDest, rlResult);
+        // Rejoin code paths
+        ArmLIR* target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
+        target2->defMask = ENCODE_ALL;
+        branch1->generic.target = (LIR*)target1;
+        branch2->generic.target = (LIR*)target2;
+    }
 }
 
 static void genConstString(CompilationUnit* cUnit, MIR* mir,
                            RegLocation rlDest, RegLocation rlSrc)
 {
-    const String* strPtr = cUnit->method->GetDeclaringClass()->GetDexCache()->
-        GetResolvedString(mir->dalvikInsn.vB);
+    /* All strings should be available at compile time */
+    const art::String* str = cUnit->method->dex_cache_strings_->
+        Get(mir->dalvikInsn.vB);
+    DCHECK(str != NULL);
 
-    if (strPtr == NULL) {
-        /* Shouldn't happen */
-        LOG(FATAL) << "Unexpected null const string pointer";
-    }
-
-    UNIMPLEMENTED(WARNING) << "Not position indendent.  Fix";
+    int mReg = loadCurrMethod(cUnit);
+    int resReg = oatAllocTemp(cUnit);
     RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-    loadConstantNoClobber(cUnit, rlResult.lowReg, (int) strPtr );
+    loadWordDisp(cUnit, mReg, OFFSETOF_MEMBER(Method, dex_cache_strings_),
+                 resReg);
+    loadWordDisp(cUnit, resReg, Array::DataOffset().Int32Value() +
+                 (sizeof(String*) * mir->dalvikInsn.vB), rlResult.lowReg);
     storeValue(cUnit, rlDest, rlResult);
 }
 
@@ -547,10 +582,10 @@
 void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
 {
     loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pArtAllocObjectNoThrow), rLR);
-    loadValueDirectFixed(cUnit, rlSrc, r1);  /* Exception object */
+                 OFFSETOF_MEMBER(Thread, pThrowException), rLR);
+    loadValueDirectFixed(cUnit, rlSrc, r1);  // Get exception object
     genRegCopy(cUnit, r0, rSELF);
-    opReg(cUnit, kOpBlx, rLR);
+    opReg(cUnit, kOpBlx, rLR); // artThrowException(thread, exception);
 }
 
 static void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
@@ -574,7 +609,7 @@
     loadWordDisp(cUnit, r0, OFFSETOF_MEMBER(Object, klass_), r1);
     /* r1 now contains object->clazz */
     loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pArtInstanceofNonTrivial), rLR);
+                 OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
     loadConstant(cUnit, r0, 1);                /* Assume true */
     opRegReg(cUnit, kOpCmp, r1, r2);
     ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq);
@@ -614,7 +649,7 @@
     /* r0 now contains object->clazz */
     loadWordDisp(cUnit, rlSrc.lowReg, OFFSETOF_MEMBER(Object, klass_), r0);
     loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pArtInstanceofNonTrivialNoThrow), rLR);
+                 OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
     opRegReg(cUnit, kOpCmp, r0, r1);
     ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq);
     // Assume success - if not, artInstanceOfNonTrivial will handle throw
@@ -782,8 +817,8 @@
     hopTarget->defMask = ENCODE_ALL;
     hopBranch->generic.target = (LIR*)hopTarget;
 
-    // Go expensive route - artLockObjectNoThrow(self, obj);
-    loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pArtLockObjectNoThrow),
+    // Go expensive route - artLockObjectFromCode(self, obj);
+    loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
                  rLR);
     genRegCopy(cUnit, r0, rSELF);
     newLIR1(cUnit, kThumbBlxR, rLR);
@@ -832,8 +867,8 @@
     hopTarget->defMask = ENCODE_ALL;
     hopBranch->generic.target = (LIR*)hopTarget;
 
-    // Go expensive route - artUnlockObjectNoThrow(self, obj);
-    loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pArtUnlockObjectNoThrow),
+    // Go expensive route - UnlockObjectFromCode(self, obj);
+    loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
                  rLR);
     genRegCopy(cUnit, r0, rSELF);
     newLIR1(cUnit, kThumbBlxR, rLR);
@@ -1057,13 +1092,13 @@
                                      2, 1);
         case OP_FLOAT_TO_LONG:
             return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
-                                     pArtF2l), 1, 2);
+                                     pF2l), 1, 2);
         case OP_LONG_TO_FLOAT:
             return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2f),
                                      2, 1);
         case OP_DOUBLE_TO_LONG:
             return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread,
-                                     pArtD2l), 2, 2);
+                                     pD2l), 2, 2);
         case OP_LONG_TO_DOUBLE:
             return genConversionCall(cUnit, mir, OFFSETOF_MEMBER(Thread, pL2d),
                                      2, 2);
@@ -1095,9 +1130,9 @@
  * Generate array store
  *
  */
-static void genArrayPut(CompilationUnit* cUnit, MIR* mir,
-                              RegLocation rlArray, RegLocation rlIndex,
-                              RegLocation rlSrc, int scale)
+static void genArrayObjPut(CompilationUnit* cUnit, MIR* mir,
+                           RegLocation rlArray, RegLocation rlIndex,
+                           RegLocation rlSrc, int scale)
 {
     RegisterClass regClass = oatRegClassBySize(kWord);
     int lenOffset = Array::LengthOffset().Int32Value();
@@ -1115,7 +1150,7 @@
                                 mir->offset, NULL);
     }
     loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pArtCanPutArrayElementNoThrow), rLR);
+                 OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode), rLR);
     /* Get the array's clazz */
     loadWordDisp(cUnit, r1, OFFSETOF_MEMBER(Object, klass_), r1);
     /* Get the object's clazz */
@@ -1546,14 +1581,6 @@
     return false;
 }
 
-/* Generate unconditional branch instructions */
-static ArmLIR* genUnconditionalBranch(CompilationUnit* cUnit, ArmLIR* target)
-{
-    ArmLIR* branch = opNone(cUnit, kOpUncondBr);
-    branch->generic.target = (LIR*) target;
-    return branch;
-}
-
 /*
  * Fetch *self->info.breakFlags. If the breakFlags are non-zero,
  * punt to the interpreter.
diff --git a/src/compiler_test.cc b/src/compiler_test.cc
index eca5b2a..305b0d8 100644
--- a/src/compiler_test.cc
+++ b/src/compiler_test.cc
@@ -165,6 +165,20 @@
                         10);
 }
 
+TEST_F(CompilerTest, ConstStringTest) {
+  AssertStaticIntMethod(LoadDex("IntMath"), "IntMath", "constStringTest",
+                                "(I)I", 2468, 1234);
+}
+
+TEST_F(CompilerTest, DISABLED_CatchTest) {
+  CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
+  CompileDirectMethod(NULL, "java.lang.NullPointerException", "<init>", "()V");
+  const ClassLoader* class_loader = LoadDex("IntMath");
+  CompileDirectMethod(class_loader, "IntMath", "throwNullPointerException", "()V");
+  AssertStaticIntMethod(class_loader, "IntMath", "catchBlock", "(I)I", 1579,
+                        1000);
+}
+
 TEST_F(CompilerTest, StaticFieldTest) {
   AssertStaticIntMethod(LoadDex("IntMath"), "IntMath", "staticFieldTest", "(I)I", 1404,
                         404);
diff --git a/src/java_lang_System.cc b/src/java_lang_System.cc
index e874987..43335ac 100644
--- a/src/java_lang_System.cc
+++ b/src/java_lang_System.cc
@@ -213,14 +213,14 @@
   Class* initialElementClass = NULL;
   if (length > 0 && srcObj[0] != NULL) {
     initialElementClass = srcObj[0]->GetClass();
-    if (!Class::CanPutArrayElementNoThrow(initialElementClass, dstClass)) {
+    if (!Class::CanPutArrayElementFromCode(initialElementClass, dstClass)) {
       initialElementClass = NULL;
     }
   }
 
   int copyCount;
   for (copyCount = 0; copyCount < length; copyCount++) {
-    if (srcObj[copyCount] != NULL && srcObj[copyCount]->GetClass() != initialElementClass && !Class::CanPutArrayElementNoThrow(srcObj[copyCount]->GetClass(), dstClass)) {
+    if (srcObj[copyCount] != NULL && srcObj[copyCount]->GetClass() != initialElementClass && !Class::CanPutArrayElementFromCode(srcObj[copyCount]->GetClass(), dstClass)) {
       // Can't put this element into the array.
       // We'll copy up to this point, then throw.
       break;
diff --git a/src/object.cc b/src/object.cc
index b71707f..cdc0e69 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -63,7 +63,7 @@
   return Heap::AllocObject(this, this->object_size_);
 }
 
-bool Class::CanPutArrayElementNoThrow(const Class* elementClass, const Class* arrayClass) {
+bool Class::CanPutArrayElementFromCode(const Class* elementClass, const Class* arrayClass) {
   UNIMPLEMENTED(FATAL);
   return false;
 }
diff --git a/src/object.h b/src/object.h
index 5ae90c9..bc6e7e5 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1123,7 +1123,7 @@
     return that->IsPublic() || this->IsInSamePackage(that);
   }
 
-  static bool CanPutArrayElementNoThrow(const Class* elementClass, const Class* arrayClass);
+  static bool CanPutArrayElementFromCode(const Class* elementClass, const Class* arrayClass);
 
   // Returns the number of static, private, and constructor methods.
   size_t NumDirectMethods() const {
diff --git a/src/runtime_support.h b/src/runtime_support.h
index b586042..8d65aaa 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -8,8 +8,6 @@
   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);
-  extern int64_t artD2L(double);
-  extern int64_t artF2L(float);
 
   /* Conversions */
   extern "C" float __aeabi_i2f(int op1);             // OP_INT_TO_FLOAT
@@ -45,6 +43,10 @@
 
 #endif
 
-  extern void artHandleFillArrayDataNoThrow(art::Array*, const uint16_t*);
+namespace art {
+  int64_t D2L(double);
+  int64_t F2L(float);
+  void HandleFillArrayDataFromCode(art::Array*, const uint16_t*);
+}
 
 #endif  // ART_SRC_RUNTIME_SUPPORT_H_
diff --git a/src/thread.cc b/src/thread.cc
index e3157f8..89ec844 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -32,6 +32,30 @@
 
 pthread_key_t Thread::pthread_key_self_;
 
+// TODO: placeholder.  This is what generated code will call to throw
+static void ThrowException(Thread* thread, Throwable* exception) {
+    /*
+     * exception may be NULL, in which case this routine should
+     * throw NPE.  NOTE: this is a convenience for generated code,
+     * which previuosly did the null check inline and constructed
+     * and threw a NPE if NULL.  This routine responsible for setting
+     * exception_ in thread.
+     */
+    UNIMPLEMENTED(FATAL) << "Unimplemented exception throw";
+}
+
+// TODO: placeholder.  Helper function to type
+static Class* InitializeTypeFromCode(uint32_t type_idx, Method* method) {
+  /*
+   * Should initialize & fix up method->dex_cache_resolved_types_[].
+   * Returns initialized type.  Does not return normally if an exception
+   * is thrown, but instead initiates the catch.  Should be similar to
+   * ClassLinker::InitializeStaticStorageFromCode.
+   */
+  UNIMPLEMENTED(FATAL);
+  return NULL;
+}
+
 void Thread::InitFunctionPointers() {
 #if defined(__arm__)
   pShlLong = art_shl_long;
@@ -56,32 +80,33 @@
   pDdiv = __aeabi_ddiv;
   pDmul = __aeabi_dmul;
   pFmod = fmod;
-  pArtF2l = artF2L;
-  pArtD2l = artD2L;
+  pF2l = F2L;
+  pD2l = D2L;
   pLdivmod = __aeabi_ldivmod;
   pLmul = __aeabi_lmul;
 #endif
   pAllocFromCode = Array::AllocFromCode;
   pAllocObjectFromCode = Class::AllocObjectFromCode;
   pMemcpy = memcpy;
-  pArtHandleFillArrayDataNoThrow = artHandleFillArrayDataNoThrow;
+  pHandleFillArrayDataFromCode = HandleFillArrayDataFromCode;
   pGet32Static = Field::Get32StaticFromCode;
   pSet32Static = Field::Set32StaticFromCode;
   pGet64Static = Field::Get64StaticFromCode;
   pSet64Static = Field::Set64StaticFromCode;
   pGetObjStatic = Field::GetObjStaticFromCode;
   pSetObjStatic = Field::SetObjStaticFromCode;
-  pArtCanPutArrayElementNoThrow = Class::CanPutArrayElementNoThrow;
+  pCanPutArrayElementFromCode = Class::CanPutArrayElementFromCode;
+  pThrowException = ThrowException;
+  pInitializeTypeFromCode = InitializeTypeFromCode;
 #if 0
-bool (Thread::*pArtUnlockObject)(Thread*, Object*);
-int (Thread::*pArtInstanceofNonTrivialNoThrow)(const Class*, const Class*);
-int (Thread::*pArtInstanceofNonTrivial) (const Class*, const Class*);
-Method* (Thread::*pArtFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, DvmDex*);
-bool (Thread::*pArtUnlockObjectNoThrow)(Thread*, Object*);
-void (Thread::*pArtLockObjectNoThrow)(Thread*, Object*);
-Object* (Thread::*pArtAllocObjectNoThrow)(Class*, int);
-void (Thread::*pArtThrowException)(Thread*, Object*);
-bool (Thread::*pArtHandleFillArrayDataNoThrow)(Array*, const uint16_t*);
+bool (Thread::*pUnlockObject)(Thread*, Object*);
+int (Thread::*pInstanceofNonTrivialFromCode)(const Class*, const Class*);
+Method* (Thread::*pFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, DvmDex*);
+bool (Thread::*pUnlockObjectFromCode)(Thread*, Object*);
+void (Thread::*pLockObjectFromCode)(Thread*, Object*);
+Object* (Thread::*pAllocObjectFromCode)(Class*, int);
+void (Thread::*pThrowException)(Thread*, Object*);
+bool (Thread::*pHandleFillArrayDataFromCode)(Array*, const uint16_t*);
 #endif
 }
 
diff --git a/src/thread.h b/src/thread.h
index 4f2d8c8..ab0660e 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -184,8 +184,8 @@
   int (*pD2iz)(double);
   float (*pL2f)(long);
   double (*pL2d)(long);
-  long long (*pArtF2l)(float);
-  long long (*pArtD2l)(double);
+  long long (*pF2l)(float);
+  long long (*pD2l)(double);
   float (*pFadd)(float, float);
   float (*pFsub)(float, float);
   float (*pFdiv)(float, float);
@@ -208,16 +208,14 @@
   void (*pSet64Static)(uint32_t, const Method*, uint64_t);
   Object* (*pGetObjStatic)(uint32_t, const Method*);
   void (*pSetObjStatic)(uint32_t, const Method*, Object*);
-  bool (*pArtUnlockObject)(Thread*, Object*);
-  bool (*pArtCanPutArrayElementNoThrow)(const Class*, const Class*);
-  int (*pArtInstanceofNonTrivialNoThrow) (const Class*, const Class*);
-  int (*pArtInstanceofNonTrivial) (const Class*, const Class*);
-  Method* (*pArtFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, struct DvmDex*);
-  bool (*pArtUnlockObjectNoThrow)(Thread*, Object*);
-  void (*pArtLockObjectNoThrow)(Thread*, Object*);
-  Object* (*pArtAllocObjectNoThrow)(Class*, int);
-  void (*pArtThrowException)(Thread*, Object*);
-  void (*pArtHandleFillArrayDataNoThrow)(Array*, const uint16_t*);
+  bool (*pCanPutArrayElementFromCode)(const Class*, const Class*);
+  int (*pInstanceofNonTrivialFromCode) (const Class*, const Class*);
+  Method* (*pFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, struct DvmDex*);
+  bool (*pUnlockObjectFromCode)(Thread*, Object*);
+  void (*pLockObjectFromCode)(Thread*, Object*);
+  void (*pThrowException)(Thread*, Throwable*);
+  void (*pHandleFillArrayDataFromCode)(Array*, const uint16_t*);
+  Class* (*pInitializeTypeFromCode)(uint32_t, Method*);
 
   class StackVisitor {
    public:
diff --git a/test/IntMath/IntMath.java b/test/IntMath/IntMath.java
index c13a79a..0d52ffc 100644
--- a/test/IntMath/IntMath.java
+++ b/test/IntMath/IntMath.java
@@ -23,6 +23,26 @@
         foo_ = 123;
     }
 
+    static int constStringTest(int x) {
+        /* TODO: flesh this test out when we can call string library */
+        String str = "Hello World!";
+        return x * 2;
+    }
+
+    static void throwNullPointerException() {
+        throw new NullPointerException();
+    }
+
+    static int catchBlock(int x) {
+        try {
+            x += 123;
+            throwNullPointerException();
+        } catch (NullPointerException npe) {
+            x += 456;
+        }
+        return x;
+    }
+
     static int staticFieldTest(int x) {
         mBoolean1 = true;
         mBoolean2 = false;
@@ -801,5 +821,12 @@
         } else {
             System.out.printf("staticFieldTest FAILED: %d\n", res);
         }
+
+        res = catchBlock(1000);
+        if (res == 1579) {
+            System.out.printf("catchBlock PASSED\n");
+        } else {
+            System.out.printf("catchBlock FAILED: %d\n", res);
+        }
     }
 }