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;
}