Implement NPE, div by 0 and AIOBE.
Implement runtime support for throwing NPE, divide by 0 and
ArrayIndexOutOfBounds excptions. Add simple unit tests.
Change-Id: I69453c10b6692aa79512bcab1f68c5ab16c8c256
diff --git a/src/asm_support.h b/src/asm_support.h
new file mode 100644
index 0000000..6eda4bf
--- /dev/null
+++ b/src/asm_support.h
@@ -0,0 +1,11 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_ASM_SUPPORT_H_
+#define ART_SRC_ASM_SUPPORT_H_
+
+#if defined(__i386__)
+// Offset of field Thread::self_ verified in InitCpu
+#define THREAD_SELF_OFFSET 0x161
+#endif
+
+#endif // ART_SRC_ASM_SUPPORT_H_
diff --git a/src/runtime_support.S b/src/runtime_support.S
index 5372742..24883fc 100644
--- a/src/runtime_support.S
+++ b/src/runtime_support.S
@@ -1,3 +1,5 @@
+#include "asm_support.h"
+
#if defined(__arm__)
.balign 4
@@ -12,9 +14,45 @@
art_deliver_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 r1, r9
- mov r2, sp
- b artDeliverExceptionHelper @ artThrowExceptionHelper(Throwable*, SP)
+ mov r1, r9 @ pass Thread::Current
+ mov r2, sp @ pass SP
+ b artDeliverExceptionHelper @ artDeliverExceptionHelper(Throwable*, Thread*, SP)
+
+ .global art_throw_null_pointer_exception_from_code
+ .extern artThrowNullPointerExceptionFromCodeHelper
+ /*
+ * Create NPE and deliver
+ */
+art_throw_null_pointer_exception_from_code:
+ 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 artThrowNullPointerExceptionFromCodeHelper @ artThrowNullPointerExceptionFromCodeHelper(Thread*, SP)
+
+ .global art_throw_div_zero_from_code
+ .extern artThrowDivZeroFromCodeHelper
+ /*
+ * Create ArithmeticException and deliver
+ */
+art_throw_div_zero_from_code:
+ 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 artThrowDivZeroFromCodeHelper @ artThrowDivZeroFromCodeHelper(Thread*, SP)
+
+ .global art_throw_array_bounds_from_code
+ .extern artThrowArrayBoundsFromCodeHelper
+ /*
+ * Create ArrayIndexOutOfBoundsException and deliver
+ */
+art_throw_array_bounds_from_code:
+ 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 r2, r9 @ pass Thread::Current
+ mov r3, sp @ pass SP
+ b artThrowArrayBoundsFromCodeHelper @ artThrowArrayBoundsFromCodeHelper(index, limit, Thread*, SP)
.global art_invoke_interface_trampoline
.extern artFindInterfaceMethodInCache
@@ -144,10 +182,10 @@
mov %esp, %ecx
// Outgoing argument set up
pushl $0 // Alignment padding
- pushl %ecx
- pushl $0 // TODO: pass fs:offsetof(Thread,self_) - for now this is computed in the helper
- pushl %eax
- call artDeliverExceptionHelper // artThrowExceptionHelper(Throwable*, Thread*, SP)
+ pushl %ecx // pass SP
+ pushl %fs:THREAD_SELF_OFFSET // pass fs:offsetof(Thread,self_)
+ pushl %eax // pass Throwable*
+ call artDeliverExceptionHelper // artDeliverExceptionHelper(Throwable*, Thread*, SP)
int3
#endif
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 1f8da91..d421fcc 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -11,6 +11,9 @@
extern "C" uint64_t art_shl_long(uint64_t, uint32_t);
extern "C" uint64_t art_shr_long(uint64_t, uint32_t);
extern "C" uint64_t art_ushr_long(uint64_t, uint32_t);
+ extern "C" void art_throw_null_pointer_exception_from_code();
+ extern "C" void art_throw_div_zero_from_code();
+ extern "C" void art_throw_array_bounds_from_code(int32_t index, int32_t limit);
extern "C" void art_invoke_interface_trampoline(void*, void*, void*, void*);
/* Conversions */
diff --git a/src/thread.cc b/src/thread.cc
index 3d68802..6eac92b 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -75,9 +75,6 @@
* and threw a NPE if NULL. This routine responsible for setting
* exception_ in thread and delivering the exception.
*/
-#if defined(__i386__)
- thread = art::Thread::Current(); // TODO: fix passing this in as an argument
-#endif
// Place a special frame at the TOS that will save all callee saves
*sp = thread->CalleeSaveMethod();
thread->SetTopOfStack(sp, 0);
@@ -88,6 +85,41 @@
thread->DeliverException(exception);
}
+// Called by generated call to throw a NPE exception
+extern "C" void artThrowNullPointerExceptionFromCodeHelper(art::Thread* thread,
+ art::Method** sp) {
+ // Place a special frame at the TOS that will save all callee saves
+ *sp = thread->CalleeSaveMethod();
+ thread->SetTopOfStack(sp, 0);
+ thread->ThrowNewException("Ljava/lang/NullPointerException;", "unexpected null reference");
+ art::Throwable* exception = thread->GetException();
+ thread->DeliverException(exception);
+}
+
+// Called by generated call to throw an arithmetic divide by zero exception
+extern "C" void artThrowDivZeroFromCodeHelper(art::Thread* thread,
+ art::Method** sp) {
+ // Place a special frame at the TOS that will save all callee saves
+ *sp = thread->CalleeSaveMethod();
+ thread->SetTopOfStack(sp, 0);
+ thread->ThrowNewException("Ljava/lang/ArithmeticException;", "divide by zero");
+ art::Throwable* exception = thread->GetException();
+ thread->DeliverException(exception);
+}
+
+// Called by generated call to throw an arithmetic divide by zero exception
+extern "C" void artThrowArrayBoundsFromCodeHelper(int index, int limit,
+ art::Thread* thread,
+ art::Method** sp) {
+ // Place a special frame at the TOS that will save all callee saves
+ *sp = thread->CalleeSaveMethod();
+ thread->SetTopOfStack(sp, 0);
+ thread->ThrowNewException("Ljava/lang/ArrayIndexOutOfBoundsException;",
+ "length=%d; index=%d", limit, index);
+ art::Throwable* exception = thread->GetException();
+ thread->DeliverException(exception);
+}
+
namespace art {
// TODO: placeholder. Helper function to type
@@ -330,6 +362,9 @@
pFmod = fmod;
pLdivmod = __aeabi_ldivmod;
pLmul = __aeabi_lmul;
+ pThrowNullPointerFromCode = art_throw_null_pointer_exception_from_code;
+ pThrowArrayBoundsFromCode = art_throw_array_bounds_from_code;
+ pThrowDivZeroFromCode = art_throw_div_zero_from_code;
pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
#endif
pDeliverException = art_deliver_exception;
@@ -357,9 +392,6 @@
pFindInstanceFieldFromCode = Field::FindInstanceFieldFromCode;
pCheckSuspendFromCode = CheckSuspendFromCode;
pStackOverflowFromCode = StackOverflowFromCode;
- pThrowNullPointerFromCode = ThrowNullPointerFromCode;
- pThrowArrayBoundsFromCode = ThrowArrayBoundsFromCode;
- pThrowDivZeroFromCode = ThrowDivZeroFromCode;
pThrowVerificationErrorFromCode = ThrowVerificationErrorFromCode;
pThrowNegArraySizeFromCode = ThrowNegArraySizeFromCode;
pThrowRuntimeExceptionFromCode = ThrowRuntimeExceptionFromCode;
diff --git a/src/thread_x86.cc b/src/thread_x86.cc
index 57eeffd..5aa6d24 100644
--- a/src/thread_x86.cc
+++ b/src/thread_x86.cc
@@ -6,6 +6,7 @@
#include <sys/syscall.h>
#include <sys/types.h>
+#include "asm_support.h"
#include "macros.h"
namespace art {
@@ -53,9 +54,10 @@
// Sanity check reads from FS goes to this Thread*
Thread* self_check;
// TODO: use our assembler to generate code
+ CHECK_EQ(THREAD_SELF_OFFSET, OFFSETOF_MEMBER(Thread, self_));
asm volatile("movl %%fs:(%1), %0"
: "=r"(self_check) // output
- : "r"(OFFSETOF_MEMBER(Thread, self_)) // input
+ : "r"(THREAD_SELF_OFFSET) // input
:); // clobber
CHECK_EQ(self_check, this);
}
diff --git a/test/ExceptionTest/ExceptionTest.java b/test/ExceptionTest/ExceptionTest.java
index 973e9e9..edd549e 100644
--- a/test/ExceptionTest/ExceptionTest.java
+++ b/test/ExceptionTest/ExceptionTest.java
@@ -138,6 +138,49 @@
}
+ static void throwImplicitAIOBE(int[] array, int index) {
+ array[index] = 0;
+ }
+
+ static int checkAIOBE() {
+ int[] array = new int[10];
+ int res;
+ try {
+ throwImplicitAIOBE(array, 11);
+ res = 123;
+ } catch (NullPointerException npe) {
+ res = 768;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ res = 456;
+ }
+ try {
+ throwImplicitAIOBE(array, -1);
+ res += 123;
+ } catch (NullPointerException npe) {
+ res += 768;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ res += 456;
+ }
+ return res;
+ }
+
+ static int throwImplicitDivZero(int x, int y) {
+ return x / y;
+ }
+
+ static int checkDivZero() {
+ try {
+ throwImplicitDivZero(100, 0);
+ return 123;
+ } catch (NullPointerException npe) {
+ return 768;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return 987;
+ } catch (ArithmeticException e) {
+ return 456;
+ }
+ }
+
public static void main(String[] args) {
boolean failure = false;
int res;
@@ -150,7 +193,6 @@
failure = true;
}
-if (false) { // TODO: enable this test when passing
res = nullCheckTestThrow(1976);
if (res == 2057) {
System.out.println("nullCheckTestThrow PASSED");
@@ -158,7 +200,22 @@
System.out.println("nullCheckTestThrow FAILED: " + res);
failure = true;
}
-}
+
+ res = checkAIOBE();
+ if (res == 912) {
+ System.out.println("checkAIOBE PASSED");
+ } else {
+ System.out.println("checkAIOBE FAILED: " + res);
+ failure = true;
+ }
+
+ res = checkDivZero();
+ if (res == 456) {
+ System.out.println("checkDivZero PASSED");
+ } else {
+ System.out.println("checkDivZero FAILED: " + res);
+ failure = true;
+ }
System.exit(failure ? 1 : 0);
}
}