diff options
| author | 2011-09-23 16:48:26 -0700 | |
|---|---|---|
| committer | 2011-09-23 16:48:26 -0700 | |
| commit | 31cc62d259b86844b505c3bfe15b44e372f705b8 (patch) | |
| tree | 3b596e14a2e7fc39027a1016e5b7c77887714330 | |
| parent | 3311f2763c4103f7c378af417a2863f7e2c224f3 (diff) | |
| parent | b886da8e3c26443ab4d2aa63268bd673c354c3d2 (diff) | |
Merge "Support for exceptions from array allocation." into dalvik-dev
| -rw-r--r-- | src/compiler/codegen/arm/MethodCodegenDriver.cc | 4 | ||||
| -rw-r--r-- | src/object.cc | 13 | ||||
| -rw-r--r-- | src/object.h | 5 | ||||
| -rw-r--r-- | src/object_test.cc | 19 | ||||
| -rw-r--r-- | src/runtime_support.S | 44 | ||||
| -rw-r--r-- | src/runtime_support.h | 2 | ||||
| -rw-r--r-- | src/thread.cc | 69 | ||||
| -rw-r--r-- | src/thread.h | 4 | ||||
| -rw-r--r-- | test/IntMath/IntMath.java | 25 |
9 files changed, 148 insertions, 37 deletions
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc index 595bc986b5..c5241ca005 100644 --- a/src/compiler/codegen/arm/MethodCodegenDriver.cc +++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc @@ -33,7 +33,7 @@ static void genNewArray(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest, { 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 @@ static void genFilledNewArray(CompilationUnit* cUnit, MIR* mir, bool isRange) 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 dac16a8bd6..29eac7736e 100644 --- a/src/object.cc +++ b/src/object.cc @@ -1196,19 +1196,6 @@ Array* Array::Alloc(Class* array_class, int32_t component_count) { 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 5b4c7ba1d5..09788be867 100644 --- a/src/object.h +++ b/src/object.h @@ -1093,11 +1093,6 @@ class MANAGED Array : public Object { 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 7f6ad4c9f4..9a5777b6aa 100644 --- a/src/object_test.cc +++ b/src/object_test.cc @@ -171,12 +171,27 @@ TEST_F(ObjectTest, AllocObjectFromCode) { 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 963e1aafdb..9cfb3ab74c 100644 --- a/src/runtime_support.S +++ b/src/runtime_support.S @@ -219,6 +219,50 @@ art_initialize_static_storage_from_code: 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 9da06c3570..20ca1d4d5e 100644 --- a/src/runtime_support.h +++ b/src/runtime_support.h @@ -8,6 +8,8 @@ extern "C" void art_deliver_exception_from_code(void*); #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 271b67b418..69dec9439b 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -191,14 +191,57 @@ void ResolveMethodFromCode(Method* method, uint32_t method_idx) { */ } -// 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 @@ extern "C" int artCanPutArrayElementFromCode(const Object* element, const Class* 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 @@ void Thread::InitFunctionPointers() { 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 @@ void Thread::InitFunctionPointers() { 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 53eff33803..945d3379f0 100644 --- a/src/thread.h +++ b/src/thread.h @@ -202,8 +202,8 @@ class PACKED Thread { 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 b1b7312fb2..7b0d5f81bd 100644 --- a/test/IntMath/IntMath.java +++ b/test/IntMath/IntMath.java @@ -833,6 +833,23 @@ class IntMath extends IntMathBase { } } + 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 @@ class IntMath extends IntMathBase { 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); |