Rewrite the invoke stubs to use JValue[]s.

The tests were only testing the static stubs, so extend the tests to include
non-static stubs too.

Also add just enough of an ARM disassembler to disassemble the invoke stubs.

Change-Id: If71dfb66b8b8188f9d871914f0eaf1013c9993b9
diff --git a/src/disassembler_arm.cc b/src/disassembler_arm.cc
index b2ddc2c..bbdc37e 100644
--- a/src/disassembler_arm.cc
+++ b/src/disassembler_arm.cc
@@ -42,7 +42,7 @@
   }
 }
 
-static const char* ConditionCodeNames[] = {
+static const char* kConditionCodeNames[] = {
     "EQ",  // 0000 - equal
     "NE",  // 0001 - not-equal
     "CS",  // 0010 - carry-set, greater than, equal or unordered
@@ -57,12 +57,12 @@
     "LT",  // 1011 - signed less than
     "GT",  // 1100 - signed greater than
     "LE",  // 1101 - signed less than or equal
-    "AL",  // 1110 - always
+    "",    // 1110 - always
 };
 
 void DisassemblerArm::DumpCond(std::ostream& os, uint32_t cond) {
   if (cond < 15) {
-    os << ConditionCodeNames[cond];
+    os << kConditionCodeNames[cond];
   } else {
     os << "Unexpected condition: " << cond;
   }
@@ -73,30 +73,10 @@
     case 13: os << "SP"; break;
     case 14: os << "LR"; break;
     case 15: os << "PC"; break;
-    default: os << "r" << reg; break;
+    default: os << "R" << reg; break;
   }
 }
 
-void DisassemblerArm::DumpRegList(std::ostream& os, uint32_t reg_list) {
-  if (reg_list == 0) {
-    os << "<no register list?>";
-    return;
-  }
-  bool first = true;
-  for (size_t i = 0; i < 16; i++) {
-    if ((reg_list & (1 << i)) != 0) {
-      if (first) {
-        os << "{";
-        first = false;
-      } else {
-        os << ", ";
-      }
-      DumpReg(os, i);
-    }
-  }
-  os << "}";
-}
-
 void DisassemblerArm::DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32) {
   os << imm32 << " (" << reinterpret_cast<const void*>(instr_ptr + imm32) << ")";
 }
@@ -109,9 +89,155 @@
   return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
 }
 
+static const char* kDataProcessingOperations[] = {
+  "AND", "EOR", "SUB", "RSB", "ADD", "ADC", "SBC", "RSC",
+  "TST", "TEQ", "CMP", "CMN", "ORR", "MOV", "BIC", "MVN",
+};
+
+struct ArmRegister {
+  ArmRegister(uint32_t r) : r(r) { CHECK_LE(r, 15U); }
+  uint32_t r;
+};
+std::ostream& operator<<(std::ostream& os, const ArmRegister& r) {
+  if (r.r == 13) {
+    os << "SP";
+  } else if (r.r == 14) {
+    os << "LR";
+  } else if (r.r == 15) {
+    os << "PC";
+  } else {
+    os << "R" << r.r;
+  }
+  return os;
+}
+
+struct Rd : ArmRegister {
+  Rd(uint32_t instruction) : ArmRegister((instruction >> 12) & 0xf) {}
+};
+typedef Rd Rt;
+struct Rn : ArmRegister {
+  Rn(uint32_t instruction) : ArmRegister((instruction >> 16) & 0xf) {}
+};
+
+struct Rm {
+  Rm(uint32_t instruction) : shift((instruction >> 4) & 0xff), rm(instruction & 0xf) {}
+  uint32_t shift;
+  ArmRegister rm;
+};
+std::ostream& operator<<(std::ostream& os, const Rm& r) {
+  os << r.rm;
+  if (r.shift != 0) {
+    os << "-shift-" << r.shift; // TODO
+  }
+  return os;
+}
+
+struct Imm12 {
+  Imm12(uint32_t instruction) : rotate((instruction >> 8) & 0xf), imm(instruction & 0xff) {}
+  uint32_t rotate;
+  uint32_t imm;
+};
+std::ostream& operator<<(std::ostream& os, const Imm12& rhs) {
+  uint32_t imm = (rhs.imm >> (2 * rhs.rotate)) | (rhs.imm << (32 - (2 * rhs.rotate)));
+  os << "#" << imm;
+  return os;
+}
+
+struct RegisterList {
+  RegisterList(uint32_t instruction) : register_list(instruction & 0xffff) {}
+  uint32_t register_list;
+};
+std::ostream& operator<<(std::ostream& os, const RegisterList& rhs) {
+  if (rhs.register_list == 0) {
+    os << "<no register list?>";
+    return os;
+  }
+  bool first = true;
+  for (size_t i = 0; i < 16; i++) {
+    if ((rhs.register_list & (1 << i)) != 0) {
+      if (first) {
+        os << "{";
+        first = false;
+      } else {
+        os << ", ";
+      }
+      os << ArmRegister(i);
+    }
+  }
+  os << "}";
+  return os;
+}
 
 void DisassemblerArm::DumpArm(std::ostream& os, const uint8_t* instr_ptr) {
-  os << StringPrintf("\t\t\t%p: %08x\n", instr_ptr, ReadU32(instr_ptr));
+  uint32_t instruction = ReadU32(instr_ptr);
+  uint32_t cond = (instruction >> 28) & 0xf;
+  uint32_t op1 = (instruction >> 25) & 0x7;
+  os << StringPrintf("\t\t\t%p: %08x: ", instr_ptr, instruction);
+  switch (op1) {
+    case 0:
+    case 1: // Data processing instructions.
+      {
+        if ((instruction & 0x0fffffd0) == 0x012fff10) { // BX and BLX (register)
+          os << (((instruction >> 5) & 1) ? "BLX" : "BX") << " " << ArmRegister(instruction & 0xf);
+          break;
+        }
+        bool i = (instruction & (1 << 25)) != 0;
+        bool s = (instruction & (1 << 20)) != 0;
+        os << kDataProcessingOperations[(instruction >> 21) & 0xf]
+           << kConditionCodeNames[cond]
+           << (s ? "S" : "")
+           << " "
+           << Rd(instruction) << ", ";
+        if (i) {
+          os << Rn(instruction) << ", " << Imm12(instruction);
+        } else {
+          os << Rm(instruction);
+        }
+      }
+      break;
+    case 2: // Load/store word and unsigned byte.
+      {
+        bool p = (instruction & (1 << 24)) != 0;
+        bool b = (instruction & (1 << 22)) != 0;
+        bool w = (instruction & (1 << 21)) != 0;
+        bool l = (instruction & (1 << 20)) != 0;
+        os << (l ? "LDR" : "STR") << (b ? "B" : "") << kConditionCodeNames[cond] << " ";
+        os << Rt(instruction) << ", ";
+        if (Rn(instruction).r == 0xf) {
+          UNIMPLEMENTED(FATAL) << "literals";
+        } else {
+          bool wback = !p || w;
+          if (p && !wback) {
+            os << "[" << Rn(instruction) << ", " << Imm12(instruction) << "]";
+          } else if (p && wback) {
+            os << "[" << Rn(instruction) << ", " << Imm12(instruction) << "]!";
+          } else if (!p && wback) {
+            os << "[" << Rn(instruction) << "], " << Imm12(instruction);
+          } else {
+            LOG(FATAL) << p << " " << w;
+          }
+        }
+      }
+      break;
+    case 4: // Load/store multiple.
+      {
+        bool p = (instruction & (1 << 24)) != 0;
+        bool u = (instruction & (1 << 23)) != 0;
+        bool w = (instruction & (1 << 21)) != 0;
+        bool l = (instruction & (1 << 20)) != 0;
+        os << StringPrintf("%s%c%c%s ",
+                           l ? "LDM" : "STM",
+                           u ? 'I' : 'D',
+                           p ? 'B' : 'A',
+                           kConditionCodeNames[cond]);
+        os << Rn(instruction) << (w ? "!" : "") << ", " << RegisterList(instruction);
+      }
+      break;
+    default:
+      os << "???";
+      break;
+    }
+    os << '\n';
 }
 
 size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) {
@@ -124,11 +250,14 @@
   // |---|---|-------|----|----------------|
   // |111|op1| op2   |    |                |
   uint32_t op1 = (instr >> 27) & 3;
+  if (op1 == 0) {
+    return DumpThumb16(os, instr_ptr);
+  }
+
   uint32_t op2 = (instr >> 20) & 0x7F;
-  os << StringPrintf("\t\t\t%p: ", instr_ptr);
+  os << StringPrintf("\t\t\t%p: %08x: ", instr_ptr, instr);
   switch (op1) {
     case 0:
-      return DumpThumb16(os, instr_ptr);
       break;
     case 1:
       switch (op2) {
@@ -150,7 +279,6 @@
           uint32_t W = (instr >> 21) & 1;
           uint32_t L = (instr >> 20) & 1;
           uint32_t Rn = (instr >> 16) & 0xF;
-          uint32_t reg_list = instr & 0xFFFF;
           if (op == 1 || op == 2) {
             if (op == 1) {
               if (L == 0) {
@@ -197,8 +325,7 @@
                 }
               }
             }
-            DumpRegList(os, reg_list);
-            os << "  // ";
+            os << RegisterList(instr);
           }
           break;
         }
@@ -247,7 +374,7 @@
         DumpReg(os, Rd);
         os << ", ";
         DumpReg(os, Rn);
-        os << ", ThumbExpand(" << imm32 << ")  // ";
+        os << ", ThumbExpand(" << imm32 << ")";
       } else if ((instr & 0x8000) == 0 && (op2 & 0x20) != 0) {
         // Data-processing (plain binary immediate)
         // |111|11|10|00000|0000|1|111110000000000|
@@ -269,7 +396,7 @@
             uint32_t imm16 = (Rn << 12) | (i << 11) | (imm3 << 8) | imm8;
             os << "MOVW ";
             DumpReg(os, Rd);
-            os << ", #" << imm16 << "  // ";
+            os << ", #" << imm16;
             break;
           }
           case 0x0A: {
@@ -283,7 +410,7 @@
             DumpReg(os, Rd);
             os << ", ";
             DumpReg(os, Rn);
-            os << ", #" << imm12 << "  // ";
+            os << ", #" << imm12;
             break;
           }
           default:
@@ -324,7 +451,6 @@
               DumpCond(os, cond);
               os << ".W ";
               DumpBranchTarget(os, instr_ptr + 4, imm32);
-              os << "  // ";
             }
             break;
           case 2:
@@ -390,7 +516,6 @@
                 if (Rn == 13 && P == 1 && U == 0 && W == 1) {
                   os << "PUSH ";
                   DumpReg(os, Rt);
-                  os << "  // ";
                 } else if (Rn == 15 || (P == 0 && W == 0)) {
                   os << "UNDEFINED ";
                 } else {
@@ -410,7 +535,6 @@
                       os << "!";
                     }
                   }
-                  os << "  // ";
                 }
               } else if (op3 == 6) {
                 uint32_t imm12 = instr & 0xFFF;
@@ -418,7 +542,7 @@
                 DumpReg(os, Rt);
                 os << ", [";
                 DumpReg(os, Rn);
-                os << ", #" << imm12 << "]  // ";
+                os << ", #" << imm12 << "]";
               }
               break;
             }
@@ -448,21 +572,21 @@
             DumpReg(os, Rt);
             os << ", [";
             DumpReg(os, Rn);
-            os << ", #" << imm12 << "]  // ";
+            os << ", #" << imm12 << "]";
           } else if (op4 == 0) {
             // LDR.W Rt, [Rn, Rm{, LSL #imm2}] - 111 11 00 00 101 nnnn tttt 000000iimmmm
             uint32_t imm2 = (instr >> 4) & 0xF;
-            uint32_t Rm = instr & 0xF;
+            uint32_t rm = instr & 0xF;
             os << "LDR.W ";
             DumpReg(os, Rt);
             os << ", [";
             DumpReg(os, Rn);
             os << ", ";
-            DumpReg(os, Rm);
+            DumpReg(os, rm);
             if (imm2 != 0) {
               os << ", LSL #" << imm2;
             }
-            os << "]  // ";
+            os << "]";
           } else {
             // LDRT Rt, [Rn, #imm8]            - 111 11 00 00 101 nnnn tttt 1110iiiiiiii
             uint32_t imm8 = instr & 0xFF;
@@ -470,7 +594,7 @@
             DumpReg(os, Rt);
             os << ", [";
             DumpReg(os, Rn);
-            os << ", #" << imm8 << "]  // ";
+            os << ", #" << imm8 << "]";
           }
           break;
         }
@@ -478,7 +602,7 @@
     default:
       break;
   }
-  os << StringPrintf("%08x\n", instr);
+  os << '\n';
   return 4;
 }
 
@@ -488,7 +612,7 @@
   if (is_32bit) {
     return DumpThumb32(os, instr_ptr);
   } else {
-    os << StringPrintf("\t\t\t%p: ", instr_ptr);
+    os << StringPrintf("\t\t\t%p: %04x    : ", instr_ptr, instr);
     uint16_t opcode1 = instr >> 10;
     if (opcode1 < 0x10) {
       // shift (immediate), add, subtract, move, and compare
@@ -500,7 +624,7 @@
           // Logical shift right    - 00 001xx xxxxxxxxx
           // Arithmetic shift right - 00 010xx xxxxxxxxx
           uint16_t imm5 = (instr >> 6) & 0x1F;
-          uint16_t Rm = (instr >> 3) & 7;
+          uint16_t rm = (instr >> 3) & 7;
           uint16_t Rd = instr & 7;
           if (opcode2 <= 3) {
             os << "LSLS ";
@@ -511,8 +635,8 @@
           }
           DumpReg(os, Rd);
           os << ", ";
-          DumpReg(os, Rm);
-          os << ", #" << imm5 << "  // ";
+          DumpReg(os, rm);
+          os << ", #" << imm5;
           break;
         }
         case 0xC: case 0xD: case 0xE: case 0xF: {
@@ -541,7 +665,6 @@
           } else if (imm3_or_Rm != 0) {
             os << ", #" << imm3_or_Rm;
           }
-          os << "  // ";
           break;
         }
         case 0x10: case 0x11: case 0x12: case 0x13:
@@ -561,7 +684,7 @@
             case 7: os << "SUBS "; break;
           }
           DumpReg(os, Rn);
-          os << ", #" << imm8 << "  // ";
+          os << ", #" << imm8;
           break;
         }
         default:
@@ -575,54 +698,50 @@
           // Add low registers  - 010001 0000 xxxxxx
           // Add high registers - 010001 0001/001x xxxxxx
           uint16_t DN = (instr >> 7) & 1;
-          uint16_t Rm = (instr >> 3) & 0xF;
+          uint16_t rm = (instr >> 3) & 0xF;
           uint16_t Rdn = instr & 7;
           uint16_t DN_Rdn = (DN << 3) | Rdn;
           os << "ADD ";
           DumpReg(os, DN_Rdn);
           os << ", ";
-          DumpReg(os, Rm);
-          os << "  // ";
+          DumpReg(os, rm);
           break;
         }
         case 0x8: case 0x9: case 0xA: case 0xB: {
           // Move low registers  - 010001 1000 xxxxxx
           // Move high registers - 010001 1001/101x xxxxxx
           uint16_t DN = (instr >> 7) & 1;
-          uint16_t Rm = (instr >> 3) & 0xF;
+          uint16_t rm = (instr >> 3) & 0xF;
           uint16_t Rdn = instr & 7;
           uint16_t DN_Rdn = (DN << 3) | Rdn;
           os << "MOV ";
           DumpReg(os, DN_Rdn);
           os << ", ";
-          DumpReg(os, Rm);
-          os << "  // ";
+          DumpReg(os, rm);
           break;
         }
         case 0x5: case 0x6: case 0x7: {
           // Compare high registers - 010001 0101/011x xxxxxx
           uint16_t N = (instr >> 7) & 1;
-          uint16_t Rm = (instr >> 3) & 0xF;
+          uint16_t rm = (instr >> 3) & 0xF;
           uint16_t Rn = instr & 7;
           uint16_t N_Rn = (N << 3) | Rn;
           os << "CMP ";
           DumpReg(os, N_Rn);
           os << ", ";
-          DumpReg(os, Rm);
-          os << "  // ";
+          DumpReg(os, rm);
           break;
         }
         case 0xC: case 0xD: case 0xE: case 0xF: {
           // Branch and exchange           - 010001 110x xxxxxx
           // Branch with link and exchange - 010001 111x xxxxxx
-          uint16_t Rm = instr >> 3 & 0xF;
+          uint16_t rm = instr >> 3 & 0xF;
           if ((opcode2 & 0x2) == 0) {
             os << "BX ";
           } else {
             os << "BLX ";
           }
-          DumpReg(os, Rm);
-          os << "  // ";
+          DumpReg(os, rm);
           break;
         }
         default:
@@ -641,7 +760,7 @@
           } else {
             os << "SUB SP, SP, #";
           }
-          os << (imm7 << 2) << "  // ";
+          os << (imm7 << 2);
           break;
         }
         case 0x78: case 0x79: case 0x7A: case 0x7B:  // 1111xxx
@@ -660,7 +779,6 @@
           } else {
             os << "IT " << reinterpret_cast<void*>(opB) << " ";
             DumpCond(os, opA);
-            os << "  // ";
           }
           break;
         }
@@ -687,7 +805,7 @@
           DumpReg(os, Rt);
           os << ", [";
           DumpReg(os, Rn);
-          os << ", #" << (imm5 << 2) << "]  // ";
+          os << ", #" << (imm5 << 2) << "]";
           break;
         }
         case 0x9: {
@@ -701,7 +819,7 @@
             os << "LDR ";
           }
           DumpReg(os, Rt);
-          os << ", [SP, #" << (imm8 << 2) << "]  // ";
+          os << ", [SP, #" << (imm8 << 2) << "]";
           break;
         }
         default:
@@ -713,9 +831,8 @@
       imm32 = (imm32 << 20) >> 20;  // sign extend 12 bit immediate
       os << "B ";
       DumpBranchTarget(os, instr_ptr + 4, imm32);
-      os << "  // ";
     }
-    os << StringPrintf("%04x\n", instr);
+    os << '\n';
   }
   return 2;
 }