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