DexInstruction* DexInstruction::set_literal(int64_t literal) { assert(has_literal()); auto format = opcode_format(opcode()); switch (format) { case FMT_f11n: m_opcode = (m_opcode & 0xfff) | ((literal & 0xf) << 12); return this; case FMT_f21s: m_arg[0] = literal; return this; case FMT_f21h: m_arg[0] = literal >> 16; return this; case FMT_f22b: m_arg[0] = literal >> 48; return this; case FMT_f22s: m_arg[0] = literal; return this; case FMT_f31i: m_arg[0] = literal & 0xffff; m_arg[1] = literal >> 16; return this; case FMT_f51l: m_arg[0] = literal; m_arg[1] = literal >> 16; m_arg[2] = literal >> 32; m_arg[3] = literal >> 48; return this; default: assert(false); } not_reached(); }
int64_t DexInstruction::literal() const { assert(has_literal()); auto format = opcode_format(opcode()); switch (format) { case FMT_f11n: return signext<4>(m_opcode >> 12); case FMT_f21s: return signext<16>(m_arg[0]); case FMT_f21h: return signext<16>(m_arg[0]) << 16; case FMT_f22b: return signext<16>(m_arg[0]) << 48; case FMT_f22s: return signext<16>(m_arg[0]); case FMT_f31i: { auto literal = uint32_t(m_arg[0]) | (uint32_t(m_arg[1]) << 16); return signext<32>(literal); } case FMT_f51l: { auto literal = uint64_t(m_arg[0]) | (uint64_t(m_arg[1]) << 16) | (uint64_t(m_arg[2]) << 32) | (uint64_t(m_arg[3]) << 48); return signext<64>(literal); } default: assert(false); } not_reached(); }
DexInstruction* DexInstruction::set_offset(int32_t offset) { auto format = opcode_format(opcode()); switch (format) { case FMT_f10t: always_assert_log((int32_t)(int8_t)(offset & 0xff) == offset, "offset %d too large for %s", offset, SHOW(this)); m_opcode = (m_opcode & 0xff) | ((offset & 0xff) << 8); return this; case FMT_f20t: case FMT_f21t: case FMT_f22t: always_assert_log((int32_t)(int16_t)(offset & 0xffff) == offset, "offset %d too large for %s", offset, SHOW(this)); m_arg[0] = offset; return this; case FMT_f30t: case FMT_f31t: m_arg[0] = offset; m_arg[1] = offset >> 16; return this; default: assert(false); } not_reached(); }
uint16_t DexInstruction::range_base() const { auto format = opcode_format(opcode()); assert(format == FMT_f3rc || format == FMT_f5rc); if (format == FMT_f5rc) return m_arg[1]; return m_arg[0]; }
DexOpcode* DexOpcode::set_arg_word_count(uint16_t count) { auto DEBUG_ONLY format = opcode_format(opcode()); assert(format == FMT_f35c); assert((count & 0xf) == count); m_opcode = (m_opcode & 0x0fff) | (count << 12); return this; }
uint16_t DexInstruction::range_size() const { auto format = opcode_format(opcode()); assert(format == FMT_f3rc || format == FMT_f5rc); if (format == FMT_f5rc) return m_arg[0]; return (m_opcode >> 8) & 0xff; }
uint16_t DexInstruction::dest() const { auto format = opcode_format(opcode()); switch (format) { case FMT_f12x: case FMT_f12x_2: case FMT_f11n: case FMT_f22s: case FMT_f22c_d: case FMT_f22cs: return (m_opcode >> 8) & 0xf; case FMT_f11x_d: case FMT_f22x: case FMT_f21s: case FMT_f21h: case FMT_f21c_d: case FMT_f23x_d: case FMT_f22b: case FMT_f31i: case FMT_f31c: case FMT_f51l: return (m_opcode >> 8) & 0xff; case FMT_f32x: return m_arg[0]; case FMT_f41c_d: case FMT_f52c_d: return m_arg[0]; default: // All other formats do not define a destination register. always_assert_log(false, "Unhandled opcode: %s", SHOW(this)); } not_reached(); }
DexOpcode* DexOpcode::set_dest(uint16_t vreg) { auto format = opcode_format(opcode()); switch (format) { case FMT_f12x: case FMT_f12x_2: case FMT_f11n: case FMT_f22s: case FMT_f22c_d: case FMT_f22cs: assert((vreg & 0xf) == vreg); m_opcode = (m_opcode & 0xf0ff) | (vreg << 8); return this; case FMT_f11x_d: case FMT_f22x: case FMT_f21s: case FMT_f21h: case FMT_f21c_d: case FMT_f23x_d: case FMT_f22b: case FMT_f31i: case FMT_f31c: case FMT_f51l: assert((vreg & 0xff) == vreg); m_opcode = (m_opcode & 0x00ff) | (vreg << 8); return this; case FMT_f32x: m_arg[0] = vreg; return this; default: // All other formats do not define a destination register. always_assert_log(false, "Unhandled opcode: %s", SHOW(this)); } not_reached(); }
uint16_t DexInstruction::arg_word_count() const { auto format = opcode_format(opcode()); assert(format == FMT_f35c || format == FMT_f57c); if (format == FMT_f57c) { return (m_arg[0]) & 0xf; } return (m_opcode >> 12) & 0xf; }
DexInstruction* DexInstruction::set_range_base(uint16_t base) { auto format = opcode_format(opcode()); assert(format == FMT_f3rc || format == FMT_f5rc); if (format == FMT_f5rc) { m_arg[1] = base; } else { m_arg[0] = base; } return this; }
unsigned DexInstruction::srcs_size() const { auto format = opcode_format(opcode()); switch (format) { case FMT_f00x: case FMT_f10x: case FMT_f11n: case FMT_f11x_d: case FMT_f10t: case FMT_f20t: case FMT_f21s: case FMT_f21h: case FMT_f21c_d: case FMT_f30t: case FMT_f31i: case FMT_f31c: case FMT_f51l: case FMT_f41c_d: case FMT_fopcode: return 0; case FMT_f12x: case FMT_f11x_s: case FMT_f22x: case FMT_f21t: case FMT_f21c_s: case FMT_f22b: case FMT_f22s: case FMT_f22c_d: case FMT_f32x: case FMT_f31t: case FMT_f3rc: case FMT_f41c_s: case FMT_f52c_d: case FMT_f5rc: return 1; case FMT_f12x_2: case FMT_f23x_d: case FMT_f22t: case FMT_f22c_s: case FMT_f52c_s: return 2; case FMT_f23x_s: return 3; case FMT_f35c: case FMT_f57c: return arg_word_count(); case FMT_f20bc: case FMT_f22cs: case FMT_f35ms: case FMT_f35mi: case FMT_f3rms: case FMT_f3rmi: always_assert_log(false, "Unimplemented opcode `%s'", SHOW(this)); } not_reached(); }
DexInstruction* DexInstruction::set_arg_word_count(uint16_t count) { auto format = opcode_format(opcode()); assert(format == FMT_f35c || format == FMT_f57c); assert((count & 0xf) == count); if (format == FMT_f57c) { m_arg[0] = (m_arg[0] & 0xfff0) | count; } else { m_opcode = (m_opcode & 0x0fff) | (count << 12); } return this; }
DexInstruction* DexInstruction::set_range_size(uint16_t size) { auto format = opcode_format(opcode()); assert(format == FMT_f3rc || format == FMT_f5rc); if (format == FMT_f5rc) { m_arg[0] = size; } else { assert(size == (size & 0xff)); m_opcode = (m_opcode & 0xff) | (size << 8); } return this; }
int DexInstruction::src_bit_width(int i) const { switch (opcode_format(opcode())) { case FMT_f00x: assert(false); case FMT_f10x: assert(false); case FMT_f12x: assert(i == 0); return 4; case FMT_f12x_2: assert(i <= 1); return 4; case FMT_f11n: assert(false); case FMT_f11x_d: assert(false); case FMT_f11x_s: assert(i == 0); return 8; case FMT_f10t: assert(false); case FMT_f20t: assert(false); case FMT_f20bc: assert(false); case FMT_f22x: assert(i == 0); return 16; case FMT_f21t: assert(i == 0); return 8; case FMT_f21s: assert(false); case FMT_f21h: assert(false); case FMT_f21c_d: assert(false); case FMT_f21c_s: assert(i == 0); return 8; case FMT_f23x_d: assert(i <= 1); return 8; case FMT_f23x_s: assert(i <= 2); return 8; case FMT_f22b: assert(i == 0); return 8; case FMT_f22t: assert(i <= 1); return 4; case FMT_f22s: assert(i == 0); return 4; case FMT_f22c_d: assert(i == 0); return 4; case FMT_f22c_s: assert(i <= 1); return 4; case FMT_f22cs: assert(false); case FMT_f30t: assert(false); case FMT_f32x: assert(i == 0); return 16; case FMT_f31i: assert(false); case FMT_f31t: assert(i == 0); return 8; case FMT_f31c: assert(false); case FMT_f35c: assert(i <= 4); return 4; case FMT_f3rc: assert(i == 0); return 16; case FMT_f41c_d: assert(false); case FMT_f41c_s: assert(i == 0); return 16; case FMT_f52c_d: assert(i == 0); return 16; case FMT_f52c_s: assert(i <= 1); return 16; case FMT_f5rc: assert(i == 0); return 16; case FMT_f57c: assert(i <= 6); return 4; case FMT_f35ms: case FMT_f35mi: case FMT_f3rms: case FMT_f3rmi: case FMT_f51l: case FMT_fopcode: default: assert(false); } not_reached(); }
int DexInstruction::dest_bit_width() const { switch (opcode_format(opcode())) { case FMT_f00x: assert(false); case FMT_f10x: assert(false); case FMT_f12x: return 4; case FMT_f12x_2: return 4; case FMT_f11n: return 4; case FMT_f11x_d: return 8; case FMT_f11x_s: assert(false); case FMT_f10t: assert(false); case FMT_f20t: assert(false); case FMT_f20bc: assert(false); case FMT_f22x: return 8; case FMT_f21t: assert(false); case FMT_f21s: return 8; case FMT_f21h: return 8; case FMT_f21c_d: return 8; case FMT_f21c_s: assert(false); case FMT_f23x_d: return 8; case FMT_f23x_s: assert(false); case FMT_f22b: return 8; case FMT_f22t: assert(false); case FMT_f22s: return 4; case FMT_f22c_d: return 4; case FMT_f22c_s: assert(false); case FMT_f22cs: assert(false); case FMT_f30t: assert(false); case FMT_f32x: return 16; case FMT_f31i: return 8; case FMT_f31t: assert(false); case FMT_f31c: return 8; case FMT_f35c: assert(false); case FMT_f35ms: case FMT_f35mi: case FMT_f3rc: case FMT_f3rms: case FMT_f3rmi: assert(false); case FMT_f51l: return 8; case FMT_f41c_d: return 16; case FMT_f41c_s: assert(false); case FMT_f52c_d: return 16; case FMT_f52c_s: assert(false); case FMT_f5rc: assert(false); case FMT_f57c: assert(false); case FMT_fopcode: default: assert(false); } not_reached(); }
bool DexInstruction::has_offset() const { auto format = opcode_format(opcode()); switch (format) { case FMT_f10t: case FMT_f20t: case FMT_f21t: case FMT_f22t: case FMT_f30t: case FMT_f31t: return true; default: return false; } not_reached(); }
unsigned DexInstruction::count_from_opcode() const { static int args[] = { 0, /* FMT_f00x */ 0, /* FMT_f10x */ 0, /* FMT_f12x */ 0, /* FMT_f12x_2 */ 0, /* FMT_f11n */ 0, /* FMT_f11x_d */ 0, /* FMT_f11x_s */ 0, /* FMT_f10t */ 1, /* FMT_f20t */ 0, /* FMT_f20bc */ 1, /* FMT_f22x */ 1, /* FMT_f21t */ 1, /* FMT_f21s */ 1, /* FMT_f21h */ 0, /* FMT_f21c_d */ 0, /* FMT_f21c_s */ 1, /* FMT_f23x_d */ 1, /* FMT_f23x_s */ 1, /* FMT_f22b */ 1, /* FMT_f22t */ 1, /* FMT_f22s */ 0, /* FMT_f22c_d */ 0, /* FMT_f22c_s */ 0, /* FMT_f22cs */ 2, /* FMT_f30t */ 2, /* FMT_f32x */ 2, /* FMT_f31i */ 2, /* FMT_f31t */ 1, /* FMT_f31c */ 1, /* FMT_f35c */ 2, /* FMT_f35ms */ 2, /* FMT_f35mi */ 1, /* FMT_f3rc */ 2, /* FMT_f3rms */ 2, /* FMT_f3rmi */ 4, /* FMT_f51l */ 1, /* FMT_f41c_d */ 1, /* FMT_f41c_s */ 2, /* FMT_f52c_d */ 2, /* FMT_f52c_s */ 2, /* FMT_f5rc */ 2, /* FMT_f57c */ 0, /* FMT_fopcode */ }; return args[opcode_format(opcode())]; };
bool DexInstruction::has_literal() const { auto format = opcode_format(opcode()); switch (format) { case FMT_f11n: case FMT_f21s: case FMT_f21h: case FMT_f22b: case FMT_f22s: case FMT_f31i: case FMT_f51l: return true; default: return false; } not_reached(); }
unsigned DexOpcode::dests_size() const { auto format = opcode_format(opcode()); switch (format) { case FMT_f00x: case FMT_f10x: case FMT_f11x_s: case FMT_f10t: case FMT_f20t: case FMT_f21t: case FMT_f21c_s: case FMT_f23x_s: case FMT_f22t: case FMT_f22c_s: case FMT_f30t: case FMT_f31t: case FMT_f35c: case FMT_f3rc: case FMT_fopcode: return 0; case FMT_f12x: case FMT_f12x_2: case FMT_f11n: case FMT_f11x_d: case FMT_f22x: case FMT_f21s: case FMT_f21h: case FMT_f21c_d: case FMT_f23x_d: case FMT_f22b: case FMT_f22s: case FMT_f22c_d: case FMT_f32x: case FMT_f31i: case FMT_f31c: case FMT_f51l: return 1; case FMT_f20bc: case FMT_f22cs: case FMT_f35ms: case FMT_f35mi: case FMT_f3rms: case FMT_f3rmi: always_assert_log(false, "Unimplemented opcode `%s'", SHOW(this)); } not_reached(); }
int32_t DexInstruction::offset() const { auto format = opcode_format(opcode()); switch (format) { case FMT_f10t: return (int32_t) signext<8>(m_opcode >> 8); case FMT_f20t: case FMT_f21t: case FMT_f22t: return (int32_t) signext<16>(m_arg[0]); case FMT_f30t: case FMT_f31t: { auto offset = uint32_t(m_arg[0]) | (uint32_t(m_arg[1]) << 16); return (int32_t) signext<32>(offset); } default: assert(false); } not_reached(); }
DexInstruction* DexInstruction::set_src(int i, uint16_t vreg) { auto format = opcode_format(opcode()); switch (format) { case FMT_f11x_s: case FMT_f21t: case FMT_f21c_s: case FMT_f31t: assert(i == 0); assert((vreg & 0xff) == vreg); m_opcode = (m_opcode & 0x00ff) | (vreg << 8); return this; case FMT_f12x: case FMT_f22s: case FMT_f22c_d: assert(i == 0); assert((vreg & 0xf) == vreg); m_opcode = (m_opcode & 0x0fff) | (vreg << 12); return this; case FMT_f12x_2: assert(i < 2); assert((vreg & 0xf) == vreg); if (i == 0) { m_opcode = (m_opcode & 0xf0ff) | (vreg << 8); } else { m_opcode = (m_opcode & 0x0fff) | (vreg << 12); } return this; case FMT_f22x: case FMT_f3rc: assert(i == 0); m_arg[0] = vreg; return this; case FMT_f23x_d: assert(i < 2); assert((vreg & 0xff) == vreg); if (i == 0) { m_arg[0] = (m_arg[0] & 0xff00) | vreg; return this; } m_arg[0] = (m_arg[0] & 0x00ff) | (vreg << 8); return this; case FMT_f23x_s: assert(i < 3); assert((vreg & 0xff) == vreg); if (i == 0) { m_opcode = (m_opcode & 0x00ff) | (vreg << 8); } else if (i == 1) { m_arg[0] = (m_arg[0] & 0xff00) | vreg; } else { m_arg[0] = (m_arg[0] & 0x00ff) | (vreg << 8); } return this; case FMT_f22b: assert(i == 0); m_arg[0] = (m_arg[0] & 0xff00) | vreg; return this; case FMT_f22t: case FMT_f22c_s: assert(i < 2); assert((vreg & 0xf) == vreg); if (i == 0) { m_opcode = (m_opcode & 0xf0ff) | (vreg << 8); } else { m_opcode = (m_opcode & 0x0fff) | (vreg << 12); } return this; case FMT_f32x: assert(i == 0); m_arg[1] = vreg; return this; case FMT_f35c: assert(i < 5); assert((vreg & 0xf) == vreg); switch (i) { case 0: m_arg[0] = (m_arg[0] & 0xfff0) | vreg; return this; case 1: m_arg[0] = (m_arg[0] & 0xff0f) | (vreg << 4); return this; case 2: m_arg[0] = (m_arg[0] & 0xf0ff) | (vreg << 8); return this; case 3: m_arg[0] = (m_arg[0] & 0x0fff) | (vreg << 12); return this; case 4: m_opcode = (m_opcode & 0xf0ff) | (vreg << 8); return this; } case FMT_f41c_s: assert(i == 0); m_arg[0] = vreg; return this; case FMT_f52c_d: assert(i == 0); m_arg[1] = vreg; return this; case FMT_f52c_s: assert(i <= 1); m_arg[i] = vreg; return this; case FMT_f5rc: assert(i == 0); m_arg[1] = vreg; return this; case FMT_f57c: assert(i <= 6); assert((vreg & 0xf) == vreg); switch (i) { case 0: m_arg[0] = (m_arg[0] & 0xff0f) | (vreg << 4); return this; case 1: m_arg[0] = (m_arg[0] & 0xf0ff) | (vreg << 8); return this; case 2: m_arg[0] = (m_arg[0] & 0x0fff) | (vreg << 12); return this; case 3: m_arg[1] = (m_arg[1] & 0xfff0) | vreg; return this; case 4: m_arg[0] = (m_arg[1] & 0xff0f) | (vreg << 4); return this; case 5: m_arg[0] = (m_arg[1] & 0xf0ff) | (vreg << 8); return this; case 6: m_arg[0] = (m_arg[1] & 0x0fff) | (vreg << 12); return this; } default: // All other formats do not define source registers. always_assert_log(false, "Unhandled opcode: %s", SHOW(this)); } not_reached(); }
DexOpcode* DexOpcode::set_range_base(uint16_t base) { assert(opcode_format(opcode()) == FMT_f3rc); m_arg[0] = base; return this; }
bool DexInstruction::has_arg_word_count() const { auto format = opcode_format(opcode()); if(format == FMT_f35c || format == FMT_f57c) return true; return false; }
uint16_t DexInstruction::src(int i) const { auto format = opcode_format(opcode()); switch (format) { case FMT_f11x_s: case FMT_f21t: case FMT_f21c_s: case FMT_f31t: assert(i == 0); return (m_opcode >> 8) & 0xff; case FMT_f12x: case FMT_f22s: case FMT_f22c_d: assert(i == 0); return (m_opcode >> 12) & 0xf; case FMT_f12x_2: assert(i < 2); if (i == 0) return (m_opcode >> 8) & 0xf; return (m_opcode >> 12) & 0xf; case FMT_f22x: case FMT_f3rc: assert(i == 0); return m_arg[0]; case FMT_f23x_d: assert(i < 2); if (i == 0) return m_arg[0] & 0xff; return (m_arg[0] >> 8) & 0xff; case FMT_f23x_s: assert(i < 3); if (i == 0) return (m_opcode >> 8) & 0xff; if (i == 1) return m_arg[0] & 0xff; return (m_arg[0] >> 8) & 0xff; case FMT_f22b: assert(i == 0); return m_arg[0] & 0xff; case FMT_f22t: case FMT_f22c_s: assert(i < 2); if (i == 0) return (m_opcode >> 8) & 0xf; if (i == 1) return (m_opcode >> 12) & 0xf; case FMT_f32x: assert(i == 0); return m_arg[1]; case FMT_f35c: assert(i < 5); switch (i) { case 0: return m_arg[0] & 0xf; case 1: return (m_arg[0] >> 4) & 0xf; case 2: return (m_arg[0] >> 8) & 0xf; case 3: return (m_arg[0] >> 12) & 0xf; case 4: return (m_opcode >> 8) & 0xf; } case FMT_f41c_s: assert(i == 0); return m_arg[0]; case FMT_f52c_d: assert(i == 0); return m_arg[1]; case FMT_f52c_s: assert(i <= 1); return m_arg[i]; case FMT_f5rc: assert(i == 0); return m_arg[1]; case FMT_f57c: assert(i <= 6); switch(i) { case 0: return (m_arg[0] >> 4) & 0xf; case 1: return (m_arg[0] >> 8) & 0xf; case 2: return (m_arg[0] >> 12) & 0xf; case 3: return m_arg[1] & 0xf; case 4: return (m_arg[1] >> 4) & 0xf; case 5: return (m_arg[1] >> 8) & 0xf; case 6: return (m_arg[1] >> 12) & 0xf; } default: // All other formats do not define source registers. always_assert_log(false, "Unhandled opcode: %s", SHOW(this)); } not_reached(); }
DexOpcode* DexOpcode::set_range_size(uint16_t size) { assert(opcode_format(opcode()) == FMT_f3rc); assert(size == (size & 0xff)); m_opcode = (m_opcode & 0xff) | (size << 8); return this; }
bool DexOpcode::has_arg_word_count() const { return opcode_format(opcode()) == FMT_f35c; }
uint16_t DexOpcode::arg_word_count() const { auto DEBUG_ONLY format = opcode_format(opcode()); assert(format == FMT_f35c); return (m_opcode >> 12) & 0xf; }
bool DexInstruction::has_range_size() const { auto format = opcode_format(opcode()); if (format == FMT_f3rc || format == FMT_f5rc) return true; return false; }
uint16_t DexOpcode::range_size() const { assert(opcode_format(opcode()) == FMT_f3rc); return (m_opcode >> 8) & 0xff; }
bool DexInstruction::dest_is_src() const { auto format = opcode_format(opcode()); return format == FMT_f12x_2; }