Support for exceptions from array allocation.
Adds support for exceptions during array allocation and checked array
allocation (used by filled-new-array). Adds more unit tests.
Change-Id: I3438b257a1cf19538d8b72529097a74347ac3b99
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);