summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2015-01-15 12:10:47 -0800
committerAndreas Gampe <agampe@google.com>2015-01-15 20:13:48 -0800
commit1a5c40672783fac98aca5a04ac798a0a0014de65 (patch)
tree18545fd8c3588dd4f4dde91d367da82c53cf17a9 /runtime
parent0223a19fa4fc39ba89de2b87b03b98a5fd97778b (diff)
downloadandroid_art-1a5c40672783fac98aca5a04ac798a0a0014de65.tar.gz
android_art-1a5c40672783fac98aca5a04ac798a0a0014de65.tar.bz2
android_art-1a5c40672783fac98aca5a04ac798a0a0014de65.zip
ART: Mips64 runtime support
Interpret-only Mips64 runtime support. Change-Id: Iee22d0c8c77105d9b2f03a67dc4e09957fe0ab0a
Diffstat (limited to 'runtime')
-rw-r--r--runtime/Android.mk13
-rw-r--r--runtime/arch/arch_test.cc17
-rw-r--r--runtime/arch/context.cc8
-rw-r--r--runtime/arch/mips64/asm_support_mips64.S71
-rw-r--r--runtime/arch/mips64/asm_support_mips64.h29
-rw-r--r--runtime/arch/mips64/context_mips64.cc147
-rw-r--r--runtime/arch/mips64/context_mips64.h92
-rw-r--r--runtime/arch/mips64/entrypoints_init_mips64.cc180
-rw-r--r--runtime/arch/mips64/fault_handler_mips64.cc57
-rw-r--r--runtime/arch/mips64/jni_entrypoints_mips64.S76
-rw-r--r--runtime/arch/mips64/memcmp16_mips64.S50
-rw-r--r--runtime/arch/mips64/quick_entrypoints_mips64.S897
-rw-r--r--runtime/arch/mips64/quick_method_frame_info_mips64.h1
-rw-r--r--runtime/arch/mips64/thread_mips64.cc34
-rw-r--r--runtime/atomic.h3
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc134
-rw-r--r--runtime/vmap_table.h2
17 files changed, 1785 insertions, 26 deletions
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<uint32_t>(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<uint32_t>(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<uintptr_t*>(&gZero);
+ gprs_[V1] = const_cast<uintptr_t*>(&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<uint32_t>(kNumberOfGpuRegisters));
+ return gprs_[reg];
+ }
+
+ bool GetGPR(uint32_t reg, uintptr_t* val) OVERRIDE {
+ CHECK_LT(reg, static_cast<uint32_t>(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<uint32_t>(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 <sys/ucontext.h>
+#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 T> 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 T> 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 T> 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 T> 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 T> 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 T> 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<int64_t>(bit_cast<uint32_t, int32_t>(val)));
+ } else {
+ PushGpr(val);
+ }
} else {
stack_entries_++;
- PushStack(val);
+ if (kMultiGPRegistersWidened) {
+ DCHECK_EQ(sizeof(uintptr_t), sizeof(int64_t));
+ PushStack(static_cast<int64_t>(bit_cast<uint32_t, int32_t>(val)));
+ } else {
+ PushStack(val);
+ }
gpr_index_ = 0;
}
}
@@ -1108,7 +1202,7 @@ template<class T> class BuildNativeCallFrameStateMachine {
if (HaveFloatFpr()) {
fpr_index_--;
if (kRegistersNeededForDouble == 1) {
- if (kMultiRegistersWidened) {
+ if (kMultiFPRegistersWidened) {
PushFpr8(bit_cast<double, uint64_t>(val));
} else {
// No widening, just use the bits.
@@ -1119,7 +1213,7 @@ template<class T> 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--;