ART: Mips64 runtime support

Interpret-only Mips64 runtime support.

Change-Id: Iee22d0c8c77105d9b2f03a67dc4e09957fe0ab0a
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 00962f5..1f040d6 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -17,7 +17,7 @@
 ifndef ART_ANDROID_COMMON_MK
 ART_ANDROID_COMMON_MK = true
 
-ART_TARGET_SUPPORTED_ARCH := arm arm64 mips x86 x86_64
+ART_TARGET_SUPPORTED_ARCH := arm arm64 mips mips64 x86 x86_64
 ART_HOST_SUPPORTED_ARCH := x86 x86_64
 
 ifeq (,$(filter $(TARGET_ARCH),$(ART_TARGET_SUPPORTED_ARCH)))
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 086f298..cd9ed50 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -95,6 +95,7 @@
 ART_TARGET_CLANG_arm64 :=
 # TODO: Enable clang mips when b/18807290 and b/18789639 are fixed.
 ART_TARGET_CLANG_mips := false
+ART_TARGET_CLANG_mips64 := false
 ART_TARGET_CLANG_x86 :=
 ART_TARGET_CLANG_x86_64 :=
 
@@ -110,6 +111,7 @@
 ART_TARGET_CLANG_CFLAGS_arm :=
 ART_TARGET_CLANG_CFLAGS_arm64 :=
 ART_TARGET_CLANG_CFLAGS_mips :=
+ART_TARGET_CLANG_CFLAGS_mips64 :=
 ART_TARGET_CLANG_CFLAGS_x86 :=
 ART_TARGET_CLANG_CFLAGS_x86_64 :=
 
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 3330b2d..fdc3e7c 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -264,9 +264,15 @@
   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_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 cac500c..ab6b00b 100644
--- a/runtime/arch/arch_test.cc
+++ b/runtime/arch/arch_test.cc
@@ -82,6 +82,16 @@
 #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 @@
                  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 b1700bb..bf40a3f 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 @@
   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 0000000..10976bb
--- /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 0000000..995fcf3
--- /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 0000000..7523ade
--- /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 0000000..4ba5f13
--- /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 0000000..4a3bf02
--- /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 0000000..7b5cd49
--- /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 0000000..90fd3ee
--- /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 0000000..962977e
--- /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 0000000..3430eb5
--- /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 281d5e6..de55e81 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 @@
     (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 0000000..c55537c
--- /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 cf61277..87de506 100644
--- a/runtime/atomic.h
+++ b/runtime/atomic.h
@@ -46,6 +46,9 @@
 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 ac640b4..cd34d88 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -64,6 +64,7 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
         + 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 @@
       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 @@
           Visit();
           stack_index_++;
           if (gpr_index_ < kNumQuickGprArgs) {
-            gpr_index_++;
+            IncGprIndex();
           }
           break;
         case Primitive::kPrimFloat:
@@ -355,11 +421,11 @@
           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 @@
             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 @@
               stack_index_++;
             }
             if (gpr_index_ < kNumQuickGprArgs) {
-              gpr_index_++;
+              IncGprIndex();
               if (GetBytesPerGprSpillLocation(kRuntimeISA) == 4) {
                 if (gpr_index_ < kNumQuickGprArgs) {
-                  gpr_index_++;
+                  IncGprIndex();
                 }
               }
             }
@@ -416,10 +482,10 @@
                 }
               }
             } 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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
       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 @@
         }
       } 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 df5cd80..db9e1ea 100644
--- a/runtime/vmap_table.h
+++ b/runtime/vmap_table.h
@@ -65,7 +65,7 @@
     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--;
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 2710df8..0916971 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -10,7 +10,7 @@
 
 ANDROID_ROOT="/system"
 ARCHITECTURES_32="(arm|x86|mips|none)"
-ARCHITECTURES_64="(arm64|x86_64|none)"
+ARCHITECTURES_64="(arm64|x86_64|mips64|none)"
 ARCHITECTURES_PATTERN="${ARCHITECTURES_32}"
 BOOT_IMAGE=""
 COMPILE_FLAGS=""
diff --git a/test/run-test b/test/run-test
index d2b1ec9..2802b75 100755
--- a/test/run-test
+++ b/test/run-test
@@ -298,7 +298,7 @@
 # Try to map the suffix64 flag and what we find in ${ANDROID_PRODUCT_OUT}/data/art-test to an architecture name.
 function guess_arch_name() {
     grep32bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm|x86|mips)$'`
-    grep64bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm64|x86_64)$'`
+    grep64bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm64|x86_64|mips64)$'`
     if [ "x${suffix64}" = "x64" ]; then
         target_arch_name=${grep64bit}
     else
diff --git a/tools/symbolize.sh b/tools/symbolize.sh
index b66191f..0168e7d 100755
--- a/tools/symbolize.sh
+++ b/tools/symbolize.sh
@@ -52,7 +52,7 @@
   DIRS=$(adbls /data/dalvik-cache/)
   for DIR in $DIRS ; do
     case $DIR in
-      arm|arm64|mips|x86|x86_64)
+      arm|arm64|mips|mips64|x86|x86_64)
         FILES=$(adbls /data/dalvik-cache/$DIR/*.oat /data/dalvik-cache/$DIR/*.dex)
         for FILE in $FILES ; do
           # Cannot use basename as the file doesn't exist.