Fix x86 slowpath getters and implement proxy.

The slowpath getters were using %eax to tell if an exception occurred,
instead of checking Thread->exception_. Also, proxy is implemented, and
run-test 004 works.

Change-Id: I0473635e093566a86d7deb54e715074373ff6d4b
diff --git a/src/asm_support.h b/src/asm_support.h
index 036e67c..e776e53 100644
--- a/src/asm_support.h
+++ b/src/asm_support.h
@@ -36,6 +36,8 @@
 #elif defined(__i386__)
 // Offset of field Thread::self_ verified in InitCpu
 #define THREAD_SELF_OFFSET 112
+// Offset of field Thread::exception_ verified in InitCpu
+#define THREAD_EXCEPTION_OFFSET 120
 #endif
 
 #endif  // ART_SRC_ASM_SUPPORT_H_
diff --git a/src/oat/runtime/support_proxy.cc b/src/oat/runtime/support_proxy.cc
index cc375ad..e4b7e36 100644
--- a/src/oat/runtime/support_proxy.cc
+++ b/src/oat/runtime/support_proxy.cc
@@ -22,6 +22,15 @@
 
 #include "ScopedLocalRef.h"
 
+#if defined(__arm__)
+#define SP_OFFSET 12
+#define FRAME_SIZE_IN_BYTES 48u
+#elif defined(__i386__)
+#define SP_OFFSET 8
+#define FRAME_SIZE_IN_BYTES 32u
+#else
+#endif
+
 namespace art {
 
 // Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
@@ -31,11 +40,10 @@
 extern "C" void artProxyInvokeHandler(Method* proxy_method, Object* receiver,
                                       Thread* self, byte* stack_args) {
   // Register the top of the managed stack
-  Method** proxy_sp = reinterpret_cast<Method**>(stack_args - 12);
+  Method** proxy_sp = reinterpret_cast<Method**>(stack_args - SP_OFFSET);
   DCHECK_EQ(*proxy_sp, proxy_method);
   self->SetTopOfStack(proxy_sp, 0);
-  // TODO: ARM specific
-  DCHECK_EQ(proxy_method->GetFrameSizeInBytes(), 48u);
+  DCHECK_EQ(proxy_method->GetFrameSizeInBytes(), FRAME_SIZE_IN_BYTES);
   // Start new JNI local reference state
   JNIEnvExt* env = self->GetJniEnv();
   ScopedJniEnvLocalRefState env_state(env);
@@ -67,7 +75,7 @@
     param_index++;
   }
   // Placing into local references incoming arguments from the caller's stack arguments
-  cur_arg += 11;  // skip callee saves, LR, Method* and out arg spills for R1 to R3
+  cur_arg += FRAME_SIZE_IN_BYTES / 4 - 1;  // skip callee saves, LR, Method* and out arg spills for R1 to R3
   while (param_index < num_params) {
     if (proxy_mh.IsParamAReference(param_index)) {
       Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
@@ -117,7 +125,7 @@
       JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
       if (cur_arg == 1 && (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble())) {
         // long/double split over regs and stack, mask in high half from stack arguments
-        uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args + (13 * kPointerSize));
+        uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args + ((FRAME_SIZE_IN_BYTES / 4 + 1) * kPointerSize));
         val.SetJ((val.GetJ() & 0xffffffffULL) | (high_half << 32));
       }
       BoxPrimitive(param_type->GetPrimitiveType(), val);
@@ -131,7 +139,7 @@
     param_index++;
   }
   // Placing into local references incoming arguments from the caller's stack arguments
-  cur_arg += 11;  // skip callee saves, LR, Method* and out arg spills for R1 to R3
+  cur_arg += FRAME_SIZE_IN_BYTES / 4 - 1;  // skip callee saves, LR, Method* and out arg spills for R1 to R3
   while (param_index < (num_params - 1)) {
     Class* param_type = param_types->Get(param_index);
     Object* obj;
diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S
index 74ae8fcc..d35afb7 100644
--- a/src/oat/runtime/x86/runtime_support_x86.S
+++ b/src/oat/runtime/x86/runtime_support_x86.S
@@ -358,6 +358,15 @@
     DELIVER_PENDING_EXCEPTION
 END_MACRO
 
+MACRO0(RETURN_OR_DELIVER_PENDING_EXCEPTION)
+    mov %fs:THREAD_EXCEPTION_OFFSET, %ebx // get exception field
+    testl %ebx, %ebx               // ebx == 0 ?
+    jnz 1f                         // if ebx != 0 goto 1
+    ret                            // return
+1:                                 // deliver exception on current thread
+    DELIVER_PENDING_EXCEPTION
+END_MACRO
+
 TWO_ARG_DOWNCALL art_alloc_object_from_code, artAllocObjectFromCode, RETURN_IF_EAX_NOT_ZERO
 TWO_ARG_DOWNCALL art_alloc_object_from_code_with_access_check, artAllocObjectFromCodeWithAccessCheck, RETURN_IF_EAX_NOT_ZERO
 THREE_ARG_DOWNCALL art_alloc_array_from_code, artAllocArrayFromCode, RETURN_IF_EAX_NOT_ZERO
@@ -592,7 +601,7 @@
     call SYMBOL(artGet32InstanceFromCode)  // (field_idx, Object*, referrer, Thread*, SP)
     addl LITERAL(32), %esp        // pop arguments
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
+    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
 
 DEFINE_FUNCTION art_get64_instance_from_code
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
@@ -607,7 +616,7 @@
     call SYMBOL(artGet64InstanceFromCode)  // (field_idx, Object*, referrer, Thread*, SP)
     addl LITERAL(32), %esp        // pop arguments
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
+    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
 
 DEFINE_FUNCTION art_get_obj_instance_from_code
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
@@ -622,7 +631,7 @@
     call SYMBOL(artGetObjInstanceFromCode) // (field_idx, Object*, referrer, Thread*, SP)
     addl LITERAL(32), %esp        // pop arguments
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
+    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
 
 DEFINE_FUNCTION art_set32_static_from_code
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
@@ -681,7 +690,7 @@
     call SYMBOL(artGet32StaticFromCode)    // (field_idx, referrer, Thread*, SP)
     addl LITERAL(16), %esp        // pop arguments
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
+    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
 
 DEFINE_FUNCTION art_get64_static_from_code
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
@@ -694,7 +703,7 @@
     call SYMBOL(artGet64StaticFromCode)    // (field_idx, referrer, Thread*, SP)
     addl LITERAL(16), %esp        // pop arguments
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
+    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
 
 DEFINE_FUNCTION art_get_obj_static_from_code
     SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
@@ -707,7 +716,20 @@
     call SYMBOL(artGetObjStaticFromCode)   // (field_idx, referrer, Thread*, SP)
     addl LITERAL(16), %esp        // pop arguments
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
-    RETURN_IF_EAX_ZERO            // return or deliver exception
+    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
+
+DEFINE_FUNCTION art_proxy_invoke_handler
+    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // save frame
+    lea 8(%esp), %ebx             // pointer to r2/r3/LR/caller's Method**/out-args as second arg
+    pushl %ebx                    // pass args
+    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
+    pushl %ecx                    // pass receiver
+    pushl %eax                    // pass proxy method
+    call SYMBOL(artProxyInvokeHandler)     // (proxy method, receiver, Thread*, args...)
+    mov 24(%esp), %eax            // get ret0 which was written into r2 on the stack
+    mov 28(%esp), %edx            // get ret1 which was written into r3 on the stack
+    addl LITERAL(44), %esp        // pop arguments
+    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
 
 MACRO1(UNIMPLEMENTED,name)
     .globl VAR(name, 0)
@@ -717,7 +739,6 @@
 END_MACRO
 
     // TODO: implement these!
-UNIMPLEMENTED art_proxy_invoke_handler
 UNIMPLEMENTED art_update_debugger
 UNIMPLEMENTED art_indexof
 UNIMPLEMENTED art_memcmp16