Fast ART MIPS64 interpreter

Change-Id: I5dda522df0acf9f9df626fe4f5ecfe6c4df600d3
diff --git a/runtime/interpreter/mterp/mips64/alt_stub.S b/runtime/interpreter/mterp/mips64/alt_stub.S
new file mode 100644
index 0000000..bd76a1b
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/alt_stub.S
@@ -0,0 +1,14 @@
+/*
+ * Inter-instruction transfer stub.  Call out to MterpCheckBefore to handle
+ * any interesting requests and then jump to the real instruction
+ * handler.  Note that the call to MterpCheckBefore is done as a tail call.
+ */
+    .extern MterpCheckBefore
+    EXPORT_PC
+    REFRESH_IBASE
+    dla     ra, artMterpAsmInstructionStart
+    dla     t9, MterpCheckBefore
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    daddu   ra, ra, (${opnum} * 128)            # Addr of primary handler.
+    jalr    zero, t9                            # (self, shadow_frame) Note: tail call.
diff --git a/runtime/interpreter/mterp/mips64/bincmp.S b/runtime/interpreter/mterp/mips64/bincmp.S
new file mode 100644
index 0000000..d39c900
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/bincmp.S
@@ -0,0 +1,32 @@
+    /*
+     * Generic two-operand compare-and-branch operation.  Provide a "condition"
+     * fragment that specifies the comparison to perform, e.g. for
+     * "if-le" you would use "le".
+     *
+     * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+     */
+    /* if-cmp vA, vB, +CCCC */
+    lh      a4, 2(rPC)                  # a4 <- sign-extended CCCC
+    ext     a2, rINST, 8, 4             # a2 <- A
+    ext     a3, rINST, 12, 4            # a3 <- B
+    GET_VREG a0, a2                     # a0 <- vA
+    GET_VREG a1, a3                     # a1 <- vB
+
+    b${condition}c a0, a1, 1f
+    li      a4, 2                       # offset if branch not taken
+1:
+
+    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + CCCC * 2
+    FETCH_INST                          # load rINST
+
+#if MTERP_SUSPEND
+    bgez    a4, 2f                      # CCCC * 2 >= 0 => no suspend check
+    REFRESH_IBASE
+2:
+#else
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    bltz    a4, MterpCheckSuspendAndContinue
+#endif
+
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/binop.S b/runtime/interpreter/mterp/mips64/binop.S
new file mode 100644
index 0000000..fab48b7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/binop.S
@@ -0,0 +1,30 @@
+%default {"preinstr":"", "result":"a0", "chkzero":"0"}
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = a0 op a1".
+     * This could be a MIPS instruction or a function call.  (If the result
+     * comes back in a register other than a0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (a1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the CPU handles it
+     * correctly.
+     *
+     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int
+     */
+    /* binop vAA, vBB, vCC */
+    srl     a4, rINST, 8                # a4 <- AA
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    GET_VREG a0, a2                     # a0 <- vBB
+    GET_VREG a1, a3                     # a1 <- vCC
+    .if $chkzero
+    beqz    a1, common_errDivideByZero  # is second operand zero?
+    .endif
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    $preinstr                           # optional op
+    $instr                              # $result <- op, a0-a3 changed
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG $result, a4                # vAA <- $result
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/binop2addr.S b/runtime/interpreter/mterp/mips64/binop2addr.S
new file mode 100644
index 0000000..1ae73f5
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/binop2addr.S
@@ -0,0 +1,30 @@
+%default {"preinstr":"", "result":"a0", "chkzero":"0"}
+    /*
+     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = a0 op a1".
+     * This could be a MIPS instruction or a function call.  (If the result
+     * comes back in a register other than a0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vB (a1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the CPU handles it
+     * correctly.
+     *
+     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr
+     */
+    /* binop/2addr vA, vB */
+    ext     a2, rINST, 8, 4             # a2 <- A
+    ext     a3, rINST, 12, 4            # a3 <- B
+    GET_VREG a0, a2                     # a0 <- vA
+    GET_VREG a1, a3                     # a1 <- vB
+    .if $chkzero
+    beqz    a1, common_errDivideByZero  # is second operand zero?
+    .endif
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    $preinstr                           # optional op
+    $instr                              # $result <- op, a0-a3 changed
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG $result, a2                # vA <- $result
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/binopLit16.S b/runtime/interpreter/mterp/mips64/binopLit16.S
new file mode 100644
index 0000000..9257758
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/binopLit16.S
@@ -0,0 +1,28 @@
+%default {"preinstr":"", "result":"a0", "chkzero":"0"}
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = a0 op a1".
+     * This could be an MIPS instruction or a function call.  (If the result
+     * comes back in a register other than a0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * CCCC (a1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+     *      rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    lh      a1, 2(rPC)                  # a1 <- sign-extended CCCC
+    ext     a2, rINST, 8, 4             # a2 <- A
+    ext     a3, rINST, 12, 4            # a3 <- B
+    GET_VREG a0, a3                     # a0 <- vB
+    .if $chkzero
+    beqz    a1, common_errDivideByZero  # is second operand zero?
+    .endif
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    $preinstr                           # optional op
+    $instr                              # $result <- op, a0-a3 changed
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG $result, a2                # vA <- $result
+    GOTO_OPCODE v0                      # jump to next instruction
+
diff --git a/runtime/interpreter/mterp/mips64/binopLit8.S b/runtime/interpreter/mterp/mips64/binopLit8.S
new file mode 100644
index 0000000..f4a0bba
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/binopLit8.S
@@ -0,0 +1,29 @@
+%default {"preinstr":"", "result":"a0", "chkzero":"0"}
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = a0 op a1".
+     * This could be an MIPS instruction or a function call.  (If the result
+     * comes back in a register other than a0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * CC (a1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+     *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+     *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
+     */
+    /* binop/lit8 vAA, vBB, #+CC */
+    lbu     a3, 2(rPC)                  # a3 <- BB
+    lb      a1, 3(rPC)                  # a1 <- sign-extended CC
+    srl     a2, rINST, 8                # a2 <- AA
+    GET_VREG a0, a3                     # a0 <- vBB
+    .if $chkzero
+    beqz    a1, common_errDivideByZero  # is second operand zero?
+    .endif
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    $preinstr                           # optional op
+    $instr                              # $result <- op, a0-a3 changed
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG $result, a2                # vAA <- $result
+    GOTO_OPCODE v0                      # jump to next instruction
+
diff --git a/runtime/interpreter/mterp/mips64/binopWide.S b/runtime/interpreter/mterp/mips64/binopWide.S
new file mode 100644
index 0000000..732f0d6
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/binopWide.S
@@ -0,0 +1,30 @@
+%default {"preinstr":"", "result":"a0", "chkzero":"0"}
+    /*
+     * Generic 64-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = a0 op a1".
+     * This could be a MIPS instruction or a function call.  (If the result
+     * comes back in a register other than a0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (a1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (LONG_MIN / -1) here, because the CPU handles it
+     * correctly.
+     *
+     * For: add-long, sub-long, mul-long, div-long, rem-long, and-long, or-long,
+     *      xor-long, shl-long, shr-long, ushr-long
+     */
+    /* binop vAA, vBB, vCC */
+    srl     a4, rINST, 8                # a4 <- AA
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    GET_VREG_WIDE a0, a2                # a0 <- vBB
+    GET_VREG_WIDE a1, a3                # a1 <- vCC
+    .if $chkzero
+    beqz    a1, common_errDivideByZero  # is second operand zero?
+    .endif
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    $preinstr                           # optional op
+    $instr                              # $result <- op, a0-a3 changed
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE $result, a4           # vAA <- $result
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/binopWide2addr.S b/runtime/interpreter/mterp/mips64/binopWide2addr.S
new file mode 100644
index 0000000..45d8d82
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/binopWide2addr.S
@@ -0,0 +1,30 @@
+%default {"preinstr":"", "result":"a0", "chkzero":"0"}
+    /*
+     * Generic 64-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = a0 op a1".
+     * This could be a MIPS instruction or a function call.  (If the result
+     * comes back in a register other than a0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vB (a1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (LONG_MIN / -1) here, because the CPU handles it
+     * correctly.
+     *
+     * For: add-long/2addr, sub-long/2addr, mul-long/2addr, div-long/2addr,
+     *      rem-long/2addr, and-long/2addr, or-long/2addr, xor-long/2addr,
+     *      shl-long/2addr, shr-long/2addr, ushr-long/2addr
+     */
+    /* binop/2addr vA, vB */
+    ext     a2, rINST, 8, 4             # a2 <- A
+    ext     a3, rINST, 12, 4            # a3 <- B
+    GET_VREG_WIDE a0, a2                # a0 <- vA
+    GET_VREG_WIDE a1, a3                # a1 <- vB
+    .if $chkzero
+    beqz    a1, common_errDivideByZero  # is second operand zero?
+    .endif
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    $preinstr                           # optional op
+    $instr                              # $result <- op, a0-a3 changed
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE $result, a2           # vA <- $result
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/entry.S b/runtime/interpreter/mterp/mips64/entry.S
new file mode 100644
index 0000000..ae6c26b
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/entry.S
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/*
+ * Interpreter entry point.
+ */
+
+    .set    reorder
+
+    .text
+    .global ExecuteMterpImpl
+    .type   ExecuteMterpImpl, %function
+    .balign 16
+/*
+ * On entry:
+ *  a0  Thread* self
+ *  a1  code_item
+ *  a2  ShadowFrame
+ *  a3  JValue* result_register
+ *
+ */
+ExecuteMterpImpl:
+    .cfi_startproc
+    .cpsetup t9, t8, ExecuteMterpImpl
+
+    .cfi_def_cfa sp, 0
+    daddu   sp, sp, -STACK_SIZE
+    .cfi_adjust_cfa_offset STACK_SIZE
+
+    sd      t8, STACK_OFFSET_GP(sp)
+    .cfi_rel_offset 28, STACK_OFFSET_GP
+    sd      ra, STACK_OFFSET_RA(sp)
+    .cfi_rel_offset 31, STACK_OFFSET_RA
+
+    sd      s0, STACK_OFFSET_S0(sp)
+    .cfi_rel_offset 16, STACK_OFFSET_S0
+    sd      s1, STACK_OFFSET_S1(sp)
+    .cfi_rel_offset 17, STACK_OFFSET_S1
+    sd      s2, STACK_OFFSET_S2(sp)
+    .cfi_rel_offset 18, STACK_OFFSET_S2
+    sd      s3, STACK_OFFSET_S3(sp)
+    .cfi_rel_offset 19, STACK_OFFSET_S3
+    sd      s4, STACK_OFFSET_S4(sp)
+    .cfi_rel_offset 20, STACK_OFFSET_S4
+    sd      s5, STACK_OFFSET_S5(sp)
+    .cfi_rel_offset 21, STACK_OFFSET_S5
+
+    /* Remember the return register */
+    sd      a3, SHADOWFRAME_RESULT_REGISTER_OFFSET(a2)
+
+    /* Remember the code_item */
+    sd      a1, SHADOWFRAME_CODE_ITEM_OFFSET(a2)
+
+    /* set up "named" registers */
+    move    rSELF, a0
+    daddu   rFP, a2, SHADOWFRAME_VREGS_OFFSET
+    lw      v0, SHADOWFRAME_NUMBER_OF_VREGS_OFFSET(a2)
+    dlsa    rREFS, v0, rFP, 2
+    daddu   rPC, a1, CODEITEM_INSNS_OFFSET
+    lw      v0, SHADOWFRAME_DEX_PC_OFFSET(a2)
+    dlsa    rPC, v0, rPC, 1
+    EXPORT_PC
+
+    /* Starting ibase */
+    REFRESH_IBASE
+
+    /* start executing the instruction at rPC */
+    FETCH_INST
+    GET_INST_OPCODE v0
+    GOTO_OPCODE v0
+
+    /* NOTE: no fallthrough */
diff --git a/runtime/interpreter/mterp/mips64/fallback.S b/runtime/interpreter/mterp/mips64/fallback.S
new file mode 100644
index 0000000..560b994
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/fallback.S
@@ -0,0 +1,2 @@
+/* Transfer stub to alternate interpreter */
+    b       MterpFallback
diff --git a/runtime/interpreter/mterp/mips64/fbinop.S b/runtime/interpreter/mterp/mips64/fbinop.S
new file mode 100644
index 0000000..f19dd1c
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/fbinop.S
@@ -0,0 +1,18 @@
+%default {}
+    /*:
+     * Generic 32-bit floating-point operation.
+     *
+     * For: add-float, sub-float, mul-float, div-float.
+     * form: <op> f0, f0, f1
+     */
+    /* binop vAA, vBB, vCC */
+    srl     a4, rINST, 8                # a4 <- AA
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    GET_VREG_FLOAT f0, a2               # f0 <- vBB
+    GET_VREG_FLOAT f1, a3               # f1 <- vCC
+    $instr                              # f0 <- f0 op f1
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_FLOAT f0, a4               # vAA <- f0
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/fbinop2addr.S b/runtime/interpreter/mterp/mips64/fbinop2addr.S
new file mode 100644
index 0000000..2e2cd7e
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/fbinop2addr.S
@@ -0,0 +1,17 @@
+%default {}
+    /*:
+     * Generic 32-bit "/2addr" floating-point operation.
+     *
+     * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr.
+     * form: <op> f0, f0, f1
+     */
+    /* binop/2addr vA, vB */
+    ext     a2, rINST, 8, 4             # a2 <- A
+    ext     a3, rINST, 12, 4            # a3 <- B
+    GET_VREG_FLOAT f0, a2               # f0 <- vA
+    GET_VREG_FLOAT f1, a3               # f1 <- vB
+    $instr                              # f0 <- f0 op f1
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_FLOAT f0, a2               # vA <- f0
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/fbinopWide.S b/runtime/interpreter/mterp/mips64/fbinopWide.S
new file mode 100644
index 0000000..8915c94
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/fbinopWide.S
@@ -0,0 +1,18 @@
+%default {}
+    /*:
+     * Generic 64-bit floating-point operation.
+     *
+     * For: add-double, sub-double, mul-double, div-double.
+     * form: <op> f0, f0, f1
+     */
+    /* binop vAA, vBB, vCC */
+    srl     a4, rINST, 8                # a4 <- AA
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    GET_VREG_DOUBLE f0, a2              # f0 <- vBB
+    GET_VREG_DOUBLE f1, a3              # f1 <- vCC
+    $instr                              # f0 <- f0 op f1
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_DOUBLE f0, a4              # vAA <- f0
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/fbinopWide2addr.S b/runtime/interpreter/mterp/mips64/fbinopWide2addr.S
new file mode 100644
index 0000000..a3f4eaa
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/fbinopWide2addr.S
@@ -0,0 +1,17 @@
+%default {}
+    /*:
+     * Generic 64-bit "/2addr" floating-point operation.
+     *
+     * For: add-double/2addr, sub-double/2addr, mul-double/2addr, div-double/2addr.
+     * form: <op> f0, f0, f1
+     */
+    /* binop/2addr vA, vB */
+    ext     a2, rINST, 8, 4             # a2 <- A
+    ext     a3, rINST, 12, 4            # a3 <- B
+    GET_VREG_DOUBLE f0, a2              # f0 <- vA
+    GET_VREG_DOUBLE f1, a3              # f1 <- vB
+    $instr                              # f0 <- f0 op f1
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_DOUBLE f0, a2              # vA <- f0
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/fcmp.S b/runtime/interpreter/mterp/mips64/fcmp.S
new file mode 100644
index 0000000..2e1a3e4
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/fcmp.S
@@ -0,0 +1,32 @@
+%default {}
+    /*
+     * Compare two floating-point values.  Puts 0, 1, or -1 into the
+     * destination register based on the results of the comparison.
+     *
+     * For: cmpl-float, cmpg-float
+     */
+    /* op vAA, vBB, vCC */
+    srl     a4, rINST, 8                # a4 <- AA
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    GET_VREG_FLOAT f0, a2               # f0 <- vBB
+    GET_VREG_FLOAT f1, a3               # f1 <- vCC
+    cmp.eq.s f2, f0, f1
+    li      a0, 0
+    bc1nez  f2, 1f                      # done if vBB == vCC (ordered)
+    .if $gt_bias
+    cmp.lt.s f2, f0, f1
+    li      a0, -1
+    bc1nez  f2, 1f                      # done if vBB < vCC (ordered)
+    li      a0, 1                       # vBB > vCC or unordered
+    .else
+    cmp.lt.s f2, f1, f0
+    li      a0, 1
+    bc1nez  f2, 1f                      # done if vBB > vCC (ordered)
+    li      a0, -1                      # vBB < vCC or unordered
+    .endif
+1:
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG a0, a4                     # vAA <- a0
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/fcmpWide.S b/runtime/interpreter/mterp/mips64/fcmpWide.S
new file mode 100644
index 0000000..2a3a341
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/fcmpWide.S
@@ -0,0 +1,32 @@
+%default {}
+    /*
+     * Compare two floating-point values.  Puts 0, 1, or -1 into the
+     * destination register based on the results of the comparison.
+     *
+     * For: cmpl-double, cmpg-double
+     */
+    /* op vAA, vBB, vCC */
+    srl     a4, rINST, 8                # a4 <- AA
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    GET_VREG_DOUBLE f0, a2              # f0 <- vBB
+    GET_VREG_DOUBLE f1, a3              # f1 <- vCC
+    cmp.eq.d f2, f0, f1
+    li      a0, 0
+    bc1nez  f2, 1f                      # done if vBB == vCC (ordered)
+    .if $gt_bias
+    cmp.lt.d f2, f0, f1
+    li      a0, -1
+    bc1nez  f2, 1f                      # done if vBB < vCC (ordered)
+    li      a0, 1                       # vBB > vCC or unordered
+    .else
+    cmp.lt.d f2, f1, f0
+    li      a0, 1
+    bc1nez  f2, 1f                      # done if vBB > vCC (ordered)
+    li      a0, -1                      # vBB < vCC or unordered
+    .endif
+1:
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG a0, a4                     # vAA <- a0
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/fcvtFooter.S b/runtime/interpreter/mterp/mips64/fcvtFooter.S
new file mode 100644
index 0000000..06e9507
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/fcvtFooter.S
@@ -0,0 +1,18 @@
+    /*
+     * Stores a specified register containing the result of conversion
+     * from or to a floating-point type and jumps to the next instruction.
+     *
+     * Expects a1 to contain the destination Dalvik register number.
+     * a1 is set up by fcvtHeader.S.
+     *
+     * For: int-to-float, int-to-double, long-to-float, long-to-double,
+     *      float-to-int, float-to-long, float-to-double, double-to-int,
+     *      double-to-long, double-to-float, neg-float, neg-double.
+     *
+     * Note that this file can't be included after a break in other files
+     * and in those files its contents appear as a copy.
+     * See: float-to-int, float-to-long, double-to-int, double-to-long.
+     */
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG$suffix $valreg, a1
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/fcvtHeader.S b/runtime/interpreter/mterp/mips64/fcvtHeader.S
new file mode 100644
index 0000000..8742e42
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/fcvtHeader.S
@@ -0,0 +1,15 @@
+    /*
+     * Loads a specified register from vB. Used primarily for conversions
+     * from or to a floating-point type.
+     *
+     * Sets up a1 = A and a2 = B. a2 is later used by fcvtFooter.S to
+     * store the result in vA and jump to the next instruction.
+     *
+     * For: int-to-float, int-to-double, long-to-float, long-to-double,
+     *      float-to-int, float-to-long, float-to-double, double-to-int,
+     *      double-to-long, double-to-float, neg-float, neg-double.
+     */
+    ext     a1, rINST, 8, 4             # a1 <- A
+    srl     a2, rINST, 12               # a2 <- B
+    GET_VREG$suffix $valreg, a2
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
diff --git a/runtime/interpreter/mterp/mips64/footer.S b/runtime/interpreter/mterp/mips64/footer.S
new file mode 100644
index 0000000..1a2e22b
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/footer.S
@@ -0,0 +1,154 @@
+/*
+ * We've detected a condition that will result in an exception, but the exception
+ * has not yet been thrown.  Just bail out to the reference interpreter to deal with it.
+ * TUNING: for consistency, we may want to just go ahead and handle these here.
+ */
+
+    .extern MterpLogDivideByZeroException
+common_errDivideByZero:
+    EXPORT_PC
+#if MTERP_LOGGING
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    jal     MterpLogDivideByZeroException
+#endif
+    b       MterpCommonFallback
+
+    .extern MterpLogArrayIndexException
+common_errArrayIndex:
+    EXPORT_PC
+#if MTERP_LOGGING
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    jal     MterpLogArrayIndexException
+#endif
+    b       MterpCommonFallback
+
+    .extern MterpLogNullObjectException
+common_errNullObject:
+    EXPORT_PC
+#if MTERP_LOGGING
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    jal     MterpLogNullObjectException
+#endif
+    b       MterpCommonFallback
+
+/*
+ * If we're here, something is out of the ordinary.  If there is a pending
+ * exception, handle it.  Otherwise, roll back and retry with the reference
+ * interpreter.
+ */
+MterpPossibleException:
+    ld      a0, THREAD_EXCEPTION_OFFSET(rSELF)
+    beqzc   a0, MterpFallback                       # If not, fall back to reference interpreter.
+    /* intentional fallthrough - handle pending exception. */
+/*
+ * On return from a runtime helper routine, we've found a pending exception.
+ * Can we handle it here - or need to bail out to caller?
+ *
+ */
+    .extern MterpHandleException
+MterpException:
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    jal     MterpHandleException                    # (self, shadow_frame)
+    beqzc   v0, MterpExceptionReturn                # no local catch, back to caller.
+    ld      a0, OFF_FP_CODE_ITEM(rFP)
+    lwu     a1, OFF_FP_DEX_PC(rFP)
+    REFRESH_IBASE
+    daddu   rPC, a0, CODEITEM_INSNS_OFFSET
+    dlsa    rPC, a1, rPC, 1                         # generate new dex_pc_ptr
+    sd      rPC, OFF_FP_DEX_PC_PTR(rFP)
+    /* resume execution at catch block */
+    FETCH_INST
+    GET_INST_OPCODE v0
+    GOTO_OPCODE v0
+    /* NOTE: no fallthrough */
+
+/*
+ * Check for suspend check request.  Assumes rINST already loaded, rPC advanced and
+ * still needs to get the opcode and branch to it, and flags are in ra.
+ */
+    .extern MterpSuspendCheck
+MterpCheckSuspendAndContinue:
+    REFRESH_IBASE
+    and     ra, ra, (THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    bnez    ra, check1
+    GET_INST_OPCODE v0                              # extract opcode from rINST
+    GOTO_OPCODE v0                                  # jump to next instruction
+check1:
+    EXPORT_PC
+    move    a0, rSELF
+    jal     MterpSuspendCheck                       # (self)
+    GET_INST_OPCODE v0                              # extract opcode from rINST
+    GOTO_OPCODE v0                                  # jump to next instruction
+
+/*
+ * Bail out to reference interpreter.
+ */
+    .extern MterpLogFallback
+MterpFallback:
+    EXPORT_PC
+#if MTERP_LOGGING
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    jal     MterpLogFallback
+#endif
+MterpCommonFallback:
+    li      v0, 0                                   # signal retry with reference interpreter.
+    b       MterpDone
+
+/*
+ * We pushed some registers on the stack in ExecuteMterpImpl, then saved
+ * SP and RA.  Here we restore SP, restore the registers, and then restore
+ * RA to PC.
+ *
+ * On entry:
+ *  uint32_t* rFP  (should still be live, pointer to base of vregs)
+ */
+MterpExceptionReturn:
+    li      v0, 1                                   # signal return to caller.
+    b       MterpDone
+/*
+ * Returned value is expected in a0 and if it's not 64-bit, the 32 most
+ * significant bits of a0 must be 0.
+ */
+MterpReturn:
+    ld      a2, OFF_FP_RESULT_REGISTER(rFP)
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)
+    sd      a0, 0(a2)
+    move    a0, rSELF
+    and     ra, ra, (THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    beqzc   ra, check2
+    jal     MterpSuspendCheck                       # (self)
+check2:
+    li      v0, 1                                   # signal return to caller.
+MterpDone:
+    ld      s5, STACK_OFFSET_S5(sp)
+    .cfi_restore 21
+    ld      s4, STACK_OFFSET_S4(sp)
+    .cfi_restore 20
+    ld      s3, STACK_OFFSET_S3(sp)
+    .cfi_restore 19
+    ld      s2, STACK_OFFSET_S2(sp)
+    .cfi_restore 18
+    ld      s1, STACK_OFFSET_S1(sp)
+    .cfi_restore 17
+    ld      s0, STACK_OFFSET_S0(sp)
+    .cfi_restore 16
+
+    ld      ra, STACK_OFFSET_RA(sp)
+    .cfi_restore 31
+
+    ld      t8, STACK_OFFSET_GP(sp)
+    .cpreturn
+    .cfi_restore 28
+
+    .set    noreorder
+    jr      ra
+    daddu   sp, sp, STACK_SIZE
+    .cfi_adjust_cfa_offset -STACK_SIZE
+
+    .cfi_endproc
+    .size ExecuteMterpImpl, .-ExecuteMterpImpl
diff --git a/runtime/interpreter/mterp/mips64/header.S b/runtime/interpreter/mterp/mips64/header.S
new file mode 100644
index 0000000..4c3ca9e
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/header.S
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2016 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 <machine/regdef.h>
+
+/* TODO: add the missing file and use its FP register definitions. */
+/* #include <machine/fpregdef.h> */
+/* FP register definitions */
+#define f0  $$f0
+#define f1  $$f1
+#define f2  $$f2
+#define f3  $$f3
+#define f12 $$f12
+#define f13 $$f13
+
+/*
+ * It looks like the GNU assembler currently does not support the blec and bgtc
+ * idioms, which should translate into bgec and bltc respectively with swapped
+ * left and right register operands.
+ * TODO: remove these macros when the assembler is fixed.
+ */
+.macro blec lreg, rreg, target
+    bgec    \rreg, \lreg, \target
+.endm
+.macro bgtc lreg, rreg, target
+    bltc    \rreg, \lreg, \target
+.endm
+
+/*
+Mterp and MIPS64 notes:
+
+The following registers have fixed assignments:
+
+  reg nick      purpose
+  s0  rPC       interpreted program counter, used for fetching instructions
+  s1  rFP       interpreted frame pointer, used for accessing locals and args
+  s2  rSELF     self (Thread) pointer
+  s3  rINST     first 16-bit code unit of current instruction
+  s4  rIBASE    interpreted instruction base pointer, used for computed goto
+  s5  rREFS     base of object references in shadow frame  (ideally, we'll get rid of this later).
+*/
+
+/* During bringup, we'll use the shadow frame model instead of rFP */
+/* single-purpose registers, given names for clarity */
+#define rPC     s0
+#define rFP     s1
+#define rSELF   s2
+#define rINST   s3
+#define rIBASE  s4
+#define rREFS   s5
+
+/*
+ * This is a #include, not a %include, because we want the C pre-processor
+ * to expand the macros into assembler assignment statements.
+ */
+#include "asm_support.h"
+
+/*
+ * Instead of holding a pointer to the shadow frame, we keep rFP at the base of the vregs.  So,
+ * to access other shadow frame fields, we need to use a backwards offset.  Define those here.
+ */
+#define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET)
+#define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET)
+#define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET)
+#define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET)
+#define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
+#define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
+#define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
+#define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
+#define OFF_FP_SHADOWFRAME (-SHADOWFRAME_VREGS_OFFSET)
+
+/*
+ *
+ * The reference interpreter performs explicit suspect checks, which is somewhat wasteful.
+ * Dalvik's interpreter folded suspend checks into the jump table mechanism, and eventually
+ * mterp should do so as well.
+ */
+#define MTERP_SUSPEND 0
+
+#define MTERP_LOGGING 0
+
+/*
+ * "export" the PC to dex_pc field in the shadow frame, f/b/o future exception objects.  Must
+ * be done *before* something throws.
+ *
+ * It's okay to do this more than once.
+ *
+ * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped
+ * dex byte codes.  However, the rest of the runtime expects dex pc to be an instruction
+ * offset into the code_items_[] array.  For effiency, we will "export" the
+ * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC
+ * to convert to a dex pc when needed.
+ */
+.macro EXPORT_PC
+    sd      rPC, OFF_FP_DEX_PC_PTR(rFP)
+.endm
+
+/*
+ * Refresh handler table.
+ */
+.macro REFRESH_IBASE
+    ld      rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF)
+.endm
+
+/*
+ * Fetch the next instruction from rPC into rINST.  Does not advance rPC.
+ */
+.macro FETCH_INST
+    lhu     rINST, 0(rPC)
+.endm
+
+/* Advance rPC by some number of code units. */
+.macro ADVANCE count
+    daddu   rPC, rPC, (\count) * 2
+.endm
+
+/*
+ * Fetch the next instruction from the specified offset.  Advances rPC
+ * to point to the next instruction.
+ *
+ * This must come AFTER anything that can throw an exception, or the
+ * exception catch may miss.  (This also implies that it must come after
+ * EXPORT_PC.)
+ */
+.macro FETCH_ADVANCE_INST count
+    ADVANCE \count
+    FETCH_INST
+.endm
+
+/*
+ * Similar to FETCH_ADVANCE_INST, but does not update rPC.  Used to load
+ * rINST ahead of possible exception point.  Be sure to manually advance rPC
+ * later.
+ */
+.macro PREFETCH_INST count
+    lhu     rINST, ((\count) * 2)(rPC)
+.endm
+
+/*
+ * Put the instruction's opcode field into the specified register.
+ */
+.macro GET_INST_OPCODE reg
+    and     \reg, rINST, 255
+.endm
+
+/*
+ * Begin executing the opcode in _reg.
+ */
+.macro GOTO_OPCODE reg
+    .set noat
+    sll     AT, \reg, 7
+    daddu   AT, rIBASE, AT
+    jic     AT, 0
+    .set at
+.endm
+
+/*
+ * Get/set the 32-bit value from a Dalvik register.
+ * Note, GET_VREG does sign extension to 64 bits while
+ * GET_VREG_U does zero extension to 64 bits.
+ * One is useful for arithmetic while the other is
+ * useful for storing the result value as 64-bit.
+ */
+.macro GET_VREG reg, vreg
+    .set noat
+    dlsa    AT, \vreg, rFP, 2
+    lw      \reg, 0(AT)
+    .set at
+.endm
+.macro GET_VREG_U reg, vreg
+    .set noat
+    dlsa    AT, \vreg, rFP, 2
+    lwu     \reg, 0(AT)
+    .set at
+.endm
+.macro GET_VREG_FLOAT reg, vreg
+    .set noat
+    dlsa    AT, \vreg, rFP, 2
+    lwc1    \reg, 0(AT)
+    .set at
+.endm
+.macro SET_VREG reg, vreg
+    .set noat
+    dlsa    AT, \vreg, rFP, 2
+    sw      \reg, 0(AT)
+    dlsa    AT, \vreg, rREFS, 2
+    sw      zero, 0(AT)
+    .set at
+.endm
+.macro SET_VREG_OBJECT reg, vreg
+    .set noat
+    dlsa    AT, \vreg, rFP, 2
+    sw      \reg, 0(AT)
+    dlsa    AT, \vreg, rREFS, 2
+    sw      \reg, 0(AT)
+    .set at
+.endm
+.macro SET_VREG_FLOAT reg, vreg
+    .set noat
+    dlsa    AT, \vreg, rFP, 2
+    swc1    \reg, 0(AT)
+    dlsa    AT, \vreg, rREFS, 2
+    sw      zero, 0(AT)
+    .set at
+.endm
+
+/*
+ * Get/set the 64-bit value from a Dalvik register.
+ * Avoid unaligned memory accesses.
+ * Note, SET_VREG_WIDE clobbers the register containing the value being stored.
+ * Note, SET_VREG_DOUBLE clobbers the register containing the Dalvik register number.
+ */
+.macro GET_VREG_WIDE reg, vreg
+    .set noat
+    dlsa    AT, \vreg, rFP, 2
+    lw      \reg, 0(AT)
+    lw      AT, 4(AT)
+    dinsu   \reg, AT, 32, 32
+    .set at
+.endm
+.macro GET_VREG_DOUBLE reg, vreg
+    .set noat
+    dlsa    AT, \vreg, rFP, 2
+    lwc1    \reg, 0(AT)
+    lw      AT, 4(AT)
+    mthc1   AT, \reg
+    .set at
+.endm
+.macro SET_VREG_WIDE reg, vreg
+    .set noat
+    dlsa    AT, \vreg, rFP, 2
+    sw      \reg, 0(AT)
+    drotr32 \reg, \reg, 0
+    sw      \reg, 4(AT)
+    dlsa    AT, \vreg, rREFS, 2
+    sw      zero, 0(AT)
+    sw      zero, 4(AT)
+    .set at
+.endm
+.macro SET_VREG_DOUBLE reg, vreg
+    .set noat
+    dlsa    AT, \vreg, rREFS, 2
+    sw      zero, 0(AT)
+    sw      zero, 4(AT)
+    dlsa    AT, \vreg, rFP, 2
+    swc1    \reg, 0(AT)
+    mfhc1   \vreg, \reg
+    sw      \vreg, 4(AT)
+    .set at
+.endm
+
+/*
+ * On-stack offsets for spilling/unspilling callee-saved registers
+ * and the frame size.
+ */
+#define STACK_OFFSET_RA 0
+#define STACK_OFFSET_GP 8
+#define STACK_OFFSET_S0 16
+#define STACK_OFFSET_S1 24
+#define STACK_OFFSET_S2 32
+#define STACK_OFFSET_S3 40
+#define STACK_OFFSET_S4 48
+#define STACK_OFFSET_S5 56
+#define STACK_SIZE      64
+
+/* Constants for float/double_to_int/long conversions */
+#define INT_MIN             0x80000000
+#define INT_MIN_AS_FLOAT    0xCF000000
+#define INT_MIN_AS_DOUBLE   0xC1E0000000000000
+#define LONG_MIN            0x8000000000000000
+#define LONG_MIN_AS_FLOAT   0xDF000000
+#define LONG_MIN_AS_DOUBLE  0xC3E0000000000000
diff --git a/runtime/interpreter/mterp/mips64/invoke.S b/runtime/interpreter/mterp/mips64/invoke.S
new file mode 100644
index 0000000..4ae4fb1
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/invoke.S
@@ -0,0 +1,17 @@
+%default { "helper":"UndefinedInvokeHandler" }
+    /*
+     * Generic invoke handler wrapper.
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    .extern $helper
+    EXPORT_PC
+    move    a0, rSELF
+    daddu   a1, rFP, OFF_FP_SHADOWFRAME
+    move    a2, rPC
+    move    a3, rINST
+    jal     $helper
+    beqzc   v0, MterpException
+    FETCH_ADVANCE_INST 3
+    GET_INST_OPCODE v0
+    GOTO_OPCODE v0
diff --git a/runtime/interpreter/mterp/mips64/op_add_double.S b/runtime/interpreter/mterp/mips64/op_add_double.S
new file mode 100644
index 0000000..1520e32
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_add_double.S
@@ -0,0 +1 @@
+%include "mips64/fbinopWide.S" {"instr":"add.d f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_add_double_2addr.S b/runtime/interpreter/mterp/mips64/op_add_double_2addr.S
new file mode 100644
index 0000000..c14382e
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_add_double_2addr.S
@@ -0,0 +1 @@
+%include "mips64/fbinopWide2addr.S" {"instr":"add.d f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_add_float.S b/runtime/interpreter/mterp/mips64/op_add_float.S
new file mode 100644
index 0000000..c6ed558
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_add_float.S
@@ -0,0 +1 @@
+%include "mips64/fbinop.S" {"instr":"add.s f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_add_float_2addr.S b/runtime/interpreter/mterp/mips64/op_add_float_2addr.S
new file mode 100644
index 0000000..4c20547
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_add_float_2addr.S
@@ -0,0 +1 @@
+%include "mips64/fbinop2addr.S" {"instr":"add.s f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_add_int.S b/runtime/interpreter/mterp/mips64/op_add_int.S
new file mode 100644
index 0000000..6e569de
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_add_int.S
@@ -0,0 +1 @@
+%include "mips64/binop.S" {"instr":"addu a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_add_int_2addr.S b/runtime/interpreter/mterp/mips64/op_add_int_2addr.S
new file mode 100644
index 0000000..2a84124
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_add_int_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binop2addr.S" {"instr":"addu a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_add_int_lit16.S b/runtime/interpreter/mterp/mips64/op_add_int_lit16.S
new file mode 100644
index 0000000..94b053b
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_add_int_lit16.S
@@ -0,0 +1 @@
+%include "mips64/binopLit16.S" {"instr":"addu a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_add_int_lit8.S b/runtime/interpreter/mterp/mips64/op_add_int_lit8.S
new file mode 100644
index 0000000..3b6d734
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_add_int_lit8.S
@@ -0,0 +1 @@
+%include "mips64/binopLit8.S" {"instr":"addu a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_add_long.S b/runtime/interpreter/mterp/mips64/op_add_long.S
new file mode 100644
index 0000000..c8d702f
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_add_long.S
@@ -0,0 +1 @@
+%include "mips64/binopWide.S" {"instr":"daddu a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_add_long_2addr.S b/runtime/interpreter/mterp/mips64/op_add_long_2addr.S
new file mode 100644
index 0000000..928ff54
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_add_long_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binopWide2addr.S" {"instr":"daddu a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_aget.S b/runtime/interpreter/mterp/mips64/op_aget.S
new file mode 100644
index 0000000..0472a06
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aget.S
@@ -0,0 +1,29 @@
+%default { "load":"lw", "shift":"2", "data_offset":"MIRROR_INT_ARRAY_DATA_OFFSET" }
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * for: aget, aget-boolean, aget-byte, aget-char, aget-short
+     *
+     * NOTE: assumes data offset for arrays is the same for all non-wide types.
+     * If this changes, specialize.
+     */
+    /* op vAA, vBB, vCC */
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    srl     a4, rINST, 8                # a4 <- AA
+    GET_VREG_U a0, a2                   # a0 <- vBB (array object)
+    GET_VREG a1, a3                     # a1 <- vCC (requested index)
+    beqz    a0, common_errNullObject    # bail if null array object
+    lw      a3, MIRROR_ARRAY_LENGTH_OFFSET(a0)  # a3 <- arrayObj->length
+    .if $shift
+    # [d]lsa does not support shift count of 0.
+    dlsa    a0, a1, a0, $shift          # a0 <- arrayObj + index*width
+    .else
+    daddu   a0, a1, a0                  # a0 <- arrayObj + index*width
+    .endif
+    bgeu    a1, a3, common_errArrayIndex  # unsigned compare: index >= length, bail
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    $load   a2, $data_offset(a0)        # a2 <- vBB[vCC]
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG a2, a4                     # vAA <- a2
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_aget_boolean.S b/runtime/interpreter/mterp/mips64/op_aget_boolean.S
new file mode 100644
index 0000000..d5be01b
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aget_boolean.S
@@ -0,0 +1 @@
+%include "mips64/op_aget.S" { "load":"lbu", "shift":"0", "data_offset":"MIRROR_BOOLEAN_ARRAY_DATA_OFFSET" }
diff --git a/runtime/interpreter/mterp/mips64/op_aget_byte.S b/runtime/interpreter/mterp/mips64/op_aget_byte.S
new file mode 100644
index 0000000..084de8d
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aget_byte.S
@@ -0,0 +1 @@
+%include "mips64/op_aget.S" { "load":"lb", "shift":"0", "data_offset":"MIRROR_BYTE_ARRAY_DATA_OFFSET" }
diff --git a/runtime/interpreter/mterp/mips64/op_aget_char.S b/runtime/interpreter/mterp/mips64/op_aget_char.S
new file mode 100644
index 0000000..6c99ed5
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aget_char.S
@@ -0,0 +1 @@
+%include "mips64/op_aget.S" { "load":"lhu", "shift":"1", "data_offset":"MIRROR_CHAR_ARRAY_DATA_OFFSET" }
diff --git a/runtime/interpreter/mterp/mips64/op_aget_object.S b/runtime/interpreter/mterp/mips64/op_aget_object.S
new file mode 100644
index 0000000..6374a05
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aget_object.S
@@ -0,0 +1,21 @@
+    /*
+     * Array object get.  vAA <- vBB[vCC].
+     *
+     * for: aget-object
+     */
+    /* op vAA, vBB, vCC */
+    .extern artAGetObjectFromMterp
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    EXPORT_PC
+    GET_VREG_U a0, a2                   # a0 <- vBB (array object)
+    GET_VREG a1, a3                     # a1 <- vCC (requested index)
+    jal     artAGetObjectFromMterp      # (array, index)
+    ld      a1, THREAD_EXCEPTION_OFFSET(rSELF)
+    srl     a4, rINST, 8                # a4 <- AA
+    PREFETCH_INST 2
+    bnez    a1, MterpException
+    SET_VREG_OBJECT v0, a4              # vAA <- v0
+    ADVANCE 2
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_aget_short.S b/runtime/interpreter/mterp/mips64/op_aget_short.S
new file mode 100644
index 0000000..0158b0a
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aget_short.S
@@ -0,0 +1 @@
+%include "mips64/op_aget.S" { "load":"lh", "shift":"1", "data_offset":"MIRROR_SHORT_ARRAY_DATA_OFFSET" }
diff --git a/runtime/interpreter/mterp/mips64/op_aget_wide.S b/runtime/interpreter/mterp/mips64/op_aget_wide.S
new file mode 100644
index 0000000..0945aca
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aget_wide.S
@@ -0,0 +1,21 @@
+    /*
+     * Array get, 64 bits.  vAA <- vBB[vCC].
+     *
+     */
+    /* aget-wide vAA, vBB, vCC */
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    srl     a4, rINST, 8                # a4 <- AA
+    GET_VREG_U a0, a2                   # a0 <- vBB (array object)
+    GET_VREG a1, a3                     # a1 <- vCC (requested index)
+    beqz    a0, common_errNullObject    # bail if null array object
+    lw      a3, MIRROR_ARRAY_LENGTH_OFFSET(a0)  # a3 <- arrayObj->length
+    dlsa    a0, a1, a0, 3               # a0 <- arrayObj + index*width
+    bgeu    a1, a3, common_errArrayIndex  # unsigned compare: index >= length, bail
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    lw      a2, MIRROR_WIDE_ARRAY_DATA_OFFSET(a0)
+    lw      a3, (MIRROR_WIDE_ARRAY_DATA_OFFSET+4)(a0)
+    dinsu   a2, a3, 32, 32              # a2 <- vBB[vCC]
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE a2, a4                # vAA <- a2
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_and_int.S b/runtime/interpreter/mterp/mips64/op_and_int.S
new file mode 100644
index 0000000..f0792a8
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_and_int.S
@@ -0,0 +1 @@
+%include "mips64/binop.S" {"instr":"and a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_and_int_2addr.S b/runtime/interpreter/mterp/mips64/op_and_int_2addr.S
new file mode 100644
index 0000000..08dc615
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_and_int_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binop2addr.S" {"instr":"and a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_and_int_lit16.S b/runtime/interpreter/mterp/mips64/op_and_int_lit16.S
new file mode 100644
index 0000000..65d28ad
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_and_int_lit16.S
@@ -0,0 +1 @@
+%include "mips64/binopLit16.S" {"instr":"and a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_and_int_lit8.S b/runtime/interpreter/mterp/mips64/op_and_int_lit8.S
new file mode 100644
index 0000000..ab84bb7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_and_int_lit8.S
@@ -0,0 +1 @@
+%include "mips64/binopLit8.S" {"instr":"and a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_and_long.S b/runtime/interpreter/mterp/mips64/op_and_long.S
new file mode 100644
index 0000000..e383ba0
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_and_long.S
@@ -0,0 +1 @@
+%include "mips64/binopWide.S" {"instr":"and a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_and_long_2addr.S b/runtime/interpreter/mterp/mips64/op_and_long_2addr.S
new file mode 100644
index 0000000..f863bb9
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_and_long_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binopWide2addr.S" {"instr":"and a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_aput.S b/runtime/interpreter/mterp/mips64/op_aput.S
new file mode 100644
index 0000000..9bfda97
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aput.S
@@ -0,0 +1,29 @@
+%default { "store":"sw", "shift":"2", "data_offset":"MIRROR_INT_ARRAY_DATA_OFFSET" }
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA.
+     *
+     * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+     *
+     * NOTE: this assumes data offset for arrays is the same for all non-wide types.
+     * If this changes, specialize.
+     */
+    /* op vAA, vBB, vCC */
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    srl     a4, rINST, 8                # a4 <- AA
+    GET_VREG_U a0, a2                   # a0 <- vBB (array object)
+    GET_VREG a1, a3                     # a1 <- vCC (requested index)
+    beqz    a0, common_errNullObject    # bail if null array object
+    lw      a3, MIRROR_ARRAY_LENGTH_OFFSET(a0)  # a3 <- arrayObj->length
+    .if $shift
+    # [d]lsa does not support shift count of 0.
+    dlsa    a0, a1, a0, $shift          # a0 <- arrayObj + index*width
+    .else
+    daddu   a0, a1, a0                  # a0 <- arrayObj + index*width
+    .endif
+    bgeu    a1, a3, common_errArrayIndex  # unsigned compare: index >= length, bail
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_VREG a2, a4                     # a2 <- vAA
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    $store  a2, $data_offset(a0)        # vBB[vCC] <- a2
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_aput_boolean.S b/runtime/interpreter/mterp/mips64/op_aput_boolean.S
new file mode 100644
index 0000000..6707a1f
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aput_boolean.S
@@ -0,0 +1 @@
+%include "mips64/op_aput.S" { "store":"sb", "shift":"0", "data_offset":"MIRROR_BOOLEAN_ARRAY_DATA_OFFSET" }
diff --git a/runtime/interpreter/mterp/mips64/op_aput_byte.S b/runtime/interpreter/mterp/mips64/op_aput_byte.S
new file mode 100644
index 0000000..7b9ce48
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aput_byte.S
@@ -0,0 +1 @@
+%include "mips64/op_aput.S" { "store":"sb", "shift":"0", "data_offset":"MIRROR_BYTE_ARRAY_DATA_OFFSET" }
diff --git a/runtime/interpreter/mterp/mips64/op_aput_char.S b/runtime/interpreter/mterp/mips64/op_aput_char.S
new file mode 100644
index 0000000..82bc8f7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aput_char.S
@@ -0,0 +1 @@
+%include "mips64/op_aput.S" { "store":"sh", "shift":"1", "data_offset":"MIRROR_CHAR_ARRAY_DATA_OFFSET" }
diff --git a/runtime/interpreter/mterp/mips64/op_aput_object.S b/runtime/interpreter/mterp/mips64/op_aput_object.S
new file mode 100644
index 0000000..b132456
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aput_object.S
@@ -0,0 +1,14 @@
+    /*
+     * Store an object into an array.  vBB[vCC] <- vAA.
+     */
+    /* op vAA, vBB, vCC */
+    .extern MterpAputObject
+    EXPORT_PC
+    daddu   a0, rFP, OFF_FP_SHADOWFRAME
+    move    a1, rPC
+    move    a2, rINST
+    jal     MterpAputObject
+    beqzc   v0, MterpPossibleException
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_aput_short.S b/runtime/interpreter/mterp/mips64/op_aput_short.S
new file mode 100644
index 0000000..a7af294
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aput_short.S
@@ -0,0 +1 @@
+%include "mips64/op_aput.S" { "store":"sh", "shift":"1", "data_offset":"MIRROR_SHORT_ARRAY_DATA_OFFSET" }
diff --git a/runtime/interpreter/mterp/mips64/op_aput_wide.S b/runtime/interpreter/mterp/mips64/op_aput_wide.S
new file mode 100644
index 0000000..a1d7a3b
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_aput_wide.S
@@ -0,0 +1,21 @@
+    /*
+     * Array put, 64 bits.  vBB[vCC] <- vAA.
+     *
+     */
+    /* aput-wide vAA, vBB, vCC */
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    srl     a4, rINST, 8                # a4 <- AA
+    GET_VREG_U a0, a2                   # a0 <- vBB (array object)
+    GET_VREG a1, a3                     # a1 <- vCC (requested index)
+    beqz    a0, common_errNullObject    # bail if null array object
+    lw      a3, MIRROR_ARRAY_LENGTH_OFFSET(a0)  # a3 <- arrayObj->length
+    dlsa    a0, a1, a0, 3               # a0 <- arrayObj + index*width
+    bgeu    a1, a3, common_errArrayIndex  # unsigned compare: index >= length, bail
+    GET_VREG_WIDE a2, a4                # a2 <- vAA
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    sw      a2, MIRROR_WIDE_ARRAY_DATA_OFFSET(a0)
+    dsrl32  a2, a2, 0
+    sw      a2, (MIRROR_WIDE_ARRAY_DATA_OFFSET+4)(a0)  # vBB[vCC] <- a2
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_array_length.S b/runtime/interpreter/mterp/mips64/op_array_length.S
new file mode 100644
index 0000000..2d9e172
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_array_length.S
@@ -0,0 +1,12 @@
+    /*
+     * Return the length of an array.
+     */
+    srl     a1, rINST, 12               # a1 <- B
+    GET_VREG_U a0, a1                   # a0 <- vB (object ref)
+    ext     a2, rINST, 8, 4             # a2 <- A
+    beqz    a0, common_errNullObject    # yup, fail
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    lw      a3, MIRROR_ARRAY_LENGTH_OFFSET(a0)  # a3 <- array length
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG a3, a2                     # vB <- length
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_check_cast.S b/runtime/interpreter/mterp/mips64/op_check_cast.S
new file mode 100644
index 0000000..472595d
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_check_cast.S
@@ -0,0 +1,17 @@
+    /*
+     * Check to see if a cast from one class to another is allowed.
+     */
+    /* check-cast vAA, class//BBBB */
+    .extern MterpCheckCast
+    EXPORT_PC
+    lhu     a0, 2(rPC)                  # a0 <- BBBB
+    srl     a1, rINST, 8                # a1 <- AA
+    dlsa    a1, a1, rFP, 2              # a1 <- &object
+    ld      a2, OFF_FP_METHOD(rFP)      # a2 <- method
+    move    a3, rSELF                   # a3 <- self
+    jal     MterpCheckCast              # (index, &obj, method, self)
+    PREFETCH_INST 2
+    bnez    v0, MterpPossibleException
+    ADVANCE 2
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_cmp_long.S b/runtime/interpreter/mterp/mips64/op_cmp_long.S
new file mode 100644
index 0000000..6e9376c
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_cmp_long.S
@@ -0,0 +1,13 @@
+    /* cmp-long vAA, vBB, vCC */
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    srl     a4, rINST, 8                # a4 <- AA
+    GET_VREG_WIDE a0, a2                # a0 <- vBB
+    GET_VREG_WIDE a1, a3                # a1 <- vCC
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    slt     a2, a0, a1
+    slt     a0, a1, a0
+    subu    a0, a0, a2
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG a0, a4                     # vAA <- result
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_cmpg_double.S b/runtime/interpreter/mterp/mips64/op_cmpg_double.S
new file mode 100644
index 0000000..a8e2ef9
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_cmpg_double.S
@@ -0,0 +1 @@
+%include "mips64/fcmpWide.S" {"gt_bias":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_cmpg_float.S b/runtime/interpreter/mterp/mips64/op_cmpg_float.S
new file mode 100644
index 0000000..0c93eac
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_cmpg_float.S
@@ -0,0 +1 @@
+%include "mips64/fcmp.S" {"gt_bias":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_cmpl_double.S b/runtime/interpreter/mterp/mips64/op_cmpl_double.S
new file mode 100644
index 0000000..9111b06
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_cmpl_double.S
@@ -0,0 +1 @@
+%include "mips64/fcmpWide.S" {"gt_bias":"0"}
diff --git a/runtime/interpreter/mterp/mips64/op_cmpl_float.S b/runtime/interpreter/mterp/mips64/op_cmpl_float.S
new file mode 100644
index 0000000..b047451
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_cmpl_float.S
@@ -0,0 +1 @@
+%include "mips64/fcmp.S" {"gt_bias":"0"}
diff --git a/runtime/interpreter/mterp/mips64/op_const.S b/runtime/interpreter/mterp/mips64/op_const.S
new file mode 100644
index 0000000..4b0d69b
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_const.S
@@ -0,0 +1,9 @@
+    /* const vAA, #+BBBBbbbb */
+    srl     a2, rINST, 8                # a2 <- AA
+    lh      a0, 2(rPC)                  # a0 <- bbbb (low)
+    lh      a1, 4(rPC)                  # a1 <- BBBB (high)
+    FETCH_ADVANCE_INST 3                # advance rPC, load rINST
+    ins     a0, a1, 16, 16              # a0 = BBBBbbbb
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG a0, a2                     # vAA <- +BBBBbbbb
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_const_16.S b/runtime/interpreter/mterp/mips64/op_const_16.S
new file mode 100644
index 0000000..51e68a7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_const_16.S
@@ -0,0 +1,7 @@
+    /* const/16 vAA, #+BBBB */
+    srl     a2, rINST, 8                # a2 <- AA
+    lh      a0, 2(rPC)                  # a0 <- sign-extended BBBB
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG a0, a2                     # vAA <- +BBBB
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_const_4.S b/runtime/interpreter/mterp/mips64/op_const_4.S
new file mode 100644
index 0000000..0a58bff
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_const_4.S
@@ -0,0 +1,8 @@
+    /* const/4 vA, #+B */
+    ext     a2, rINST, 8, 4             # a2 <- A
+    seh     a0, rINST                   # sign extend B in rINST
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    sra     a0, a0, 12                  # shift B into its final position
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG a0, a2                     # vA <- +B
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_const_class.S b/runtime/interpreter/mterp/mips64/op_const_class.S
new file mode 100644
index 0000000..adf79df
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_const_class.S
@@ -0,0 +1,13 @@
+    /* const/class vAA, Class//BBBB */
+    .extern MterpConstClass
+    EXPORT_PC
+    lhu     a0, 2(rPC)                  # a0 <- BBBB
+    srl     a1, rINST, 8                # a1 <- AA
+    daddu   a2, rFP, OFF_FP_SHADOWFRAME
+    move    a3, rSELF
+    jal     MterpConstClass             # (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 2                     # load rINST
+    bnez    v0, MterpPossibleException  # let reference interpreter deal with it.
+    ADVANCE 2                           # advance rPC
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_const_high16.S b/runtime/interpreter/mterp/mips64/op_const_high16.S
new file mode 100644
index 0000000..43effb6
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_const_high16.S
@@ -0,0 +1,8 @@
+    /* const/high16 vAA, #+BBBB0000 */
+    srl     a2, rINST, 8                # a2 <- AA
+    lh      a0, 2(rPC)                  # a0 <- BBBB
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    sll     a0, a0, 16                  # a0 <- BBBB0000
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG a0, a2                     # vAA <- +BBBB0000
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_const_string.S b/runtime/interpreter/mterp/mips64/op_const_string.S
new file mode 100644
index 0000000..4684c11
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_const_string.S
@@ -0,0 +1,13 @@
+    /* const/string vAA, String//BBBB */
+    .extern MterpConstString
+    EXPORT_PC
+    lhu     a0, 2(rPC)                  # a0 <- BBBB
+    srl     a1, rINST, 8                # a1 <- AA
+    daddu   a2, rFP, OFF_FP_SHADOWFRAME
+    move    a3, rSELF
+    jal     MterpConstString            # (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 2                     # load rINST
+    bnez    v0, MterpPossibleException  # let reference interpreter deal with it.
+    ADVANCE 2                           # advance rPC
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_const_string_jumbo.S b/runtime/interpreter/mterp/mips64/op_const_string_jumbo.S
new file mode 100644
index 0000000..47f2101
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_const_string_jumbo.S
@@ -0,0 +1,15 @@
+    /* const/string vAA, String//BBBBBBBB */
+    .extern MterpConstString
+    EXPORT_PC
+    lh      a0, 2(rPC)                  # a0 <- bbbb (low)
+    lh      a4, 4(rPC)                  # a4 <- BBBB (high)
+    srl     a1, rINST, 8                # a1 <- AA
+    ins     a0, a4, 16, 16              # a0 <- BBBBbbbb
+    daddu   a2, rFP, OFF_FP_SHADOWFRAME
+    move    a3, rSELF
+    jal     MterpConstString            # (index, tgt_reg, shadow_frame, self)
+    PREFETCH_INST 3                     # load rINST
+    bnez    v0, MterpPossibleException  # let reference interpreter deal with it.
+    ADVANCE 3                           # advance rPC
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_const_wide.S b/runtime/interpreter/mterp/mips64/op_const_wide.S
new file mode 100644
index 0000000..f7eaf7c
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_const_wide.S
@@ -0,0 +1,13 @@
+    /* const-wide vAA, #+HHHHhhhhBBBBbbbb */
+    srl     a4, rINST, 8                # a4 <- AA
+    lh      a0, 2(rPC)                  # a0 <- bbbb (low)
+    lh      a1, 4(rPC)                  # a1 <- BBBB (low middle)
+    lh      a2, 6(rPC)                  # a2 <- hhhh (high middle)
+    lh      a3, 8(rPC)                  # a3 <- HHHH (high)
+    FETCH_ADVANCE_INST 5                # advance rPC, load rINST
+    ins     a0, a1, 16, 16              # a0 = BBBBbbbb
+    ins     a2, a3, 16, 16              # a2 = HHHHhhhh
+    dinsu   a0, a2, 32, 32              # a0 = HHHHhhhhBBBBbbbb
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE a0, a4                # vAA <- +HHHHhhhhBBBBbbbb
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_const_wide_16.S b/runtime/interpreter/mterp/mips64/op_const_wide_16.S
new file mode 100644
index 0000000..3a70937
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_const_wide_16.S
@@ -0,0 +1,7 @@
+    /* const-wide/16 vAA, #+BBBB */
+    srl     a2, rINST, 8                # a2 <- AA
+    lh      a0, 2(rPC)                  # a0 <- sign-extended BBBB
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE a0, a2                # vAA <- +BBBB
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_const_wide_32.S b/runtime/interpreter/mterp/mips64/op_const_wide_32.S
new file mode 100644
index 0000000..867197c
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_const_wide_32.S
@@ -0,0 +1,9 @@
+    /* const-wide/32 vAA, #+BBBBbbbb */
+    srl     a2, rINST, 8                # a2 <- AA
+    lh      a0, 2(rPC)                  # a0 <- bbbb (low)
+    lh      a1, 4(rPC)                  # a1 <- BBBB (high)
+    FETCH_ADVANCE_INST 3                # advance rPC, load rINST
+    ins     a0, a1, 16, 16              # a0 = BBBBbbbb
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE a0, a2                # vAA <- +BBBBbbbb
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_const_wide_high16.S b/runtime/interpreter/mterp/mips64/op_const_wide_high16.S
new file mode 100644
index 0000000..d741631
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_const_wide_high16.S
@@ -0,0 +1,8 @@
+    /* const-wide/high16 vAA, #+BBBB000000000000 */
+    srl     a2, rINST, 8                # a2 <- AA
+    lh      a0, 2(rPC)                  # a0 <- BBBB
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    dsll32  a0, a0, 16                  # a0 <- BBBB000000000000
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE a0, a2                # vAA <- +BBBB000000000000
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_div_double.S b/runtime/interpreter/mterp/mips64/op_div_double.S
new file mode 100644
index 0000000..44998f0
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_div_double.S
@@ -0,0 +1 @@
+%include "mips64/fbinopWide.S" {"instr":"div.d f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_div_double_2addr.S b/runtime/interpreter/mterp/mips64/op_div_double_2addr.S
new file mode 100644
index 0000000..396af79
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_div_double_2addr.S
@@ -0,0 +1 @@
+%include "mips64/fbinopWide2addr.S" {"instr":"div.d f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_div_float.S b/runtime/interpreter/mterp/mips64/op_div_float.S
new file mode 100644
index 0000000..7b09d52
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_div_float.S
@@ -0,0 +1 @@
+%include "mips64/fbinop.S" {"instr":"div.s f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_div_float_2addr.S b/runtime/interpreter/mterp/mips64/op_div_float_2addr.S
new file mode 100644
index 0000000..e74fdda
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_div_float_2addr.S
@@ -0,0 +1 @@
+%include "mips64/fbinop2addr.S" {"instr":"div.s f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_div_int.S b/runtime/interpreter/mterp/mips64/op_div_int.S
new file mode 100644
index 0000000..fb04acb
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_div_int.S
@@ -0,0 +1 @@
+%include "mips64/binop.S" {"instr":"div a0, a0, a1", "chkzero":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_div_int_2addr.S b/runtime/interpreter/mterp/mips64/op_div_int_2addr.S
new file mode 100644
index 0000000..db29b84
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_div_int_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binop2addr.S" {"instr":"div a0, a0, a1", "chkzero":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_div_int_lit16.S b/runtime/interpreter/mterp/mips64/op_div_int_lit16.S
new file mode 100644
index 0000000..e903dde
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_div_int_lit16.S
@@ -0,0 +1 @@
+%include "mips64/binopLit16.S" {"instr":"div a0, a0, a1", "chkzero":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_div_int_lit8.S b/runtime/interpreter/mterp/mips64/op_div_int_lit8.S
new file mode 100644
index 0000000..0559605
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_div_int_lit8.S
@@ -0,0 +1 @@
+%include "mips64/binopLit8.S" {"instr":"div a0, a0, a1", "chkzero":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_div_long.S b/runtime/interpreter/mterp/mips64/op_div_long.S
new file mode 100644
index 0000000..01fc2b2
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_div_long.S
@@ -0,0 +1 @@
+%include "mips64/binopWide.S" {"instr":"ddiv a0, a0, a1", "chkzero":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_div_long_2addr.S b/runtime/interpreter/mterp/mips64/op_div_long_2addr.S
new file mode 100644
index 0000000..9627ab8
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_div_long_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binopWide2addr.S" {"instr":"ddiv a0, a0, a1", "chkzero":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_double_to_float.S b/runtime/interpreter/mterp/mips64/op_double_to_float.S
new file mode 100644
index 0000000..2b2acee
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_double_to_float.S
@@ -0,0 +1,8 @@
+    /*
+     * Conversion from or to floating-point happens in a floating-point register.
+     * Therefore we load the input and store the output into or from a
+     * floating-point register irrespective of the type.
+     */
+%include "mips64/fcvtHeader.S" { "suffix":"_DOUBLE", "valreg":"f0" }
+    cvt.s.d f0, f0
+%include "mips64/fcvtFooter.S" { "suffix":"_FLOAT", "valreg":"f0" }
diff --git a/runtime/interpreter/mterp/mips64/op_double_to_int.S b/runtime/interpreter/mterp/mips64/op_double_to_int.S
new file mode 100644
index 0000000..aa2cbca
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_double_to_int.S
@@ -0,0 +1,23 @@
+%include "mips64/fcvtHeader.S" { "suffix":"_DOUBLE", "valreg":"f0" }
+    /*
+     * TODO: simplify this when the MIPS64R6 emulator
+     * supports NAN2008=1.
+     */
+    dli     t0, INT_MIN_AS_DOUBLE
+    dmtc1   t0, f1
+    cmp.le.d f1, f1, f0
+    bc1nez  f1, .L${opcode}_trunc
+    cmp.eq.d f1, f0, f0
+    li      t0, INT_MIN
+    mfc1    t1, f1
+    and     t0, t0, t1
+    b       .L${opcode}_done
+%break
+.L${opcode}_trunc:
+    trunc.w.d f0, f0
+    mfc1    t0, f0
+.L${opcode}_done:
+    /* Can't include fcvtFooter.S after break */
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG t0, a1
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_double_to_long.S b/runtime/interpreter/mterp/mips64/op_double_to_long.S
new file mode 100644
index 0000000..777cfeb
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_double_to_long.S
@@ -0,0 +1,23 @@
+%include "mips64/fcvtHeader.S" { "suffix":"_DOUBLE", "valreg":"f0" }
+    /*
+     * TODO: simplify this when the MIPS64R6 emulator
+     * supports NAN2008=1.
+     */
+    dli     t0, LONG_MIN_AS_DOUBLE
+    dmtc1   t0, f1
+    cmp.le.d f1, f1, f0
+    bc1nez  f1, .L${opcode}_trunc
+    cmp.eq.d f1, f0, f0
+    dli     t0, LONG_MIN
+    mfc1    t1, f1
+    and     t0, t0, t1
+    b       .L${opcode}_done
+%break
+.L${opcode}_trunc:
+    trunc.l.d f0, f0
+    dmfc1   t0, f0
+.L${opcode}_done:
+    /* Can't include fcvtFooter.S after break */
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE t0, a1
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_fill_array_data.S b/runtime/interpreter/mterp/mips64/op_fill_array_data.S
new file mode 100644
index 0000000..c90f0b9
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_fill_array_data.S
@@ -0,0 +1,14 @@
+    /* fill-array-data vAA, +BBBBBBBB */
+    .extern MterpFillArrayData
+    EXPORT_PC
+    lh      a1, 2(rPC)                  # a1 <- bbbb (lo)
+    lh      a0, 4(rPC)                  # a0 <- BBBB (hi)
+    srl     a3, rINST, 8                # a3 <- AA
+    ins     a1, a0, 16, 16              # a1 <- BBBBbbbb
+    GET_VREG_U a0, a3                   # a0 <- vAA (array object)
+    dlsa    a1, a1, rPC, 1              # a1 <- PC + BBBBbbbb*2 (array data off.)
+    jal     MterpFillArrayData          # (obj, payload)
+    beqzc   v0, MterpPossibleException  # exception?
+    FETCH_ADVANCE_INST 3                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_filled_new_array.S b/runtime/interpreter/mterp/mips64/op_filled_new_array.S
new file mode 100644
index 0000000..35f55c2
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_filled_new_array.S
@@ -0,0 +1,18 @@
+%default { "helper":"MterpFilledNewArray" }
+    /*
+     * Create a new array with elements filled from registers.
+     *
+     * for: filled-new-array, filled-new-array/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class//CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, type//BBBB */
+    .extern $helper
+    EXPORT_PC
+    daddu   a0, rFP, OFF_FP_SHADOWFRAME
+    move    a1, rPC
+    move    a2, rSELF
+    jal     $helper
+    beqzc   v0, MterpPossibleException
+    FETCH_ADVANCE_INST 3                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_filled_new_array_range.S b/runtime/interpreter/mterp/mips64/op_filled_new_array_range.S
new file mode 100644
index 0000000..a4e18f6
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_filled_new_array_range.S
@@ -0,0 +1 @@
+%include "mips64/op_filled_new_array.S" { "helper":"MterpFilledNewArrayRange" }
diff --git a/runtime/interpreter/mterp/mips64/op_float_to_double.S b/runtime/interpreter/mterp/mips64/op_float_to_double.S
new file mode 100644
index 0000000..6accfee
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_float_to_double.S
@@ -0,0 +1,8 @@
+    /*
+     * Conversion from or to floating-point happens in a floating-point register.
+     * Therefore we load the input and store the output into or from a
+     * floating-point register irrespective of the type.
+     */
+%include "mips64/fcvtHeader.S" { "suffix":"_FLOAT", "valreg":"f0" }
+    cvt.d.s f0, f0
+%include "mips64/fcvtFooter.S" { "suffix":"_DOUBLE", "valreg":"f0" }
diff --git a/runtime/interpreter/mterp/mips64/op_float_to_int.S b/runtime/interpreter/mterp/mips64/op_float_to_int.S
new file mode 100644
index 0000000..d957540
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_float_to_int.S
@@ -0,0 +1,23 @@
+%include "mips64/fcvtHeader.S" { "suffix":"_FLOAT", "valreg":"f0" }
+    /*
+     * TODO: simplify this when the MIPS64R6 emulator
+     * supports NAN2008=1.
+     */
+    li      t0, INT_MIN_AS_FLOAT
+    mtc1    t0, f1
+    cmp.le.s f1, f1, f0
+    bc1nez  f1, .L${opcode}_trunc
+    cmp.eq.s f1, f0, f0
+    li      t0, INT_MIN
+    mfc1    t1, f1
+    and     t0, t0, t1
+    b       .L${opcode}_done
+%break
+.L${opcode}_trunc:
+    trunc.w.s f0, f0
+    mfc1    t0, f0
+.L${opcode}_done:
+    /* Can't include fcvtFooter.S after break */
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG t0, a1
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_float_to_long.S b/runtime/interpreter/mterp/mips64/op_float_to_long.S
new file mode 100644
index 0000000..5d036c8
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_float_to_long.S
@@ -0,0 +1,23 @@
+%include "mips64/fcvtHeader.S" { "suffix":"_FLOAT", "valreg":"f0" }
+    /*
+     * TODO: simplify this when the MIPS64R6 emulator
+     * supports NAN2008=1.
+     */
+    li      t0, LONG_MIN_AS_FLOAT
+    mtc1    t0, f1
+    cmp.le.s f1, f1, f0
+    bc1nez  f1, .L${opcode}_trunc
+    cmp.eq.s f1, f0, f0
+    dli     t0, LONG_MIN
+    mfc1    t1, f1
+    and     t0, t0, t1
+    b       .L${opcode}_done
+%break
+.L${opcode}_trunc:
+    trunc.l.s f0, f0
+    dmfc1   t0, f0
+.L${opcode}_done:
+    /* Can't include fcvtFooter.S after break */
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE t0, a1
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_goto.S b/runtime/interpreter/mterp/mips64/op_goto.S
new file mode 100644
index 0000000..f2df3e4
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_goto.S
@@ -0,0 +1,23 @@
+    /*
+     * Unconditional branch, 8-bit offset.
+     *
+     * The branch distance is a signed code-unit offset, which we need to
+     * double to get a byte offset.
+     */
+    /* goto +AA */
+    srl     a0, rINST, 8
+    seb     a0, a0                      # a0 <- sign-extended AA
+    dlsa    rPC, a0, rPC, 1             # rPC <- rPC + AA * 2
+    FETCH_INST                          # load rINST
+
+#if MTERP_SUSPEND
+    bgez    a0, 1f                      # AA * 2 >= 0 => no suspend check
+    REFRESH_IBASE
+1:
+#else
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    bltz    a0, MterpCheckSuspendAndContinue
+#endif
+
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_goto_16.S b/runtime/interpreter/mterp/mips64/op_goto_16.S
new file mode 100644
index 0000000..cbf8cf2
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_goto_16.S
@@ -0,0 +1,22 @@
+    /*
+     * Unconditional branch, 16-bit offset.
+     *
+     * The branch distance is a signed code-unit offset, which we need to
+     * double to get a byte offset.
+     */
+    /* goto/16 +AAAA */
+    lh      a0, 2(rPC)                  # a0 <- sign-extended AAAA
+    dlsa    rPC, a0, rPC, 1             # rPC <- rPC + AAAA * 2
+    FETCH_INST                          # load rINST
+
+#if MTERP_SUSPEND
+    bgez    a0, 1f                      # AA * 2 >= 0 => no suspend check
+    REFRESH_IBASE
+1:
+#else
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    bltz    a0, MterpCheckSuspendAndContinue
+#endif
+
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_goto_32.S b/runtime/interpreter/mterp/mips64/op_goto_32.S
new file mode 100644
index 0000000..4a1feac
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_goto_32.S
@@ -0,0 +1,27 @@
+    /*
+     * Unconditional branch, 32-bit offset.
+     *
+     * The branch distance is a signed code-unit offset, which we need to
+     * double to get a byte offset.
+     *
+     * Unlike most opcodes, this one is allowed to branch to itself, so
+     * our "backward branch" test must be "<=0" instead of "<0".
+     */
+    /* goto/32 +AAAAAAAA */
+    lh      a0, 2(rPC)                  # a0 <- aaaa (low)
+    lh      a1, 4(rPC)                  # a1 <- AAAA (high)
+    ins     a0, a1, 16, 16              # a0 = sign-extended AAAAaaaa
+    dlsa    rPC, a0, rPC, 1             # rPC <- rPC + AAAAAAAA * 2
+    FETCH_INST                          # load rINST
+
+#if MTERP_SUSPEND
+    bgtz    a0, 1f                      # AA * 2 > 0 => no suspend check
+    REFRESH_IBASE
+1:
+#else
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    blez    a0, MterpCheckSuspendAndContinue
+#endif
+
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_if_eq.S b/runtime/interpreter/mterp/mips64/op_if_eq.S
new file mode 100644
index 0000000..aa35cad
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_if_eq.S
@@ -0,0 +1 @@
+%include "mips64/bincmp.S" { "condition":"eq" }
diff --git a/runtime/interpreter/mterp/mips64/op_if_eqz.S b/runtime/interpreter/mterp/mips64/op_if_eqz.S
new file mode 100644
index 0000000..0fe3418
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_if_eqz.S
@@ -0,0 +1 @@
+%include "mips64/zcmp.S" { "condition":"eq" }
diff --git a/runtime/interpreter/mterp/mips64/op_if_ge.S b/runtime/interpreter/mterp/mips64/op_if_ge.S
new file mode 100644
index 0000000..59fdcc5
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_if_ge.S
@@ -0,0 +1 @@
+%include "mips64/bincmp.S" { "condition":"ge" }
diff --git a/runtime/interpreter/mterp/mips64/op_if_gez.S b/runtime/interpreter/mterp/mips64/op_if_gez.S
new file mode 100644
index 0000000..57f1f66
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_if_gez.S
@@ -0,0 +1 @@
+%include "mips64/zcmp.S" { "condition":"ge" }
diff --git a/runtime/interpreter/mterp/mips64/op_if_gt.S b/runtime/interpreter/mterp/mips64/op_if_gt.S
new file mode 100644
index 0000000..26cc119
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_if_gt.S
@@ -0,0 +1 @@
+%include "mips64/bincmp.S" { "condition":"gt" }
diff --git a/runtime/interpreter/mterp/mips64/op_if_gtz.S b/runtime/interpreter/mterp/mips64/op_if_gtz.S
new file mode 100644
index 0000000..69fcacb
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_if_gtz.S
@@ -0,0 +1 @@
+%include "mips64/zcmp.S" { "condition":"gt" }
diff --git a/runtime/interpreter/mterp/mips64/op_if_le.S b/runtime/interpreter/mterp/mips64/op_if_le.S
new file mode 100644
index 0000000..a7fce17
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_if_le.S
@@ -0,0 +1 @@
+%include "mips64/bincmp.S" { "condition":"le" }
diff --git a/runtime/interpreter/mterp/mips64/op_if_lez.S b/runtime/interpreter/mterp/mips64/op_if_lez.S
new file mode 100644
index 0000000..f3edcc6
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_if_lez.S
@@ -0,0 +1 @@
+%include "mips64/zcmp.S" { "condition":"le" }
diff --git a/runtime/interpreter/mterp/mips64/op_if_lt.S b/runtime/interpreter/mterp/mips64/op_if_lt.S
new file mode 100644
index 0000000..a975a31
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_if_lt.S
@@ -0,0 +1 @@
+%include "mips64/bincmp.S" { "condition":"lt" }
diff --git a/runtime/interpreter/mterp/mips64/op_if_ltz.S b/runtime/interpreter/mterp/mips64/op_if_ltz.S
new file mode 100644
index 0000000..c1d730d
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_if_ltz.S
@@ -0,0 +1 @@
+%include "mips64/zcmp.S" { "condition":"lt" }
diff --git a/runtime/interpreter/mterp/mips64/op_if_ne.S b/runtime/interpreter/mterp/mips64/op_if_ne.S
new file mode 100644
index 0000000..f143ee9
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_if_ne.S
@@ -0,0 +1 @@
+%include "mips64/bincmp.S" { "condition":"ne" }
diff --git a/runtime/interpreter/mterp/mips64/op_if_nez.S b/runtime/interpreter/mterp/mips64/op_if_nez.S
new file mode 100644
index 0000000..1856b96
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_if_nez.S
@@ -0,0 +1 @@
+%include "mips64/zcmp.S" { "condition":"ne" }
diff --git a/runtime/interpreter/mterp/mips64/op_iget.S b/runtime/interpreter/mterp/mips64/op_iget.S
new file mode 100644
index 0000000..ade4b31
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget.S
@@ -0,0 +1,26 @@
+%default { "is_object":"0", "helper":"artGet32InstanceFromCode"}
+    /*
+     * General instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    .extern $helper
+    EXPORT_PC
+    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
+    srl      a1, rINST, 12              # a1 <- B
+    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
+    ld       a2, OFF_FP_METHOD(rFP)     # a2 <- referrer
+    move     a3, rSELF                  # a3 <- self
+    jal      $helper
+    ld       a3, THREAD_EXCEPTION_OFFSET(rSELF)
+    ext      a2, rINST, 8, 4            # a2 <- A
+    PREFETCH_INST 2
+    bnez     a3, MterpPossibleException # bail out
+    .if $is_object
+    SET_VREG_OBJECT v0, a2              # fp[A] <- v0
+    .else
+    SET_VREG v0, a2                     # fp[A] <- v0
+    .endif
+    ADVANCE 2
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_iget_boolean.S b/runtime/interpreter/mterp/mips64/op_iget_boolean.S
new file mode 100644
index 0000000..cb2c8be
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget_boolean.S
@@ -0,0 +1 @@
+%include "mips64/op_iget.S" { "helper":"artGetBooleanInstanceFromCode" }
diff --git a/runtime/interpreter/mterp/mips64/op_iget_boolean_quick.S b/runtime/interpreter/mterp/mips64/op_iget_boolean_quick.S
new file mode 100644
index 0000000..979dc70
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget_boolean_quick.S
@@ -0,0 +1 @@
+%include "mips64/op_iget_quick.S" { "load":"lbu" }
diff --git a/runtime/interpreter/mterp/mips64/op_iget_byte.S b/runtime/interpreter/mterp/mips64/op_iget_byte.S
new file mode 100644
index 0000000..099d8d0
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget_byte.S
@@ -0,0 +1 @@
+%include "mips64/op_iget.S" { "helper":"artGetByteInstanceFromCode" }
diff --git a/runtime/interpreter/mterp/mips64/op_iget_byte_quick.S b/runtime/interpreter/mterp/mips64/op_iget_byte_quick.S
new file mode 100644
index 0000000..cb35556
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget_byte_quick.S
@@ -0,0 +1 @@
+%include "mips64/op_iget_quick.S" { "load":"lb" }
diff --git a/runtime/interpreter/mterp/mips64/op_iget_char.S b/runtime/interpreter/mterp/mips64/op_iget_char.S
new file mode 100644
index 0000000..927b7af
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget_char.S
@@ -0,0 +1 @@
+%include "mips64/op_iget.S" { "helper":"artGetCharInstanceFromCode" }
diff --git a/runtime/interpreter/mterp/mips64/op_iget_char_quick.S b/runtime/interpreter/mterp/mips64/op_iget_char_quick.S
new file mode 100644
index 0000000..6034567
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget_char_quick.S
@@ -0,0 +1 @@
+%include "mips64/op_iget_quick.S" { "load":"lhu" }
diff --git a/runtime/interpreter/mterp/mips64/op_iget_object.S b/runtime/interpreter/mterp/mips64/op_iget_object.S
new file mode 100644
index 0000000..c658556
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget_object.S
@@ -0,0 +1 @@
+%include "mips64/op_iget.S" { "is_object":"1", "helper":"artGetObjInstanceFromCode" }
diff --git a/runtime/interpreter/mterp/mips64/op_iget_object_quick.S b/runtime/interpreter/mterp/mips64/op_iget_object_quick.S
new file mode 100644
index 0000000..171d543
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget_object_quick.S
@@ -0,0 +1,16 @@
+    /* For: iget-object-quick */
+    /* op vA, vB, offset//CCCC */
+    .extern artIGetObjectFromMterp
+    srl     a2, rINST, 12               # a2 <- B
+    lhu     a1, 2(rPC)                  # a1 <- field byte offset
+    EXPORT_PC
+    GET_VREG_U a0, a2                   # a0 <- object we're operating on
+    jal     artIGetObjectFromMterp      # (obj, offset)
+    ld      a3, THREAD_EXCEPTION_OFFSET(rSELF)
+    ext     a2, rINST, 8, 4             # a2 <- A
+    PREFETCH_INST 2
+    bnez    a3, MterpPossibleException  # bail out
+    SET_VREG_OBJECT v0, a2              # fp[A] <- v0
+    ADVANCE 2                           # advance rPC
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_iget_quick.S b/runtime/interpreter/mterp/mips64/op_iget_quick.S
new file mode 100644
index 0000000..fee6ab7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget_quick.S
@@ -0,0 +1,14 @@
+%default { "load":"lw" }
+    /* For: iget-quick, iget-boolean-quick, iget-byte-quick, iget-char-quick, iget-short-quick */
+    /* op vA, vB, offset//CCCC */
+    srl     a2, rINST, 12               # a2 <- B
+    lhu     a1, 2(rPC)                  # a1 <- field byte offset
+    GET_VREG_U a3, a2                   # a3 <- object we're operating on
+    ext     a4, rINST, 8, 4             # a4 <- A
+    daddu   a1, a1, a3
+    beqz    a3, common_errNullObject    # object was null
+    $load   a0, 0(a1)                   # a0 <- obj.field
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    SET_VREG a0, a4                     # fp[A] <- a0
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_iget_short.S b/runtime/interpreter/mterp/mips64/op_iget_short.S
new file mode 100644
index 0000000..28b5093
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget_short.S
@@ -0,0 +1 @@
+%include "mips64/op_iget.S" { "helper":"artGetShortInstanceFromCode" }
diff --git a/runtime/interpreter/mterp/mips64/op_iget_short_quick.S b/runtime/interpreter/mterp/mips64/op_iget_short_quick.S
new file mode 100644
index 0000000..6e152db
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget_short_quick.S
@@ -0,0 +1 @@
+%include "mips64/op_iget_quick.S" { "load":"lh" }
diff --git a/runtime/interpreter/mterp/mips64/op_iget_wide.S b/runtime/interpreter/mterp/mips64/op_iget_wide.S
new file mode 100644
index 0000000..85cf670
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget_wide.S
@@ -0,0 +1,21 @@
+    /*
+     * 64-bit instance field get.
+     *
+     * for: iget-wide
+     */
+    .extern artGet64InstanceFromCode
+    EXPORT_PC
+    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
+    srl      a1, rINST, 12              # a1 <- B
+    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
+    ld       a2, OFF_FP_METHOD(rFP)     # a2 <- referrer
+    move     a3, rSELF                  # a3 <- self
+    jal      artGet64InstanceFromCode
+    ld       a3, THREAD_EXCEPTION_OFFSET(rSELF)
+    ext      a2, rINST, 8, 4            # a2 <- A
+    PREFETCH_INST 2
+    bnez     a3, MterpPossibleException # bail out
+    SET_VREG_WIDE v0, a2                # fp[A] <- v0
+    ADVANCE 2
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_iget_wide_quick.S b/runtime/interpreter/mterp/mips64/op_iget_wide_quick.S
new file mode 100644
index 0000000..2adc6ad
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iget_wide_quick.S
@@ -0,0 +1,14 @@
+    /* iget-wide-quick vA, vB, offset//CCCC */
+    srl     a2, rINST, 12               # a2 <- B
+    lhu     a4, 2(rPC)                  # a4 <- field byte offset
+    GET_VREG_U a3, a2                   # a3 <- object we're operating on
+    ext     a2, rINST, 8, 4             # a2 <- A
+    beqz    a3, common_errNullObject    # object was null
+    daddu   a4, a3, a4                  # create direct pointer
+    lw      a0, 0(a4)
+    lw      a1, 4(a4)
+    dinsu   a0, a1, 32, 32
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    SET_VREG_WIDE a0, a2
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_instance_of.S b/runtime/interpreter/mterp/mips64/op_instance_of.S
new file mode 100644
index 0000000..39a5dc7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_instance_of.S
@@ -0,0 +1,23 @@
+    /*
+     * Check to see if an object reference is an instance of a class.
+     *
+     * Most common situation is a non-null object, being compared against
+     * an already-resolved class.
+     */
+    /* instance-of vA, vB, class//CCCC */
+    .extern MterpInstanceOf
+    EXPORT_PC
+    lhu     a0, 2(rPC)                  # a0 <- CCCC
+    srl     a1, rINST, 12               # a1 <- B
+    dlsa    a1, a1, rFP, 2              # a1 <- &object
+    ld      a2, OFF_FP_METHOD(rFP)      # a2 <- method
+    move    a3, rSELF                   # a3 <- self
+    jal     MterpInstanceOf             # (index, &obj, method, self)
+    ld      a1, THREAD_EXCEPTION_OFFSET(rSELF)
+    ext     a2, rINST, 8, 4             # a2 <- A
+    PREFETCH_INST 2
+    bnez    a1, MterpException
+    ADVANCE 2                           # advance rPC
+    SET_VREG v0, a2                     # vA <- v0
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_int_to_byte.S b/runtime/interpreter/mterp/mips64/op_int_to_byte.S
new file mode 100644
index 0000000..1993e07
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_int_to_byte.S
@@ -0,0 +1 @@
+%include "mips64/unop.S" {"instr":"seb     a0, a0"}
diff --git a/runtime/interpreter/mterp/mips64/op_int_to_char.S b/runtime/interpreter/mterp/mips64/op_int_to_char.S
new file mode 100644
index 0000000..8f03acd
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_int_to_char.S
@@ -0,0 +1 @@
+%include "mips64/unop.S" {"instr":"and     a0, a0, 0xffff"}
diff --git a/runtime/interpreter/mterp/mips64/op_int_to_double.S b/runtime/interpreter/mterp/mips64/op_int_to_double.S
new file mode 100644
index 0000000..6df71be
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_int_to_double.S
@@ -0,0 +1,8 @@
+    /*
+     * Conversion from or to floating-point happens in a floating-point register.
+     * Therefore we load the input and store the output into or from a
+     * floating-point register irrespective of the type.
+     */
+%include "mips64/fcvtHeader.S" { "suffix":"_FLOAT", "valreg":"f0" }
+    cvt.d.w f0, f0
+%include "mips64/fcvtFooter.S" { "suffix":"_DOUBLE", "valreg":"f0" }
diff --git a/runtime/interpreter/mterp/mips64/op_int_to_float.S b/runtime/interpreter/mterp/mips64/op_int_to_float.S
new file mode 100644
index 0000000..77e9eba
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_int_to_float.S
@@ -0,0 +1,8 @@
+    /*
+     * Conversion from or to floating-point happens in a floating-point register.
+     * Therefore we load the input and store the output into or from a
+     * floating-point register irrespective of the type.
+     */
+%include "mips64/fcvtHeader.S" { "suffix":"_FLOAT", "valreg":"f0" }
+    cvt.s.w f0, f0
+%include "mips64/fcvtFooter.S" { "suffix":"_FLOAT", "valreg":"f0" }
diff --git a/runtime/interpreter/mterp/mips64/op_int_to_long.S b/runtime/interpreter/mterp/mips64/op_int_to_long.S
new file mode 100644
index 0000000..7b9ad86
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_int_to_long.S
@@ -0,0 +1,8 @@
+    /* int-to-long vA, vB */
+    ext     a3, rINST, 12, 4            # a3 <- B
+    GET_VREG a0, a3                     # a0 <- vB (sign-extended to 64 bits)
+    ext     a2, rINST, 8, 4             # a2 <- A
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE a0, a2                # vA <- vB
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_int_to_short.S b/runtime/interpreter/mterp/mips64/op_int_to_short.S
new file mode 100644
index 0000000..4a3f234
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_int_to_short.S
@@ -0,0 +1 @@
+%include "mips64/unop.S" {"instr":"seh     a0, a0"}
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_direct.S b/runtime/interpreter/mterp/mips64/op_invoke_direct.S
new file mode 100644
index 0000000..5047118
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_direct.S
@@ -0,0 +1 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeDirect" }
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_direct_range.S b/runtime/interpreter/mterp/mips64/op_invoke_direct_range.S
new file mode 100644
index 0000000..5c9b95f
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_direct_range.S
@@ -0,0 +1 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeDirectRange" }
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_interface.S b/runtime/interpreter/mterp/mips64/op_invoke_interface.S
new file mode 100644
index 0000000..ed148ad
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_interface.S
@@ -0,0 +1,8 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeInterface" }
+    /*
+     * Handle an interface method call.
+     *
+     * for: invoke-interface, invoke-interface/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_interface_range.S b/runtime/interpreter/mterp/mips64/op_invoke_interface_range.S
new file mode 100644
index 0000000..91c231e
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_interface_range.S
@@ -0,0 +1 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeInterfaceRange" }
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_static.S b/runtime/interpreter/mterp/mips64/op_invoke_static.S
new file mode 100644
index 0000000..44f5cb7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_static.S
@@ -0,0 +1 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeStatic" }
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_static_range.S b/runtime/interpreter/mterp/mips64/op_invoke_static_range.S
new file mode 100644
index 0000000..289e5aa
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_static_range.S
@@ -0,0 +1 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeStaticRange" }
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_super.S b/runtime/interpreter/mterp/mips64/op_invoke_super.S
new file mode 100644
index 0000000..b13fffe
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_super.S
@@ -0,0 +1,8 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeSuper" }
+    /*
+     * Handle a "super" method call.
+     *
+     * for: invoke-super, invoke-super/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_super_range.S b/runtime/interpreter/mterp/mips64/op_invoke_super_range.S
new file mode 100644
index 0000000..350b975
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_super_range.S
@@ -0,0 +1 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeSuperRange" }
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_virtual.S b/runtime/interpreter/mterp/mips64/op_invoke_virtual.S
new file mode 100644
index 0000000..0d26cda
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_virtual.S
@@ -0,0 +1,8 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeVirtual" }
+    /*
+     * Handle a virtual method call.
+     *
+     * for: invoke-virtual, invoke-virtual/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_virtual_quick.S b/runtime/interpreter/mterp/mips64/op_invoke_virtual_quick.S
new file mode 100644
index 0000000..f39562c
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_virtual_quick.S
@@ -0,0 +1 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeVirtualQuick" }
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_virtual_range.S b/runtime/interpreter/mterp/mips64/op_invoke_virtual_range.S
new file mode 100644
index 0000000..0bb43f8
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_virtual_range.S
@@ -0,0 +1 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeVirtualRange" }
diff --git a/runtime/interpreter/mterp/mips64/op_invoke_virtual_range_quick.S b/runtime/interpreter/mterp/mips64/op_invoke_virtual_range_quick.S
new file mode 100644
index 0000000..c448851
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_invoke_virtual_range_quick.S
@@ -0,0 +1 @@
+%include "mips64/invoke.S" { "helper":"MterpInvokeVirtualQuickRange" }
diff --git a/runtime/interpreter/mterp/mips64/op_iput.S b/runtime/interpreter/mterp/mips64/op_iput.S
new file mode 100644
index 0000000..a906a0f
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput.S
@@ -0,0 +1,21 @@
+%default { "helper":"artSet32InstanceFromMterp" }
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field//CCCC */
+    .extern $helper
+    EXPORT_PC
+    lhu     a0, 2(rPC)                  # a0 <- field ref CCCC
+    srl     a1, rINST, 12               # a1 <- B
+    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
+    ext     a2, rINST, 8, 4             # a2 <- A
+    GET_VREG a2, a2                     # a2 <- fp[A]
+    ld      a3, OFF_FP_METHOD(rFP)      # a3 <- referrer
+    PREFETCH_INST 2
+    jal     $helper
+    bnez    v0, MterpPossibleException  # bail out
+    ADVANCE 2
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_iput_boolean.S b/runtime/interpreter/mterp/mips64/op_iput_boolean.S
new file mode 100644
index 0000000..3034fa5
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput_boolean.S
@@ -0,0 +1 @@
+%include "mips64/op_iput.S" { "helper":"artSet8InstanceFromMterp" }
diff --git a/runtime/interpreter/mterp/mips64/op_iput_boolean_quick.S b/runtime/interpreter/mterp/mips64/op_iput_boolean_quick.S
new file mode 100644
index 0000000..df99948
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput_boolean_quick.S
@@ -0,0 +1 @@
+%include "mips64/op_iput_quick.S" { "store":"sb" }
diff --git a/runtime/interpreter/mterp/mips64/op_iput_byte.S b/runtime/interpreter/mterp/mips64/op_iput_byte.S
new file mode 100644
index 0000000..3034fa5
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput_byte.S
@@ -0,0 +1 @@
+%include "mips64/op_iput.S" { "helper":"artSet8InstanceFromMterp" }
diff --git a/runtime/interpreter/mterp/mips64/op_iput_byte_quick.S b/runtime/interpreter/mterp/mips64/op_iput_byte_quick.S
new file mode 100644
index 0000000..df99948
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput_byte_quick.S
@@ -0,0 +1 @@
+%include "mips64/op_iput_quick.S" { "store":"sb" }
diff --git a/runtime/interpreter/mterp/mips64/op_iput_char.S b/runtime/interpreter/mterp/mips64/op_iput_char.S
new file mode 100644
index 0000000..4c2fa28
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput_char.S
@@ -0,0 +1 @@
+%include "mips64/op_iput.S" { "helper":"artSet16InstanceFromMterp" }
diff --git a/runtime/interpreter/mterp/mips64/op_iput_char_quick.S b/runtime/interpreter/mterp/mips64/op_iput_char_quick.S
new file mode 100644
index 0000000..a6286b7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput_char_quick.S
@@ -0,0 +1 @@
+%include "mips64/op_iput_quick.S" { "store":"sh" }
diff --git a/runtime/interpreter/mterp/mips64/op_iput_object.S b/runtime/interpreter/mterp/mips64/op_iput_object.S
new file mode 100644
index 0000000..9a42f54
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput_object.S
@@ -0,0 +1,11 @@
+    .extern MterpIputObject
+    EXPORT_PC
+    daddu   a0, rFP, OFF_FP_SHADOWFRAME
+    move    a1, rPC
+    move    a2, rINST
+    move    a3, rSELF
+    jal     MterpIputObject
+    beqzc   v0, MterpException
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_iput_object_quick.S b/runtime/interpreter/mterp/mips64/op_iput_object_quick.S
new file mode 100644
index 0000000..658ef42
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput_object_quick.S
@@ -0,0 +1,10 @@
+    .extern MterpIputObjectQuick
+    EXPORT_PC
+    daddu   a0, rFP, OFF_FP_SHADOWFRAME
+    move    a1, rPC
+    move    a2, rINST
+    jal     MterpIputObjectQuick
+    beqzc   v0, MterpException
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_iput_quick.S b/runtime/interpreter/mterp/mips64/op_iput_quick.S
new file mode 100644
index 0000000..b95adfc
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput_quick.S
@@ -0,0 +1,14 @@
+%default { "store":"sw" }
+    /* For: iput-quick, iput-boolean-quick, iput-byte-quick, iput-char-quick, iput-short-quick */
+    /* op vA, vB, offset//CCCC */
+    srl     a2, rINST, 12               # a2 <- B
+    lhu     a1, 2(rPC)                  # a1 <- field byte offset
+    GET_VREG_U a3, a2                   # a3 <- fp[B], the object pointer
+    ext     a2, rINST, 8, 4             # a2 <- A
+    beqz    a3, common_errNullObject    # object was null
+    GET_VREG a0, a2                     # a0 <- fp[A]
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    daddu   a1, a1, a3
+    $store  a0, 0(a1)                   # obj.field <- a0
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_iput_short.S b/runtime/interpreter/mterp/mips64/op_iput_short.S
new file mode 100644
index 0000000..4c2fa28
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput_short.S
@@ -0,0 +1 @@
+%include "mips64/op_iput.S" { "helper":"artSet16InstanceFromMterp" }
diff --git a/runtime/interpreter/mterp/mips64/op_iput_short_quick.S b/runtime/interpreter/mterp/mips64/op_iput_short_quick.S
new file mode 100644
index 0000000..a6286b7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput_short_quick.S
@@ -0,0 +1 @@
+%include "mips64/op_iput_quick.S" { "store":"sh" }
diff --git a/runtime/interpreter/mterp/mips64/op_iput_wide.S b/runtime/interpreter/mterp/mips64/op_iput_wide.S
new file mode 100644
index 0000000..9b790f8
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput_wide.S
@@ -0,0 +1,15 @@
+    /* iput-wide vA, vB, field//CCCC */
+    .extern artSet64InstanceFromMterp
+    EXPORT_PC
+    lhu      a0, 2(rPC)                 # a0 <- field ref CCCC
+    srl      a1, rINST, 12              # a1 <- B
+    GET_VREG_U a1, a1                   # a1 <- fp[B], the object pointer
+    ext      a2, rINST, 8, 4            # a2 <- A
+    dlsa     a2, a2, rFP, 2             # a2 <- &fp[A]
+    ld       a3, OFF_FP_METHOD(rFP)     # a3 <- referrer
+    PREFETCH_INST 2
+    jal      artSet64InstanceFromMterp
+    bnez     v0, MterpPossibleException # bail out
+    ADVANCE 2
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_iput_wide_quick.S b/runtime/interpreter/mterp/mips64/op_iput_wide_quick.S
new file mode 100644
index 0000000..95a8ad8
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_iput_wide_quick.S
@@ -0,0 +1,14 @@
+    /* iput-wide-quick vA, vB, offset//CCCC */
+    srl     a2, rINST, 12               # a2 <- B
+    lhu     a3, 2(rPC)                  # a3 <- field byte offset
+    GET_VREG_U a2, a2                   # a2 <- fp[B], the object pointer
+    ext     a0, rINST, 8, 4             # a0 <- A
+    beqz    a2, common_errNullObject    # object was null
+    GET_VREG_WIDE a0, a0                # a0 <- fp[A]
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    daddu   a1, a2, a3                  # create a direct pointer
+    sw      a0, 0(a1)
+    dsrl32  a0, a0, 0
+    sw      a0, 4(a1)
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_long_to_double.S b/runtime/interpreter/mterp/mips64/op_long_to_double.S
new file mode 100644
index 0000000..8503e76
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_long_to_double.S
@@ -0,0 +1,8 @@
+    /*
+     * Conversion from or to floating-point happens in a floating-point register.
+     * Therefore we load the input and store the output into or from a
+     * floating-point register irrespective of the type.
+     */
+%include "mips64/fcvtHeader.S" { "suffix":"_DOUBLE", "valreg":"f0" }
+    cvt.d.l f0, f0
+%include "mips64/fcvtFooter.S" { "suffix":"_DOUBLE", "valreg":"f0" }
diff --git a/runtime/interpreter/mterp/mips64/op_long_to_float.S b/runtime/interpreter/mterp/mips64/op_long_to_float.S
new file mode 100644
index 0000000..31f5c0e
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_long_to_float.S
@@ -0,0 +1,8 @@
+    /*
+     * Conversion from or to floating-point happens in a floating-point register.
+     * Therefore we load the input and store the output into or from a
+     * floating-point register irrespective of the type.
+     */
+%include "mips64/fcvtHeader.S" { "suffix":"_DOUBLE", "valreg":"f0" }
+    cvt.s.l f0, f0
+%include "mips64/fcvtFooter.S" { "suffix":"_FLOAT", "valreg":"f0" }
diff --git a/runtime/interpreter/mterp/mips64/op_long_to_int.S b/runtime/interpreter/mterp/mips64/op_long_to_int.S
new file mode 100644
index 0000000..4ef4b51
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_long_to_int.S
@@ -0,0 +1,2 @@
+/* we ignore the high word, making this equivalent to a 32-bit reg move */
+%include "mips64/op_move.S"
diff --git a/runtime/interpreter/mterp/mips64/op_monitor_enter.S b/runtime/interpreter/mterp/mips64/op_monitor_enter.S
new file mode 100644
index 0000000..36ae503
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_monitor_enter.S
@@ -0,0 +1,14 @@
+    /*
+     * Synchronize on an object.
+     */
+    /* monitor-enter vAA */
+    .extern artLockObjectFromCode
+    EXPORT_PC
+    srl     a2, rINST, 8                # a2 <- AA
+    GET_VREG_U a0, a2                   # a0 <- vAA (object)
+    move    a1, rSELF                   # a1 <- self
+    jal     artLockObjectFromCode
+    bnezc   v0, MterpException
+    FETCH_ADVANCE_INST 1
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_monitor_exit.S b/runtime/interpreter/mterp/mips64/op_monitor_exit.S
new file mode 100644
index 0000000..9945952
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_monitor_exit.S
@@ -0,0 +1,18 @@
+    /*
+     * Unlock an object.
+     *
+     * Exceptions that occur when unlocking a monitor need to appear as
+     * if they happened at the following instruction.  See the Dalvik
+     * instruction spec.
+     */
+    /* monitor-exit vAA */
+    .extern artUnlockObjectFromCode
+    EXPORT_PC
+    srl     a2, rINST, 8                # a2 <- AA
+    GET_VREG_U a0, a2                   # a0 <- vAA (object)
+    move    a1, rSELF                   # a1 <- self
+    jal     artUnlockObjectFromCode     # v0 <- success for unlock(self, obj)
+    bnezc   v0, MterpException
+    FETCH_ADVANCE_INST 1                # before throw: advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_move.S b/runtime/interpreter/mterp/mips64/op_move.S
new file mode 100644
index 0000000..c79f6cd
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_move.S
@@ -0,0 +1,14 @@
+%default { "is_object":"0" }
+    /* for move, move-object, long-to-int */
+    /* op vA, vB */
+    ext     a2, rINST, 8, 4             # a2 <- A
+    ext     a3, rINST, 12, 4            # a3 <- B
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    GET_VREG a0, a3                     # a0 <- vB
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    .if $is_object
+    SET_VREG_OBJECT a0, a2              # vA <- vB
+    .else
+    SET_VREG a0, a2                     # vA <- vB
+    .endif
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_move_16.S b/runtime/interpreter/mterp/mips64/op_move_16.S
new file mode 100644
index 0000000..9d5c4dc
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_move_16.S
@@ -0,0 +1,14 @@
+%default { "is_object":"0" }
+    /* for: move/16, move-object/16 */
+    /* op vAAAA, vBBBB */
+    lhu     a3, 4(rPC)                  # a3 <- BBBB
+    lhu     a2, 2(rPC)                  # a2 <- AAAA
+    FETCH_ADVANCE_INST 3                # advance rPC, load rINST
+    GET_VREG a0, a3                     # a0 <- vBBBB
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    .if $is_object
+    SET_VREG_OBJECT a0, a2              # vAAAA <- vBBBB
+    .else
+    SET_VREG a0, a2                     # vAAAA <- vBBBB
+    .endif
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_move_exception.S b/runtime/interpreter/mterp/mips64/op_move_exception.S
new file mode 100644
index 0000000..d226718
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_move_exception.S
@@ -0,0 +1,8 @@
+    /* move-exception vAA */
+    srl     a2, rINST, 8                # a2 <- AA
+    ld      a0, THREAD_EXCEPTION_OFFSET(rSELF)  # load exception obj
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    SET_VREG_OBJECT a0, a2              # vAA <- exception obj
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    sd      zero, THREAD_EXCEPTION_OFFSET(rSELF)  # clear exception
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_move_from16.S b/runtime/interpreter/mterp/mips64/op_move_from16.S
new file mode 100644
index 0000000..6d6bde0
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_move_from16.S
@@ -0,0 +1,14 @@
+%default { "is_object":"0" }
+    /* for: move/from16, move-object/from16 */
+    /* op vAA, vBBBB */
+    lhu     a3, 2(rPC)                  # a3 <- BBBB
+    srl     a2, rINST, 8                # a2 <- AA
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_VREG a0, a3                     # a0 <- vBBBB
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    .if $is_object
+    SET_VREG_OBJECT a0, a2              # vAA <- vBBBB
+    .else
+    SET_VREG a0, a2                     # vAA <- vBBBB
+    .endif
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_move_object.S b/runtime/interpreter/mterp/mips64/op_move_object.S
new file mode 100644
index 0000000..47e0272
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_move_object.S
@@ -0,0 +1 @@
+%include "mips64/op_move.S" {"is_object":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_move_object_16.S b/runtime/interpreter/mterp/mips64/op_move_object_16.S
new file mode 100644
index 0000000..a777dcd
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_move_object_16.S
@@ -0,0 +1 @@
+%include "mips64/op_move_16.S" {"is_object":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_move_object_from16.S b/runtime/interpreter/mterp/mips64/op_move_object_from16.S
new file mode 100644
index 0000000..ab55ebd
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_move_object_from16.S
@@ -0,0 +1 @@
+%include "mips64/op_move_from16.S" {"is_object":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_move_result.S b/runtime/interpreter/mterp/mips64/op_move_result.S
new file mode 100644
index 0000000..1ec28cb
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_move_result.S
@@ -0,0 +1,14 @@
+%default { "is_object":"0" }
+    /* for: move-result, move-result-object */
+    /* op vAA */
+    srl     a2, rINST, 8                # a2 <- AA
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    ld      a0, OFF_FP_RESULT_REGISTER(rFP)  # get pointer to result JType
+    lw      a0, 0(a0)                   # a0 <- result.i
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    .if $is_object
+    SET_VREG_OBJECT a0, a2              # vAA <- result
+    .else
+    SET_VREG a0, a2                     # vAA <- result
+    .endif
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_move_result_object.S b/runtime/interpreter/mterp/mips64/op_move_result_object.S
new file mode 100644
index 0000000..e76bc22
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_move_result_object.S
@@ -0,0 +1 @@
+%include "mips64/op_move_result.S" {"is_object":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_move_result_wide.S b/runtime/interpreter/mterp/mips64/op_move_result_wide.S
new file mode 100644
index 0000000..3ba0d72
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_move_result_wide.S
@@ -0,0 +1,9 @@
+    /* for: move-result-wide */
+    /* op vAA */
+    srl     a2, rINST, 8                # a2 <- AA
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    ld      a0, OFF_FP_RESULT_REGISTER(rFP)  # get pointer to result JType
+    ld      a0, 0(a0)                   # a0 <- result.j
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE a0, a2                # vAA <- result
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_move_wide.S b/runtime/interpreter/mterp/mips64/op_move_wide.S
new file mode 100644
index 0000000..ea23f87
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_move_wide.S
@@ -0,0 +1,9 @@
+    /* move-wide vA, vB */
+    /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+    ext     a3, rINST, 12, 4            # a3 <- B
+    ext     a2, rINST, 8, 4             # a2 <- A
+    GET_VREG_WIDE a0, a3                # a0 <- vB
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE a0, a2                # vA <- vB
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_move_wide_16.S b/runtime/interpreter/mterp/mips64/op_move_wide_16.S
new file mode 100644
index 0000000..8ec6068
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_move_wide_16.S
@@ -0,0 +1,9 @@
+    /* move-wide/16 vAAAA, vBBBB */
+    /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+    lhu     a3, 4(rPC)                  # a3 <- BBBB
+    lhu     a2, 2(rPC)                  # a2 <- AAAA
+    GET_VREG_WIDE a0, a3                # a0 <- vBBBB
+    FETCH_ADVANCE_INST 3                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE a0, a2                # vAAAA <- vBBBB
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_move_wide_from16.S b/runtime/interpreter/mterp/mips64/op_move_wide_from16.S
new file mode 100644
index 0000000..11d5603
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_move_wide_from16.S
@@ -0,0 +1,9 @@
+    /* move-wide/from16 vAA, vBBBB */
+    /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+    lhu     a3, 2(rPC)                  # a3 <- BBBB
+    srl     a2, rINST, 8                # a2 <- AA
+    GET_VREG_WIDE a0, a3                # a0 <- vBBBB
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE a0, a2                # vAA <- vBBBB
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_mul_double.S b/runtime/interpreter/mterp/mips64/op_mul_double.S
new file mode 100644
index 0000000..e7e17f7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_mul_double.S
@@ -0,0 +1 @@
+%include "mips64/fbinopWide.S" {"instr":"mul.d f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_mul_double_2addr.S b/runtime/interpreter/mterp/mips64/op_mul_double_2addr.S
new file mode 100644
index 0000000..f404d46
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_mul_double_2addr.S
@@ -0,0 +1 @@
+%include "mips64/fbinopWide2addr.S" {"instr":"mul.d f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_mul_float.S b/runtime/interpreter/mterp/mips64/op_mul_float.S
new file mode 100644
index 0000000..9a695fc
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_mul_float.S
@@ -0,0 +1 @@
+%include "mips64/fbinop.S" {"instr":"mul.s f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_mul_float_2addr.S b/runtime/interpreter/mterp/mips64/op_mul_float_2addr.S
new file mode 100644
index 0000000..a134a34
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_mul_float_2addr.S
@@ -0,0 +1 @@
+%include "mips64/fbinop2addr.S" {"instr":"mul.s f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_mul_int.S b/runtime/interpreter/mterp/mips64/op_mul_int.S
new file mode 100644
index 0000000..e1b90ff
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_mul_int.S
@@ -0,0 +1 @@
+%include "mips64/binop.S" {"instr":"mul a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_mul_int_2addr.S b/runtime/interpreter/mterp/mips64/op_mul_int_2addr.S
new file mode 100644
index 0000000..c0c4063
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_mul_int_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binop2addr.S" {"instr":"mul a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_mul_int_lit16.S b/runtime/interpreter/mterp/mips64/op_mul_int_lit16.S
new file mode 100644
index 0000000..bb4fff8
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_mul_int_lit16.S
@@ -0,0 +1 @@
+%include "mips64/binopLit16.S" {"instr":"mul a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_mul_int_lit8.S b/runtime/interpreter/mterp/mips64/op_mul_int_lit8.S
new file mode 100644
index 0000000..da11ea9
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_mul_int_lit8.S
@@ -0,0 +1 @@
+%include "mips64/binopLit8.S" {"instr":"mul a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_mul_long.S b/runtime/interpreter/mterp/mips64/op_mul_long.S
new file mode 100644
index 0000000..ec32850
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_mul_long.S
@@ -0,0 +1 @@
+%include "mips64/binopWide.S" {"instr":"dmul a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_mul_long_2addr.S b/runtime/interpreter/mterp/mips64/op_mul_long_2addr.S
new file mode 100644
index 0000000..eb50cda
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_mul_long_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binopWide2addr.S" {"instr":"dmul a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_neg_double.S b/runtime/interpreter/mterp/mips64/op_neg_double.S
new file mode 100644
index 0000000..a135d61
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_neg_double.S
@@ -0,0 +1,3 @@
+%include "mips64/fcvtHeader.S" { "suffix":"_DOUBLE", "valreg":"f0" }
+    neg.d   f0, f0
+%include "mips64/fcvtFooter.S" { "suffix":"_DOUBLE", "valreg":"f0" }
diff --git a/runtime/interpreter/mterp/mips64/op_neg_float.S b/runtime/interpreter/mterp/mips64/op_neg_float.S
new file mode 100644
index 0000000..78019f0
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_neg_float.S
@@ -0,0 +1,3 @@
+%include "mips64/fcvtHeader.S" { "suffix":"_FLOAT", "valreg":"f0" }
+    neg.s   f0, f0
+%include "mips64/fcvtFooter.S" { "suffix":"_FLOAT", "valreg":"f0" }
diff --git a/runtime/interpreter/mterp/mips64/op_neg_int.S b/runtime/interpreter/mterp/mips64/op_neg_int.S
new file mode 100644
index 0000000..31538c0
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_neg_int.S
@@ -0,0 +1 @@
+%include "mips64/unop.S" {"instr":"subu    a0, zero, a0"}
diff --git a/runtime/interpreter/mterp/mips64/op_neg_long.S b/runtime/interpreter/mterp/mips64/op_neg_long.S
new file mode 100644
index 0000000..bc80d06
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_neg_long.S
@@ -0,0 +1 @@
+%include "mips64/unopWide.S" {"instr":"dsubu   a0, zero, a0"}
diff --git a/runtime/interpreter/mterp/mips64/op_new_array.S b/runtime/interpreter/mterp/mips64/op_new_array.S
new file mode 100644
index 0000000..d78b4ac
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_new_array.S
@@ -0,0 +1,19 @@
+    /*
+     * Allocate an array of objects, specified with the array class
+     * and a count.
+     *
+     * The verifier guarantees that this is an array class, so we don't
+     * check for it here.
+     */
+    /* new-array vA, vB, class//CCCC */
+    .extern MterpNewArray
+    EXPORT_PC
+    daddu   a0, rFP, OFF_FP_SHADOWFRAME
+    move    a1, rPC
+    move    a2, rINST
+    move    a3, rSELF
+    jal     MterpNewArray
+    beqzc   v0, MterpPossibleException
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_new_instance.S b/runtime/interpreter/mterp/mips64/op_new_instance.S
new file mode 100644
index 0000000..cc5e13e
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_new_instance.S
@@ -0,0 +1,14 @@
+    /*
+     * Create a new instance of a class.
+     */
+    /* new-instance vAA, class//BBBB */
+    .extern MterpNewInstance
+    EXPORT_PC
+    daddu   a0, rFP, OFF_FP_SHADOWFRAME
+    move    a1, rSELF
+    move    a2, rINST
+    jal     MterpNewInstance            # (shadow_frame, self, inst_data)
+    beqzc   v0, MterpPossibleException
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_nop.S b/runtime/interpreter/mterp/mips64/op_nop.S
new file mode 100644
index 0000000..cc803a7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_nop.S
@@ -0,0 +1,3 @@
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_not_int.S b/runtime/interpreter/mterp/mips64/op_not_int.S
new file mode 100644
index 0000000..5954095
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_not_int.S
@@ -0,0 +1 @@
+%include "mips64/unop.S" {"instr":"nor     a0, zero, a0"}
diff --git a/runtime/interpreter/mterp/mips64/op_not_long.S b/runtime/interpreter/mterp/mips64/op_not_long.S
new file mode 100644
index 0000000..c8f5da7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_not_long.S
@@ -0,0 +1 @@
+%include "mips64/unopWide.S" {"instr":"nor     a0, zero, a0"}
diff --git a/runtime/interpreter/mterp/mips64/op_or_int.S b/runtime/interpreter/mterp/mips64/op_or_int.S
new file mode 100644
index 0000000..0102355
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_or_int.S
@@ -0,0 +1 @@
+%include "mips64/binop.S" {"instr":"or a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_or_int_2addr.S b/runtime/interpreter/mterp/mips64/op_or_int_2addr.S
new file mode 100644
index 0000000..eed8900
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_or_int_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binop2addr.S" {"instr":"or a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_or_int_lit16.S b/runtime/interpreter/mterp/mips64/op_or_int_lit16.S
new file mode 100644
index 0000000..16a0f3e
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_or_int_lit16.S
@@ -0,0 +1 @@
+%include "mips64/binopLit16.S" {"instr":"or a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_or_int_lit8.S b/runtime/interpreter/mterp/mips64/op_or_int_lit8.S
new file mode 100644
index 0000000..dbbf790
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_or_int_lit8.S
@@ -0,0 +1 @@
+%include "mips64/binopLit8.S" {"instr":"or a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_or_long.S b/runtime/interpreter/mterp/mips64/op_or_long.S
new file mode 100644
index 0000000..e6f8639
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_or_long.S
@@ -0,0 +1 @@
+%include "mips64/binopWide.S" {"instr":"or a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_or_long_2addr.S b/runtime/interpreter/mterp/mips64/op_or_long_2addr.S
new file mode 100644
index 0000000..ad5e6c8
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_or_long_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binopWide2addr.S" {"instr":"or a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_packed_switch.S b/runtime/interpreter/mterp/mips64/op_packed_switch.S
new file mode 100644
index 0000000..cdbdf75
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_packed_switch.S
@@ -0,0 +1,31 @@
+%default { "func":"MterpDoPackedSwitch" }
+    /*
+     * Handle a packed-switch or sparse-switch instruction.  In both cases
+     * we decode it and hand it off to a helper function.
+     *
+     * We don't really expect backward branches in a switch statement, but
+     * they're perfectly legal, so we check for them here.
+     *
+     * for: packed-switch, sparse-switch
+     */
+    /* op vAA, +BBBBBBBB */
+    .extern $func
+    lh      a0, 2(rPC)                  # a0 <- bbbb (lo)
+    lh      a1, 4(rPC)                  # a1 <- BBBB (hi)
+    srl     a3, rINST, 8                # a3 <- AA
+    ins     a0, a1, 16, 16              # a0 <- BBBBbbbb
+    GET_VREG a1, a3                     # a1 <- vAA
+    dlsa    a0, a0, rPC, 1              # a0 <- PC + BBBBbbbb*2
+    jal     $func                       # v0 <- code-unit branch offset
+    dlsa    rPC, v0, rPC, 1             # rPC <- rPC + offset * 2
+    FETCH_INST                          # load rINST
+#if MTERP_SUSPEND
+    bgtz    v0, 1f                      # offset * 2 > 0 => no suspend check
+    REFRESH_IBASE
+1:
+#else
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    blez    v0, MterpCheckSuspendAndContinue
+#endif
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_rem_double.S b/runtime/interpreter/mterp/mips64/op_rem_double.S
new file mode 100644
index 0000000..ba61cfd
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_rem_double.S
@@ -0,0 +1,12 @@
+    /* rem-double vAA, vBB, vCC */
+    .extern fmod
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    GET_VREG_DOUBLE f12, a2             # f12 <- vBB
+    GET_VREG_DOUBLE f13, a3             # f13 <- vCC
+    jal     fmod                        # f0 <- f12 op f13
+    srl     a4, rINST, 8                # a4 <- AA
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_DOUBLE f0, a4              # vAA <- f0
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_rem_double_2addr.S b/runtime/interpreter/mterp/mips64/op_rem_double_2addr.S
new file mode 100644
index 0000000..c649f0d
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_rem_double_2addr.S
@@ -0,0 +1,12 @@
+    /* rem-double/2addr vA, vB */
+    .extern fmod
+    ext     a2, rINST, 8, 4             # a2 <- A
+    ext     a3, rINST, 12, 4            # a3 <- B
+    GET_VREG_DOUBLE f12, a2             # f12 <- vA
+    GET_VREG_DOUBLE f13, a3             # f13 <- vB
+    jal     fmod                        # f0 <- f12 op f13
+    ext     a2, rINST, 8, 4             # a2 <- A
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_DOUBLE f0, a2              # vA <- f0
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_rem_float.S b/runtime/interpreter/mterp/mips64/op_rem_float.S
new file mode 100644
index 0000000..3967b0b
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_rem_float.S
@@ -0,0 +1,12 @@
+    /* rem-float vAA, vBB, vCC */
+    .extern fmodf
+    lbu     a2, 2(rPC)                  # a2 <- BB
+    lbu     a3, 3(rPC)                  # a3 <- CC
+    GET_VREG_FLOAT f12, a2              # f12 <- vBB
+    GET_VREG_FLOAT f13, a3              # f13 <- vCC
+    jal     fmodf                       # f0 <- f12 op f13
+    srl     a4, rINST, 8                # a4 <- AA
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_FLOAT f0, a4               # vAA <- f0
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_rem_float_2addr.S b/runtime/interpreter/mterp/mips64/op_rem_float_2addr.S
new file mode 100644
index 0000000..3fed41e
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_rem_float_2addr.S
@@ -0,0 +1,12 @@
+    /* rem-float/2addr vA, vB */
+    .extern fmodf
+    ext     a2, rINST, 8, 4             # a2 <- A
+    ext     a3, rINST, 12, 4            # a3 <- B
+    GET_VREG_FLOAT f12, a2              # f12 <- vA
+    GET_VREG_FLOAT f13, a3              # f13 <- vB
+    jal     fmodf                       # f0 <- f12 op f13
+    ext     a2, rINST, 8, 4             # a2 <- A
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_FLOAT f0, a2               # vA <- f0
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_rem_int.S b/runtime/interpreter/mterp/mips64/op_rem_int.S
new file mode 100644
index 0000000..c05e9c4
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_rem_int.S
@@ -0,0 +1 @@
+%include "mips64/binop.S" {"instr":"mod a0, a0, a1", "chkzero":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_rem_int_2addr.S b/runtime/interpreter/mterp/mips64/op_rem_int_2addr.S
new file mode 100644
index 0000000..a4e162d
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_rem_int_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binop2addr.S" {"instr":"mod a0, a0, a1", "chkzero":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_rem_int_lit16.S b/runtime/interpreter/mterp/mips64/op_rem_int_lit16.S
new file mode 100644
index 0000000..3284f14
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_rem_int_lit16.S
@@ -0,0 +1 @@
+%include "mips64/binopLit16.S" {"instr":"mod a0, a0, a1", "chkzero":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_rem_int_lit8.S b/runtime/interpreter/mterp/mips64/op_rem_int_lit8.S
new file mode 100644
index 0000000..1e6a584
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_rem_int_lit8.S
@@ -0,0 +1 @@
+%include "mips64/binopLit8.S" {"instr":"mod a0, a0, a1", "chkzero":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_rem_long.S b/runtime/interpreter/mterp/mips64/op_rem_long.S
new file mode 100644
index 0000000..32b2d19
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_rem_long.S
@@ -0,0 +1 @@
+%include "mips64/binopWide.S" {"instr":"dmod a0, a0, a1", "chkzero":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_rem_long_2addr.S b/runtime/interpreter/mterp/mips64/op_rem_long_2addr.S
new file mode 100644
index 0000000..ad658e1
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_rem_long_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binopWide2addr.S" {"instr":"dmod a0, a0, a1", "chkzero":"1"}
diff --git a/runtime/interpreter/mterp/mips64/op_return.S b/runtime/interpreter/mterp/mips64/op_return.S
new file mode 100644
index 0000000..ec986b8
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_return.S
@@ -0,0 +1,18 @@
+    /*
+     * Return a 32-bit value.
+     *
+     * for: return, return-object
+     */
+    /* op vAA */
+    .extern MterpThreadFenceForConstructor
+    .extern MterpSuspendCheck
+    jal     MterpThreadFenceForConstructor
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)
+    move    a0, rSELF
+    and     ra, ra, (THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    beqzc   ra, 1f
+    jal     MterpSuspendCheck           # (self)
+1:
+    srl     a2, rINST, 8                # a2 <- AA
+    GET_VREG_U a0, a2                   # a0 <- vAA
+    b       MterpReturn
diff --git a/runtime/interpreter/mterp/mips64/op_return_object.S b/runtime/interpreter/mterp/mips64/op_return_object.S
new file mode 100644
index 0000000..67f1871
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_return_object.S
@@ -0,0 +1 @@
+%include "mips64/op_return.S"
diff --git a/runtime/interpreter/mterp/mips64/op_return_void.S b/runtime/interpreter/mterp/mips64/op_return_void.S
new file mode 100644
index 0000000..05253ae
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_return_void.S
@@ -0,0 +1,11 @@
+    .extern MterpThreadFenceForConstructor
+    .extern MterpSuspendCheck
+    jal     MterpThreadFenceForConstructor
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)
+    move    a0, rSELF
+    and     ra, ra, (THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    beqzc   ra, 1f
+    jal     MterpSuspendCheck           # (self)
+1:
+    li      a0, 0
+    b       MterpReturn
diff --git a/runtime/interpreter/mterp/mips64/op_return_void_no_barrier.S b/runtime/interpreter/mterp/mips64/op_return_void_no_barrier.S
new file mode 100644
index 0000000..f67e811
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_return_void_no_barrier.S
@@ -0,0 +1,9 @@
+    .extern MterpSuspendCheck
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)
+    move    a0, rSELF
+    and     ra, ra, (THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    beqzc   ra, 1f
+    jal     MterpSuspendCheck           # (self)
+1:
+    li      a0, 0
+    b       MterpReturn
diff --git a/runtime/interpreter/mterp/mips64/op_return_wide.S b/runtime/interpreter/mterp/mips64/op_return_wide.S
new file mode 100644
index 0000000..544e027
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_return_wide.S
@@ -0,0 +1,17 @@
+    /*
+     * Return a 64-bit value.
+     */
+    /* return-wide vAA */
+    /* op vAA */
+    .extern MterpThreadFenceForConstructor
+    .extern MterpSuspendCheck
+    jal     MterpThreadFenceForConstructor
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)
+    move    a0, rSELF
+    and     ra, ra, (THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
+    beqzc   ra, 1f
+    jal     MterpSuspendCheck           # (self)
+1:
+    srl     a2, rINST, 8                # a2 <- AA
+    GET_VREG_WIDE a0, a2                # a0 <- vAA
+    b       MterpReturn
diff --git a/runtime/interpreter/mterp/mips64/op_rsub_int.S b/runtime/interpreter/mterp/mips64/op_rsub_int.S
new file mode 100644
index 0000000..fa31a0a
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_rsub_int.S
@@ -0,0 +1 @@
+%include "mips64/binopLit16.S" {"instr":"subu a0, a1, a0"}
diff --git a/runtime/interpreter/mterp/mips64/op_rsub_int_lit8.S b/runtime/interpreter/mterp/mips64/op_rsub_int_lit8.S
new file mode 100644
index 0000000..c31ff32
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_rsub_int_lit8.S
@@ -0,0 +1 @@
+%include "mips64/binopLit8.S" {"instr":"subu a0, a1, a0"}
diff --git a/runtime/interpreter/mterp/mips64/op_sget.S b/runtime/interpreter/mterp/mips64/op_sget.S
new file mode 100644
index 0000000..bd2cfe3
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sget.S
@@ -0,0 +1,26 @@
+%default { "is_object":"0", "helper":"artGet32StaticFromCode", "extend":"" }
+    /*
+     * General SGET handler wrapper.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field//BBBB */
+    .extern $helper
+    EXPORT_PC
+    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
+    ld      a1, OFF_FP_METHOD(rFP)
+    move    a2, rSELF
+    jal     $helper
+    ld      a3, THREAD_EXCEPTION_OFFSET(rSELF)
+    srl     a2, rINST, 8                # a2 <- AA
+    $extend
+    PREFETCH_INST 2
+    bnez    a3, MterpException          # bail out
+    .if $is_object
+    SET_VREG_OBJECT v0, a2              # fp[AA] <- v0
+    .else
+    SET_VREG v0, a2                     # fp[AA] <- v0
+    .endif
+    ADVANCE 2
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0
diff --git a/runtime/interpreter/mterp/mips64/op_sget_boolean.S b/runtime/interpreter/mterp/mips64/op_sget_boolean.S
new file mode 100644
index 0000000..e7b1844
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sget_boolean.S
@@ -0,0 +1 @@
+%include "mips64/op_sget.S" {"helper":"artGetBooleanStaticFromCode", "extend":"and v0, v0, 0xff"}
diff --git a/runtime/interpreter/mterp/mips64/op_sget_byte.S b/runtime/interpreter/mterp/mips64/op_sget_byte.S
new file mode 100644
index 0000000..52a2e4a
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sget_byte.S
@@ -0,0 +1 @@
+%include "mips64/op_sget.S" {"helper":"artGetByteStaticFromCode", "extend":"seb v0, v0"}
diff --git a/runtime/interpreter/mterp/mips64/op_sget_char.S b/runtime/interpreter/mterp/mips64/op_sget_char.S
new file mode 100644
index 0000000..873d82a
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sget_char.S
@@ -0,0 +1 @@
+%include "mips64/op_sget.S" {"helper":"artGetCharStaticFromCode", "extend":"and v0, v0, 0xffff"}
diff --git a/runtime/interpreter/mterp/mips64/op_sget_object.S b/runtime/interpreter/mterp/mips64/op_sget_object.S
new file mode 100644
index 0000000..3108417
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sget_object.S
@@ -0,0 +1 @@
+%include "mips64/op_sget.S" {"is_object":"1", "helper":"artGetObjStaticFromCode"}
diff --git a/runtime/interpreter/mterp/mips64/op_sget_short.S b/runtime/interpreter/mterp/mips64/op_sget_short.S
new file mode 100644
index 0000000..fed4e76
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sget_short.S
@@ -0,0 +1 @@
+%include "mips64/op_sget.S" {"helper":"artGetShortStaticFromCode", "extend":"seh v0, v0"}
diff --git a/runtime/interpreter/mterp/mips64/op_sget_wide.S b/runtime/interpreter/mterp/mips64/op_sget_wide.S
new file mode 100644
index 0000000..77124d1
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sget_wide.S
@@ -0,0 +1,18 @@
+    /*
+     * SGET_WIDE handler wrapper.
+     *
+     */
+    /* sget-wide vAA, field//BBBB */
+    .extern artGet64StaticFromCode
+    EXPORT_PC
+    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
+    ld      a1, OFF_FP_METHOD(rFP)
+    move    a2, rSELF
+    jal     artGet64StaticFromCode
+    ld      a3, THREAD_EXCEPTION_OFFSET(rSELF)
+    srl     a4, rINST, 8                # a4 <- AA
+    bnez    a3, MterpException          # bail out
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    SET_VREG_WIDE v0, a4
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_shl_int.S b/runtime/interpreter/mterp/mips64/op_shl_int.S
new file mode 100644
index 0000000..784481f
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_shl_int.S
@@ -0,0 +1 @@
+%include "mips64/binop.S" {"instr":"sll a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_shl_int_2addr.S b/runtime/interpreter/mterp/mips64/op_shl_int_2addr.S
new file mode 100644
index 0000000..a6c8a78
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_shl_int_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binop2addr.S" {"instr":"sll a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_shl_int_lit8.S b/runtime/interpreter/mterp/mips64/op_shl_int_lit8.S
new file mode 100644
index 0000000..36ef207
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_shl_int_lit8.S
@@ -0,0 +1 @@
+%include "mips64/binopLit8.S" {"instr":"sll a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_shl_long.S b/runtime/interpreter/mterp/mips64/op_shl_long.S
new file mode 100644
index 0000000..225a2cb
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_shl_long.S
@@ -0,0 +1 @@
+%include "mips64/binopWide.S" {"instr":"dsll a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_shl_long_2addr.S b/runtime/interpreter/mterp/mips64/op_shl_long_2addr.S
new file mode 100644
index 0000000..c04d882
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_shl_long_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binopWide2addr.S" {"instr":"dsll a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_shr_int.S b/runtime/interpreter/mterp/mips64/op_shr_int.S
new file mode 100644
index 0000000..eded037
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_shr_int.S
@@ -0,0 +1 @@
+%include "mips64/binop.S" {"instr":"sra a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_shr_int_2addr.S b/runtime/interpreter/mterp/mips64/op_shr_int_2addr.S
new file mode 100644
index 0000000..5b4d96f
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_shr_int_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binop2addr.S" {"instr":"sra a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_shr_int_lit8.S b/runtime/interpreter/mterp/mips64/op_shr_int_lit8.S
new file mode 100644
index 0000000..175eb86
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_shr_int_lit8.S
@@ -0,0 +1 @@
+%include "mips64/binopLit8.S" {"instr":"sra a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_shr_long.S b/runtime/interpreter/mterp/mips64/op_shr_long.S
new file mode 100644
index 0000000..0db38c8
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_shr_long.S
@@ -0,0 +1 @@
+%include "mips64/binopWide.S" {"instr":"dsra a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_shr_long_2addr.S b/runtime/interpreter/mterp/mips64/op_shr_long_2addr.S
new file mode 100644
index 0000000..48131ad
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_shr_long_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binopWide2addr.S" {"instr":"dsra a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_sparse_switch.S b/runtime/interpreter/mterp/mips64/op_sparse_switch.S
new file mode 100644
index 0000000..b065aaa
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sparse_switch.S
@@ -0,0 +1 @@
+%include "mips64/op_packed_switch.S" { "func":"MterpDoSparseSwitch" }
diff --git a/runtime/interpreter/mterp/mips64/op_sput.S b/runtime/interpreter/mterp/mips64/op_sput.S
new file mode 100644
index 0000000..142f18f
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sput.S
@@ -0,0 +1,20 @@
+%default { "helper":"artSet32StaticFromCode" }
+    /*
+     * General SPUT handler wrapper.
+     *
+     * for: sput, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field//BBBB */
+    .extern $helper
+    EXPORT_PC
+    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
+    srl     a3, rINST, 8                # a3 <- AA
+    GET_VREG a1, a3                     # a1 <- fp[AA]
+    ld      a2, OFF_FP_METHOD(rFP)
+    move    a3, rSELF
+    PREFETCH_INST 2                     # Get next inst, but don't advance rPC
+    jal     $helper
+    bnezc   v0, MterpException          # 0 on success
+    ADVANCE 2                           # Past exception point - now advance rPC
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_sput_boolean.S b/runtime/interpreter/mterp/mips64/op_sput_boolean.S
new file mode 100644
index 0000000..f5b8dbf
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sput_boolean.S
@@ -0,0 +1 @@
+%include "mips64/op_sput.S" {"helper":"artSet8StaticFromCode"}
diff --git a/runtime/interpreter/mterp/mips64/op_sput_byte.S b/runtime/interpreter/mterp/mips64/op_sput_byte.S
new file mode 100644
index 0000000..f5b8dbf
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sput_byte.S
@@ -0,0 +1 @@
+%include "mips64/op_sput.S" {"helper":"artSet8StaticFromCode"}
diff --git a/runtime/interpreter/mterp/mips64/op_sput_char.S b/runtime/interpreter/mterp/mips64/op_sput_char.S
new file mode 100644
index 0000000..c4d195c
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sput_char.S
@@ -0,0 +1 @@
+%include "mips64/op_sput.S" {"helper":"artSet16StaticFromCode"}
diff --git a/runtime/interpreter/mterp/mips64/op_sput_object.S b/runtime/interpreter/mterp/mips64/op_sput_object.S
new file mode 100644
index 0000000..ef4c685
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sput_object.S
@@ -0,0 +1,11 @@
+    .extern MterpSputObject
+    EXPORT_PC
+    daddu   a0, rFP, OFF_FP_SHADOWFRAME
+    move    a1, rPC
+    move    a2, rINST
+    move    a3, rSELF
+    jal     MterpSputObject
+    beqzc   v0, MterpException
+    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_sput_short.S b/runtime/interpreter/mterp/mips64/op_sput_short.S
new file mode 100644
index 0000000..c4d195c
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sput_short.S
@@ -0,0 +1 @@
+%include "mips64/op_sput.S" {"helper":"artSet16StaticFromCode"}
diff --git a/runtime/interpreter/mterp/mips64/op_sput_wide.S b/runtime/interpreter/mterp/mips64/op_sput_wide.S
new file mode 100644
index 0000000..828ddc1
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sput_wide.S
@@ -0,0 +1,18 @@
+    /*
+     * SPUT_WIDE handler wrapper.
+     *
+     */
+    /* sput-wide vAA, field//BBBB */
+    .extern artSet64IndirectStaticFromMterp
+    EXPORT_PC
+    lhu     a0, 2(rPC)                  # a0 <- field ref BBBB
+    ld      a1, OFF_FP_METHOD(rFP)
+    srl     a2, rINST, 8                # a2 <- AA
+    dlsa    a2, a2, rFP, 2
+    move    a3, rSELF
+    PREFETCH_INST 2                     # Get next inst, but don't advance rPC
+    jal     artSet64IndirectStaticFromMterp
+    bnezc   v0, MterpException          # 0 on success, -1 on failure
+    ADVANCE 2                           # Past exception point - now advance rPC
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/op_sub_double.S b/runtime/interpreter/mterp/mips64/op_sub_double.S
new file mode 100644
index 0000000..40a6c89
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sub_double.S
@@ -0,0 +1 @@
+%include "mips64/fbinopWide.S" {"instr":"sub.d f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_sub_double_2addr.S b/runtime/interpreter/mterp/mips64/op_sub_double_2addr.S
new file mode 100644
index 0000000..984737e
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sub_double_2addr.S
@@ -0,0 +1 @@
+%include "mips64/fbinopWide2addr.S" {"instr":"sub.d f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_sub_float.S b/runtime/interpreter/mterp/mips64/op_sub_float.S
new file mode 100644
index 0000000..9010592
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sub_float.S
@@ -0,0 +1 @@
+%include "mips64/fbinop.S" {"instr":"sub.s f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_sub_float_2addr.S b/runtime/interpreter/mterp/mips64/op_sub_float_2addr.S
new file mode 100644
index 0000000..e7d4ffe
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sub_float_2addr.S
@@ -0,0 +1 @@
+%include "mips64/fbinop2addr.S" {"instr":"sub.s f0, f0, f1"}
diff --git a/runtime/interpreter/mterp/mips64/op_sub_int.S b/runtime/interpreter/mterp/mips64/op_sub_int.S
new file mode 100644
index 0000000..609ea05
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sub_int.S
@@ -0,0 +1 @@
+%include "mips64/binop.S" {"instr":"subu a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_sub_int_2addr.S b/runtime/interpreter/mterp/mips64/op_sub_int_2addr.S
new file mode 100644
index 0000000..ba2f1e8
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sub_int_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binop2addr.S" {"instr":"subu a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_sub_long.S b/runtime/interpreter/mterp/mips64/op_sub_long.S
new file mode 100644
index 0000000..09a6afd
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sub_long.S
@@ -0,0 +1 @@
+%include "mips64/binopWide.S" {"instr":"dsubu a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_sub_long_2addr.S b/runtime/interpreter/mterp/mips64/op_sub_long_2addr.S
new file mode 100644
index 0000000..b9ec82a
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_sub_long_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binopWide2addr.S" {"instr":"dsubu a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_throw.S b/runtime/interpreter/mterp/mips64/op_throw.S
new file mode 100644
index 0000000..6418d57
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_throw.S
@@ -0,0 +1,10 @@
+    /*
+     * Throw an exception object in the current thread.
+     */
+    /* throw vAA */
+    EXPORT_PC
+    srl     a2, rINST, 8                # a2 <- AA
+    GET_VREG_U a0, a2                   # a0 <- vAA (exception object)
+    beqzc   a0, common_errNullObject
+    sd      a0, THREAD_EXCEPTION_OFFSET(rSELF)  # thread->exception <- obj
+    b       MterpException
diff --git a/runtime/interpreter/mterp/mips64/op_unused_3e.S b/runtime/interpreter/mterp/mips64/op_unused_3e.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_3e.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_3f.S b/runtime/interpreter/mterp/mips64/op_unused_3f.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_3f.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_40.S b/runtime/interpreter/mterp/mips64/op_unused_40.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_40.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_41.S b/runtime/interpreter/mterp/mips64/op_unused_41.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_41.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_42.S b/runtime/interpreter/mterp/mips64/op_unused_42.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_42.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_43.S b/runtime/interpreter/mterp/mips64/op_unused_43.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_43.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_79.S b/runtime/interpreter/mterp/mips64/op_unused_79.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_79.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_7a.S b/runtime/interpreter/mterp/mips64/op_unused_7a.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_7a.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_f4.S b/runtime/interpreter/mterp/mips64/op_unused_f4.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_f4.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_fa.S b/runtime/interpreter/mterp/mips64/op_unused_fa.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_fa.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_fb.S b/runtime/interpreter/mterp/mips64/op_unused_fb.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_fb.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_fc.S b/runtime/interpreter/mterp/mips64/op_unused_fc.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_fc.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_fd.S b/runtime/interpreter/mterp/mips64/op_unused_fd.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_fd.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_fe.S b/runtime/interpreter/mterp/mips64/op_unused_fe.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_fe.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_unused_ff.S b/runtime/interpreter/mterp/mips64/op_unused_ff.S
new file mode 100644
index 0000000..29463d7
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_unused_ff.S
@@ -0,0 +1 @@
+%include "mips64/unused.S"
diff --git a/runtime/interpreter/mterp/mips64/op_ushr_int.S b/runtime/interpreter/mterp/mips64/op_ushr_int.S
new file mode 100644
index 0000000..37c90cb
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_ushr_int.S
@@ -0,0 +1 @@
+%include "mips64/binop.S" {"instr":"srl a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_ushr_int_2addr.S b/runtime/interpreter/mterp/mips64/op_ushr_int_2addr.S
new file mode 100644
index 0000000..d6bf413
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_ushr_int_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binop2addr.S" {"instr":"srl a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_ushr_int_lit8.S b/runtime/interpreter/mterp/mips64/op_ushr_int_lit8.S
new file mode 100644
index 0000000..2a2d843
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_ushr_int_lit8.S
@@ -0,0 +1 @@
+%include "mips64/binopLit8.S" {"instr":"srl a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_ushr_long.S b/runtime/interpreter/mterp/mips64/op_ushr_long.S
new file mode 100644
index 0000000..e724405
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_ushr_long.S
@@ -0,0 +1 @@
+%include "mips64/binopWide.S" {"instr":"dsrl a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_ushr_long_2addr.S b/runtime/interpreter/mterp/mips64/op_ushr_long_2addr.S
new file mode 100644
index 0000000..d2cf135
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_ushr_long_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binopWide2addr.S" {"instr":"dsrl a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_xor_int.S b/runtime/interpreter/mterp/mips64/op_xor_int.S
new file mode 100644
index 0000000..ee25ebc
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_xor_int.S
@@ -0,0 +1 @@
+%include "mips64/binop.S" {"instr":"xor a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_xor_int_2addr.S b/runtime/interpreter/mterp/mips64/op_xor_int_2addr.S
new file mode 100644
index 0000000..0f04967
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_xor_int_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binop2addr.S" {"instr":"xor a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_xor_int_lit16.S b/runtime/interpreter/mterp/mips64/op_xor_int_lit16.S
new file mode 100644
index 0000000..ecb21ae
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_xor_int_lit16.S
@@ -0,0 +1 @@
+%include "mips64/binopLit16.S" {"instr":"xor a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_xor_int_lit8.S b/runtime/interpreter/mterp/mips64/op_xor_int_lit8.S
new file mode 100644
index 0000000..115ae99
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_xor_int_lit8.S
@@ -0,0 +1 @@
+%include "mips64/binopLit8.S" {"instr":"xor a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_xor_long.S b/runtime/interpreter/mterp/mips64/op_xor_long.S
new file mode 100644
index 0000000..7ebabc2
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_xor_long.S
@@ -0,0 +1 @@
+%include "mips64/binopWide.S" {"instr":"xor a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/op_xor_long_2addr.S b/runtime/interpreter/mterp/mips64/op_xor_long_2addr.S
new file mode 100644
index 0000000..0f1919a
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/op_xor_long_2addr.S
@@ -0,0 +1 @@
+%include "mips64/binopWide2addr.S" {"instr":"xor a0, a0, a1"}
diff --git a/runtime/interpreter/mterp/mips64/unop.S b/runtime/interpreter/mterp/mips64/unop.S
new file mode 100644
index 0000000..e3f7ea0
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/unop.S
@@ -0,0 +1,18 @@
+%default {"preinstr":""}
+    /*
+     * Generic 32-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "a0 = op a0".
+     *
+     * for: int-to-byte, int-to-char, int-to-short,
+     *      not-int, neg-int
+     */
+    /* unop vA, vB */
+    ext     a3, rINST, 12, 4            # a3 <- B
+    GET_VREG a0, a3                     # a0 <- vB
+    ext     a2, rINST, 8, 4             # a2 <- A
+    $preinstr                           # optional op
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    $instr                              # a0 <- op, a0-a3 changed
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG a0, a2                     # vA <- a0
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/unopWide.S b/runtime/interpreter/mterp/mips64/unopWide.S
new file mode 100644
index 0000000..c0dd1aa
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/unopWide.S
@@ -0,0 +1,17 @@
+%default {"preinstr":""}
+    /*
+     * Generic 64-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "a0 = op a0".
+     *
+     * For: not-long, neg-long
+     */
+    /* unop vA, vB */
+    ext     a3, rINST, 12, 4            # a3 <- B
+    GET_VREG_WIDE a0, a3                # a0 <- vB
+    ext     a2, rINST, 8, 4             # a2 <- A
+    $preinstr                           # optional op
+    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
+    $instr                              # a0 <- op, a0-a3 changed
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_WIDE a0, a2                # vA <- a0
+    GOTO_OPCODE v0                      # jump to next instruction
diff --git a/runtime/interpreter/mterp/mips64/unused.S b/runtime/interpreter/mterp/mips64/unused.S
new file mode 100644
index 0000000..30d38bd
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/unused.S
@@ -0,0 +1,4 @@
+/*
+ * Bail to reference interpreter to throw.
+ */
+    b       MterpFallback
diff --git a/runtime/interpreter/mterp/mips64/zcmp.S b/runtime/interpreter/mterp/mips64/zcmp.S
new file mode 100644
index 0000000..d7ad894
--- /dev/null
+++ b/runtime/interpreter/mterp/mips64/zcmp.S
@@ -0,0 +1,30 @@
+    /*
+     * Generic one-operand compare-and-branch operation.  Provide a "condition"
+     * fragment that specifies the comparison to perform, e.g. for
+     * "if-lez" you would use "le".
+     *
+     * For: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+     */
+    /* if-cmp vAA, +BBBB */
+    lh      a4, 2(rPC)                  # a4 <- sign-extended BBBB
+    srl     a2, rINST, 8                # a2 <- AA
+    GET_VREG a0, a2                     # a0 <- vAA
+
+    b${condition}zc a0, 1f
+    li      a4, 2                       # offset if branch not taken
+1:
+
+    dlsa    rPC, a4, rPC, 1             # rPC <- rPC + BBBB * 2
+    FETCH_INST                          # load rINST
+
+#if MTERP_SUSPEND
+    bgez    a4, 2f                      # BBBB * 2 >= 0 => no suspend check
+    REFRESH_IBASE
+2:
+#else
+    lw      ra, THREAD_FLAGS_OFFSET(rSELF)  # Preload flags for MterpCheckSuspendAndContinue
+    bltz    a4, MterpCheckSuspendAndContinue
+#endif
+
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    GOTO_OPCODE v0                      # jump to next instruction