Merge "Support for exceptions from array allocation." into dalvik-dev
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 595bc98..c5241ca 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -33,7 +33,7 @@
 {
     oatFlushAllRegs(cUnit);    /* Everything to home location */
     loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pAllocFromCode), rLR);
+                 OFFSETOF_MEMBER(Thread, pArrayAllocFromCode), rLR);
     loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
     loadConstant(cUnit, r0, mir->dalvikInsn.vC);  // arg0 <- type_id
     loadValueDirectFixed(cUnit, rlSrc, r2);       // arg2 <- count
@@ -56,7 +56,7 @@
     int typeId = dInsn->vB;
     oatFlushAllRegs(cUnit);    /* Everything to home location */
     loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pCheckAndAllocFromCode), rLR);
+                 OFFSETOF_MEMBER(Thread, pCheckAndArrayAllocFromCode), rLR);
     loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
     loadConstant(cUnit, r0, typeId);              // arg0 <- type_id
     loadConstant(cUnit, r2, elems);               // arg2 <- count
diff --git a/src/object.cc b/src/object.cc
index dac16a8..29eac77 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -1196,19 +1196,6 @@
   return Alloc(array_class, component_count, array_class->GetComponentSize());
 }
 
-Array* Array::AllocFromCode(uint32_t type_idx, Method* method, int32_t component_count) {
-  // TODO: throw on negative component_count
-  Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
-  if (klass == NULL) {
-    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
-    if (klass == NULL || !klass->IsArrayClass()) {
-      UNIMPLEMENTED(FATAL) << "throw an error";
-      return NULL;
-    }
-  }
-  return Array::Alloc(klass, component_count);
-}
-
 template<typename T>
 PrimitiveArray<T>* PrimitiveArray<T>::Alloc(size_t length) {
   DCHECK(array_class_ != NULL);
diff --git a/src/object.h b/src/object.h
index 5b4c7ba..09788be 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1093,11 +1093,6 @@
     return sizeof(Array) + component_count * component_size;
   }
 
-  // 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.
-  static Array* AllocFromCode(uint32_t type_idx, Method* method, int32_t component_count);
-
   // A convenience for code that doesn't know the component size,
   // and doesn't want to have to work it out itself.
   static Array* Alloc(Class* array_class, int32_t component_count);
diff --git a/src/object_test.cc b/src/object_test.cc
index 7f6ad4c..9a5777b 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -171,12 +171,27 @@
   EXPECT_TRUE(string->IsString());
 }
 
-TEST_F(ObjectTest, AllocArrayFromCode) {
+extern "C" Array* artArrayAllocFromCode(uint32_t type_idx, Method* method, int32_t component_count);
+TEST_F(ObjectTest, ArrayAllocFromCode) {
   // pretend we are trying to call 'new char[3]' from String.toCharArray
   Class* java_lang_String = class_linker_->FindSystemClass("Ljava/lang/String;");
   Method* toCharArray = java_lang_String->FindVirtualMethod("toCharArray", "()[C");
   uint32_t type_idx = FindTypeIdxByDescriptor(*java_lang_dex_file_.get(), "[C");
-  Object* array = Array::AllocFromCode(type_idx, toCharArray, 3);
+  Object* array = artArrayAllocFromCode(type_idx, toCharArray, 3);
+  EXPECT_TRUE(array->IsArrayInstance());
+  EXPECT_EQ(3, array->AsArray()->GetLength());
+  EXPECT_TRUE(array->GetClass()->IsArrayClass());
+  EXPECT_TRUE(array->GetClass()->GetComponentType()->IsPrimitive());
+}
+
+extern "C" Array* artCheckAndArrayAllocFromCode(uint32_t type_idx, Method* method,
+                                                int32_t component_count);
+TEST_F(ObjectTest, CheckAndArrayAllocFromCode) {
+  // pretend we are trying to call 'new char[3]' from String.toCharArray
+  Class* java_util_Arrays = class_linker_->FindSystemClass("Ljava/util/Arrays;");
+  Method* sort = java_util_Arrays->FindDirectMethod("sort", "([I)V");
+  uint32_t type_idx = FindTypeIdxByDescriptor(*java_lang_dex_file_.get(), "[I");
+  Object* array = artCheckAndArrayAllocFromCode(type_idx, sort, 3);
   EXPECT_TRUE(array->IsArrayInstance());
   EXPECT_EQ(3, array->AsArray()->GetLength());
   EXPECT_TRUE(array->GetClass()->IsArrayClass());
diff --git a/src/runtime_support.S b/src/runtime_support.S
index 963e1aa..9cfb3ab 100644
--- a/src/runtime_support.S
+++ b/src/runtime_support.S
@@ -219,6 +219,50 @@
     mov    r1, sp                             @ pass SP
     b      artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
 
+    .global art_array_alloc_from_code
+    .extern artArrayAllocFromCode
+    /*
+     * Called by managed code to allocate an array
+     */
+art_array_alloc_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     artArrayAllocFromCode  @ (uint32_t type_idx, Method* method, int32_t component_count)
+    add    sp, #12
+    ldmia  sp!, {lr}              @ restore LR
+    cmp    r0, #0                 @ success if result is non-null
+    movne  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_and_array_alloc_from_code
+    .extern artCheckAndArrayAllocFromCode
+    /*
+     * Called by managed code to allocate an array
+     */
+art_check_and_array_alloc_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     artCheckAndArrayAllocFromCode  @ (uint32_t type_idx, Method* method, int32_t count)
+    add    sp, #12
+    ldmia  sp!, {lr}                      @ restore LR
+    cmp    r0, #0                         @ success if result is non-null
+    movne  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:
     /*
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 9da06c3..20ca1d4 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -8,6 +8,8 @@
 
 #if defined(__arm__)
   /* Compiler helpers */
+  extern "C" void* art_array_alloc_from_code(uint32_t, void*, int32_t);
+  extern "C" void* art_check_and_array_alloc_from_code(uint32_t, void*, int32_t);
   extern "C" void art_can_put_array_element_from_code(void*, void*);
   extern "C" void art_check_cast_from_code(void*, void*);
   extern "C" void art_handle_fill_data_from_code(void*, void*);
diff --git a/src/thread.cc b/src/thread.cc
index 271b67b..69dec94 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -191,14 +191,57 @@
      */
 }
 
-// TODO: placeholder.  Helper function to alloc array for OP_FILLED_NEW_ARRAY
-Array* CheckAndAllocFromCode(uint32_t type_index, Method* method, int32_t component_count) {
-    /*
-     * Just a wrapper around Array::AllocFromCode() that additionally
-     * throws a runtime exception "bad Filled array req" for 'D' and 'J'.
-     */
-    UNIMPLEMENTED(WARNING) << "Need check that not 'D' or 'J'";
-    return Array::AllocFromCode(type_index, method, component_count);
+// Helper function to alloc array for OP_FILLED_NEW_ARRAY
+extern "C" Array* artCheckAndArrayAllocFromCode(uint32_t type_idx, Method* method,
+                                                int32_t component_count) {
+  if (component_count < 0) {
+    Thread::Current()->ThrowNewException("Ljava/lang/NegativeArraySizeException;", "%d",
+                                         component_count);
+    return NULL;  // Failure
+  }
+  Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
+  if (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
+    }
+  }
+  if (klass->IsPrimitive() && !klass->IsPrimitiveInt()) {
+    if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
+      Thread::Current()->ThrowNewException("Ljava/lang/RuntimeException;",
+          "Bad filled array request for type %s",
+          PrettyDescriptor(klass->GetDescriptor()).c_str());
+    } else {
+      Thread::Current()->ThrowNewException("Ljava/lang/InternalError;",
+          "Found type %s; filled-new-array not implemented for anything but \'int\'",
+          PrettyDescriptor(klass->GetDescriptor()).c_str());
+    }
+    return NULL;  // Failure
+  } else {
+    CHECK(klass->IsArrayClass());
+    return Array::Alloc(klass, component_count);
+  }
+}
+
+// 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* artArrayAllocFromCode(uint32_t type_idx, Method* method, int32_t component_count) {
+  if (component_count < 0) {
+    Thread::Current()->ThrowNewException("Ljava/lang/NegativeArraySizeException;", "%d",
+                                         component_count);
+    return NULL;  // Failure
+  }
+  Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
+  if (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());
+  }
+  return Array::Alloc(klass, component_count);
 }
 
 // Check whether it is safe to cast one class to the other, throw exception and return -1 on failure
@@ -227,9 +270,9 @@
     return 0;  // Success
   } else {
     Thread::Current()->ThrowNewException("Ljava/lang/ArrayStoreException;",
-                                      "Cannot store an object of type %s in to an array of type %s",
-                                         PrettyDescriptor(element_class->GetDescriptor()).c_str(),
-                                         PrettyDescriptor(array_class->GetDescriptor()).c_str());
+        "Cannot store an object of type %s in to an array of type %s",
+        PrettyDescriptor(element_class->GetDescriptor()).c_str(),
+        PrettyDescriptor(array_class->GetDescriptor()).c_str());
     return -1;  // Failure
   }
 }
@@ -375,7 +418,9 @@
   pFmod = fmod;
   pLdivmod = __aeabi_ldivmod;
   pLmul = __aeabi_lmul;
+  pArrayAllocFromCode = art_array_alloc_from_code;
   pCanPutArrayElementFromCode = art_can_put_array_element_from_code;
+  pCheckAndArrayAllocFromCode = art_check_and_array_alloc_from_code;
   pCheckCastFromCode = art_check_cast_from_code;
   pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
   pInitializeStaticStorage = art_initialize_static_storage_from_code;
@@ -390,8 +435,6 @@
   pDeliverException = art_deliver_exception_from_code;
   pF2l = F2L;
   pD2l = D2L;
-  pAllocFromCode = Array::AllocFromCode;
-  pCheckAndAllocFromCode = CheckAndAllocFromCode;
   pAllocObjectFromCode = Class::AllocObjectFromCode;
   pMemcpy = memcpy;
   pGet32Static = Field::Get32StaticFromCode;
diff --git a/src/thread.h b/src/thread.h
index 53eff33..945d337 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -202,8 +202,8 @@
   int (*pIdiv)(int, int);
   long long (*pLmul)(long long, long long);
   long long (*pLdivmod)(long long, long long);
-  Array* (*pAllocFromCode)(uint32_t, Method*, int32_t);
-  Array* (*pCheckAndAllocFromCode)(uint32_t, Method*, int32_t);
+  void* (*pArrayAllocFromCode)(uint32_t, void*, int32_t);
+  void* (*pCheckAndArrayAllocFromCode)(uint32_t, void*, int32_t);
   Object* (*pAllocObjectFromCode)(uint32_t, Method*);
   uint32_t (*pGet32Static)(uint32_t, const Method*);
   void (*pSet32Static)(uint32_t, const Method*, uint32_t);
diff --git a/test/IntMath/IntMath.java b/test/IntMath/IntMath.java
index b1b7312..7b0d5f8 100644
--- a/test/IntMath/IntMath.java
+++ b/test/IntMath/IntMath.java
@@ -833,6 +833,23 @@
       }
     }
 
+    static int testArrayAllocation() {
+      int res = 0;
+      try {
+        int[] x = new int[-1];
+        res += 1;
+      } catch (NegativeArraySizeException e) {
+        res += 2;
+      }
+      try {
+        int[] x = new int [1];
+        res += 10;
+      } catch (Throwable e) {
+        res += 20;
+      }
+      return res;
+    }
+
     public static void main(String[] args) {
         boolean failure = false;
         int res;
@@ -1010,6 +1027,14 @@
             failure = true;
         }
 
+        res = testArrayAllocation();
+        if (res == 12) {
+          System.out.println("testArrayAllocation PASSED");
+        } else {
+          System.out.println("testArrayAllocation FAILED: " + res);
+          failure = true;
+        }
+
         res = manyArgs(0, 1L, 2, 3L, 4, 5L, 6, 7, 8.0, 9.0f, 10.0,
                        (short)11, 12, (char)13, 14, 15, (byte)-16, true, 18,
                        19, 20L, 21L, 22, 23, 24, 25, 26);