Exception support for CanPutArrayElementFromCode.
Also a unit test.
Change-Id: I6fb4b4180d36ea2d8447a9b4d5cf28cf410960cd
diff --git a/src/object.cc b/src/object.cc
index 64607e8..dac16a8 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -927,18 +927,6 @@
return false;
}
-void Class::CanPutArrayElementFromCode(const Object* element, const Class* array_class) {
- DCHECK(array_class != NULL);
- if (element == NULL) {
- return;
- }
- if (!array_class->GetComponentType()->IsAssignableFrom(element->GetClass())) {
- LOG(ERROR) << "Can't put a " << PrettyClass(element->GetClass())
- << " into a " << PrettyClass(array_class);
- UNIMPLEMENTED(FATAL) << "need to throw ArrayStoreException and unwind stack";
- }
-}
-
// Determine whether "this" is assignable from "klazz", where both of these
// are array classes.
//
diff --git a/src/object.h b/src/object.h
index 63a2b30..5b4c7ba 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1427,10 +1427,6 @@
return !IsPrimitive() && GetSuperClass() == NULL;
}
- // Tests whether a possibly null 'element' can be
- // assigned into an array of type 'array_class'.
- static void CanPutArrayElementFromCode(const Object* element, const Class* array_class);
-
// 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.
diff --git a/src/runtime_support.S b/src/runtime_support.S
index 185cdc2..963e1aa 100644
--- a/src/runtime_support.S
+++ b/src/runtime_support.S
@@ -169,6 +169,31 @@
mov r1, sp @ pass SP
b artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP)
+ .global art_can_put_array_element_from_code
+ .extern artCanPutArrayElementFromCode
+ /*
+ * Entry from managed code that calls artCanPutArrayElementFromCode and delivers exception on
+ * failure.
+ */
+art_can_put_array_element_from_code:
+ cmp r0, #0 @ return if element == NULL
+ moveq pc, lr
+ 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 artCanPutArrayElementFromCode @ (Object* element, Class* array_class)
+ add sp, #12
+ ldmia sp!, {lr} @ restore LR
+ cmp r0, #0 @ success?
+ moveq 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_initialize_static_storage_from_code
.extern _ZN3art11ClassLinker31InitializeStaticStorageFromCodeEjPKNS_6MethodE
/*
diff --git a/src/runtime_support.h b/src/runtime_support.h
index de2a975..9da06c3 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -8,6 +8,7 @@
#if defined(__arm__)
/* Compiler helpers */
+ 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*);
extern "C" void* art_initialize_static_storage_from_code(uint32_t, void*);
diff --git a/src/thread.cc b/src/thread.cc
index 232c115..271b67b 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -201,7 +201,7 @@
return Array::AllocFromCode(type_index, method, component_count);
}
-// TODO: placeholder (throw on failure)
+// Check whether it is safe to cast one class to the other, throw exception and return -1 on failure
extern "C" int artCheckCastFromCode(const Class* a, const Class* b) {
DCHECK(a->IsClass());
DCHECK(b->IsClass());
@@ -216,6 +216,24 @@
}
}
+// Tests whether 'element' can be assigned into an array of type 'array_class'.
+// Returns 0 on success and -1 if an exception is pending.
+extern "C" int artCanPutArrayElementFromCode(const Object* element, const Class* array_class) {
+ DCHECK(array_class != NULL);
+ // element can't be NULL as we catch this is screened in runtime_support
+ Class* element_class = element->GetClass();
+ Class* component_type = array_class->GetComponentType();
+ if (component_type->IsAssignableFrom(element_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());
+ return -1; // Failure
+ }
+}
+
extern "C" int artUnlockObjectFromCode(Thread* thread, Object* obj) {
DCHECK(obj != NULL); // Assumed to have been checked before entry
return obj->MonitorExit(thread) ? 0 /* Success */ : -1 /* Failure */;
@@ -357,6 +375,7 @@
pFmod = fmod;
pLdivmod = __aeabi_ldivmod;
pLmul = __aeabi_lmul;
+ pCanPutArrayElementFromCode = art_can_put_array_element_from_code;
pCheckCastFromCode = art_check_cast_from_code;
pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
pInitializeStaticStorage = art_initialize_static_storage_from_code;
@@ -381,7 +400,6 @@
pSet64Static = Field::Set64StaticFromCode;
pGetObjStatic = Field::GetObjStaticFromCode;
pSetObjStatic = Field::SetObjStaticFromCode;
- pCanPutArrayElementFromCode = Class::CanPutArrayElementFromCode;
pInitializeTypeFromCode = InitializeTypeFromCode;
pResolveMethodFromCode = ResolveMethodFromCode;
pInstanceofNonTrivialFromCode = Object::InstanceOf;
diff --git a/src/thread.h b/src/thread.h
index 39d984b..53eff33 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -211,7 +211,7 @@
void (*pSet64Static)(uint32_t, const Method*, uint64_t);
Object* (*pGetObjStatic)(uint32_t, const Method*);
void (*pSetObjStatic)(uint32_t, const Method*, Object*);
- void (*pCanPutArrayElementFromCode)(const Object*, const Class*);
+ void (*pCanPutArrayElementFromCode)(void*, void*);
bool (*pInstanceofNonTrivialFromCode) (const Object*, const Class*);
void (*pCheckCastFromCode) (void*, void*);
Method* (*pFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, struct DvmDex*);
diff --git a/test/IntMath/IntMath.java b/test/IntMath/IntMath.java
index e5fa806..b1b7312 100644
--- a/test/IntMath/IntMath.java
+++ b/test/IntMath/IntMath.java
@@ -786,6 +786,34 @@
return res;
}
+ static void throwArrayStoreException(Object[] array, Object element) {
+ array[0] = element;
+ }
+
+ static int testArrayStoreException() {
+ int res=0;
+ Object[] array = new Number[2];
+ try {
+ throwArrayStoreException(array, null);
+ res += 1;
+ } catch(ArrayStoreException e) {
+ res += 2;
+ }
+ try {
+ throwArrayStoreException(array, Integer.valueOf(1));
+ res += 10;
+ } catch(ArrayStoreException e) {
+ res += 20;
+ }
+ try {
+ throwArrayStoreException(array, "hello MTV-44");
+ res += 100;
+ } catch(ArrayStoreException e) {
+ res += 200;
+ }
+ return res;
+ }
+
static long recursion_count_;
static void throwStackOverflow(long l) {
recursion_count_++;
@@ -966,6 +994,14 @@
failure = true;
}
+ res = testArrayStoreException();
+ if (res == 211) {
+ System.out.println("testArrayStore PASSED");
+ } else {
+ System.out.println("testArrayStore FAILED: " + res);
+ failure = true;
+ }
+
lres= testStackOverflow();
if (lres == 0) {
System.out.println("testStackOverflow PASSED");