ART: Allow to compile interpret-only mips64 files

Include enough infrastructure to allow cross-compiling for mips64,
interpret-only. This includes the instruction-set-features, frame
size info and utils assembler.

Also add a disassembler for oatdump, and support in patchoat.

Note: the runtime cannot run mips64, yet.

Change-Id: Id106581fa76b478984741c62a8a03be0f370d992
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 13a216c..3330b2d 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -170,6 +170,8 @@
   arch/arm64/registers_arm64.cc \
   arch/mips/instruction_set_features_mips.cc \
   arch/mips/registers_mips.cc \
+  arch/mips64/instruction_set_features_mips64.cc \
+  arch/mips64/registers_mips64.cc \
   arch/x86/instruction_set_features_x86.cc \
   arch/x86/registers_x86.cc \
   arch/x86_64/registers_x86_64.cc \
diff --git a/runtime/arch/instruction_set.cc b/runtime/arch/instruction_set.cc
index 92fa727..5ab461b 100644
--- a/runtime/arch/instruction_set.cc
+++ b/runtime/arch/instruction_set.cc
@@ -57,7 +57,7 @@
   } else if (strcmp("mips", isa_str) == 0) {
     return kMips;
   } else if (strcmp("mips64", isa_str) == 0) {
-    return kMips;
+    return kMips64;
   }
 
   return kNone;
@@ -76,6 +76,8 @@
     case kX86_64:
       return kX86Alignment;
     case kMips:
+      // Fall-through.
+    case kMips64:
       return kMipsAlignment;
     case kNone:
       LOG(FATAL) << "ISA kNone does not have alignment.";
@@ -88,6 +90,7 @@
 
 static constexpr size_t kDefaultStackOverflowReservedBytes = 16 * KB;
 static constexpr size_t kMipsStackOverflowReservedBytes = kDefaultStackOverflowReservedBytes;
+static constexpr size_t kMips64StackOverflowReservedBytes = kDefaultStackOverflowReservedBytes;
 
 static constexpr size_t kArmStackOverflowReservedBytes =    8 * KB;
 static constexpr size_t kArm64StackOverflowReservedBytes =  8 * KB;
@@ -106,6 +109,9 @@
     case kMips:
       return kMipsStackOverflowReservedBytes;
 
+    case kMips64:
+      return kMips64StackOverflowReservedBytes;
+
     case kX86:
       return kX86StackOverflowReservedBytes;
 
diff --git a/runtime/arch/instruction_set.h b/runtime/arch/instruction_set.h
index e413880..9135e58 100644
--- a/runtime/arch/instruction_set.h
+++ b/runtime/arch/instruction_set.h
@@ -40,8 +40,10 @@
 static constexpr InstructionSet kRuntimeISA = kArm;
 #elif defined(__aarch64__)
 static constexpr InstructionSet kRuntimeISA = kArm64;
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
 static constexpr InstructionSet kRuntimeISA = kMips;
+#elif defined(__mips__) && defined(__LP64__)
+static constexpr InstructionSet kRuntimeISA = kMips64;
 #elif defined(__i386__)
 static constexpr InstructionSet kRuntimeISA = kX86;
 #elif defined(__x86_64__)
@@ -145,6 +147,8 @@
       return 8;
     case kMips:
       return 4;
+    case kMips64:
+      return 8;
     case kNone:
       LOG(FATAL) << "ISA kNone does not have spills.";
       UNREACHABLE();
@@ -168,6 +172,8 @@
       return 8;
     case kMips:
       return 4;
+    case kMips64:
+      return 8;
     case kNone:
       LOG(FATAL) << "ISA kNone does not have spills.";
       UNREACHABLE();
@@ -186,8 +192,8 @@
 // On x86, ARM32 and MIPS, this is given for a *scalar* 64bit value. The definition thus *must* be
 // uint64_t or long long int.
 //
-// On x86_64 and ARM64, structs are decomposed for allocation, so we can create a structs of two
-// size_t-sized values.
+// On x86_64, ARM64 and MIPS64, structs are decomposed for allocation, so we can create a structs of
+// two size_t-sized values.
 //
 // We need two operations:
 //
@@ -202,7 +208,7 @@
 //            when the garbage collector can move objects concurrently. Ensure that required locks
 //            are held when using!
 
-#if defined(__i386__) || defined(__arm__) || defined(__mips__)
+#if defined(__i386__) || defined(__arm__) || (defined(__mips__) && !defined(__LP64__))
 typedef uint64_t TwoWordReturn;
 
 // Encodes method_ptr==nullptr and code_ptr==nullptr
@@ -218,7 +224,7 @@
   return ((hi64 << 32) | lo32);
 }
 
-#elif defined(__x86_64__) || defined(__aarch64__)
+#elif defined(__x86_64__) || defined(__aarch64__) || (defined(__mips__) && defined(__LP64__))
 struct TwoWordReturn {
   uintptr_t lo;
   uintptr_t hi;
diff --git a/runtime/arch/instruction_set_features.cc b/runtime/arch/instruction_set_features.cc
index 1072562..1fd1dea 100644
--- a/runtime/arch/instruction_set_features.cc
+++ b/runtime/arch/instruction_set_features.cc
@@ -23,6 +23,7 @@
 #include "arm/instruction_set_features_arm.h"
 #include "arm64/instruction_set_features_arm64.h"
 #include "mips/instruction_set_features_mips.h"
+#include "mips64/instruction_set_features_mips64.h"
 #include "x86/instruction_set_features_x86.h"
 #include "x86_64/instruction_set_features_x86_64.h"
 
@@ -43,6 +44,9 @@
     case kMips:
       result = MipsInstructionSetFeatures::FromVariant(variant, error_msg);
       break;
+    case kMips64:
+      result = Mips64InstructionSetFeatures::FromVariant(variant, error_msg);
+      break;
     case kX86:
       result = X86InstructionSetFeatures::FromVariant(variant, error_msg);
       break;
@@ -71,6 +75,9 @@
     case kMips:
       result = MipsInstructionSetFeatures::FromBitmap(bitmap);
       break;
+    case kMips64:
+      result = Mips64InstructionSetFeatures::FromBitmap(bitmap);
+      break;
     case kX86:
       result = X86InstructionSetFeatures::FromBitmap(bitmap);
       break;
@@ -98,6 +105,9 @@
     case kMips:
       result = MipsInstructionSetFeatures::FromCppDefines();
       break;
+    case kMips64:
+      result = Mips64InstructionSetFeatures::FromCppDefines();
+      break;
     case kX86:
       result = X86InstructionSetFeatures::FromCppDefines();
       break;
@@ -125,6 +135,9 @@
     case kMips:
       result = MipsInstructionSetFeatures::FromCpuInfo();
       break;
+    case kMips64:
+      result = Mips64InstructionSetFeatures::FromCpuInfo();
+      break;
     case kX86:
       result = X86InstructionSetFeatures::FromCpuInfo();
       break;
@@ -151,6 +164,9 @@
     case kMips:
       result = MipsInstructionSetFeatures::FromHwcap();
       break;
+    case kMips64:
+      result = Mips64InstructionSetFeatures::FromHwcap();
+      break;
     case kX86:
       result = X86InstructionSetFeatures::FromHwcap();
       break;
@@ -177,6 +193,9 @@
     case kMips:
       result = MipsInstructionSetFeatures::FromAssembly();
       break;
+    case kMips64:
+      result = Mips64InstructionSetFeatures::FromAssembly();
+      break;
     case kX86:
       result = X86InstructionSetFeatures::FromAssembly();
       break;
@@ -250,6 +269,11 @@
   return down_cast<const MipsInstructionSetFeatures*>(this);
 }
 
+const Mips64InstructionSetFeatures* InstructionSetFeatures::AsMips64InstructionSetFeatures() const {
+  DCHECK_EQ(kMips64, GetInstructionSet());
+  return down_cast<const Mips64InstructionSetFeatures*>(this);
+}
+
 const X86InstructionSetFeatures* InstructionSetFeatures::AsX86InstructionSetFeatures() const {
   DCHECK(kX86 == GetInstructionSet() || kX86_64 == GetInstructionSet());
   return down_cast<const X86InstructionSetFeatures*>(this);
diff --git a/runtime/arch/instruction_set_features.h b/runtime/arch/instruction_set_features.h
index 2c6e699..e4513ef 100644
--- a/runtime/arch/instruction_set_features.h
+++ b/runtime/arch/instruction_set_features.h
@@ -28,6 +28,7 @@
 class ArmInstructionSetFeatures;
 class Arm64InstructionSetFeatures;
 class MipsInstructionSetFeatures;
+class Mips64InstructionSetFeatures;
 class X86InstructionSetFeatures;
 class X86_64InstructionSetFeatures;
 
@@ -87,6 +88,9 @@
   // Down cast this MipsInstructionFeatures.
   const MipsInstructionSetFeatures* AsMipsInstructionSetFeatures() const;
 
+  // Down cast this Mips64InstructionFeatures.
+  const Mips64InstructionSetFeatures* AsMips64InstructionSetFeatures() const;
+
   // Down cast this X86InstructionFeatures.
   const X86InstructionSetFeatures* AsX86InstructionSetFeatures() const;
 
diff --git a/runtime/arch/instruction_set_test.cc b/runtime/arch/instruction_set_test.cc
index 932ef32..2f3cf18 100644
--- a/runtime/arch/instruction_set_test.cc
+++ b/runtime/arch/instruction_set_test.cc
@@ -28,6 +28,7 @@
   EXPECT_EQ(kX86, GetInstructionSetFromString("x86"));
   EXPECT_EQ(kX86_64, GetInstructionSetFromString("x86_64"));
   EXPECT_EQ(kMips, GetInstructionSetFromString("mips"));
+  EXPECT_EQ(kMips64, GetInstructionSetFromString("mips64"));
   EXPECT_EQ(kNone, GetInstructionSetFromString("none"));
   EXPECT_EQ(kNone, GetInstructionSetFromString("random-string"));
 }
@@ -39,6 +40,7 @@
   EXPECT_STREQ("x86", GetInstructionSetString(kX86));
   EXPECT_STREQ("x86_64", GetInstructionSetString(kX86_64));
   EXPECT_STREQ("mips", GetInstructionSetString(kMips));
+  EXPECT_STREQ("mips64", GetInstructionSetString(kMips64));
   EXPECT_STREQ("none", GetInstructionSetString(kNone));
 }
 
diff --git a/runtime/arch/mips64/instruction_set_features_mips64.cc b/runtime/arch/mips64/instruction_set_features_mips64.cc
new file mode 100644
index 0000000..26478cb
--- /dev/null
+++ b/runtime/arch/mips64/instruction_set_features_mips64.cc
@@ -0,0 +1,116 @@
+/*
+ * 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 "instruction_set_features_mips64.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "base/stringprintf.h"
+#include "utils.h"  // For Trim.
+
+namespace art {
+
+const Mips64InstructionSetFeatures* Mips64InstructionSetFeatures::FromVariant(
+    const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED) {
+  // TODO: r6 variant.
+  if (variant != "default") {
+    std::ostringstream os;
+    LOG(WARNING) << "Unexpected CPU variant for Mips64 using defaults: " << variant;
+  }
+  bool smp = true;  // Conservative default.
+  return new Mips64InstructionSetFeatures(smp);
+}
+
+const Mips64InstructionSetFeatures* Mips64InstructionSetFeatures::FromBitmap(uint32_t bitmap) {
+  bool smp = (bitmap & kSmpBitfield) != 0;
+  return new Mips64InstructionSetFeatures(smp);
+}
+
+const Mips64InstructionSetFeatures* Mips64InstructionSetFeatures::FromCppDefines() {
+  const bool smp = true;
+
+  return new Mips64InstructionSetFeatures(smp);
+}
+
+const Mips64InstructionSetFeatures* Mips64InstructionSetFeatures::FromCpuInfo() {
+  // Look in /proc/cpuinfo for features we need.  Only use this when we can guarantee that
+  // the kernel puts the appropriate feature flags in here.  Sometimes it doesn't.
+  bool smp = false;
+
+  std::ifstream in("/proc/cpuinfo");
+  if (!in.fail()) {
+    while (!in.eof()) {
+      std::string line;
+      std::getline(in, line);
+      if (!in.eof()) {
+        LOG(INFO) << "cpuinfo line: " << line;
+        if (line.find("processor") != std::string::npos && line.find(": 1") != std::string::npos) {
+          smp = true;
+        }
+      }
+    }
+    in.close();
+  } else {
+    LOG(ERROR) << "Failed to open /proc/cpuinfo";
+  }
+  return new Mips64InstructionSetFeatures(smp);
+}
+
+const Mips64InstructionSetFeatures* Mips64InstructionSetFeatures::FromHwcap() {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines();
+}
+
+const Mips64InstructionSetFeatures* Mips64InstructionSetFeatures::FromAssembly() {
+  UNIMPLEMENTED(WARNING);
+  return FromCppDefines();
+}
+
+bool Mips64InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
+  if (kMips64 != other->GetInstructionSet()) {
+    return false;
+  }
+  return (IsSmp() == other->IsSmp());
+}
+
+uint32_t Mips64InstructionSetFeatures::AsBitmap() const {
+  return (IsSmp() ? kSmpBitfield : 0);
+}
+
+std::string Mips64InstructionSetFeatures::GetFeatureString() const {
+  std::string result;
+  if (IsSmp()) {
+    result += "smp";
+  } else {
+    result += "-smp";
+  }
+  return result;
+}
+
+const InstructionSetFeatures* Mips64InstructionSetFeatures::AddFeaturesFromSplitString(
+    const bool smp, const std::vector<std::string>& features, std::string* error_msg) const {
+  auto i = features.begin();
+  if (i != features.end()) {
+    // We don't have any features.
+    std::string feature = Trim(*i);
+    *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
+    return nullptr;
+  }
+  return new Mips64InstructionSetFeatures(smp);
+}
+
+}  // namespace art
diff --git a/runtime/arch/mips64/instruction_set_features_mips64.h b/runtime/arch/mips64/instruction_set_features_mips64.h
new file mode 100644
index 0000000..d5d6012
--- /dev/null
+++ b/runtime/arch/mips64/instruction_set_features_mips64.h
@@ -0,0 +1,80 @@
+/*
+ * 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_INSTRUCTION_SET_FEATURES_MIPS64_H_
+#define ART_RUNTIME_ARCH_MIPS64_INSTRUCTION_SET_FEATURES_MIPS64_H_
+
+#include "arch/instruction_set_features.h"
+
+namespace art {
+
+// Instruction set features relevant to the MIPS64 architecture.
+class Mips64InstructionSetFeatures FINAL : public InstructionSetFeatures {
+ public:
+  // Process a CPU variant string like "r4000" and create InstructionSetFeatures.
+  static const Mips64InstructionSetFeatures* FromVariant(const std::string& variant,
+                                                        std::string* error_msg);
+
+  // Parse a bitmap and create an InstructionSetFeatures.
+  static const Mips64InstructionSetFeatures* FromBitmap(uint32_t bitmap);
+
+  // Turn C pre-processor #defines into the equivalent instruction set features.
+  static const Mips64InstructionSetFeatures* FromCppDefines();
+
+  // Process /proc/cpuinfo and use kRuntimeISA to produce InstructionSetFeatures.
+  static const Mips64InstructionSetFeatures* FromCpuInfo();
+
+  // Process the auxiliary vector AT_HWCAP entry and use kRuntimeISA to produce
+  // InstructionSetFeatures.
+  static const Mips64InstructionSetFeatures* FromHwcap();
+
+  // Use assembly tests of the current runtime (ie kRuntimeISA) to determine the
+  // InstructionSetFeatures. This works around kernel bugs in AT_HWCAP and /proc/cpuinfo.
+  static const Mips64InstructionSetFeatures* FromAssembly();
+
+  bool Equals(const InstructionSetFeatures* other) const OVERRIDE;
+
+  InstructionSet GetInstructionSet() const OVERRIDE {
+    return kMips64;
+  }
+
+  uint32_t AsBitmap() const OVERRIDE;
+
+  std::string GetFeatureString() const OVERRIDE;
+
+  virtual ~Mips64InstructionSetFeatures() {}
+
+ protected:
+  // Parse a vector of the form "fpu32", "mips2" adding these to a new Mips64InstructionSetFeatures.
+  virtual const InstructionSetFeatures*
+      AddFeaturesFromSplitString(const bool smp, const std::vector<std::string>& features,
+                                 std::string* error_msg) const OVERRIDE;
+
+ private:
+  explicit Mips64InstructionSetFeatures(bool smp) : InstructionSetFeatures(smp) {
+  }
+
+  // Bitmap positions for encoding features as a bitmap.
+  enum {
+    kSmpBitfield = 1,
+  };
+
+  DISALLOW_COPY_AND_ASSIGN(Mips64InstructionSetFeatures);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_MIPS64_INSTRUCTION_SET_FEATURES_MIPS64_H_
diff --git a/runtime/arch/mips64/instruction_set_features_mips64_test.cc b/runtime/arch/mips64/instruction_set_features_mips64_test.cc
new file mode 100644
index 0000000..dc34506
--- /dev/null
+++ b/runtime/arch/mips64/instruction_set_features_mips64_test.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 "instruction_set_features_mips64.h"
+
+#include <gtest/gtest.h>
+
+namespace art {
+
+TEST(Mips64InstructionSetFeaturesTest, Mips64Features) {
+  std::string error_msg;
+  std::unique_ptr<const InstructionSetFeatures> mips64_features(
+      InstructionSetFeatures::FromVariant(kMips64, "default", &error_msg));
+  ASSERT_TRUE(mips64_features.get() != nullptr) << error_msg;
+  EXPECT_EQ(mips64_features->GetInstructionSet(), kMips64);
+  EXPECT_TRUE(mips64_features->Equals(mips64_features.get()));
+  EXPECT_STREQ("smp", mips64_features->GetFeatureString().c_str());
+  EXPECT_EQ(mips64_features->AsBitmap(), 1U);
+}
+
+}  // namespace art
diff --git a/runtime/arch/mips64/quick_method_frame_info_mips64.h b/runtime/arch/mips64/quick_method_frame_info_mips64.h
new file mode 100644
index 0000000..281d5e6
--- /dev/null
+++ b/runtime/arch/mips64/quick_method_frame_info_mips64.h
@@ -0,0 +1,75 @@
+/*
+ * 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_QUICK_METHOD_FRAME_INFO_MIPS64_H_
+#define ART_RUNTIME_ARCH_MIPS64_QUICK_METHOD_FRAME_INFO_MIPS64_H_
+
+#include "quick/quick_method_frame_info.h"
+#include "registers_mips64.h"
+#include "runtime.h"  // for Runtime::CalleeSaveType.
+
+namespace art {
+namespace mips64 {
+
+static constexpr uint32_t kMips64CalleeSaveRefSpills =
+    (1 << art::mips64::S2) | (1 << art::mips64::S3) | (1 << art::mips64::S4) |
+    (1 << art::mips64::S5) | (1 << art::mips64::S6) | (1 << art::mips64::S7) |
+    (1 << art::mips64::GP) | (1 << art::mips64::S8);
+static constexpr uint32_t kMips64CalleeSaveArgSpills =
+    (1 << art::mips64::A1) | (1 << art::mips64::A2) | (1 << art::mips64::A3) |
+    (1 << art::mips64::A4) | (1 << art::mips64::A5) | (1 << art::mips64::A6) |
+    (1 << art::mips64::A7);
+static constexpr uint32_t kMips64CalleeSaveAllSpills =
+    (1 << art::mips64::S0) | (1 << art::mips64::S1);
+
+static constexpr uint32_t kMips64CalleeSaveFpRefSpills = 0;
+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);
+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) |
+    (1 << art::mips64::F30) | (1 << art::mips64::F31);
+
+constexpr uint32_t Mips64CalleeSaveCoreSpills(Runtime::CalleeSaveType type) {
+  return kMips64CalleeSaveRefSpills |
+      (type == Runtime::kRefsAndArgs ? kMips64CalleeSaveArgSpills : 0) |
+      (type == Runtime::kSaveAll ? kMips64CalleeSaveAllSpills : 0) | (1 << art::mips64::RA);
+}
+
+constexpr uint32_t Mips64CalleeSaveFpSpills(Runtime::CalleeSaveType type) {
+  return kMips64CalleeSaveFpRefSpills |
+      (type == Runtime::kRefsAndArgs ? kMips64CalleeSaveFpArgSpills: 0) |
+      (type == Runtime::kSaveAll ? kMips64CalleeSaveFpAllSpills : 0);
+}
+
+constexpr uint32_t Mips64CalleeSaveFrameSize(Runtime::CalleeSaveType type) {
+  return RoundUp((POPCOUNT(Mips64CalleeSaveCoreSpills(type)) /* gprs */ +
+                  POPCOUNT(Mips64CalleeSaveFpSpills(type))   /* fprs */ +
+                  + 1 /* Method* */) * kMips64PointerSize, kStackAlignment);
+}
+
+constexpr QuickMethodFrameInfo Mips64CalleeSaveMethodFrameInfo(Runtime::CalleeSaveType type) {
+  return QuickMethodFrameInfo(Mips64CalleeSaveFrameSize(type),
+                              Mips64CalleeSaveCoreSpills(type),
+                              Mips64CalleeSaveFpSpills(type));
+}
+
+}  // namespace mips64
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_MIPS64_QUICK_METHOD_FRAME_INFO_MIPS64_H_
diff --git a/runtime/arch/mips64/registers_mips64.cc b/runtime/arch/mips64/registers_mips64.cc
new file mode 100644
index 0000000..4959208
--- /dev/null
+++ b/runtime/arch/mips64/registers_mips64.cc
@@ -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.
+ */
+
+#include "registers_mips64.h"
+
+#include <ostream>
+
+namespace art {
+namespace mips64 {
+
+static const char* kRegisterNames[] = {
+  "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+  "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
+  "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+  "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
+};
+
+std::ostream& operator<<(std::ostream& os, const GpuRegister& rhs) {
+  if (rhs >= ZERO && rhs < kNumberOfGpuRegisters) {
+    os << kRegisterNames[rhs];
+  } else {
+    os << "GpuRegister[" << static_cast<int>(rhs) << "]";
+  }
+  return os;
+}
+
+std::ostream& operator<<(std::ostream& os, const FpuRegister& rhs) {
+  if (rhs >= F0 && rhs < kNumberOfFpuRegisters) {
+    os << "f" << static_cast<int>(rhs);
+  } else {
+    os << "FpuRegister[" << static_cast<int>(rhs) << "]";
+  }
+  return os;
+}
+
+}  // namespace mips64
+}  // namespace art
diff --git a/runtime/arch/mips64/registers_mips64.h b/runtime/arch/mips64/registers_mips64.h
new file mode 100644
index 0000000..38bc8f2
--- /dev/null
+++ b/runtime/arch/mips64/registers_mips64.h
@@ -0,0 +1,109 @@
+/*
+ * 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_REGISTERS_MIPS64_H_
+#define ART_RUNTIME_ARCH_MIPS64_REGISTERS_MIPS64_H_
+
+#include <iosfwd>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "globals.h"
+
+namespace art {
+namespace mips64 {
+
+enum GpuRegister {
+  ZERO =  0,
+  AT   =  1,  // Assembler temporary.
+  V0   =  2,  // Values.
+  V1   =  3,
+  A0   =  4,  // Arguments.
+  A1   =  5,
+  A2   =  6,
+  A3   =  7,
+  A4   =  8,
+  A5   =  9,
+  A6   = 10,
+  A7   = 11,
+  T0   = 12,  // Temporaries.
+  T1   = 13,
+  T2   = 14,
+  T3   = 15,
+  S0   = 16,  // Saved values.
+  S1   = 17,
+  S2   = 18,
+  S3   = 19,
+  S4   = 20,
+  S5   = 21,
+  S6   = 22,
+  S7   = 23,
+  T8   = 24,  // More temporaries.
+  T9   = 25,
+  K0   = 26,  // Reserved for trap handler.
+  K1   = 27,
+  GP   = 28,  // Global pointer.
+  SP   = 29,  // Stack pointer.
+  S8   = 30,  // Saved value/frame pointer.
+  RA   = 31,  // Return address.
+  kNumberOfGpuRegisters = 32,
+  kNoGpuRegister = -1  // Signals an illegal register.
+};
+std::ostream& operator<<(std::ostream& os, const GpuRegister& rhs);
+
+// Values for floating point registers.
+enum FpuRegister {
+  F0  =  0,
+  F1  =  1,
+  F2  =  2,
+  F3  =  3,
+  F4  =  4,
+  F5  =  5,
+  F6  =  6,
+  F7  =  7,
+  F8  =  8,
+  F9  =  9,
+  F10 = 10,
+  F11 = 11,
+  F12 = 12,
+  F13 = 13,
+  F14 = 14,
+  F15 = 15,
+  F16 = 16,
+  F17 = 17,
+  F18 = 18,
+  F19 = 19,
+  F20 = 20,
+  F21 = 21,
+  F22 = 22,
+  F23 = 23,
+  F24 = 24,
+  F25 = 25,
+  F26 = 26,
+  F27 = 27,
+  F28 = 28,
+  F29 = 29,
+  F30 = 30,
+  F31 = 31,
+  kNumberOfFpuRegisters = 32,
+  kNoFpuRegister = -1,
+};
+std::ostream& operator<<(std::ostream& os, const FpuRegister& rhs);
+
+}  // namespace mips64
+}  // namespace art
+
+#endif  // ART_RUNTIME_ARCH_MIPS64_REGISTERS_MIPS64_H_
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index b6df609..1b91aa6 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1335,6 +1335,8 @@
         if ((GetHeader().e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R2 ||
             (GetHeader().e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) {
           elf_ISA = kMips;
+        } else if ((GetHeader().e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) {
+          elf_ISA = kMips64;
         }
         break;
       }
diff --git a/runtime/elf_utils.h b/runtime/elf_utils.h
index 3579e27..418d937 100644
--- a/runtime/elf_utils.h
+++ b/runtime/elf_utils.h
@@ -31,6 +31,7 @@
 #define EF_MIPS_ABI_O32 0x00001000
 #define EF_MIPS_ARCH_32R2 0x70000000
 #define EF_MIPS_ARCH_32R6 0x90000000
+#define EF_MIPS_ARCH_64R6 0xa0000000
 
 #define EI_ABIVERSION 8
 #define EM_ARM 40
diff --git a/runtime/entrypoints/quick/callee_save_frame.h b/runtime/entrypoints/quick/callee_save_frame.h
index 9ffd199..8cd6ca6 100644
--- a/runtime/entrypoints/quick/callee_save_frame.h
+++ b/runtime/entrypoints/quick/callee_save_frame.h
@@ -27,6 +27,7 @@
 #include "arch/arm/quick_method_frame_info_arm.h"
 #include "arch/arm64/quick_method_frame_info_arm64.h"
 #include "arch/mips/quick_method_frame_info_mips.h"
+#include "arch/mips64/quick_method_frame_info_mips64.h"
 #include "arch/x86/quick_method_frame_info_x86.h"
 #include "arch/x86_64/quick_method_frame_info_x86_64.h"
 
@@ -76,6 +77,7 @@
   return (isa == kArm || isa == kThumb2) ? arm::ArmCalleeSaveFrameSize(type) :
          isa == kArm64 ? arm64::Arm64CalleeSaveFrameSize(type) :
          isa == kMips ? mips::MipsCalleeSaveFrameSize(type) :
+         isa == kMips64 ? mips64::Mips64CalleeSaveFrameSize(type) :
          isa == kX86 ? x86::X86CalleeSaveFrameSize(type) :
          isa == kX86_64 ? x86_64::X86_64CalleeSaveFrameSize(type) :
          isa == kNone ? (LOG(FATAL) << "kNone has no frame size", 0) :
@@ -88,6 +90,7 @@
   return (isa == kArm || isa == kThumb2) ? kArmPointerSize :
          isa == kArm64 ? kArm64PointerSize :
          isa == kMips ? kMipsPointerSize :
+         isa == kMips64 ? kMips64PointerSize :
          isa == kX86 ? kX86PointerSize :
          isa == kX86_64 ? kX86_64PointerSize :
          isa == kNone ? (LOG(FATAL) << "kNone has no pointer size", 0) :
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index fabbbfb..e531091 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -40,6 +40,8 @@
 #include "arch/instruction_set_features.h"
 #include "arch/mips/quick_method_frame_info_mips.h"
 #include "arch/mips/registers_mips.h"
+#include "arch/mips64/quick_method_frame_info_mips64.h"
+#include "arch/mips64/registers_mips64.h"
 #include "arch/x86/quick_method_frame_info_x86.h"
 #include "arch/x86/registers_x86.h"
 #include "arch/x86_64/quick_method_frame_info_x86_64.h"
@@ -1356,6 +1358,11 @@
       CalleeSaveType type = static_cast<CalleeSaveType>(i);
       callee_save_method_frame_infos_[i] = mips::MipsCalleeSaveMethodFrameInfo(type);
     }
+  } else if (instruction_set_ == kMips64) {
+    for (int i = 0; i != kLastCalleeSaveType; ++i) {
+      CalleeSaveType type = static_cast<CalleeSaveType>(i);
+      callee_save_method_frame_infos_[i] = mips64::Mips64CalleeSaveMethodFrameInfo(type);
+    }
   } else if (instruction_set_ == kX86) {
     for (int i = 0; i != kLastCalleeSaveType; ++i) {
       CalleeSaveType type = static_cast<CalleeSaveType>(i);