diff --git a/dexmaker-mockito-inline/external/slicer/README.txt b/dexmaker-mockito-inline/external/slicer/README.txt index 2589a5d1..f8b401ec 100644 --- a/dexmaker-mockito-inline/external/slicer/README.txt +++ b/dexmaker-mockito-inline/external/slicer/README.txt @@ -1 +1 @@ -Copied from aosp/master::tools/dexter/slicer on 02/26/2018 + removed Android.bp +Copied from aosp/main::tools/dexter/slicer on 07/24/2025 + removed Android.bp and tests diff --git a/dexmaker-mockito-inline/external/slicer/bytecode_encoder.cc b/dexmaker-mockito-inline/external/slicer/bytecode_encoder.cc index f4caae4c..6e8aa581 100644 --- a/dexmaker-mockito-inline/external/slicer/bytecode_encoder.cc +++ b/dexmaker-mockito-inline/external/slicer/bytecode_encoder.cc @@ -15,86 +15,89 @@ */ #include "slicer/bytecode_encoder.h" + #include "slicer/common.h" #include "slicer/chronometer.h" #include +#include +#include namespace lir { // Pack a 16bit word: 00AA static dex::u2 Pack_Z_8(dex::u4 a) { dex::u2 fa = (a & 0xff); - SLICER_CHECK(fa == a); + SLICER_CHECK_EQ(fa, a); return fa; } // Pack a 16bit word: AABB static dex::u2 Pack_8_8(dex::u4 a, dex::u4 b) { dex::u2 fa = (a & 0xff); - SLICER_CHECK(fa == a); + SLICER_CHECK_EQ(fa, a); dex::u2 fb = (b & 0xff); - SLICER_CHECK(fb == b); + SLICER_CHECK_EQ(fb, b); return (fa << 8) | fb; } // Pack a 16bit word: ABCC static dex::u2 Pack_4_4_8(dex::u4 a, dex::u4 b, dex::u4 c) { dex::u2 fa = (a & 0xf); - SLICER_CHECK(fa == a); + SLICER_CHECK_EQ(fa, a); dex::u2 fb = (b & 0xf); - SLICER_CHECK(fb == b); + SLICER_CHECK_EQ(fb, b); dex::u2 fc = (c & 0xff); - SLICER_CHECK(fc == c); + SLICER_CHECK_EQ(fc, c); return (fa << 12) | (fb << 8) | fc; } // Pack a 16bit word: ABCD static dex::u2 Pack_4_4_4_4(dex::u4 a, dex::u4 b, dex::u4 c, dex::u4 d) { dex::u2 fa = (a & 0xf); - SLICER_CHECK(fa == a); + SLICER_CHECK_EQ(fa, a); dex::u2 fb = (b & 0xf); - SLICER_CHECK(fb == b); + SLICER_CHECK_EQ(fb, b); dex::u2 fc = (c & 0xf); - SLICER_CHECK(fc == c); + SLICER_CHECK_EQ(fc, c); dex::u2 fd = (d & 0xf); - SLICER_CHECK(fd == d); + SLICER_CHECK_EQ(fd, d); return (fa << 12) | (fb << 8) | (fc << 4) | fd; } // Pack a 16bit word: AAAA static dex::u2 Pack_16(dex::u4 a) { dex::u2 fa = (a & 0xffff); - SLICER_CHECK(fa == a); + SLICER_CHECK_EQ(fa, a); return fa; } // Trim a 4bit signed integer, making sure we're not discarding significant bits static dex::u4 Trim_S0(dex::u4 value) { dex::u4 trim = value & 0xf; - SLICER_CHECK(dex::u4(dex::s4(trim << 28) >> 28) == value); + SLICER_CHECK_EQ(dex::u4(dex::s4(trim << 28) >> 28), value); return trim; } // Trim a 8bit signed integer, making sure we're not discarding significant bits static dex::u4 Trim_S1(dex::u4 value) { dex::u4 trim = value & 0xff; - SLICER_CHECK(dex::u4(dex::s4(trim << 24) >> 24) == value); + SLICER_CHECK_EQ(dex::u4(dex::s4(trim << 24) >> 24), value); return trim; } // Trim a 16bit signed integer, making sure we're not discarding significant bits static dex::u4 Trim_S2(dex::u4 value) { dex::u4 trim = value & 0xffff; - SLICER_CHECK(dex::u4(dex::s4(trim << 16) >> 16) == value); + SLICER_CHECK_EQ(dex::u4(dex::s4(trim << 16) >> 16), value); return trim; } // Returns a register operand, checking the match between format and type // (register fields can encode either a single 32bit vreg or a wide 64bit vreg pair) static dex::u4 GetRegA(const Bytecode* bytecode, int index) { - auto flags = dex::GetFlagsFromOpcode(bytecode->opcode); - return (flags & dex::kInstrWideRegA) != 0 + auto verify_flags = dex::GetVerifyFlagsFromOpcode(bytecode->opcode); + return (verify_flags & dex::kVerifyRegAWide) != 0 ? bytecode->CastOperand(index)->base_reg : bytecode->CastOperand(index)->reg; } @@ -102,8 +105,8 @@ static dex::u4 GetRegA(const Bytecode* bytecode, int index) { // Returns a register operand, checking the match between format and type // (register fields can encode either a single 32bit vreg or a wide 64bit vreg pair) static dex::u4 GetRegB(const Bytecode* bytecode, int index) { - auto flags = dex::GetFlagsFromOpcode(bytecode->opcode); - return (flags & dex::kInstrWideRegB) != 0 + auto verify_flags = dex::GetVerifyFlagsFromOpcode(bytecode->opcode); + return (verify_flags & dex::kVerifyRegBWide) != 0 ? bytecode->CastOperand(index)->base_reg : bytecode->CastOperand(index)->reg; } @@ -111,8 +114,8 @@ static dex::u4 GetRegB(const Bytecode* bytecode, int index) { // Returns a register operand, checking the match between format and type // (register fields can encode either a single 32bit vreg or a wide 64bit vreg pair) static dex::u4 GetRegC(const Bytecode* bytecode, int index) { - auto flags = dex::GetFlagsFromOpcode(bytecode->opcode); - return (flags & dex::kInstrWideRegC) != 0 + auto verify_flags = dex::GetVerifyFlagsFromOpcode(bytecode->opcode); + return (verify_flags & dex::kVerifyRegCWide) != 0 ? bytecode->CastOperand(index)->base_reg : bytecode->CastOperand(index)->reg; } @@ -137,32 +140,32 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { auto format = dex::GetFormatFromOpcode(opcode); switch (format) { - case dex::kFmt10x: // op + case dex::k10x: // op { - SLICER_CHECK(bytecode->operands.size() == 0); + SLICER_CHECK_EQ(bytecode->operands.size(), 0); bytecode_.Push(Pack_Z_8(opcode)); } break; - case dex::kFmt12x: // op vA, vB + case dex::k12x: // op vA, vB { - SLICER_CHECK(bytecode->operands.size() == 2); + SLICER_CHECK_EQ(bytecode->operands.size(), 2); dex::u4 vA = GetRegA(bytecode, 0); dex::u4 vB = GetRegB(bytecode, 1); bytecode_.Push(Pack_4_4_8(vB, vA, opcode)); } break; - case dex::kFmt22x: // op vAA, vBBBB + case dex::k22x: // op vAA, vBBBB { - SLICER_CHECK(bytecode->operands.size() == 2); + SLICER_CHECK_EQ(bytecode->operands.size(), 2); dex::u4 vA = GetRegA(bytecode, 0); dex::u4 vB = GetRegB(bytecode, 1); bytecode_.Push(Pack_8_8(vA, opcode)); bytecode_.Push(Pack_16(vB)); } break; - case dex::kFmt32x: // op vAAAA, vBBBB + case dex::k32x: // op vAAAA, vBBBB { - SLICER_CHECK(bytecode->operands.size() == 2); + SLICER_CHECK_EQ(bytecode->operands.size(), 2); dex::u4 vA = GetRegA(bytecode, 0); dex::u4 vB = GetRegB(bytecode, 1); bytecode_.Push(Pack_Z_8(opcode)); @@ -170,33 +173,33 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_16(vB)); } break; - case dex::kFmt11n: // op vA, #+B + case dex::k11n: // op vA, #+B { - SLICER_CHECK(bytecode->operands.size() == 2); + SLICER_CHECK_EQ(bytecode->operands.size(), 2); dex::u4 vA = GetRegA(bytecode, 0); dex::u4 B = Trim_S0(bytecode->CastOperand(1)->u.u4_value); bytecode_.Push(Pack_4_4_8(B, vA, opcode)); } break; - case dex::kFmt21s: // op vAA, #+BBBB + case dex::k21s: // op vAA, #+BBBB { - SLICER_CHECK(bytecode->operands.size() == 2); + SLICER_CHECK_EQ(bytecode->operands.size(), 2); dex::u4 vA = GetRegA(bytecode, 0); dex::u4 B = Trim_S2(bytecode->CastOperand(1)->u.u4_value); bytecode_.Push(Pack_8_8(vA, opcode)); bytecode_.Push(Pack_16(B)); } break; - case dex::kFmt11x: // op vAA + case dex::k11x: // op vAA { - SLICER_CHECK(bytecode->operands.size() == 1); + SLICER_CHECK_EQ(bytecode->operands.size(), 1); dex::u4 vA = GetRegA(bytecode, 0); bytecode_.Push(Pack_8_8(vA, opcode)); } break; - case dex::kFmt31i: // op vAA, #+BBBBBBBB + case dex::k31i: // op vAA, #+BBBBBBBB { - SLICER_CHECK(bytecode->operands.size() == 2); + SLICER_CHECK_EQ(bytecode->operands.size(), 2); dex::u4 vA = GetRegA(bytecode, 0); dex::u4 B = bytecode->CastOperand(1)->u.u4_value; bytecode_.Push(Pack_8_8(vA, opcode)); @@ -204,16 +207,16 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_16(B >> 16)); } break; - case dex::kFmt20t: // op +AAAA + case dex::k20t: // op +AAAA { - SLICER_CHECK(bytecode->operands.size() == 1); + SLICER_CHECK_EQ(bytecode->operands.size(), 1); auto label = bytecode->CastOperand(0)->label; dex::u4 A = 0; if (label->offset != kInvalidOffset) { assert(label->offset <= offset_); A = label->offset - offset_; - SLICER_CHECK(A != 0); - SLICER_CHECK((A >> 16) == 0xffff); // TODO: out of range! + SLICER_CHECK_NE(A, 0); + SLICER_CHECK_EQ((A >> 16), 0xffff); // TODO: out of range! } else { fixups_.push_back(LabelFixup(offset_, label, true)); } @@ -221,9 +224,9 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_16(A & 0xffff)); } break; - case dex::kFmt30t: // op +AAAAAAAA + case dex::k30t: // op +AAAAAAAA { - SLICER_CHECK(bytecode->operands.size() == 1); + SLICER_CHECK_EQ(bytecode->operands.size(), 1); auto label = bytecode->CastOperand(0)->label; dex::u4 A = 0; if (label->offset != kInvalidOffset) { @@ -238,17 +241,17 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_16(A >> 16)); } break; - case dex::kFmt21t: // op vAA, +BBBB + case dex::k21t: // op vAA, +BBBB { - SLICER_CHECK(bytecode->operands.size() == 2); + SLICER_CHECK_EQ(bytecode->operands.size(), 2); dex::u4 vA = GetRegA(bytecode, 0); auto label = bytecode->CastOperand(1)->label; dex::u4 B = 0; if (label->offset != kInvalidOffset) { assert(label->offset <= offset_); B = label->offset - offset_; - SLICER_CHECK(B != 0); - SLICER_CHECK((B >> 16) == 0xffff); // TODO: out of range! + SLICER_CHECK_NE(B, 0); + SLICER_CHECK_EQ((B >> 16), 0xffff); // TODO: out of range! } else { fixups_.push_back(LabelFixup(offset_, label, true)); } @@ -256,9 +259,9 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_16(B & 0xffff)); } break; - case dex::kFmt22t: // op vA, vB, +CCCC + case dex::k22t: // op vA, vB, +CCCC { - SLICER_CHECK(bytecode->operands.size() == 3); + SLICER_CHECK_EQ(bytecode->operands.size(), 3); dex::u4 vA = GetRegA(bytecode, 0); dex::u4 vB = GetRegB(bytecode, 1); auto label = bytecode->CastOperand(2)->label; @@ -266,8 +269,8 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { if (label->offset != kInvalidOffset) { assert(label->offset <= offset_); C = label->offset - offset_; - SLICER_CHECK(C != 0); - SLICER_CHECK((C >> 16) == 0xffff); // TODO: out of range! + SLICER_CHECK_NE(C, 0); + SLICER_CHECK_EQ((C >> 16), 0xffff); // TODO: out of range! } else { fixups_.push_back(LabelFixup(offset_, label, true)); } @@ -275,16 +278,16 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_16(C & 0xffff)); } break; - case dex::kFmt31t: // op vAA, +BBBBBBBB + case dex::k31t: // op vAA, +BBBBBBBB { - SLICER_CHECK(bytecode->operands.size() == 2); + SLICER_CHECK_EQ(bytecode->operands.size(), 2); dex::u4 vA = GetRegA(bytecode, 0); auto label = bytecode->CastOperand(1)->label; dex::u4 B = 0; if (label->offset != kInvalidOffset) { assert(label->offset <= offset_); B = label->offset - offset_; - SLICER_CHECK(B != 0); + SLICER_CHECK_NE(B, 0); } else { fixups_.push_back(LabelFixup(offset_, label, false)); } @@ -293,9 +296,9 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_16(B >> 16)); } break; - case dex::kFmt23x: // op vAA, vBB, vCC + case dex::k23x: // op vAA, vBB, vCC { - SLICER_CHECK(bytecode->operands.size() == 3); + SLICER_CHECK_EQ(bytecode->operands.size(), 3); dex::u4 vA = GetRegA(bytecode, 0); dex::u4 vB = GetRegB(bytecode, 1); dex::u4 vC = GetRegC(bytecode, 2); @@ -303,9 +306,9 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_8_8(vC, vB)); } break; - case dex::kFmt22b: // op vAA, vBB, #+CC + case dex::k22b: // op vAA, vBB, #+CC { - SLICER_CHECK(bytecode->operands.size() == 3); + SLICER_CHECK_EQ(bytecode->operands.size(), 3); dex::u4 vA = GetRegA(bytecode, 0); dex::u4 vB = GetRegB(bytecode, 1); dex::u4 C = Trim_S1(bytecode->CastOperand(2)->u.u4_value); @@ -313,9 +316,9 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_8_8(C, vB)); } break; - case dex::kFmt22s: // op vA, vB, #+CCCC + case dex::k22s: // op vA, vB, #+CCCC { - SLICER_CHECK(bytecode->operands.size() == 3); + SLICER_CHECK_EQ(bytecode->operands.size(), 3); dex::u4 vA = GetRegA(bytecode, 0); dex::u4 vB = GetRegB(bytecode, 1); dex::u4 C = Trim_S2(bytecode->CastOperand(2)->u.u4_value); @@ -323,9 +326,9 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_16(C)); } break; - case dex::kFmt22c: // op vA, vB, thing@CCCC + case dex::k22c: // op vA, vB, thing@CCCC { - SLICER_CHECK(bytecode->operands.size() == 3); + SLICER_CHECK_EQ(bytecode->operands.size(), 3); dex::u4 vA = GetRegA(bytecode, 0); dex::u4 vB = GetRegB(bytecode, 1); dex::u4 C = bytecode->CastOperand(2)->index; @@ -333,18 +336,18 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_16(C)); } break; - case dex::kFmt21c: // op vAA, thing@BBBB + case dex::k21c: // op vAA, thing@BBBB { - SLICER_CHECK(bytecode->operands.size() == 2); + SLICER_CHECK_EQ(bytecode->operands.size(), 2); dex::u4 vA = GetRegA(bytecode, 0); dex::u4 B = bytecode->CastOperand(1)->index; bytecode_.Push(Pack_8_8(vA, opcode)); bytecode_.Push(Pack_16(B)); } break; - case dex::kFmt31c: // op vAA, string@BBBBBBBB + case dex::k31c: // op vAA, string@BBBBBBBB { - SLICER_CHECK(bytecode->operands.size() == 2); + SLICER_CHECK_EQ(bytecode->operands.size(), 2); dex::u4 vA = GetRegA(bytecode, 0); dex::u4 B = bytecode->CastOperand(1)->index; bytecode_.Push(Pack_8_8(vA, opcode)); @@ -352,9 +355,9 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_16(B >> 16)); } break; - case dex::kFmt35c: // op {vC,vD,vE,vF,vG}, thing@BBBB + case dex::k35c: // op {vC,vD,vE,vF,vG}, thing@BBBB { - SLICER_CHECK(bytecode->operands.size() == 2); + SLICER_CHECK_EQ(bytecode->operands.size(), 2); const auto& regs = bytecode->CastOperand(0)->registers; dex::u4 B = bytecode->CastOperand(1)->index; dex::u4 A = regs.size(); @@ -368,14 +371,14 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_4_4_4_4(F, E, D, C)); // keep track of the outs_count - if ((dex::GetFlagsFromOpcode(opcode) & dex::kInstrInvoke) != 0) { + if ((dex::GetFlagsFromOpcode(opcode) & dex::kInvoke) != 0) { outs_count_ = std::max(outs_count_, A); } } break; - case dex::kFmt3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB + case dex::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB { - SLICER_CHECK(bytecode->operands.size() == 2); + SLICER_CHECK_EQ(bytecode->operands.size(), 2); auto vreg_range = bytecode->CastOperand(0); dex::u4 A = vreg_range->count; dex::u4 B = bytecode->CastOperand(1)->index; @@ -385,14 +388,14 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_16(C)); // keep track of the outs_count - if ((dex::GetFlagsFromOpcode(opcode) & dex::kInstrInvoke) != 0) { + if ((dex::GetFlagsFromOpcode(opcode) & dex::kInvoke) != 0) { outs_count_ = std::max(outs_count_, A); } } break; - case dex::kFmt51l: // op vAA, #+BBBBBBBBBBBBBBBB + case dex::k51l: // op vAA, #+BBBBBBBBBBBBBBBB { - SLICER_CHECK(bytecode->operands.size() == 2); + SLICER_CHECK_EQ(bytecode->operands.size(), 2); dex::u4 vA = GetRegA(bytecode, 0); dex::u8 B = bytecode->CastOperand(1)->u.u8_value; bytecode_.Push(Pack_8_8(vA, opcode)); @@ -402,8 +405,50 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_16((B >> 48) & 0xffff)); } break; - case dex::kFmt21h: // op vAA, #+BBBB0000[00000000] - SLICER_CHECK(bytecode->operands.size() == 2); + case dex::k45cc: // op {vC, vD, vE, vF, vG}, thing@BBBB, other@HHHH + { + SLICER_CHECK_EQ(bytecode->operands.size(), 3); + const auto& regs = bytecode->CastOperand(0)->registers; + dex::u4 A = regs.size(); + dex::u4 B = bytecode->CastOperand(1)->index; + dex::u4 H = bytecode->CastOperand(2)->index; + dex::u4 C = (A > 0) ? regs[0] : 0; + dex::u4 D = (A > 1) ? regs[1] : 0; + dex::u4 E = (A > 2) ? regs[2] : 0; + dex::u4 F = (A > 3) ? regs[3] : 0; + dex::u4 G = (A > 4) ? regs[4] : 0; + bytecode_.Push(Pack_4_4_8(A, G, opcode)); + bytecode_.Push(Pack_16(B)); + bytecode_.Push(Pack_4_4_4_4(F, E, D, C)); + bytecode_.Push(Pack_16(H)); + + // keep track of the outs_count + if ((dex::GetFlagsFromOpcode(opcode) & dex::kInvoke) != 0) { + outs_count_ = std::max(outs_count_, A); + } + } break; + + case dex::k4rcc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB, other@HHHH + { + SLICER_CHECK_EQ(bytecode->operands.size(), 3); + auto vreg_range = bytecode->CastOperand(0); + dex::u4 A = vreg_range->count; + dex::u4 B = bytecode->CastOperand(1)->index; + dex::u4 C = vreg_range->base_reg; + dex::u4 H = bytecode->CastOperand(2)->index; + bytecode_.Push(Pack_8_8(A, opcode)); + bytecode_.Push(Pack_16(B)); + bytecode_.Push(Pack_16(C)); + bytecode_.Push(Pack_16(H)); + + // keep track of the outs_count + if ((dex::GetFlagsFromOpcode(opcode) & dex::kInvoke) != 0) { + outs_count_ = std::max(outs_count_, A); + } + } break; + + case dex::k21h: // op vAA, #+BBBB0000[00000000] + SLICER_CHECK_EQ(bytecode->operands.size(), 2); switch (opcode) { case dex::OP_CONST_HIGH16: { dex::u4 vA = GetRegA(bytecode, 0); @@ -419,27 +464,33 @@ bool BytecodeEncoder::Visit(Bytecode* bytecode) { bytecode_.Push(Pack_16(B)); } break; - default: - SLICER_FATAL("Unexpected fmt21h opcode: 0x%02x", opcode); + default: { + std::stringstream ss; + ss << "Unexpected fmt21h opcode: " << opcode; + SLICER_FATAL(ss.str()); + } } break; - default: - SLICER_FATAL("Unexpected format: 0x%02x", format); + default: { + std::stringstream ss; + ss << "Unexpected format: " << format; + SLICER_FATAL(ss.str()); + } } - SLICER_CHECK(bytecode_.size() - buff_offset == 2 * GetWidthFromOpcode(opcode)); - offset_ += GetWidthFromOpcode(opcode); + SLICER_CHECK_EQ(bytecode_.size() - buff_offset, 2 * GetWidthFromFormat(format)); + offset_ += GetWidthFromFormat(format); return true; } bool BytecodeEncoder::Visit(PackedSwitchPayload* packed_switch) { - SLICER_CHECK(offset_ % 2 == 0); + SLICER_CHECK_EQ(offset_ % 2, 0); // keep track of the switches packed_switch->offset = offset_; auto& instr = packed_switches_[offset_]; - SLICER_CHECK(instr == nullptr); + SLICER_CHECK_EQ(instr, nullptr); instr = packed_switch; // we're going to fix up the offsets in a later pass @@ -458,12 +509,12 @@ bool BytecodeEncoder::Visit(PackedSwitchPayload* packed_switch) { } bool BytecodeEncoder::Visit(SparseSwitchPayload* sparse_switch) { - SLICER_CHECK(offset_ % 2 == 0); + SLICER_CHECK_EQ(offset_ % 2, 0); // keep track of the switches sparse_switch->offset = offset_; auto& instr = sparse_switches_[offset_]; - SLICER_CHECK(instr == nullptr); + SLICER_CHECK_EQ(instr, nullptr); instr = sparse_switch; // we're going to fix up the offsets in a later pass @@ -482,7 +533,7 @@ bool BytecodeEncoder::Visit(SparseSwitchPayload* sparse_switch) { } bool BytecodeEncoder::Visit(ArrayData* array_data) { - SLICER_CHECK(offset_ % 2 == 0); + SLICER_CHECK_EQ(offset_ % 2, 0); array_data->offset = offset_; auto orig_size = bytecode_.size(); @@ -539,19 +590,19 @@ void BytecodeEncoder::FixupSwitchOffsets() { FixupSparseSwitch(offset, offset + dex::s4(dex_instr.vB)); } auto isize = dex::GetWidthFromBytecode(ptr); - SLICER_CHECK(isize > 0); + SLICER_CHECK_GT(isize, 0); ptr += isize; } - SLICER_CHECK(ptr == end); + SLICER_CHECK_EQ(ptr, end); } void BytecodeEncoder::FixupPackedSwitch(dex::u4 base_offset, dex::u4 payload_offset) { auto instr = packed_switches_[payload_offset]; - SLICER_CHECK(instr != nullptr); + SLICER_CHECK_NE(instr, nullptr); auto payload = bytecode_.ptr(payload_offset * 2); - SLICER_CHECK(payload->ident == dex::kPackedSwitchSignature); + SLICER_CHECK_EQ(payload->ident, dex::kPackedSwitchSignature); SLICER_CHECK(reinterpret_cast(payload->targets + payload->size) <= bytecode_.data() + bytecode_.size()); @@ -565,10 +616,10 @@ void BytecodeEncoder::FixupPackedSwitch(dex::u4 base_offset, void BytecodeEncoder::FixupSparseSwitch(dex::u4 base_offset, dex::u4 payload_offset) { auto instr = sparse_switches_[payload_offset]; - SLICER_CHECK(instr != nullptr); + SLICER_CHECK_NE(instr, nullptr); auto payload = bytecode_.ptr(payload_offset * 2); - SLICER_CHECK(payload->ident == dex::kSparseSwitchSignature); + SLICER_CHECK_EQ(payload->ident, dex::kSparseSwitchSignature); dex::s4* const targets = payload->data + payload->size; SLICER_CHECK(reinterpret_cast(targets + payload->size) <= @@ -587,7 +638,7 @@ void BytecodeEncoder::FixupLabels() { assert(label_offset != kInvalidOffset); assert(label_offset > fixup.offset); dex::u4 rel_offset = label_offset - fixup.offset; - SLICER_CHECK(rel_offset != 0); + SLICER_CHECK_NE(rel_offset, 0); dex::u2* instr = bytecode_.ptr(fixup.offset * 2); if (fixup.short_fixup) { // TODO: explicit out-of-range check @@ -604,8 +655,8 @@ void BytecodeEncoder::FixupLabels() { void BytecodeEncoder::Encode(ir::Code* ir_code, std::shared_ptr dex_ir) { SLICER_CHECK(bytecode_.empty()); - SLICER_CHECK(offset_ == 0); - SLICER_CHECK(outs_count_ == 0); + SLICER_CHECK_EQ(offset_, 0); + SLICER_CHECK_EQ(outs_count_, 0); packed_switches_.clear(); sparse_switches_.clear(); diff --git a/dexmaker-mockito-inline/external/slicer/code_ir.cc b/dexmaker-mockito-inline/external/slicer/code_ir.cc index 3434ca6f..6b870dbf 100644 --- a/dexmaker-mockito-inline/external/slicer/code_ir.cc +++ b/dexmaker-mockito-inline/external/slicer/code_ir.cc @@ -14,28 +14,27 @@ * limitations under the License. */ -#include "slicer/common.h" #include "slicer/code_ir.h" + +#include "slicer/bytecode_encoder.h" +#include "slicer/common.h" +#include "slicer/debuginfo_encoder.h" #include "slicer/dex_bytecode.h" #include "slicer/dex_format.h" #include "slicer/dex_ir.h" #include "slicer/dex_leb128.h" -#include "slicer/bytecode_encoder.h" -#include "slicer/debuginfo_encoder.h" #include "slicer/tryblocks_encoder.h" -#include -#include #include -#include -#include +#include +#include #include namespace lir { void CodeIr::Assemble() { auto ir_code = ir_method->code; - SLICER_CHECK(ir_code != nullptr); + SLICER_CHECK_NE(ir_code, nullptr); // new .dex bytecode // @@ -56,7 +55,7 @@ void CodeIr::Assemble() { try_blocks_encoder.Encode(ir_code, dex_ir); } -void CodeIr::DissasembleTryBlocks(const ir::Code* ir_code) { +void CodeIr::DisassembleTryBlocks(const ir::Code* ir_code) { int nextTryBlockId = 1; for (const auto& tryBlock : ir_code->try_blocks) { auto try_block_begin = Alloc(); @@ -78,7 +77,7 @@ void CodeIr::DissasembleTryBlocks(const ir::Code* ir_code) { // type dex::u4 type_index = dex::ReadULeb128(&ptr); handler.ir_type = dex_ir->types_map[type_index]; - SLICER_CHECK(handler.ir_type != nullptr); + SLICER_CHECK_NE(handler.ir_type, nullptr); // address dex::u4 address = dex::ReadULeb128(&ptr); @@ -106,7 +105,7 @@ void CodeIr::DissasembleTryBlocks(const ir::Code* ir_code) { } } -void CodeIr::DissasembleDebugInfo(const ir::DebugInfo* ir_debug_info) { +void CodeIr::DisassembleDebugInfo(const ir::DebugInfo* ir_debug_info) { if (ir_debug_info == nullptr) { return; } @@ -156,7 +155,7 @@ void CodeIr::DissasembleDebugInfo(const ir::DebugInfo* ir_debug_info) { case dex::DBG_ADVANCE_LINE: // line_diff line += dex::ReadSLeb128(&ptr); - SLICER_WEAK_CHECK(line > 0); + SLICER_WEAK_CHECK(line >= 0); break; case dex::DBG_START_LOCAL: { @@ -223,7 +222,7 @@ void CodeIr::DissasembleDebugInfo(const ir::DebugInfo* ir_debug_info) { int adjusted_opcode = opcode - dex::DBG_FIRST_SPECIAL; line += dex::DBG_LINE_BASE + (adjusted_opcode % dex::DBG_LINE_RANGE); address += (adjusted_opcode / dex::DBG_LINE_RANGE); - SLICER_WEAK_CHECK(line > 0); + SLICER_WEAK_CHECK(line >= 0); annotation = Alloc(dex::DBG_ADVANCE_LINE); annotation->operands.push_back(Alloc(line)); } break; @@ -236,14 +235,14 @@ void CodeIr::DissasembleDebugInfo(const ir::DebugInfo* ir_debug_info) { } } -void CodeIr::DissasembleBytecode(const ir::Code* ir_code) { +void CodeIr::DisassembleBytecode(const ir::Code* ir_code) { const dex::u2* begin = ir_code->instructions.begin(); const dex::u2* end = ir_code->instructions.end(); const dex::u2* ptr = begin; while (ptr < end) { auto isize = dex::GetWidthFromBytecode(ptr); - SLICER_CHECK(isize > 0); + SLICER_CHECK_GT(isize, 0); dex::u4 offset = ptr - begin; @@ -270,7 +269,7 @@ void CodeIr::DissasembleBytecode(const ir::Code* ir_code) { instructions.push_back(instr); ptr += isize; } - SLICER_CHECK(ptr == end); + SLICER_CHECK_EQ(ptr, end); } void CodeIr::FixupSwitches() { @@ -313,7 +312,7 @@ static void MergeInstructions(I_LIST& instructions, const E_LIST& extra) { } } -void CodeIr::Dissasemble() { +void CodeIr::Disassemble() { nodes_.clear(); labels_.clear(); @@ -329,13 +328,13 @@ void CodeIr::Dissasemble() { } // decode the .dex bytecodes - DissasembleBytecode(ir_code); + DisassembleBytecode(ir_code); // try/catch blocks - DissasembleTryBlocks(ir_code); + DisassembleTryBlocks(ir_code); // debug information - DissasembleDebugInfo(ir_code->debug_info); + DisassembleDebugInfo(ir_code->debug_info); // fixup switches FixupSwitches(); @@ -360,9 +359,9 @@ PackedSwitchPayload* CodeIr::DecodePackedSwitch(const dex::u2* /*ptr*/, // actual decoding is delayed to FixupPackedSwitch() // (since the label offsets are relative to the referring // instruction, not the switch data) - SLICER_CHECK(offset % 2 == 0); + SLICER_CHECK_EQ(offset % 2, 0); auto& instr = packed_switches_[offset].instr; - SLICER_CHECK(instr == nullptr); + SLICER_CHECK_EQ(instr, nullptr); instr = Alloc(); return instr; } @@ -372,7 +371,7 @@ void CodeIr::FixupPackedSwitch(PackedSwitchPayload* instr, dex::u4 base_offset, SLICER_CHECK(instr->targets.empty()); auto dex_packed_switch = reinterpret_cast(ptr); - SLICER_CHECK(dex_packed_switch->ident == dex::kPackedSwitchSignature); + SLICER_CHECK_EQ(dex_packed_switch->ident, dex::kPackedSwitchSignature); instr->first_key = dex_packed_switch->first_key; for (dex::u2 i = 0; i < dex_packed_switch->size; ++i) { @@ -386,9 +385,9 @@ SparseSwitchPayload* CodeIr::DecodeSparseSwitch(const dex::u2* /*ptr*/, // actual decoding is delayed to FixupSparseSwitch() // (since the label offsets are relative to the referring // instruction, not the switch data) - SLICER_CHECK(offset % 2 == 0); + SLICER_CHECK_EQ(offset % 2, 0); auto& instr = sparse_switches_[offset].instr; - SLICER_CHECK(instr == nullptr); + SLICER_CHECK_EQ(instr, nullptr); instr = Alloc(); return instr; } @@ -398,7 +397,7 @@ void CodeIr::FixupSparseSwitch(SparseSwitchPayload* instr, dex::u4 base_offset, SLICER_CHECK(instr->switch_cases.empty()); auto dex_sparse_switch = reinterpret_cast(ptr); - SLICER_CHECK(dex_sparse_switch->ident == dex::kSparseSwitchSignature); + SLICER_CHECK_EQ(dex_sparse_switch->ident, dex::kSparseSwitchSignature); auto& data = dex_sparse_switch->data; auto& size = dex_sparse_switch->size; @@ -413,8 +412,8 @@ void CodeIr::FixupSparseSwitch(SparseSwitchPayload* instr, dex::u4 base_offset, ArrayData* CodeIr::DecodeArrayData(const dex::u2* ptr, dex::u4 offset) { auto dex_array_data = reinterpret_cast(ptr); - SLICER_CHECK(dex_array_data->ident == dex::kArrayDataSignature); - SLICER_CHECK(offset % 2 == 0); + SLICER_CHECK_EQ(dex_array_data->ident, dex::kArrayDataSignature); + SLICER_CHECK_EQ(offset % 2, 0); auto instr = Alloc(); instr->data = slicer::MemView(ptr, dex::GetWidthFromBytecode(ptr) * 2); @@ -422,8 +421,8 @@ ArrayData* CodeIr::DecodeArrayData(const dex::u2* ptr, dex::u4 offset) { } Operand* CodeIr::GetRegA(const dex::Instruction& dex_instr) { - auto flags = dex::GetFlagsFromOpcode(dex_instr.opcode); - if ((flags & dex::kInstrWideRegA) != 0) { + auto verify_flags = dex::GetVerifyFlagsFromOpcode(dex_instr.opcode); + if ((verify_flags & dex::kVerifyRegAWide) != 0) { return Alloc(dex_instr.vA); } else { return Alloc(dex_instr.vA); @@ -431,8 +430,8 @@ Operand* CodeIr::GetRegA(const dex::Instruction& dex_instr) { } Operand* CodeIr::GetRegB(const dex::Instruction& dex_instr) { - auto flags = dex::GetFlagsFromOpcode(dex_instr.opcode); - if ((flags & dex::kInstrWideRegB) != 0) { + auto verify_flags = dex::GetVerifyFlagsFromOpcode(dex_instr.opcode); + if ((verify_flags & dex::kVerifyRegBWide) != 0) { return Alloc(dex_instr.vB); } else { return Alloc(dex_instr.vB); @@ -440,8 +439,8 @@ Operand* CodeIr::GetRegB(const dex::Instruction& dex_instr) { } Operand* CodeIr::GetRegC(const dex::Instruction& dex_instr) { - auto flags = dex::GetFlagsFromOpcode(dex_instr.opcode); - if ((flags & dex::kInstrWideRegC) != 0) { + auto verify_flags = dex::GetVerifyFlagsFromOpcode(dex_instr.opcode); + if ((verify_flags & dex::kVerifyRegCWide) != 0) { return Alloc(dex_instr.vC); } else { return Alloc(dex_instr.vC); @@ -455,39 +454,39 @@ Bytecode* CodeIr::DecodeBytecode(const dex::u2* ptr, dex::u4 offset) { instr->opcode = dex_instr.opcode; auto index_type = dex::GetIndexTypeFromOpcode(dex_instr.opcode); - - switch (dex::GetFormatFromOpcode(dex_instr.opcode)) { - case dex::kFmt10x: // op + auto format = dex::GetFormatFromOpcode(dex_instr.opcode); + switch (format) { + case dex::k10x: // op break; - case dex::kFmt12x: // op vA, vB - case dex::kFmt22x: // op vAA, vBBBB - case dex::kFmt32x: // op vAAAA, vBBBB + case dex::k12x: // op vA, vB + case dex::k22x: // op vAA, vBBBB + case dex::k32x: // op vAAAA, vBBBB instr->operands.push_back(GetRegA(dex_instr)); instr->operands.push_back(GetRegB(dex_instr)); break; - case dex::kFmt11n: // op vA, #+B - case dex::kFmt21s: // op vAA, #+BBBB - case dex::kFmt31i: // op vAA, #+BBBBBBBB + case dex::k11n: // op vA, #+B + case dex::k21s: // op vAA, #+BBBB + case dex::k31i: // op vAA, #+BBBBBBBB instr->operands.push_back(GetRegA(dex_instr)); instr->operands.push_back(Alloc(dex_instr.vB)); break; - case dex::kFmt11x: // op vAA + case dex::k11x: // op vAA instr->operands.push_back(GetRegA(dex_instr)); break; - case dex::kFmt10t: // op +AA - case dex::kFmt20t: // op +AAAA - case dex::kFmt30t: // op +AAAAAAAA + case dex::k10t: // op +AA + case dex::k20t: // op +AAAA + case dex::k30t: // op +AAAAAAAA { auto label = GetLabel(offset + dex::s4(dex_instr.vA)); instr->operands.push_back(Alloc(label)); } break; - case dex::kFmt21t: // op vAA, +BBBB - case dex::kFmt31t: // op vAA, +BBBBBBBB + case dex::k21t: // op vAA, +BBBB + case dex::k31t: // op vAA, +BBBBBBBB { dex::u4 targetOffset = offset + dex::s4(dex_instr.vB); instr->operands.push_back(GetRegA(dex_instr)); @@ -497,25 +496,25 @@ Bytecode* CodeIr::DecodeBytecode(const dex::u2* ptr, dex::u4 offset) { if (dex_instr.opcode == dex::OP_PACKED_SWITCH) { label->aligned = true; dex::u4& base_offset = packed_switches_[targetOffset].base_offset; - SLICER_CHECK(base_offset == kInvalidOffset); + SLICER_CHECK_EQ(base_offset, kInvalidOffset); base_offset = offset; } else if (dex_instr.opcode == dex::OP_SPARSE_SWITCH) { label->aligned = true; dex::u4& base_offset = sparse_switches_[targetOffset].base_offset; - SLICER_CHECK(base_offset == kInvalidOffset); + SLICER_CHECK_EQ(base_offset, kInvalidOffset); base_offset = offset; } else if (dex_instr.opcode == dex::OP_FILL_ARRAY_DATA) { label->aligned = true; } } break; - case dex::kFmt23x: // op vAA, vBB, vCC + case dex::k23x: // op vAA, vBB, vCC instr->operands.push_back(GetRegA(dex_instr)); instr->operands.push_back(GetRegB(dex_instr)); instr->operands.push_back(GetRegC(dex_instr)); break; - case dex::kFmt22t: // op vA, vB, +CCCC + case dex::k22t: // op vA, vB, +CCCC { instr->operands.push_back(GetRegA(dex_instr)); instr->operands.push_back(GetRegB(dex_instr)); @@ -523,28 +522,28 @@ Bytecode* CodeIr::DecodeBytecode(const dex::u2* ptr, dex::u4 offset) { instr->operands.push_back(Alloc(label)); } break; - case dex::kFmt22b: // op vAA, vBB, #+CC - case dex::kFmt22s: // op vA, vB, #+CCCC + case dex::k22b: // op vAA, vBB, #+CC + case dex::k22s: // op vA, vB, #+CCCC instr->operands.push_back(GetRegA(dex_instr)); instr->operands.push_back(GetRegB(dex_instr)); instr->operands.push_back(Alloc(dex_instr.vC)); break; - case dex::kFmt22c: // op vA, vB, thing@CCCC + case dex::k22c: // op vA, vB, thing@CCCC instr->operands.push_back(GetRegA(dex_instr)); instr->operands.push_back(GetRegB(dex_instr)); instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vC)); break; - case dex::kFmt21c: // op vAA, thing@BBBB - case dex::kFmt31c: // op vAA, string@BBBBBBBB + case dex::k21c: // op vAA, thing@BBBB + case dex::k31c: // op vAA, string@BBBBBBBB instr->operands.push_back(GetRegA(dex_instr)); instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vB)); break; - case dex::kFmt35c: // op {vC,vD,vE,vF,vG}, thing@BBBB + case dex::k35c: // op {vC,vD,vE,vF,vG}, thing@BBBB { - SLICER_CHECK(dex_instr.vA <= 5); + SLICER_CHECK_LE(dex_instr.vA, 5); auto vreg_list = Alloc(); for (dex::u4 i = 0; i < dex_instr.vA; ++i) { vreg_list->registers.push_back(dex_instr.arg[i]); @@ -553,14 +552,43 @@ Bytecode* CodeIr::DecodeBytecode(const dex::u2* ptr, dex::u4 offset) { instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vB)); } break; - case dex::kFmt3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB + case dex::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB { auto vreg_range = Alloc(dex_instr.vC, dex_instr.vA); instr->operands.push_back(vreg_range); instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vB)); } break; - case dex::kFmt21h: // op vAA, #+BBBB0000[00000000] + case dex::k45cc: // op {vC, vD, vE, vF, vG}, thing@BBBB, other@HHHH + { + auto vreg_list = Alloc(); + SLICER_CHECK_LE(dex_instr.vA, 5); + // vC if necessary. + if (dex_instr.vA > 1) { + vreg_list->registers.push_back(dex_instr.vC); + } + // Add vD,vE,vF,vG as necessary. + for (dex::u4 i = 1; i < dex_instr.vA; ++i) { + vreg_list->registers.push_back(dex_instr.arg[i - 1]); + } + instr->operands.push_back(vreg_list); + instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vB)); + dex::u4 vH = dex_instr.arg[4]; + auto proto_operand = GetSecondIndexedOperand(index_type, vH); + instr->operands.push_back(proto_operand); + } break; + + case dex::k4rcc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB, other@HHHH + { + auto vreg_range = Alloc(dex_instr.vC, dex_instr.vA); + instr->operands.push_back(vreg_range); + instr->operands.push_back(GetIndexedOperand(index_type, dex_instr.vB)); + dex::u4 vH = dex_instr.arg[4]; + auto proto_operand = GetSecondIndexedOperand(index_type, vH); + instr->operands.push_back(proto_operand); + } break; + + case dex::k21h: // op vAA, #+BBBB0000[00000000] switch (dex_instr.opcode) { case dex::OP_CONST_HIGH16: instr->operands.push_back(GetRegA(dex_instr)); @@ -572,18 +600,24 @@ Bytecode* CodeIr::DecodeBytecode(const dex::u2* ptr, dex::u4 offset) { instr->operands.push_back(Alloc(dex::u8(dex_instr.vB) << 48)); break; - default: - SLICER_FATAL("Unexpected opcode 0x%02x", dex_instr.opcode); + default: { + std::stringstream ss; + ss << "Unexpected opcode: " << dex_instr.opcode; + SLICER_FATAL(ss.str()); + } } break; - case dex::kFmt51l: // op vAA, #+BBBBBBBBBBBBBBBB + case dex::k51l: // op vAA, #+BBBBBBBBBBBBBBBB instr->operands.push_back(GetRegA(dex_instr)); instr->operands.push_back(Alloc(dex_instr.vB_wide)); break; - default: - SLICER_FATAL("Unexpected bytecode format (opcode 0x%02x)", dex_instr.opcode); + default: { + std::stringstream ss; + ss << "Unexpected bytecode format " << format << " for opcode " << dex_instr.opcode; + SLICER_FATAL(ss.str()); + } } return instr; @@ -593,7 +627,7 @@ Bytecode* CodeIr::DecodeBytecode(const dex::u2* ptr, dex::u4 offset) { // (index must be valid != kNoIndex) IndexedOperand* CodeIr::GetIndexedOperand(dex::InstructionIndexType index_type, dex::u4 index) { - SLICER_CHECK(index != dex::kNoIndex); + SLICER_CHECK_NE(index, dex::kNoIndex); switch (index_type) { case dex::kIndexStringRef: return Alloc(dex_ir->strings_map[index], index); @@ -605,13 +639,28 @@ IndexedOperand* CodeIr::GetIndexedOperand(dex::InstructionIndexType index_type, return Alloc(dex_ir->fields_map[index], index); case dex::kIndexMethodRef: + case dex::kIndexMethodAndProtoRef: return Alloc(dex_ir->methods_map[index], index); + case dex::kIndexMethodHandleRef: + return Alloc(dex_ir->method_handles_map[index], index); + default: - SLICER_FATAL("Unexpected index type 0x%02x", index_type); + std::stringstream ss; + ss << "Unexpected index type 0x"; + ss << std::hex << std::setfill('0') << std::setw(2) << index_type; + SLICER_FATAL(ss.str()); } } +// Get the second indexed object (if any). +IndexedOperand* CodeIr::GetSecondIndexedOperand(dex::InstructionIndexType index_type, + dex::u4 index) { + SLICER_CHECK_NE(index, dex::kNoIndex); + SLICER_CHECK_EQ(index_type, dex::kIndexMethodAndProtoRef); + return Alloc(dex_ir->protos_map[index], index); +} + // Get a type based on its index (potentially kNoIndex) Type* CodeIr::GetType(dex::u4 index) { auto ir_type = (index == dex::kNoIndex) ? nullptr : dex_ir->types_map[index]; diff --git a/dexmaker-mockito-inline/external/slicer/common.cc b/dexmaker-mockito-inline/external/slicer/common.cc index c504390f..6dcfc30f 100644 --- a/dexmaker-mockito-inline/external/slicer/common.cc +++ b/dexmaker-mockito-inline/external/slicer/common.cc @@ -18,15 +18,52 @@ #include #include -#include + +#include +#include #include #include namespace slicer { +static void log_(const std::string& msg) { + printf("%s", msg.c_str()); + fflush(stdout); +} + +static logger_type log = log_; + +void set_logger(logger_type new_logger) { + log = new_logger; +} + // Helper for the default SLICER_CHECK() policy void _checkFailed(const char* expr, int line, const char* file) { - printf("\nSLICER_CHECK failed [%s] at %s:%d\n\n", expr, file, line); + std::stringstream ss; + ss << std::endl << "SLICER_CHECK failed ["; + ss << expr << "] at " << file << ":" << line; + ss << std::endl << std::endl; + log(ss.str()); + abort(); +} + +void _checkFailedOp(const void* lhs, const void* rhs, const char* op, const char* suffix, int line, + const char* file) { + std::stringstream ss; + ss << std::endl << "SLICER_CHECK_" << suffix << " failed ["; + ss << lhs << " " << op << " " << rhs; + ss << "] at " << file << ":" << line; + log(ss.str()); + abort(); +} + +void _checkFailedOp(uint32_t lhs, uint32_t rhs, const char* op, const char* suffix, int line, + const char* file) { + std::stringstream ss; + ss << std::endl << "SLICER_CHECK_" << suffix << " failed ["; + ss << lhs << " " << op << " " << rhs; + ss << "] at " << file << ":" << line; + log(ss.str()); abort(); } @@ -40,17 +77,18 @@ thread_local std::set> weak_failures; void _weakCheckFailed(const char* expr, int line, const char* file) { auto failure_id = std::make_pair(line, file); if (weak_failures.find(failure_id) == weak_failures.end()) { - printf("\nSLICER_WEAK_CHECK failed [%s] at %s:%d\n\n", expr, file, line); + std::stringstream ss; + ss << std::endl << "SLICER_WEAK_CHECK failed ["; + ss << expr << "] at " << file << ":"; + ss << line << std::endl << std::endl; + log(ss.str()); weak_failures.insert(failure_id); } } // Prints a formatted message and aborts -void _fatal(const char* format, ...) { - va_list args; - va_start(args, format); - vprintf(format, args); - va_end(args); +void _fatal(const std::string& msg) { + log("SLICER_FATAL: " + msg); abort(); } diff --git a/dexmaker-mockito-inline/external/slicer/control_flow_graph.cc b/dexmaker-mockito-inline/external/slicer/control_flow_graph.cc index dc7b386a..06fb17d4 100644 --- a/dexmaker-mockito-inline/external/slicer/control_flow_graph.cc +++ b/dexmaker-mockito-inline/external/slicer/control_flow_graph.cc @@ -15,7 +15,6 @@ */ #include "slicer/control_flow_graph.h" -#include "slicer/chronometer.h" namespace lir { @@ -56,16 +55,16 @@ bool BasicBlocksVisitor::Visit(Bytecode* bytecode) { const auto flags = dex::GetFlagsFromOpcode(bytecode->opcode); if (model_exceptions_) { constexpr auto exit_instr_flags = - dex::kInstrCanBranch | - dex::kInstrCanSwitch | - dex::kInstrCanThrow | - dex::kInstrCanReturn; + dex::kBranch | + dex::kSwitch | + dex::kThrow | + dex::kReturn; terminate_block = (flags & exit_instr_flags) != 0; } else { constexpr auto exit_instr_flags = - dex::kInstrCanBranch | - dex::kInstrCanSwitch | - dex::kInstrCanReturn; + dex::kBranch | + dex::kSwitch | + dex::kReturn; terminate_block = bytecode->opcode == dex::OP_THROW || (flags & exit_instr_flags) != 0; } if (terminate_block) { diff --git a/dexmaker-mockito-inline/external/slicer/debuginfo_encoder.cc b/dexmaker-mockito-inline/external/slicer/debuginfo_encoder.cc index c99c65de..e8c35197 100644 --- a/dexmaker-mockito-inline/external/slicer/debuginfo_encoder.cc +++ b/dexmaker-mockito-inline/external/slicer/debuginfo_encoder.cc @@ -14,11 +14,14 @@ * limitations under the License. */ -#include "slicer/common.h" #include "slicer/debuginfo_encoder.h" -#include "slicer/chronometer.h" + +#include "slicer/common.h" #include +#include +#include + namespace lir { @@ -31,7 +34,7 @@ bool DebugInfoEncoder::Visit(DbgInfoHeader* dbg_header) { bool DebugInfoEncoder::Visit(DbgInfoAnnotation* dbg_annotation) { // keep the address in sync if (last_address_ != dbg_annotation->offset) { - SLICER_CHECK(dbg_annotation->offset > last_address_); + SLICER_CHECK_GT(dbg_annotation->offset, last_address_); dbginfo_.Push(dex::DBG_ADVANCE_PC); dbginfo_.PushULeb128(dbg_annotation->offset - last_address_); last_address_ = dbg_annotation->offset; @@ -49,10 +52,10 @@ bool DebugInfoEncoder::Visit(DbgInfoAnnotation* dbg_annotation) { // it's not perfectly clear from the .dex specification // if initial line == 0 is valid, but a number of existing // .dex files do this so we have to support it - SLICER_CHECK(line >= 0); + SLICER_CHECK_GE(line, 0); line_start_ = line; } else { - SLICER_WEAK_CHECK(line > 0); + SLICER_WEAK_CHECK(line >= 0); int delta = line - last_line_; int adj_opcode = delta - dex::DBG_LINE_BASE; // out of range for special opcode? @@ -111,8 +114,11 @@ bool DebugInfoEncoder::Visit(DbgInfoAnnotation* dbg_annotation) { } } break; - default: - SLICER_FATAL("Unexpected debug info opcode: 0x%02x", dbg_annotation->dbg_opcode); + default: { + std::stringstream ss; + ss << "Unexpected debug info opcode: " << dbg_annotation->dbg_opcode; + SLICER_FATAL(ss.str()); + } } return true; @@ -122,11 +128,11 @@ void DebugInfoEncoder::Encode(ir::EncodedMethod* ir_method, std::shared_ptrcode->debug_info; SLICER_CHECK(dbginfo_.empty()); - SLICER_CHECK(param_names_ == nullptr); - SLICER_CHECK(line_start_ == 0); - SLICER_CHECK(last_line_ == 0); - SLICER_CHECK(last_address_ == 0); - SLICER_CHECK(source_file_ == nullptr); + SLICER_CHECK_EQ(param_names_, nullptr); + SLICER_CHECK_EQ(line_start_, 0); + SLICER_CHECK_EQ(last_line_, 0); + SLICER_CHECK_EQ(last_address_, 0); + SLICER_CHECK_EQ(source_file_, nullptr); // generate new debug info source_file_ = ir_method->decl->parent->class_def->source_file; diff --git a/dexmaker-mockito-inline/external/slicer/dex_bytecode.cc b/dexmaker-mockito-inline/external/slicer/dex_bytecode.cc index 7a97f288..d28f7af7 100644 --- a/dexmaker-mockito-inline/external/slicer/dex_bytecode.cc +++ b/dexmaker-mockito-inline/external/slicer/dex_bytecode.cc @@ -15,133 +15,92 @@ */ #include "slicer/dex_bytecode.h" + #include "slicer/common.h" -#include #include +#include +#include namespace dex { Opcode OpcodeFromBytecode(u2 bytecode) { Opcode opcode = Opcode(bytecode & 0xff); - SLICER_CHECK(opcode != OP_UNUSED_FF); return opcode; } // Table that maps each opcode to the index type implied by that opcode -static constexpr std::array - gInstructionIndexTypeTable = { - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexStringRef, - kIndexStringRef, kIndexTypeRef, kIndexNone, - kIndexNone, kIndexTypeRef, kIndexTypeRef, - kIndexNone, kIndexTypeRef, kIndexTypeRef, - kIndexTypeRef, kIndexTypeRef, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexUnknown, - kIndexUnknown, kIndexUnknown, kIndexUnknown, - kIndexUnknown, kIndexUnknown, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexMethodRef, - kIndexMethodRef, kIndexMethodRef, kIndexMethodRef, - kIndexMethodRef, kIndexUnknown, kIndexMethodRef, - kIndexMethodRef, kIndexMethodRef, kIndexMethodRef, - kIndexMethodRef, kIndexUnknown, kIndexUnknown, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexNone, - kIndexNone, kIndexNone, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexFieldRef, kIndexFieldRef, kIndexUnknown, - kIndexVaries, kIndexInlineMethod, kIndexInlineMethod, - kIndexMethodRef, kIndexNone, kIndexFieldOffset, - kIndexFieldOffset, kIndexFieldOffset, kIndexFieldOffset, - kIndexFieldOffset, kIndexFieldOffset, kIndexVtableOffset, - kIndexVtableOffset, kIndexVtableOffset, kIndexVtableOffset, - kIndexFieldRef, kIndexFieldRef, kIndexFieldRef, - kIndexUnknown, -}; +static constexpr std::array + gInstructionDescriptors = {{ +#define INSTRUCTION_DESCR(o, c, p, format, index, flags, e, vflags) \ + { \ + vflags, \ + format, \ + index, \ + flags, \ + }, +#include "export/slicer/dex_instruction_list.h" + DEX_INSTRUCTION_LIST(INSTRUCTION_DESCR) +#undef DEX_INSTRUCTION_LIST +#undef INSTRUCTION_DESCR + }}; InstructionIndexType GetIndexTypeFromOpcode(Opcode opcode) { - return gInstructionIndexTypeTable[opcode]; + return gInstructionDescriptors[opcode].index_type; } -// Table that maps each opcode to the full width of instructions that -// use that opcode, in (16-bit) code units. Unimplemented opcodes as -// well as the "breakpoint" opcode have a width of zero. -static constexpr std::array gInstructionWidthTable = { - 1, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 2, 3, - 5, 2, 2, 3, 2, 1, 1, 2, 2, 1, 2, 2, 3, 3, 3, 1, 1, 2, 3, 3, 3, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, - 3, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 3, 3, - 3, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 0, -}; +InstructionFormat GetFormatFromOpcode(Opcode opcode) { + return gInstructionDescriptors[opcode].format; +} + +OpcodeFlags GetFlagsFromOpcode(Opcode opcode) { + return gInstructionDescriptors[opcode].flags; +} + +VerifyFlags GetVerifyFlagsFromOpcode(Opcode opcode) { + return gInstructionDescriptors[opcode].verify_flags; +} -size_t GetWidthFromOpcode(Opcode opcode) { - return gInstructionWidthTable[opcode]; +size_t GetWidthFromFormat(InstructionFormat format) { + switch (format) { + case k10x: + case k12x: + case k11n: + case k11x: + case k10t: + return 1; + case k20t: + case k20bc: + case k21c: + case k22x: + case k21s: + case k21t: + case k21h: + case k23x: + case k22b: + case k22s: + case k22t: + case k22c: + case k22cs: + return 2; + case k30t: + case k31t: + case k31c: + case k32x: + case k31i: + case k35c: + case k35ms: + case k35mi: + case k3rc: + case k3rms: + case k3rmi: + return 3; + case k45cc: + case k4rcc: + return 4; + case k51l: + return 5; + } } size_t GetWidthFromBytecode(const u2* bytecode) { @@ -156,578 +115,19 @@ size_t GetWidthFromBytecode(const u2* bytecode) { // The plus 1 is to round up for odd size and width. width = 4 + (elemWidth * len + 1) / 2; } else { - width = GetWidthFromOpcode(OpcodeFromBytecode(bytecode[0])); + width = GetWidthFromFormat( + GetFormatFromOpcode(OpcodeFromBytecode(bytecode[0]))); } return width; } -// Table that maps each opcode to the instruction flags -static constexpr std::array gOpcodeFlagsTable = { - /* NOP */ kInstrCanContinue, - /* MOVE */ kInstrCanContinue, - /* MOVE_FROM16 */ kInstrCanContinue, - /* MOVE_16 */ kInstrCanContinue, - /* MOVE_WIDE */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* MOVE_WIDE_FROM16 */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* MOVE_WIDE_16 */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* MOVE_OBJECT */ kInstrCanContinue, - /* MOVE_OBJECT_FROM16 */ kInstrCanContinue, - /* MOVE_OBJECT_16 */ kInstrCanContinue, - /* MOVE_RESULT */ kInstrCanContinue, - /* MOVE_RESULT_WIDE */ kInstrCanContinue|kInstrWideRegA, - /* MOVE_RESULT_OBJECT */ kInstrCanContinue, - /* MOVE_EXCEPTION */ kInstrCanContinue, - /* RETURN_VOID */ kInstrCanReturn, - /* RETURN */ kInstrCanReturn, - /* RETURN_WIDE */ kInstrCanReturn|kInstrWideRegA, - /* RETURN_OBJECT */ kInstrCanReturn, - /* CONST_4 */ kInstrCanContinue, - /* CONST_16 */ kInstrCanContinue, - /* CONST */ kInstrCanContinue, - /* CONST_HIGH16 */ kInstrCanContinue, - /* CONST_WIDE_16 */ kInstrCanContinue|kInstrWideRegA, - /* CONST_WIDE_32 */ kInstrCanContinue|kInstrWideRegA, - /* CONST_WIDE */ kInstrCanContinue|kInstrWideRegA, - /* CONST_WIDE_HIGH16 */ kInstrCanContinue|kInstrWideRegA, - /* CONST_STRING */ kInstrCanContinue|kInstrCanThrow, - /* CONST_STRING_JUMBO */ kInstrCanContinue|kInstrCanThrow, - /* CONST_CLASS */ kInstrCanContinue|kInstrCanThrow, - /* MONITOR_ENTER */ kInstrCanContinue|kInstrCanThrow, - /* MONITOR_EXIT */ kInstrCanContinue|kInstrCanThrow, - /* SLICER_CHECK_CAST */ kInstrCanContinue|kInstrCanThrow, - /* INSTANCE_OF */ kInstrCanContinue|kInstrCanThrow, - /* ARRAY_LENGTH */ kInstrCanContinue|kInstrCanThrow, - /* NEW_INSTANCE */ kInstrCanContinue|kInstrCanThrow, - /* NEW_ARRAY */ kInstrCanContinue|kInstrCanThrow, - /* FILLED_NEW_ARRAY */ kInstrCanContinue|kInstrCanThrow, - /* FILLED_NEW_ARRAY_RANGE */ kInstrCanContinue|kInstrCanThrow, - /* FILL_ARRAY_DATA */ kInstrCanContinue, - /* THROW */ kInstrCanThrow, - /* GOTO */ kInstrCanBranch, - /* GOTO_16 */ kInstrCanBranch, - /* GOTO_32 */ kInstrCanBranch, - /* PACKED_SWITCH */ kInstrCanContinue|kInstrCanSwitch, - /* SPARSE_SWITCH */ kInstrCanContinue|kInstrCanSwitch, - /* CMPL_FLOAT */ kInstrCanContinue, - /* CMPG_FLOAT */ kInstrCanContinue, - /* CMPL_DOUBLE */ kInstrCanContinue|kInstrWideRegB|kInstrWideRegC, - /* CMPG_DOUBLE */ kInstrCanContinue|kInstrWideRegB|kInstrWideRegC, - /* CMP_LONG */ kInstrCanContinue|kInstrWideRegB|kInstrWideRegC, - /* IF_EQ */ kInstrCanContinue|kInstrCanBranch, - /* IF_NE */ kInstrCanContinue|kInstrCanBranch, - /* IF_LT */ kInstrCanContinue|kInstrCanBranch, - /* IF_GE */ kInstrCanContinue|kInstrCanBranch, - /* IF_GT */ kInstrCanContinue|kInstrCanBranch, - /* IF_LE */ kInstrCanContinue|kInstrCanBranch, - /* IF_EQZ */ kInstrCanContinue|kInstrCanBranch, - /* IF_NEZ */ kInstrCanContinue|kInstrCanBranch, - /* IF_LTZ */ kInstrCanContinue|kInstrCanBranch, - /* IF_GEZ */ kInstrCanContinue|kInstrCanBranch, - /* IF_GTZ */ kInstrCanContinue|kInstrCanBranch, - /* IF_LEZ */ kInstrCanContinue|kInstrCanBranch, - /* UNUSED_3E */ 0, - /* UNUSED_3F */ 0, - /* UNUSED_40 */ 0, - /* UNUSED_41 */ 0, - /* UNUSED_42 */ 0, - /* UNUSED_43 */ 0, - /* AGET */ kInstrCanContinue|kInstrCanThrow, - /* AGET_WIDE */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA, - /* AGET_OBJECT */ kInstrCanContinue|kInstrCanThrow, - /* AGET_BOOLEAN */ kInstrCanContinue|kInstrCanThrow, - /* AGET_BYTE */ kInstrCanContinue|kInstrCanThrow, - /* AGET_CHAR */ kInstrCanContinue|kInstrCanThrow, - /* AGET_SHORT */ kInstrCanContinue|kInstrCanThrow, - /* APUT */ kInstrCanContinue|kInstrCanThrow, - /* APUT_WIDE */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA, - /* APUT_OBJECT */ kInstrCanContinue|kInstrCanThrow, - /* APUT_BOOLEAN */ kInstrCanContinue|kInstrCanThrow, - /* APUT_BYTE */ kInstrCanContinue|kInstrCanThrow, - /* APUT_CHAR */ kInstrCanContinue|kInstrCanThrow, - /* APUT_SHORT */ kInstrCanContinue|kInstrCanThrow, - /* IGET */ kInstrCanContinue|kInstrCanThrow, - /* IGET_WIDE */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA, - /* IGET_OBJECT */ kInstrCanContinue|kInstrCanThrow, - /* IGET_BOOLEAN */ kInstrCanContinue|kInstrCanThrow, - /* IGET_BYTE */ kInstrCanContinue|kInstrCanThrow, - /* IGET_CHAR */ kInstrCanContinue|kInstrCanThrow, - /* IGET_SHORT */ kInstrCanContinue|kInstrCanThrow, - /* IPUT */ kInstrCanContinue|kInstrCanThrow, - /* IPUT_WIDE */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA, - /* IPUT_OBJECT */ kInstrCanContinue|kInstrCanThrow, - /* IPUT_BOOLEAN */ kInstrCanContinue|kInstrCanThrow, - /* IPUT_BYTE */ kInstrCanContinue|kInstrCanThrow, - /* IPUT_CHAR */ kInstrCanContinue|kInstrCanThrow, - /* IPUT_SHORT */ kInstrCanContinue|kInstrCanThrow, - /* SGET */ kInstrCanContinue|kInstrCanThrow, - /* SGET_WIDE */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA, - /* SGET_OBJECT */ kInstrCanContinue|kInstrCanThrow, - /* SGET_BOOLEAN */ kInstrCanContinue|kInstrCanThrow, - /* SGET_BYTE */ kInstrCanContinue|kInstrCanThrow, - /* SGET_CHAR */ kInstrCanContinue|kInstrCanThrow, - /* SGET_SHORT */ kInstrCanContinue|kInstrCanThrow, - /* SPUT */ kInstrCanContinue|kInstrCanThrow, - /* SPUT_WIDE */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA, - /* SPUT_OBJECT */ kInstrCanContinue|kInstrCanThrow, - /* SPUT_BOOLEAN */ kInstrCanContinue|kInstrCanThrow, - /* SPUT_BYTE */ kInstrCanContinue|kInstrCanThrow, - /* SPUT_CHAR */ kInstrCanContinue|kInstrCanThrow, - /* SPUT_SHORT */ kInstrCanContinue|kInstrCanThrow, - /* INVOKE_VIRTUAL */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* INVOKE_SUPER */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* INVOKE_DIRECT */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* INVOKE_STATIC */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* INVOKE_INTERFACE */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* UNUSED_73 */ 0, - /* INVOKE_VIRTUAL_RANGE */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* INVOKE_SUPER_RANGE */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* INVOKE_DIRECT_RANGE */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* INVOKE_STATIC_RANGE */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* INVOKE_INTERFACE_RANGE */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* UNUSED_79 */ 0, - /* UNUSED_7A */ 0, - /* NEG_INT */ kInstrCanContinue, - /* NOT_INT */ kInstrCanContinue, - /* NEG_LONG */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* NOT_LONG */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* NEG_FLOAT */ kInstrCanContinue, - /* NEG_DOUBLE */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* INT_TO_LONG */ kInstrCanContinue|kInstrWideRegA, - /* INT_TO_FLOAT */ kInstrCanContinue, - /* INT_TO_DOUBLE */ kInstrCanContinue|kInstrWideRegA, - /* LONG_TO_INT */ kInstrCanContinue|kInstrWideRegB, - /* LONG_TO_FLOAT */ kInstrCanContinue|kInstrWideRegB, - /* LONG_TO_DOUBLE */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* FLOAT_TO_INT */ kInstrCanContinue, - /* FLOAT_TO_LONG */ kInstrCanContinue|kInstrWideRegA, - /* FLOAT_TO_DOUBLE */ kInstrCanContinue|kInstrWideRegA, - /* DOUBLE_TO_INT */ kInstrCanContinue|kInstrWideRegB, - /* DOUBLE_TO_LONG */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* DOUBLE_TO_FLOAT */ kInstrCanContinue|kInstrWideRegB, - /* INT_TO_BYTE */ kInstrCanContinue, - /* INT_TO_CHAR */ kInstrCanContinue, - /* INT_TO_SHORT */ kInstrCanContinue, - /* ADD_INT */ kInstrCanContinue, - /* SUB_INT */ kInstrCanContinue, - /* MUL_INT */ kInstrCanContinue, - /* DIV_INT */ kInstrCanContinue|kInstrCanThrow, - /* REM_INT */ kInstrCanContinue|kInstrCanThrow, - /* AND_INT */ kInstrCanContinue, - /* OR_INT */ kInstrCanContinue, - /* XOR_INT */ kInstrCanContinue, - /* SHL_INT */ kInstrCanContinue, - /* SHR_INT */ kInstrCanContinue, - /* USHR_INT */ kInstrCanContinue, - /* ADD_LONG */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB|kInstrWideRegC, - /* SUB_LONG */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB|kInstrWideRegC, - /* MUL_LONG */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB|kInstrWideRegC, - /* DIV_LONG */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA|kInstrWideRegB|kInstrWideRegC, - /* REM_LONG */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA|kInstrWideRegB|kInstrWideRegC, - /* AND_LONG */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB|kInstrWideRegC, - /* OR_LONG */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB|kInstrWideRegC, - /* XOR_LONG */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB|kInstrWideRegC, - /* SHL_LONG */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* SHR_LONG */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* USHR_LONG */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* ADD_FLOAT */ kInstrCanContinue, - /* SUB_FLOAT */ kInstrCanContinue, - /* MUL_FLOAT */ kInstrCanContinue, - /* DIV_FLOAT */ kInstrCanContinue, - /* REM_FLOAT */ kInstrCanContinue, - /* ADD_DOUBLE */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB|kInstrWideRegC, - /* SUB_DOUBLE */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB|kInstrWideRegC, - /* MUL_DOUBLE */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB|kInstrWideRegC, - /* DIV_DOUBLE */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB|kInstrWideRegC, - /* REM_DOUBLE */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB|kInstrWideRegC, - /* ADD_INT_2ADDR */ kInstrCanContinue, - /* SUB_INT_2ADDR */ kInstrCanContinue, - /* MUL_INT_2ADDR */ kInstrCanContinue, - /* DIV_INT_2ADDR */ kInstrCanContinue|kInstrCanThrow, - /* REM_INT_2ADDR */ kInstrCanContinue|kInstrCanThrow, - /* AND_INT_2ADDR */ kInstrCanContinue, - /* OR_INT_2ADDR */ kInstrCanContinue, - /* XOR_INT_2ADDR */ kInstrCanContinue, - /* SHL_INT_2ADDR */ kInstrCanContinue, - /* SHR_INT_2ADDR */ kInstrCanContinue, - /* USHR_INT_2ADDR */ kInstrCanContinue, - /* ADD_LONG_2ADDR */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* SUB_LONG_2ADDR */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* MUL_LONG_2ADDR */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* DIV_LONG_2ADDR */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA|kInstrWideRegB, - /* REM_LONG_2ADDR */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA|kInstrWideRegB, - /* AND_LONG_2ADDR */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* OR_LONG_2ADDR */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* XOR_LONG_2ADDR */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* SHL_LONG_2ADDR */ kInstrCanContinue|kInstrWideRegA, - /* SHR_LONG_2ADDR */ kInstrCanContinue|kInstrWideRegA, - /* USHR_LONG_2ADDR */ kInstrCanContinue|kInstrWideRegA, - /* ADD_FLOAT_2ADDR */ kInstrCanContinue, - /* SUB_FLOAT_2ADDR */ kInstrCanContinue, - /* MUL_FLOAT_2ADDR */ kInstrCanContinue, - /* DIV_FLOAT_2ADDR */ kInstrCanContinue, - /* REM_FLOAT_2ADDR */ kInstrCanContinue, - /* ADD_DOUBLE_2ADDR */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* SUB_DOUBLE_2ADDR */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* MUL_DOUBLE_2ADDR */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* DIV_DOUBLE_2ADDR */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* REM_DOUBLE_2ADDR */ kInstrCanContinue|kInstrWideRegA|kInstrWideRegB, - /* ADD_INT_LIT16 */ kInstrCanContinue, - /* RSUB_INT */ kInstrCanContinue, - /* MUL_INT_LIT16 */ kInstrCanContinue, - /* DIV_INT_LIT16 */ kInstrCanContinue|kInstrCanThrow, - /* REM_INT_LIT16 */ kInstrCanContinue|kInstrCanThrow, - /* AND_INT_LIT16 */ kInstrCanContinue, - /* OR_INT_LIT16 */ kInstrCanContinue, - /* XOR_INT_LIT16 */ kInstrCanContinue, - /* ADD_INT_LIT8 */ kInstrCanContinue, - /* RSUB_INT_LIT8 */ kInstrCanContinue, - /* MUL_INT_LIT8 */ kInstrCanContinue, - /* DIV_INT_LIT8 */ kInstrCanContinue|kInstrCanThrow, - /* REM_INT_LIT8 */ kInstrCanContinue|kInstrCanThrow, - /* AND_INT_LIT8 */ kInstrCanContinue, - /* OR_INT_LIT8 */ kInstrCanContinue, - /* XOR_INT_LIT8 */ kInstrCanContinue, - /* SHL_INT_LIT8 */ kInstrCanContinue, - /* SHR_INT_LIT8 */ kInstrCanContinue, - /* USHR_INT_LIT8 */ kInstrCanContinue, - /* IGET_VOLATILE */ kInstrCanContinue|kInstrCanThrow, - /* IPUT_VOLATILE */ kInstrCanContinue|kInstrCanThrow, - /* SGET_VOLATILE */ kInstrCanContinue|kInstrCanThrow, - /* SPUT_VOLATILE */ kInstrCanContinue|kInstrCanThrow, - /* IGET_OBJECT_VOLATILE */ kInstrCanContinue|kInstrCanThrow, - /* IGET_WIDE_VOLATILE */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA, - /* IPUT_WIDE_VOLATILE */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA, - /* SGET_WIDE_VOLATILE */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA, - /* SPUT_WIDE_VOLATILE */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA, - /* BREAKPOINT */ 0, - /* THROW_VERIFICATION_ERROR */ kInstrCanThrow, - /* EXECUTE_INLINE */ kInstrCanContinue|kInstrCanThrow, - /* EXECUTE_INLINE_RANGE */ kInstrCanContinue|kInstrCanThrow, - /* INVOKE_OBJECT_INIT_RANGE */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* RETURN_VOID_BARRIER */ kInstrCanReturn, - /* IGET_QUICK */ kInstrCanContinue|kInstrCanThrow, - /* IGET_WIDE_QUICK */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA, - /* IGET_OBJECT_QUICK */ kInstrCanContinue|kInstrCanThrow, - /* IPUT_QUICK */ kInstrCanContinue|kInstrCanThrow, - /* IPUT_WIDE_QUICK */ kInstrCanContinue|kInstrCanThrow|kInstrWideRegA, - /* IPUT_OBJECT_QUICK */ kInstrCanContinue|kInstrCanThrow, - /* INVOKE_VIRTUAL_QUICK */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* INVOKE_VIRTUAL_QUICK_RANGE */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* INVOKE_SUPER_QUICK */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* INVOKE_SUPER_QUICK_RANGE */ kInstrCanContinue|kInstrCanThrow|kInstrInvoke, - /* IPUT_OBJECT_VOLATILE */ kInstrCanContinue|kInstrCanThrow, - /* SGET_OBJECT_VOLATILE */ kInstrCanContinue|kInstrCanThrow, - /* SPUT_OBJECT_VOLATILE */ kInstrCanContinue|kInstrCanThrow, - /* UNUSED_FF */ 0, -}; - -// Table that maps each opcode to the instruction format -static constexpr std::array gInstructionFormatTable = { - kFmt10x, kFmt12x, kFmt22x, kFmt32x, kFmt12x, kFmt22x, kFmt32x, - kFmt12x, kFmt22x, kFmt32x, kFmt11x, kFmt11x, kFmt11x, kFmt11x, - kFmt10x, kFmt11x, kFmt11x, kFmt11x, kFmt11n, kFmt21s, kFmt31i, - kFmt21h, kFmt21s, kFmt31i, kFmt51l, kFmt21h, kFmt21c, kFmt31c, - kFmt21c, kFmt11x, kFmt11x, kFmt21c, kFmt22c, kFmt12x, kFmt21c, - kFmt22c, kFmt35c, kFmt3rc, kFmt31t, kFmt11x, kFmt10t, kFmt20t, - kFmt30t, kFmt31t, kFmt31t, kFmt23x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt22t, kFmt22t, kFmt22t, kFmt22t, kFmt22t, kFmt22t, - kFmt21t, kFmt21t, kFmt21t, kFmt21t, kFmt21t, kFmt21t, kFmt00x, - kFmt00x, kFmt00x, kFmt00x, kFmt00x, kFmt00x, kFmt23x, kFmt23x, - kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt22c, kFmt22c, - kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt22c, - kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt22c, kFmt21c, kFmt21c, - kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt21c, - kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt21c, kFmt35c, kFmt35c, - kFmt35c, kFmt35c, kFmt35c, kFmt00x, kFmt3rc, kFmt3rc, kFmt3rc, - kFmt3rc, kFmt3rc, kFmt00x, kFmt00x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, kFmt23x, - kFmt23x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, - kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt12x, kFmt22s, kFmt22s, - kFmt22s, kFmt22s, kFmt22s, kFmt22s, kFmt22s, kFmt22s, kFmt22b, - kFmt22b, kFmt22b, kFmt22b, kFmt22b, kFmt22b, kFmt22b, kFmt22b, - kFmt22b, kFmt22b, kFmt22b, kFmt22c, kFmt22c, kFmt21c, kFmt21c, - kFmt22c, kFmt22c, kFmt22c, kFmt21c, kFmt21c, kFmt00x, kFmt20bc, - kFmt35mi, kFmt3rmi, kFmt35c, kFmt10x, kFmt22cs, kFmt22cs, kFmt22cs, - kFmt22cs, kFmt22cs, kFmt22cs, kFmt35ms, kFmt3rms, kFmt35ms, kFmt3rms, - kFmt22c, kFmt21c, kFmt21c, kFmt00x, -}; - -InstructionFormat GetFormatFromOpcode(Opcode opcode) { - return gInstructionFormatTable[opcode]; -} - -OpcodeFlags GetFlagsFromOpcode(Opcode opcode) { - return gOpcodeFlagsTable[opcode]; -} - // Dalvik opcode names. static constexpr std::array gOpcodeNames = { - "nop", - "move", - "move/from16", - "move/16", - "move-wide", - "move-wide/from16", - "move-wide/16", - "move-object", - "move-object/from16", - "move-object/16", - "move-result", - "move-result-wide", - "move-result-object", - "move-exception", - "return-void", - "return", - "return-wide", - "return-object", - "const/4", - "const/16", - "const", - "const/high16", - "const-wide/16", - "const-wide/32", - "const-wide", - "const-wide/high16", - "const-string", - "const-string/jumbo", - "const-class", - "monitor-enter", - "monitor-exit", - "check-cast", - "instance-of", - "array-length", - "new-instance", - "new-array", - "filled-new-array", - "filled-new-array/range", - "fill-array-data", - "throw", - "goto", - "goto/16", - "goto/32", - "packed-switch", - "sparse-switch", - "cmpl-float", - "cmpg-float", - "cmpl-double", - "cmpg-double", - "cmp-long", - "if-eq", - "if-ne", - "if-lt", - "if-ge", - "if-gt", - "if-le", - "if-eqz", - "if-nez", - "if-ltz", - "if-gez", - "if-gtz", - "if-lez", - "unused-3e", - "unused-3f", - "unused-40", - "unused-41", - "unused-42", - "unused-43", - "aget", - "aget-wide", - "aget-object", - "aget-boolean", - "aget-byte", - "aget-char", - "aget-short", - "aput", - "aput-wide", - "aput-object", - "aput-boolean", - "aput-byte", - "aput-char", - "aput-short", - "iget", - "iget-wide", - "iget-object", - "iget-boolean", - "iget-byte", - "iget-char", - "iget-short", - "iput", - "iput-wide", - "iput-object", - "iput-boolean", - "iput-byte", - "iput-char", - "iput-short", - "sget", - "sget-wide", - "sget-object", - "sget-boolean", - "sget-byte", - "sget-char", - "sget-short", - "sput", - "sput-wide", - "sput-object", - "sput-boolean", - "sput-byte", - "sput-char", - "sput-short", - "invoke-virtual", - "invoke-super", - "invoke-direct", - "invoke-static", - "invoke-interface", - "unused-73", - "invoke-virtual/range", - "invoke-super/range", - "invoke-direct/range", - "invoke-static/range", - "invoke-interface/range", - "unused-79", - "unused-7a", - "neg-int", - "not-int", - "neg-long", - "not-long", - "neg-float", - "neg-double", - "int-to-long", - "int-to-float", - "int-to-double", - "long-to-int", - "long-to-float", - "long-to-double", - "float-to-int", - "float-to-long", - "float-to-double", - "double-to-int", - "double-to-long", - "double-to-float", - "int-to-byte", - "int-to-char", - "int-to-short", - "add-int", - "sub-int", - "mul-int", - "div-int", - "rem-int", - "and-int", - "or-int", - "xor-int", - "shl-int", - "shr-int", - "ushr-int", - "add-long", - "sub-long", - "mul-long", - "div-long", - "rem-long", - "and-long", - "or-long", - "xor-long", - "shl-long", - "shr-long", - "ushr-long", - "add-float", - "sub-float", - "mul-float", - "div-float", - "rem-float", - "add-double", - "sub-double", - "mul-double", - "div-double", - "rem-double", - "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", - "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", - "add-float/2addr", - "sub-float/2addr", - "mul-float/2addr", - "div-float/2addr", - "rem-float/2addr", - "add-double/2addr", - "sub-double/2addr", - "mul-double/2addr", - "div-double/2addr", - "rem-double/2addr", - "add-int/lit16", - "rsub-int", - "mul-int/lit16", - "div-int/lit16", - "rem-int/lit16", - "and-int/lit16", - "or-int/lit16", - "xor-int/lit16", - "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", - "+iget-volatile", - "+iput-volatile", - "+sget-volatile", - "+sput-volatile", - "+iget-object-volatile", - "+iget-wide-volatile", - "+iput-wide-volatile", - "+sget-wide-volatile", - "+sput-wide-volatile", - "^breakpoint", - "^throw-verification-error", - "+execute-inline", - "+execute-inline/range", - "+invoke-object-init/range", - "+return-void-barrier", - "+iget-quick", - "+iget-wide-quick", - "+iget-object-quick", - "+iput-quick", - "+iput-wide-quick", - "+iput-object-quick", - "+invoke-virtual-quick", - "+invoke-virtual-quick/range", - "+invoke-super-quick", - "+invoke-super-quick/range", - "+iput-object-volatile", - "+sget-object-volatile", - "+sput-object-volatile", - "unused-ff", +#define INSTRUCTION_NAME(o, c, pname, f, i, a, e, v) pname, +#include "export/slicer/dex_instruction_list.h" + DEX_INSTRUCTION_LIST(INSTRUCTION_NAME) +#undef DEX_INSTRUCTION_LIST +#undef INSTRUCTION_NAME }; const char* GetOpcodeName(Opcode opcode) { return gOpcodeNames[opcode]; } @@ -738,9 +138,7 @@ static u4 InstB(u2 inst) { return inst >> 12; } static u4 InstAA(u2 inst) { return inst >> 8; } // Helper for DecodeInstruction() -static u4 FetchU4(const u2* ptr) { - return ptr[0] | (u4(ptr[1]) << 16); -} +static u4 FetchU4(const u2* ptr) { return ptr[0] | (u4(ptr[1]) << 16); } // Helper for DecodeInstruction() static u8 FetchU8(const u2* ptr) { @@ -757,85 +155,84 @@ Instruction DecodeInstruction(const u2* bytecode) { dec.opcode = opcode; switch (format) { - case kFmt10x: // op - break; - case kFmt12x: // op vA, vB + case k10x: // op + return dec; + case k12x: // op vA, vB dec.vA = InstA(inst); dec.vB = InstB(inst); - break; - case kFmt11n: // op vA, #+B + return dec; + case k11n: // op vA, #+B dec.vA = InstA(inst); dec.vB = s4(InstB(inst) << 28) >> 28; // sign extend 4-bit value - break; - case kFmt11x: // op vAA + return dec; + case k11x: // op vAA dec.vA = InstAA(inst); - break; - case kFmt10t: // op +AA + return dec; + case k10t: // op +AA dec.vA = s1(InstAA(inst)); // sign-extend 8-bit value - break; - case kFmt20t: // op +AAAA + return dec; + case k20t: // op +AAAA dec.vA = s2(bytecode[1]); // sign-extend 16-bit value - break; - case kFmt20bc: // [opt] op AA, thing@BBBB - case kFmt21c: // op vAA, thing@BBBB - case kFmt22x: // op vAA, vBBBB + return dec; + case k20bc: // [opt] op AA, thing@BBBB + case k21c: // op vAA, thing@BBBB + case k22x: // op vAA, vBBBB dec.vA = InstAA(inst); dec.vB = bytecode[1]; - break; - case kFmt21s: // op vAA, #+BBBB - case kFmt21t: // op vAA, +BBBB + return dec; + case k21s: // op vAA, #+BBBB + case k21t: // op vAA, +BBBB dec.vA = InstAA(inst); dec.vB = s2(bytecode[1]); // sign-extend 16-bit value - break; - case kFmt21h: // op vAA, #+BBBB0000[00000000] + return dec; + case k21h: // op vAA, #+BBBB0000[00000000] dec.vA = InstAA(inst); // The value should be treated as right-zero-extended, but we don't // actually do that here. Among other things, we don't know if it's // the top bits of a 32- or 64-bit value. dec.vB = bytecode[1]; - break; - case kFmt23x: // op vAA, vBB, vCC + return dec; + case k23x: // op vAA, vBB, vCC dec.vA = InstAA(inst); dec.vB = bytecode[1] & 0xff; dec.vC = bytecode[1] >> 8; - break; - case kFmt22b: // op vAA, vBB, #+CC + return dec; + case k22b: // op vAA, vBB, #+CC dec.vA = InstAA(inst); dec.vB = bytecode[1] & 0xff; dec.vC = s1(bytecode[1] >> 8); // sign-extend 8-bit value - break; - case kFmt22s: // op vA, vB, #+CCCC - case kFmt22t: // op vA, vB, +CCCC + return dec; + case k22s: // op vA, vB, #+CCCC + case k22t: // op vA, vB, +CCCC dec.vA = InstA(inst); dec.vB = InstB(inst); dec.vC = s2(bytecode[1]); // sign-extend 16-bit value - break; - case kFmt22c: // op vA, vB, thing@CCCC - case kFmt22cs: // [opt] op vA, vB, field offset CCCC + return dec; + case k22c: // op vA, vB, thing@CCCC + case k22cs: // [opt] op vA, vB, field offset CCCC dec.vA = InstA(inst); dec.vB = InstB(inst); dec.vC = bytecode[1]; - break; - case kFmt30t: // op +AAAAAAAA + return dec; + case k30t: // op +AAAAAAAA dec.vA = FetchU4(bytecode + 1); - break; - case kFmt31t: // op vAA, +BBBBBBBB - case kFmt31c: // op vAA, string@BBBBBBBB + return dec; + case k31t: // op vAA, +BBBBBBBB + case k31c: // op vAA, string@BBBBBBBB dec.vA = InstAA(inst); dec.vB = FetchU4(bytecode + 1); - break; - case kFmt32x: // op vAAAA, vBBBB + return dec; + case k32x: // op vAAAA, vBBBB dec.vA = bytecode[1]; dec.vB = bytecode[2]; - break; - case kFmt31i: // op vAA, #+BBBBBBBB + return dec; + case k31i: // op vAA, #+BBBBBBBB dec.vA = InstAA(inst); dec.vB = FetchU4(bytecode + 1); - break; - case kFmt35c: // op {vC, vD, vE, vF, vG}, thing@BBBB - case kFmt35ms: // [opt] invoke-virtual+super - case kFmt35mi: // [opt] inline invoke - { + return dec; + case k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB + case k35ms: // [opt] invoke-virtual+super + case k35mi: { // [opt] inline invoke dec.vA = InstB(inst); // This is labeled A in the spec. dec.vB = bytecode[1]; @@ -849,49 +246,91 @@ Instruction DecodeInstruction(const u2* bytecode) { switch (dec.vA) { case 5: // A fifth arg is verboten for inline invokes - SLICER_CHECK(format != kFmt35mi); + SLICER_CHECK_NE(format, k35mi); // Per note at the top of this format decoder, the // fifth argument comes from the A field in the // instruction, but it's labeled G in the spec. dec.arg[4] = InstA(inst); - // fallthrough + FALLTHROUGH_INTENDED; case 4: dec.arg[3] = (regList >> 12) & 0x0f; - // fallthrough + FALLTHROUGH_INTENDED; case 3: dec.arg[2] = (regList >> 8) & 0x0f; - // fallthrough + FALLTHROUGH_INTENDED; case 2: dec.arg[1] = (regList >> 4) & 0x0f; - // fallthrough + FALLTHROUGH_INTENDED; case 1: dec.vC = dec.arg[0] = regList & 0x0f; - // fallthrough + FALLTHROUGH_INTENDED; case 0: // Valid, but no need to do anything - break; - default: - SLICER_CHECK(!"Invalid arg count in 35c/35ms/35mi"); - break; + return dec; } - } break; - case kFmt3rc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB - case kFmt3rms: // [opt] invoke-virtual+super/range - case kFmt3rmi: // [opt] execute-inline/range + } + SLICER_CHECK(!"Invalid arg count in 35c/35ms/35mi"); + case k3rc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB + case k3rms: // [opt] invoke-virtual+super/range + case k3rmi: // [opt] execute-inline/range + dec.vA = InstAA(inst); + dec.vB = bytecode[1]; + dec.vC = bytecode[2]; + return dec; + case k45cc: { + // AG op BBBB FEDC HHHH + dec.vA = InstB(inst); // This is labelled A in the spec. + dec.vB = bytecode[1]; // vB meth@BBBB + + u2 regList = bytecode[2]; + dec.vC = regList & 0xf; + dec.arg[0] = (regList >> 4) & 0xf; // vD + dec.arg[1] = (regList >> 8) & 0xf; // vE + dec.arg[2] = (regList >> 12); // vF + dec.arg[3] = InstA(inst); // vG + dec.arg[4] = bytecode[3]; // vH proto@HHHH + } + return dec; + case k4rcc: + // AA op BBBB CCCC HHHH dec.vA = InstAA(inst); dec.vB = bytecode[1]; dec.vC = bytecode[2]; - break; - case kFmt51l: // op vAA, #+BBBBBBBBBBBBBBBB + dec.arg[4] = bytecode[3]; // vH proto@HHHH + return dec; + case k51l: // op vAA, #+BBBBBBBBBBBBBBBB dec.vA = InstAA(inst); dec.vB_wide = FetchU8(bytecode + 1); - break; - default: - SLICER_FATAL("Can't decode unexpected format 0x%02x", format); + return dec; } - return dec; + std::stringstream ss; + ss << "Can't decode unexpected format " << format << " for " << opcode; + SLICER_FATAL(ss.str()); +} + +static inline std::string HexByte(int value) { + std::stringstream ss; + ss << "0x" << std::setw(2) << std::setfill('0') << std::hex << value; + return ss.str(); +} + +std::ostream& operator<<(std::ostream& os, Opcode opcode) { + return os << "[" << HexByte(opcode) << "] " << gOpcodeNames[opcode]; +} + +std::ostream& operator<<(std::ostream& os, InstructionFormat format) { + switch (format) { + #define EMIT_INSTRUCTION_FORMAT_NAME(name) \ + case InstructionFormat::k##name: return os << #name; + #include "export/slicer/dex_instruction_list.h" + DEX_INSTRUCTION_FORMAT_LIST(EMIT_INSTRUCTION_FORMAT_NAME) + #undef EMIT_INSTRUCTION_FORMAT_NAME + #undef DEX_INSTRUCTION_FORMAT_LIST + #undef DEX_INSTRUCTION_LIST + } + return os << "[" << HexByte(format) << "] " << "Unknown"; } } // namespace dex diff --git a/dexmaker-mockito-inline/external/slicer/dex_format.cc b/dexmaker-mockito-inline/external/slicer/dex_format.cc index 7dbc762c..16b36a04 100644 --- a/dexmaker-mockito-inline/external/slicer/dex_format.cc +++ b/dexmaker-mockito-inline/external/slicer/dex_format.cc @@ -15,13 +15,22 @@ */ #include "slicer/dex_format.h" + #include "slicer/common.h" -#include #include +#include +#include namespace dex { +// The expected format of the magic is dex\nXXX\0 where XXX are digits. We extract this value. +// Returns 0 if the version can not be parsed. +u4 Header::GetVersion(const void* magic) { + const char* version = reinterpret_cast(magic) + 4; + return version[3] == '\0' ? strtol(version, nullptr, 10) : 0; +} + // Compute the DEX file checksum for a memory-mapped DEX file u4 ComputeChecksum(const Header* header) { const u1* start = reinterpret_cast(header); @@ -64,14 +73,14 @@ std::string DescriptorToDecl(const char* descriptor) { if (*descriptor == 'L') { for (++descriptor; *descriptor != ';'; ++descriptor) { - SLICER_CHECK(*descriptor != '\0'); + SLICER_CHECK_NE(*descriptor, '\0'); ss << (*descriptor == '/' ? '.' : *descriptor); } } else { ss << PrimitiveTypeName(*descriptor); } - SLICER_CHECK(descriptor[1] == '\0'); + SLICER_CHECK_EQ(descriptor[1], '\0'); // add the array brackets for (int i = 0; i < array_dimensions; ++i) { @@ -95,10 +104,10 @@ char DescriptorToShorty(const char* descriptor) { if (short_descriptor == 'L') { // skip the full class name for(; *descriptor && *descriptor != ';'; ++descriptor); - SLICER_CHECK(*descriptor == ';'); + SLICER_CHECK_EQ(*descriptor, ';'); } - SLICER_CHECK(descriptor[1] == '\0'); + SLICER_CHECK_EQ(descriptor[1], '\0'); SLICER_CHECK(short_descriptor == 'L' || PrimitiveTypeName(short_descriptor) != nullptr); return array_dimensions > 0 ? 'L' : short_descriptor; diff --git a/dexmaker-mockito-inline/external/slicer/dex_ir.cc b/dexmaker-mockito-inline/external/slicer/dex_ir.cc index 0ab1726e..b3a172e2 100644 --- a/dexmaker-mockito-inline/external/slicer/dex_ir.cc +++ b/dexmaker-mockito-inline/external/slicer/dex_ir.cc @@ -15,17 +15,16 @@ */ #include "slicer/dex_ir.h" + #include "slicer/chronometer.h" #include "slicer/dex_utf8.h" #include "slicer/dex_format.h" -#include #include -#include +#include #include -#include #include -#include +#include namespace ir { @@ -109,6 +108,15 @@ std::string Proto::Signature() const { return ss.str(); } +bool MethodHandle::IsField(){ + return ( + method_handle_type == dex::METHOD_HANDLE_TYPE_STATIC_PUT || + method_handle_type == dex::METHOD_HANDLE_TYPE_STATIC_GET || + method_handle_type == dex::METHOD_HANDLE_TYPE_INSTANCE_PUT || + method_handle_type == dex::METHOD_HANDLE_TYPE_INSTANCE_GET + ); +} + // Helper for IR normalization // (it sorts items and update the numeric idexes to match) template @@ -140,7 +148,7 @@ void DexFile::TopSortClassIndex(Class* irClass, dex::u4* nextIndex) { } } - SLICER_CHECK(*nextIndex < classes.size()); + SLICER_CHECK_LT(*nextIndex, classes.size()); irClass->index = (*nextIndex)++; } } @@ -256,8 +264,8 @@ void DexFile::Normalize() { SortClassIndexes(); IndexItems(classes, [&](const own& a, const own& b) { - SLICER_CHECK(a->index < classes.size()); - SLICER_CHECK(b->index < classes.size()); + SLICER_CHECK_LT(a->index, classes.size()); + SLICER_CHECK_LT(b->index, classes.size()); SLICER_CHECK(a->index != b->index || a == b); return a->index < b->index; }); diff --git a/dexmaker-mockito-inline/external/slicer/dex_ir_builder.cc b/dexmaker-mockito-inline/external/slicer/dex_ir_builder.cc index a078a62c..6b33de5e 100644 --- a/dexmaker-mockito-inline/external/slicer/dex_ir_builder.cc +++ b/dexmaker-mockito-inline/external/slicer/dex_ir_builder.cc @@ -78,7 +78,7 @@ String* Builder::GetAsciiString(const char* cstr) { // update the index -> ir node map auto new_index = dex_ir_->strings_indexes.AllocateIndex(); auto& ir_node = dex_ir_->strings_map[new_index]; - SLICER_CHECK(ir_node == nullptr); + SLICER_CHECK_EQ(ir_node, nullptr); ir_node = ir_string; ir_string->orig_index = new_index; @@ -106,7 +106,7 @@ Type* Builder::GetType(String* descriptor) { // update the index -> ir node map auto new_index = dex_ir_->types_indexes.AllocateIndex(); auto& ir_node = dex_ir_->types_map[new_index]; - SLICER_CHECK(ir_node == nullptr); + SLICER_CHECK_EQ(ir_node, nullptr); ir_node = ir_type; ir_type->orig_index = new_index; @@ -165,7 +165,7 @@ Proto* Builder::GetProto(Type* return_type, TypeList* param_types) { // update the index -> ir node map auto new_index = dex_ir_->protos_indexes.AllocateIndex(); auto& ir_node = dex_ir_->protos_map[new_index]; - SLICER_CHECK(ir_node == nullptr); + SLICER_CHECK_EQ(ir_node, nullptr); ir_node = ir_proto; ir_proto->orig_index = new_index; @@ -194,7 +194,7 @@ FieldDecl* Builder::GetFieldDecl(String* name, Type* type, Type* parent) { // update the index -> ir node map auto new_index = dex_ir_->fields_indexes.AllocateIndex(); auto& ir_node = dex_ir_->fields_map[new_index]; - SLICER_CHECK(ir_node == nullptr); + SLICER_CHECK_EQ(ir_node, nullptr); ir_node = ir_field; ir_field->orig_index = new_index; @@ -220,7 +220,7 @@ MethodDecl* Builder::GetMethodDecl(String* name, Proto* proto, Type* parent) { // update the index -> ir node map auto new_index = dex_ir_->methods_indexes.AllocateIndex(); auto& ir_node = dex_ir_->methods_map[new_index]; - SLICER_CHECK(ir_node == nullptr); + SLICER_CHECK_EQ(ir_node, nullptr); ir_node = ir_method; ir_method->orig_index = new_index; diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/arrayview.h b/dexmaker-mockito-inline/external/slicer/export/slicer/arrayview.h index 53c624c8..84db71ae 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/arrayview.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/arrayview.h @@ -39,7 +39,7 @@ class ArrayView { T* data() const { return begin_; } T& operator[](size_t i) const { - SLICER_CHECK(i < size()); + SLICER_CHECK_LT(i, size()); return *(begin_ + i); } diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/buffer.h b/dexmaker-mockito-inline/external/slicer/export/slicer/buffer.h index d20324d9..fa08ee7f 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/buffer.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/buffer.h @@ -16,10 +16,10 @@ #pragma once -#include "common.h" #include "arrayview.h" -#include "memview.h" +#include "common.h" #include "dex_leb128.h" +#include "memview.h" #include #include @@ -73,7 +73,7 @@ class Buffer { // template T* ptr(size_t offset) { - SLICER_CHECK(offset + sizeof(T) <= size_); + SLICER_CHECK_LE(offset + sizeof(T), size_); return reinterpret_cast(buff_ + offset); } @@ -115,7 +115,7 @@ class Buffer { } size_t Push(const Buffer& buff) { - SLICER_CHECK(&buff != this); + SLICER_CHECK_NE(&buff, this); return Push(buff.data(), buff.size()); } @@ -153,7 +153,7 @@ class Buffer { } const dex::u1* data() const { - SLICER_CHECK(buff_ != nullptr); + SLICER_CHECK_NE(buff_, nullptr); return buff_; } @@ -163,7 +163,7 @@ class Buffer { if (size_ + size > capacity_) { capacity_ = std::max(size_t(capacity_ * 1.5), size_ + size); buff_ = static_cast(::realloc(buff_, capacity_)); - SLICER_CHECK(buff_ != nullptr); + SLICER_CHECK_NE(buff_, nullptr); } size_ += size; } diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/bytecode_encoder.h b/dexmaker-mockito-inline/external/slicer/export/slicer/bytecode_encoder.h index 28d2bfae..908cbc6c 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/bytecode_encoder.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/bytecode_encoder.h @@ -16,10 +16,10 @@ #pragma once +#include "buffer.h" #include "common.h" #include "code_ir.h" #include "dex_ir.h" -#include "buffer.h" #include #include diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/chronometer.h b/dexmaker-mockito-inline/external/slicer/export/slicer/chronometer.h index a293ac43..0eae04d8 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/chronometer.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/chronometer.h @@ -26,7 +26,7 @@ class Chronometer { public: // elapsed time is in milliseconds - Chronometer(double& elapsed, bool cumulative = false) : + explicit Chronometer(double& elapsed, bool cumulative = false) : elapsed_(elapsed), cumulative_(cumulative) { start_time_ = Clock::now(); } diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/code_ir.h b/dexmaker-mockito-inline/external/slicer/export/slicer/code_ir.h index 2d028b97..34544d70 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/code_ir.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/code_ir.h @@ -16,6 +16,12 @@ #pragma once +#if defined(__clang__) + #if __has_feature(cxx_rtti) + #define RTTI_ENABLED 1 + #endif +#endif + #include "common.h" #include "memview.h" #include "dex_bytecode.h" @@ -60,6 +66,8 @@ struct String; struct Type; struct Field; struct Method; +struct MethodHandle; +struct Proto; struct DbgInfoHeader; struct LineNumber; struct DbgInfoAnnotation; @@ -96,7 +104,9 @@ class Visitor { virtual bool Visit(Type* type) { return false; } virtual bool Visit(Field* field) { return false; } virtual bool Visit(Method* method) { return false; } + virtual bool Visit(Proto* proto) { return false; } virtual bool Visit(LineNumber* line) { return false; } + virtual bool Visit(MethodHandle* mh) { return false; } }; // The root of the polymorphic code IR nodes hierarchy @@ -114,11 +124,6 @@ struct Node { Node& operator=(const Node&) = delete; virtual bool Accept(Visitor* visitor) { return false; } - - template - bool IsA() const { - return dynamic_cast(this) != nullptr; - } }; struct Operand : public Node {}; @@ -130,7 +135,7 @@ struct Const32 : public Operand { float float_value; } u; - Const32(dex::u4 value) { u.u4_value = value; } + explicit Const32(dex::u4 value) { u.u4_value = value; } virtual bool Accept(Visitor* visitor) override { return visitor->Visit(this); } }; @@ -142,7 +147,7 @@ struct Const64 : public Operand { double double_value; } u; - Const64(dex::u8 value) { u.u8_value = value; } + explicit Const64(dex::u8 value) { u.u8_value = value; } virtual bool Accept(Visitor* visitor) override { return visitor->Visit(this); } }; @@ -150,7 +155,7 @@ struct Const64 : public Operand { struct VReg : public Operand { dex::u4 reg; - VReg(dex::u4 reg) : reg(reg) {} + explicit VReg(dex::u4 reg) : reg(reg) {} virtual bool Accept(Visitor* visitor) override { return visitor->Visit(this); } }; @@ -158,7 +163,7 @@ struct VReg : public Operand { struct VRegPair : public Operand { dex::u4 base_reg; - VRegPair(dex::u4 base_reg) : base_reg(base_reg) {} + explicit VRegPair(dex::u4 base_reg) : base_reg(base_reg) {} virtual bool Accept(Visitor* visitor) override { return visitor->Visit(this); } }; @@ -181,7 +186,7 @@ struct VRegRange : public Operand { struct IndexedOperand : public Operand { dex::u4 index; - IndexedOperand(dex::u4 index) : index(index) {} + explicit IndexedOperand(dex::u4 index) : index(index) {} }; struct String : public IndexedOperand { @@ -211,7 +216,27 @@ struct Field : public IndexedOperand { struct Method : public IndexedOperand { ir::MethodDecl* ir_method; - Method(ir::MethodDecl* ir_method, dex::u4 index) : IndexedOperand(index), ir_method(ir_method) {} + Method(ir::MethodDecl* ir_method, dex::u4 index) : IndexedOperand(index), ir_method(ir_method) { + SLICER_CHECK_NE(ir_method, nullptr); + } + + virtual bool Accept(Visitor* visitor) override { return visitor->Visit(this); } +}; + +struct MethodHandle : public IndexedOperand { + ir::MethodHandle* ir_method_handle; + + MethodHandle(ir::MethodHandle* ir_method_handle, dex::u4 index) : IndexedOperand(index), ir_method_handle(ir_method_handle) { + SLICER_CHECK_NE(ir_method_handle, nullptr); + } + + virtual bool Accept(Visitor* visitor) override { return visitor->Visit(this); } +}; + +struct Proto : public IndexedOperand { + ir::Proto* ir_proto; + + Proto(ir::Proto* ir_proto, dex::u4 index) : IndexedOperand(index), ir_proto(ir_proto) {} virtual bool Accept(Visitor* visitor) override { return visitor->Visit(this); } }; @@ -219,7 +244,7 @@ struct Method : public IndexedOperand { struct CodeLocation : public Operand { Label* label; - CodeLocation(Label* label) : label(label) {} + explicit CodeLocation(Label* label) : label(label) {} virtual bool Accept(Visitor* visitor) override { return visitor->Visit(this); } }; @@ -235,15 +260,82 @@ struct Instruction : public Node { using InstructionsList = slicer::IntrusiveList; +namespace detail { + +template +inline T* CastOperand(Operand* op) { +#ifdef RTTI_ENABLED + T* operand = dynamic_cast(op); + SLICER_CHECK_NE(operand, nullptr); + return operand; +#else + SLICER_CHECK_NE(op, nullptr); + struct CastVisitor : public Visitor { + T* converted = nullptr; + bool Visit(T* val) override { + converted = val; + return true; + } + }; + CastVisitor cv; + op->Accept(&cv); + SLICER_CHECK_NE(cv.converted, nullptr); + return cv.converted; +#endif +} + +// Special-case for IndexedOperand. +template<> +inline IndexedOperand* CastOperand(Operand* op) { +#ifdef RTTI_ENABLED + IndexedOperand* operand = dynamic_cast(op); + SLICER_CHECK_NE(operand, nullptr); + return operand; +#else + SLICER_CHECK_NE(op, nullptr); + struct CastVisitor : public Visitor { + IndexedOperand* converted = nullptr; + bool Visit(String* val) override { + converted = val; + return true; + } + bool Visit(Type* val) override { + converted = val; + return true; + } + bool Visit(Field* val) override { + converted = val; + return true; + } + bool Visit(Method* val) override { + converted = val; + return true; + } + bool Visit(MethodHandle* val) override { + converted = val; + return true; + } + bool Visit(Proto* val) override { + converted = val; + return true; + } + }; + CastVisitor cv; + op->Accept(&cv); + SLICER_CHECK_NE(cv.converted, nullptr); + return cv.converted; +#endif +} + +} // namespace detail + struct Bytecode : public Instruction { dex::Opcode opcode = dex::OP_NOP; std::vector operands; template T* CastOperand(int index) const { - T* operand = dynamic_cast(operands[index]); - SLICER_CHECK(operand != nullptr); - return operand; + return detail::CastOperand(operands[index]); } virtual bool Accept(Visitor* visitor) override { return visitor->Visit(this); } @@ -278,7 +370,7 @@ struct Label : public Instruction { int refCount = 0; bool aligned = false; - Label(dex::u4 offset) { this->offset = offset; } + explicit Label(dex::u4 offset) { this->offset = offset; } virtual bool Accept(Visitor* visitor) override { return visitor->Visit(this); } }; @@ -311,8 +403,8 @@ struct DbgInfoHeader : public Instruction { struct LineNumber : public Operand { int line = 0; - LineNumber(int line) : line(line) { - SLICER_WEAK_CHECK(line > 0); + explicit LineNumber(int line) : line(line) { + SLICER_WEAK_CHECK(line >= 0); } virtual bool Accept(Visitor* visitor) override { return visitor->Visit(this); } @@ -322,13 +414,11 @@ struct DbgInfoAnnotation : public Instruction { dex::u1 dbg_opcode = 0; std::vector operands; - DbgInfoAnnotation(dex::u1 dbg_opcode) : dbg_opcode(dbg_opcode) {} + explicit DbgInfoAnnotation(dex::u1 dbg_opcode) : dbg_opcode(dbg_opcode) {} template T* CastOperand(int index) const { - T* operand = dynamic_cast(operands[index]); - SLICER_CHECK(operand != nullptr); - return operand; + return detail::CastOperand(operands[index]); } virtual bool Accept(Visitor* visitor) override { return visitor->Visit(this); } @@ -345,7 +435,7 @@ struct CodeIr { public: CodeIr(ir::EncodedMethod* ir_method, std::shared_ptr dex_ir) : ir_method(ir_method), dex_ir(dex_ir) { - Dissasemble(); + Disassemble(); } // No copy/move semantics @@ -368,10 +458,10 @@ struct CodeIr { } private: - void Dissasemble(); - void DissasembleBytecode(const ir::Code* ir_code); - void DissasembleTryBlocks(const ir::Code* ir_code); - void DissasembleDebugInfo(const ir::DebugInfo* ir_debug_info); + void Disassemble(); + void DisassembleBytecode(const ir::Code* ir_code); + void DisassembleTryBlocks(const ir::Code* ir_code); + void DisassembleDebugInfo(const ir::DebugInfo* ir_debug_info); void FixupSwitches(); void FixupPackedSwitch(PackedSwitchPayload* instr, dex::u4 base_offset, const dex::u2* ptr); @@ -383,6 +473,7 @@ struct CodeIr { Bytecode* DecodeBytecode(const dex::u2* ptr, dex::u4 offset); IndexedOperand* GetIndexedOperand(dex::InstructionIndexType index_type, dex::u4 index); + IndexedOperand* GetSecondIndexedOperand(dex::InstructionIndexType index_type, dex::u4 index); Type* GetType(dex::u4 index); String* GetString(dex::u4 index); diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/common.h b/dexmaker-mockito-inline/external/slicer/export/slicer/common.h index 4c2554cd..2d7a7dae 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/common.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/common.h @@ -16,6 +16,9 @@ #pragma once +#include +#include + namespace slicer { // Encapsulate the runtime check and error reporting policy. @@ -23,6 +26,30 @@ namespace slicer { void _checkFailed(const char* expr, int line, const char* file) __attribute__((noreturn)); #define SLICER_CHECK(expr) do { if(!(expr)) slicer::_checkFailed(#expr, __LINE__, __FILE__); } while(false) +// Helper methods for SLICER_CHECK_OP macro. +void _checkFailedOp(const void* lhs, const void* rhs, const char* op, const char* suffix, + int line, const char* file) + __attribute__((noreturn)); +void _checkFailedOp(uint32_t lhs, uint32_t rhs, const char* op, const char* suffix, int line, + const char* file) + __attribute__((noreturn)); + +#define SLICER_CHECK_OP(lhs, rhs, op, suffix) \ + do { \ + if (!((lhs) op (rhs))) { \ + slicer::_checkFailedOp(lhs, rhs, #op, suffix, __LINE__, __FILE__); \ + } \ + } while(false) + +// Macros that check the binary relation between two values. If the relation is not true, +// the values are logged and the process aborts. +#define SLICER_CHECK_EQ(a, b) SLICER_CHECK_OP(a, b, ==, "EQ") +#define SLICER_CHECK_NE(a, b) SLICER_CHECK_OP(a, b, !=, "NE") +#define SLICER_CHECK_LT(a, b) SLICER_CHECK_OP(a, b, <, "LT") +#define SLICER_CHECK_LE(a, b) SLICER_CHECK_OP(a, b, <=, "LE") +#define SLICER_CHECK_GT(a, b) SLICER_CHECK_OP(a, b, >, "GT") +#define SLICER_CHECK_GE(a, b) SLICER_CHECK_OP(a, b, >=, "GE") + // A modal check: if the strict mode is enabled, it behaves as a SLICER_CHECK, // otherwise it will only log a warning and continue // @@ -34,8 +61,8 @@ void _weakCheckFailed(const char* expr, int line, const char* file); #define SLICER_WEAK_CHECK(expr) do { if(!(expr)) slicer::_weakCheckFailed(#expr, __LINE__, __FILE__); } while(false) // Report a fatal condition with a printf-formatted message -void _fatal(const char* format, ...) __attribute__((noreturn)); -#define SLICER_FATAL(format, ...) slicer::_fatal("\nSLICER_FATAL: " format "\n\n", ##__VA_ARGS__); +void _fatal(const std::string& msg) __attribute__((noreturn)); +#define SLICER_FATAL(msg) slicer::_fatal(msg) // Annotation customization point for extra validation / state. #ifdef NDEBUG @@ -44,5 +71,19 @@ void _fatal(const char* format, ...) __attribute__((noreturn)); #define SLICER_EXTRA(x) x #endif +#ifndef FALLTHROUGH_INTENDED +#ifdef __clang__ +#define FALLTHROUGH_INTENDED [[clang::fallthrough]] +#else +#define FALLTHROUGH_INTENDED +#endif // __clang__ +#endif // FALLTHROUGH_INTENDED + +typedef void (*logger_type)(const std::string&); + +// By default, slicer prints error messages to stdout. Users can set their own +// callback. +void set_logger(const logger_type new_logger); + } // namespace slicer diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/control_flow_graph.h b/dexmaker-mockito-inline/external/slicer/export/slicer/control_flow_graph.h index 05934ff5..8ec0752c 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/control_flow_graph.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/control_flow_graph.h @@ -16,8 +16,8 @@ #pragma once -#include "common.h" #include "code_ir.h" +#include "common.h" #include diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/debuginfo_encoder.h b/dexmaker-mockito-inline/external/slicer/export/slicer/debuginfo_encoder.h index a46d4d63..53201392 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/debuginfo_encoder.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/debuginfo_encoder.h @@ -16,11 +16,11 @@ #pragma once +#include "buffer.h" +#include "chronometer.h" #include "common.h" #include "code_ir.h" #include "dex_ir.h" -#include "buffer.h" -#include "chronometer.h" #include diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/dex_bytecode.h b/dexmaker-mockito-inline/external/slicer/export/slicer/dex_bytecode.h index defcfcd6..56e113ac 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/dex_bytecode.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/dex_bytecode.h @@ -18,6 +18,7 @@ #include "dex_format.h" +#include #include // .dex bytecode definitions and helpers: @@ -35,338 +36,98 @@ constexpr u2 kPackedSwitchSignature = 0x0100; constexpr u2 kSparseSwitchSignature = 0x0200; constexpr u2 kArrayDataSignature = 0x0300; +// Include for DEX_INSTRUCTION_LIST and DEX_INSTRUCTION_FORMAT_LIST +#include "dex_instruction_list.h" + // Enumeration of all Dalvik opcodes enum Opcode : u1 { - OP_NOP = 0x00, - OP_MOVE = 0x01, - OP_MOVE_FROM16 = 0x02, - OP_MOVE_16 = 0x03, - OP_MOVE_WIDE = 0x04, - OP_MOVE_WIDE_FROM16 = 0x05, - OP_MOVE_WIDE_16 = 0x06, - OP_MOVE_OBJECT = 0x07, - OP_MOVE_OBJECT_FROM16 = 0x08, - OP_MOVE_OBJECT_16 = 0x09, - OP_MOVE_RESULT = 0x0a, - OP_MOVE_RESULT_WIDE = 0x0b, - OP_MOVE_RESULT_OBJECT = 0x0c, - OP_MOVE_EXCEPTION = 0x0d, - OP_RETURN_VOID = 0x0e, - OP_RETURN = 0x0f, - OP_RETURN_WIDE = 0x10, - OP_RETURN_OBJECT = 0x11, - OP_CONST_4 = 0x12, - OP_CONST_16 = 0x13, - OP_CONST = 0x14, - OP_CONST_HIGH16 = 0x15, - OP_CONST_WIDE_16 = 0x16, - OP_CONST_WIDE_32 = 0x17, - OP_CONST_WIDE = 0x18, - OP_CONST_WIDE_HIGH16 = 0x19, - OP_CONST_STRING = 0x1a, - OP_CONST_STRING_JUMBO = 0x1b, - OP_CONST_CLASS = 0x1c, - OP_MONITOR_ENTER = 0x1d, - OP_MONITOR_EXIT = 0x1e, - OP_CHECK_CAST = 0x1f, - OP_INSTANCE_OF = 0x20, - OP_ARRAY_LENGTH = 0x21, - OP_NEW_INSTANCE = 0x22, - OP_NEW_ARRAY = 0x23, - OP_FILLED_NEW_ARRAY = 0x24, - OP_FILLED_NEW_ARRAY_RANGE = 0x25, - OP_FILL_ARRAY_DATA = 0x26, - OP_THROW = 0x27, - OP_GOTO = 0x28, - OP_GOTO_16 = 0x29, - OP_GOTO_32 = 0x2a, - OP_PACKED_SWITCH = 0x2b, - OP_SPARSE_SWITCH = 0x2c, - OP_CMPL_FLOAT = 0x2d, - OP_CMPG_FLOAT = 0x2e, - OP_CMPL_DOUBLE = 0x2f, - OP_CMPG_DOUBLE = 0x30, - OP_CMP_LONG = 0x31, - OP_IF_EQ = 0x32, - OP_IF_NE = 0x33, - OP_IF_LT = 0x34, - OP_IF_GE = 0x35, - OP_IF_GT = 0x36, - OP_IF_LE = 0x37, - OP_IF_EQZ = 0x38, - OP_IF_NEZ = 0x39, - OP_IF_LTZ = 0x3a, - OP_IF_GEZ = 0x3b, - OP_IF_GTZ = 0x3c, - OP_IF_LEZ = 0x3d, - OP_UNUSED_3E = 0x3e, - OP_UNUSED_3F = 0x3f, - OP_UNUSED_40 = 0x40, - OP_UNUSED_41 = 0x41, - OP_UNUSED_42 = 0x42, - OP_UNUSED_43 = 0x43, - OP_AGET = 0x44, - OP_AGET_WIDE = 0x45, - OP_AGET_OBJECT = 0x46, - OP_AGET_BOOLEAN = 0x47, - OP_AGET_BYTE = 0x48, - OP_AGET_CHAR = 0x49, - OP_AGET_SHORT = 0x4a, - OP_APUT = 0x4b, - OP_APUT_WIDE = 0x4c, - OP_APUT_OBJECT = 0x4d, - OP_APUT_BOOLEAN = 0x4e, - OP_APUT_BYTE = 0x4f, - OP_APUT_CHAR = 0x50, - OP_APUT_SHORT = 0x51, - OP_IGET = 0x52, - OP_IGET_WIDE = 0x53, - OP_IGET_OBJECT = 0x54, - OP_IGET_BOOLEAN = 0x55, - OP_IGET_BYTE = 0x56, - OP_IGET_CHAR = 0x57, - OP_IGET_SHORT = 0x58, - OP_IPUT = 0x59, - OP_IPUT_WIDE = 0x5a, - OP_IPUT_OBJECT = 0x5b, - OP_IPUT_BOOLEAN = 0x5c, - OP_IPUT_BYTE = 0x5d, - OP_IPUT_CHAR = 0x5e, - OP_IPUT_SHORT = 0x5f, - OP_SGET = 0x60, - OP_SGET_WIDE = 0x61, - OP_SGET_OBJECT = 0x62, - OP_SGET_BOOLEAN = 0x63, - OP_SGET_BYTE = 0x64, - OP_SGET_CHAR = 0x65, - OP_SGET_SHORT = 0x66, - OP_SPUT = 0x67, - OP_SPUT_WIDE = 0x68, - OP_SPUT_OBJECT = 0x69, - OP_SPUT_BOOLEAN = 0x6a, - OP_SPUT_BYTE = 0x6b, - OP_SPUT_CHAR = 0x6c, - OP_SPUT_SHORT = 0x6d, - OP_INVOKE_VIRTUAL = 0x6e, - OP_INVOKE_SUPER = 0x6f, - OP_INVOKE_DIRECT = 0x70, - OP_INVOKE_STATIC = 0x71, - OP_INVOKE_INTERFACE = 0x72, - OP_UNUSED_73 = 0x73, - OP_INVOKE_VIRTUAL_RANGE = 0x74, - OP_INVOKE_SUPER_RANGE = 0x75, - OP_INVOKE_DIRECT_RANGE = 0x76, - OP_INVOKE_STATIC_RANGE = 0x77, - OP_INVOKE_INTERFACE_RANGE = 0x78, - OP_UNUSED_79 = 0x79, - OP_UNUSED_7A = 0x7a, - OP_NEG_INT = 0x7b, - OP_NOT_INT = 0x7c, - OP_NEG_LONG = 0x7d, - OP_NOT_LONG = 0x7e, - OP_NEG_FLOAT = 0x7f, - OP_NEG_DOUBLE = 0x80, - OP_INT_TO_LONG = 0x81, - OP_INT_TO_FLOAT = 0x82, - OP_INT_TO_DOUBLE = 0x83, - OP_LONG_TO_INT = 0x84, - OP_LONG_TO_FLOAT = 0x85, - OP_LONG_TO_DOUBLE = 0x86, - OP_FLOAT_TO_INT = 0x87, - OP_FLOAT_TO_LONG = 0x88, - OP_FLOAT_TO_DOUBLE = 0x89, - OP_DOUBLE_TO_INT = 0x8a, - OP_DOUBLE_TO_LONG = 0x8b, - OP_DOUBLE_TO_FLOAT = 0x8c, - OP_INT_TO_BYTE = 0x8d, - OP_INT_TO_CHAR = 0x8e, - OP_INT_TO_SHORT = 0x8f, - OP_ADD_INT = 0x90, - OP_SUB_INT = 0x91, - OP_MUL_INT = 0x92, - OP_DIV_INT = 0x93, - OP_REM_INT = 0x94, - OP_AND_INT = 0x95, - OP_OR_INT = 0x96, - OP_XOR_INT = 0x97, - OP_SHL_INT = 0x98, - OP_SHR_INT = 0x99, - OP_USHR_INT = 0x9a, - OP_ADD_LONG = 0x9b, - OP_SUB_LONG = 0x9c, - OP_MUL_LONG = 0x9d, - OP_DIV_LONG = 0x9e, - OP_REM_LONG = 0x9f, - OP_AND_LONG = 0xa0, - OP_OR_LONG = 0xa1, - OP_XOR_LONG = 0xa2, - OP_SHL_LONG = 0xa3, - OP_SHR_LONG = 0xa4, - OP_USHR_LONG = 0xa5, - OP_ADD_FLOAT = 0xa6, - OP_SUB_FLOAT = 0xa7, - OP_MUL_FLOAT = 0xa8, - OP_DIV_FLOAT = 0xa9, - OP_REM_FLOAT = 0xaa, - OP_ADD_DOUBLE = 0xab, - OP_SUB_DOUBLE = 0xac, - OP_MUL_DOUBLE = 0xad, - OP_DIV_DOUBLE = 0xae, - OP_REM_DOUBLE = 0xaf, - OP_ADD_INT_2ADDR = 0xb0, - OP_SUB_INT_2ADDR = 0xb1, - OP_MUL_INT_2ADDR = 0xb2, - OP_DIV_INT_2ADDR = 0xb3, - OP_REM_INT_2ADDR = 0xb4, - OP_AND_INT_2ADDR = 0xb5, - OP_OR_INT_2ADDR = 0xb6, - OP_XOR_INT_2ADDR = 0xb7, - OP_SHL_INT_2ADDR = 0xb8, - OP_SHR_INT_2ADDR = 0xb9, - OP_USHR_INT_2ADDR = 0xba, - OP_ADD_LONG_2ADDR = 0xbb, - OP_SUB_LONG_2ADDR = 0xbc, - OP_MUL_LONG_2ADDR = 0xbd, - OP_DIV_LONG_2ADDR = 0xbe, - OP_REM_LONG_2ADDR = 0xbf, - OP_AND_LONG_2ADDR = 0xc0, - OP_OR_LONG_2ADDR = 0xc1, - OP_XOR_LONG_2ADDR = 0xc2, - OP_SHL_LONG_2ADDR = 0xc3, - OP_SHR_LONG_2ADDR = 0xc4, - OP_USHR_LONG_2ADDR = 0xc5, - OP_ADD_FLOAT_2ADDR = 0xc6, - OP_SUB_FLOAT_2ADDR = 0xc7, - OP_MUL_FLOAT_2ADDR = 0xc8, - OP_DIV_FLOAT_2ADDR = 0xc9, - OP_REM_FLOAT_2ADDR = 0xca, - OP_ADD_DOUBLE_2ADDR = 0xcb, - OP_SUB_DOUBLE_2ADDR = 0xcc, - OP_MUL_DOUBLE_2ADDR = 0xcd, - OP_DIV_DOUBLE_2ADDR = 0xce, - OP_REM_DOUBLE_2ADDR = 0xcf, - OP_ADD_INT_LIT16 = 0xd0, - OP_RSUB_INT = 0xd1, - OP_MUL_INT_LIT16 = 0xd2, - OP_DIV_INT_LIT16 = 0xd3, - OP_REM_INT_LIT16 = 0xd4, - OP_AND_INT_LIT16 = 0xd5, - OP_OR_INT_LIT16 = 0xd6, - OP_XOR_INT_LIT16 = 0xd7, - OP_ADD_INT_LIT8 = 0xd8, - OP_RSUB_INT_LIT8 = 0xd9, - OP_MUL_INT_LIT8 = 0xda, - OP_DIV_INT_LIT8 = 0xdb, - OP_REM_INT_LIT8 = 0xdc, - OP_AND_INT_LIT8 = 0xdd, - OP_OR_INT_LIT8 = 0xde, - OP_XOR_INT_LIT8 = 0xdf, - OP_SHL_INT_LIT8 = 0xe0, - OP_SHR_INT_LIT8 = 0xe1, - OP_USHR_INT_LIT8 = 0xe2, - OP_IGET_VOLATILE = 0xe3, - OP_IPUT_VOLATILE = 0xe4, - OP_SGET_VOLATILE = 0xe5, - OP_SPUT_VOLATILE = 0xe6, - OP_IGET_OBJECT_VOLATILE = 0xe7, - OP_IGET_WIDE_VOLATILE = 0xe8, - OP_IPUT_WIDE_VOLATILE = 0xe9, - OP_SGET_WIDE_VOLATILE = 0xea, - OP_SPUT_WIDE_VOLATILE = 0xeb, - OP_BREAKPOINT = 0xec, - OP_THROW_VERIFICATION_ERROR = 0xed, - OP_EXECUTE_INLINE = 0xee, - OP_EXECUTE_INLINE_RANGE = 0xef, - OP_INVOKE_OBJECT_INIT_RANGE = 0xf0, - OP_RETURN_VOID_BARRIER = 0xf1, - OP_IGET_QUICK = 0xf2, - OP_IGET_WIDE_QUICK = 0xf3, - OP_IGET_OBJECT_QUICK = 0xf4, - OP_IPUT_QUICK = 0xf5, - OP_IPUT_WIDE_QUICK = 0xf6, - OP_IPUT_OBJECT_QUICK = 0xf7, - OP_INVOKE_VIRTUAL_QUICK = 0xf8, - OP_INVOKE_VIRTUAL_QUICK_RANGE = 0xf9, - OP_INVOKE_SUPER_QUICK = 0xfa, - OP_INVOKE_SUPER_QUICK_RANGE = 0xfb, - OP_IPUT_OBJECT_VOLATILE = 0xfc, - OP_SGET_OBJECT_VOLATILE = 0xfd, - OP_SPUT_OBJECT_VOLATILE = 0xfe, - OP_UNUSED_FF = 0xff, +#define INSTRUCTION_ENUM(opcode, cname, ...) OP_##cname = (opcode), + DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM) +#undef INSTRUCTION_ENUM }; // Instruction formats associated with Dalvik opcodes enum InstructionFormat : u1 { - kFmt00x = 0, // unknown format (also used for "breakpoint" opcode) - kFmt10x, // op - kFmt12x, // op vA, vB - kFmt11n, // op vA, #+B - kFmt11x, // op vAA - kFmt10t, // op +AA - kFmt20bc, // [opt] op AA, thing@BBBB - kFmt20t, // op +AAAA - kFmt22x, // op vAA, vBBBB - kFmt21t, // op vAA, +BBBB - kFmt21s, // op vAA, #+BBBB - kFmt21h, // op vAA, #+BBBB00000[00000000] - kFmt21c, // op vAA, thing@BBBB - kFmt23x, // op vAA, vBB, vCC - kFmt22b, // op vAA, vBB, #+CC - kFmt22t, // op vA, vB, +CCCC - kFmt22s, // op vA, vB, #+CCCC - kFmt22c, // op vA, vB, thing@CCCC - kFmt22cs, // [opt] op vA, vB, field offset CCCC - kFmt30t, // op +AAAAAAAA - kFmt32x, // op vAAAA, vBBBB - kFmt31i, // op vAA, #+BBBBBBBB - kFmt31t, // op vAA, +BBBBBBBB - kFmt31c, // op vAA, string@BBBBBBBB - kFmt35c, // op {vC,vD,vE,vF,vG}, thing@BBBB - kFmt35ms, // [opt] invoke-virtual+super - kFmt3rc, // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB - kFmt3rms, // [opt] invoke-virtual+super/range - kFmt51l, // op vAA, #+BBBBBBBBBBBBBBBB - kFmt35mi, // [opt] inline invoke - kFmt3rmi, // [opt] inline invoke/range +#define INSTRUCTION_FORMAT_ENUM(name) k##name, +#include "dex_instruction_list.h" + DEX_INSTRUCTION_FORMAT_LIST(INSTRUCTION_FORMAT_ENUM) +#undef INSTRUCTION_FORMAT_ENUM }; -using OpcodeFlags = u4; +#undef DEX_INSTRUCTION_FORMAT_LIST +#undef DEX_INSTRUCTION_LIST +using OpcodeFlags = u1; enum : OpcodeFlags { - kInstrCanBranch = 1 << 0, // conditional or unconditional branch - kInstrCanContinue = 1 << 1, // flow can continue to next statement - kInstrCanSwitch = 1 << 2, // switch statement - kInstrCanThrow = 1 << 3, // could cause an exception to be thrown - kInstrCanReturn = 1 << 4, // returns, no additional statements - kInstrInvoke = 1 << 5, // a flavor of invoke - kInstrWideRegA = 1 << 6, // wide (64bit) vA - kInstrWideRegB = 1 << 7, // wide (64bit) vB - kInstrWideRegC = 1 << 8, // wide (64bit) vC + kBranch = 0x01, // conditional or unconditional branch + kContinue = 0x02, // flow can continue to next statement + kSwitch = 0x04, // switch statement + kThrow = 0x08, // could cause an exception to be thrown + kReturn = 0x10, // returns, no additional statements + kInvoke = 0x20, // a flavor of invoke + kUnconditional = 0x40, // unconditional branch + kExperimental = 0x80, // is an experimental opcode +}; + +using VerifyFlags = u4; +enum : VerifyFlags { + kVerifyNothing = 0x0000000, + kVerifyRegA = 0x0000001, + kVerifyRegAWide = 0x0000002, + kVerifyRegB = 0x0000004, + kVerifyRegBField = 0x0000008, + kVerifyRegBMethod = 0x0000010, + kVerifyRegBNewInstance = 0x0000020, + kVerifyRegBString = 0x0000040, + kVerifyRegBType = 0x0000080, + kVerifyRegBWide = 0x0000100, + kVerifyRegC = 0x0000200, + kVerifyRegCField = 0x0000400, + kVerifyRegCNewArray = 0x0000800, + kVerifyRegCType = 0x0001000, + kVerifyRegCWide = 0x0002000, + kVerifyArrayData = 0x0004000, + kVerifyBranchTarget = 0x0008000, + kVerifySwitchTargets = 0x0010000, + kVerifyVarArg = 0x0020000, + kVerifyVarArgNonZero = 0x0040000, + kVerifyVarArgRange = 0x0080000, + kVerifyVarArgRangeNonZero = 0x0100000, + kVerifyRuntimeOnly = 0x0200000, + kVerifyError = 0x0400000, + kVerifyRegHPrototype = 0x0800000, + kVerifyRegBCallSite = 0x1000000, + kVerifyRegBMethodHandle = 0x2000000, + kVerifyRegBPrototype = 0x4000000, }; // Types of indexed reference that are associated with opcodes whose // formats include such an indexed reference (e.g., 21c and 35c). enum InstructionIndexType : u1 { kIndexUnknown = 0, - kIndexNone, // has no index - kIndexVaries, // "It depends." Used for throw-verification-error - kIndexTypeRef, // type reference index - kIndexStringRef, // string reference index - kIndexMethodRef, // method reference index - kIndexFieldRef, // field reference index - kIndexInlineMethod, // inline method index (for inline linked methods) - kIndexVtableOffset, // vtable offset (for static linked methods) - kIndexFieldOffset // field offset (for static linked fields) + kIndexNone, // has no index + kIndexVaries, // "It depends." Used for throw-verification-error + kIndexTypeRef, // type reference index + kIndexStringRef, // string reference index + kIndexMethodRef, // method reference index + kIndexFieldRef, // field reference index + kIndexInlineMethod, // inline method index (for inline linked methods) + kIndexVtableOffset, // vtable offset (for static linked methods) + kIndexFieldOffset, // field offset (for static linked fields) + kIndexMethodAndProtoRef, // method index and proto index + kIndexCallSiteRef, // call site index + kIndexMethodHandleRef, // constant method handle reference index + kIndexProtoRef, // constant prototype reference index }; // Holds the contents of a decoded instruction. struct Instruction { - u4 vA; // the A field of the instruction - u4 vB; // the B field of the instruction - u8 vB_wide; // 64bit version of the B field (for kFmt51l) - u4 vC; // the C field of the instruction - u4 arg[5]; // vC/D/E/F/G in invoke or filled-new-array - Opcode opcode; // instruction opcode + u4 vA; // the A field of the instruction + u4 vB; // the B field of the instruction + u8 vB_wide; // 64bit version of the B field (for k51l) + u4 vC; // the C field of the instruction + u4 arg[5]; // vC/D/E/F/G in invoke or filled-new-array + Opcode opcode; // instruction opcode }; // "packed-switch-payload" format @@ -392,6 +153,14 @@ struct ArrayData { u1 data[]; }; +// Collect the enums in a struct for better locality. +struct InstructionDescriptor { + u4 verify_flags; // Set of VerifyFlag. + InstructionFormat format; + InstructionIndexType index_type; + u1 flags; // Set of Flags. +}; + // Extracts the opcode from a Dalvik code unit (bytecode) Opcode OpcodeFromBytecode(u2 bytecode); @@ -407,8 +176,11 @@ InstructionFormat GetFormatFromOpcode(Opcode opcode); // Returns the flags for the specified opcode OpcodeFlags GetFlagsFromOpcode(Opcode opcode); -// Returns the instruction width for the specified opcode -size_t GetWidthFromOpcode(Opcode opcode); +// Returns the verify flags for the specified opcode +VerifyFlags GetVerifyFlagsFromOpcode(Opcode opcode); + +// Returns the instruction width for the specified opcode format +size_t GetWidthFromFormat(InstructionFormat format); // Return the width of the specified instruction, or 0 if not defined. Also // works for special OP_NOP entries, including switch statement data tables @@ -418,4 +190,10 @@ size_t GetWidthFromBytecode(const u2* bytecode); // Decode a .dex bytecode Instruction DecodeInstruction(const u2* bytecode); +// Writes a hex formatted opcode to an output stream. +std::ostream& operator<<(std::ostream& os, Opcode opcode); + +// Writes name of format to an outputstream. +std::ostream& operator<<(std::ostream& os, InstructionFormat format); + } // namespace dex diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/dex_format.h b/dexmaker-mockito-inline/external/slicer/export/slicer/dex_format.h index 77a247de..e73d1dc7 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/dex_format.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/dex_format.h @@ -101,6 +101,7 @@ constexpr u2 kProtoIdItem = 0x0003; constexpr u2 kFieldIdItem = 0x0004; constexpr u2 kMethodIdItem = 0x0005; constexpr u2 kClassDefItem = 0x0006; +constexpr u2 kMethodHandleItem = 0x0008; constexpr u2 kMapList = 0x1000; constexpr u2 kTypeList = 0x1001; constexpr u2 kAnnotationSetRefList = 0x1002; @@ -126,12 +127,54 @@ constexpr u1 DBG_SET_EPILOGUE_BEGIN = 0x08; constexpr u1 DBG_SET_FILE = 0x09; constexpr u1 DBG_FIRST_SPECIAL = 0x0a; + +// method handle type +constexpr u1 METHOD_HANDLE_TYPE_STATIC_PUT = 0x00; +constexpr u1 METHOD_HANDLE_TYPE_STATIC_GET = 0x01; +constexpr u1 METHOD_HANDLE_TYPE_INSTANCE_PUT = 0x02; +constexpr u1 METHOD_HANDLE_TYPE_INSTANCE_GET = 0x03; +constexpr u1 METHOD_HANDLE_TYPE_INVOKE_STATIC = 0x04; +constexpr u1 METHOD_HANDLE_TYPE_INVOKE_INSTANCE = 0x05; +constexpr u1 METHOD_HANDLE_TYPE_INVOKE_CONSTRUCTOR = 0x06; +constexpr u1 METHOD_HANDLE_TYPE_INVOKE_DIRECT = 0x07; +constexpr u1 METHOD_HANDLE_TYPE_INVOKE_INTERFACE = 0x08; + // special debug info values constexpr int DBG_LINE_BASE = -4; constexpr int DBG_LINE_RANGE = 15; // "header_item" struct Header { + static constexpr size_t kV40Size = 0x70; // Same as all previous dex versions. + static constexpr size_t kV41Size = 0x78; // Added container_{size,off} fields. + // See http://go/dex-container-format + static constexpr size_t kMaxSize = kV41Size; + + static constexpr u4 kV41 = 41; + static constexpr u4 kMinVersion = 35; // Minimum supported dex version. + static constexpr u4 kMaxVersion = 41; // Maximum supported dex version. + + // Parse magic number and extract the version integer. E.g.: `dex\n123\0` returns `123`. + // Returns 0 upon failure. + static u4 GetVersion(const void* magic); + + u4 GetVersion() const { + return GetVersion(magic); + } + + u4 ContainerSize() const { + return header_size >= kV41Size ? container_size : file_size; + } + + u4 ContainerOff() const { + return header_size >= kV41Size ? container_off : 0; + } + + void SetContainer(u4 off, u4 size) { + container_off = off; + container_size = size; + } + u1 magic[8]; u4 checksum; u1 signature[kSHA1DigestLen]; @@ -155,6 +198,10 @@ struct Header { u4 class_defs_off; u4 data_size; u4 data_off; + + private: + u4 container_size; + u4 container_off; }; // "map_item" @@ -214,6 +261,14 @@ struct ClassDef { u4 static_values_off; }; +// "method_handle_item" +struct MethodHandle { + u2 method_handle_type; + u2 unused; + u2 field_or_method_id; + u2 unused2; +}; + // "type_item" struct TypeItem { u2 type_idx; diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/dex_instruction_list.h b/dexmaker-mockito-inline/external/slicer/export/slicer/dex_instruction_list.h new file mode 100644 index 00000000..86566cd9 --- /dev/null +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/dex_instruction_list.h @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_LIST_H_ +#define ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_LIST_H_ + +/** + * Cloned from //art/libdexfile/dex/dex_instruction_list.h. + */ + +// V(opcode, instruction_code, name, format, index, flags, extended_flags, verifier_flags); +#define DEX_INSTRUCTION_LIST(V) \ + V(0x00, NOP, "nop", k10x, kIndexNone, kContinue, 0, kVerifyNothing) \ + V(0x01, MOVE, "move", k12x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \ + V(0x02, MOVE_FROM16, "move/from16", k22x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \ + V(0x03, MOVE_16, "move/16", k32x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \ + V(0x04, MOVE_WIDE, "move-wide", k12x, kIndexNone, kContinue, 0, kVerifyRegAWide | kVerifyRegBWide) \ + V(0x05, MOVE_WIDE_FROM16, "move-wide/from16", k22x, kIndexNone, kContinue, 0, kVerifyRegAWide | kVerifyRegBWide) \ + V(0x06, MOVE_WIDE_16, "move-wide/16", k32x, kIndexNone, kContinue, 0, kVerifyRegAWide | kVerifyRegBWide) \ + V(0x07, MOVE_OBJECT, "move-object", k12x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \ + V(0x08, MOVE_OBJECT_FROM16, "move-object/from16", k22x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \ + V(0x09, MOVE_OBJECT_16, "move-object/16", k32x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \ + V(0x0A, MOVE_RESULT, "move-result", k11x, kIndexNone, kContinue, 0, kVerifyRegA) \ + V(0x0B, MOVE_RESULT_WIDE, "move-result-wide", k11x, kIndexNone, kContinue, 0, kVerifyRegAWide) \ + V(0x0C, MOVE_RESULT_OBJECT, "move-result-object", k11x, kIndexNone, kContinue, 0, kVerifyRegA) \ + V(0x0D, MOVE_EXCEPTION, "move-exception", k11x, kIndexNone, kContinue, 0, kVerifyRegA) \ + V(0x0E, RETURN_VOID, "return-void", k10x, kIndexNone, kReturn, 0, kVerifyNothing) \ + V(0x0F, RETURN, "return", k11x, kIndexNone, kReturn, 0, kVerifyRegA) \ + V(0x10, RETURN_WIDE, "return-wide", k11x, kIndexNone, kReturn, 0, kVerifyRegAWide) \ + V(0x11, RETURN_OBJECT, "return-object", k11x, kIndexNone, kReturn, 0, kVerifyRegA) \ + V(0x12, CONST_4, "const/4", k11n, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegA) \ + V(0x13, CONST_16, "const/16", k21s, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegA) \ + V(0x14, CONST, "const", k31i, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegA) \ + V(0x15, CONST_HIGH16, "const/high16", k21h, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegA) \ + V(0x16, CONST_WIDE_16, "const-wide/16", k21s, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegAWide) \ + V(0x17, CONST_WIDE_32, "const-wide/32", k31i, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegAWide) \ + V(0x18, CONST_WIDE, "const-wide", k51l, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegAWide) \ + V(0x19, CONST_WIDE_HIGH16, "const-wide/high16", k21h, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegAWide) \ + V(0x1A, CONST_STRING, "const-string", k21c, kIndexStringRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBString) \ + V(0x1B, CONST_STRING_JUMBO, "const-string/jumbo", k31c, kIndexStringRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBString) \ + V(0x1C, CONST_CLASS, "const-class", k21c, kIndexTypeRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBType) \ + V(0x1D, MONITOR_ENTER, "monitor-enter", k11x, kIndexNone, kContinue | kThrow, kClobber, kVerifyRegA) \ + V(0x1E, MONITOR_EXIT, "monitor-exit", k11x, kIndexNone, kContinue | kThrow, kClobber, kVerifyRegA) \ + V(0x1F, CHECK_CAST, "check-cast", k21c, kIndexTypeRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBType) \ + V(0x20, INSTANCE_OF, "instance-of", k22c, kIndexTypeRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegB | kVerifyRegCType) \ + V(0x21, ARRAY_LENGTH, "array-length", k12x, kIndexNone, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegB) \ + V(0x22, NEW_INSTANCE, "new-instance", k21c, kIndexTypeRef, kContinue | kThrow, kClobber, kVerifyRegA | kVerifyRegBNewInstance) \ + V(0x23, NEW_ARRAY, "new-array", k22c, kIndexTypeRef, kContinue | kThrow, kClobber, kVerifyRegA | kVerifyRegB | kVerifyRegCNewArray) \ + V(0x24, FILLED_NEW_ARRAY, "filled-new-array", k35c, kIndexTypeRef, kContinue | kThrow, kClobber, kVerifyRegBType | kVerifyVarArg) \ + V(0x25, FILLED_NEW_ARRAY_RANGE, "filled-new-array/range", k3rc, kIndexTypeRef, kContinue | kThrow, kClobber, kVerifyRegBType | kVerifyVarArgRange) \ + V(0x26, FILL_ARRAY_DATA, "fill-array-data", k31t, kIndexNone, kContinue | kThrow, kClobber, kVerifyRegA | kVerifyArrayData) \ + V(0x27, THROW, "throw", k11x, kIndexNone, kThrow, 0, kVerifyRegA) \ + V(0x28, GOTO, "goto", k10t, kIndexNone, kBranch | kUnconditional, 0, kVerifyBranchTarget) \ + V(0x29, GOTO_16, "goto/16", k20t, kIndexNone, kBranch | kUnconditional, 0, kVerifyBranchTarget) \ + V(0x2A, GOTO_32, "goto/32", k30t, kIndexNone, kBranch | kUnconditional, 0, kVerifyBranchTarget) \ + V(0x2B, PACKED_SWITCH, "packed-switch", k31t, kIndexNone, kContinue | kSwitch, 0, kVerifyRegA | kVerifySwitchTargets) \ + V(0x2C, SPARSE_SWITCH, "sparse-switch", k31t, kIndexNone, kContinue | kSwitch, 0, kVerifyRegA | kVerifySwitchTargets) \ + V(0x2D, CMPL_FLOAT, "cmpl-float", k23x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x2E, CMPG_FLOAT, "cmpg-float", k23x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x2F, CMPL_DOUBLE, "cmpl-double", k23x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \ + V(0x30, CMPG_DOUBLE, "cmpg-double", k23x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \ + V(0x31, CMP_LONG, "cmp-long", k23x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \ + V(0x32, IF_EQ, "if-eq", k22t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \ + V(0x33, IF_NE, "if-ne", k22t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \ + V(0x34, IF_LT, "if-lt", k22t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \ + V(0x35, IF_GE, "if-ge", k22t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \ + V(0x36, IF_GT, "if-gt", k22t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \ + V(0x37, IF_LE, "if-le", k22t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \ + V(0x38, IF_EQZ, "if-eqz", k21t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyBranchTarget) \ + V(0x39, IF_NEZ, "if-nez", k21t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyBranchTarget) \ + V(0x3A, IF_LTZ, "if-ltz", k21t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyBranchTarget) \ + V(0x3B, IF_GEZ, "if-gez", k21t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyBranchTarget) \ + V(0x3C, IF_GTZ, "if-gtz", k21t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyBranchTarget) \ + V(0x3D, IF_LEZ, "if-lez", k21t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyBranchTarget) \ + V(0x3E, UNUSED_3E, "unused-3e", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0x3F, UNUSED_3F, "unused-3f", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0x40, UNUSED_40, "unused-40", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0x41, UNUSED_41, "unused-41", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0x42, UNUSED_42, "unused-42", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0x43, UNUSED_43, "unused-43", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0x44, AGET, "aget", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x45, AGET_WIDE, "aget-wide", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \ + V(0x46, AGET_OBJECT, "aget-object", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x47, AGET_BOOLEAN, "aget-boolean", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x48, AGET_BYTE, "aget-byte", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x49, AGET_CHAR, "aget-char", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x4A, AGET_SHORT, "aget-short", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x4B, APUT, "aput", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x4C, APUT_WIDE, "aput-wide", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \ + V(0x4D, APUT_OBJECT, "aput-object", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x4E, APUT_BOOLEAN, "aput-boolean", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x4F, APUT_BYTE, "aput-byte", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x50, APUT_CHAR, "aput-char", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x51, APUT_SHORT, "aput-short", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x52, IGET, "iget", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x53, IGET_WIDE, "iget-wide", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \ + V(0x54, IGET_OBJECT, "iget-object", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x55, IGET_BOOLEAN, "iget-boolean", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x56, IGET_BYTE, "iget-byte", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x57, IGET_CHAR, "iget-char", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x58, IGET_SHORT, "iget-short", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x59, IPUT, "iput", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x5A, IPUT_WIDE, "iput-wide", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \ + V(0x5B, IPUT_OBJECT, "iput-object", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x5C, IPUT_BOOLEAN, "iput-boolean", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x5D, IPUT_BYTE, "iput-byte", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x5E, IPUT_CHAR, "iput-char", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x5F, IPUT_SHORT, "iput-short", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x60, SGET, "sget", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x61, SGET_WIDE, "sget-wide", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegAWide | kVerifyRegBField) \ + V(0x62, SGET_OBJECT, "sget-object", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x63, SGET_BOOLEAN, "sget-boolean", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x64, SGET_BYTE, "sget-byte", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x65, SGET_CHAR, "sget-char", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x66, SGET_SHORT, "sget-short", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x67, SPUT, "sput", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x68, SPUT_WIDE, "sput-wide", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegAWide | kVerifyRegBField) \ + V(0x69, SPUT_OBJECT, "sput-object", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x6A, SPUT_BOOLEAN, "sput-boolean", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x6B, SPUT_BYTE, "sput-byte", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x6C, SPUT_CHAR, "sput-char", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x6D, SPUT_SHORT, "sput-short", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x6E, INVOKE_VIRTUAL, "invoke-virtual", k35c, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgNonZero) \ + V(0x6F, INVOKE_SUPER, "invoke-super", k35c, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgNonZero) \ + V(0x70, INVOKE_DIRECT, "invoke-direct", k35c, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgNonZero) \ + V(0x71, INVOKE_STATIC, "invoke-static", k35c, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArg) \ + V(0x72, INVOKE_INTERFACE, "invoke-interface", k35c, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgNonZero) \ + V(0x73, RETURN_VOID_NO_BARRIER, "return-void-no-barrier", k10x, kIndexNone, kReturn, 0, kVerifyNothing) \ + V(0x74, INVOKE_VIRTUAL_RANGE, "invoke-virtual/range", k3rc, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \ + V(0x75, INVOKE_SUPER_RANGE, "invoke-super/range", k3rc, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \ + V(0x76, INVOKE_DIRECT_RANGE, "invoke-direct/range", k3rc, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \ + V(0x77, INVOKE_STATIC_RANGE, "invoke-static/range", k3rc, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgRange) \ + V(0x78, INVOKE_INTERFACE_RANGE, "invoke-interface/range", k3rc, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \ + V(0x79, UNUSED_79, "unused-79", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0x7A, UNUSED_7A, "unused-7a", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0x7B, NEG_INT, "neg-int", k12x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \ + V(0x7C, NOT_INT, "not-int", k12x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \ + V(0x7D, NEG_LONG, "neg-long", k12x, kIndexNone, kContinue, 0, kVerifyRegAWide | kVerifyRegBWide) \ + V(0x7E, NOT_LONG, "not-long", k12x, kIndexNone, kContinue, 0, kVerifyRegAWide | kVerifyRegBWide) \ + V(0x7F, NEG_FLOAT, "neg-float", k12x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \ + V(0x80, NEG_DOUBLE, "neg-double", k12x, kIndexNone, kContinue, 0, kVerifyRegAWide | kVerifyRegBWide) \ + V(0x81, INT_TO_LONG, "int-to-long", k12x, kIndexNone, kContinue, kCast, kVerifyRegAWide | kVerifyRegB) \ + V(0x82, INT_TO_FLOAT, "int-to-float", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegB) \ + V(0x83, INT_TO_DOUBLE, "int-to-double", k12x, kIndexNone, kContinue, kCast, kVerifyRegAWide | kVerifyRegB) \ + V(0x84, LONG_TO_INT, "long-to-int", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegBWide) \ + V(0x85, LONG_TO_FLOAT, "long-to-float", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegBWide) \ + V(0x86, LONG_TO_DOUBLE, "long-to-double", k12x, kIndexNone, kContinue, kCast, kVerifyRegAWide | kVerifyRegBWide) \ + V(0x87, FLOAT_TO_INT, "float-to-int", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegB) \ + V(0x88, FLOAT_TO_LONG, "float-to-long", k12x, kIndexNone, kContinue, kCast, kVerifyRegAWide | kVerifyRegB) \ + V(0x89, FLOAT_TO_DOUBLE, "float-to-double", k12x, kIndexNone, kContinue, kCast, kVerifyRegAWide | kVerifyRegB) \ + V(0x8A, DOUBLE_TO_INT, "double-to-int", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegBWide) \ + V(0x8B, DOUBLE_TO_LONG, "double-to-long", k12x, kIndexNone, kContinue, kCast, kVerifyRegAWide | kVerifyRegBWide) \ + V(0x8C, DOUBLE_TO_FLOAT, "double-to-float", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegBWide) \ + V(0x8D, INT_TO_BYTE, "int-to-byte", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegB) \ + V(0x8E, INT_TO_CHAR, "int-to-char", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegB) \ + V(0x8F, INT_TO_SHORT, "int-to-short", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegB) \ + V(0x90, ADD_INT, "add-int", k23x, kIndexNone, kContinue, kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x91, SUB_INT, "sub-int", k23x, kIndexNone, kContinue, kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x92, MUL_INT, "mul-int", k23x, kIndexNone, kContinue, kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x93, DIV_INT, "div-int", k23x, kIndexNone, kContinue | kThrow, kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x94, REM_INT, "rem-int", k23x, kIndexNone, kContinue | kThrow, kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x95, AND_INT, "and-int", k23x, kIndexNone, kContinue, kAnd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x96, OR_INT, "or-int", k23x, kIndexNone, kContinue, kOr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x97, XOR_INT, "xor-int", k23x, kIndexNone, kContinue, kXor, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x98, SHL_INT, "shl-int", k23x, kIndexNone, kContinue, kShl, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x99, SHR_INT, "shr-int", k23x, kIndexNone, kContinue, kShr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x9A, USHR_INT, "ushr-int", k23x, kIndexNone, kContinue, kUshr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x9B, ADD_LONG, "add-long", k23x, kIndexNone, kContinue, kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0x9C, SUB_LONG, "sub-long", k23x, kIndexNone, kContinue, kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0x9D, MUL_LONG, "mul-long", k23x, kIndexNone, kContinue, kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0x9E, DIV_LONG, "div-long", k23x, kIndexNone, kContinue | kThrow, kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0x9F, REM_LONG, "rem-long", k23x, kIndexNone, kContinue | kThrow, kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xA0, AND_LONG, "and-long", k23x, kIndexNone, kContinue, kAnd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xA1, OR_LONG, "or-long", k23x, kIndexNone, kContinue, kOr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xA2, XOR_LONG, "xor-long", k23x, kIndexNone, kContinue, kXor, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xA3, SHL_LONG, "shl-long", k23x, kIndexNone, kContinue, kShl, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \ + V(0xA4, SHR_LONG, "shr-long", k23x, kIndexNone, kContinue, kShr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \ + V(0xA5, USHR_LONG, "ushr-long", k23x, kIndexNone, kContinue, kUshr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \ + V(0xA6, ADD_FLOAT, "add-float", k23x, kIndexNone, kContinue, kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0xA7, SUB_FLOAT, "sub-float", k23x, kIndexNone, kContinue, kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0xA8, MUL_FLOAT, "mul-float", k23x, kIndexNone, kContinue, kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0xA9, DIV_FLOAT, "div-float", k23x, kIndexNone, kContinue, kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0xAA, REM_FLOAT, "rem-float", k23x, kIndexNone, kContinue, kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0xAB, ADD_DOUBLE, "add-double", k23x, kIndexNone, kContinue, kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xAC, SUB_DOUBLE, "sub-double", k23x, kIndexNone, kContinue, kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xAD, MUL_DOUBLE, "mul-double", k23x, kIndexNone, kContinue, kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xAE, DIV_DOUBLE, "div-double", k23x, kIndexNone, kContinue, kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xAF, REM_DOUBLE, "rem-double", k23x, kIndexNone, kContinue, kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xB0, ADD_INT_2ADDR, "add-int/2addr", k12x, kIndexNone, kContinue, kAdd, kVerifyRegA | kVerifyRegB) \ + V(0xB1, SUB_INT_2ADDR, "sub-int/2addr", k12x, kIndexNone, kContinue, kSubtract, kVerifyRegA | kVerifyRegB) \ + V(0xB2, MUL_INT_2ADDR, "mul-int/2addr", k12x, kIndexNone, kContinue, kMultiply, kVerifyRegA | kVerifyRegB) \ + V(0xB3, DIV_INT_2ADDR, "div-int/2addr", k12x, kIndexNone, kContinue | kThrow, kDivide, kVerifyRegA | kVerifyRegB) \ + V(0xB4, REM_INT_2ADDR, "rem-int/2addr", k12x, kIndexNone, kContinue | kThrow, kRemainder, kVerifyRegA | kVerifyRegB) \ + V(0xB5, AND_INT_2ADDR, "and-int/2addr", k12x, kIndexNone, kContinue, kAnd, kVerifyRegA | kVerifyRegB) \ + V(0xB6, OR_INT_2ADDR, "or-int/2addr", k12x, kIndexNone, kContinue, kOr, kVerifyRegA | kVerifyRegB) \ + V(0xB7, XOR_INT_2ADDR, "xor-int/2addr", k12x, kIndexNone, kContinue, kXor, kVerifyRegA | kVerifyRegB) \ + V(0xB8, SHL_INT_2ADDR, "shl-int/2addr", k12x, kIndexNone, kContinue, kShl, kVerifyRegA | kVerifyRegB) \ + V(0xB9, SHR_INT_2ADDR, "shr-int/2addr", k12x, kIndexNone, kContinue, kShr, kVerifyRegA | kVerifyRegB) \ + V(0xBA, USHR_INT_2ADDR, "ushr-int/2addr", k12x, kIndexNone, kContinue, kUshr, kVerifyRegA | kVerifyRegB) \ + V(0xBB, ADD_LONG_2ADDR, "add-long/2addr", k12x, kIndexNone, kContinue, kAdd, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xBC, SUB_LONG_2ADDR, "sub-long/2addr", k12x, kIndexNone, kContinue, kSubtract, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xBD, MUL_LONG_2ADDR, "mul-long/2addr", k12x, kIndexNone, kContinue, kMultiply, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xBE, DIV_LONG_2ADDR, "div-long/2addr", k12x, kIndexNone, kContinue | kThrow, kDivide, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xBF, REM_LONG_2ADDR, "rem-long/2addr", k12x, kIndexNone, kContinue | kThrow, kRemainder, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xC0, AND_LONG_2ADDR, "and-long/2addr", k12x, kIndexNone, kContinue, kAnd, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xC1, OR_LONG_2ADDR, "or-long/2addr", k12x, kIndexNone, kContinue, kOr, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xC2, XOR_LONG_2ADDR, "xor-long/2addr", k12x, kIndexNone, kContinue, kXor, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xC3, SHL_LONG_2ADDR, "shl-long/2addr", k12x, kIndexNone, kContinue, kShl, kVerifyRegAWide | kVerifyRegB) \ + V(0xC4, SHR_LONG_2ADDR, "shr-long/2addr", k12x, kIndexNone, kContinue, kShr, kVerifyRegAWide | kVerifyRegB) \ + V(0xC5, USHR_LONG_2ADDR, "ushr-long/2addr", k12x, kIndexNone, kContinue, kUshr, kVerifyRegAWide | kVerifyRegB) \ + V(0xC6, ADD_FLOAT_2ADDR, "add-float/2addr", k12x, kIndexNone, kContinue, kAdd, kVerifyRegA | kVerifyRegB) \ + V(0xC7, SUB_FLOAT_2ADDR, "sub-float/2addr", k12x, kIndexNone, kContinue, kSubtract, kVerifyRegA | kVerifyRegB) \ + V(0xC8, MUL_FLOAT_2ADDR, "mul-float/2addr", k12x, kIndexNone, kContinue, kMultiply, kVerifyRegA | kVerifyRegB) \ + V(0xC9, DIV_FLOAT_2ADDR, "div-float/2addr", k12x, kIndexNone, kContinue, kDivide, kVerifyRegA | kVerifyRegB) \ + V(0xCA, REM_FLOAT_2ADDR, "rem-float/2addr", k12x, kIndexNone, kContinue, kRemainder, kVerifyRegA | kVerifyRegB) \ + V(0xCB, ADD_DOUBLE_2ADDR, "add-double/2addr", k12x, kIndexNone, kContinue, kAdd, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xCC, SUB_DOUBLE_2ADDR, "sub-double/2addr", k12x, kIndexNone, kContinue, kSubtract, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xCD, MUL_DOUBLE_2ADDR, "mul-double/2addr", k12x, kIndexNone, kContinue, kMultiply, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xCE, DIV_DOUBLE_2ADDR, "div-double/2addr", k12x, kIndexNone, kContinue, kDivide, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xCF, REM_DOUBLE_2ADDR, "rem-double/2addr", k12x, kIndexNone, kContinue, kRemainder, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xD0, ADD_INT_LIT16, "add-int/lit16", k22s, kIndexNone, kContinue, kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD1, RSUB_INT, "rsub-int", k22s, kIndexNone, kContinue, kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD2, MUL_INT_LIT16, "mul-int/lit16", k22s, kIndexNone, kContinue, kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD3, DIV_INT_LIT16, "div-int/lit16", k22s, kIndexNone, kContinue | kThrow, kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD4, REM_INT_LIT16, "rem-int/lit16", k22s, kIndexNone, kContinue | kThrow, kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD5, AND_INT_LIT16, "and-int/lit16", k22s, kIndexNone, kContinue, kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD6, OR_INT_LIT16, "or-int/lit16", k22s, kIndexNone, kContinue, kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD7, XOR_INT_LIT16, "xor-int/lit16", k22s, kIndexNone, kContinue, kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD8, ADD_INT_LIT8, "add-int/lit8", k22b, kIndexNone, kContinue, kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD9, RSUB_INT_LIT8, "rsub-int/lit8", k22b, kIndexNone, kContinue, kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xDA, MUL_INT_LIT8, "mul-int/lit8", k22b, kIndexNone, kContinue, kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xDB, DIV_INT_LIT8, "div-int/lit8", k22b, kIndexNone, kContinue | kThrow, kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xDC, REM_INT_LIT8, "rem-int/lit8", k22b, kIndexNone, kContinue | kThrow, kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xDD, AND_INT_LIT8, "and-int/lit8", k22b, kIndexNone, kContinue, kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xDE, OR_INT_LIT8, "or-int/lit8", k22b, kIndexNone, kContinue, kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xDF, XOR_INT_LIT8, "xor-int/lit8", k22b, kIndexNone, kContinue, kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, kIndexNone, kContinue, kShl | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, kIndexNone, kContinue, kShr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, kIndexNone, kContinue, kUshr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xE3, IGET_QUICK, "iget-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xE6, IPUT_QUICK, "iput-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xE9, INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", k35c, kIndexVtableOffset, kContinue | kThrow | kInvoke, 0, kVerifyVarArgNonZero | kVerifyRuntimeOnly) \ + V(0xEA, INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", k3rc, kIndexVtableOffset, kContinue | kThrow | kInvoke, 0, kVerifyVarArgRangeNonZero | kVerifyRuntimeOnly) \ + V(0xEB, IPUT_BOOLEAN_QUICK, "iput-boolean-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xEC, IPUT_BYTE_QUICK, "iput-byte-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xED, IPUT_CHAR_QUICK, "iput-char-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xEE, IPUT_SHORT_QUICK, "iput-short-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xEF, IGET_BOOLEAN_QUICK, "iget-boolean-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xF0, IGET_BYTE_QUICK, "iget-byte-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xF1, IGET_CHAR_QUICK, "iget-char-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xF2, IGET_SHORT_QUICK, "iget-short-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ + V(0xF3, UNUSED_F3, "unused-f3", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0xF4, UNUSED_F4, "unused-f4", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0xF5, UNUSED_F5, "unused-f5", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0xF6, UNUSED_F6, "unused-f6", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0xF7, UNUSED_F7, "unused-f7", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0xF8, UNUSED_F8, "unused-f8", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0xF9, UNUSED_F9, "unused-f9", k10x, kIndexUnknown, 0, 0, kVerifyError) \ + V(0xFA, INVOKE_POLYMORPHIC, "invoke-polymorphic", k45cc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgNonZero | kVerifyRegHPrototype) \ + V(0xFB, INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range", k4rcc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgRangeNonZero | kVerifyRegHPrototype) \ + V(0xFC, INVOKE_CUSTOM, "invoke-custom", k35c, kIndexCallSiteRef, kContinue | kThrow, 0, kVerifyRegBCallSite | kVerifyVarArg) \ + V(0xFD, INVOKE_CUSTOM_RANGE, "invoke-custom/range", k3rc, kIndexCallSiteRef, kContinue | kThrow, 0, kVerifyRegBCallSite | kVerifyVarArgRange) \ + V(0xFE, CONST_METHOD_HANDLE, "const-method-handle", k21c, kIndexMethodHandleRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBMethodHandle) \ + V(0xFF, CONST_METHOD_TYPE, "const-method-type", k21c, kIndexProtoRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBPrototype) + +#define DEX_INSTRUCTION_FORMAT_LIST(V) \ + V(10x) /* op */ \ + V(12x) /* op vA, vB */ \ + V(11n) /* op vA, #+B */ \ + V(11x) /* op vAA */ \ + V(10t) /* op +AA */ \ + V(20t) /* op +AAAA */ \ + V(20bc) /* [opt] op AA, thing@BBBB */ \ + V(22x) /* op vAA, vBBBB */ \ + V(21t) /* op vAA, +BBBB */ \ + V(21s) /* op vAA, #+BBBB */ \ + V(21h) /* op vAA, #+BBBB00000[00000000] */ \ + V(21c) /* op vAA, thing@BBBB */ \ + V(23x) /* op vAA, vBB, vCC */ \ + V(22b) /* op vAA, vBB, #+CC */ \ + V(22t) /* op vA, vB, +CCCC */ \ + V(22s) /* op vA, vB, #+CCCC */ \ + V(22c) /* op vA, vB, thing@CCCC */ \ + V(22cs) /* [opt] op vA, vB, field offset CCCC */ \ + V(30t) /* op +AAAAAAAA */ \ + V(32x) /* op vAAAA, vBBBB */ \ + V(31i) /* op vAA, #+BBBBBBBB */ \ + V(31t) /* op vAA, +BBBBBBBB */ \ + V(31c) /* op vAA, string@BBBBBBBB */ \ + V(35c) /* op {vC,vD,vE,vF,vG}, thing@BBBB */ \ + V(35ms) /* [opt] invoke-virtual+super */ \ + V(3rc) /* op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB */ \ + V(3rms) /* [opt] invoke-virtual+super/range */ \ + V(35mi) /* [opt] inline invoke */ \ + V(3rmi) /* [opt] inline invoke/range */ \ + V(45cc) /* op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH */ \ + V(4rcc) /* op {VCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH */ \ + V(51l) /* op vAA, #+BBBBBBBBBBBBBBBB */ + +#endif // ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_LIST_H_ +#undef ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_LIST_H_ // the guard in this file is just for cpplint diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/dex_ir.h b/dexmaker-mockito-inline/external/slicer/export/slicer/dex_ir.h index 1d5dc3c6..5fe1b812 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/dex_ir.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/dex_ir.h @@ -16,14 +16,14 @@ #pragma once -#include "common.h" -#include "memview.h" #include "arrayview.h" +#include "buffer.h" +#include "common.h" #include "dex_format.h" #include "dex_leb128.h" -#include "buffer.h" -#include "index_map.h" #include "hash_table.h" +#include "index_map.h" +#include "memview.h" #include #include @@ -62,6 +62,7 @@ struct String; struct Type; struct TypeList; struct Proto; +struct MethodHandle; struct FieldDecl; struct EncodedField; struct DebugInfo; @@ -197,6 +198,16 @@ struct Proto : public IndexedNode { std::string Signature() const; }; +struct MethodHandle : public IndexedNode { + SLICER_IR_INDEXED_TYPE; + + dex::u2 method_handle_type; + MethodDecl* method; + FieldDecl* field; + + bool IsField(); +}; + struct FieldDecl : public IndexedNode { SLICER_IR_INDEXED_TYPE; @@ -365,6 +376,7 @@ struct DexFile { std::vector> fields; std::vector> methods; std::vector> classes; + std::vector> method_handles; // data segment structures std::vector> encoded_fields; @@ -394,6 +406,7 @@ struct DexFile { std::map fields_map; std::map methods_map; std::map classes_map; + std::map method_handles_map; // original .dex header "magic" signature slicer::MemView magic; @@ -406,6 +419,7 @@ struct DexFile { IndexMap fields_indexes; IndexMap methods_indexes; IndexMap classes_indexes; + IndexMap method_handle_indexes; // lookup hash tables StringsLookup strings_lookup; @@ -447,6 +461,7 @@ struct DexFile { void Track(FieldDecl* p) { PushOwn(fields, p); } void Track(MethodDecl* p) { PushOwn(methods, p); } void Track(Class* p) { PushOwn(classes, p); } + void Track(MethodHandle* p) { PushOwn(method_handles, p); } void Track(EncodedField* p) { PushOwn(encoded_fields, p); } void Track(EncodedMethod* p) { PushOwn(encoded_methods, p); } diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/hash_table.h b/dexmaker-mockito-inline/external/slicer/export/slicer/hash_table.h index 7eca41a2..3b3da676 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/hash_table.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/hash_table.h @@ -16,9 +16,9 @@ #pragma once -#include #include #include +#include namespace slicer { @@ -124,7 +124,7 @@ HashTable::Partition::Partition(Index size, const Hash& hasher) // template bool HashTable::Partition::Insert(T* value) { - SLICER_CHECK(value != nullptr); + SLICER_CHECK_NE(value, nullptr); // overflow? if (buckets_.size() + 1 > buckets_.capacity()) { return false; @@ -211,7 +211,7 @@ void HashTable::Partition::PrintStats(const char* name, bool verbo ++used_buckets; int chain_length = 0; for (Index ci = i; buckets_[ci].next != kInvalidIndex; ci = buckets_[ci].next) { - SLICER_CHECK(buckets_[ci].value != nullptr); + SLICER_CHECK_NE(buckets_[ci].value, nullptr); ++chain_length; if (verbose) printf("*"); } diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/instrumentation.h b/dexmaker-mockito-inline/external/slicer/export/slicer/instrumentation.h index f5210fdc..776efa33 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/instrumentation.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/instrumentation.h @@ -22,9 +22,9 @@ #include "dex_ir_builder.h" #include -#include -#include #include +#include +#include namespace slicer { @@ -40,23 +40,42 @@ class Transformation { // an explicit "this" argument for non-static methods. class EntryHook : public Transformation { public: - explicit EntryHook( - const ir::MethodId& hook_method_id, - bool use_object_type_for_this_argument = false) - : hook_method_id_(hook_method_id), - use_object_type_for_this_argument_(use_object_type_for_this_argument) { + enum class Tweak { + None, + // Expose the "this" argument of non-static methods as the "Object" type. + // This can be helpful when the code you want to handle the hook doesn't + // have access to the actual type in its classpath. + ThisAsObject, + // Forward incoming arguments as an array. Zero-th element of the array is + // the method signature. First element of the array is + // "this" object if instrumented method isn't static. + // It is helpul, when you inject the same hook into the different + // methods. + ArrayParams, + }; + + explicit EntryHook(const ir::MethodId& hook_method_id, Tweak tweak) + : hook_method_id_(hook_method_id), tweak_(tweak) { // hook method signature is generated automatically - SLICER_CHECK(hook_method_id_.signature == nullptr); + SLICER_CHECK_EQ(hook_method_id_.signature, nullptr); } + // TODO: Delete this legacy constrcutor. + // It is left in temporarily so we can move callers away from it to the new + // `tweak` constructor. + explicit EntryHook(const ir::MethodId& hook_method_id, + bool use_object_type_for_this_argument = false) + : EntryHook(hook_method_id, use_object_type_for_this_argument + ? Tweak::ThisAsObject + : Tweak::None) {} + virtual bool Apply(lir::CodeIr* code_ir) override; private: ir::MethodId hook_method_id_; - // If true, "this" argument of non-static methods is forwarded as Object type. - // For example "this" argument of OkHttpClient type is forwared as Object and - // is used to get OkHttp class loader. - bool use_object_type_for_this_argument_; + Tweak tweak_; + + bool InjectArrayParamsHook(lir::CodeIr* code_ir, lir::Bytecode* bytecode); }; // Insert a call to the "exit hook" method before every return @@ -64,35 +83,86 @@ class EntryHook : public Transformation { // original return value and it may return a new return value. class ExitHook : public Transformation { public: - explicit ExitHook(const ir::MethodId& hook_method_id) : hook_method_id_(hook_method_id) { + enum class Tweak { + None = 0, + // return value will be passed as "Object" type. + // This can be helpful when the code you want to handle the hook doesn't + // have access to the actual type in its classpath or when you want to inject + // the same hook in multiple methods. + ReturnAsObject = 1 << 0, + // Pass method signature as the first parameter of the hook method. + PassMethodSignature = 1 << 1, + }; + + explicit ExitHook(const ir::MethodId& hook_method_id, Tweak tweak) + : hook_method_id_(hook_method_id), tweak_(tweak) { // hook method signature is generated automatically - SLICER_CHECK(hook_method_id_.signature == nullptr); + SLICER_CHECK_EQ(hook_method_id_.signature, nullptr); } + explicit ExitHook(const ir::MethodId& hook_method_id) : ExitHook(hook_method_id, Tweak::None) {} + virtual bool Apply(lir::CodeIr* code_ir) override; private: ir::MethodId hook_method_id_; + Tweak tweak_; }; -// Replace every invoke-virtual[/range] to the a specified method with -// a invoke-static[/range] to the detour method. The detour is a static -// method which takes the same arguments as the original method plus -// an explicit "this" argument, and returns the same type as the original method -class DetourVirtualInvoke : public Transformation { +inline ExitHook::Tweak operator|(ExitHook::Tweak a, ExitHook::Tweak b) { + return static_cast(static_cast(a) | static_cast(b)); +} + +inline int operator&(ExitHook::Tweak a, ExitHook::Tweak b) { + return static_cast(a) & static_cast(b); +} + +// Base class for detour hooks. Replace every occurrence of specific opcode with +// something else. The detour is a static method which takes the same arguments +// as the original method plus an explicit "this" argument and returns the same +// type as the original method. Derived classes must implement GetNewOpcode. +class DetourHook : public Transformation { public: - DetourVirtualInvoke(const ir::MethodId& orig_method_id, const ir::MethodId& detour_method_id) - : orig_method_id_(orig_method_id), detour_method_id_(detour_method_id) { + DetourHook(const ir::MethodId& orig_method_id, + const ir::MethodId& detour_method_id) + : orig_method_id_(orig_method_id), detour_method_id_(detour_method_id) { // detour method signature is automatically created // to match the original method and must not be explicitly specified - SLICER_CHECK(detour_method_id_.signature == nullptr); + SLICER_CHECK_EQ(detour_method_id_.signature, nullptr); } virtual bool Apply(lir::CodeIr* code_ir) override; - private: + protected: ir::MethodId orig_method_id_; ir::MethodId detour_method_id_; + + // Returns a new opcode to replace the desired opcode or OP_NOP otherwise. + virtual dex::Opcode GetNewOpcode(dex::Opcode opcode) = 0; +}; + +// Replace every invoke-virtual[/range] to the a specified method with +// a invoke-static[/range] to the detour method. +class DetourVirtualInvoke : public DetourHook { + public: + DetourVirtualInvoke(const ir::MethodId& orig_method_id, + const ir::MethodId& detour_method_id) + : DetourHook(orig_method_id, detour_method_id) {} + + protected: + virtual dex::Opcode GetNewOpcode(dex::Opcode opcode) override; +}; + +// Replace every invoke-interface[/range] to the a specified method with +// a invoke-static[/range] to the detour method. +class DetourInterfaceInvoke : public DetourHook { + public: + DetourInterfaceInvoke(const ir::MethodId& orig_method_id, + const ir::MethodId& detour_method_id) + : DetourHook(orig_method_id, detour_method_id) {} + + protected: + virtual dex::Opcode GetNewOpcode(dex::Opcode opcode) override; }; // Allocates scratch registers without doing a full register allocation @@ -100,13 +170,13 @@ class AllocateScratchRegs : public Transformation { public: explicit AllocateScratchRegs(int allocate_count, bool allow_renumbering = true) : allocate_count_(allocate_count), allow_renumbering_(allow_renumbering) { - SLICER_CHECK(allocate_count > 0); + SLICER_CHECK_GT(allocate_count, 0); } virtual bool Apply(lir::CodeIr* code_ir) override; const std::set& ScratchRegs() const { - SLICER_CHECK(scratch_regs_.size() == static_cast(allocate_count_)); + SLICER_CHECK_EQ(scratch_regs_.size(), static_cast(allocate_count_)); return scratch_regs_; } diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/intrusive_list.h b/dexmaker-mockito-inline/external/slicer/export/slicer/intrusive_list.h index 67408aec..acdf8766 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/intrusive_list.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/intrusive_list.h @@ -114,7 +114,7 @@ class IntrusiveList { } void Remove(T* pos) { - SLICER_CHECK(pos != end_); + SLICER_CHECK_NE(pos, end_); if (pos->prev != nullptr) { assert(pos != begin_); pos->prev->next = pos->next; diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/reader.h b/dexmaker-mockito-inline/external/slicer/export/slicer/reader.h index 4e08f524..ee4d99cc 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/reader.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/reader.h @@ -53,6 +53,7 @@ class Reader { slicer::ArrayView FieldIds() const; slicer::ArrayView MethodIds() const; slicer::ArrayView ProtoIds() const; + slicer::ArrayView MethodHandles() const; const dex::MapList* DexMapList() const; // IR creation interface @@ -69,6 +70,7 @@ class Reader { ir::MethodDecl* GetMethodDecl(dex::u4 index); ir::Proto* GetProto(dex::u4 index); ir::String* GetString(dex::u4 index); + ir::MethodHandle* GetMethodHandle(dex::u4 index); // Parsing annotations ir::AnnotationsDirectory* ExtractAnnotations(dex::u4 offset); @@ -80,6 +82,7 @@ class Reader { ir::ParamAnnotation* ParseParamAnnotation(const dex::u1** pptr); ir::EncodedField* ParseEncodedField(const dex::u1** pptr, dex::u4* baseIndex); ir::Annotation* ParseAnnotation(const dex::u1** pptr); + ir::MethodHandle* ParseMethodHandle(dex::u4 index); // Parse encoded values and arrays ir::EncodedValue* ParseEncodedValue(const dex::u1** pptr); @@ -104,7 +107,7 @@ class Reader { // Convert a file pointer (absolute offset) to an in-memory pointer template const T* ptr(int offset) const { - SLICER_CHECK(offset >= 0 && offset + sizeof(T) <= size_); + SLICER_CHECK_GE(offset, 0 && offset + sizeof(T) <= size_); return reinterpret_cast(image_ + offset); } @@ -112,7 +115,7 @@ class Reader { // (offset should be inside the data section) template const T* dataPtr(int offset) const { - SLICER_CHECK(offset >= header_->data_off && offset + sizeof(T) <= size_); + SLICER_CHECK_GE(offset, header_->data_off && offset + sizeof(T) <= size_); return reinterpret_cast(image_ + offset); } diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/scopeguard.h b/dexmaker-mockito-inline/external/slicer/export/slicer/scopeguard.h index 28e3bc99..f98e2146 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/scopeguard.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/scopeguard.h @@ -16,6 +16,8 @@ #pragma once +#include + namespace slicer { // A simple and lightweight scope guard and macro diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/tryblocks_encoder.h b/dexmaker-mockito-inline/external/slicer/export/slicer/tryblocks_encoder.h index 32e0143a..05a39762 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/tryblocks_encoder.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/tryblocks_encoder.h @@ -16,11 +16,11 @@ #pragma once -#include "common.h" -#include "code_ir.h" -#include "dex_ir.h" #include "buffer.h" #include "chronometer.h" +#include "code_ir.h" +#include "common.h" +#include "dex_ir.h" namespace lir { diff --git a/dexmaker-mockito-inline/external/slicer/export/slicer/writer.h b/dexmaker-mockito-inline/external/slicer/export/slicer/writer.h index 00a04ce5..e0d4e27f 100644 --- a/dexmaker-mockito-inline/external/slicer/export/slicer/writer.h +++ b/dexmaker-mockito-inline/external/slicer/export/slicer/writer.h @@ -16,9 +16,9 @@ #pragma once -#include "common.h" -#include "buffer.h" #include "arrayview.h" +#include "buffer.h" +#include "common.h" #include "dex_format.h" #include "dex_ir.h" @@ -32,25 +32,25 @@ namespace dex { // (tracking the section offset, section type, ...) class Section : public slicer::Buffer { public: - Section(dex::u2 mapEntryType) : map_entry_type_(mapEntryType) {} + explicit Section(dex::u2 mapEntryType) : map_entry_type_(mapEntryType) {} ~Section() = default; Section(const Section&) = delete; Section& operator=(const Section&) = delete; void SetOffset(dex::u4 offset) { - SLICER_CHECK(offset > 0 && offset % 4 == 0); + SLICER_CHECK_EQ(offset > 0 && offset % 4, 0); offset_ = offset; } dex::u4 SectionOffset() const { - SLICER_CHECK(offset_ > 0 && offset_ % 4 == 0); + SLICER_CHECK_EQ(offset_ > 0 && offset_ % 4, 0); return ItemsCount() > 0 ? offset_ : 0; } dex::u4 AbsoluteOffset(dex::u4 itemOffset) const { - SLICER_CHECK(offset_ > 0); - SLICER_CHECK(itemOffset < size()); + SLICER_CHECK_GT(offset_, 0); + SLICER_CHECK_LT(itemOffset, size()); return offset_ + itemOffset; } @@ -76,7 +76,7 @@ class Section : public slicer::Buffer { template class Index { public: - Index(dex::u2 mapEntryType) : map_entry_type_(mapEntryType) {} + explicit Index(dex::u2 mapEntryType) : map_entry_type_(mapEntryType) {} ~Index() = default; Index(const Index&) = delete; @@ -96,7 +96,7 @@ class Index { } dex::u4 SectionOffset() const { - SLICER_CHECK(offset_ > 0 && offset_ % 4 == 0); + SLICER_CHECK_EQ(offset_ > 0 && offset_ % 4, 0); return ItemsCount() > 0 ? offset_ : 0; } @@ -110,7 +110,7 @@ class Index { dex::u4 size() const { return count_ * sizeof(T); } T& operator[](int i) { - SLICER_CHECK(i >= 0 && i < count_); + SLICER_CHECK_GE(i, 0 && i < count_); return values_[i]; } @@ -135,6 +135,7 @@ class Writer { field_ids(dex::kFieldIdItem), method_ids(dex::kMethodIdItem), class_defs(dex::kClassDefItem), + method_handles(dex::kMethodHandleItem), string_data(dex::kStringDataItem), type_lists(dex::kTypeList), debug_info(dex::kDebugInfoItem), @@ -153,6 +154,7 @@ class Writer { Index field_ids; Index method_ids; Index class_defs; + Index method_handles; Section string_data; Section type_lists; @@ -176,7 +178,7 @@ class Writer { }; public: - Writer(std::shared_ptr dex_ir) : dex_ir_(dex_ir) {} + explicit Writer(std::shared_ptr dex_ir) : dex_ir_(dex_ir) {} ~Writer() = default; Writer(const Writer&) = delete; @@ -205,6 +207,7 @@ class Writer { void FillFields(); void FillMethods(); void FillClassDefs(); + void FillMethodHandles(); // helpers for writing .dex structures dex::u4 WriteTypeList(const std::vector& types); @@ -223,6 +226,8 @@ class Writer { dex::u4 MapTypeIndex(dex::u4 index) const; dex::u4 MapFieldIndex(dex::u4 index) const; dex::u4 MapMethodIndex(dex::u4 index) const; + dex::u4 MapProtoIndex(dex::u4 index) const; + dex::u4 MapMethodHandleIndex(dex::u4 index) const; // writing parts of a class definition void WriteInstructions(slicer::ArrayView instructions); diff --git a/dexmaker-mockito-inline/external/slicer/instrumentation.cc b/dexmaker-mockito-inline/external/slicer/instrumentation.cc index 55e2ae88..b05abc3d 100644 --- a/dexmaker-mockito-inline/external/slicer/instrumentation.cc +++ b/dexmaker-mockito-inline/external/slicer/instrumentation.cc @@ -15,11 +15,111 @@ */ #include "slicer/instrumentation.h" + #include "slicer/dex_ir_builder.h" +#include +#include + namespace slicer { +namespace { + +struct BytecodeConvertingVisitor : public lir::Visitor { + lir::Bytecode* out = nullptr; + bool Visit(lir::Bytecode* bytecode) { + out = bytecode; + return true; + } +}; + +void BoxValue(lir::Bytecode* bytecode, + lir::CodeIr* code_ir, + ir::Type* type, + dex::u4 src_reg, + dex::u4 dst_reg) { + bool is_wide = false; + const char* boxed_type_name = nullptr; + switch (*(type->descriptor)->c_str()) { + case 'Z': + boxed_type_name = "Ljava/lang/Boolean;"; + break; + case 'B': + boxed_type_name = "Ljava/lang/Byte;"; + break; + case 'C': + boxed_type_name = "Ljava/lang/Character;"; + break; + case 'S': + boxed_type_name = "Ljava/lang/Short;"; + break; + case 'I': + boxed_type_name = "Ljava/lang/Integer;"; + break; + case 'J': + is_wide = true; + boxed_type_name = "Ljava/lang/Long;"; + break; + case 'F': + boxed_type_name = "Ljava/lang/Float;"; + break; + case 'D': + is_wide = true; + boxed_type_name = "Ljava/lang/Double;"; + break; + } + SLICER_CHECK_NE(boxed_type_name, nullptr); + + ir::Builder builder(code_ir->dex_ir); + std::vector param_types; + param_types.push_back(type); + + auto boxed_type = builder.GetType(boxed_type_name); + auto ir_proto = builder.GetProto(boxed_type, builder.GetTypeList(param_types)); + + auto ir_method_decl = builder.GetMethodDecl( + builder.GetAsciiString("valueOf"), ir_proto, boxed_type); + + auto boxing_method = code_ir->Alloc(ir_method_decl, ir_method_decl->orig_index); + + auto args = code_ir->Alloc(src_reg, 1 + is_wide); + auto boxing_invoke = code_ir->Alloc(); + boxing_invoke->opcode = dex::OP_INVOKE_STATIC_RANGE; + boxing_invoke->operands.push_back(args); + boxing_invoke->operands.push_back(boxing_method); + code_ir->instructions.InsertBefore(bytecode, boxing_invoke); + + auto move_result = code_ir->Alloc(); + move_result->opcode = dex::OP_MOVE_RESULT_OBJECT; + move_result->operands.push_back(code_ir->Alloc(dst_reg)); + code_ir->instructions.InsertBefore(bytecode, move_result); +} + +std::string MethodLabel(ir::EncodedMethod* ir_method) { + auto signature_str = ir_method->decl->prototype->Signature(); + return ir_method->decl->parent->Decl() + "->" + ir_method->decl->name->c_str() + signature_str; +} + +} // namespace + bool EntryHook::Apply(lir::CodeIr* code_ir) { + lir::Bytecode* bytecode = nullptr; + // find the first bytecode in the method body to insert the hook before it + for (auto instr : code_ir->instructions) { + BytecodeConvertingVisitor visitor; + instr->Accept(&visitor); + bytecode = visitor.out; + if (bytecode != nullptr) { + break; + } + } + if (bytecode == nullptr) { + return false; + } + if (tweak_ == Tweak::ArrayParams) { + return InjectArrayParamsHook(code_ir, bytecode); + } + ir::Builder builder(code_ir->dex_ir); const auto ir_method = code_ir->ir_method; @@ -27,10 +127,13 @@ bool EntryHook::Apply(lir::CodeIr* code_ir) { std::vector param_types; if ((ir_method->access_flags & dex::kAccStatic) == 0) { ir::Type* this_argument_type; - if (use_object_type_for_this_argument_) { - this_argument_type = builder.GetType("Ljava/lang/Object;"); - } else { - this_argument_type = ir_method->decl->parent; + switch (tweak_) { + case Tweak::ThisAsObject: + this_argument_type = builder.GetType("Ljava/lang/Object;"); + break; + default: + this_argument_type = ir_method->decl->parent; + break; } param_types.push_back(this_argument_type); } @@ -60,28 +163,221 @@ bool EntryHook::Apply(lir::CodeIr* code_ir) { hook_invoke->operands.push_back(hook_method); // insert the hook before the first bytecode in the method body - for (auto instr : code_ir->instructions) { - auto bytecode = dynamic_cast(instr); - if (bytecode == nullptr) { - continue; + code_ir->instructions.InsertBefore(bytecode, hook_invoke); + return true; +} + +void GenerateShiftParamsCode(lir::CodeIr* code_ir, lir::Instruction* position, dex::u4 shift) { + const auto ir_method = code_ir->ir_method; + + // Since the goal is to relocate the registers when extra scratch registers are needed, + // if there are no parameters this is a no-op. + if (ir_method->code->ins_count == 0) { + return; + } + + // build a param list with the explicit "this" argument for non-static methods + std::vector param_types; + if ((ir_method->access_flags & dex::kAccStatic) == 0) { + param_types.push_back(ir_method->decl->parent); + } + if (ir_method->decl->prototype->param_types != nullptr) { + const auto& orig_param_types = ir_method->decl->prototype->param_types->types; + param_types.insert(param_types.end(), orig_param_types.begin(), orig_param_types.end()); + } + + const dex::u4 regs = ir_method->code->registers; + const dex::u4 ins_count = ir_method->code->ins_count; + SLICER_CHECK_GE(regs, ins_count); + + // generate the args "relocation" instructions + dex::u4 reg = regs - ins_count; + for (const auto& type : param_types) { + auto move = code_ir->Alloc(); + switch (type->GetCategory()) { + case ir::Type::Category::Reference: + move->opcode = dex::OP_MOVE_OBJECT_16; + move->operands.push_back(code_ir->Alloc(reg - shift)); + move->operands.push_back(code_ir->Alloc(reg)); + reg += 1; + break; + case ir::Type::Category::Scalar: + move->opcode = dex::OP_MOVE_16; + move->operands.push_back(code_ir->Alloc(reg - shift)); + move->operands.push_back(code_ir->Alloc(reg)); + reg += 1; + break; + case ir::Type::Category::WideScalar: + move->opcode = dex::OP_MOVE_WIDE_16; + move->operands.push_back(code_ir->Alloc(reg - shift)); + move->operands.push_back(code_ir->Alloc(reg)); + reg += 2; + break; + case ir::Type::Category::Void: + SLICER_FATAL("void parameter type"); } - code_ir->instructions.InsertBefore(bytecode, hook_invoke); - break; + code_ir->instructions.InsertBefore(position, move); + } +} + +bool EntryHook::InjectArrayParamsHook(lir::CodeIr* code_ir, lir::Bytecode* bytecode) { + ir::Builder builder(code_ir->dex_ir); + const auto ir_method = code_ir->ir_method; + auto param_types_list = ir_method->decl->prototype->param_types; + auto param_types = param_types_list != nullptr ? param_types_list->types : std::vector(); + bool is_static = (ir_method->access_flags & dex::kAccStatic) != 0; + + // number of registers that we need to operate + dex::u2 regs_count = 3; + auto non_param_regs = ir_method->code->registers - ir_method->code->ins_count; + + // do we have enough registers to operate? + bool needsExtraRegs = non_param_regs < regs_count; + if (needsExtraRegs) { + // we don't have enough registers, so we allocate more, we will shift + // params to their original registers later. + code_ir->ir_method->code->registers += regs_count - non_param_regs; } + // use three first registers: + // all three are needed when we "aput" a string/boxed-value (1) into an array (2) at an index (3) + + // register that will store size of during allocation + // later will be reused to store index when do "aput" + dex::u4 array_size_reg = 0; + // register that will store an array that will be passed + // as a parameter in entry hook + dex::u4 array_reg = 1; + // stores result of boxing (if it's needed); also stores the method signature string + dex::u4 value_reg = 2; + // array size bytecode + auto const_size_op = code_ir->Alloc(); + const_size_op->opcode = dex::OP_CONST; + const_size_op->operands.push_back(code_ir->Alloc(array_size_reg)); + const_size_op->operands.push_back(code_ir->Alloc( + 2 + param_types.size())); // method signature + params + "this" object + code_ir->instructions.InsertBefore(bytecode, const_size_op); + + // allocate array + const auto obj_array_type = builder.GetType("[Ljava/lang/Object;"); + auto allocate_array_op = code_ir->Alloc(); + allocate_array_op->opcode = dex::OP_NEW_ARRAY; + allocate_array_op->operands.push_back(code_ir->Alloc(array_reg)); + allocate_array_op->operands.push_back(code_ir->Alloc(array_size_reg)); + allocate_array_op->operands.push_back( + code_ir->Alloc(obj_array_type, obj_array_type->orig_index)); + code_ir->instructions.InsertBefore(bytecode, allocate_array_op); + + // fill the array with parameters passed into function + + std::vector types; + types.push_back(builder.GetType("Ljava/lang/String;")); // method signature string + if (!is_static) { + types.push_back(ir_method->decl->parent); // "this" object + } + + types.insert(types.end(), param_types.begin(), param_types.end()); // parameters + + // register where params start + dex::u4 current_reg = ir_method->code->registers - ir_method->code->ins_count; + // reuse not needed anymore register to store indexes + dex::u4 array_index_reg = array_size_reg; + int i = 0; + for (auto type: types) { + dex::u4 src_reg = 0; + if (i == 0) { // method signature string + // e.g. const-string v2, "(I[Ljava/lang/String;)Ljava/lang/String;" + // for (int, String[]) -> String + auto const_str_op = code_ir->Alloc(); + const_str_op->opcode = dex::OP_CONST_STRING; + const_str_op->operands.push_back(code_ir->Alloc(value_reg)); // dst + auto method_label = builder.GetAsciiString(MethodLabel(ir_method).c_str()); + const_str_op->operands.push_back( + code_ir->Alloc(method_label, method_label->orig_index)); // src + code_ir->instructions.InsertBefore(bytecode, const_str_op); + src_reg = value_reg; + } else if (type->GetCategory() != ir::Type::Category::Reference) { + BoxValue(bytecode, code_ir, type, current_reg, value_reg); + src_reg = value_reg; + current_reg += 1 + (type->GetCategory() == ir::Type::Category::WideScalar); + } else { + src_reg = current_reg; + current_reg++; + } + + auto index_const_op = code_ir->Alloc(); + index_const_op->opcode = dex::OP_CONST; + index_const_op->operands.push_back(code_ir->Alloc(array_index_reg)); + index_const_op->operands.push_back(code_ir->Alloc(i++)); + code_ir->instructions.InsertBefore(bytecode, index_const_op); + + auto aput_op = code_ir->Alloc(); + aput_op->opcode = dex::OP_APUT_OBJECT; + aput_op->operands.push_back(code_ir->Alloc(src_reg)); + aput_op->operands.push_back(code_ir->Alloc(array_reg)); + aput_op->operands.push_back(code_ir->Alloc(array_index_reg)); + code_ir->instructions.InsertBefore(bytecode, aput_op); + + // if function is static, then jumping over index 1 + // since null should be be passed in this case + if (i == 1 && is_static) i++; + } + + std::vector hook_param_types; + hook_param_types.push_back(obj_array_type); + + auto ir_proto = builder.GetProto(builder.GetType("V"), + builder.GetTypeList(hook_param_types)); + + auto ir_method_decl = builder.GetMethodDecl( + builder.GetAsciiString(hook_method_id_.method_name), ir_proto, + builder.GetType(hook_method_id_.class_descriptor)); + + auto hook_method = code_ir->Alloc(ir_method_decl, ir_method_decl->orig_index); + auto args = code_ir->Alloc(array_reg, 1); + auto hook_invoke = code_ir->Alloc(); + hook_invoke->opcode = dex::OP_INVOKE_STATIC_RANGE; + hook_invoke->operands.push_back(args); + hook_invoke->operands.push_back(hook_method); + code_ir->instructions.InsertBefore(bytecode, hook_invoke); + + // clean up registries used by us + // registers are assigned to a marker value 0xFE_FE_FE_FE (decimal + // value: -16843010) to help identify use of uninitialized registers. + for (dex::u2 i = 0; i < regs_count; ++i) { + auto cleanup = code_ir->Alloc(); + cleanup->opcode = dex::OP_CONST; + cleanup->operands.push_back(code_ir->Alloc(i)); + cleanup->operands.push_back(code_ir->Alloc(0xFEFEFEFE)); + code_ir->instructions.InsertBefore(bytecode, cleanup); + } + + // now we have to shift params to their original registers + if (needsExtraRegs) { + GenerateShiftParamsCode(code_ir, bytecode, regs_count - non_param_regs); + } return true; } bool ExitHook::Apply(lir::CodeIr* code_ir) { ir::Builder builder(code_ir->dex_ir); const auto ir_method = code_ir->ir_method; - const auto return_type = ir_method->decl->prototype->return_type; - + const auto declared_return_type = ir_method->decl->prototype->return_type; + bool return_as_object = (tweak_ & Tweak::ReturnAsObject) != 0; // do we have a void-return method? - bool return_void = (::strcmp(return_type->descriptor->c_str(), "V") == 0); - + bool return_void = (::strcmp(declared_return_type->descriptor->c_str(), "V") == 0); + // returnAsObject supports only object return type; + SLICER_CHECK(!return_as_object || + (declared_return_type->GetCategory() == ir::Type::Category::Reference)); + const auto return_type = return_as_object ? builder.GetType("Ljava/lang/Object;") + : declared_return_type; + + bool pass_method_signature = (tweak_ & Tweak::PassMethodSignature) != 0; // construct the hook method declaration std::vector param_types; + if (pass_method_signature) { + param_types.push_back(builder.GetType("Ljava/lang/String;")); + } if (!return_void) { param_types.push_back(return_type); } @@ -96,7 +392,9 @@ bool ExitHook::Apply(lir::CodeIr* code_ir) { // find and instrument all return instructions for (auto instr : code_ir->instructions) { - auto bytecode = dynamic_cast(instr); + BytecodeConvertingVisitor visitor; + instr->Accept(&visitor); + auto bytecode = visitor.out; if (bytecode == nullptr) { continue; } @@ -104,7 +402,6 @@ bool ExitHook::Apply(lir::CodeIr* code_ir) { dex::Opcode move_result_opcode = dex::OP_NOP; dex::u4 reg = 0; int reg_count = 0; - switch (bytecode->opcode) { case dex::OP_RETURN_VOID: SLICER_CHECK(return_void); @@ -132,8 +429,65 @@ bool ExitHook::Apply(lir::CodeIr* code_ir) { continue; } - // invoke hook bytecode - auto args = code_ir->Alloc(reg, reg_count); + dex::u4 scratch_reg = 0; + // load method signature into scratch_reg + if (pass_method_signature) { + // is there a register that can be overtaken + bool needsScratchReg = ir_method->code->registers < reg_count + 1; + if (needsScratchReg) { + // don't renumber registers underneath us + slicer::AllocateScratchRegs alloc_regs(1, false); + alloc_regs.Apply(code_ir); + } + + // we need use one register before results to put signature there + // however result starts in register 0, thefore it is shifted + // to register 1 + if (reg == 0 && bytecode->opcode != dex::OP_RETURN_VOID) { + auto move_op = code_ir->Alloc(); + switch (bytecode->opcode) { + case dex::OP_RETURN_OBJECT: + move_op->opcode = dex::OP_MOVE_OBJECT_16; + move_op->operands.push_back(code_ir->Alloc(reg + 1)); + move_op->operands.push_back(code_ir->Alloc(reg)); + break; + case dex::OP_RETURN: + move_op->opcode = dex::OP_MOVE_16; + move_op->operands.push_back(code_ir->Alloc(reg + 1)); + move_op->operands.push_back(code_ir->Alloc(reg)); + break; + case dex::OP_RETURN_WIDE: + move_op->opcode = dex::OP_MOVE_WIDE_16; + move_op->operands.push_back(code_ir->Alloc(reg + 1)); + move_op->operands.push_back(code_ir->Alloc(reg)); + break; + default: { + std::stringstream ss; + ss <<"Unexpected bytecode opcode: " << bytecode->opcode; + SLICER_FATAL(ss.str()); + } + } + code_ir->instructions.InsertBefore(bytecode, move_op); + // return is the last call, return is shifted to one, so taking over 0 registry + scratch_reg = 0; + } else { + // return is the last call, so we're taking over previous registry + scratch_reg = bytecode->opcode == dex::OP_RETURN_VOID ? 0 : reg - 1; + } + + + // return is the last call, so we're taking over previous registry + auto method_label = builder.GetAsciiString(MethodLabel(ir_method).c_str()); + auto const_str_op = code_ir->Alloc(); + const_str_op->opcode = dex::OP_CONST_STRING; + const_str_op->operands.push_back(code_ir->Alloc(scratch_reg)); // dst + const_str_op->operands.push_back(code_ir->Alloc(method_label, method_label->orig_index)); // src + code_ir->instructions.InsertBefore(bytecode, const_str_op); + } + + auto args = pass_method_signature + ? code_ir->Alloc(scratch_reg, reg_count + 1) + : code_ir->Alloc(reg, reg_count); auto hook_invoke = code_ir->Alloc(); hook_invoke->opcode = dex::OP_INVOKE_STATIC_RANGE; hook_invoke->operands.push_back(args); @@ -152,35 +506,37 @@ bool ExitHook::Apply(lir::CodeIr* code_ir) { move_result->opcode = move_result_opcode; move_result->operands.push_back(bytecode->operands[0]); code_ir->instructions.InsertBefore(bytecode, move_result); + + if ((tweak_ & Tweak::ReturnAsObject) != 0) { + auto check_cast = code_ir->Alloc(); + check_cast->opcode = dex::OP_CHECK_CAST; + check_cast->operands.push_back(code_ir->Alloc(reg)); + check_cast->operands.push_back( + code_ir->Alloc(declared_return_type, declared_return_type->orig_index)); + code_ir->instructions.InsertBefore(bytecode, check_cast); + } } } return true; } -bool DetourVirtualInvoke::Apply(lir::CodeIr* code_ir) { +bool DetourHook::Apply(lir::CodeIr* code_ir) { ir::Builder builder(code_ir->dex_ir); // search for matching invoke-virtual[/range] bytecodes for (auto instr : code_ir->instructions) { - auto bytecode = dynamic_cast(instr); + BytecodeConvertingVisitor visitor; + instr->Accept(&visitor); + auto bytecode = visitor.out; if (bytecode == nullptr) { continue; } - dex::Opcode new_call_opcode = dex::OP_NOP; - switch (bytecode->opcode) { - case dex::OP_INVOKE_VIRTUAL: - new_call_opcode = dex::OP_INVOKE_STATIC; - break; - case dex::OP_INVOKE_VIRTUAL_RANGE: - new_call_opcode = dex::OP_INVOKE_STATIC_RANGE; - break; - default: - // skip instruction ... - continue; + dex::Opcode new_call_opcode = GetNewOpcode(bytecode->opcode); + if (new_call_opcode == dex::OP_NOP) { + continue; } - assert(new_call_opcode != dex::OP_NOP); auto orig_method = bytecode->CastOperand(1)->ir_method; if (!orig_method_id_.Match(orig_method)) { @@ -194,7 +550,8 @@ bool DetourVirtualInvoke::Apply(lir::CodeIr* code_ir) { param_types.push_back(orig_method->parent); if (orig_method->prototype->param_types != nullptr) { const auto& orig_param_types = orig_method->prototype->param_types->types; - param_types.insert(param_types.end(), orig_param_types.begin(), orig_param_types.end()); + param_types.insert(param_types.end(), orig_param_types.begin(), + orig_param_types.end()); } auto ir_proto = builder.GetProto(orig_method->prototype->return_type, @@ -204,7 +561,8 @@ bool DetourVirtualInvoke::Apply(lir::CodeIr* code_ir) { builder.GetAsciiString(detour_method_id_.method_name), ir_proto, builder.GetType(detour_method_id_.class_descriptor)); - auto detour_method = code_ir->Alloc(ir_method_decl, ir_method_decl->orig_index); + auto detour_method = + code_ir->Alloc(ir_method_decl, ir_method_decl->orig_index); // We mutate the original invoke bytecode in-place: this is ok // because lir::Instructions can't be shared (referenced multiple times) @@ -217,12 +575,36 @@ bool DetourVirtualInvoke::Apply(lir::CodeIr* code_ir) { return true; } +dex::Opcode DetourVirtualInvoke::GetNewOpcode(dex::Opcode opcode) { + switch (opcode) { + case dex::OP_INVOKE_VIRTUAL: + return dex::OP_INVOKE_STATIC; + case dex::OP_INVOKE_VIRTUAL_RANGE: + return dex::OP_INVOKE_STATIC_RANGE; + default: + // skip instruction ... + return dex::OP_NOP; + } +} + +dex::Opcode DetourInterfaceInvoke::GetNewOpcode(dex::Opcode opcode) { + switch (opcode) { + case dex::OP_INVOKE_INTERFACE: + return dex::OP_INVOKE_STATIC; + case dex::OP_INVOKE_INTERFACE_RANGE: + return dex::OP_INVOKE_STATIC_RANGE; + default: + // skip instruction ... + return dex::OP_NOP; + } +} + // Register re-numbering visitor // (renumbers vN to vN+shift) class RegsRenumberVisitor : public lir::Visitor { public: - RegsRenumberVisitor(int shift) : shift_(shift) { - SLICER_CHECK(shift > 0); + explicit RegsRenumberVisitor(int shift) : shift_(shift) { + SLICER_CHECK_GT(shift, 0); } private: @@ -272,7 +654,7 @@ class RegsRenumberVisitor : public lir::Visitor { // make existing bytecodes "unencodable" (if they have 4 bit reg fields) // void AllocateScratchRegs::RegsRenumbering(lir::CodeIr* code_ir) { - SLICER_CHECK(left_to_allocate_ > 0); + SLICER_CHECK_GT(left_to_allocate_, 0); int delta = std::min(left_to_allocate_, 16 - static_cast(code_ir->ir_method->code->registers)); if (delta < 1) { @@ -301,57 +683,15 @@ void AllocateScratchRegs::RegsRenumbering(lir::CodeIr* code_ir) { // void AllocateScratchRegs::ShiftParams(lir::CodeIr* code_ir) { const auto ir_method = code_ir->ir_method; - SLICER_CHECK(ir_method->code->ins_count > 0); - SLICER_CHECK(left_to_allocate_ > 0); - - // build a param list with the explicit "this" argument for non-static methods - std::vector param_types; - if ((ir_method->access_flags & dex::kAccStatic) == 0) { - param_types.push_back(ir_method->decl->parent); - } - if (ir_method->decl->prototype->param_types != nullptr) { - const auto& orig_param_types = ir_method->decl->prototype->param_types->types; - param_types.insert(param_types.end(), orig_param_types.begin(), orig_param_types.end()); - } + SLICER_CHECK_GT(left_to_allocate_, 0); const dex::u4 shift = left_to_allocate_; - Allocate(code_ir, ir_method->code->registers, left_to_allocate_); assert(left_to_allocate_ == 0); - const dex::u4 regs = ir_method->code->registers; - const dex::u4 ins_count = ir_method->code->ins_count; - SLICER_CHECK(regs >= ins_count); - // generate the args "relocation" instructions - auto first_instr = code_ir->instructions.begin(); - dex::u4 reg = regs - ins_count; - for (const auto& type : param_types) { - auto move = code_ir->Alloc(); - switch (type->GetCategory()) { - case ir::Type::Category::Reference: - move->opcode = dex::OP_MOVE_OBJECT_16; - move->operands.push_back(code_ir->Alloc(reg - shift)); - move->operands.push_back(code_ir->Alloc(reg)); - reg += 1; - break; - case ir::Type::Category::Scalar: - move->opcode = dex::OP_MOVE_16; - move->operands.push_back(code_ir->Alloc(reg - shift)); - move->operands.push_back(code_ir->Alloc(reg)); - reg += 1; - break; - case ir::Type::Category::WideScalar: - move->opcode = dex::OP_MOVE_WIDE_16; - move->operands.push_back(code_ir->Alloc(reg - shift)); - move->operands.push_back(code_ir->Alloc(reg)); - reg += 2; - break; - case ir::Type::Category::Void: - SLICER_FATAL("void parameter type"); - } - code_ir->instructions.insert(first_instr, move); - } + auto first_instr = *(code_ir->instructions.begin()); + GenerateShiftParamsCode(code_ir, first_instr, shift); } // Mark [first_reg, first_reg + count) as scratch registers @@ -374,7 +714,7 @@ void AllocateScratchRegs::Allocate(lir::CodeIr* code_ir, dex::u4 first_reg, int bool AllocateScratchRegs::Apply(lir::CodeIr* code_ir) { const auto code = code_ir->ir_method->code; // .dex bytecode allows up to 64k vregs - SLICER_CHECK(code->registers + allocate_count_ <= (1 << 16)); + SLICER_CHECK_LE(code->registers + allocate_count_, (1 << 16)); scratch_regs_.clear(); left_to_allocate_ = allocate_count_; @@ -402,7 +742,7 @@ bool AllocateScratchRegs::Apply(lir::CodeIr* code_ir) { } bool MethodInstrumenter::InstrumentMethod(ir::EncodedMethod* ir_method) { - SLICER_CHECK(ir_method != nullptr); + SLICER_CHECK_NE(ir_method, nullptr); if (ir_method->code == nullptr) { // can't instrument abstract methods return false; diff --git a/dexmaker-mockito-inline/external/slicer/reader.cc b/dexmaker-mockito-inline/external/slicer/reader.cc index 1c547af3..14c43d73 100644 --- a/dexmaker-mockito-inline/external/slicer/reader.cc +++ b/dexmaker-mockito-inline/external/slicer/reader.cc @@ -15,8 +15,9 @@ */ #include "slicer/reader.h" -#include "slicer/dex_bytecode.h" + #include "slicer/chronometer.h" +#include "slicer/dex_bytecode.h" #include "slicer/dex_leb128.h" #include @@ -66,6 +67,30 @@ slicer::ArrayView Reader::ProtoIds() const { header_->proto_ids_size); } +slicer::ArrayView Reader::MethodHandles() const { + const dex::MapList* ml = DexMapList(); + if(ml == nullptr){ + slicer::ArrayView ret; + return ret; + } + + // Find MethodHandle entry + const dex::MapItem* mi = nullptr; + for(int i = 0; i < ml->size; i++){ + if(ml->list[i].type == dex::kMethodHandleItem){ + mi = &(ml->list[i]); + break; + } + } + + if(mi == nullptr){ + slicer::ArrayView ret; + return ret; + } + + return section(mi->offset, mi->size); +} + const dex::MapList* Reader::DexMapList() const { return dataPtr(header_->map_off); } @@ -88,7 +113,7 @@ void Reader::CreateFullIr() { void Reader::CreateClassIr(dex::u4 index) { auto ir_class = GetClass(index); - SLICER_CHECK(ir_class != nullptr); + SLICER_CHECK_NE(ir_class, nullptr); } // Returns the index of the class with the specified @@ -109,112 +134,128 @@ dex::u4 Reader::FindClassIndex(const char* class_descriptor) const { // map a .dex index to corresponding .dex IR node // // NOTES: -// 1. the mapping beween an index and the indexed +// 1. the mapping between an index and the indexed // .dex IR nodes is 1:1 // 2. we do a single index lookup for both existing // nodes as well as new nodes -// 3. dummy is an invalid, but non-null pointer value -// used to check that the mapping loookup/update is atomic +// 3. placeholder is an invalid, but non-null pointer value +// used to check that the mapping lookup/update is atomic // 4. there should be no recursion with the same index -// (we use the dummy value to guard against this too) +// (we use the placeholder value to guard against this too) // ir::Class* Reader::GetClass(dex::u4 index) { - SLICER_CHECK(index != dex::kNoIndex); + SLICER_CHECK_NE(index, dex::kNoIndex); auto& p = dex_ir_->classes_map[index]; - auto dummy = reinterpret_cast(1); + auto placeholder = reinterpret_cast(1); if (p == nullptr) { - p = dummy; + p = placeholder; auto newClass = ParseClass(index); - SLICER_CHECK(p == dummy); + SLICER_CHECK_EQ(p, placeholder); p = newClass; dex_ir_->classes_indexes.MarkUsedIndex(index); } - SLICER_CHECK(p != dummy); + SLICER_CHECK_NE(p, placeholder); return p; } // map a .dex index to corresponding .dex IR node // (see the Reader::GetClass() comments) ir::Type* Reader::GetType(dex::u4 index) { - SLICER_CHECK(index != dex::kNoIndex); + SLICER_CHECK_NE(index, dex::kNoIndex); auto& p = dex_ir_->types_map[index]; - auto dummy = reinterpret_cast(1); + auto placeholder = reinterpret_cast(1); if (p == nullptr) { - p = dummy; + p = placeholder; auto newType = ParseType(index); - SLICER_CHECK(p == dummy); + SLICER_CHECK_EQ(p, placeholder); p = newType; dex_ir_->types_indexes.MarkUsedIndex(index); } - SLICER_CHECK(p != dummy); + SLICER_CHECK_NE(p, placeholder); return p; } // map a .dex index to corresponding .dex IR node // (see the Reader::GetClass() comments) ir::FieldDecl* Reader::GetFieldDecl(dex::u4 index) { - SLICER_CHECK(index != dex::kNoIndex); + SLICER_CHECK_NE(index, dex::kNoIndex); auto& p = dex_ir_->fields_map[index]; - auto dummy = reinterpret_cast(1); + auto placeholder = reinterpret_cast(1); if (p == nullptr) { - p = dummy; + p = placeholder; auto newField = ParseFieldDecl(index); - SLICER_CHECK(p == dummy); + SLICER_CHECK_EQ(p, placeholder); p = newField; dex_ir_->fields_indexes.MarkUsedIndex(index); } - SLICER_CHECK(p != dummy); + SLICER_CHECK_NE(p, placeholder); + return p; +} + +ir::MethodHandle* Reader::GetMethodHandle(dex::u4 index){ + SLICER_CHECK_NE(index, dex::kNoIndex); + auto& p = dex_ir_->method_handles_map[index]; + auto placeholder = reinterpret_cast(1); + if(p == nullptr) { + p = placeholder; + auto newMethodHandle = ParseMethodHandle(index); + SLICER_CHECK_EQ(p, placeholder); + p = newMethodHandle; + dex_ir_->method_handle_indexes.MarkUsedIndex(index); + } + + SLICER_CHECK_NE(p, placeholder); return p; } // map a .dex index to corresponding .dex IR node // (see the Reader::GetClass() comments) ir::MethodDecl* Reader::GetMethodDecl(dex::u4 index) { - SLICER_CHECK(index != dex::kNoIndex); + SLICER_CHECK_NE(index, dex::kNoIndex); auto& p = dex_ir_->methods_map[index]; - auto dummy = reinterpret_cast(1); + auto placeholder = reinterpret_cast(1); if (p == nullptr) { - p = dummy; + p = placeholder; auto newMethod = ParseMethodDecl(index); - SLICER_CHECK(p == dummy); + SLICER_CHECK_EQ(p, placeholder); p = newMethod; dex_ir_->methods_indexes.MarkUsedIndex(index); } - SLICER_CHECK(p != dummy); + SLICER_CHECK_NE(p, placeholder); return p; } // map a .dex index to corresponding .dex IR node // (see the Reader::GetClass() comments) ir::Proto* Reader::GetProto(dex::u4 index) { - SLICER_CHECK(index != dex::kNoIndex); + SLICER_CHECK_NE(index, dex::kNoIndex); auto& p = dex_ir_->protos_map[index]; - auto dummy = reinterpret_cast(1); + auto placeholder = reinterpret_cast(1); if (p == nullptr) { - p = dummy; + p = placeholder; auto newProto = ParseProto(index); - SLICER_CHECK(p == dummy); + SLICER_CHECK_EQ(p, placeholder); p = newProto; dex_ir_->protos_indexes.MarkUsedIndex(index); } - SLICER_CHECK(p != dummy); + SLICER_CHECK_NE(p, placeholder); return p; } // map a .dex index to corresponding .dex IR node // (see the Reader::GetClass() comments) ir::String* Reader::GetString(dex::u4 index) { - SLICER_CHECK(index != dex::kNoIndex); + SLICER_CHECK_NE(index, dex::kNoIndex); auto& p = dex_ir_->strings_map[index]; - auto dummy = reinterpret_cast(1); + auto placeholder = reinterpret_cast(1); if (p == nullptr) { - p = dummy; + p = placeholder; auto newString = ParseString(index); - SLICER_CHECK(p == dummy); + SLICER_CHECK_EQ(p, placeholder); p = newString; dex_ir_->strings_indexes.MarkUsedIndex(index); } - SLICER_CHECK(p != dummy); + SLICER_CHECK_NE(p, placeholder); return p; } @@ -282,7 +323,7 @@ ir::AnnotationsDirectory* Reader::ExtractAnnotations(dex::u4 offset) { return nullptr; } - SLICER_CHECK(offset % 4 == 0); + SLICER_CHECK_EQ(offset % 4, 0); // first check if we already extracted the same "annotations_directory_item" auto& ir_annotations = annotations_directories_[offset]; @@ -312,7 +353,7 @@ ir::AnnotationsDirectory* Reader::ExtractAnnotations(dex::u4 offset) { } ir::Annotation* Reader::ExtractAnnotationItem(dex::u4 offset) { - SLICER_CHECK(offset != 0); + SLICER_CHECK_NE(offset, 0); // first check if we already extracted the same "annotation_item" auto& ir_annotation = annotations_[offset]; @@ -330,7 +371,7 @@ ir::AnnotationSet* Reader::ExtractAnnotationSet(dex::u4 offset) { return nullptr; } - SLICER_CHECK(offset % 4 == 0); + SLICER_CHECK_EQ(offset % 4, 0); // first check if we already extracted the same "annotation_set_item" auto& ir_annotation_set = annotation_sets_[offset]; @@ -348,7 +389,7 @@ ir::AnnotationSet* Reader::ExtractAnnotationSet(dex::u4 offset) { } ir::AnnotationSetRefList* Reader::ExtractAnnotationSetRefList(dex::u4 offset) { - SLICER_CHECK(offset % 4 == 0); + SLICER_CHECK_EQ(offset % 4, 0); auto dex_annotation_set_ref_list = dataPtr(offset); auto ir_annotation_set_ref_list = dex_ir_->Alloc(); @@ -357,7 +398,7 @@ ir::AnnotationSetRefList* Reader::ExtractAnnotationSetRefList(dex::u4 offset) { dex::u4 entry_offset = dex_annotation_set_ref_list->list[i].annotations_off; if (entry_offset != 0) { auto ir_annotation_set = ExtractAnnotationSet(entry_offset); - SLICER_CHECK(ir_annotation_set != nullptr); + SLICER_CHECK_NE(ir_annotation_set, nullptr); ir_annotation_set_ref_list->annotations.push_back(ir_annotation_set); } } @@ -373,7 +414,7 @@ ir::FieldAnnotation* Reader::ParseFieldAnnotation(const dex::u1** pptr) { ir_field_annotation->annotations = ExtractAnnotationSet(dex_field_annotation->annotations_off); - SLICER_CHECK(ir_field_annotation->annotations != nullptr); + SLICER_CHECK_NE(ir_field_annotation->annotations, nullptr); *pptr += sizeof(dex::FieldAnnotationsItem); return ir_field_annotation; @@ -388,7 +429,7 @@ ir::MethodAnnotation* Reader::ParseMethodAnnotation(const dex::u1** pptr) { ir_method_annotation->annotations = ExtractAnnotationSet(dex_method_annotation->annotations_off); - SLICER_CHECK(ir_method_annotation->annotations != nullptr); + SLICER_CHECK_NE(ir_method_annotation->annotations, nullptr); *pptr += sizeof(dex::MethodAnnotationsItem); return ir_method_annotation; @@ -403,7 +444,7 @@ ir::ParamAnnotation* Reader::ParseParamAnnotation(const dex::u1** pptr) { ir_param_annotation->annotations = ExtractAnnotationSetRefList(dex_param_annotation->annotations_off); - SLICER_CHECK(ir_param_annotation->annotations != nullptr); + SLICER_CHECK_NE(ir_param_annotation->annotations, nullptr); *pptr += sizeof(dex::ParameterAnnotationsItem); return ir_param_annotation; @@ -413,9 +454,9 @@ ir::EncodedField* Reader::ParseEncodedField(const dex::u1** pptr, dex::u4* base_ auto ir_encoded_field = dex_ir_->Alloc(); auto field_index = dex::ReadULeb128(pptr); - SLICER_CHECK(field_index != dex::kNoIndex); + SLICER_CHECK_NE(field_index, dex::kNoIndex); if (*base_index != dex::kNoIndex) { - SLICER_CHECK(field_index != 0); + SLICER_CHECK_NE(field_index, 0); field_index += *base_index; } *base_index = field_index; @@ -432,8 +473,8 @@ template static T ParseIntValue(const dex::u1** pptr, size_t size) { static_assert(std::is_integral::value, "must be an integral type"); - SLICER_CHECK(size > 0); - SLICER_CHECK(size <= sizeof(T)); + SLICER_CHECK_GT(size, 0); + SLICER_CHECK_LE(size, sizeof(T)); T value = 0; for (int i = 0; i < size; ++i) { @@ -453,8 +494,8 @@ static T ParseIntValue(const dex::u1** pptr, size_t size) { // (zero-extend to the right) template static T ParseFloatValue(const dex::u1** pptr, size_t size) { - SLICER_CHECK(size > 0); - SLICER_CHECK(size <= sizeof(T)); + SLICER_CHECK_GT(size, 0); + SLICER_CHECK_LE(size, sizeof(T)); T value = 0; int start_byte = sizeof(T) - size; @@ -531,21 +572,21 @@ ir::EncodedValue* Reader::ParseEncodedValue(const dex::u1** pptr) { } break; case dex::kEncodedArray: - SLICER_CHECK(arg == 0); + SLICER_CHECK_EQ(arg, 0); ir_encoded_value->u.array_value = ParseEncodedArray(pptr); break; case dex::kEncodedAnnotation: - SLICER_CHECK(arg == 0); + SLICER_CHECK_EQ(arg, 0); ir_encoded_value->u.annotation_value = ParseAnnotation(pptr); break; case dex::kEncodedNull: - SLICER_CHECK(arg == 0); + SLICER_CHECK_EQ(arg, 0); break; case dex::kEncodedBoolean: - SLICER_CHECK(arg < 2); + SLICER_CHECK_LT(arg, 2); ir_encoded_value->u.bool_value = (arg == 1); break; @@ -703,7 +744,7 @@ ir::Code* Reader::ExtractCode(dex::u4 offset) { return nullptr; } - SLICER_CHECK(offset % 4 == 0); + SLICER_CHECK_EQ(offset % 4, 0); auto dex_code = dataPtr(offset); auto ir_code = dex_ir_->Alloc(); @@ -769,9 +810,9 @@ ir::EncodedMethod* Reader::ParseEncodedMethod(const dex::u1** pptr, dex::u4* bas auto ir_encoded_method = dex_ir_->Alloc(); auto method_index = dex::ReadULeb128(pptr); - SLICER_CHECK(method_index != dex::kNoIndex); + SLICER_CHECK_NE(method_index, dex::kNoIndex); if (*base_index != dex::kNoIndex) { - SLICER_CHECK(method_index != 0); + SLICER_CHECK_NE(method_index, 0); method_index += *base_index; } *base_index = method_index; @@ -810,6 +851,22 @@ ir::FieldDecl* Reader::ParseFieldDecl(dex::u4 index) { return ir_field; } +ir::MethodHandle* Reader::ParseMethodHandle(dex::u4 index){ + auto& dex_method_handle = MethodHandles()[index]; + auto ir_method_handle = dex_ir_->Alloc(); + + ir_method_handle->method_handle_type = dex_method_handle.method_handle_type; + + if(ir_method_handle->IsField()){ + ir_method_handle->field = GetFieldDecl(dex_method_handle.field_or_method_id); + } + else { + ir_method_handle->method = GetMethodDecl(dex_method_handle.field_or_method_id); + } + + return ir_method_handle; +} + ir::MethodDecl* Reader::ParseMethodDecl(dex::u4 index) { auto& dex_method = MethodIds()[index]; auto ir_method = dex_ir_->Alloc(); @@ -881,16 +938,23 @@ void Reader::ParseInstructions(slicer::ArrayView code) { auto dex_instr = dex::DecodeInstruction(ptr); dex::u4 index = dex::kNoIndex; + dex::u4 index2 = dex::kNoIndex; switch (dex::GetFormatFromOpcode(dex_instr.opcode)) { - case dex::kFmt20bc: - case dex::kFmt21c: - case dex::kFmt31c: - case dex::kFmt35c: - case dex::kFmt3rc: + case dex::k20bc: + case dex::k21c: + case dex::k31c: + case dex::k35c: + case dex::k3rc: index = dex_instr.vB; break; - case dex::kFmt22c: + case dex::k45cc: + case dex::k4rcc: + index = dex_instr.vB; + index2 = dex_instr.arg[4]; + break; + + case dex::k22c: index = dex_instr.vC; break; @@ -915,44 +979,63 @@ void Reader::ParseInstructions(slicer::ArrayView code) { GetMethodDecl(index); break; + case dex::kIndexMethodAndProtoRef: + GetMethodDecl(index); + GetProto(index2); + break; + + case dex::kIndexMethodHandleRef: + GetMethodHandle(index); + break; + default: break; } auto isize = dex::GetWidthFromBytecode(ptr); - SLICER_CHECK(isize > 0); + SLICER_CHECK_GT(isize, 0); ptr += isize; } - SLICER_CHECK(ptr == code.end()); + SLICER_CHECK_EQ(ptr, code.end()); } // Basic .dex header structural checks void Reader::ValidateHeader() { - SLICER_CHECK(size_ > sizeof(dex::Header)); + SLICER_CHECK_GT(size_, dex::Header::kV40Size); // Known issue: For performance reasons the initial size_ passed to jvmti events might be an // estimate. b/72402467 - SLICER_CHECK(header_->file_size <= size_); - SLICER_CHECK(header_->header_size == sizeof(dex::Header)); - SLICER_CHECK(header_->endian_tag == dex::kEndianConstant); - SLICER_CHECK(header_->data_size % 4 == 0); + SLICER_CHECK_LE(header_->file_size, size_); + // Check that we support this version of dex header + SLICER_CHECK( + header_->header_size == dex::Header::kV40Size || + header_->header_size == dex::Header::kV41Size); + SLICER_CHECK_EQ(header_->endian_tag, dex::kEndianConstant); + SLICER_CHECK_EQ(header_->data_size % 4, 0); + + // If the dex file is within container with other dex files, + // adjust the base address to the start of the container. + SLICER_CHECK_LE(header_->ContainerSize() - header_->ContainerOff(), size_); + image_ -= header_->ContainerOff(); + size_ = header_->ContainerSize(); // Known issue: The fields might be slighly corrupted b/65452964 - // SLICER_CHECK(header_->data_off + header_->data_size <= size_); - - SLICER_CHECK(header_->string_ids_off % 4 == 0); - SLICER_CHECK(header_->type_ids_size < 65536); - SLICER_CHECK(header_->type_ids_off % 4 == 0); - SLICER_CHECK(header_->proto_ids_size < 65536); - SLICER_CHECK(header_->proto_ids_off % 4 == 0); - SLICER_CHECK(header_->field_ids_off % 4 == 0); - SLICER_CHECK(header_->method_ids_off % 4 == 0); - SLICER_CHECK(header_->class_defs_off % 4 == 0); - SLICER_CHECK(header_->map_off >= header_->data_off && header_->map_off < size_); - SLICER_CHECK(header_->link_size == 0); - SLICER_CHECK(header_->link_off == 0); - SLICER_CHECK(header_->data_off % 4 == 0); - SLICER_CHECK(header_->map_off % 4 == 0); + // SLICER_CHECK_LE(header_->data_off + header_->data_size, size_); + + SLICER_CHECK_EQ(header_->string_ids_off % 4, 0); + SLICER_CHECK_LT(header_->type_ids_size, 65536); + SLICER_CHECK_EQ(header_->type_ids_off % 4, 0); + SLICER_CHECK_LT(header_->proto_ids_size, 65536); + SLICER_CHECK_EQ(header_->proto_ids_off % 4, 0); + SLICER_CHECK_EQ(header_->field_ids_off % 4, 0); + SLICER_CHECK_EQ(header_->method_ids_off % 4, 0); + SLICER_CHECK_EQ(header_->class_defs_off % 4, 0); + SLICER_CHECK_GE(header_->map_off, header_->data_off); + SLICER_CHECK_LT(header_->map_off, size_); + SLICER_CHECK_EQ(header_->link_size, 0); + SLICER_CHECK_EQ(header_->link_off, 0); + SLICER_CHECK_EQ(header_->data_off % 4, 0); + SLICER_CHECK_EQ(header_->map_off % 4, 0); // we seem to have .dex files with extra bytes at the end ... // Known issue: For performance reasons the initial size_ passed to jvmti events might be an @@ -961,18 +1044,18 @@ void Reader::ValidateHeader() { // but we should still have the whole data section - // Known issue: The fields might be slighly corrupted b/65452964 + // Known issue: The fields might be slightly corrupted b/65452964 // Known issue: For performance reasons the initial size_ passed to jvmti events might be an // estimate. b/72402467 - // SLICER_CHECK(header_->data_off + header_->data_size <= size_); + // SLICER_CHECK_LE(header_->data_off + header_->data_size, size_); // validate the map // (map section size = sizeof(MapList::size) + sizeof(MapList::list[size]) auto map_list = ptr(header_->map_off); - SLICER_CHECK(map_list->size > 0); + SLICER_CHECK_GT(map_list->size, 0); auto map_section_size = sizeof(dex::u4) + sizeof(dex::MapItem) * map_list->size; - SLICER_CHECK(header_->map_off + map_section_size <= size_); + SLICER_CHECK_LE(header_->map_off + map_section_size, size_); } } // namespace dex diff --git a/dexmaker-mockito-inline/external/slicer/tryblocks_encoder.cc b/dexmaker-mockito-inline/external/slicer/tryblocks_encoder.cc index 547e9d05..2950cee6 100644 --- a/dexmaker-mockito-inline/external/slicer/tryblocks_encoder.cc +++ b/dexmaker-mockito-inline/external/slicer/tryblocks_encoder.cc @@ -15,18 +15,17 @@ */ #include "slicer/tryblocks_encoder.h" + #include "slicer/chronometer.h" #include "slicer/common.h" -#include - namespace lir { bool TryBlocksEncoder::Visit(TryBlockEnd* try_end) { const dex::u4 begin_offset = try_end->try_begin->offset; const dex::u4 end_offset = try_end->offset; - SLICER_CHECK(end_offset > begin_offset); - SLICER_CHECK(end_offset - begin_offset < (1 << 16)); + SLICER_CHECK_GT(end_offset, begin_offset); + SLICER_CHECK_LT(end_offset - begin_offset, (1 << 16)); // generate the "try_item" dex::TryBlock try_block = {}; @@ -43,12 +42,12 @@ bool TryBlocksEncoder::Visit(TryBlockEnd* try_end) { // type_idx handlers_.PushULeb128(handler.ir_type->orig_index); // address - SLICER_CHECK(handler.label->offset != kInvalidOffset); + SLICER_CHECK_NE(handler.label->offset, kInvalidOffset); handlers_.PushULeb128(handler.label->offset); } if (try_end->catch_all != nullptr) { // address - SLICER_CHECK(try_end->catch_all->offset != kInvalidOffset); + SLICER_CHECK_NE(try_end->catch_all->offset, kInvalidOffset); handlers_.PushULeb128(try_end->catch_all->offset); } @@ -60,13 +59,19 @@ void TryBlocksEncoder::Encode(ir::Code* ir_code, std::shared_ptr de SLICER_CHECK(tries_.empty()); // first, count the number of try blocks - int tries_count = 0; - for (auto instr : instructions_) { - if (instr->IsA()) { + struct TryBlockEndVisitor : public Visitor { + int tries_count = 0; + bool Visit(TryBlockEnd* try_end) override { ++tries_count; + return true; } + }; + TryBlockEndVisitor visitor; + for (auto instr : instructions_) { + instr->Accept(&visitor); } - SLICER_CHECK(tries_count < (1 << 16)); + int tries_count = visitor.tries_count; + SLICER_CHECK_LT(tries_count, (1 << 16)); // no try blocks? if (tries_count == 0) { diff --git a/dexmaker-mockito-inline/external/slicer/writer.cc b/dexmaker-mockito-inline/external/slicer/writer.cc index 3361c708..c1f68a97 100644 --- a/dexmaker-mockito-inline/external/slicer/writer.cc +++ b/dexmaker-mockito-inline/external/slicer/writer.cc @@ -15,6 +15,7 @@ */ #include "slicer/writer.h" + #include "slicer/common.h" #include "slicer/scopeguard.h" #include "slicer/dex_bytecode.h" @@ -25,7 +26,6 @@ #include #include #include -#include #include #include @@ -189,8 +189,8 @@ static void WriteEncodedValue(const ir::EncodedValue* ir_value, Section& data) { case dex::kEncodedBoolean: auto ptr = data.ptr(offset); auto size = data.size() - offset; - SLICER_CHECK(size == ir_value->original.size()); - SLICER_CHECK(memcmp(ptr, ir_value->original.ptr(), size) == 0); + SLICER_CHECK_EQ(size, ir_value->original.size()); + SLICER_CHECK_EQ(memcmp(ptr, ir_value->original.ptr(), size), 0); break; } }); @@ -219,19 +219,26 @@ static void WriteEncodedArray(const ir::EncodedArray* ir_array, Section& data) { template static void CopySection(const T& section, dex::u1* image, dex::u4 image_size) { if (section.size() == 0) { - SLICER_CHECK(section.ItemsCount() == 0); + SLICER_CHECK_EQ(section.ItemsCount(), 0); return; } - SLICER_CHECK(section.ItemsCount() > 0); + SLICER_CHECK_GT(section.ItemsCount(), 0); dex::u4 offset = section.SectionOffset(); dex::u4 size = section.size(); - SLICER_CHECK(offset >= sizeof(dex::Header)); - SLICER_CHECK(offset + size <= image_size); + SLICER_CHECK_GE(offset, dex::Header::kV40Size); + SLICER_CHECK_LE(offset + size, image_size); ::memcpy(image + offset, section.data(), size); } +static u4 ReadU4(const u2* ptr) { return ptr[0] | (u4(ptr[1]) << 16); } + +static void WriteU4(u2* ptr, u4 val) { + ptr[0] = val & 0xffff; + ptr[1] = val >> 16; +} + // This is the main interface for the .dex writer // (returns nullptr on failure) dex::u1* Writer::CreateImage(Allocator* allocator, size_t* new_image_size) { @@ -246,21 +253,28 @@ dex::u1* Writer::CreateImage(Allocator* allocator, size_t* new_image_size) { // (ideally we shouldn't change the IR while generating an image) dex_ir_->Normalize(); + int version = Header::GetVersion(dex_ir_->magic.ptr()); + SLICER_CHECK_NE(version, 0); + SLICER_CHECK_GE(version, Header::kMinVersion); + SLICER_CHECK_LE(version, Header::kMaxVersion); + u4 header_size = version >= Header::kV41 ? Header::kV41Size : Header::kV40Size; + // track the current offset within the .dex image dex::u4 offset = 0; // allocate the image and index sections // (they will be back-filled) - offset += sizeof(dex::Header); + offset += header_size; offset += dex_->string_ids.Init(offset, dex_ir_->strings.size()); offset += dex_->type_ids.Init(offset, dex_ir_->types.size()); offset += dex_->proto_ids.Init(offset, dex_ir_->protos.size()); offset += dex_->field_ids.Init(offset, dex_ir_->fields.size()); offset += dex_->method_ids.Init(offset, dex_ir_->methods.size()); offset += dex_->class_defs.Init(offset, dex_ir_->classes.size()); + offset += dex_->method_handles.Init(offset, dex_ir_->method_handles.size()); // the base offset for the "data" meta-section - SLICER_CHECK(offset % 4 == 0); + SLICER_CHECK_EQ(offset % 4, 0); const dex::u4 data_offset = offset; // we must create the sections in a very specific @@ -283,9 +297,10 @@ dex::u1* Writer::CreateImage(Allocator* allocator, size_t* new_image_size) { FillProtos(); FillMethods(); FillClassDefs(); + FillMethodHandles(); // allocate the final buffer for the .dex image - SLICER_CHECK(offset % 4 == 0); + SLICER_CHECK_EQ(offset % 4, 0); const dex::u4 image_size = offset; dex::u1* image = static_cast(allocator->Allocate(image_size)); if (image == nullptr) { @@ -295,7 +310,7 @@ dex::u1* Writer::CreateImage(Allocator* allocator, size_t* new_image_size) { memset(image, 0, image_size); // finally, back-fill the header - SLICER_CHECK(image_size > sizeof(dex::Header)); + SLICER_CHECK_GT(image_size, header_size); dex::Header* header = reinterpret_cast(image + 0); @@ -303,7 +318,7 @@ dex::u1* Writer::CreateImage(Allocator* allocator, size_t* new_image_size) { memcpy(header->magic, dex_ir_->magic.ptr(), dex_ir_->magic.size()); header->file_size = image_size; - header->header_size = sizeof(dex::Header); + header->header_size = header_size; header->endian_tag = dex::kEndianConstant; header->link_size = 0; @@ -324,6 +339,11 @@ dex::u1* Writer::CreateImage(Allocator* allocator, size_t* new_image_size) { header->class_defs_off = dex_->class_defs.SectionOffset(); header->data_size = image_size - data_offset; header->data_off = data_offset; + if (version >= Header::kV41) { + header->data_size = 0; + header->data_off = 0; + header->SetContainer(0, header->file_size); + } // copy the individual sections to the final image CopySection(dex_->string_ids, image, image_size); @@ -332,6 +352,7 @@ dex::u1* Writer::CreateImage(Allocator* allocator, size_t* new_image_size) { CopySection(dex_->field_ids, image, image_size); CopySection(dex_->method_ids, image, image_size); CopySection(dex_->class_defs, image, image_size); + CopySection(dex_->method_handles, image, image_size); CopySection(dex_->string_data, image, image_size); CopySection(dex_->type_lists, image, image_size); CopySection(dex_->debug_info, image, image_size); @@ -374,7 +395,7 @@ dex::u4 Writer::CreateStringDataSection(dex::u4 section_offset) { template static void AddMapItem(const T& section, std::vector& items) { if (section.ItemsCount() > 0) { - SLICER_CHECK(section.SectionOffset() >= sizeof(dex::Header)); + SLICER_CHECK_GE(section.SectionOffset(), dex::Header::kV40Size); dex::MapItem map_item = {}; map_item.type = section.MapEntryType(); map_item.size = section.ItemsCount(); @@ -403,6 +424,7 @@ dex::u4 Writer::CreateMapSection(dex::u4 section_offset) { AddMapItem(dex_->field_ids, map_items); AddMapItem(dex_->method_ids, map_items); AddMapItem(dex_->class_defs, map_items); + AddMapItem(dex_->method_handles, map_items); AddMapItem(dex_->string_data, map_items); AddMapItem(dex_->type_lists, map_items); AddMapItem(dex_->debug_info, map_items); @@ -417,7 +439,7 @@ dex::u4 Writer::CreateMapSection(dex::u4 section_offset) { std::sort(map_items.begin(), map_items.end(), [](const dex::MapItem& a, const dex::MapItem& b) { - SLICER_CHECK(a.offset != b.offset); + SLICER_CHECK_NE(a.offset, b.offset); return a.offset < b.offset; }); @@ -434,7 +456,7 @@ dex::u4 Writer::CreateAnnItemSection(dex::u4 section_offset) { if (ir_node->visibility != dex::kVisibilityEncoded) { // TODO: factor out the node_offset_ updating dex::u4& offset = node_offset_[ir_node.get()]; - SLICER_CHECK(offset == 0); + SLICER_CHECK_EQ(offset, 0); offset = WriteAnnotationItem(ir_node.get()); } } @@ -448,7 +470,7 @@ dex::u4 Writer::CreateAnnSetsSection(dex::u4 section_offset) { for (const auto& ir_node : dex_ir_->annotation_sets) { dex::u4& offset = node_offset_[ir_node.get()]; - SLICER_CHECK(offset == 0); + SLICER_CHECK_EQ(offset, 0); offset = WriteAnnotationSet(ir_node.get()); } @@ -461,7 +483,7 @@ dex::u4 Writer::CreateAnnSetRefListsSection(dex::u4 section_offset) { for (const auto& ir_node : dex_ir_->annotation_set_ref_lists) { dex::u4& offset = node_offset_[ir_node.get()]; - SLICER_CHECK(offset == 0); + SLICER_CHECK_EQ(offset, 0); offset = WriteAnnotationSetRefList(ir_node.get()); } @@ -474,7 +496,7 @@ dex::u4 Writer::CreateTypeListsSection(dex::u4 section_offset) { for (const auto& ir_type_list : dex_ir_->type_lists) { dex::u4& offset = node_offset_[ir_type_list.get()]; - SLICER_CHECK(offset == 0); + SLICER_CHECK_EQ(offset, 0); offset = WriteTypeList(ir_type_list->types); } @@ -487,7 +509,7 @@ dex::u4 Writer::CreateCodeItemSection(dex::u4 section_offset) { for (const auto& ir_node : dex_ir_->code) { dex::u4& offset = node_offset_[ir_node.get()]; - SLICER_CHECK(offset == 0); + SLICER_CHECK_EQ(offset, 0); offset = WriteCode(ir_node.get()); } @@ -501,7 +523,7 @@ dex::u4 Writer::CreateDebugInfoSection(dex::u4 section_offset) { for (const auto& ir_node : dex_ir_->debug_info) { dex::u4& offset = node_offset_[ir_node.get()]; - SLICER_CHECK(offset == 0); + SLICER_CHECK_EQ(offset, 0); offset = WriteDebugInfo(ir_node.get()); } @@ -567,14 +589,34 @@ void Writer::FillTypes() { void Writer::FillProtos() { const auto& protos = dex_ir_->protos; for (size_t i = 0; i < protos.size(); ++i) { + const auto& irProto = protos[i]; auto dexProtoId = &dex_->proto_ids[i]; + dexProtoId->shorty_idx = irProto->shorty->index; dexProtoId->return_type_idx = irProto->return_type->index; dexProtoId->parameters_off = FilePointer(irProto->param_types); } } +void Writer::FillMethodHandles(){ + const auto& methodHandles = dex_ir_->method_handles; + for(size_t i = 0; i < methodHandles.size(); ++i){ + + const auto& irMethodHandle = methodHandles[i]; + auto dexMethodHandle = &dex_->method_handles[i]; + + dexMethodHandle->method_handle_type = irMethodHandle->method_handle_type; + + if(irMethodHandle->IsField()){ + dexMethodHandle->field_or_method_id = irMethodHandle->field->index; + } + else{ + dexMethodHandle->field_or_method_id = irMethodHandle->method->index; + } + } +} + // "field_id_item" void Writer::FillFields() { const auto& fields = dex_ir_->fields; @@ -637,7 +679,7 @@ dex::u4 Writer::WriteTypeList(const std::vector& types) { // "annotation_item" dex::u4 Writer::WriteAnnotationItem(const ir::Annotation* ir_annotation) { - SLICER_CHECK(ir_annotation->visibility != dex::kVisibilityEncoded); + SLICER_CHECK_NE(ir_annotation->visibility, dex::kVisibilityEncoded); auto& data = dex_->ann_items; dex::u4 offset = data.AddItem(); @@ -648,7 +690,7 @@ dex::u4 Writer::WriteAnnotationItem(const ir::Annotation* ir_annotation) { // "annotation_set_item" dex::u4 Writer::WriteAnnotationSet(const ir::AnnotationSet* ir_annotation_set) { - SLICER_CHECK(ir_annotation_set != nullptr); + SLICER_CHECK_NE(ir_annotation_set, nullptr); const auto& annotations = ir_annotation_set->annotations; @@ -664,7 +706,7 @@ dex::u4 Writer::WriteAnnotationSet(const ir::AnnotationSet* ir_annotation_set) { // "annotation_set_ref_list" dex::u4 Writer::WriteAnnotationSetRefList( const ir::AnnotationSetRefList* ir_annotation_set_ref_list) { - SLICER_CHECK(ir_annotation_set_ref_list != nullptr); + SLICER_CHECK_NE(ir_annotation_set_ref_list, nullptr); const auto& annotations = ir_annotation_set_ref_list->annotations; @@ -740,7 +782,7 @@ dex::u4 Writer::WriteClassAnnotations(const ir::Class* ir_class) { // "debug_info_item" dex::u4 Writer::WriteDebugInfo(const ir::DebugInfo* ir_debug_info) { - SLICER_CHECK(ir_debug_info != nullptr); + SLICER_CHECK_NE(ir_debug_info, nullptr); auto& data = dex_->debug_info; dex::u4 offset = data.AddItem(); @@ -822,64 +864,90 @@ void Writer::WriteInstructions(slicer::ArrayView instructions) { // relocate the instructions while (ptr < end) { auto opcode = dex::OpcodeFromBytecode(*ptr); + dex::u2* idx = &ptr[1]; + dex::u2* idx2 = nullptr; - dex::u2* index16 = nullptr; - dex::u4* index32 = nullptr; - + size_t idx_size = 0; switch (dex::GetFormatFromOpcode(opcode)) { - case dex::kFmt20bc: - case dex::kFmt21c: - case dex::kFmt35c: - case dex::kFmt3rc: - case dex::kFmt22c: - index16 = &ptr[1]; + case dex::k20bc: + case dex::k21c: + case dex::k35c: + case dex::k3rc: + case dex::k22c: + idx_size = 2; break; - case dex::kFmt31c: - index32 = reinterpret_cast(&ptr[1]); + case dex::k31c: + idx_size = 4; break; + case dex::k45cc: + case dex::k4rcc: + idx_size = 2; + idx2 = &ptr[3]; + break; + default: break; } switch (dex::GetIndexTypeFromOpcode(opcode)) { case dex::kIndexStringRef: - if (index32 != nullptr) { - SLICER_CHECK(index16 == nullptr); - dex::u4 new_index = MapStringIndex(*index32); - SLICER_CHECK(new_index != dex::kNoIndex); - *index32 = new_index; + if (idx_size == 4) { + dex::u4 new_index = MapStringIndex(ReadU4(idx)); + SLICER_CHECK_NE(new_index, dex::kNoIndex); + WriteU4(idx, new_index); } else { - dex::u4 new_index = MapStringIndex(*index16); - SLICER_CHECK(new_index != dex::kNoIndex); - SLICER_CHECK(dex::u2(new_index) == new_index); - *index16 = dex::u2(new_index); + SLICER_CHECK_EQ(idx_size, 2); + dex::u4 new_index = MapStringIndex(*idx); + SLICER_CHECK_NE(new_index, dex::kNoIndex); + SLICER_CHECK_EQ(dex::u2(new_index), new_index); + *idx = dex::u2(new_index); } break; case dex::kIndexTypeRef: { - SLICER_CHECK(index32 == nullptr); - dex::u4 new_index = MapTypeIndex(*index16); - SLICER_CHECK(new_index != dex::kNoIndex); - SLICER_CHECK(dex::u2(new_index) == new_index); - *index16 = dex::u2(new_index); + SLICER_CHECK_EQ(idx_size, 2); + dex::u4 new_index = MapTypeIndex(*idx); + SLICER_CHECK_NE(new_index, dex::kNoIndex); + SLICER_CHECK_EQ(dex::u2(new_index), new_index); + *idx = dex::u2(new_index); } break; case dex::kIndexFieldRef: { - SLICER_CHECK(index32 == nullptr); - dex::u4 new_index = MapFieldIndex(*index16); - SLICER_CHECK(new_index != dex::kNoIndex); - SLICER_CHECK(dex::u2(new_index) == new_index); - *index16 = dex::u2(new_index); + SLICER_CHECK_EQ(idx_size, 2); + dex::u4 new_index = MapFieldIndex(*idx); + SLICER_CHECK_NE(new_index, dex::kNoIndex); + SLICER_CHECK_EQ(dex::u2(new_index), new_index); + *idx = dex::u2(new_index); } break; case dex::kIndexMethodRef: { - SLICER_CHECK(index32 == nullptr); - dex::u4 new_index = MapMethodIndex(*index16); - SLICER_CHECK(new_index != dex::kNoIndex); - SLICER_CHECK(dex::u2(new_index) == new_index); - *index16 = dex::u2(new_index); + SLICER_CHECK_EQ(idx_size, 2); + dex::u4 new_index = MapMethodIndex(*idx); + SLICER_CHECK_NE(new_index, dex::kNoIndex); + SLICER_CHECK_EQ(dex::u2(new_index), new_index); + *idx = dex::u2(new_index); + } break; + + case dex::kIndexMethodAndProtoRef: { + SLICER_CHECK_EQ(idx_size, 2); + dex::u4 new_index = MapMethodIndex(*idx); + SLICER_CHECK_NE(new_index, dex::kNoIndex); + SLICER_CHECK_EQ(dex::u2(new_index), new_index); + *idx = dex::u2(new_index); + dex::u4 new_index2 = MapProtoIndex(*idx2); + SLICER_CHECK_NE(new_index2, dex::kNoIndex); + SLICER_CHECK_EQ(dex::u2(new_index2), new_index2); + *idx2 = dex::u2(new_index2); + } break; + + case dex::kIndexMethodHandleRef: { + SLICER_CHECK_EQ(idx_size, 2); + dex::u4 new_index = MapMethodHandleIndex(*idx); + SLICER_CHECK_NE(new_index, dex::kNoIndex); + SLICER_CHECK_EQ(dex::u2(new_index), new_index); + *idx = dex::u2(new_index); } break; default: @@ -887,10 +955,10 @@ void Writer::WriteInstructions(slicer::ArrayView instructions) { } auto isize = dex::GetWidthFromBytecode(ptr); - SLICER_CHECK(isize > 0); + SLICER_CHECK_GT(isize, 0); ptr += isize; } - SLICER_CHECK(ptr == end); + SLICER_CHECK_EQ(ptr, end); } // "try_item[] + encoded_catch_handler_list" @@ -941,14 +1009,14 @@ void Writer::WriteTryBlocks(const ir::Code* irCode) { for (dex::TryBlock& dex_try : slicer::ArrayView( data.ptr(tries_offset), irCode->try_blocks.size())) { dex::u2 new_Handler_offset = handlers_offset_map[dex_try.handler_off]; - SLICER_CHECK(new_Handler_offset != 0); + SLICER_CHECK_NE(new_Handler_offset, 0); dex_try.handler_off = new_Handler_offset; } } // "code_item" dex::u4 Writer::WriteCode(const ir::Code* irCode) { - SLICER_CHECK(irCode != nullptr); + SLICER_CHECK_NE(irCode, nullptr); dex::Code dex_code = {}; dex_code.registers_size = irCode->registers; @@ -973,9 +1041,9 @@ dex::u4 Writer::WriteCode(const ir::Code* irCode) { void Writer::WriteEncodedField(const ir::EncodedField* ir_encoded_field, dex::u4* base_index) { dex::u4 index_delta = ir_encoded_field->decl->index; - SLICER_CHECK(index_delta != dex::kNoIndex); + SLICER_CHECK_NE(index_delta, dex::kNoIndex); if (*base_index != dex::kNoIndex) { - SLICER_CHECK(index_delta > *base_index); + SLICER_CHECK_GT(index_delta, *base_index); index_delta = index_delta - *base_index; } *base_index = ir_encoded_field->decl->index; @@ -989,9 +1057,9 @@ void Writer::WriteEncodedField(const ir::EncodedField* ir_encoded_field, void Writer::WriteEncodedMethod(const ir::EncodedMethod* ir_encoded_method, dex::u4* base_index) { dex::u4 index_delta = ir_encoded_method->decl->index; - SLICER_CHECK(index_delta != dex::kNoIndex); + SLICER_CHECK_NE(index_delta, dex::kNoIndex); if (*base_index != dex::kNoIndex) { - SLICER_CHECK(index_delta > *base_index); + SLICER_CHECK_GT(index_delta, *base_index); index_delta = index_delta - *base_index; } *base_index = ir_encoded_method->decl->index; @@ -1062,7 +1130,7 @@ dex::u4 Writer::WriteClassStaticValues(const ir::Class* ir_class) { dex::u4 Writer::MapStringIndex(dex::u4 index) const { if (index != dex::kNoIndex) { index = dex_ir_->strings_map.at(index)->index; - SLICER_CHECK(index != dex::kNoIndex); + SLICER_CHECK_NE(index, dex::kNoIndex); } return index; } @@ -1071,7 +1139,7 @@ dex::u4 Writer::MapStringIndex(dex::u4 index) const { dex::u4 Writer::MapTypeIndex(dex::u4 index) const { if (index != dex::kNoIndex) { index = dex_ir_->types_map.at(index)->index; - SLICER_CHECK(index != dex::kNoIndex); + SLICER_CHECK_NE(index, dex::kNoIndex); } return index; } @@ -1080,7 +1148,7 @@ dex::u4 Writer::MapTypeIndex(dex::u4 index) const { dex::u4 Writer::MapFieldIndex(dex::u4 index) const { if (index != dex::kNoIndex) { index = dex_ir_->fields_map.at(index)->index; - SLICER_CHECK(index != dex::kNoIndex); + SLICER_CHECK_NE(index, dex::kNoIndex); } return index; } @@ -1089,7 +1157,25 @@ dex::u4 Writer::MapFieldIndex(dex::u4 index) const { dex::u4 Writer::MapMethodIndex(dex::u4 index) const { if (index != dex::kNoIndex) { index = dex_ir_->methods_map.at(index)->index; - SLICER_CHECK(index != dex::kNoIndex); + SLICER_CHECK_NE(index, dex::kNoIndex); + } + return index; +} + +// Map an index from the original .dex to the new index +dex::u4 Writer::MapMethodHandleIndex(dex::u4 index) const { + if (index != dex::kNoIndex) { + index = dex_ir_->method_handles_map.at(index)->index; + SLICER_CHECK_NE(index, dex::kNoIndex); + } + return index; +} + +// Map an index from the original .dex to the new index +dex::u4 Writer::MapProtoIndex(dex::u4 index) const { + if (index != dex::kNoIndex) { + index = dex_ir_->protos_map.at(index)->index; + SLICER_CHECK_NE(index, dex::kNoIndex); } return index; } @@ -1102,7 +1188,7 @@ dex::u4 Writer::FilePointer(const ir::Node* ir_node) const { auto it = node_offset_.find(ir_node); SLICER_CHECK(it != node_offset_.end()); dex::u4 offset = it->second; - SLICER_CHECK(offset > 0); + SLICER_CHECK_GT(offset, 0); return offset; }