diff options
author | 2019-05-31 20:01:46 +0100 | |
---|---|---|
committer | 2019-06-07 17:01:44 +0000 | |
commit | 8867f3b017546ff187a99ac57bc91ac2bcf1f4f9 (patch) | |
tree | 29dbf68255584d48694bd8a50b23d8758987278c | |
parent | d3b6664f454e7ea61597c0235b4a9df95056f4cd (diff) |
Switch-interpreter: Add new 'next' instruction field.
This field is set by handlers to the next instruction to execute.
It is initialized to fall-through and can be overwritten as needed.
As the first step, only DCHECK its value against the 'inst' field.
The next step will be to remove all the inst->Next_xxx() calls.
Test: test.py -b -r --host --64 --interpreter
Test: run-libjdwp-tests.sh --mode=host --variant=X64 --debug --no-jit
Change-Id: I92740d21871cf3a5b34d9d1615ad2a71ba021339
-rw-r--r-- | libdexfile/dex/dex_instruction-inl.h | 32 | ||||
-rw-r--r-- | libdexfile/dex/dex_instruction.h | 3 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_switch_impl-inl.h | 41 |
3 files changed, 67 insertions, 9 deletions
diff --git a/libdexfile/dex/dex_instruction-inl.h b/libdexfile/dex/dex_instruction-inl.h index 88e93811f1..a1e72677d8 100644 --- a/libdexfile/dex/dex_instruction-inl.h +++ b/libdexfile/dex/dex_instruction-inl.h @@ -21,6 +21,38 @@ namespace art { +inline constexpr size_t Instruction::SizeInCodeUnits(Format format) { + switch (format) { + case k10x: + case k12x: + case k11n: + case k11x: + case k10t: return 1; + case k20t: + case k22x: + case k21t: + case k21s: + case k21h: + case k21c: + case k23x: + case k22b: + case k22t: + case k22s: + case k22c: return 2; + case k32x: + case k30t: + case k31t: + case k31i: + case k31c: + case k35c: + case k3rc: return 3; + case k45cc: + case k4rcc: return 4; + case k51l: return 5; + case kInvalidFormat: return 0; + } +} + //------------------------------------------------------------------------------ // VRegA //------------------------------------------------------------------------------ diff --git a/libdexfile/dex/dex_instruction.h b/libdexfile/dex/dex_instruction.h index a78330181f..c15fa43749 100644 --- a/libdexfile/dex/dex_instruction.h +++ b/libdexfile/dex/dex_instruction.h @@ -227,6 +227,9 @@ class Instruction { } } + // Returns the size (in 2 byte code units) of the given instruction format. + ALWAYS_INLINE static constexpr size_t SizeInCodeUnits(Format format); + // Code units required to calculate the size of the instruction. size_t CodeUnitsRequiredForSizeComputation() const { const int8_t result = kInstructionDescriptors[Opcode()].size_in_code_units; diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h index 00d8b9d0ff..a487cd6630 100644 --- a/runtime/interpreter/interpreter_switch_impl-inl.h +++ b/runtime/interpreter/interpreter_switch_impl-inl.h @@ -134,6 +134,7 @@ class InstructionHandler { } int32_t displacement = static_cast<int32_t>(shadow_frame.GetDexPC()) - static_cast<int32_t>(dex_pc); + SetNextInstruction(inst->RelativeAt(displacement)); inst = inst->RelativeAt(displacement); return false; // Stop executing this opcode and continue in the exception handler. } @@ -147,13 +148,15 @@ class InstructionHandler { // address (for 'this' argument). Make a copy of the handler just for the slow path. // * The modifiable fields should also be in registers, so we don't want to store their // address even in the handler copy. Make a copy of them just for the call as well. - const Instruction* inst_copy = inst; - bool exit_loop_copy = exit_interpreter_loop; + const Instruction* inst2 = inst; + const Instruction* next2 = next; + bool exit2 = exit_interpreter_loop; InstructionHandler<do_access_check, transaction_active, kFormat> handler_copy( - ctx, instrumentation, self, shadow_frame, dex_pc, inst_copy, inst_data, exit_loop_copy); + ctx, instrumentation, self, shadow_frame, dex_pc, inst2, inst_data, next2, exit2); bool result = handler_copy.HandlePendingExceptionWithInstrumentationImpl(instr); - inst = inst_copy; - exit_interpreter_loop = exit_loop_copy; + inst = inst2; + next = next2; + exit_interpreter_loop = exit2; return result; } @@ -179,6 +182,7 @@ class InstructionHandler { } self->ClearException(); } + SetNextInstruction(inst); } else if (UNLIKELY(is_exception_pending)) { /* Should have succeeded. */ DCHECK(!shadow_frame.GetForceRetryInstruction()); @@ -186,6 +190,7 @@ class InstructionHandler { return false; } } else { + SetNextInstruction(next_inst); inst = next_inst; } return true; @@ -202,6 +207,7 @@ class InstructionHandler { return false; } } else { + SetNextInstruction(next_inst); inst = next_inst; } return true; @@ -422,6 +428,7 @@ class InstructionHandler { return false; } BRANCH_INSTRUMENTATION(offset); + SetNextInstruction(inst->RelativeAt(offset)); inst = inst->RelativeAt(offset); HandleBackwardBranch(offset); return true; @@ -467,6 +474,7 @@ class InstructionHandler { REQUIRES_SHARED(Locks::mutator_lock_) { if (cond) { BRANCH_INSTRUMENTATION(offset); + SetNextInstruction(inst->RelativeAt(offset)); inst = inst->RelativeAt(offset); HandleBackwardBranch(offset); } else { @@ -1043,6 +1051,7 @@ class InstructionHandler { ALWAYS_INLINE bool PACKED_SWITCH() REQUIRES_SHARED(Locks::mutator_lock_) { int32_t offset = DoPackedSwitch(inst, shadow_frame, inst_data); BRANCH_INSTRUMENTATION(offset); + SetNextInstruction(inst->RelativeAt(offset)); inst = inst->RelativeAt(offset); HandleBackwardBranch(offset); return true; @@ -1051,6 +1060,7 @@ class InstructionHandler { ALWAYS_INLINE bool SPARSE_SWITCH() REQUIRES_SHARED(Locks::mutator_lock_) { int32_t offset = DoSparseSwitch(inst, shadow_frame, inst_data); BRANCH_INSTRUMENTATION(offset); + SetNextInstruction(inst->RelativeAt(offset)); inst = inst->RelativeAt(offset); HandleBackwardBranch(offset); return true; @@ -2173,6 +2183,7 @@ class InstructionHandler { uint16_t dex_pc, const Instruction*& inst, uint16_t inst_data, + const Instruction*& next, bool& exit_interpreter_loop) : ctx(ctx), instrumentation(instrumentation), @@ -2181,6 +2192,7 @@ class InstructionHandler { dex_pc(dex_pc), inst(inst), inst_data(inst_data), + next(next), exit_interpreter_loop(exit_interpreter_loop) { } @@ -2212,6 +2224,12 @@ class InstructionHandler { shadow_frame.SetVRegReference(i, val); } + // Set the next instruction to be executed. It is the 'fall-through' instruction by default. + ALWAYS_INLINE void SetNextInstruction(const Instruction* next_inst) { + DCHECK_LT(next_inst->GetDexPc(Insns()), Accessor().InsnsSizeInCodeUnits()); + next = next_inst; + } + SwitchImplContext* const ctx; const instrumentation::Instrumentation* const instrumentation; Thread* const self; @@ -2219,6 +2237,8 @@ class InstructionHandler { uint32_t const dex_pc; const Instruction*& inst; uint16_t const inst_data; + const Instruction*& next; + bool& exit_interpreter_loop; }; @@ -2259,9 +2279,10 @@ ATTRIBUTE_NO_SANITIZE_ADDRESS void ExecuteSwitchImplCpp(SwitchImplContext* ctx) TraceExecution(shadow_frame, inst, dex_pc); inst_data = inst->Fetch16(0); { + const Instruction* next = nullptr; bool exit_loop = false; InstructionHandler<do_access_check, transaction_active, Instruction::kInvalidFormat> handler( - ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, exit_loop); + ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, next, exit_loop); if (!handler.Preamble()) { if (UNLIKELY(exit_loop)) { return; @@ -2273,16 +2294,18 @@ ATTRIBUTE_NO_SANITIZE_ADDRESS void ExecuteSwitchImplCpp(SwitchImplContext* ctx) } } switch (inst->Opcode(inst_data)) { -#define OPCODE_CASE(OPCODE, OPCODE_NAME, pname, FORMAT, i, a, e, v) \ +#define OPCODE_CASE(OPCODE, OPCODE_NAME, NAME, FORMAT, i, a, e, v) \ case OPCODE: { \ + size_t inst_size = Instruction::SizeInCodeUnits(Instruction::FORMAT); \ + const Instruction* next = inst->RelativeAt(inst_size); \ bool exit_loop = false; \ InstructionHandler<do_access_check, transaction_active, Instruction::FORMAT> handler( \ - ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, exit_loop); \ + ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, next, exit_loop); \ handler.OPCODE_NAME(); \ - /* TODO: Advance 'inst' here, instead of explicitly in each handler */ \ if (UNLIKELY(exit_loop)) { \ return; \ } \ + DCHECK_EQ(next, inst) << NAME; \ break; \ } DEX_INSTRUCTION_LIST(OPCODE_CASE) |