Class cast, fill array and interface exception support.

This change uses the deliver exception mechanism to implement support
for a number of runtime exceptions. It also tidies up code in the
compiler and allocates a singular callee save method in the image.

Also adds a fix for JNI internal test where we weren't passing
Thread::Current() and that this value is now being used in generated code.

Change-Id: I57eefd9afe40e92fa3a7e737f1a2ed7e1094b5c1
diff --git a/src/runtime_support.S b/src/runtime_support.S
index 6522243..5746059 100644
--- a/src/runtime_support.S
+++ b/src/runtime_support.S
@@ -4,92 +4,161 @@
 
     .balign 4
 
-    .global art_deliver_exception
-    .extern artDeliverExceptionHelper
+    /* Deliver the given exception */
+    .extern artDeliverExceptionFromCode
+    /* Deliver an exception pending on a thread */
+    .extern artDeliverPendingException
+
+    .global art_deliver_exception_from_code
     /*
-     * Called by managed code, saves mosts registers (forms basis of long jump context).
-     * artThrowExceptionHelper will place a mock Method* at the bottom of the thread.
-     * r0 holds Throwable
+     * Called by managed code, saves mosts registers (forms basis of long jump context) and passes
+     * the bottom of the stack. artDeliverExceptionFromCode will place the callee save Method* at
+     * the bottom of the thread. On entry r0 holds Throwable*
      */
-art_deliver_exception:
+art_deliver_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 r1, r9                   @ pass Thread::Current
-    mov r2, sp                   @ pass SP
-    b artDeliverExceptionHelper  @ artDeliverExceptionHelper(Throwable*, Thread*, SP)
+    sub sp, #16                     @ 4 words of space, bottom word will hold Method*
+    mov r1, r9                      @ pass Thread::Current
+    mov r2, sp                      @ pass SP
+    b   artDeliverExceptionFromCode @ artDeliverExceptionFromCode(Throwable*, Thread*, SP)
 
     .global art_throw_null_pointer_exception_from_code
-    .extern artThrowNullPointerExceptionFromCodeHelper
+    .extern artThrowNullPointerExceptionFromCode
     /*
-     * Create NPE and deliver
+     * Called by managed code to create and deliver a NullPointerException
      */
 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)
+    sub sp, #16                              @ 4 words of space, bottom word will hold Method*
+    mov r0, r9                               @ pass Thread::Current
+    mov r1, sp                               @ pass SP
+    b   artThrowNullPointerExceptionFromCode @ artThrowNullPointerExceptionFromCode(Thread*, SP)
 
     .global art_throw_div_zero_from_code
-    .extern artThrowDivZeroFromCodeHelper
+    .extern artThrowDivZeroFromCode
     /*
-     * Create ArithmeticException and deliver
+     * Called by managed code to create and deliver an ArithmeticException
      */
 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)
+    sub sp, #16                 @ 4 words of space, bottom word will hold Method*
+    mov r0, r9                  @ pass Thread::Current
+    mov r1, sp                  @ pass SP
+    b   artThrowDivZeroFromCode @ artThrowDivZeroFromCode(Thread*, SP)
 
     .global art_throw_array_bounds_from_code
-    .extern artThrowArrayBoundsFromCodeHelper
+    .extern artThrowArrayBoundsFromCode
     /*
-     * Create ArrayIndexOutOfBoundsException and deliver
+     * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException
      */
 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)
+    sub sp, #16                     @ 4 words of space, bottom word will hold Method*
+    mov r2, r9                      @ pass Thread::Current
+    mov r3, sp                      @ pass SP
+    b   artThrowArrayBoundsFromCode @ artThrowArrayBoundsFromCode(index, limit, Thread*, SP)
 
     .global art_invoke_interface_trampoline
-    .extern artFindInterfaceMethodInCache
-    .extern artFailedInvokeInterface
-art_invoke_interface_trampoline:
+    .extern artFindInterfaceMethodInCacheFromCode
     /*
-     * All generated callsites for interface invokes will load arguments
-     * as usual - except instead of loading arg0/r0 with the target
-     * Method*, arg0/r0 will contain the method_idx.  This wrapper will
-     * save arg1-arg3, load the caller's Method*, align the stack and
-     * call the helper artFindInterfaceMethodInCache(idx, this, method);
-     * NOTE: "this" is first visable argument of the target, and so can be
-     * found in arg1/r1.
+     * All generated callsites for interface invokes will load arguments as usual - except instead
+     * of loading arg0/r0 with the target Method*, arg0/r0 will contain the method_idx.  This
+     * wrapper will save arg1-arg3, load the caller's Method*, align the stack and call the helper
+     * artFindInterfaceMethodInCacheFromCode(idx, this, method);
+     * NOTE: "this" is first visable argument of the target, and so can be found in arg1/r1.
      *
-     * artFindInterfaceMethodInCache will attempt to locate the target
-     * and return a 64-bit result in r0/r1 consisting of the target
-     * Method* in r0 and method->code_ in r1.
+     * artFindInterfaceMethodInCacheFromCode will attempt to locate the target and return a 64-bit
+     * result in r0/r1 consisting of the target Method* in r0 and method->code_ in r1.
      *
-     * If unsuccessful, artFindInterfaceMethodInCache will return
-     * NULL/NULL.  This is somewhat different than the usual
-     * mechanism of helper routines performing the unwind & throw.
-     * The reason is that this trampoline is not unwindable.  In the
-     * event artFindInterfaceMethodInCache fails to resolve, the wrapper
-     * will prepare an unwindable environment and jump to another helper
-     * to do unwind/throw.
+     * If unsuccessful, artFindInterfaceMethodInCacheFromCode will return NULL/NULL. There will be
+     * a pending exception in the thread and we branch to another stub to deliver it.
      *
-     * On success this wrapper will restore arguments and *jump* to the
-     * target, leaving the lr pointing back to the original caller.
+     * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
+     * pointing back to the original caller.
      */
+art_invoke_interface_trampoline:
+    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!, {r1, r2, r3, lr}
-    ldr    r2, [sp, #16]                 @ load caller's Method*
-    bl     artFindInterfaceMethodInCache @ (method_idx, this, callerMethod)
-    mov    r12, r1                       @ save r0->code_
-    ldmia  sp!, {r1, r2, r3, lr}         @ restore arguments
-    cmp    r0, #0                        @ did we find the target?
-    bxne   r12                           @ tail call to target if so
-    b      artFailedInvokeInterface      @ Will appear as if called directly
+    ldr    r2, [sp, #16]                         @ load caller's Method*
+    bl     artFindInterfaceMethodInCacheFromCode @ (method_idx, this, callerMethod)
+    mov    r12, r1                               @ save r0->code_
+    ldmia  sp!, {r1, r2, r3, lr}                 @ restore arguments
+    cmp    r0, #0                                @ did we find the target?
+    bxne   r12                                   @ tail call to target if so
+                                                 @ 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_handle_fill_data_from_code
+    .extern artHandleFillArrayDataFromCode
+    /*
+     * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
+     * failure.
+     */
+art_handle_fill_data_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     artHandleFillArrayDataFromCode     @ (Array* array, const uint16_t* table)
+    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_unlock_object_from_code
+    .extern artUnlockObjectFromCode
+    /*
+     * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
+     */
+art_unlock_object_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     artUnlockObjectFromCode            @ (Thread* thread, Object* obj)
+    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_check_cast_from_code
+    .extern artCheckCastFromCode
+    /*
+     * Entry from managed code that calls artCheckCastFromCode and delivers exception on failure.
+     */
+art_check_cast_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     artCheckCastFromCode               @ (Class* a, Class* b)
+    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_shl_long
 art_shl_long:
@@ -180,14 +249,14 @@
 
 #if defined(__i386__)
 
-    .global art_deliver_exception
-    .extern artDeliverExceptionHelper
+    .global art_deliver_exception_from_code
+    .extern artDeliverExceptionFromCode
     /*
-     * Called by managed code, saves callee saves and then calls artThrowExceptionHelper
+     * Called by managed code, saves callee saves and then calls artThrowException
      * that will place a mock Method* at the bottom of the stack.
      * EAX holds the exception.
      */
-art_deliver_exception:
+art_deliver_exception_from_code:
     // Create frame
     pushl %edi  // Save callee saves
     pushl %esi
@@ -198,11 +267,11 @@
     pushl $0   // Will be clobbered to be Method*
     mov %esp, %ecx
     // Outgoing argument set up
-    pushl $0    // Alignment padding
-    pushl %ecx                      // pass SP
-    pushl %fs:THREAD_SELF_OFFSET    // pass fs:offsetof(Thread,self_)
-    pushl %eax                      // pass Throwable*
-    call artDeliverExceptionHelper  // artDeliverExceptionHelper(Throwable*, Thread*, SP)
+    pushl $0  // Alignment padding
+    pushl %ecx                        // pass SP
+    pushl %fs:THREAD_SELF_OFFSET      // pass fs:offsetof(Thread,self_)
+    pushl %eax                        // pass Throwable*
+    call artDeliverExceptionFromCode  // artDeliverExceptionFromCode(Throwable*, Thread*, SP)
     int3
 
 #endif