From 1a5c40672783fac98aca5a04ac798a0a0014de65 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Thu, 15 Jan 2015 12:10:47 -0800 Subject: ART: Mips64 runtime support Interpret-only Mips64 runtime support. Change-Id: Iee22d0c8c77105d9b2f03a67dc4e09957fe0ab0a --- runtime/Android.mk | 13 +- runtime/arch/arch_test.cc | 17 + runtime/arch/context.cc | 8 +- runtime/arch/mips64/asm_support_mips64.S | 71 ++ runtime/arch/mips64/asm_support_mips64.h | 29 + runtime/arch/mips64/context_mips64.cc | 147 ++++ runtime/arch/mips64/context_mips64.h | 92 +++ runtime/arch/mips64/entrypoints_init_mips64.cc | 180 +++++ runtime/arch/mips64/fault_handler_mips64.cc | 57 ++ runtime/arch/mips64/jni_entrypoints_mips64.S | 76 ++ runtime/arch/mips64/memcmp16_mips64.S | 50 ++ runtime/arch/mips64/quick_entrypoints_mips64.S | 897 +++++++++++++++++++++ .../arch/mips64/quick_method_frame_info_mips64.h | 1 + runtime/arch/mips64/thread_mips64.cc | 34 + runtime/atomic.h | 3 + .../quick/quick_trampoline_entrypoints.cc | 134 ++- runtime/vmap_table.h | 2 +- 17 files changed, 1785 insertions(+), 26 deletions(-) create mode 100644 runtime/arch/mips64/asm_support_mips64.S create mode 100644 runtime/arch/mips64/asm_support_mips64.h create mode 100644 runtime/arch/mips64/context_mips64.cc create mode 100644 runtime/arch/mips64/context_mips64.h create mode 100644 runtime/arch/mips64/entrypoints_init_mips64.cc create mode 100644 runtime/arch/mips64/fault_handler_mips64.cc create mode 100644 runtime/arch/mips64/jni_entrypoints_mips64.S create mode 100644 runtime/arch/mips64/memcmp16_mips64.S create mode 100644 runtime/arch/mips64/quick_entrypoints_mips64.S create mode 100644 runtime/arch/mips64/thread_mips64.cc (limited to 'runtime') diff --git a/runtime/Android.mk b/runtime/Android.mk index 3330b2dcb9..fdc3e7c82f 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -264,9 +264,15 @@ LIBART_TARGET_SRC_FILES_mips := \ arch/mips/thread_mips.cc \ arch/mips/fault_handler_mips.cc -ifeq ($(TARGET_ARCH),mips64) -$(info TODOMips64: $(LOCAL_PATH)/Android.mk Add mips64 specific runtime files) -endif # TARGET_ARCH != mips64 +LIBART_TARGET_SRC_FILES_mips64 := \ + arch/mips64/context_mips64.cc \ + arch/mips64/entrypoints_init_mips64.cc \ + arch/mips64/jni_entrypoints_mips64.S \ + arch/mips64/memcmp16_mips64.S \ + arch/mips64/quick_entrypoints_mips64.S \ + arch/mips64/thread_mips64.cc \ + monitor_pool.cc \ + arch/mips64/fault_handler_mips64.cc LIBART_HOST_SRC_FILES := \ $(LIBART_COMMON_SRC_FILES) \ @@ -525,6 +531,7 @@ LIBART_TARGET_SRC_FILES_arm64 := LIBART_TARGET_SRC_FILES_x86 := LIBART_TARGET_SRC_FILES_x86_64 := LIBART_TARGET_SRC_FILES_mips := +LIBART_TARGET_SRC_FILES_mips64 := LIBART_HOST_SRC_FILES := LIBART_HOST_SRC_FILES_32 := LIBART_HOST_SRC_FILES_64 := diff --git a/runtime/arch/arch_test.cc b/runtime/arch/arch_test.cc index cac500c13e..ab6b00bddf 100644 --- a/runtime/arch/arch_test.cc +++ b/runtime/arch/arch_test.cc @@ -82,6 +82,16 @@ static constexpr size_t kFrameSizeRefsAndArgsCalleeSave = FRAME_SIZE_REFS_AND_AR #undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE } +namespace mips64 { +#include "arch/mips64/asm_support_mips64.h" +static constexpr size_t kFrameSizeSaveAllCalleeSave = FRAME_SIZE_SAVE_ALL_CALLEE_SAVE; +#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE +static constexpr size_t kFrameSizeRefsOnlyCalleeSave = FRAME_SIZE_REFS_ONLY_CALLEE_SAVE; +#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE +static constexpr size_t kFrameSizeRefsAndArgsCalleeSave = FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE; +#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE +} + namespace x86 { #include "arch/x86/asm_support_x86.h" static constexpr size_t kFrameSizeSaveAllCalleeSave = FRAME_SIZE_SAVE_ALL_CALLEE_SAVE; @@ -124,6 +134,13 @@ TEST_F(ArchTest, MIPS) { mips::kFrameSizeRefsAndArgsCalleeSave); } +TEST_F(ArchTest, MIPS64) { + CheckFrameSize(InstructionSet::kMips64, Runtime::kSaveAll, mips64::kFrameSizeSaveAllCalleeSave); + CheckFrameSize(InstructionSet::kMips64, Runtime::kRefsOnly, mips64::kFrameSizeRefsOnlyCalleeSave); + CheckFrameSize(InstructionSet::kMips64, Runtime::kRefsAndArgs, + mips64::kFrameSizeRefsAndArgsCalleeSave); +} + TEST_F(ArchTest, X86) { CheckFrameSize(InstructionSet::kX86, Runtime::kSaveAll, x86::kFrameSizeSaveAllCalleeSave); CheckFrameSize(InstructionSet::kX86, Runtime::kRefsOnly, x86::kFrameSizeRefsOnlyCalleeSave); diff --git a/runtime/arch/context.cc b/runtime/arch/context.cc index b1700bbef8..bf40a3f8ce 100644 --- a/runtime/arch/context.cc +++ b/runtime/arch/context.cc @@ -20,8 +20,10 @@ #include "arm/context_arm.h" #elif defined(__aarch64__) #include "arm64/context_arm64.h" -#elif defined(__mips__) +#elif defined(__mips__) && !defined(__LP64__) #include "mips/context_mips.h" +#elif defined(__mips__) && defined(__LP64__) +#include "mips64/context_mips64.h" #elif defined(__i386__) #include "x86/context_x86.h" #elif defined(__x86_64__) @@ -37,8 +39,10 @@ Context* Context::Create() { return new arm::ArmContext(); #elif defined(__aarch64__) return new arm64::Arm64Context(); -#elif defined(__mips__) +#elif defined(__mips__) && !defined(__LP64__) return new mips::MipsContext(); +#elif defined(__mips__) && defined(__LP64__) + return new mips64::Mips64Context(); #elif defined(__i386__) return new x86::X86Context(); #elif defined(__x86_64__) diff --git a/runtime/arch/mips64/asm_support_mips64.S b/runtime/arch/mips64/asm_support_mips64.S new file mode 100644 index 0000000000..10976bb70d --- /dev/null +++ b/runtime/arch/mips64/asm_support_mips64.S @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2014 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_MIPS64_ASM_SUPPORT_MIPS64_S_ +#define ART_RUNTIME_ARCH_MIPS64_ASM_SUPPORT_MIPS64_S_ + +#include "asm_support_mips64.h" + +// Define special registers. + +// Register holding suspend check count down. +#define rSUSPEND $s0 +// Register holding Thread::Current(). +#define rSELF $s1 + + + // Declare a function called name, sets up $gp. +.macro ENTRY name + .type \name, %function + .global \name + // Cache alignment for function entry. + .balign 16 +\name: + .cfi_startproc + // Ensure we get a sane starting CFA. + .cfi_def_cfa $sp,0 + // Load $gp. We expect that ".set noreorder" is in effect. + .cpload $t9 + // Declare a local convenience label to be branched to when $gp is already set up. +.L\name\()_gp_set: +.endm + + // Declare a function called name, doesn't set up $gp. +.macro ENTRY_NO_GP name + .type \name, %function + .global \name + // Cache alignment for function entry. + .balign 16 +\name: + .cfi_startproc + // Ensure we get a sane starting CFA. + .cfi_def_cfa $sp,0 +.endm + +.macro END name + .cfi_endproc + .size \name, .-\name +.endm + +.macro UNIMPLEMENTED name + ENTRY \name + break + break + END \name +.endm + + +#endif // ART_RUNTIME_ARCH_MIPS64_ASM_SUPPORT_MIPS64_S_ diff --git a/runtime/arch/mips64/asm_support_mips64.h b/runtime/arch/mips64/asm_support_mips64.h new file mode 100644 index 0000000000..995fcf37bf --- /dev/null +++ b/runtime/arch/mips64/asm_support_mips64.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2014 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_MIPS64_ASM_SUPPORT_MIPS64_H_ +#define ART_RUNTIME_ARCH_MIPS64_ASM_SUPPORT_MIPS64_H_ + +#include "asm_support.h" + +// 64 ($f24-$f31) + 64 ($s0-$s7) + 8 ($gp) + 8 ($s8) + 8 ($ra) + 1x8 bytes padding +#define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 160 +// 48 ($s2-$s7) + 8 ($gp) + 8 ($s8) + 8 ($ra) + 1x8 bytes padding +#define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 80 +// $f12-$f19, $a1-$a7, $s2-$s7 + $gp + $s8 + $ra, 16 total + 1x8 bytes padding + method* +#define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 208 + +#endif // ART_RUNTIME_ARCH_MIPS64_ASM_SUPPORT_MIPS64_H_ diff --git a/runtime/arch/mips64/context_mips64.cc b/runtime/arch/mips64/context_mips64.cc new file mode 100644 index 0000000000..7523adee31 --- /dev/null +++ b/runtime/arch/mips64/context_mips64.cc @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2014 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 "context_mips64.h" + +#include "mirror/art_method-inl.h" +#include "quick/quick_method_frame_info.h" +#include "util.h" + +namespace art { +namespace mips64 { + +static constexpr uintptr_t gZero = 0; + +void Mips64Context::Reset() { + for (size_t i = 0; i < kNumberOfGpuRegisters; i++) { + gprs_[i] = nullptr; + } + for (size_t i = 0; i < kNumberOfFpuRegisters; i++) { + fprs_[i] = nullptr; + } + gprs_[SP] = &sp_; + gprs_[RA] = &ra_; + // Initialize registers with easy to spot debug values. + sp_ = Mips64Context::kBadGprBase + SP; + ra_ = Mips64Context::kBadGprBase + RA; +} + +void Mips64Context::FillCalleeSaves(const StackVisitor& fr) { + mirror::ArtMethod* method = fr.GetMethod(); + const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo(); + size_t spill_count = POPCOUNT(frame_info.CoreSpillMask()); + size_t fp_spill_count = POPCOUNT(frame_info.FpSpillMask()); + if (spill_count > 0) { + // Lowest number spill is farthest away, walk registers and fill into context. + int j = 1; + for (size_t i = 0; i < kNumberOfGpuRegisters; i++) { + if (((frame_info.CoreSpillMask() >> i) & 1) != 0) { + gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_info.FrameSizeInBytes()); + j++; + } + } + } + if (fp_spill_count > 0) { + // Lowest number spill is farthest away, walk registers and fill into context. + int j = 1; + for (size_t i = 0; i < kNumberOfFpuRegisters; i++) { + if (((frame_info.FpSpillMask() >> i) & 1) != 0) { + fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j, + frame_info.FrameSizeInBytes()); + j++; + } + } + } +} + +bool Mips64Context::SetGPR(uint32_t reg, uintptr_t value) { + CHECK_LT(reg, static_cast(kNumberOfGpuRegisters)); + CHECK_NE(gprs_[reg], &gZero); // Can't overwrite this static value since they are never reset. + if (gprs_[reg] != nullptr) { + *gprs_[reg] = value; + return true; + } else { + return false; + } +} + +bool Mips64Context::SetFPR(uint32_t reg, uintptr_t value) { + CHECK_LT(reg, static_cast(kNumberOfFpuRegisters)); + CHECK_NE(fprs_[reg], &gZero); // Can't overwrite this static value since they are never reset. + if (fprs_[reg] != nullptr) { + *fprs_[reg] = value; + return true; + } else { + return false; + } +} + +void Mips64Context::SmashCallerSaves() { + // This needs to be 0 because we want a null/zero return value. + gprs_[V0] = const_cast(&gZero); + gprs_[V1] = const_cast(&gZero); + gprs_[A1] = nullptr; + gprs_[A0] = nullptr; + gprs_[A2] = nullptr; + gprs_[A3] = nullptr; + gprs_[A4] = nullptr; + gprs_[A5] = nullptr; + gprs_[A6] = nullptr; + gprs_[A7] = nullptr; + + // f0-f23 are caller-saved; f24-f31 are callee-saved. + fprs_[F0] = nullptr; + fprs_[F1] = nullptr; + fprs_[F2] = nullptr; + fprs_[F3] = nullptr; + fprs_[F4] = nullptr; + fprs_[F5] = nullptr; + fprs_[F6] = nullptr; + fprs_[F7] = nullptr; + fprs_[F8] = nullptr; + fprs_[F9] = nullptr; + fprs_[F10] = nullptr; + fprs_[F11] = nullptr; + fprs_[F12] = nullptr; + fprs_[F13] = nullptr; + fprs_[F14] = nullptr; + fprs_[F15] = nullptr; + fprs_[F16] = nullptr; + fprs_[F17] = nullptr; + fprs_[F18] = nullptr; + fprs_[F19] = nullptr; + fprs_[F20] = nullptr; + fprs_[F21] = nullptr; + fprs_[F22] = nullptr; + fprs_[F23] = nullptr; +} + +extern "C" void art_quick_do_long_jump(uintptr_t*, uintptr_t*); + +void Mips64Context::DoLongJump() { + uintptr_t gprs[kNumberOfGpuRegisters]; + uintptr_t fprs[kNumberOfFpuRegisters]; + for (size_t i = 0; i < kNumberOfGpuRegisters; ++i) { + gprs[i] = gprs_[i] != nullptr ? *gprs_[i] : Mips64Context::kBadGprBase + i; + } + for (size_t i = 0; i < kNumberOfFpuRegisters; ++i) { + fprs[i] = fprs_[i] != nullptr ? *fprs_[i] : Mips64Context::kBadFprBase + i; + } + art_quick_do_long_jump(gprs, fprs); +} + +} // namespace mips64 +} // namespace art diff --git a/runtime/arch/mips64/context_mips64.h b/runtime/arch/mips64/context_mips64.h new file mode 100644 index 0000000000..4ba5f13b14 --- /dev/null +++ b/runtime/arch/mips64/context_mips64.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2014 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_MIPS64_CONTEXT_MIPS64_H_ +#define ART_RUNTIME_ARCH_MIPS64_CONTEXT_MIPS64_H_ + +#include "arch/context.h" +#include "base/logging.h" +#include "registers_mips64.h" + +namespace art { +namespace mips64 { + +class Mips64Context : public Context { + public: + Mips64Context() { + Reset(); + } + virtual ~Mips64Context() {} + + void Reset() OVERRIDE; + + void FillCalleeSaves(const StackVisitor& fr) OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + void SetSP(uintptr_t new_sp) OVERRIDE { + bool success = SetGPR(SP, new_sp); + CHECK(success) << "Failed to set SP register"; + } + + void SetPC(uintptr_t new_pc) OVERRIDE { + bool success = SetGPR(RA, new_pc); + CHECK(success) << "Failed to set RA register"; + } + + uintptr_t* GetGPRAddress(uint32_t reg) OVERRIDE { + DCHECK_LT(reg, static_cast(kNumberOfGpuRegisters)); + return gprs_[reg]; + } + + bool GetGPR(uint32_t reg, uintptr_t* val) OVERRIDE { + CHECK_LT(reg, static_cast(kNumberOfGpuRegisters)); + if (gprs_[reg] == nullptr) { + return false; + } else { + DCHECK(val != nullptr); + *val = *gprs_[reg]; + return true; + } + } + + bool SetGPR(uint32_t reg, uintptr_t value) OVERRIDE; + + bool GetFPR(uint32_t reg, uintptr_t* val) OVERRIDE { + CHECK_LT(reg, static_cast(kNumberOfFpuRegisters)); + if (fprs_[reg] == nullptr) { + return false; + } else { + DCHECK(val != nullptr); + *val = *fprs_[reg]; + return true; + } + } + + bool SetFPR(uint32_t reg, uintptr_t value) OVERRIDE; + + void SmashCallerSaves() OVERRIDE; + void DoLongJump() OVERRIDE; + + private: + // Pointers to registers in the stack, initialized to NULL except for the special cases below. + uintptr_t* gprs_[kNumberOfGpuRegisters]; + uint64_t* fprs_[kNumberOfFpuRegisters]; + // Hold values for sp and ra (return address) if they are not located within a stack frame. + uintptr_t sp_, ra_; +}; +} // namespace mips64 +} // namespace art + +#endif // ART_RUNTIME_ARCH_MIPS64_CONTEXT_MIPS64_H_ diff --git a/runtime/arch/mips64/entrypoints_init_mips64.cc b/runtime/arch/mips64/entrypoints_init_mips64.cc new file mode 100644 index 0000000000..4a3bf02f2f --- /dev/null +++ b/runtime/arch/mips64/entrypoints_init_mips64.cc @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2014 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 "atomic.h" +#include "entrypoints/interpreter/interpreter_entrypoints.h" +#include "entrypoints/jni/jni_entrypoints.h" +#include "entrypoints/quick/quick_alloc_entrypoints.h" +#include "entrypoints/quick/quick_default_externs.h" +#include "entrypoints/quick/quick_entrypoints.h" +#include "entrypoints/entrypoint_utils.h" +#include "entrypoints/math_entrypoints.h" +#include "entrypoints/runtime_asm_entrypoints.h" +#include "interpreter/interpreter.h" + +namespace art { + +// Cast entrypoints. +extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass, + const mirror::Class* ref_class); +// Math entrypoints. +extern int32_t CmpgDouble(double a, double b); +extern int32_t CmplDouble(double a, double b); +extern int32_t CmpgFloat(float a, float b); +extern int32_t CmplFloat(float a, float b); +extern "C" int64_t artLmul(int64_t a, int64_t b); +extern "C" int64_t artLdiv(int64_t a, int64_t b); +extern "C" int64_t artLmod(int64_t a, int64_t b); + +// Math conversions. +extern "C" int32_t __fixsfsi(float op1); // FLOAT_TO_INT +extern "C" int32_t __fixdfsi(double op1); // DOUBLE_TO_INT +extern "C" float __floatdisf(int64_t op1); // LONG_TO_FLOAT +extern "C" double __floatdidf(int64_t op1); // LONG_TO_DOUBLE +extern "C" int64_t __fixsfdi(float op1); // FLOAT_TO_LONG +extern "C" int64_t __fixdfdi(double op1); // DOUBLE_TO_LONG + +// Single-precision FP arithmetics. +extern "C" float fmodf(float a, float b); // REM_FLOAT[_2ADDR] + +// Double-precision FP arithmetics. +extern "C" double fmod(double a, double b); // REM_DOUBLE[_2ADDR] + +// Long long arithmetics - REM_LONG[_2ADDR] and DIV_LONG[_2ADDR] +extern "C" int64_t __divdi3(int64_t, int64_t); +extern "C" int64_t __moddi3(int64_t, int64_t); + +void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, + QuickEntryPoints* qpoints) { + // Interpreter + ipoints->pInterpreterToInterpreterBridge = artInterpreterToInterpreterBridge; + ipoints->pInterpreterToCompiledCodeBridge = artInterpreterToCompiledCodeBridge; + + // JNI + jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub; + + // Alloc + ResetQuickAllocEntryPoints(qpoints); + + // Cast + qpoints->pInstanceofNonTrivial = artIsAssignableFromCode; + qpoints->pCheckCast = art_quick_check_cast; + + // DexCache + qpoints->pInitializeStaticStorage = art_quick_initialize_static_storage; + qpoints->pInitializeTypeAndVerifyAccess = art_quick_initialize_type_and_verify_access; + qpoints->pInitializeType = art_quick_initialize_type; + qpoints->pResolveString = art_quick_resolve_string; + + // Field + qpoints->pSet8Instance = art_quick_set8_instance; + qpoints->pSet8Static = art_quick_set8_static; + qpoints->pSet16Instance = art_quick_set16_instance; + qpoints->pSet16Static = art_quick_set16_static; + qpoints->pSet32Instance = art_quick_set32_instance; + qpoints->pSet32Static = art_quick_set32_static; + qpoints->pSet64Instance = art_quick_set64_instance; + qpoints->pSet64Static = art_quick_set64_static; + qpoints->pSetObjInstance = art_quick_set_obj_instance; + qpoints->pSetObjStatic = art_quick_set_obj_static; + qpoints->pGetBooleanInstance = art_quick_get_boolean_instance; + qpoints->pGetByteInstance = art_quick_get_byte_instance; + qpoints->pGetCharInstance = art_quick_get_char_instance; + qpoints->pGetShortInstance = art_quick_get_short_instance; + qpoints->pGet32Instance = art_quick_get32_instance; + qpoints->pGet64Instance = art_quick_get64_instance; + qpoints->pGetObjInstance = art_quick_get_obj_instance; + qpoints->pGetBooleanStatic = art_quick_get_boolean_static; + qpoints->pGetByteStatic = art_quick_get_byte_static; + qpoints->pGetCharStatic = art_quick_get_char_static; + qpoints->pGetShortStatic = art_quick_get_short_static; + qpoints->pGet32Static = art_quick_get32_static; + qpoints->pGet64Static = art_quick_get64_static; + qpoints->pGetObjStatic = art_quick_get_obj_static; + + // Array + qpoints->pAputObjectWithNullAndBoundCheck = art_quick_aput_obj_with_null_and_bound_check; + qpoints->pAputObjectWithBoundCheck = art_quick_aput_obj_with_bound_check; + qpoints->pAputObject = art_quick_aput_obj; + qpoints->pHandleFillArrayData = art_quick_handle_fill_data; + + // JNI + qpoints->pJniMethodStart = JniMethodStart; + qpoints->pJniMethodStartSynchronized = JniMethodStartSynchronized; + qpoints->pJniMethodEnd = JniMethodEnd; + qpoints->pJniMethodEndSynchronized = JniMethodEndSynchronized; + qpoints->pJniMethodEndWithReference = JniMethodEndWithReference; + qpoints->pJniMethodEndWithReferenceSynchronized = JniMethodEndWithReferenceSynchronized; + qpoints->pQuickGenericJniTrampoline = art_quick_generic_jni_trampoline; + + // Locks + qpoints->pLockObject = art_quick_lock_object; + qpoints->pUnlockObject = art_quick_unlock_object; + + // Math + qpoints->pCmpgDouble = CmpgDouble; + qpoints->pCmpgFloat = CmpgFloat; + qpoints->pCmplDouble = CmplDouble; + qpoints->pCmplFloat = CmplFloat; + qpoints->pFmod = fmod; + qpoints->pL2d = art_l2d; + qpoints->pFmodf = fmodf; + qpoints->pL2f = art_l2f; + qpoints->pD2iz = art_d2i; + qpoints->pF2iz = art_f2i; + qpoints->pIdivmod = NULL; + qpoints->pD2l = art_d2l; + qpoints->pF2l = art_f2l; + qpoints->pLdiv = artLdiv; + qpoints->pLmod = artLmod; + qpoints->pLmul = artLmul; + qpoints->pShlLong = NULL; + qpoints->pShrLong = NULL; + qpoints->pUshrLong = NULL; + + // Intrinsics + qpoints->pIndexOf = art_quick_indexof; + qpoints->pStringCompareTo = art_quick_string_compareto; + qpoints->pMemcpy = memcpy; + + // Invocation + qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; + qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; + qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; + qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; + 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->pTestSuspend = art_quick_test_suspend; + + // Throws + qpoints->pDeliverException = art_quick_deliver_exception; + qpoints->pThrowArrayBounds = art_quick_throw_array_bounds; + qpoints->pThrowDivZero = art_quick_throw_div_zero; + qpoints->pThrowNoSuchMethod = art_quick_throw_no_such_method; + qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception; + qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow; + + // TODO - use lld/scd instructions for Mips64 + // Atomic 64-bit load/store + qpoints->pA64Load = QuasiAtomic::Read64; + qpoints->pA64Store = QuasiAtomic::Write64; +}; + +} // namespace art diff --git a/runtime/arch/mips64/fault_handler_mips64.cc b/runtime/arch/mips64/fault_handler_mips64.cc new file mode 100644 index 0000000000..7b5cd4913c --- /dev/null +++ b/runtime/arch/mips64/fault_handler_mips64.cc @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 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 "fault_handler.h" +#include +#include "base/macros.h" +#include "globals.h" +#include "base/logging.h" +#include "base/hex_dump.h" + + +// +// Mips64 specific fault handler functions. +// + +namespace art { + +void FaultManager::HandleNestedSignal(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED, + void* context ATTRIBUTE_UNUSED) { +} + +void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED, + void* context ATTRIBUTE_UNUSED, + mirror::ArtMethod** out_method ATTRIBUTE_UNUSED, + uintptr_t* out_return_pc ATTRIBUTE_UNUSED, + uintptr_t* out_sp ATTRIBUTE_UNUSED) { +} + +bool NullPointerHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED, + void* context ATTRIBUTE_UNUSED) { + return false; +} + +bool SuspensionHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED, + void* context ATTRIBUTE_UNUSED) { + return false; +} + +bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED, + void* context ATTRIBUTE_UNUSED) { + return false; +} +} // namespace art diff --git a/runtime/arch/mips64/jni_entrypoints_mips64.S b/runtime/arch/mips64/jni_entrypoints_mips64.S new file mode 100644 index 0000000000..90fd3ee63e --- /dev/null +++ b/runtime/arch/mips64/jni_entrypoints_mips64.S @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2014 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_mips64.S" + + .set noreorder + .balign 16 + + /* + * Jni dlsym lookup stub. + */ + .extern artFindNativeMethod +ENTRY art_jni_dlsym_lookup_stub + daddiu $sp, $sp, -80 # save a0-a7 and $ra + .cfi_adjust_cfa_offset 80 + sd $ra, 64($sp) + .cfi_rel_offset 31, 64 + sw $a7, 56($sp) + .cfi_rel_offset 11, 56 + sw $a6, 48($sp) + .cfi_rel_offset 10, 48 + sw $a5, 40($sp) + .cfi_rel_offset 9, 40 + sw $a4, 32($sp) + .cfi_rel_offset 8, 32 + sw $a3, 24($sp) + .cfi_rel_offset 7, 24 + sw $a2, 16($sp) + .cfi_rel_offset 6, 16 + sw $a1, 8($sp) + .cfi_rel_offset 5, 8 + sw $a0, 0($sp) + .cfi_rel_offset 4, 0 + jal artFindNativeMethod # (Thread*) + move $a0, $s1 # pass Thread::Current() + ld $a0, 0($sp) # restore registers from stack + .cfi_restore 4 + ld $a1, 8($sp) + .cfi_restore 5 + ld $a2, 16($sp) + .cfi_restore 6 + ld $a3, 24($sp) + .cfi_restore 7 + ld $a4, 32($sp) + .cfi_restore 8 + ld $a5, 40($sp) + .cfi_restore 9 + ld $a6, 48($sp) + .cfi_restore 10 + ld $a7, 56($sp) + .cfi_restore 11 + ld $ra, 64($sp) + .cfi_restore 31 + beq $v0, $zero, .Lno_native_code_found + daddiu $sp, $sp, 80 # restore the stack + .cfi_adjust_cfa_offset -80 + move $t9, $v0 # put method code result in $t9 + jalr $zero, $t9 # leaf call to method's code + nop +.Lno_native_code_found: + jalr $zero, $ra + nop +END art_jni_dlsym_lookup_stub diff --git a/runtime/arch/mips64/memcmp16_mips64.S b/runtime/arch/mips64/memcmp16_mips64.S new file mode 100644 index 0000000000..962977ee13 --- /dev/null +++ b/runtime/arch/mips64/memcmp16_mips64.S @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2014 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_MIPS64_MEMCMP16_MIPS64_S_ +#define ART_RUNTIME_ARCH_MIPS64_MEMCMP16_MIPS64_S_ + +#include "asm_support_mips64.S" + +.set noreorder + +// u4 __memcmp16(const u2*, const u2*, size_t); +ENTRY_NO_GP __memcmp16 + move $t0, $zero + move $t1, $zero + beqz $a2, done /* 0 length string */ + nop + beq $a0, $a1, done /* addresses are identical */ + nop + +1: + lhu $t0, 0($a0) + lhu $t1, 0($a1) + bne $t0, $t1, done + nop + daddu $a0, 2 + daddu $a1, 2 + dsubu $a2, 1 + bnez $a2, 1b + nop + +done: + dsubu $v0, $t0, $t1 + j $ra + nop +END __memcmp16 + +#endif // ART_RUNTIME_ARCH_MIPS64_MEMCMP16_MIPS64_S_ diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S new file mode 100644 index 0000000000..3430eb5e3b --- /dev/null +++ b/runtime/arch/mips64/quick_entrypoints_mips64.S @@ -0,0 +1,897 @@ +/* + * Copyright (C) 2014 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_mips64.S" + +#include "arch/quick_alloc_entrypoints.S" + + .set noreorder + .balign 16 + + /* Deliver the given exception */ + .extern artDeliverExceptionFromCode + /* Deliver an exception pending on a thread */ + .extern artDeliverPendingExceptionFromCode + + /* + * Macro that sets up the callee save frame to conform with + * Runtime::CreateCalleeSaveMethod(kSaveAll) + * callee-save: padding + $f24-$f31 + $s0-$s7 + $gp + $ra + $s8 = 19 total + 1x8 bytes padding + */ +.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME + daddiu $sp, $sp, -160 + .cfi_adjust_cfa_offset 160 + + // Ugly compile-time check, but we only have the preprocessor. +#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 160) +#error "SAVE_ALL_CALLEE_SAVE_FRAME(MIPS64) size not as expected." +#endif + + sd $ra, 152($sp) + .cfi_rel_offset 31, 152 + sd $s8, 144($sp) + .cfi_rel_offset 30, 144 + sd $gp, 136($sp) + .cfi_rel_offset 28, 136 + sd $s7, 128($sp) + .cfi_rel_offset 23, 128 + sd $s6, 120($sp) + .cfi_rel_offset 22, 120 + sd $s5, 112($sp) + .cfi_rel_offset 21, 112 + sd $s4, 104($sp) + .cfi_rel_offset 20, 104 + sd $s3, 96($sp) + .cfi_rel_offset 19, 96 + sd $s2, 88($sp) + .cfi_rel_offset 18, 88 + sd $s1, 80($sp) + .cfi_rel_offset 17, 80 + sd $s0, 72($sp) + .cfi_rel_offset 16, 72 + + // FP callee-saves + s.d $f31, 64($sp) + s.d $f30, 56($sp) + s.d $f29, 48($sp) + s.d $f28, 40($sp) + s.d $f27, 32($sp) + s.d $f26, 24($sp) + s.d $f25, 16($sp) + s.d $f24, 8($sp) + + # load appropriate callee-save-method + ld $v0, %got(_ZN3art7Runtime9instance_E)($gp) + ld $v0, 0($v0) + THIS_LOAD_REQUIRES_READ_BARRIER + ld $v0, RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET($v0) + sw $v0, 0($sp) # Place Method* at bottom of stack. + sd $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF) # Place sp in Thread::Current()->top_quick_frame. +.endm + + /* + * Macro that sets up the callee save frame to conform with + * Runtime::CreateCalleeSaveMethod(kRefsOnly). Restoration assumes + * non-moving GC. + * Does not include rSUSPEND or rSELF + * callee-save: padding + $s2-$s7 + $gp + $ra + $s8 = 9 total + 1x8 bytes padding + */ +.macro SETUP_REFS_ONLY_CALLEE_SAVE_FRAME + daddiu $sp, $sp, -80 + .cfi_adjust_cfa_offset 80 + + // Ugly compile-time check, but we only have the preprocessor. +#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 80) +#error "REFS_ONLY_CALLEE_SAVE_FRAME(MIPS64) size not as expected." +#endif + + sd $ra, 72($sp) + .cfi_rel_offset 31, 72 + sd $s8, 64($sp) + .cfi_rel_offset 30, 64 + sd $gp, 56($sp) + .cfi_rel_offset 28, 56 + sd $s7, 48($sp) + .cfi_rel_offset 23, 48 + sd $s6, 40($sp) + .cfi_rel_offset 22, 40 + sd $s5, 32($sp) + .cfi_rel_offset 21, 32 + sd $s4, 24($sp) + .cfi_rel_offset 20, 24 + sd $s3, 16($sp) + .cfi_rel_offset 19, 16 + sd $s2, 8($sp) + .cfi_rel_offset 18, 8 + # load appropriate callee-save-method + ld $v0, %got(_ZN3art7Runtime9instance_E)($gp) + ld $v0, 0($v0) + THIS_LOAD_REQUIRES_READ_BARRIER + ld $v0, RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET($v0) + sw $v0, 0($sp) # Place Method* at bottom of stack. + sd $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF) # Place sp in Thread::Current()->top_quick_frame. +.endm + +.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME + ld $ra, 72($sp) + .cfi_restore 31 + ld $s8, 64($sp) + .cfi_restore 30 + ld $gp, 56($sp) + .cfi_restore 28 + ld $s7, 48($sp) + .cfi_restore 23 + ld $s6, 40($sp) + .cfi_restore 22 + ld $s5, 32($sp) + .cfi_restore 21 + ld $s4, 24($sp) + .cfi_restore 20 + ld $s3, 16($sp) + .cfi_restore 19 + ld $s2, 8($sp) + .cfi_restore 18 + daddiu $sp, $sp, 80 + .cfi_adjust_cfa_offset -80 +.endm + +.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN + ld $ra, 72($sp) + .cfi_restore 31 + ld $s8, 64($sp) + .cfi_restore 30 + ld $gp, 56($sp) + .cfi_restore 28 + ld $s7, 48($sp) + .cfi_restore 23 + ld $s6, 40($sp) + .cfi_restore 22 + ld $s5, 32($sp) + .cfi_restore 21 + ld $s4, 24($sp) + .cfi_restore 20 + ld $s3, 16($sp) + .cfi_restore 19 + ld $s2, 8($sp) + .cfi_restore 18 + jalr $zero, $ra + daddiu $sp, $sp, 80 + .cfi_adjust_cfa_offset -80 +.endm + +// This assumes the top part of these stack frame types are identical. +#define REFS_AND_ARGS_MINUS_REFS_SIZE (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE) + + /* + * Macro that sets up the callee save frame to conform with + * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). Restoration assumes + * non-moving GC. + * callee-save: padding + $f12-$f19 + $a1-$a7 + $s2-$s7 + $gp + $ra + $s8 = 24 total + 1 words padding + Method* + */ +.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL + daddiu $sp, $sp, -208 + .cfi_adjust_cfa_offset 208 + + // Ugly compile-time check, but we only have the preprocessor. +#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 208) +#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(MIPS64) size not as expected." +#endif + + sd $ra, 200($sp) # = kQuickCalleeSaveFrame_RefAndArgs_LrOffset + .cfi_rel_offset 31, 200 + sd $s8, 192($sp) + .cfi_rel_offset 30, 192 + sd $gp, 184($sp) + .cfi_rel_offset 28, 184 + sd $s7, 176($sp) + .cfi_rel_offset 23, 176 + sd $s6, 168($sp) + .cfi_rel_offset 22, 168 + sd $s5, 160($sp) + .cfi_rel_offset 21, 160 + sd $s4, 152($sp) + .cfi_rel_offset 20, 152 + sd $s3, 144($sp) + .cfi_rel_offset 19, 144 + sd $s2, 136($sp) + .cfi_rel_offset 18, 136 + + sd $a7, 128($sp) + .cfi_rel_offset 11, 128 + sd $a6, 120($sp) + .cfi_rel_offset 10, 120 + sd $a5, 112($sp) + .cfi_rel_offset 9, 112 + sd $a4, 104($sp) + .cfi_rel_offset 8, 104 + sd $a3, 96($sp) + .cfi_rel_offset 7, 96 + sd $a2, 88($sp) + .cfi_rel_offset 6, 88 + sd $a1, 80($sp) # = kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset + .cfi_rel_offset 5, 80 + + s.d $f19, 72($sp) + s.d $f18, 64($sp) + s.d $f17, 56($sp) + s.d $f16, 48($sp) + s.d $f15, 40($sp) + s.d $f14, 32($sp) + s.d $f13, 24($sp) # = kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset + s.d $f12, 16($sp) # This isn't necessary to store. + + # 1x8 bytes paddig + Method* + ld $v0, %got(_ZN3art7Runtime9instance_E)($gp) + ld $v0, 0($v0) + THIS_LOAD_REQUIRES_READ_BARRIER + ld $v0, RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET($v0) + sw $v0, 0($sp) # Place Method* at bottom of stack. + sd $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF) # Place sp in Thread::Current()->top_quick_frame. +.endm + +.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME + SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL + # load appropriate callee-save-method + ld $v0, %got(_ZN3art7Runtime9instance_E)($gp) + ld $v0, 0($v0) + THIS_LOAD_REQUIRES_READ_BARRIER + ld $v0, RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET($v0) + sw $v0, 0($sp) # Place Method* at bottom of stack. + sd $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF) # Place sp in Thread::Current()->top_quick_frame. +.endm + +.macro RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME + ld $ra, 200($sp) + .cfi_restore 31 + ld $s8, 192($sp) + .cfi_restore 30 + ld $gp, 184($sp) + .cfi_restore 28 + ld $s7, 176($sp) + .cfi_restore 23 + ld $s6, 168($sp) + .cfi_restore 22 + ld $s5, 160($sp) + .cfi_restore 21 + ld $s4, 152($sp) + .cfi_restore 20 + ld $s3, 144($sp) + .cfi_restore 19 + ld $s2, 136($sp) + .cfi_restore 18 + + ld $a7, 128($sp) + .cfi_restore 11 + ld $a6, 120($sp) + .cfi_restore 10 + ld $a5, 112($sp) + .cfi_restore 9 + ld $a4, 104($sp) + .cfi_restore 8 + ld $a3, 96($sp) + .cfi_restore 7 + ld $a2, 88($sp) + .cfi_restore 6 + ld $a1, 80($sp) + .cfi_restore 5 + + l.d $f19, 72($sp) + l.d $f18, 64($sp) + l.d $f17, 56($sp) + l.d $f16, 48($sp) + l.d $f15, 40($sp) + l.d $f14, 32($sp) + l.d $f13, 24($sp) + l.d $f12, 16($sp) + + daddiu $sp, $sp, 208 + .cfi_adjust_cfa_offset -208 +.endm + + /* + * Macro that set calls through to artDeliverPendingExceptionFromCode, + * where the pending + * exception is Thread::Current()->exception_ + */ +.macro DELIVER_PENDING_EXCEPTION + SETUP_SAVE_ALL_CALLEE_SAVE_FRAME # save callee saves for throw + dla $t9, artDeliverPendingExceptionFromCode + jalr $zero, $t9 # artDeliverPendingExceptionFromCode(Thread*) + move $a0, rSELF # pass Thread::Current +.endm + +.macro RETURN_IF_NO_EXCEPTION + ld $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_ + RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME + bne $t0, $zero, 1f # success if no exception is pending + nop + jalr $zero, $ra + nop +1: + DELIVER_PENDING_EXCEPTION +.endm + +.macro RETURN_IF_ZERO + RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME + bne $v0, $zero, 1f # success? + nop + jalr $zero, $ra # return on success + nop +1: + DELIVER_PENDING_EXCEPTION +.endm + +.macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER + RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME + beq $v0, $zero, 1f # success? + nop + jalr $zero, $ra # return on success + nop +1: + DELIVER_PENDING_EXCEPTION +.endm + + /* + * On entry $a0 is uint32_t* gprs_ and $a1 is uint32_t* fprs_ + * FIXME: just guessing about the shape of the jmpbuf. Where will pc be? + */ +ENTRY art_quick_do_long_jump + l.d $f0, 0($a1) + l.d $f1, 8($a1) + l.d $f2, 16($a1) + l.d $f3, 24($a1) + l.d $f4, 32($a1) + l.d $f5, 40($a1) + l.d $f6, 48($a1) + l.d $f7, 56($a1) + l.d $f8, 64($a1) + l.d $f9, 72($a1) + l.d $f10, 80($a1) + l.d $f11, 88($a1) + l.d $f12, 96($a1) + l.d $f13, 104($a1) + l.d $f14, 112($a1) + l.d $f15, 120($a1) + l.d $f16, 128($a1) + l.d $f17, 136($a1) + l.d $f18, 144($a1) + l.d $f19, 152($a1) + l.d $f20, 160($a1) + l.d $f21, 168($a1) + l.d $f22, 176($a1) + l.d $f23, 184($a1) + l.d $f24, 192($a1) + l.d $f25, 200($a1) + l.d $f26, 208($a1) + l.d $f27, 216($a1) + l.d $f28, 224($a1) + l.d $f29, 232($a1) + l.d $f30, 240($a1) + l.d $f31, 248($a1) + .set push + .set nomacro + .set noat +# no need to load zero + ld $at, 8($a0) + .set pop + ld $v0, 16($a0) + ld $v1, 24($a0) +# a0 has to be loaded last + ld $a1, 40($a0) + ld $a2, 48($a0) + ld $a3, 56($a0) + ld $a4, 64($a0) + ld $a5, 72($a0) + ld $a6, 80($a0) + ld $a7, 88($a0) + ld $t0, 96($a0) + ld $t1, 104($a0) + ld $t2, 112($a0) + ld $t3, 120($a0) + ld $s0, 128($a0) + ld $s1, 136($a0) + ld $s2, 144($a0) + ld $s3, 152($a0) + ld $s4, 160($a0) + ld $s5, 168($a0) + ld $s6, 176($a0) + ld $s7, 184($a0) + ld $t8, 192($a0) + ld $t9, 200($a0) +# no need to load k0, k1 + ld $gp, 224($a0) + ld $sp, 232($a0) + ld $s8, 240($a0) + ld $ra, 248($a0) + ld $a0, 32($a0) + move $v0, $zero # clear result registers v0 and v1 + jalr $zero, $ra # do long jump + move $v1, $zero +END art_quick_do_long_jump + +UNIMPLEMENTED art_quick_deliver_exception +UNIMPLEMENTED art_quick_throw_null_pointer_exception +UNIMPLEMENTED art_quick_throw_div_zero +UNIMPLEMENTED art_quick_throw_array_bounds +UNIMPLEMENTED art_quick_throw_stack_overflow +UNIMPLEMENTED art_quick_throw_no_such_method + +UNIMPLEMENTED art_quick_invoke_interface_trampoline +UNIMPLEMENTED art_quick_invoke_interface_trampoline_with_access_check + +UNIMPLEMENTED art_quick_invoke_static_trampoline_with_access_check +UNIMPLEMENTED art_quick_invoke_direct_trampoline_with_access_check +UNIMPLEMENTED art_quick_invoke_super_trampoline_with_access_check +UNIMPLEMENTED art_quick_invoke_virtual_trampoline_with_access_check + + # On entry: + # t0 = shorty + # t1 = ptr to arg_array + # t2 = number of argument bytes remain + # v0 = ptr to stack frame where to copy arg_array + # This macro modifies t3, t9 and v0 +.macro LOOP_OVER_SHORTY_LOADING_REG gpu, fpu, label + lbu $t3, 0($t0) # get argument type from shorty + beqz $t3, \label + daddiu $t0, 1 + li $t9, 68 # put char 'D' into t9 + beq $t9, $t3, 1f # branch if result type char == 'D' + li $t9, 70 # put char 'F' into t9 + beq $t9, $t3, 2f # branch if result type char == 'F' + li $t9, 74 # put char 'J' into t9 + beq $t9, $t3, 3f # branch if result type char == 'J' + nop + lwu $\gpu, 0($t1) + sw $\gpu, 0($v0) + daddiu $v0, 4 + daddiu $t1, 4 + b 4f + daddiu $t2, -4 # delay slot + +1: # found double + lwu $t3, 0($t1) + mtc1 $t3, $\fpu + sw $t3, 0($v0) + lwu $t3, 4($t1) + mthc1 $t3, $\fpu + sw $t3, 4($v0) + daddiu $v0, 8 + daddiu $t1, 8 + b 4f + daddiu $t2, -8 # delay slot + +2: # found float + lwu $t3, 0($t1) + mtc1 $t3, $\fpu + sw $t3, 0($v0) + daddiu $v0, 4 + daddiu $t1, 4 + b 4f + daddiu $t2, -4 # delay slot + +3: # found long (8 bytes) + lwu $t3, 0($t1) + sw $t3, 0($v0) + lwu $t9, 4($t1) + sw $t9, 4($v0) + dsll $t9, $t9, 32 + or $\gpu, $t9, $t3 + daddiu $v0, 8 + daddiu $t1, 8 + daddiu $t2, -8 +4: +.endm + + /* + * Invocation stub for quick code. + * On entry: + * a0 = method pointer + * a1 = argument array that must at least contain the this ptr. + * a2 = size of argument array in bytes + * a3 = (managed) thread pointer + * a4 = JValue* result + * a5 = shorty + */ +ENTRY art_quick_invoke_stub + # push a4, a5, s0(rSUSPEND), s1(rSELF), s8, ra onto the stack + daddiu $sp, $sp, -48 + .cfi_adjust_cfa_offset 48 + sd $ra, 40($sp) + .cfi_rel_offset 31, 40 + sd $s8, 32($sp) + .cfi_rel_offset 30, 32 + sd $s1, 24($sp) + .cfi_rel_offset 17, 24 + sd $s0, 16($sp) + .cfi_rel_offset 16, 16 + sd $a5, 8($sp) + .cfi_rel_offset 9, 8 + sd $a4, 0($sp) + .cfi_rel_offset 8, 0 + + daddiu $s0, $zero, SUSPEND_CHECK_INTERVAL # reset rSUSPEND to SUSPEND_CHECK_INTERVAL + move $s1, $a3 # move managed thread pointer into s1 (rSELF) + move $s8, $sp # save sp in s8 (fp) + + daddiu $t3, $a2, 20 # add 4 for method* and 16 for stack alignment + dsrl $t3, $t3, 4 # shift the frame size right 4 + dsll $t3, $t3, 4 # shift the frame size left 4 to align to 16 bytes + dsubu $sp, $sp, $t3 # reserve stack space for argument array + + daddiu $t0, $a5, 1 # t0 = shorty[1] (skip 1 for return type) + daddiu $t1, $a1, 4 # t1 = ptr to arg_array[4] (skip this ptr) + daddiu $t2, $a2, -4 # t2 = number of argument bytes remain (skip this ptr) + daddiu $v0, $sp, 8 # v0 points to where to copy arg_array + LOOP_OVER_SHORTY_LOADING_REG a2, f14, call_fn + LOOP_OVER_SHORTY_LOADING_REG a3, f15, call_fn + LOOP_OVER_SHORTY_LOADING_REG a4, f16, call_fn + LOOP_OVER_SHORTY_LOADING_REG a5, f17, call_fn + LOOP_OVER_SHORTY_LOADING_REG a6, f18, call_fn + LOOP_OVER_SHORTY_LOADING_REG a7, f19, call_fn + + # copy arguments onto stack (t2 should be multiples of 4) + ble $t2, $zero, call_fn # t2 = number of argument bytes remain +1: + lw $t3, 0($t1) # load from argument array + daddiu $t1, $t1, 4 + sw $t3, 0($v0) # save to stack + daddiu $t2, -4 + bgt $t2, $zero, 1b # t2 = number of argument bytes remain + daddiu $v0, $v0, 4 + +call_fn: + # call method (a0 and a1 have been untouched) + lwu $a1, 0($a1) # make a1 = this ptr + sw $a1, 4($sp) # copy this ptr (skip 4 bytes for method*) + sw $zero, 0($sp) # store NULL for method* at bottom of frame + ld $t9, MIRROR_ART_METHOD_QUICK_CODE_OFFSET_64($a0) # get pointer to the code + jalr $t9 # call the method + nop + move $sp, $s8 # restore sp + + # pop a4, a5, s1(rSELF), s8, ra off of the stack + ld $a4, 0($sp) + .cfi_restore 8 + ld $a5, 8($sp) + .cfi_restore 9 + ld $s0, 16($sp) + .cfi_restore 16 + ld $s1, 24($sp) + .cfi_restore 17 + ld $s8, 32($sp) + .cfi_restore 30 + ld $ra, 40($sp) + .cfi_restore 31 + daddiu $sp, $sp, 48 + .cfi_adjust_cfa_offset -48 + + # a4 = JValue* result + # a5 = shorty string + lbu $t1, 0($a5) # get result type from shorty + li $t2, 68 # put char 'D' into t2 + beq $t1, $t2, 1f # branch if result type char == 'D' + li $t3, 70 # put char 'F' into t3 + beq $t1, $t3, 1f # branch if result type char == 'F' + sw $v0, 0($a4) # store the result + dsrl $v1, $v0, 32 + jalr $zero, $ra + sw $v1, 4($a4) # store the other half of the result +1: + mfc1 $v0, $f0 + mfhc1 $v1, $f0 + sw $v0, 0($a4) # store the result + jalr $zero, $ra + sw $v1, 4($a4) # store the other half of the result +END art_quick_invoke_stub + + /* + * Invocation static stub for quick code. + * On entry: + * a0 = method pointer + * a1 = argument array that must at least contain the this ptr. + * a2 = size of argument array in bytes + * a3 = (managed) thread pointer + * a4 = JValue* result + * a5 = shorty + */ +ENTRY art_quick_invoke_static_stub + + # push a4, a5, s0(rSUSPEND), s1(rSELF), s8, ra, onto the stack + daddiu $sp, $sp, -48 + .cfi_adjust_cfa_offset 48 + sd $ra, 40($sp) + .cfi_rel_offset 31, 40 + sd $s8, 32($sp) + .cfi_rel_offset 30, 32 + sd $s1, 24($sp) + .cfi_rel_offset 17, 24 + sd $s0, 16($sp) + .cfi_rel_offset 16, 16 + sd $a5, 8($sp) + .cfi_rel_offset 9, 8 + sd $a4, 0($sp) + .cfi_rel_offset 8, 0 + + daddiu $s0, $zero, SUSPEND_CHECK_INTERVAL # reset rSUSPEND to SUSPEND_CHECK_INTERVAL + move $s1, $a3 # move managed thread pointer into s1 (rSELF) + move $s8, $sp # save sp in s8 (fp) + + daddiu $t3, $a2, 20 # add 4 for method* and 16 for stack alignment + dsrl $t3, $t3, 4 # shift the frame size right 4 + dsll $t3, $t3, 4 # shift the frame size left 4 to align to 16 bytes + dsubu $sp, $sp, $t3 # reserve stack space for argument array + + daddiu $t0, $a5, 1 # t0 = shorty[1] (skip 1 for return type) + move $t1, $a1 # t1 = arg_array + move $t2, $a2 # t2 = number of argument bytes remain + daddiu $v0, $sp, 4 # v0 points to where to copy arg_array + LOOP_OVER_SHORTY_LOADING_REG a1, f13, call_sfn + LOOP_OVER_SHORTY_LOADING_REG a2, f14, call_sfn + LOOP_OVER_SHORTY_LOADING_REG a3, f15, call_sfn + LOOP_OVER_SHORTY_LOADING_REG a4, f16, call_sfn + LOOP_OVER_SHORTY_LOADING_REG a5, f17, call_sfn + LOOP_OVER_SHORTY_LOADING_REG a6, f18, call_sfn + LOOP_OVER_SHORTY_LOADING_REG a7, f19, call_sfn + + # copy arguments onto stack (t2 should be multiples of 4) + ble $t2, $zero, call_sfn # t2 = number of argument bytes remain +1: + lw $t3, 0($t1) # load from argument array + daddiu $t1, $t1, 4 + sw $t3, 0($v0) # save to stack + daddiu $t2, -4 + bgt $t2, $zero, 1b # t2 = number of argument bytes remain + daddiu $v0, $v0, 4 + +call_sfn: + # call method (a0 has been untouched) + sw $zero, 0($sp) # store NULL for method* at bottom of frame + ld $t9, MIRROR_ART_METHOD_QUICK_CODE_OFFSET_64($a0) # get pointer to the code + jalr $t9 # call the method + nop + move $sp, $s8 # restore sp + + # pop a4, a5, s0(rSUSPEND), s1(rSELF), s8, ra off of the stack + ld $a4, 0($sp) + .cfi_restore 8 + ld $a5, 8($sp) + .cfi_restore 9 + ld $s0, 16($sp) + .cfi_restore 16 + ld $s1, 24($sp) + .cfi_restore 17 + ld $s8, 32($sp) + .cfi_restore 30 + ld $ra, 40($sp) + .cfi_restore 31 + daddiu $sp, $sp, 48 + .cfi_adjust_cfa_offset -48 + + # a4 = JValue* result + # a5 = shorty string + lbu $t1, 0($a5) # get result type from shorty + li $t2, 68 # put char 'D' into t2 + beq $t1, $t2, 1f # branch if result type char == 'D' + li $t3, 70 # put char 'F' into t3 + beq $t1, $t3, 1f # branch if result type char == 'F' + sw $v0, 0($a4) # store the result + dsrl $v1, $v0, 32 + jalr $zero, $ra + sw $v1, 4($a4) # store the other half of the result +1: + mfc1 $v0, $f0 + mfhc1 $v1, $f0 + sw $v0, 0($a4) # store the result + jalr $zero, $ra + sw $v1, 4($a4) # store the other half of the result +END art_quick_invoke_static_stub + + + +UNIMPLEMENTED art_quick_handle_fill_data +UNIMPLEMENTED art_quick_lock_object +UNIMPLEMENTED art_quick_unlock_object +UNIMPLEMENTED art_quick_check_cast +UNIMPLEMENTED art_quick_aput_obj_with_null_and_bound_check +UNIMPLEMENTED art_quick_aput_obj_with_bound_check +UNIMPLEMENTED art_quick_aput_obj +UNIMPLEMENTED art_quick_initialize_static_storage +UNIMPLEMENTED art_quick_initialize_type +UNIMPLEMENTED art_quick_initialize_type_and_verify_access +UNIMPLEMENTED art_quick_get_boolean_static +UNIMPLEMENTED art_quick_get_byte_static +UNIMPLEMENTED art_quick_get_char_static +UNIMPLEMENTED art_quick_get_short_static +UNIMPLEMENTED art_quick_get32_static +UNIMPLEMENTED art_quick_get64_static +UNIMPLEMENTED art_quick_get_obj_static +UNIMPLEMENTED art_quick_get_boolean_instance +UNIMPLEMENTED art_quick_get_byte_instance +UNIMPLEMENTED art_quick_get_char_instance +UNIMPLEMENTED art_quick_get_short_instance +UNIMPLEMENTED art_quick_get32_instance +UNIMPLEMENTED art_quick_get64_instance +UNIMPLEMENTED art_quick_get_obj_instance +UNIMPLEMENTED art_quick_set8_static +UNIMPLEMENTED art_quick_set16_static +UNIMPLEMENTED art_quick_set32_static +UNIMPLEMENTED art_quick_set64_static +UNIMPLEMENTED art_quick_set_obj_static +UNIMPLEMENTED art_quick_set8_instance +UNIMPLEMENTED art_quick_set16_instance +UNIMPLEMENTED art_quick_set32_instance +UNIMPLEMENTED art_quick_set64_instance +UNIMPLEMENTED art_quick_set_obj_instance +UNIMPLEMENTED art_quick_resolve_string + +// Macro to facilitate adding new allocation entrypoints. +.macro TWO_ARG_DOWNCALL name, entrypoint, return +ENTRY \name + break + break +END \name +.endm + +.macro THREE_ARG_DOWNCALL name, entrypoint, return +ENTRY \name + break + break +END \name +.endm + +// Generate the allocation entrypoints for each allocator. +GENERATE_ALL_ALLOC_ENTRYPOINTS + +UNIMPLEMENTED art_quick_test_suspend +UNIMPLEMENTED art_quick_proxy_invoke_handler +UNIMPLEMENTED art_quick_imt_conflict_trampoline +UNIMPLEMENTED art_quick_resolution_trampoline + + .extern artQuickGenericJniTrampoline + .extern artQuickGenericJniEndTrampoline +ENTRY art_quick_generic_jni_trampoline + SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL + sd $a0, 0($sp) # store native ArtMethod* to bottom of stack + move $s8, $sp # save $sp + + # prepare for call to artQuickGenericJniTrampoline(Thread*, SP) + move $a0, rSELF # pass Thread::Current + move $a1, $sp # pass $sp + jal artQuickGenericJniTrampoline # (Thread*, SP) + daddiu $sp, $sp, -5120 # reserve space on the stack + + # The C call will have registered the complete save-frame on success. + # The result of the call is: + # v0: ptr to native code, 0 on error. + # v1: ptr to the bottom of the used area of the alloca, can restore stack till here. + beq $v0, $zero, 1f # check entry error + move $t9, $v0 # save the code ptr + move $sp, $v1 # release part of the alloca + + # Load parameters from stack into registers + ld $a0, 0($sp) + ld $a1, 8($sp) + ld $a2, 16($sp) + ld $a3, 24($sp) + ld $a4, 32($sp) + ld $a5, 40($sp) + ld $a6, 48($sp) + ld $a7, 56($sp) + # Load FPRs the same as GPRs. Look at BuildNativeCallFrameStateMachine. + l.d $f12, 0($sp) + l.d $f13, 8($sp) + l.d $f14, 16($sp) + l.d $f15, 24($sp) + l.d $f16, 32($sp) + l.d $f17, 40($sp) + l.d $f18, 48($sp) + l.d $f19, 56($sp) + jalr $t9 # native call + daddiu $sp, $sp, 64 + + # result sign extension is handled in C code + # prepare for call to artQuickGenericJniEndTrampoline(Thread*, result, result_f) + move $a0, rSELF # pass Thread::Current + move $a1, $v0 + jal artQuickGenericJniEndTrampoline + dmfc1 $a2, $f0 + + ld $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_ + bne $t0, $zero, 2f # check for pending exceptions + move $sp, $s8 # tear down the alloca + + # tear dpown the callee-save frame + RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME + + jalr $zero, $ra + dmtc1 $v0, $f0 # place return value to FP return value + +1: + move $sp, $s8 # tear down the alloca +2: + RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME + DELIVER_PENDING_EXCEPTION +END art_quick_generic_jni_trampoline + + .extern artQuickToInterpreterBridge +ENTRY art_quick_to_interpreter_bridge + SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME + move $a1, rSELF # pass Thread::Current + jal artQuickToInterpreterBridge # (Method* method, Thread*, SP) + move $a2, $sp # pass $sp + ld $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_ + daddiu $sp, $sp, REFS_AND_ARGS_MINUS_REFS_SIZE # skip a0-a7 and f12-f19 + RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME + bne $t0, $zero, 1f + dmtc1 $v0, $f0 # place return value to FP return value + jalr $zero, $ra + dmtc1 $v1, $f1 # place return value to FP return value +1: + DELIVER_PENDING_EXCEPTION +END art_quick_to_interpreter_bridge + + /* + * Routine that intercepts method calls and returns. + */ + .extern artInstrumentationMethodEntryFromCode + .extern artInstrumentationMethodExitFromCode +ENTRY art_quick_instrumentation_entry + SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME + daddiu $sp, $sp, -16 # space for saving arg0 + .cfi_adjust_cfa_offset 16 + sd $a0, 0($sp) # save arg0 + move $a3, $ra # pass $ra + jal artInstrumentationMethodEntryFromCode # (Method*, Object*, Thread*, RA) + move $a2, rSELF # pass Thread::Current + move $t9, $v0 # $t9 holds reference to code + ld $a0, 0($sp) # restore arg0 + daddiu $sp, $sp, 16 # remove args + .cfi_adjust_cfa_offset -16 + RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME + jalr $t9 # call method + nop +END art_quick_instrumentation_entry + /* intentional fallthrough */ + .global art_quick_instrumentation_exit +art_quick_instrumentation_exit: + .cfi_startproc + daddiu $t9, $ra, 4 # put current address into $t9 to rebuild $gp + .cpload $t9 + move $ra, $zero # link register is to here, so clobber with 0 for later checks + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME + move $t0, $sp # remember bottom of caller's frame + daddiu $sp, $sp, -16 # save return values and set up args + .cfi_adjust_cfa_offset 16 + sd $v0, 0($sp) + .cfi_rel_offset 2, 0 + s.d $f0, 8($sp) + mov.d $f15, $f0 # pass fpr result + move $a2, $v0 # pass gpr result + move $a1, $t0 # pass $sp + jal artInstrumentationMethodExitFromCode # (Thread*, SP, gpr_res, fpr_res) + move $a0, rSELF # pass Thread::Current + move $t0, $v0 # set aside returned link register + move $ra, $v1 # set link register for deoptimization + ld $v0, 0($sp) # restore return values + l.d $f0, 8($sp) + jalr $zero, $t0 # return + daddiu $sp, $sp, 16+FRAME_SIZE_REFS_ONLY_CALLEE_SAVE # 16 bytes of saved values + ref_only callee save frame + .cfi_adjust_cfa_offset -(16+FRAME_SIZE_REFS_ONLY_CALLEE_SAVE) +END art_quick_instrumentation_exit + +UNIMPLEMENTED art_quick_deoptimize +UNIMPLEMENTED art_quick_indexof +UNIMPLEMENTED art_quick_string_compareto diff --git a/runtime/arch/mips64/quick_method_frame_info_mips64.h b/runtime/arch/mips64/quick_method_frame_info_mips64.h index 281d5e68a4..de55e81654 100644 --- a/runtime/arch/mips64/quick_method_frame_info_mips64.h +++ b/runtime/arch/mips64/quick_method_frame_info_mips64.h @@ -40,6 +40,7 @@ static constexpr uint32_t kMips64CalleeSaveFpArgSpills = (1 << art::mips64::F12) | (1 << art::mips64::F13) | (1 << art::mips64::F14) | (1 << art::mips64::F15) | (1 << art::mips64::F16) | (1 << art::mips64::F17) | (1 << art::mips64::F18) | (1 << art::mips64::F19); +// F12 should not be necessary to spill, as A0 is always in use. static constexpr uint32_t kMips64CalleeSaveFpAllSpills = (1 << art::mips64::F24) | (1 << art::mips64::F25) | (1 << art::mips64::F26) | (1 << art::mips64::F27) | (1 << art::mips64::F28) | (1 << art::mips64::F29) | diff --git a/runtime/arch/mips64/thread_mips64.cc b/runtime/arch/mips64/thread_mips64.cc new file mode 100644 index 0000000000..c55537ccc2 --- /dev/null +++ b/runtime/arch/mips64/thread_mips64.cc @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 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 "asm_support_mips64.h" +#include "base/logging.h" + +namespace art { + +void Thread::InitCpu() { + CHECK_EQ(THREAD_FLAGS_OFFSET, ThreadFlagsOffset<8>().Int32Value()); + CHECK_EQ(THREAD_CARD_TABLE_OFFSET, CardTableOffset<8>().Int32Value()); + CHECK_EQ(THREAD_EXCEPTION_OFFSET, ExceptionOffset<8>().Int32Value()); +} + +void Thread::CleanupCpu() { + // Do nothing. +} + +} // namespace art diff --git a/runtime/atomic.h b/runtime/atomic.h index cf61277053..87de506a85 100644 --- a/runtime/atomic.h +++ b/runtime/atomic.h @@ -46,6 +46,9 @@ class Mutex; class QuasiAtomic { #if defined(__mips__) && !defined(__LP64__) static constexpr bool kNeedSwapMutexes = true; +#elif defined(__mips__) && defined(__LP64__) + // TODO - mips64 still need this for Cas64 ??? + static constexpr bool kNeedSwapMutexes = true; #else static constexpr bool kNeedSwapMutexes = false; #endif diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index ac640b4454..cd34d8880d 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -64,6 +64,7 @@ class QuickArgumentVisitor { static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = !kArm32QuickCodeUseSoftFloat; static constexpr size_t kNumQuickGprArgs = 3; static constexpr size_t kNumQuickFprArgs = kArm32QuickCodeUseSoftFloat ? 0 : 16; + static constexpr bool kGprFprLockstep = false; static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = arm::ArmCalleeSaveFpr1Offset(Runtime::kRefsAndArgs); // Offset of first FPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = @@ -99,6 +100,7 @@ class QuickArgumentVisitor { static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false; static constexpr size_t kNumQuickGprArgs = 7; // 7 arguments passed in GPRs. static constexpr size_t kNumQuickFprArgs = 8; // 8 arguments passed in FPRs. + static constexpr bool kGprFprLockstep = false; static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = arm64::Arm64CalleeSaveFpr1Offset(Runtime::kRefsAndArgs); // Offset of first FPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = @@ -108,7 +110,7 @@ class QuickArgumentVisitor { static size_t GprIndexToGprOffset(uint32_t gpr_index) { return gpr_index * GetBytesPerGprSpillLocation(kRuntimeISA); } -#elif defined(__mips__) +#elif defined(__mips__) && !defined(__LP64__) // The callee save frame is pointed to by SP. // | argN | | // | ... | | @@ -128,12 +130,60 @@ class QuickArgumentVisitor { static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false; static constexpr size_t kNumQuickGprArgs = 3; // 3 arguments passed in GPRs. static constexpr size_t kNumQuickFprArgs = 0; // 0 arguments passed in FPRs. + static constexpr bool kGprFprLockstep = false; static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 0; // Offset of first FPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 4; // Offset of first GPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 60; // Offset of return address. static size_t GprIndexToGprOffset(uint32_t gpr_index) { return gpr_index * GetBytesPerGprSpillLocation(kRuntimeISA); } +#elif defined(__mips__) && defined(__LP64__) + // The callee save frame is pointed to by SP. + // | argN | | + // | ... | | + // | arg4 | | + // | arg3 spill | | Caller's frame + // | arg2 spill | | + // | arg1 spill | | + // | Method* | --- + // | RA | + // | ... | callee saves + // | F7 | f_arg7 + // | F6 | f_arg6 + // | F5 | f_arg5 + // | F6 | f_arg6 + // | F5 | f_arg5 + // | F4 | f_arg4 + // | F3 | f_arg3 + // | F2 | f_arg2 + // | F1 | f_arg1 + // | F0 | f_arg0 + // | A7 | arg7 + // | A6 | arg6 + // | A5 | arg5 + // | A4 | arg4 + // | A3 | arg3 + // | A2 | arg2 + // | A1 | arg1 + // | | padding + // | A0/Method* | <- sp + // NOTE: for Mip64, when A0 is skipped, F0 is also skipped. + static constexpr bool kAlignPairRegister = false; + static constexpr bool kQuickSoftFloatAbi = false; + static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false; + // These values are set to zeros because GPR and FPR register + // assignments for Mips64 are interleaved, which the current VisitArguments() + // function does not support. + static constexpr size_t kNumQuickGprArgs = 7; // 7 arguments passed in GPRs. + static constexpr size_t kNumQuickFprArgs = 7; // 7 arguments passed in FPRs. + static constexpr bool kGprFprLockstep = true; + + static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 24; // Offset of first FPR arg (F1). + static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 80; // Offset of first GPR arg (A1). + static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 200; // Offset of return address. + static size_t GprIndexToGprOffset(uint32_t gpr_index) { + return gpr_index * GetBytesPerGprSpillLocation(kRuntimeISA); + } #elif defined(__i386__) // The callee save frame is pointed to by SP. // | argN | | @@ -154,6 +204,7 @@ class QuickArgumentVisitor { static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false; static constexpr size_t kNumQuickGprArgs = 3; // 3 arguments passed in GPRs. static constexpr size_t kNumQuickFprArgs = 0; // 0 arguments passed in FPRs. + static constexpr bool kGprFprLockstep = false; static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 0; // Offset of first FPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 4; // Offset of first GPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 28; // Offset of return address. @@ -193,6 +244,7 @@ class QuickArgumentVisitor { static constexpr bool kQuickDoubleRegAlignedFloatBackFilled = false; static constexpr size_t kNumQuickGprArgs = 5; // 5 arguments passed in GPRs. static constexpr size_t kNumQuickFprArgs = 8; // 8 arguments passed in FPRs. + static constexpr bool kGprFprLockstep = false; static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset = 16; // Offset of first FPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset = 80 + 4*8; // Offset of first GPR arg. static constexpr size_t kQuickCalleeSaveFrame_RefAndArgs_LrOffset = 168 + 4*8; // Offset of return address. @@ -314,6 +366,20 @@ class QuickArgumentVisitor { + stack_index_ * kBytesStackArgLocation); } + void IncGprIndex() { + gpr_index_++; + if (kGprFprLockstep) { + fpr_index_++; + } + } + + void IncFprIndex() { + fpr_index_++; + if (kGprFprLockstep) { + gpr_index_++; + } + } + void VisitArguments() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // (a) 'stack_args_' should point to the first method's argument // (b) whatever the argument type it is, the 'stack_index_' should @@ -330,7 +396,7 @@ class QuickArgumentVisitor { Visit(); stack_index_++; if (kNumQuickGprArgs > 0) { - gpr_index_++; + IncGprIndex(); } } for (uint32_t shorty_index = 1; shorty_index < shorty_len_; ++shorty_index) { @@ -346,7 +412,7 @@ class QuickArgumentVisitor { Visit(); stack_index_++; if (gpr_index_ < kNumQuickGprArgs) { - gpr_index_++; + IncGprIndex(); } break; case Primitive::kPrimFloat: @@ -355,11 +421,11 @@ class QuickArgumentVisitor { stack_index_++; if (kQuickSoftFloatAbi) { if (gpr_index_ < kNumQuickGprArgs) { - gpr_index_++; + IncGprIndex(); } } else { if (fpr_index_ + 1 < kNumQuickFprArgs + 1) { - fpr_index_++; + IncFprIndex(); if (kQuickDoubleRegAlignedFloatBackFilled) { // Double should not overlap with float. // For example, if fpr_index_ = 3, fpr_double_index_ should be at least 4. @@ -378,7 +444,7 @@ class QuickArgumentVisitor { if (cur_type_ == Primitive::kPrimLong && kAlignPairRegister && gpr_index_ == 0) { // Currently, this is only for ARM, where the first available parameter register // is R1. So we skip it, and use R2 instead. - gpr_index_++; + IncGprIndex(); } is_split_long_or_double_ = (GetBytesPerGprSpillLocation(kRuntimeISA) == 4) && ((gpr_index_ + 1) == kNumQuickGprArgs); @@ -390,10 +456,10 @@ class QuickArgumentVisitor { stack_index_++; } if (gpr_index_ < kNumQuickGprArgs) { - gpr_index_++; + IncGprIndex(); if (GetBytesPerGprSpillLocation(kRuntimeISA) == 4) { if (gpr_index_ < kNumQuickGprArgs) { - gpr_index_++; + IncGprIndex(); } } } @@ -416,10 +482,10 @@ class QuickArgumentVisitor { } } } else if (fpr_index_ + 1 < kNumQuickFprArgs + 1) { - fpr_index_++; + IncFprIndex(); if (GetBytesPerFprSpillLocation(kRuntimeISA) == 4) { if (fpr_index_ + 1 < kNumQuickFprArgs + 1) { - fpr_index_++; + IncFprIndex(); } } } @@ -939,7 +1005,8 @@ template class BuildNativeCallFrameStateMachine { static constexpr size_t kRegistersNeededForLong = 2; static constexpr size_t kRegistersNeededForDouble = 2; static constexpr bool kMultiRegistersAligned = true; - static constexpr bool kMultiRegistersWidened = false; + static constexpr bool kMultiFPRegistersWidened = false; + static constexpr bool kMultiGPRegistersWidened = false; static constexpr bool kAlignLongOnStack = true; static constexpr bool kAlignDoubleOnStack = true; #elif defined(__aarch64__) @@ -950,10 +1017,11 @@ template class BuildNativeCallFrameStateMachine { static constexpr size_t kRegistersNeededForLong = 1; static constexpr size_t kRegistersNeededForDouble = 1; static constexpr bool kMultiRegistersAligned = false; - static constexpr bool kMultiRegistersWidened = false; + static constexpr bool kMultiFPRegistersWidened = false; + static constexpr bool kMultiGPRegistersWidened = false; static constexpr bool kAlignLongOnStack = false; static constexpr bool kAlignDoubleOnStack = false; -#elif defined(__mips__) +#elif defined(__mips__) && !defined(__LP64__) static constexpr bool kNativeSoftFloatAbi = true; // This is a hard float ABI. static constexpr size_t kNumNativeGprArgs = 4; // 4 arguments passed in GPRs. static constexpr size_t kNumNativeFprArgs = 0; // 0 arguments passed in FPRs. @@ -961,9 +1029,23 @@ template class BuildNativeCallFrameStateMachine { static constexpr size_t kRegistersNeededForLong = 2; static constexpr size_t kRegistersNeededForDouble = 2; static constexpr bool kMultiRegistersAligned = true; - static constexpr bool kMultiRegistersWidened = true; + static constexpr bool kMultiFPRegistersWidened = true; + static constexpr bool kMultiGPRegistersWidened = false; static constexpr bool kAlignLongOnStack = true; static constexpr bool kAlignDoubleOnStack = true; +#elif defined(__mips__) && defined(__LP64__) + // Let the code prepare GPRs only and we will load the FPRs with same data. + static constexpr bool kNativeSoftFloatAbi = true; + static constexpr size_t kNumNativeGprArgs = 8; + static constexpr size_t kNumNativeFprArgs = 0; + + static constexpr size_t kRegistersNeededForLong = 1; + static constexpr size_t kRegistersNeededForDouble = 1; + static constexpr bool kMultiRegistersAligned = false; + static constexpr bool kMultiFPRegistersWidened = false; + static constexpr bool kMultiGPRegistersWidened = true; + static constexpr bool kAlignLongOnStack = false; + static constexpr bool kAlignDoubleOnStack = false; #elif defined(__i386__) // TODO: Check these! static constexpr bool kNativeSoftFloatAbi = false; // Not using int registers for fp @@ -973,7 +1055,8 @@ template class BuildNativeCallFrameStateMachine { static constexpr size_t kRegistersNeededForLong = 2; static constexpr size_t kRegistersNeededForDouble = 2; static constexpr bool kMultiRegistersAligned = false; // x86 not using regs, anyways - static constexpr bool kMultiRegistersWidened = false; + static constexpr bool kMultiFPRegistersWidened = false; + static constexpr bool kMultiGPRegistersWidened = false; static constexpr bool kAlignLongOnStack = false; static constexpr bool kAlignDoubleOnStack = false; #elif defined(__x86_64__) @@ -984,7 +1067,8 @@ template class BuildNativeCallFrameStateMachine { static constexpr size_t kRegistersNeededForLong = 1; static constexpr size_t kRegistersNeededForDouble = 1; static constexpr bool kMultiRegistersAligned = false; - static constexpr bool kMultiRegistersWidened = false; + static constexpr bool kMultiFPRegistersWidened = false; + static constexpr bool kMultiGPRegistersWidened = false; static constexpr bool kAlignLongOnStack = false; static constexpr bool kAlignDoubleOnStack = false; #else @@ -1043,10 +1127,20 @@ template class BuildNativeCallFrameStateMachine { void AdvanceInt(uint32_t val) { if (HaveIntGpr()) { gpr_index_--; - PushGpr(val); + if (kMultiGPRegistersWidened) { + DCHECK_EQ(sizeof(uintptr_t), sizeof(int64_t)); + PushGpr(static_cast(bit_cast(val))); + } else { + PushGpr(val); + } } else { stack_entries_++; - PushStack(val); + if (kMultiGPRegistersWidened) { + DCHECK_EQ(sizeof(uintptr_t), sizeof(int64_t)); + PushStack(static_cast(bit_cast(val))); + } else { + PushStack(val); + } gpr_index_ = 0; } } @@ -1108,7 +1202,7 @@ template class BuildNativeCallFrameStateMachine { if (HaveFloatFpr()) { fpr_index_--; if (kRegistersNeededForDouble == 1) { - if (kMultiRegistersWidened) { + if (kMultiFPRegistersWidened) { PushFpr8(bit_cast(val)); } else { // No widening, just use the bits. @@ -1119,7 +1213,7 @@ template class BuildNativeCallFrameStateMachine { } } else { stack_entries_++; - if (kRegistersNeededForDouble == 1 && kMultiRegistersWidened) { + if (kRegistersNeededForDouble == 1 && kMultiFPRegistersWidened) { // Need to widen before storing: Note the "double" in the template instantiation. // Note: We need to jump through those hoops to make the compiler happy. DCHECK_EQ(sizeof(uintptr_t), sizeof(uint64_t)); diff --git a/runtime/vmap_table.h b/runtime/vmap_table.h index df5cd80e97..db9e1ea5cb 100644 --- a/runtime/vmap_table.h +++ b/runtime/vmap_table.h @@ -65,7 +65,7 @@ class VmapTable { uint16_t adjusted_vreg = vreg + kEntryAdjustment; size_t end = DecodeUnsignedLeb128(&table); bool high_reg = (kind == kLongHiVReg) || (kind == kDoubleHiVReg); - bool target64 = (kRuntimeISA == kArm64) || (kRuntimeISA == kX86_64); + bool target64 = (kRuntimeISA == kArm64) || (kRuntimeISA == kX86_64) || (kRuntimeISA == kMips64); if (target64 && high_reg) { // Wide promoted registers are associated with the sreg of the low portion. adjusted_vreg--; -- cgit v1.2.3