Implement array allocation with access checks.

Change-Id: I0b2c0274087f3f7ed5b0b71c441e5d7e5a25f819
diff --git a/src/asm_support.h b/src/asm_support.h
index 95d4754..4d3569e 100644
--- a/src/asm_support.h
+++ b/src/asm_support.h
@@ -24,13 +24,13 @@
 #define rSELF r9
 #define rLR r14
 // Offset of field Thread::suspend_count_ verified in InitCpu
-#define THREAD_SUSPEND_COUNT_OFFSET 392
+#define THREAD_SUSPEND_COUNT_OFFSET 400
 // Offset of field Thread::exception_ verified in InitCpu
-#define THREAD_EXCEPTION_OFFSET 388
+#define THREAD_EXCEPTION_OFFSET 396
 
 #elif defined(__i386__)
 // Offset of field Thread::self_ verified in InitCpu
-#define THREAD_SELF_OFFSET 380
+#define THREAD_SELF_OFFSET 388
 #endif
 
 #endif  // ART_SRC_ASM_SUPPORT_H_
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 6f476f93..bb66451 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -58,11 +58,8 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
     } else {
-        UNIMPLEMENTED(WARNING) << "Need to check access of '"
-                               << PrettyMethod(cUnit->method_idx, *cUnit->dex_file)
-                               << "' to unresolved type " << type_idx;
         loadWordDisp(cUnit, rSELF,
-                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
+                     OFFSETOF_MEMBER(Thread, pAllocArrayFromCodeWithAccessCheck), rLR);
     }
     loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
     loadConstant(cUnit, r0, type_idx);            // arg0 <- type_id
@@ -84,15 +81,15 @@
     int elems = dInsn->vA;
     int typeId = dInsn->vB;
     oatFlushAllRegs(cUnit);    /* Everything to home location */
-    loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
-    if (!cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
-                                                     cUnit->dex_cache,
-                                                     *cUnit->dex_file,
-                                                     typeId)) {
-        UNIMPLEMENTED(WARNING) << "Need to check access of '"
-            << PrettyMethod(cUnit->method_idx, *cUnit->dex_file)
-            << "' to unresolved type " << typeId;
+    if (cUnit->compiler->CanAccessTypeWithoutChecks(cUnit->method_idx,
+                                                    cUnit->dex_cache,
+                                                    *cUnit->dex_file,
+                                                    typeId)) {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), rLR);
+    } else {
+        loadWordDisp(cUnit, rSELF,
+                     OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCodeWithAccessCheck), rLR);
     }
     loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
     loadConstant(cUnit, r0, typeId);              // arg0 <- type_id
diff --git a/src/object_test.cc b/src/object_test.cc
index ce19b9b..82f52de 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -182,7 +182,7 @@
       java_lang_dex_file_->GetIndexForStringId(*string_id));
   ASSERT_TRUE(type_id != NULL);
   uint32_t type_idx = java_lang_dex_file_->GetIndexForTypeId(*type_id);
-  Object* array = CheckAndAllocArrayFromCode(type_idx, sort, 3, Thread::Current());
+  Object* array = CheckAndAllocArrayFromCode(type_idx, sort, 3, Thread::Current(), false);
   EXPECT_TRUE(array->IsArrayInstance());
   EXPECT_EQ(3, array->AsArray()->GetLength());
   EXPECT_TRUE(array->GetClass()->IsArrayClass());
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index f73e621..63efbf7 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -637,9 +637,10 @@
 
 // Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
 // cannot be resolved, throw an error. If it can, use it to create an instance.
-extern "C" Object* artAllocObjectFromCode(uint32_t type_idx, Method* method,
-                                          Thread* self, Method** sp) {
-  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+// When verification/compiler hasn't been able to verify access, optionally perform an access
+// check.
+static Object* AllocObjectFromCode(uint32_t type_idx, Method* method, Thread* self,
+                                   bool access_check) {
   Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
   Runtime* runtime = Runtime::Current();
   if (UNLIKELY(klass == NULL)) {
@@ -649,6 +650,16 @@
       return NULL;  // Failure
     }
   }
+  if (access_check) {
+    Class* referrer = method->GetDeclaringClass();
+    if (UNLIKELY(!referrer->CanAccess(klass))) {
+      self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+                               "illegal class access: '%s' -> '%s'",
+                               PrettyDescriptor(referrer).c_str(),
+                               PrettyDescriptor(klass).c_str());
+      return NULL;  // Failure
+    }
+  }
   if (!runtime->GetClassLinker()->EnsureInitialized(klass, true)) {
     DCHECK(self->IsExceptionPending());
     return NULL;  // Failure
@@ -656,34 +667,67 @@
   return klass->AllocObject();
 }
 
+extern "C" Object* artAllocObjectFromCode(uint32_t type_idx, Method* method,
+                                          Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  return AllocObjectFromCode(type_idx, method, self, false);
+}
+
 extern "C" Object* artAllocObjectFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
                                                          Thread* self, Method** sp) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  return AllocObjectFromCode(type_idx, method, self, true);
+}
+
+// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
+// it cannot be resolved, throw an error. If it can, use it to create an array.
+// When verification/compiler hasn't been able to verify access, optionally perform an access
+// check.
+static Array* AllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
+                                  Thread* self, bool access_check) {
+  if (UNLIKELY(component_count < 0)) {
+    Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
+                                         component_count);
+    return NULL;  // Failure
+  }
   Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
-  Runtime* runtime = Runtime::Current();
-  if (UNLIKELY(klass == NULL)) {
-    klass = runtime->GetClassLinker()->ResolveType(type_idx, method);
-    if (klass == NULL) {
-      DCHECK(self->IsExceptionPending());
+  if (UNLIKELY(klass == NULL)) {  // Not in dex cache so try to resolve
+    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
+    if (klass == NULL) {  // Error
+      DCHECK(Thread::Current()->IsExceptionPending());
+      return NULL;  // Failure
+    }
+    CHECK(klass->IsArrayClass()) << PrettyClass(klass);
+  }
+  if (access_check) {
+    Class* referrer = method->GetDeclaringClass();
+    if (UNLIKELY(!referrer->CanAccess(klass))) {
+      self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+                               "illegal class access: '%s' -> '%s'",
+                               PrettyDescriptor(referrer).c_str(),
+                               PrettyDescriptor(klass).c_str());
       return NULL;  // Failure
     }
   }
-  Class* referrer = method->GetDeclaringClass();
-  if (UNLIKELY(!referrer->CanAccess(klass))) {
-    self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;", "illegal class access: '%s' -> '%s'",
-                             PrettyDescriptor(referrer).c_str(),
-                             PrettyDescriptor(klass).c_str());
-    return NULL;  // Failure
-  }
-  if (!runtime->GetClassLinker()->EnsureInitialized(klass, true)) {
-    DCHECK(self->IsExceptionPending());
-    return NULL;  // Failure
-  }
-  return klass->AllocObject();
+  return Array::Alloc(klass, component_count);
 }
 
+extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
+                                        Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  return AllocArrayFromCode(type_idx, method, component_count, self, false);
+}
+
+extern "C" Array* artAllocArrayFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
+                                                       int32_t component_count,
+                                                       Thread* self, Method** sp) {
+  FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+  return AllocArrayFromCode(type_idx, method, component_count, self, true);
+}
+
+// Helper function to alloc array for OP_FILLED_NEW_ARRAY
 Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
-                                     Thread* self) {
+                                  Thread* self, bool access_check) {
   if (UNLIKELY(component_count < 0)) {
     self->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", component_count);
     return NULL;  // Failure
@@ -708,38 +752,32 @@
     }
     return NULL;  // Failure
   } else {
+    if (access_check) {
+      Class* referrer = method->GetDeclaringClass();
+      if (UNLIKELY(!referrer->CanAccess(klass))) {
+        self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
+                                 "illegal class access: '%s' -> '%s'",
+                                 PrettyDescriptor(referrer).c_str(),
+                                 PrettyDescriptor(klass).c_str());
+        return NULL;  // Failure
+      }
+    }
     DCHECK(klass->IsArrayClass()) << PrettyClass(klass);
     return Array::Alloc(klass, component_count);
   }
 }
 
-// Helper function to alloc array for OP_FILLED_NEW_ARRAY
 extern "C" Array* artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method,
                                                int32_t component_count, Thread* self, Method** sp) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  return CheckAndAllocArrayFromCode(type_idx, method, component_count, self);
+  return CheckAndAllocArrayFromCode(type_idx, method, component_count, self, false);
 }
 
-// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
-// it cannot be resolved, throw an error. If it can, use it to create an array.
-extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
-                                        Thread* self, Method** sp) {
+extern "C" Array* artCheckAndAllocArrayFromCodeWithAccessCheck(uint32_t type_idx, Method* method,
+                                                               int32_t component_count,
+                                                               Thread* self, Method** sp) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
-  if (UNLIKELY(component_count < 0)) {
-    Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
-                                         component_count);
-    return NULL;  // Failure
-  }
-  Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
-  if (UNLIKELY(klass == NULL)) {  // Not in dex cache so try to resolve
-    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
-    if (klass == NULL) {  // Error
-      DCHECK(Thread::Current()->IsExceptionPending());
-      return NULL;  // Failure
-    }
-    CHECK(klass->IsArrayClass()) << PrettyClass(klass);
-  }
-  return Array::Alloc(klass, component_count);
+  return CheckAndAllocArrayFromCode(type_idx, method, component_count, self, true);
 }
 
 // Assignable test for code, won't throw.  Null and equality tests already performed
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 096e6ab..68e9587 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -26,7 +26,7 @@
 
 extern void CheckSuspendFromCode(Thread* thread);
 extern Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
-                                         Thread* self);
+                                         Thread* self, bool access_check);
 extern void DebugMe(Method* method, uint32_t info);
 extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
 extern Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, bool is_static);
@@ -73,9 +73,11 @@
   extern "C" void art_throw_verification_error_from_code(int32_t src1, int32_t ref);
   extern "C" void art_unlock_object_from_code(void*);
   extern "C" void* art_alloc_array_from_code(uint32_t, void*, int32_t);
+  extern "C" void* art_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
   extern "C" void* art_alloc_object_from_code(uint32_t type_idx, void* method);
   extern "C" void* art_alloc_object_from_code_with_access_check(uint32_t type_idx, void* method);
   extern "C" void* art_check_and_alloc_array_from_code(uint32_t, void*, int32_t);
+  extern "C" void* art_check_and_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
   extern "C" void* art_find_instance_field_from_code(uint32_t, void*);
   extern "C" void* art_find_static_field_from_code(uint32_t, void*);
   extern "C" void* art_get_obj_static_from_code(uint32_t, void*);
diff --git a/src/runtime_support_arm.S b/src/runtime_support_arm.S
index c73588e..cee9043 100644
--- a/src/runtime_support_arm.S
+++ b/src/runtime_support_arm.S
@@ -520,10 +520,27 @@
     bxne   lr                         @ return on success
     DELIVER_PENDING_EXCEPTION
 
+    .global art_alloc_array_from_code_with_access_check
+    .extern artAllocArrayFromCodeWithAccessCheck
+    /*
+     * Called by managed code to allocate an array when the caller doesn't know whether it has
+     * access to the created type
+     */
+art_alloc_array_from_code_with_access_check:
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
+    mov    r3, r9                     @ pass Thread::Current
+    str    sp, [sp, #0]               @ pass SP
+    @ artAllocArrayFromCodeWithAccessCheck(type_idx, method, component_count, Thread*, SP)
+    bl     artAllocArrayFromCodeWithAccessCheck
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    cmp    r0, #0                     @ success if result is non-null
+    bxne   lr                         @ return on success
+    DELIVER_PENDING_EXCEPTION
+
     .global art_check_and_alloc_array_from_code
     .extern artCheckAndAllocArrayFromCode
     /*
-     * Called by managed code to allocate an array
+     * Called by managed code to allocate an array in a special case for OP_FILLED_NEW_ARRAY
      */
 art_check_and_alloc_array_from_code:
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
@@ -536,6 +553,22 @@
     bxne   lr                         @ return on success
     DELIVER_PENDING_EXCEPTION
 
+    .global art_check_and_alloc_array_from_code_with_access_check
+    .extern artCheckAndAllocArrayFromCodeWithAccessCheck
+    /*
+     * Called by managed code to allocate an array in a special case for OP_FILLED_NEW_ARRAY
+     */
+art_check_and_alloc_array_from_code_with_access_check:
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
+    mov    r3, r9                     @ pass Thread::Current
+    str    sp, [sp, #0]               @ pass SP
+    @ artCheckAndAllocArrayFromCodeWithAccessCheck(type_idx, method, count, Thread* , SP)
+    bl     artCheckAndAllocArrayFromCodeWithAccessCheck
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    cmp    r0, #0                     @ success if result is non-null
+    bxne   lr                         @ return on success
+    DELIVER_PENDING_EXCEPTION
+
     .global art_test_suspend
     .extern artTestSuspendFromCode
     /*
diff --git a/src/thread.cc b/src/thread.cc
index 1a534f1..014e2f0 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -99,10 +99,12 @@
   pLdivmod = __aeabi_ldivmod;
   pLmul = __aeabi_lmul;
   pAllocArrayFromCode = art_alloc_array_from_code;
+  pAllocArrayFromCodeWithAccessCheck = art_alloc_array_from_code_with_access_check;
   pAllocObjectFromCode = art_alloc_object_from_code;
   pAllocObjectFromCodeWithAccessCheck = art_alloc_object_from_code_with_access_check;
   pCanPutArrayElementFromCode = art_can_put_array_element_from_code;
   pCheckAndAllocArrayFromCode = art_check_and_alloc_array_from_code;
+  pCheckAndAllocArrayFromCodeWithAccessCheck = art_check_and_alloc_array_from_code_with_access_check;
   pCheckCastFromCode = art_check_cast_from_code;
   pFindInstanceFieldFromCode = art_find_instance_field_from_code;
   pGet32Static = art_get32_static_from_code;
diff --git a/src/thread.h b/src/thread.h
index d612f62..bade52e 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -124,8 +124,10 @@
   void* (*pAllocObjectFromCode)(uint32_t, void*);
   void* (*pAllocObjectFromCodeWithAccessCheck)(uint32_t, void*);
   void* (*pAllocArrayFromCode)(uint32_t, void*, int32_t);
+  void* (*pAllocArrayFromCodeWithAccessCheck)(uint32_t, void*, int32_t);
   void (*pCanPutArrayElementFromCode)(void*, void*);
   void* (*pCheckAndAllocArrayFromCode)(uint32_t, void*, int32_t);
+  void* (*pCheckAndAllocArrayFromCodeWithAccessCheck)(uint32_t, void*, int32_t);
   void (*pCheckCastFromCode)(void*, void*);
   Object* (*pDecodeJObjectInThread)(Thread* thread, jobject obj);
   void (*pDeliverException)(void*);