Portable refactorings.

Separate quick from portable entrypoints.
Move architectural dependencies into arch.

Change-Id: I9adbc0a9782e2959fdc3308215f01e3107632b7c
diff --git a/runtime/arch/x86/asm_support_x86.S b/runtime/arch/x86/asm_support_x86.S
new file mode 100644
index 0000000..7e6dce9
--- /dev/null
+++ b/runtime/arch/x86/asm_support_x86.S
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_
+#define ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_
+
+#include "asm_support_x86.h"
+
+#if defined(__APPLE__)
+    // Mac OS' as(1) doesn't let you name macro parameters.
+    #define MACRO0(macro_name) .macro macro_name
+    #define MACRO1(macro_name, macro_arg1) .macro macro_name
+    #define MACRO2(macro_name, macro_arg1, macro_args2) .macro macro_name
+    #define MACRO3(macro_name, macro_arg1, macro_args2, macro_args3) .macro macro_name
+    #define END_MACRO .endmacro
+
+    // Mac OS' as(1) uses $0, $1, and so on for macro arguments, and function names
+    // are mangled with an extra underscore prefix. The use of $x for arguments
+    // mean that literals need to be represented with $$x in macros.
+    #define SYMBOL(name) _ ## name
+    #define VAR(name,index) SYMBOL($index)
+    #define REG_VAR(name,index) %$index
+    #define CALL_MACRO(name,index) $index
+    #define LITERAL(value) $value
+    #define MACRO_LITERAL(value) $$value
+#else
+    // Regular gas(1) lets you name macro parameters.
+    #define MACRO0(macro_name) .macro macro_name
+    #define MACRO1(macro_name, macro_arg1) .macro macro_name macro_arg1
+    #define MACRO2(macro_name, macro_arg1, macro_arg2) .macro macro_name macro_arg1, macro_arg2
+    #define MACRO3(macro_name, macro_arg1, macro_arg2, macro_arg3) .macro macro_name macro_arg1, macro_arg2, macro_arg3
+    #define END_MACRO .endm
+
+    // Regular gas(1) uses \argument_name for macro arguments.
+    // We need to turn on alternate macro syntax so we can use & instead or the preprocessor
+    // will screw us by inserting a space between the \ and the name. Even in this mode there's
+    // no special meaning to $, so literals are still just $x. The use of altmacro means % is a
+    // special character meaning care needs to be taken when passing registers as macro arguments.
+    .altmacro
+    #define SYMBOL(name) name
+    #define VAR(name,index) name&
+    #define REG_VAR(name,index) %name
+    #define CALL_MACRO(name,index) name&
+    #define LITERAL(value) $value
+    #define MACRO_LITERAL(value) $value
+#endif
+
+    /* Cache alignment for function entry */
+MACRO0(ALIGN_FUNCTION_ENTRY)
+    .balign 16
+END_MACRO
+
+MACRO1(DEFINE_FUNCTION, c_name)
+    .type VAR(c_name, 0), @function
+    .globl VAR(c_name, 0)
+    ALIGN_FUNCTION_ENTRY
+VAR(c_name, 0):
+    .cfi_startproc
+END_MACRO
+
+MACRO1(END_FUNCTION, c_name)
+    .cfi_endproc
+    .size \c_name, .-\c_name
+END_MACRO
+
+MACRO1(PUSH, reg)
+  pushl REG_VAR(reg, 0)
+  .cfi_adjust_cfa_offset 4
+  .cfi_rel_offset REG_VAR(reg, 0), 0
+END_MACRO
+
+MACRO1(POP, reg)
+  popl REG_VAR(reg,0)
+  .cfi_adjust_cfa_offset -4
+  .cfi_restore REG_VAR(reg,0)
+END_MACRO
+
+#endif  // ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_
diff --git a/runtime/arch/x86/asm_support_x86.h b/runtime/arch/x86/asm_support_x86.h
new file mode 100644
index 0000000..1092910
--- /dev/null
+++ b/runtime/arch/x86/asm_support_x86.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_
+#define ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_
+
+#include "asm_support.h"
+
+// Offset of field Thread::self_ verified in InitCpu
+#define THREAD_SELF_OFFSET 40
+// Offset of field Thread::exception_ verified in InitCpu
+#define THREAD_EXCEPTION_OFFSET 12
+
+#endif  // ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_
diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc
new file mode 100644
index 0000000..d47dfef
--- /dev/null
+++ b/runtime/arch/x86/entrypoints_init_x86.cc
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "entrypoints/portable/portable_entrypoints.h"
+#include "entrypoints/quick/quick_entrypoints.h"
+#include "entrypoints/entrypoint_utils.h"
+
+namespace art {
+
+// Alloc entrypoints.
+extern "C" void* art_quick_alloc_array_from_code(uint32_t, void*, int32_t);
+extern "C" void* art_quick_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
+extern "C" void* art_quick_alloc_object_from_code(uint32_t type_idx, void* method);
+extern "C" void* art_quick_alloc_object_from_code_with_access_check(uint32_t type_idx, void* method);
+extern "C" void* art_quick_check_and_alloc_array_from_code(uint32_t, void*, int32_t);
+extern "C" void* art_quick_check_and_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
+
+// Cast entrypoints.
+extern "C" uint32_t art_quick_is_assignable_from_code(const mirror::Class* klass,
+                                                const mirror::Class* ref_class);
+extern "C" void art_quick_can_put_array_element_from_code(void*, void*);
+extern "C" void art_quick_check_cast_from_code(void*, void*);
+
+// DexCache entrypoints.
+extern "C" void* art_quick_initialize_static_storage_from_code(uint32_t, void*);
+extern "C" void* art_quick_initialize_type_from_code(uint32_t, void*);
+extern "C" void* art_quick_initialize_type_and_verify_access_from_code(uint32_t, void*);
+extern "C" void* art_quick_resolve_string_from_code(void*, uint32_t);
+
+// Field entrypoints.
+extern "C" int art_quick_set32_instance_from_code(uint32_t, void*, int32_t);
+extern "C" int art_quick_set32_static_from_code(uint32_t, int32_t);
+extern "C" int art_quick_set64_instance_from_code(uint32_t, void*, int64_t);
+extern "C" int art_quick_set64_static_from_code(uint32_t, int64_t);
+extern "C" int art_quick_set_obj_instance_from_code(uint32_t, void*, void*);
+extern "C" int art_quick_set_obj_static_from_code(uint32_t, void*);
+extern "C" int32_t art_quick_get32_instance_from_code(uint32_t, void*);
+extern "C" int32_t art_quick_get32_static_from_code(uint32_t);
+extern "C" int64_t art_quick_get64_instance_from_code(uint32_t, void*);
+extern "C" int64_t art_quick_get64_static_from_code(uint32_t);
+extern "C" void* art_quick_get_obj_instance_from_code(uint32_t, void*);
+extern "C" void* art_quick_get_obj_static_from_code(uint32_t);
+
+// FillArray entrypoint.
+extern "C" void art_quick_handle_fill_data_from_code(void*, void*);
+
+// Lock entrypoints.
+extern "C" void art_quick_lock_object_from_code(void*);
+extern "C" void art_quick_unlock_object_from_code(void*);
+
+// Math entrypoints.
+extern "C" double art_quick_fmod_from_code(double, double);
+extern "C" float art_quick_fmodf_from_code(float, float);
+extern "C" double art_quick_l2d_from_code(int64_t);
+extern "C" float art_quick_l2f_from_code(int64_t);
+extern "C" int64_t art_quick_d2l_from_code(double);
+extern "C" int64_t art_quick_f2l_from_code(float);
+extern "C" int32_t art_quick_idivmod_from_code(int32_t, int32_t);
+extern "C" int64_t art_quick_ldiv_from_code(int64_t, int64_t);
+extern "C" int64_t art_quick_ldivmod_from_code(int64_t, int64_t);
+extern "C" int64_t art_quick_lmul_from_code(int64_t, int64_t);
+extern "C" uint64_t art_quick_lshl_from_code(uint64_t, uint32_t);
+extern "C" uint64_t art_quick_lshr_from_code(uint64_t, uint32_t);
+extern "C" uint64_t art_quick_lushr_from_code(uint64_t, uint32_t);
+
+// Interpreter entrypoints.
+extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
+                                                 const DexFile::CodeItem* code_item,
+                                                 ShadowFrame* shadow_frame, JValue* result);
+extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
+                                           const DexFile::CodeItem* code_item,
+                                           ShadowFrame* shadow_frame, JValue* result);
+
+// Intrinsic entrypoints.
+extern "C" int32_t art_quick_memcmp16(void*, void*, int32_t);
+extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
+extern "C" int32_t art_quick_string_compareto(void*, void*);
+extern "C" void* art_quick_memcpy(void*, const void*, size_t);
+
+// Invoke entrypoints.
+extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
+                                                       mirror::Object* receiver,
+                                                       mirror::AbstractMethod** sp, Thread* thread);
+extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
+                                                    mirror::Object* receiver,
+                                                    mirror::AbstractMethod** sp, Thread* thread);
+extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
+extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*);
+extern "C" void art_quick_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
+
+// Thread entrypoints.
+extern void CheckSuspendFromCode(Thread* thread);
+extern "C" void art_quick_test_suspend();
+
+// Throw entrypoints.
+extern "C" void art_quick_deliver_exception_from_code(void*);
+extern "C" void art_quick_throw_array_bounds_from_code(int32_t index, int32_t limit);
+extern "C" void art_quick_throw_div_zero_from_code();
+extern "C" void art_quick_throw_no_such_method_from_code(int32_t method_idx);
+extern "C" void art_quick_throw_null_pointer_exception_from_code();
+extern "C" void art_quick_throw_stack_overflow_from_code(void*);
+
+void InitEntryPoints(QuickEntryPoints* qpoints, PortableEntryPoints* ppoints) {
+  // Alloc
+  qpoints->pAllocArrayFromCode = art_quick_alloc_array_from_code;
+  qpoints->pAllocArrayFromCodeWithAccessCheck = art_quick_alloc_array_from_code_with_access_check;
+  qpoints->pAllocObjectFromCode = art_quick_alloc_object_from_code;
+  qpoints->pAllocObjectFromCodeWithAccessCheck = art_quick_alloc_object_from_code_with_access_check;
+  qpoints->pCheckAndAllocArrayFromCode = art_quick_check_and_alloc_array_from_code;
+  qpoints->pCheckAndAllocArrayFromCodeWithAccessCheck = art_quick_check_and_alloc_array_from_code_with_access_check;
+
+  // Cast
+  qpoints->pInstanceofNonTrivialFromCode = art_quick_is_assignable_from_code;
+  qpoints->pCanPutArrayElementFromCode = art_quick_can_put_array_element_from_code;
+  qpoints->pCheckCastFromCode = art_quick_check_cast_from_code;
+
+  // DexCache
+  qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage_from_code;
+  qpoints->pInitializeTypeAndVerifyAccessFromCode = art_quick_initialize_type_and_verify_access_from_code;
+  qpoints->pInitializeTypeFromCode = art_quick_initialize_type_from_code;
+  qpoints->pResolveStringFromCode = art_quick_resolve_string_from_code;
+
+  // Field
+  qpoints->pSet32Instance = art_quick_set32_instance_from_code;
+  qpoints->pSet32Static = art_quick_set32_static_from_code;
+  qpoints->pSet64Instance = art_quick_set64_instance_from_code;
+  qpoints->pSet64Static = art_quick_set64_static_from_code;
+  qpoints->pSetObjInstance = art_quick_set_obj_instance_from_code;
+  qpoints->pSetObjStatic = art_quick_set_obj_static_from_code;
+  qpoints->pGet32Instance = art_quick_get32_instance_from_code;
+  qpoints->pGet64Instance = art_quick_get64_instance_from_code;
+  qpoints->pGetObjInstance = art_quick_get_obj_instance_from_code;
+  qpoints->pGet32Static = art_quick_get32_static_from_code;
+  qpoints->pGet64Static = art_quick_get64_static_from_code;
+  qpoints->pGetObjStatic = art_quick_get_obj_static_from_code;
+
+  // FillArray
+  qpoints->pHandleFillArrayDataFromCode = art_quick_handle_fill_data_from_code;
+
+  // JNI
+  qpoints->pJniMethodStart = JniMethodStart;
+  qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized;
+  qpoints->pJniMethodEnd = JniMethodEnd;
+  qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized;
+  qpoints->pJniMethodEndWithReference = JniMethodEndWithReference;
+  qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized;
+
+  // Locks
+  qpoints->pLockObjectFromCode = art_quick_lock_object_from_code;
+  qpoints->pUnlockObjectFromCode = art_quick_unlock_object_from_code;
+
+  // Math
+  // points->pCmpgDouble = NULL;  // Not needed on x86.
+  // points->pCmpgFloat = NULL;  // Not needed on x86.
+  // points->pCmplDouble = NULL;  // Not needed on x86.
+  // points->pCmplFloat = NULL;  // Not needed on x86.
+  qpoints->pFmod = art_quick_fmod_from_code;
+  qpoints->pL2d = art_quick_l2d_from_code;
+  qpoints->pFmodf = art_quick_fmodf_from_code;
+  qpoints->pL2f = art_quick_l2f_from_code;
+  // points->pD2iz = NULL;  // Not needed on x86.
+  // points->pF2iz = NULL;  // Not needed on x86.
+  qpoints->pIdivmod = art_quick_idivmod_from_code;
+  qpoints->pD2l = art_quick_d2l_from_code;
+  qpoints->pF2l = art_quick_f2l_from_code;
+  qpoints->pLdiv = art_quick_ldiv_from_code;
+  qpoints->pLdivmod = art_quick_ldivmod_from_code;
+  qpoints->pLmul = art_quick_lmul_from_code;
+  qpoints->pShlLong = art_quick_lshl_from_code;
+  qpoints->pShrLong = art_quick_lshr_from_code;
+  qpoints->pUshrLong = art_quick_lushr_from_code;
+
+  // Interpreter
+  qpoints->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry;
+  qpoints->pInterpreterToQuickEntry = artInterpreterToQuickEntry;
+
+  // Intrinsics
+  qpoints->pIndexOf = art_quick_indexof;
+  qpoints->pMemcmp16 = art_quick_memcmp16;
+  qpoints->pStringCompareTo = art_quick_string_compareto;
+  qpoints->pMemcpy = art_quick_memcpy;
+
+  // Invocation
+  qpoints->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline;
+  qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
+  qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
+  qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
+  qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check;
+  qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check;
+  qpoints->pInvokeVirtualTrampolineWithAccessCheck = art_quick_invoke_virtual_trampoline_with_access_check;
+
+  // Thread
+  qpoints->pCheckSuspendFromCode = CheckSuspendFromCode;
+  qpoints->pTestSuspendFromCode = art_quick_test_suspend;
+
+  // Throws
+  qpoints->pDeliverException = art_quick_deliver_exception_from_code;
+  qpoints->pThrowArrayBoundsFromCode = art_quick_throw_array_bounds_from_code;
+  qpoints->pThrowDivZeroFromCode = art_quick_throw_div_zero_from_code;
+  qpoints->pThrowNoSuchMethodFromCode = art_quick_throw_no_such_method_from_code;
+  qpoints->pThrowNullPointerFromCode = art_quick_throw_null_pointer_exception_from_code;
+  qpoints->pThrowStackOverflowFromCode = art_quick_throw_stack_overflow_from_code;
+
+  // Portable
+  ppoints->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline;
+};
+
+}  // namespace art
diff --git a/runtime/arch/x86/jni_entrypoints_x86.S b/runtime/arch/x86/jni_entrypoints_x86.S
new file mode 100644
index 0000000..e9c88fe
--- /dev/null
+++ b/runtime/arch/x86/jni_entrypoints_x86.S
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "asm_support_x86.S"
+
+    /*
+     * Portable resolution trampoline.
+     */
+DEFINE_FUNCTION art_jni_dlsym_lookup_stub
+    subl LITERAL(8), %esp         // align stack
+    .cfi_adjust_cfa_offset 8
+    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
+    .cfi_adjust_cfa_offset 4
+    call SYMBOL(artFindNativeMethod)  // (Thread*)
+    addl LITERAL(12), %esp        // restore the stack
+    .cfi_adjust_cfa_offset -12
+    cmpl LITERAL(0), %eax         // check if returned method code is null
+    je no_native_code_found       // if null, jump to return to handle
+    jmp *%eax                     // otherwise, tail call to intended method
+no_native_code_found:
+    ret
+END_FUNCTION art_jni_dlsym_lookup_stub
diff --git a/runtime/arch/x86/portable_entrypoints_x86.S b/runtime/arch/x86/portable_entrypoints_x86.S
new file mode 100644
index 0000000..a0fca6c
--- /dev/null
+++ b/runtime/arch/x86/portable_entrypoints_x86.S
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "asm_support_x86.S"
+
+    /*
+     * Portable invocation stub.
+     * On entry:
+     *   [sp] = return address
+     *   [sp + 4] = method pointer
+     *   [sp + 8] = argument array or NULL for no argument methods
+     *   [sp + 12] = size of argument array in bytes
+     *   [sp + 16] = (managed) thread pointer
+     *   [sp + 20] = JValue* result
+     *   [sp + 24] = result type char
+     */
+DEFINE_FUNCTION art_portable_invoke_stub
+    PUSH ebp                      // save ebp
+    PUSH ebx                      // save ebx
+    mov %esp, %ebp                // copy value of stack pointer into base pointer
+    .cfi_def_cfa_register ebp
+    mov 20(%ebp), %ebx            // get arg array size
+    addl LITERAL(28), %ebx        // reserve space for return addr, method*, ebx, and ebp in frame
+    andl LITERAL(0xFFFFFFF0), %ebx    // align frame size to 16 bytes
+    subl LITERAL(12), %ebx        // remove space for return address, ebx, and ebp
+    subl %ebx, %esp               // reserve stack space for argument array
+    lea  4(%esp), %eax            // use stack pointer + method ptr as dest for memcpy
+    pushl 20(%ebp)                // push size of region to memcpy
+    pushl 16(%ebp)                // push arg array as source of memcpy
+    pushl %eax                    // push stack pointer as destination of memcpy
+    call SYMBOL(memcpy)           // (void*, const void*, size_t)
+    addl LITERAL(12), %esp        // pop arguments to memcpy
+    mov 12(%ebp), %eax            // move method pointer into eax
+    mov %eax, (%esp)              // push method pointer onto stack
+    call *METHOD_CODE_OFFSET(%eax) // call the method
+    mov %ebp, %esp                // restore stack pointer
+    POP ebx                       // pop ebx
+    POP ebp                       // pop ebp
+    mov 20(%esp), %ecx            // get result pointer
+    cmpl LITERAL(68), 24(%esp)    // test if result type char == 'D'
+    je return_double_portable
+    cmpl LITERAL(70), 24(%esp)    // test if result type char == 'F'
+    je return_float_portable
+    mov %eax, (%ecx)              // store the result
+    mov %edx, 4(%ecx)             // store the other half of the result
+    ret
+return_double_portable:
+    fstpl (%ecx)                  // store the floating point result as double
+    ret
+return_float_portable:
+    fstps (%ecx)                  // store the floating point result as float
+    ret
+END_FUNCTION art_portable_invoke_stub
+
+DEFINE_FUNCTION art_portable_proxy_invoke_handler
+    // Fake callee save ref and args frame set up, note portable doesn't use callee save frames.
+    // TODO: just save the registers that are needed in artPortableProxyInvokeHandler.
+    PUSH edi  // Save callee saves
+    PUSH esi
+    PUSH ebp
+    PUSH ebx  // Save args
+    PUSH edx
+    PUSH ecx
+    PUSH eax   // Align stack, eax will be clobbered by Method*
+    // Begin argument set up.
+    PUSH esp                      // pass SP
+    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
+    .cfi_adjust_cfa_offset 4
+    PUSH ecx                      // pass receiver
+    PUSH eax                      // pass proxy method
+    call SYMBOL(artPortableProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
+    movd %eax, %xmm0              // place return value also into floating point return value
+    movd %edx, %xmm1
+    punpckldq %xmm1, %xmm0
+    addl LITERAL(44), %esp        // pop arguments
+    .cfi_adjust_cfa_offset -44
+    ret
+END_FUNCTION art_portable_proxy_invoke_handler
+
+    /*
+     * Portable abstract method error stub. method* is at %esp + 4 on entry.
+     */
+DEFINE_FUNCTION art_portable_abstract_method_error_stub
+    PUSH ebp
+    movl %esp, %ebp               // Remember SP.
+    .cfi_def_cfa_register ebp
+    subl LITERAL(12), %esp        // Align stack.
+    PUSH esp                      // Pass sp (not used).
+    pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
+    pushl 8(%ebp)                 // Pass Method*.
+    call SYMBOL(artThrowAbstractMethodErrorFromCode)  // (Method*, Thread*, SP)
+    leave                         // Restore the stack and %ebp.
+    .cfi_def_cfa esp, 4
+    .cfi_restore ebp
+    ret                           // Return to caller to handle pending exception.
+END_FUNCTION art_portable_abstract_method_error_stub
diff --git a/runtime/arch/x86/quick_entrypoints_init_x86.cc b/runtime/arch/x86/quick_entrypoints_init_x86.cc
deleted file mode 100644
index cced916..0000000
--- a/runtime/arch/x86/quick_entrypoints_init_x86.cc
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "entrypoints/quick/quick_entrypoints.h"
-#include "runtime_support.h"
-
-namespace art {
-
-// Alloc entrypoints.
-extern "C" void* art_quick_alloc_array_from_code(uint32_t, void*, int32_t);
-extern "C" void* art_quick_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
-extern "C" void* art_quick_alloc_object_from_code(uint32_t type_idx, void* method);
-extern "C" void* art_quick_alloc_object_from_code_with_access_check(uint32_t type_idx, void* method);
-extern "C" void* art_quick_check_and_alloc_array_from_code(uint32_t, void*, int32_t);
-extern "C" void* art_quick_check_and_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
-
-// Cast entrypoints.
-extern "C" uint32_t art_quick_is_assignable_from_code(const mirror::Class* klass,
-                                                const mirror::Class* ref_class);
-extern "C" void art_quick_can_put_array_element_from_code(void*, void*);
-extern "C" void art_quick_check_cast_from_code(void*, void*);
-
-// DexCache entrypoints.
-extern "C" void* art_quick_initialize_static_storage_from_code(uint32_t, void*);
-extern "C" void* art_quick_initialize_type_from_code(uint32_t, void*);
-extern "C" void* art_quick_initialize_type_and_verify_access_from_code(uint32_t, void*);
-extern "C" void* art_quick_resolve_string_from_code(void*, uint32_t);
-
-// Field entrypoints.
-extern "C" int art_quick_set32_instance_from_code(uint32_t, void*, int32_t);
-extern "C" int art_quick_set32_static_from_code(uint32_t, int32_t);
-extern "C" int art_quick_set64_instance_from_code(uint32_t, void*, int64_t);
-extern "C" int art_quick_set64_static_from_code(uint32_t, int64_t);
-extern "C" int art_quick_set_obj_instance_from_code(uint32_t, void*, void*);
-extern "C" int art_quick_set_obj_static_from_code(uint32_t, void*);
-extern "C" int32_t art_quick_get32_instance_from_code(uint32_t, void*);
-extern "C" int32_t art_quick_get32_static_from_code(uint32_t);
-extern "C" int64_t art_quick_get64_instance_from_code(uint32_t, void*);
-extern "C" int64_t art_quick_get64_static_from_code(uint32_t);
-extern "C" void* art_quick_get_obj_instance_from_code(uint32_t, void*);
-extern "C" void* art_quick_get_obj_static_from_code(uint32_t);
-
-// FillArray entrypoint.
-extern "C" void art_quick_handle_fill_data_from_code(void*, void*);
-
-// Lock entrypoints.
-extern "C" void art_quick_lock_object_from_code(void*);
-extern "C" void art_quick_unlock_object_from_code(void*);
-
-// Math entrypoints.
-extern "C" double art_quick_fmod_from_code(double, double);
-extern "C" float art_quick_fmodf_from_code(float, float);
-extern "C" double art_quick_l2d_from_code(int64_t);
-extern "C" float art_quick_l2f_from_code(int64_t);
-extern "C" int64_t art_quick_d2l_from_code(double);
-extern "C" int64_t art_quick_f2l_from_code(float);
-extern "C" int32_t art_quick_idivmod_from_code(int32_t, int32_t);
-extern "C" int64_t art_quick_ldiv_from_code(int64_t, int64_t);
-extern "C" int64_t art_quick_ldivmod_from_code(int64_t, int64_t);
-extern "C" int64_t art_quick_lmul_from_code(int64_t, int64_t);
-extern "C" uint64_t art_quick_lshl_from_code(uint64_t, uint32_t);
-extern "C" uint64_t art_quick_lshr_from_code(uint64_t, uint32_t);
-extern "C" uint64_t art_quick_lushr_from_code(uint64_t, uint32_t);
-
-// Interpreter entrypoints.
-extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh,
-                                                 const DexFile::CodeItem* code_item,
-                                                 ShadowFrame* shadow_frame, JValue* result);
-extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh,
-                                           const DexFile::CodeItem* code_item,
-                                           ShadowFrame* shadow_frame, JValue* result);
-
-// Intrinsic entrypoints.
-extern "C" int32_t art_quick_memcmp16(void*, void*, int32_t);
-extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
-extern "C" int32_t art_quick_string_compareto(void*, void*);
-extern "C" void* art_quick_memcpy(void*, const void*, size_t);
-
-// Invoke entrypoints.
-extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called,
-                                                       mirror::Object* receiver,
-                                                       mirror::AbstractMethod** sp, Thread* thread);
-extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called,
-                                                    mirror::Object* receiver,
-                                                    mirror::AbstractMethod** sp, Thread* thread);
-extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*);
-extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*);
-extern "C" void art_quick_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
-
-// Thread entrypoints.
-extern void CheckSuspendFromCode(Thread* thread);
-extern "C" void art_quick_test_suspend();
-
-// Throw entrypoints.
-extern "C" void art_quick_deliver_exception_from_code(void*);
-extern "C" void art_quick_throw_array_bounds_from_code(int32_t index, int32_t limit);
-extern "C" void art_quick_throw_div_zero_from_code();
-extern "C" void art_quick_throw_no_such_method_from_code(int32_t method_idx);
-extern "C" void art_quick_throw_null_pointer_exception_from_code();
-extern "C" void art_quick_throw_stack_overflow_from_code(void*);
-
-void InitEntryPoints(QuickEntryPoints* points) {
-  // Alloc
-  points->pAllocArrayFromCode = art_quick_alloc_array_from_code;
-  points->pAllocArrayFromCodeWithAccessCheck = art_quick_alloc_array_from_code_with_access_check;
-  points->pAllocObjectFromCode = art_quick_alloc_object_from_code;
-  points->pAllocObjectFromCodeWithAccessCheck = art_quick_alloc_object_from_code_with_access_check;
-  points->pCheckAndAllocArrayFromCode = art_quick_check_and_alloc_array_from_code;
-  points->pCheckAndAllocArrayFromCodeWithAccessCheck = art_quick_check_and_alloc_array_from_code_with_access_check;
-
-  // Cast
-  points->pInstanceofNonTrivialFromCode = art_quick_is_assignable_from_code;
-  points->pCanPutArrayElementFromCode = art_quick_can_put_array_element_from_code;
-  points->pCheckCastFromCode = art_quick_check_cast_from_code;
-
-  // DexCache
-  points->pInitializeStaticStorage = art_quick_initialize_static_storage_from_code;
-  points->pInitializeTypeAndVerifyAccessFromCode = art_quick_initialize_type_and_verify_access_from_code;
-  points->pInitializeTypeFromCode = art_quick_initialize_type_from_code;
-  points->pResolveStringFromCode = art_quick_resolve_string_from_code;
-
-  // Field
-  points->pSet32Instance = art_quick_set32_instance_from_code;
-  points->pSet32Static = art_quick_set32_static_from_code;
-  points->pSet64Instance = art_quick_set64_instance_from_code;
-  points->pSet64Static = art_quick_set64_static_from_code;
-  points->pSetObjInstance = art_quick_set_obj_instance_from_code;
-  points->pSetObjStatic = art_quick_set_obj_static_from_code;
-  points->pGet32Instance = art_quick_get32_instance_from_code;
-  points->pGet64Instance = art_quick_get64_instance_from_code;
-  points->pGetObjInstance = art_quick_get_obj_instance_from_code;
-  points->pGet32Static = art_quick_get32_static_from_code;
-  points->pGet64Static = art_quick_get64_static_from_code;
-  points->pGetObjStatic = art_quick_get_obj_static_from_code;
-
-  // FillArray
-  points->pHandleFillArrayDataFromCode = art_quick_handle_fill_data_from_code;
-
-  // JNI
-  points->pJniMethodStart = JniMethodStart;
-  points->pJniMethodStartSynchronized = JniMethodStartSynchronized;
-  points->pJniMethodEnd = JniMethodEnd;
-  points->pJniMethodEndSynchronized = JniMethodEndSynchronized;
-  points->pJniMethodEndWithReference = JniMethodEndWithReference;
-  points->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized;
-
-  // Locks
-  points->pLockObjectFromCode = art_quick_lock_object_from_code;
-  points->pUnlockObjectFromCode = art_quick_unlock_object_from_code;
-
-  // Math
-  // points->pCmpgDouble = NULL;  // Not needed on x86.
-  // points->pCmpgFloat = NULL;  // Not needed on x86.
-  // points->pCmplDouble = NULL;  // Not needed on x86.
-  // points->pCmplFloat = NULL;  // Not needed on x86.
-  points->pFmod = art_quick_fmod_from_code;
-  points->pL2d = art_quick_l2d_from_code;
-  points->pFmodf = art_quick_fmodf_from_code;
-  points->pL2f = art_quick_l2f_from_code;
-  // points->pD2iz = NULL;  // Not needed on x86.
-  // points->pF2iz = NULL;  // Not needed on x86.
-  points->pIdivmod = art_quick_idivmod_from_code;
-  points->pD2l = art_quick_d2l_from_code;
-  points->pF2l = art_quick_f2l_from_code;
-  points->pLdiv = art_quick_ldiv_from_code;
-  points->pLdivmod = art_quick_ldivmod_from_code;
-  points->pLmul = art_quick_lmul_from_code;
-  points->pShlLong = art_quick_lshl_from_code;
-  points->pShrLong = art_quick_lshr_from_code;
-  points->pUshrLong = art_quick_lushr_from_code;
-
-  // Interpreter
-  points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry;
-  points->pInterpreterToQuickEntry = artInterpreterToQuickEntry;
-
-  // Intrinsics
-  points->pIndexOf = art_quick_indexof;
-  points->pMemcmp16 = art_quick_memcmp16;
-  points->pStringCompareTo = art_quick_string_compareto;
-  points->pMemcpy = art_quick_memcpy;
-
-  // Invocation
-  points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline;
-  points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline;
-  points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check;
-  points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline;
-  points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check;
-  points->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check;
-  points->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check;
-  points->pInvokeVirtualTrampolineWithAccessCheck = art_quick_invoke_virtual_trampoline_with_access_check;
-
-  // Thread
-  points->pCheckSuspendFromCode = CheckSuspendFromCode;
-  points->pTestSuspendFromCode = art_quick_test_suspend;
-
-  // Throws
-  points->pDeliverException = art_quick_deliver_exception_from_code;
-  points->pThrowArrayBoundsFromCode = art_quick_throw_array_bounds_from_code;
-  points->pThrowDivZeroFromCode = art_quick_throw_div_zero_from_code;
-  points->pThrowNoSuchMethodFromCode = art_quick_throw_no_such_method_from_code;
-  points->pThrowNullPointerFromCode = art_quick_throw_null_pointer_exception_from_code;
-  points->pThrowStackOverflowFromCode = art_quick_throw_stack_overflow_from_code;
-};
-
-}  // namespace art
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index ee6db0c..89ea71a 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -14,76 +14,7 @@
  * limitations under the License.
  */
 
-#include "asm_support.h"
-
-#if defined(__APPLE__)
-    // Mac OS' as(1) doesn't let you name macro parameters.
-    #define MACRO0(macro_name) .macro macro_name
-    #define MACRO1(macro_name, macro_arg1) .macro macro_name
-    #define MACRO2(macro_name, macro_arg1, macro_args2) .macro macro_name
-    #define MACRO3(macro_name, macro_arg1, macro_args2, macro_args3) .macro macro_name
-    #define END_MACRO .endmacro
-
-    // Mac OS' as(1) uses $0, $1, and so on for macro arguments, and function names
-    // are mangled with an extra underscore prefix. The use of $x for arguments
-    // mean that literals need to be represented with $$x in macros.
-    #define SYMBOL(name) _ ## name
-    #define VAR(name,index) SYMBOL($index)
-    #define REG_VAR(name,index) %$index
-    #define CALL_MACRO(name,index) $index
-    #define LITERAL(value) $value
-    #define MACRO_LITERAL(value) $$value
-#else
-    // Regular gas(1) lets you name macro parameters.
-    #define MACRO0(macro_name) .macro macro_name
-    #define MACRO1(macro_name, macro_arg1) .macro macro_name macro_arg1
-    #define MACRO2(macro_name, macro_arg1, macro_arg2) .macro macro_name macro_arg1, macro_arg2
-    #define MACRO3(macro_name, macro_arg1, macro_arg2, macro_arg3) .macro macro_name macro_arg1, macro_arg2, macro_arg3
-    #define END_MACRO .endm
-
-    // Regular gas(1) uses \argument_name for macro arguments.
-    // We need to turn on alternate macro syntax so we can use & instead or the preprocessor
-    // will screw us by inserting a space between the \ and the name. Even in this mode there's
-    // no special meaning to $, so literals are still just $x. The use of altmacro means % is a
-    // special character meaning care needs to be taken when passing registers as macro arguments.
-    .altmacro
-    #define SYMBOL(name) name
-    #define VAR(name,index) name&
-    #define REG_VAR(name,index) %name
-    #define CALL_MACRO(name,index) name&
-    #define LITERAL(value) $value
-    #define MACRO_LITERAL(value) $value
-#endif
-
-    /* Cache alignment for function entry */
-MACRO0(ALIGN_FUNCTION_ENTRY)
-    .balign 16
-END_MACRO
-
-MACRO1(DEFINE_FUNCTION, c_name)
-    .type VAR(c_name, 0), @function
-    .globl VAR(c_name, 0)
-    ALIGN_FUNCTION_ENTRY
-VAR(c_name, 0):
-    .cfi_startproc
-END_MACRO
-
-MACRO1(END_FUNCTION, c_name)
-    .cfi_endproc
-    .size \c_name, .-\c_name
-END_MACRO
-
-MACRO1(PUSH, reg)
-  pushl REG_VAR(reg, 0)
-  .cfi_adjust_cfa_offset 4
-  .cfi_rel_offset REG_VAR(reg, 0), 0
-END_MACRO
-
-MACRO1(POP, reg)
-  popl REG_VAR(reg,0)
-  .cfi_adjust_cfa_offset -4
-  .cfi_restore REG_VAR(reg,0)
-END_MACRO
+#include "asm_support_x86.S"
 
     /*
      * Macro that sets up the callee save frame to conform with
@@ -302,55 +233,6 @@
 INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
 
     /*
-     * Portable invocation stub.
-     * On entry:
-     *   [sp] = return address
-     *   [sp + 4] = method pointer
-     *   [sp + 8] = argument array or NULL for no argument methods
-     *   [sp + 12] = size of argument array in bytes
-     *   [sp + 16] = (managed) thread pointer
-     *   [sp + 20] = JValue* result
-     *   [sp + 24] = result type char
-     */
-DEFINE_FUNCTION art_portable_invoke_stub
-    PUSH ebp                      // save ebp
-    PUSH ebx                      // save ebx
-    mov %esp, %ebp                // copy value of stack pointer into base pointer
-    .cfi_def_cfa_register ebp
-    mov 20(%ebp), %ebx            // get arg array size
-    addl LITERAL(28), %ebx        // reserve space for return addr, method*, ebx, and ebp in frame
-    andl LITERAL(0xFFFFFFF0), %ebx    // align frame size to 16 bytes
-    subl LITERAL(12), %ebx        // remove space for return address, ebx, and ebp
-    subl %ebx, %esp               // reserve stack space for argument array
-    lea  4(%esp), %eax            // use stack pointer + method ptr as dest for memcpy
-    pushl 20(%ebp)                // push size of region to memcpy
-    pushl 16(%ebp)                // push arg array as source of memcpy
-    pushl %eax                    // push stack pointer as destination of memcpy
-    call SYMBOL(memcpy)           // (void*, const void*, size_t)
-    addl LITERAL(12), %esp        // pop arguments to memcpy
-    mov 12(%ebp), %eax            // move method pointer into eax
-    mov %eax, (%esp)              // push method pointer onto stack
-    call *METHOD_CODE_OFFSET(%eax) // call the method
-    mov %ebp, %esp                // restore stack pointer
-    POP ebx                       // pop ebx
-    POP ebp                       // pop ebp
-    mov 20(%esp), %ecx            // get result pointer
-    cmpl LITERAL(68), 24(%esp)    // test if result type char == 'D'
-    je return_double_portable
-    cmpl LITERAL(70), 24(%esp)    // test if result type char == 'F'
-    je return_float_portable
-    mov %eax, (%ecx)              // store the result
-    mov %edx, 4(%ecx)             // store the other half of the result
-    ret
-return_double_portable:
-    fstpl (%ecx)                  // store the floating point result as double
-    ret
-return_float_portable:
-    fstps (%ecx)                  // store the floating point result as float
-    ret
-END_FUNCTION art_portable_invoke_stub
-
-    /*
      * Quick invocation stub.
      * On entry:
      *   [sp] = return address
@@ -920,22 +802,6 @@
     RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
 END_FUNCTION art_quick_get_obj_static_from_code
 
-DEFINE_FUNCTION art_portable_proxy_invoke_handler
-    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // save frame and Method*
-    PUSH esp                      // pass SP
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    .cfi_adjust_cfa_offset 4
-    PUSH ecx                      // pass receiver
-    PUSH eax                      // pass proxy method
-    call SYMBOL(artPortableProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
-    movd %eax, %xmm0              // place return value also into floating point return value
-    movd %edx, %xmm1
-    punpckldq %xmm1, %xmm0
-    addl LITERAL(44), %esp        // pop arguments
-    .cfi_adjust_cfa_offset -44
-    ret
-END_FUNCTION art_portable_proxy_invoke_handler
-
 DEFINE_FUNCTION art_quick_proxy_invoke_handler
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // save frame and Method*
     PUSH esp                      // pass SP
@@ -1054,24 +920,6 @@
 END_FUNCTION art_quick_deoptimize
 
     /*
-     * Portable abstract method error stub. method* is at %esp + 4 on entry.
-     */
-DEFINE_FUNCTION art_portable_abstract_method_error_stub
-    PUSH ebp
-    movl %esp, %ebp               // Remember SP.
-    .cfi_def_cfa_register ebp
-    subl LITERAL(12), %esp        // Align stack.
-    PUSH esp                      // Pass sp (not used).
-    pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
-    pushl 8(%ebp)                 // Pass Method*.
-    call SYMBOL(artThrowAbstractMethodErrorFromCode)  // (Method*, Thread*, SP)
-    leave                         // Restore the stack and %ebp.
-    .cfi_def_cfa esp, 4
-    .cfi_restore ebp
-    ret                           // Return to caller to handle pending exception.
-END_FUNCTION art_portable_abstract_method_error_stub
-
-    /*
      * Quick abstract method error stub. %eax contains method* on entry.
      */
 DEFINE_FUNCTION art_quick_abstract_method_error_stub
@@ -1087,24 +935,6 @@
 END_FUNCTION art_quick_abstract_method_error_stub
 
     /*
-     * Portable resolution trampoline.
-     */
-DEFINE_FUNCTION art_jni_dlsym_lookup_stub
-    subl LITERAL(8), %esp         // align stack
-    .cfi_adjust_cfa_offset 8
-    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
-    .cfi_adjust_cfa_offset 4
-    call SYMBOL(artFindNativeMethod)  // (Thread*)
-    addl LITERAL(12), %esp        // restore the stack
-    .cfi_adjust_cfa_offset -12
-    cmpl LITERAL(0), %eax         // check if returned method code is null
-    je no_native_code_found       // if null, jump to return to handle
-    jmp *%eax                     // otherwise, tail call to intended method
-no_native_code_found:
-    ret
-END_FUNCTION art_jni_dlsym_lookup_stub
-
-    /*
      * String's indexOf.
      *
      * On entry:
diff --git a/runtime/arch/x86/thread_x86.cc b/runtime/arch/x86/thread_x86.cc
new file mode 100644
index 0000000..dd3e7dd
--- /dev/null
+++ b/runtime/arch/x86/thread_x86.cc
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "thread.h"
+
+#include <sys/syscall.h>
+#include <sys/types.h>
+
+#include "asm_support_x86.h"
+#include "base/macros.h"
+#include "thread.h"
+#include "thread_list.h"
+
+#if defined(__APPLE__)
+#include <architecture/i386/table.h>
+#include <i386/user_ldt.h>
+struct descriptor_table_entry_t {
+  uint16_t limit0;
+  uint16_t base0;
+  unsigned base1: 8, type: 4, s: 1, dpl: 2, p: 1;
+  unsigned limit: 4, avl: 1, l: 1, d: 1, g: 1, base2: 8;
+} __attribute__((packed));
+#define MODIFY_LDT_CONTENTS_DATA 0
+#else
+#include <asm/ldt.h>
+#endif
+
+namespace art {
+
+void Thread::InitCpu() {
+  static Mutex modify_ldt_lock("modify_ldt lock");
+  MutexLock mu(Thread::Current(), modify_ldt_lock);
+
+  const uintptr_t base = reinterpret_cast<uintptr_t>(this);
+  const size_t limit = kPageSize;
+
+  const int contents = MODIFY_LDT_CONTENTS_DATA;
+  const int seg_32bit = 1;
+  const int read_exec_only = 0;
+  const int limit_in_pages = 0;
+  const int seg_not_present = 0;
+  const int useable = 1;
+
+  int entry_number = -1;
+
+#if defined(__APPLE__)
+  descriptor_table_entry_t entry;
+  memset(&entry, 0, sizeof(entry));
+  entry.limit0 = (limit & 0x0ffff);
+  entry.limit  = (limit & 0xf0000) >> 16;
+  entry.base0 = (base & 0x0000ffff);
+  entry.base1 = (base & 0x00ff0000) >> 16;
+  entry.base2 = (base & 0xff000000) >> 24;
+  entry.type = ((read_exec_only ^ 1) << 1) | (contents << 2);
+  entry.s = 1;
+  entry.dpl = 0x3;
+  entry.p = seg_not_present ^ 1;
+  entry.avl = useable;
+  entry.l = 0;
+  entry.d = seg_32bit;
+  entry.g = limit_in_pages;
+
+  entry_number = i386_set_ldt(LDT_AUTO_ALLOC, reinterpret_cast<ldt_entry*>(&entry), 1);
+  if (entry_number == -1) {
+    PLOG(FATAL) << "i386_set_ldt failed";
+  }
+#else
+  // Read current LDT entries.
+  CHECK_EQ((size_t)LDT_ENTRY_SIZE, sizeof(uint64_t));
+  std::vector<uint64_t> ldt(LDT_ENTRIES);
+  size_t ldt_size(sizeof(uint64_t) * ldt.size());
+  memset(&ldt[0], 0, ldt_size);
+  // TODO: why doesn't this return LDT_ENTRY_SIZE * LDT_ENTRIES for the main thread?
+  syscall(__NR_modify_ldt, 0, &ldt[0], ldt_size);
+
+  // Find the first empty slot.
+  for (entry_number = 0; entry_number < LDT_ENTRIES && ldt[entry_number] != 0; ++entry_number) {
+  }
+  if (entry_number >= LDT_ENTRIES) {
+    LOG(FATAL) << "Failed to find a free LDT slot";
+  }
+
+  // Update LDT entry.
+  user_desc ldt_entry;
+  memset(&ldt_entry, 0, sizeof(ldt_entry));
+  ldt_entry.entry_number = entry_number;
+  ldt_entry.base_addr = base;
+  ldt_entry.limit = limit;
+  ldt_entry.seg_32bit = seg_32bit;
+  ldt_entry.contents = contents;
+  ldt_entry.read_exec_only = read_exec_only;
+  ldt_entry.limit_in_pages = limit_in_pages;
+  ldt_entry.seg_not_present = seg_not_present;
+  ldt_entry.useable = useable;
+  CHECK_EQ(0, syscall(__NR_modify_ldt, 1, &ldt_entry, sizeof(ldt_entry)));
+  entry_number = ldt_entry.entry_number;
+#endif
+
+  // Change %fs to be new LDT entry.
+  uint16_t table_indicator = 1 << 2;  // LDT
+  uint16_t rpl = 3;  // Requested privilege level
+  uint16_t selector = (entry_number << 3) | table_indicator | rpl;
+  // TODO: use our assembler to generate code
+  __asm__ __volatile__("movw %w0, %%fs"
+      :    // output
+      : "q"(selector)  // input
+      :);  // clobber
+
+  // Allow easy indirection back to Thread*.
+  self_ = this;
+
+  // Sanity check that reads from %fs point 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"(THREAD_SELF_OFFSET)  // input
+      :);  // clobber
+  CHECK_EQ(self_check, this);
+
+  // Sanity check other offsets.
+  CHECK_EQ(THREAD_EXCEPTION_OFFSET, OFFSETOF_MEMBER(Thread, exception_));
+}
+
+}  // namespace art