Support for unresolved types in new-instance during verification.

Also, ensure that classes that don't load are erroneous, warn early
about exceptions left on a thread by the verifier/compiler, factor out
slowpath checks for the compiler and fix the slowpath selector for
const-class.

This change causes more dex cache misses at runtime (more slowpath
execution). It also requires a "mm clean-oat".

Change-Id: I014b49ebdd7d8f7dd2e39cc0958fc0b708d58c4c
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 7098188..4e3888d 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -442,7 +442,7 @@
     loadWordDisp(cUnit, rSELF,
                  OFFSETOF_MEMBER(Thread, pFindInstanceFieldFromCode), rLR);
     loadConstant(cUnit, r0, fieldIdx);
-    callRuntimeHelper(cUnit, rLR);  // resolveTypeFromCode(idx, method)
+    callRuntimeHelper(cUnit, rLR);  // FindInstanceFieldFromCoderesolveTypeFromCode(idx, method)
     ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
     target->defMask = ENCODE_ALL;
     if (!EXERCISE_SLOWEST_FIELD_PATH) {
@@ -606,42 +606,46 @@
 STATIC void genConstClass(CompilationUnit* cUnit, MIR* mir,
                           RegLocation rlDest, RegLocation rlSrc)
 {
-    art::Class* classPtr = cUnit->method->GetDexCacheResolvedTypes()->
-        Get(mir->dalvikInsn.vB);
+    uint32_t type_idx = mir->dalvikInsn.vB;
     int mReg = loadCurrMethod(cUnit);
     int resReg = oatAllocTemp(cUnit);
     RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-    loadWordDisp(cUnit, mReg, Method::DexCacheResolvedTypesOffset().Int32Value(),
-                 resReg);
-    loadWordDisp(cUnit, resReg, Array::DataOffset().Int32Value() +
-                 (sizeof(String*) * mir->dalvikInsn.vB), rlResult.lowReg);
-    if (SLOW_TYPE_PATH || (classPtr == NULL)) {
-        // Fast path, we're done - just store result
-        storeValue(cUnit, rlDest, rlResult);
+    if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
+        // Check we have access to type_idx and if not throw IllegalAccessError
+        UNIMPLEMENTED(FATAL);
     } else {
-        // Slow path.  Must test at runtime
-        oatFlushAllRegs(cUnit);
-        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);
-        callRuntimeHelper(cUnit, rLR);
-        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;
+        // We're don't need access checks, load type from dex cache
+        int32_t dex_cache_offset = Method::DexCacheResolvedTypesOffset().Int32Value();
+        loadWordDisp(cUnit, mReg, dex_cache_offset, resReg);
+        int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
+        loadWordDisp(cUnit, resReg, offset_of_type, rlResult.lowReg);
+        if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->method, type_idx) ||
+            SLOW_TYPE_PATH) {
+            // Slow path, at runtime test if the type is null and if so initialize
+            oatFlushAllRegs(cUnit);
+            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, type_idx);
+            callRuntimeHelper(cUnit, rLR);
+            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;
+        } else {
+            // Fast path, we're done - just store result
+            storeValue(cUnit, rlDest, rlResult);
+        }
     }
 }
 
@@ -649,20 +653,19 @@
                            RegLocation rlDest, RegLocation rlSrc)
 {
     /* NOTE: Most strings should be available at compile time */
-    const art::String* str = cUnit->method->GetDexCacheStrings()->
-        Get(mir->dalvikInsn.vB);
-    if (SLOW_STRING_PATH || (str == NULL) || !cUnit->compiler->IsImage()) {
+    uint32_t string_idx = mir->dalvikInsn.vB;
+    int32_t offset_of_string = Array::DataOffset().Int32Value() + (sizeof(String*) * string_idx);
+    if (!cUnit->compiler->CanAssumeStringIsPresentInDexCache(cUnit->method, string_idx) ||
+        SLOW_STRING_PATH) {
+        // slow path, resolve string if not in dex cache
         oatFlushAllRegs(cUnit);
         oatLockCallTemps(cUnit); // Using explicit registers
         loadCurrMethodDirect(cUnit, r2);
-        loadWordDisp(cUnit, r2, Method::DexCacheStringsOffset().Int32Value(),
-                     r0);
+        loadWordDisp(cUnit, r2, Method::DexCacheStringsOffset().Int32Value(), r0);
         // Might call out to helper, which will return resolved string in r0
-        loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pResolveStringFromCode), rLR);
-        loadWordDisp(cUnit, r0, Array::DataOffset().Int32Value() +
-                 (sizeof(String*) * mir->dalvikInsn.vB), r0);
-        loadConstant(cUnit, r1, mir->dalvikInsn.vB);
+        loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pResolveStringFromCode), rLR);
+        loadWordDisp(cUnit, r0, offset_of_string, r0);
+        loadConstant(cUnit, r1, string_idx);
         opRegImm(cUnit, kOpCmp, r0, 0);  // Is resolved?
         genBarrier(cUnit);
         // For testing, always force through helper
@@ -677,10 +680,8 @@
         int mReg = loadCurrMethod(cUnit);
         int resReg = oatAllocTemp(cUnit);
         RegLocation rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-        loadWordDisp(cUnit, mReg, Method::DexCacheStringsOffset().Int32Value(),
-                     resReg);
-        loadWordDisp(cUnit, resReg, Array::DataOffset().Int32Value() +
-                    (sizeof(String*) * mir->dalvikInsn.vB), rlResult.lowReg);
+        loadWordDisp(cUnit, mReg, Method::DexCacheStringsOffset().Int32Value(), resReg);
+        loadWordDisp(cUnit, resReg, offset_of_string, rlResult.lowReg);
         storeValue(cUnit, rlDest, rlResult);
     }
 }
@@ -693,13 +694,17 @@
                            RegLocation rlDest)
 {
     oatFlushAllRegs(cUnit);    /* Everything to home location */
-    art::Class* classPtr = cUnit->method->GetDexCacheResolvedTypes()->
-        Get(mir->dalvikInsn.vB);
-    loadWordDisp(cUnit, rSELF, (classPtr != NULL)
-                 ? OFFSETOF_MEMBER(Thread, pAllocObjectFromCode)
-                 : OFFSETOF_MEMBER(Thread, pAllocObjectFromCodeSlowPath), rLR);
-    loadCurrMethodDirect(cUnit, r1);              // arg1 <= Method*
-    loadConstant(cUnit, r0, mir->dalvikInsn.vB);  // arg0 <- type_id
+    uint32_t type_idx = mir->dalvikInsn.vB;
+    // alloc will always check for resolution, do we also need to verify access because the
+    // verifier was unable to?
+    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
+        loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pAllocObjectFromCode), rLR);
+    } else {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pAllocObjectFromCodeWithAccessCheck), rLR);
+    }
+    loadCurrMethodDirect(cUnit, r1);    // arg1 <= Method*
+    loadConstant(cUnit, r0, type_idx);  // arg0 <- type_idx
     callRuntimeHelper(cUnit, rLR);
     RegLocation rlResult = oatGetReturn(cUnit);
     storeValue(cUnit, rlDest, rlResult);
@@ -708,8 +713,7 @@
 void genThrow(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
 {
     oatFlushAllRegs(cUnit);
-    loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pDeliverException), rLR);
+    loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pDeliverException), rLR);
     loadValueDirectFixed(cUnit, rlSrc, r0);  // Get exception object
     callRuntimeHelper(cUnit, rLR);  // art_deliver_exception(exception);
 }
@@ -720,30 +724,33 @@
     oatFlushAllRegs(cUnit);
     // May generate a call - use explicit registers
     oatLockCallTemps(cUnit);
-    art::Class* classPtr = cUnit->method->GetDexCacheResolvedTypes()->
-        Get(mir->dalvikInsn.vC);
-    int classReg = r2;   // Fixed usage
+    uint32_t type_idx = mir->dalvikInsn.vC;
     loadCurrMethodDirect(cUnit, r1);  // r1 <= current Method*
-    loadValueDirectFixed(cUnit, rlSrc, r0);  /* Ref */
-    loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(),
-                 classReg);
-    loadWordDisp(cUnit, classReg, Array::DataOffset().Int32Value() +
-                 (sizeof(String*) * mir->dalvikInsn.vC), classReg);
-    if (classPtr == NULL) {
-        // Generate a runtime test
-        ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
-        // Not resolved
-        // Call out to helper, which will return resolved type in r0
-        loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
-        loadConstant(cUnit, r0, mir->dalvikInsn.vC);
-        callRuntimeHelper(cUnit, rLR);  // resolveTypeFromCode(idx, method)
-        genRegCopy(cUnit, r2, r0); // Align usage with fast path
-        loadValueDirectFixed(cUnit, rlSrc, r0);  /* reload Ref */
-        // Rejoin code paths
-        ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
-        hopTarget->defMask = ENCODE_ALL;
-        hopBranch->generic.target = (LIR*)hopTarget;
+    loadValueDirectFixed(cUnit, rlSrc, r0);  // r0 <= ref
+    int classReg = r2;  // r2 will hold the Class*
+    if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
+        // Check we have access to type_idx and if not throw IllegalAccessError
+        UNIMPLEMENTED(FATAL);
+    } else {
+        // Load dex cache entry into classReg (r2)
+        loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
+        int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
+        loadWordDisp(cUnit, classReg, offset_of_type, classReg);
+        if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->method, type_idx)) {
+            // Need to test presence of type in dex cache at runtime
+            ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
+            // Not resolved
+            // Call out to helper, which will return resolved type in r0
+            loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
+            loadConstant(cUnit, r0, type_idx);
+            callRuntimeHelper(cUnit, rLR);  // resolveTypeFromCode(idx, method)
+            genRegCopy(cUnit, r2, r0); // Align usage with fast path
+            loadValueDirectFixed(cUnit, rlSrc, r0);  /* reload Ref */
+            // Rejoin code paths
+            ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
+            hopTarget->defMask = ENCODE_ALL;
+            hopBranch->generic.target = (LIR*)hopTarget;
+        }
     }
     /* r0 is ref, r2 is class.  If ref==null, use directly as bool result */
     ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
@@ -751,8 +758,7 @@
     DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
     loadWordDisp(cUnit, r0,  Object::ClassOffset().Int32Value(), r1);
     /* r0 is ref, r1 is ref->clazz, r2 is class */
-    loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
+    loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInstanceofNonTrivialFromCode), rLR);
     opRegReg(cUnit, kOpCmp, r1, r2);  // Same?
     genBarrier(cUnit);
     genIT(cUnit, kArmCondEq, "EE");   // if-convert the test
@@ -774,39 +780,41 @@
     oatFlushAllRegs(cUnit);
     // May generate a call - use explicit registers
     oatLockCallTemps(cUnit);
-    art::Class* classPtr = cUnit->method->GetDexCacheResolvedTypes()->
-        Get(mir->dalvikInsn.vB);
-    int classReg = r2;   // Fixed usage
+    uint32_t type_idx = mir->dalvikInsn.vB;
     loadCurrMethodDirect(cUnit, r1);  // r1 <= current Method*
-    loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(),
-                 classReg);
-    loadWordDisp(cUnit, classReg, Array::DataOffset().Int32Value() +
-                 (sizeof(String*) * mir->dalvikInsn.vB), classReg);
-    if (classPtr == NULL) {
-        // Generate a runtime test
-        ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
-        // Not resolved
-        // Call out to helper, which will return resolved type in r0
-        loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
-        loadConstant(cUnit, r0, mir->dalvikInsn.vB);
-        callRuntimeHelper(cUnit, rLR);  // resolveTypeFromCode(idx, method)
-        genRegCopy(cUnit, r2, r0); // Align usage with fast path
-        // Rejoin code paths
-        ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
-        hopTarget->defMask = ENCODE_ALL;
-        hopBranch->generic.target = (LIR*)hopTarget;
+    int classReg = r2;  // r2 will hold the Class*
+    if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method, type_idx)) {
+        // Check we have access to type_idx and if not throw IllegalAccessError
+        UNIMPLEMENTED(FATAL);
+    } else {
+        // Load dex cache entry into classReg (r2)
+        loadWordDisp(cUnit, r1, Method::DexCacheResolvedTypesOffset().Int32Value(), classReg);
+        int32_t offset_of_type = Array::DataOffset().Int32Value() + (sizeof(Class*) * type_idx);
+        loadWordDisp(cUnit, classReg, offset_of_type, classReg);
+        if (!cUnit->compiler->CanAssumeTypeIsPresentInDexCache(cUnit->method, type_idx)) {
+            // Need to test presence of type in dex cache at runtime
+            ArmLIR* hopBranch = genCmpImmBranch(cUnit, kArmCondNe, classReg, 0);
+            // Not resolved
+            // Call out to helper, which will return resolved type in r0
+            loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
+            loadConstant(cUnit, r0, type_idx);
+            callRuntimeHelper(cUnit, rLR);  // resolveTypeFromCode(idx, method)
+            genRegCopy(cUnit, r2, r0); // Align usage with fast path
+            // Rejoin code paths
+            ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
+            hopTarget->defMask = ENCODE_ALL;
+            hopBranch->generic.target = (LIR*)hopTarget;
+        }
     }
-    // At this point, r2 has class
-    loadValueDirectFixed(cUnit, rlSrc, r0);  /* Ref */
+    // At this point, classReg (r2) has class
+    loadValueDirectFixed(cUnit, rlSrc, r0);  // r0 <= ref
     /* Null is OK - continue */
     ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r0, 0);
     /* load object->clazz */
     DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
     loadWordDisp(cUnit, r0,  Object::ClassOffset().Int32Value(), r1);
     /* r1 now contains object->clazz */
-    loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pCheckCastFromCode), rLR);
+    loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pCheckCastFromCode), rLR);
     opRegReg(cUnit, kOpCmp, r1, r2);
     ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq); /* If equal, trivial yes */
     genRegCopy(cUnit, r0, r1);