diff options
author | 2016-08-03 12:46:23 +0100 | |
---|---|---|
committer | 2016-08-10 14:00:16 +0100 | |
commit | 8ec3bd2b31ccbc9027b8e9b1949dd1804bb6d30f (patch) | |
tree | 6cc457a060c7faade49229010bfe3119e55b254d | |
parent | c218427ab96e521e0c4e9a3ffeb87e6c57eea0a5 (diff) |
Instruction: Add new formats 45cc and 4rcc.
These are new 4 byte formats with the following properties.
- The first three (16 bit) words of these instructions have the same
format as 35c and 3rc respectively.
- The fourth 16 bit word encodes an additional constant index reference.
This change includes placeholder opcodes for invoke-polymorphic and
invoke-polymorphic/range which will be the first dex instructions that
use this new format. In addition to a method_idx that gives the invoked
method, these instructions also provide a proto_idx which gives the
(static) type signature of the call site.
The only reason these are included in this change is because we need
an instruction with a given format to write a unit_test using the Instruction
API.
bug: 30550796
test: make test-art-host
Change-Id: I02612ddee47169757175a8079d82f811f6545945
-rw-r--r-- | runtime/dex_instruction-inl.h | 75 | ||||
-rw-r--r-- | runtime/dex_instruction.cc | 11 | ||||
-rw-r--r-- | runtime/dex_instruction.h | 34 | ||||
-rw-r--r-- | runtime/dex_instruction_list.h | 5 | ||||
-rw-r--r-- | runtime/dex_instruction_test.cc | 92 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_switch_impl.cc | 5 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.cc | 5 |
7 files changed, 217 insertions, 10 deletions
diff --git a/runtime/dex_instruction-inl.h b/runtime/dex_instruction-inl.h index dd65f2c0c6..3d0fea07ad 100644 --- a/runtime/dex_instruction-inl.h +++ b/runtime/dex_instruction-inl.h @@ -49,6 +49,8 @@ inline bool Instruction::HasVRegA() const { case k32x: return true; case k35c: return true; case k3rc: return true; + case k45cc: return true; + case k4rcc: return true; case k51l: return true; default: return false; } @@ -79,6 +81,8 @@ inline int32_t Instruction::VRegA() const { case k32x: return VRegA_32x(); case k35c: return VRegA_35c(); case k3rc: return VRegA_3rc(); + case k45cc: return VRegA_45cc(); + case k4rcc: return VRegA_4rcc(); case k51l: return VRegA_51l(); default: LOG(FATAL) << "Tried to access vA of instruction " << Name() << " which has no A operand."; @@ -206,6 +210,16 @@ inline uint8_t Instruction::VRegA_51l(uint16_t inst_data) const { return InstAA(inst_data); } +inline uint4_t Instruction::VRegA_45cc(uint16_t inst_data) const { + DCHECK_EQ(FormatOf(Opcode()), k45cc); + return InstB(inst_data); // This is labeled A in the spec. +} + +inline uint8_t Instruction::VRegA_4rcc(uint16_t inst_data) const { + DCHECK_EQ(FormatOf(Opcode()), k4rcc); + return InstAA(inst_data); +} + //------------------------------------------------------------------------------ // VRegB //------------------------------------------------------------------------------ @@ -229,6 +243,8 @@ inline bool Instruction::HasVRegB() const { case k32x: return true; case k35c: return true; case k3rc: return true; + case k45cc: return true; + case k4rcc: return true; case k51l: return true; default: return false; } @@ -258,6 +274,8 @@ inline int32_t Instruction::VRegB() const { case k32x: return VRegB_32x(); case k35c: return VRegB_35c(); case k3rc: return VRegB_3rc(); + case k45cc: return VRegB_45cc(); + case k4rcc: return VRegB_4rcc(); case k51l: return VRegB_51l(); default: LOG(FATAL) << "Tried to access vB of instruction " << Name() << " which has no B operand."; @@ -359,6 +377,16 @@ inline uint16_t Instruction::VRegB_3rc() const { return Fetch16(1); } +inline uint16_t Instruction::VRegB_45cc() const { + DCHECK_EQ(FormatOf(Opcode()), k45cc); + return Fetch16(1); +} + +inline uint16_t Instruction::VRegB_4rcc() const { + DCHECK_EQ(FormatOf(Opcode()), k4rcc); + return Fetch16(1); +} + inline uint64_t Instruction::VRegB_51l() const { DCHECK_EQ(FormatOf(Opcode()), k51l); uint64_t vB_wide = Fetch32(1) | ((uint64_t) Fetch32(3) << 32); @@ -377,6 +405,8 @@ inline bool Instruction::HasVRegC() const { case k23x: return true; case k35c: return true; case k3rc: return true; + case k45cc: return true; + case k4rcc: return true; default: return false; } } @@ -390,6 +420,8 @@ inline int32_t Instruction::VRegC() const { case k23x: return VRegC_23x(); case k35c: return VRegC_35c(); case k3rc: return VRegC_3rc(); + case k45cc: return VRegC_45cc(); + case k4rcc: return VRegC_4rcc(); default: LOG(FATAL) << "Tried to access vC of instruction " << Name() << " which has no C operand."; exit(EXIT_FAILURE); @@ -431,11 +463,52 @@ inline uint16_t Instruction::VRegC_3rc() const { return Fetch16(2); } +inline uint4_t Instruction::VRegC_45cc() const { + DCHECK_EQ(FormatOf(Opcode()), k45cc); + return static_cast<uint4_t>(Fetch16(2) & 0x0f); +} + +inline uint16_t Instruction::VRegC_4rcc() const { + DCHECK_EQ(FormatOf(Opcode()), k4rcc); + return Fetch16(2); +} + +//------------------------------------------------------------------------------ +// VRegH +//------------------------------------------------------------------------------ +inline bool Instruction::HasVRegH() const { + switch (FormatOf(Opcode())) { + case k45cc: return true; + case k4rcc: return true; + default : return false; + } +} + +inline int32_t Instruction::VRegH() const { + switch (FormatOf(Opcode())) { + case k45cc: return VRegH_45cc(); + case k4rcc: return VRegH_4rcc(); + default : + LOG(FATAL) << "Tried to access vH of instruction " << Name() << " which has no H operand."; + exit(EXIT_FAILURE); + } +} + +inline uint16_t Instruction::VRegH_45cc() const { + DCHECK_EQ(FormatOf(Opcode()), k45cc); + return Fetch16(3); +} + +inline uint16_t Instruction::VRegH_4rcc() const { + DCHECK_EQ(FormatOf(Opcode()), k4rcc); + return Fetch16(3); +} + inline bool Instruction::HasVarArgs() const { return FormatOf(Opcode()) == k35c; } -inline void Instruction::GetVarArgs(uint32_t arg[5], uint16_t inst_data) const { +inline void Instruction::GetVarArgs(uint32_t arg[kMaxVarArgRegs], uint16_t inst_data) const { DCHECK_EQ(FormatOf(Opcode()), k35c); /* diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc index fabc47b5c9..c31d236dc7 100644 --- a/runtime/dex_instruction.cc +++ b/runtime/dex_instruction.cc @@ -69,11 +69,12 @@ int const Instruction::kInstructionVerifyFlags[] = { int const Instruction::kInstructionSizeInCodeUnits[] = { #define INSTRUCTION_SIZE(opcode, c, p, format, i, a, v) \ - (((opcode) == NOP) ? -1 : \ - (((format) >= k10x) && ((format) <= k10t)) ? 1 : \ - (((format) >= k20t) && ((format) <= k22c)) ? 2 : \ - (((format) >= k32x) && ((format) <= k3rc)) ? 3 : \ - ((format) == k51l) ? 5 : -1), + (((opcode) == NOP) ? -1 : \ + (((format) >= k10x) && ((format) <= k10t)) ? 1 : \ + (((format) >= k20t) && ((format) <= k22c)) ? 2 : \ + (((format) >= k32x) && ((format) <= k3rc)) ? 3 : \ + (((format) >= k45cc) && ((format) <= k4rcc)) ? 4 : \ + ((format) == k51l) ? 5 : -1), #include "dex_instruction_list.h" DEX_INSTRUCTION_LIST(INSTRUCTION_SIZE) #undef DEX_INSTRUCTION_LIST diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h index 1ac0f11886..f437fdef1c 100644 --- a/runtime/dex_instruction.h +++ b/runtime/dex_instruction.h @@ -112,6 +112,15 @@ class Instruction { k31c, // op vAA, thing@BBBBBBBB k35c, // op {vC, vD, vE, vF, vG}, thing@BBBB (B: count, A: vG) k3rc, // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB + + // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH (A: count) + // format: AG op BBBB FEDC HHHH + k45cc, + + // op {VCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH (AA: count) + // format: AA op BBBB CCCC HHHH + k4rcc, // op {VCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH (AA: count) + k51l, // op vAA, #+BBBBBBBBBBBBBBBB }; @@ -227,6 +236,12 @@ class Instruction { return RelativeAt(3); } + // Returns a pointer to the instruction after this 4xx instruction in the stream. + const Instruction* Next_4xx() const { + DCHECK(FormatOf(Opcode()) >= k45cc && FormatOf(Opcode()) <= k4rcc); + return RelativeAt(4); + } + // Returns a pointer to the instruction after this 51l instruction in the stream. const Instruction* Next_51l() const { DCHECK(FormatOf(Opcode()) == k51l); @@ -313,6 +328,12 @@ class Instruction { uint8_t VRegA_51l() const { return VRegA_51l(Fetch16(0)); } + uint4_t VRegA_45cc() const { + return VRegA_45cc(Fetch16(0)); + } + uint8_t VRegA_4rcc() const { + return VRegA_4rcc(Fetch16(0)); + } // The following methods return the vA operand for various instruction formats. The "inst_data" // parameter holds the first 16 bits of instruction which the returned value is decoded from. @@ -337,6 +358,8 @@ class Instruction { uint4_t VRegA_35c(uint16_t inst_data) const; uint8_t VRegA_3rc(uint16_t inst_data) const; uint8_t VRegA_51l(uint16_t inst_data) const; + uint4_t VRegA_45cc(uint16_t inst_data) const; + uint8_t VRegA_4rcc(uint16_t inst_data) const; // VRegB bool HasVRegB() const; @@ -374,6 +397,8 @@ class Instruction { uint16_t VRegB_35c() const; uint16_t VRegB_3rc() const; uint64_t VRegB_51l() const; // vB_wide + uint16_t VRegB_45cc() const; + uint16_t VRegB_4rcc() const; // The following methods return the vB operand for all instruction formats where it is encoded in // the first 16 bits of instruction. The "inst_data" parameter holds these 16 bits. The returned @@ -395,6 +420,15 @@ class Instruction { uint8_t VRegC_23x() const; uint4_t VRegC_35c() const; uint16_t VRegC_3rc() const; + uint4_t VRegC_45cc() const; + uint16_t VRegC_4rcc() const; + + + // VRegH + bool HasVRegH() const; + int32_t VRegH() const; + uint16_t VRegH_45cc() const; + uint16_t VRegH_4rcc() const; // Fills the given array with the 'arg' array of the instruction. bool HasVarArgs() const; diff --git a/runtime/dex_instruction_list.h b/runtime/dex_instruction_list.h index 40ea285fe5..e9749324c0 100644 --- a/runtime/dex_instruction_list.h +++ b/runtime/dex_instruction_list.h @@ -269,8 +269,9 @@ V(0xF7, UNUSED_F7, "unused-f7", k10x, kIndexUnknown, 0, kVerifyError) \ V(0xF8, UNUSED_F8, "unused-f8", k10x, kIndexUnknown, 0, kVerifyError) \ V(0xF9, UNUSED_F9, "unused-f9", k10x, kIndexUnknown, 0, kVerifyError) \ - V(0xFA, UNUSED_FA, "unused-fa", k10x, kIndexUnknown, 0, kVerifyError) \ - V(0xFB, UNUSED_FB, "unused-fb", k10x, kIndexUnknown, 0, kVerifyError) \ + /* TODO(narayan): The following two entries are placeholders. */ \ + V(0xFA, INVOKE_POLYMORPHIC, "invoke-polymorphic", k45cc, kIndexUnknown, 0, kVerifyError) \ + V(0xFB, INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range", k4rcc, kIndexUnknown, 0, kVerifyError) \ V(0xFC, UNUSED_FC, "unused-fc", k10x, kIndexUnknown, 0, kVerifyError) \ V(0xFD, UNUSED_FD, "unused-fd", k10x, kIndexUnknown, 0, kVerifyError) \ V(0xFE, UNUSED_FE, "unused-fe", k10x, kIndexUnknown, 0, kVerifyError) \ diff --git a/runtime/dex_instruction_test.cc b/runtime/dex_instruction_test.cc index 671ac0e52b..00c8e07a72 100644 --- a/runtime/dex_instruction_test.cc +++ b/runtime/dex_instruction_test.cc @@ -28,4 +28,96 @@ TEST(StaticGetters, PropertiesOfNopTest) { EXPECT_EQ(Instruction::kVerifyNone, Instruction::VerifyFlagsOf(nop)); } +static void Build45cc(uint8_t num_args, uint16_t method_idx, uint16_t proto_idx, + uint16_t arg_regs, uint16_t* out) { + // A = num argument registers + // B = method_idx + // C - G = argument registers + // H = proto_idx + // + // op = 0xFA + // + // format: + // AG op BBBB FEDC HHHH + out[0] = 0; + out[0] |= (num_args << 12); + out[0] |= 0x00FA; + + out[1] = method_idx; + out[2] = arg_regs; + out[3] = proto_idx; +} + +static void Build4rcc(uint16_t num_args, uint16_t method_idx, uint16_t proto_idx, + uint16_t arg_regs_start, uint16_t* out) { + // A = num argument registers + // B = method_idx + // C = first argument register + // H = proto_idx + // + // op = 0xFB + // + // format: + // AA op BBBB CCCC HHHH + out[0] = 0; + out[0] |= (num_args << 8); + out[0] |= 0x00FB; + + out[1] = method_idx; + out[2] = arg_regs_start; + out[3] = proto_idx; +} + +TEST(Instruction, PropertiesOf45cc) { + uint16_t instruction[4]; + Build45cc(4u /* num_vregs */, 16u /* method_idx */, 32u /* proto_idx */, + 0xcafe /* arg_regs */, instruction); + + const Instruction* ins = Instruction::At(instruction); + ASSERT_EQ(4u, ins->SizeInCodeUnits()); + + ASSERT_TRUE(ins->HasVRegA()); + ASSERT_EQ(4, ins->VRegA()); + ASSERT_EQ(4u, ins->VRegA_45cc()); + ASSERT_EQ(4u, ins->VRegA_45cc(instruction[0])); + + ASSERT_TRUE(ins->HasVRegB()); + ASSERT_EQ(16, ins->VRegB()); + ASSERT_EQ(16u, ins->VRegB_45cc()); + + ASSERT_TRUE(ins->HasVRegC()); + ASSERT_EQ(0xe, ins->VRegC()); + ASSERT_EQ(0xe, ins->VRegC_45cc()); + + ASSERT_TRUE(ins->HasVRegH()); + ASSERT_EQ(32, ins->VRegH()); + ASSERT_EQ(32, ins->VRegH_45cc()); +} + +TEST(Instruction, PropertiesOf4rcc) { + uint16_t instruction[4]; + Build4rcc(4u /* num_vregs */, 16u /* method_idx */, 32u /* proto_idx */, + 0xcafe /* arg_regs */, instruction); + + const Instruction* ins = Instruction::At(instruction); + ASSERT_EQ(4u, ins->SizeInCodeUnits()); + + ASSERT_TRUE(ins->HasVRegA()); + ASSERT_EQ(4, ins->VRegA()); + ASSERT_EQ(4u, ins->VRegA_4rcc()); + ASSERT_EQ(4u, ins->VRegA_4rcc(instruction[0])); + + ASSERT_TRUE(ins->HasVRegB()); + ASSERT_EQ(16, ins->VRegB()); + ASSERT_EQ(16u, ins->VRegB_4rcc()); + + ASSERT_TRUE(ins->HasVRegC()); + ASSERT_EQ(0xcafe, ins->VRegC()); + ASSERT_EQ(0xcafe, ins->VRegC_4rcc()); + + ASSERT_TRUE(ins->HasVRegH()); + ASSERT_EQ(32, ins->VRegH()); + ASSERT_EQ(32, ins->VRegH_4rcc()); +} + } // namespace art diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index 3623db2a35..a6349fcf88 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -2322,9 +2322,12 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, inst = inst->Next_2xx(); break; case Instruction::UNUSED_3E ... Instruction::UNUSED_43: - case Instruction::UNUSED_F3 ... Instruction::UNUSED_FF: + case Instruction::UNUSED_F3 ... Instruction::UNUSED_F9: + case Instruction::UNUSED_FC ... Instruction::UNUSED_FF: case Instruction::UNUSED_79: case Instruction::UNUSED_7A: + case Instruction::INVOKE_POLYMORPHIC: + case Instruction::INVOKE_POLYMORPHIC_RANGE: UnexpectedOpcode(inst, shadow_frame); } } while (!interpret_one_instruction); diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index daf5ec4292..40f12e9178 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -3331,9 +3331,12 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { /* These should never appear during verification. */ case Instruction::UNUSED_3E ... Instruction::UNUSED_43: - case Instruction::UNUSED_F3 ... Instruction::UNUSED_FF: + case Instruction::UNUSED_F3 ... Instruction::UNUSED_F9: + case Instruction::UNUSED_FC ... Instruction::UNUSED_FF: case Instruction::UNUSED_79: case Instruction::UNUSED_7A: + case Instruction::INVOKE_POLYMORPHIC: + case Instruction::INVOKE_POLYMORPHIC_RANGE: Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Unexpected opcode " << inst->DumpString(dex_file_); break; |