Implement the "unreasonable array allocation" OutOfMemoryError.

This doesn't fix test 061 because we still need AllocWithGrowth, but at least
it gets us far enough to need that.

Change-Id: Ia7b4a1f91a31e25d439f36b17280ce21c9ed8933
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index a4e211b..6be9f76 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -48,7 +48,7 @@
 {
     oatFlushAllRegs(cUnit);    /* Everything to home location */
     loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pArrayAllocFromCode), rLR);
+                 OFFSETOF_MEMBER(Thread, pAllocArrayFromCode), rLR);
     loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
     loadConstant(cUnit, r0, mir->dalvikInsn.vC);  // arg0 <- type_id
     loadValueDirectFixed(cUnit, rlSrc, r2);       // arg2 <- count
@@ -70,7 +70,7 @@
     int typeId = dInsn->vB;
     oatFlushAllRegs(cUnit);    /* Everything to home location */
     loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pCheckAndArrayAllocFromCode), rLR);
+                 OFFSETOF_MEMBER(Thread, pCheckAndAllocArrayFromCode), 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 8fc4108..49d689c 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -1220,12 +1220,30 @@
   DCHECK(array_class != NULL);
   DCHECK_GE(component_count, 0);
   DCHECK(array_class->IsArrayClass());
-  size_t size = SizeOf(component_count, component_size);
+
+  size_t header_size = sizeof(Array);
+  size_t data_size = component_count * component_size;
+  size_t size = header_size + data_size;
+
+  // Check for overflow and throw OutOfMemoryError if this was an unreasonable request.
+  size_t component_shift = sizeof(size_t) * 8 - 1 - CLZ(component_size);
+  if (data_size >> component_shift != size_t(component_count) || size < data_size) {
+    Thread::Current()->ThrowNewExceptionF("Ljava/lang/OutOfMemoryError;",
+        "%s of length %zd exceeds the VM limit",
+        PrettyDescriptor(array_class->GetDescriptor()).c_str(), component_count);
+    return NULL;
+  }
+
   Array* array = down_cast<Array*>(Heap::AllocObject(array_class, size));
   if (array != NULL) {
     DCHECK(array->IsArrayInstance());
     array->SetLength(component_count);
   }
+
+  // TODO: throw OutOfMemoryError. (here or in Heap::AllocObject?)
+  CHECK(array != NULL) << PrettyClass(array_class)
+                       << " component_count=" << component_count
+                       << " component_size=" << component_size;
   return array;
 }
 
diff --git a/src/object.h b/src/object.h
index 42235b8..205d7c0 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1107,11 +1107,6 @@
 
 class MANAGED Array : public Object {
  public:
-  static size_t SizeOf(size_t component_count,
-                       size_t component_size) {
-    return sizeof(Array) + component_count * component_size;
-  }
-
   // 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);
@@ -2226,7 +2221,8 @@
 }
 
 inline size_t Array::SizeOf() const {
-  return SizeOf(GetLength(), GetClass()->GetComponentSize());
+  // This is safe from overflow because the array was already allocated, so we know it's sane.
+  return sizeof(Array) + GetLength() * GetClass()->GetComponentSize();
 }
 
 template<class T>
diff --git a/src/object_test.cc b/src/object_test.cc
index 1451929..167c770 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -172,27 +172,27 @@
   EXPECT_TRUE(string->IsString());
 }
 
-extern "C" Array* artArrayAllocFromCode(uint32_t type_idx, Method* method, int32_t component_count);
-TEST_F(ObjectTest, ArrayAllocFromCode) {
+extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count);
+TEST_F(ObjectTest, AllocArrayFromCode) {
   // 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 = artArrayAllocFromCode(type_idx, toCharArray, 3);
+  Object* array = artAllocArrayFromCode(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,
+extern "C" Array* artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method,
                                                 int32_t component_count);
-TEST_F(ObjectTest, CheckAndArrayAllocFromCode) {
+TEST_F(ObjectTest, CheckAndAllocArrayFromCode) {
   // 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);
+  Object* array = artCheckAndAllocArrayFromCode(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.cc b/src/runtime_support.cc
index 89dac70..039a749 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -352,7 +352,7 @@
 }
 
 // Helper function to alloc array for OP_FILLED_NEW_ARRAY
-extern "C" Array* artCheckAndArrayAllocFromCode(uint32_t type_idx, Method* method,
+extern "C" Array* artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method,
                                                 int32_t component_count) {
   if (component_count < 0) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
@@ -386,7 +386,7 @@
 
 // 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) {
+extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count) {
   if (component_count < 0) {
     Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
                                          component_count);
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 3a1ffcf..985074c 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -29,8 +29,8 @@
 #if defined(__arm__)
   /* Compiler helpers */
   extern "C" void* art_alloc_object_from_code(uint32_t type_idx, void* method);
-  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_alloc_array_from_code(uint32_t, void*, int32_t);
+  extern "C" void* art_check_and_alloc_array_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/runtime_support_asm.S b/src/runtime_support_asm.S
index 25a6872..eb12854 100644
--- a/src/runtime_support_asm.S
+++ b/src/runtime_support_asm.S
@@ -276,17 +276,17 @@
     mov    r1, sp                  @ pass SP
     b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*, SP)
 
-    .global art_array_alloc_from_code
-    .extern artArrayAllocFromCode
+    .global art_alloc_array_from_code
+    .extern artAllocArrayFromCode
     /*
      * Called by managed code to allocate an array
      */
-art_array_alloc_from_code:
+art_alloc_array_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)
+    bl     artAllocArrayFromCode  @ (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
@@ -297,17 +297,17 @@
     mov    r1, sp                 @ pass SP
     b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*, SP)
 
-    .global art_check_and_array_alloc_from_code
-    .extern artCheckAndArrayAllocFromCode
+    .global art_check_and_alloc_array_from_code
+    .extern artCheckAndAllocArrayFromCode
     /*
      * Called by managed code to allocate an array
      */
-art_check_and_array_alloc_from_code:
+art_check_and_alloc_array_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)
+    bl     artCheckAndAllocArrayFromCode  @ (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
diff --git a/src/thread.cc b/src/thread.cc
index e997723..87a2017 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -86,9 +86,9 @@
   pLdivmod = __aeabi_ldivmod;
   pLmul = __aeabi_lmul;
   pAllocObjectFromCode = art_alloc_object_from_code;
-  pArrayAllocFromCode = art_array_alloc_from_code;
+  pAllocArrayFromCode = art_alloc_array_from_code;
   pCanPutArrayElementFromCode = art_can_put_array_element_from_code;
-  pCheckAndArrayAllocFromCode = art_check_and_array_alloc_from_code;
+  pCheckAndAllocArrayFromCode = art_check_and_alloc_array_from_code;
   pCheckCastFromCode = art_check_cast_from_code;
   pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
   pInitializeStaticStorage = art_initialize_static_storage_from_code;
diff --git a/src/thread.h b/src/thread.h
index 4f85b70..c949339 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -203,8 +203,8 @@
   long long (*pLmul)(long long, long long);
   long long (*pLdivmod)(long long, long long);
   void* (*pAllocObjectFromCode)(uint32_t, void*);
-  void* (*pArrayAllocFromCode)(uint32_t, void*, int32_t);
-  void* (*pCheckAndArrayAllocFromCode)(uint32_t, void*, int32_t);
+  void* (*pAllocArrayFromCode)(uint32_t, void*, int32_t);
+  void* (*pCheckAndAllocArrayFromCode)(uint32_t, void*, int32_t);
   uint32_t (*pGet32Static)(uint32_t, const Method*);
   void (*pSet32Static)(uint32_t, const Method*, uint32_t);
   uint64_t (*pGet64Static)(uint32_t, const Method*);