summaryrefslogtreecommitdiffstats
path: root/runtime/interpreter/interpreter_goto_table_impl.cc
diff options
context:
space:
mode:
authorSebastien Hertz <shertz@google.com>2013-09-19 14:47:09 +0200
committerSebastien Hertz <shertz@google.com>2013-10-17 11:15:43 +0200
commitee1997a3b83334985e757f369c09e111b121661b (patch)
tree8745229cde52990208b27af54d7e80ea2fc274c4 /runtime/interpreter/interpreter_goto_table_impl.cc
parent9f69b62e6b009b29e6420c49e7444e91466a6a33 (diff)
downloadart-ee1997a3b83334985e757f369c09e111b121661b.zip
art-ee1997a3b83334985e757f369c09e111b121661b.tar.gz
art-ee1997a3b83334985e757f369c09e111b121661b.tar.bz2
Improve interpreter handler table management.
We still have two handlers table: - the "main" table which holds execution handlers of each instruction, - the "alternative" table which holds handlers supporting instrumentation before jumping to the corresponding instruction handler from the "main" table. Instrumentation holds the index of the handler table the interpreter must use. This index is represented by the InterpreterHandlerTable enum and is stored in the Instrumentation::interpreter_handler_table_ field. Interpreter's current handler table update happens: - on backward branch - after invoke - when throwing exception. In the case of the backward branch and exception, we only update the table if any thread's flags is set. This allows to only do one test for handling thread suspension and handler table update. This CL also removes the local variable "instrumentation". Every handler which needs it will get it from Runtime::Current()->GetInstrumentation(). Change-Id: Id886ea7ebf3dac1285f0ca701c098aee7ebaab8d
Diffstat (limited to 'runtime/interpreter/interpreter_goto_table_impl.cc')
-rw-r--r--runtime/interpreter/interpreter_goto_table_impl.cc162
1 files changed, 108 insertions, 54 deletions
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index daf6f93..608cd41 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -51,14 +51,8 @@ namespace interpreter {
} \
} while (false)
-#define UPDATE_HANDLER_TABLE() \
- do { \
- if (UNLIKELY(instrumentation->HasDexPcListeners())) { \
- currentHandlersTable = instrumentationHandlersTable; \
- } else { \
- currentHandlersTable = handlersTable; \
- } \
- } while (false);
+#define UPDATE_HANDLER_TABLE() \
+ currentHandlersTable = handlersTable[Runtime::Current()->GetInstrumentation()->GetInterpreterHandlerTable()]
#define UNREACHABLE_CODE_CHECK() \
do { \
@@ -70,10 +64,77 @@ namespace interpreter {
#define HANDLE_INSTRUCTION_START(opcode) op_##opcode: // NOLINT(whitespace/labels)
#define HANDLE_INSTRUCTION_END() UNREACHABLE_CODE_CHECK()
+/**
+ * Interpreter based on computed goto tables.
+ *
+ * Each instruction is associated to a handler. This handler is responsible for executing the
+ * instruction and jump to the next instruction's handler.
+ * In order to limit the cost of instrumentation, we have two handler tables:
+ * - the "main" handler table: it contains handlers for normal execution of each instruction without
+ * handling of instrumentation.
+ * - the "alternative" handler table: it contains alternative handlers which first handle
+ * instrumentation before jumping to the corresponding "normal" instruction's handler.
+ *
+ * When instrumentation is active, the interpreter uses the "alternative" handler table. Otherwise
+ * it uses the "main" handler table.
+ *
+ * The current handler table is the handler table being used by the interpreter. It is updated:
+ * - on backward branch (goto, if and switch instructions)
+ * - after invoke
+ * - when an exception is thrown.
+ * This allows to support an attaching debugger to an already running application for instance.
+ *
+ * For a fast handler table update, handler tables are stored in an array of handler tables. Each
+ * handler table is represented by the InterpreterHandlerTable enum which allows to associate it
+ * to an index in this array of handler tables ((see Instrumentation::GetInterpreterHandlerTable).
+ *
+ * Here's the current layout of this array of handler tables:
+ *
+ * ---------------------+---------------+
+ * | NOP | (handler for NOP instruction)
+ * +---------------+
+ * "main" | MOVE | (handler for MOVE instruction)
+ * handler table +---------------+
+ * | ... |
+ * +---------------+
+ * | UNUSED_FF | (handler for UNUSED_FF instruction)
+ * ---------------------+---------------+
+ * | NOP | (alternative handler for NOP instruction)
+ * +---------------+
+ * "alternative" | MOVE | (alternative handler for MOVE instruction)
+ * handler table +---------------+
+ * | ... |
+ * +---------------+
+ * | UNUSED_FF | (alternative handler for UNUSED_FF instruction)
+ * ---------------------+---------------+
+ *
+ */
template<bool do_access_check>
JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register) {
- bool do_assignability_check = do_access_check;
+ // Define handler tables:
+ // - The main handler table contains execution handlers for each instruction.
+ // - The alternative handler table contains prelude handlers which check for thread suspend and
+ // manage instrumentation before jumping to the execution handler.
+ static const void* const handlersTable[instrumentation::kNumHandlerTables][kNumPackedOpcodes] = {
+ {
+ // Main handler table.
+#define INSTRUCTION_HANDLER(o, code, n, f, r, i, a, v) &&op_##code,
+#include "dex_instruction_list.h"
+ DEX_INSTRUCTION_LIST(INSTRUCTION_HANDLER)
+#undef DEX_INSTRUCTION_LIST
+#undef INSTRUCTION_HANDLER
+ }, {
+ // Alternative handler table.
+#define INSTRUCTION_HANDLER(o, code, n, f, r, i, a, v) &&alt_op_##code,
+#include "dex_instruction_list.h"
+ DEX_INSTRUCTION_LIST(INSTRUCTION_HANDLER)
+#undef DEX_INSTRUCTION_LIST
+#undef INSTRUCTION_HANDLER
+ }
+ };
+
+ const bool do_assignability_check = do_access_check;
if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
LOG(FATAL) << "Invalid shadow frame for interpreter use";
return JValue();
@@ -81,35 +142,17 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
self->VerifyStack();
uint32_t dex_pc = shadow_frame.GetDexPC();
- const instrumentation::Instrumentation* const instrumentation = Runtime::Current()->GetInstrumentation();
+ const Instruction* inst = Instruction::At(code_item->insns_ + dex_pc);
+ uint16_t inst_data;
+ const void* const* currentHandlersTable;
+ UPDATE_HANDLER_TABLE();
if (LIKELY(dex_pc == 0)) { // We are entering the method as opposed to deoptimizing..
+ instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
instrumentation->MethodEnterEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), 0);
}
}
- const Instruction* inst = Instruction::At(code_item->insns_ + dex_pc);
- uint16_t inst_data;
-
- // Define handlers table.
- static const void* handlersTable[kNumPackedOpcodes] = {
-#define INSTRUCTION_HANDLER(o, code, n, f, r, i, a, v) &&op_##code,
-#include "dex_instruction_list.h"
- DEX_INSTRUCTION_LIST(INSTRUCTION_HANDLER)
-#undef DEX_INSTRUCTION_LIST
-#undef INSTRUCTION_HANDLER
- };
-
- static const void* instrumentationHandlersTable[kNumPackedOpcodes] = {
-#define INSTRUCTION_HANDLER(o, code, n, f, r, i, a, v) &&instrumentation_op_##code,
-#include "dex_instruction_list.h"
- DEX_INSTRUCTION_LIST(INSTRUCTION_HANDLER)
-#undef DEX_INSTRUCTION_LIST
-#undef INSTRUCTION_HANDLER
- };
-
- const void** currentHandlersTable;
- UPDATE_HANDLER_TABLE();
// Jump to first instruction.
ADVANCE(0);
@@ -207,6 +250,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
}
+ instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), dex_pc,
@@ -222,6 +266,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
}
+ instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), dex_pc,
@@ -238,6 +283,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
}
+ instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), dex_pc,
@@ -253,6 +299,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
}
+ instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), dex_pc,
@@ -286,6 +333,7 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
HANDLE_PENDING_EXCEPTION();
}
}
+ instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
shadow_frame.GetMethod(), dex_pc,
@@ -547,8 +595,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
}
@@ -559,8 +607,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
}
@@ -571,8 +619,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
}
@@ -583,8 +631,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
}
@@ -595,8 +643,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
}
@@ -688,8 +736,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
} else {
@@ -704,8 +752,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
} else {
@@ -720,8 +768,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
} else {
@@ -736,8 +784,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
} else {
@@ -752,8 +800,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
} else {
@@ -768,8 +816,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
} else {
@@ -784,8 +832,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
} else {
@@ -800,8 +848,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
} else {
@@ -816,8 +864,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
} else {
@@ -832,8 +880,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
} else {
@@ -848,8 +896,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
} else {
@@ -864,8 +912,8 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
if (IsBackwardBranch(offset)) {
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
- UPDATE_HANDLER_TABLE();
}
ADVANCE(offset);
} else {
@@ -2306,8 +2354,10 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
CHECK(self->IsExceptionPending());
if (UNLIKELY(self->TestAllFlags())) {
CheckSuspend(self);
+ UPDATE_HANDLER_TABLE();
}
Object* this_object = shadow_frame.GetThisObject(code_item->ins_size_);
+ instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
uint32_t found_dex_pc = FindNextInstructionFollowingException(self, shadow_frame, dex_pc,
this_object,
instrumentation);
@@ -2320,11 +2370,15 @@ JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem*
}
// Create alternative instruction handlers dedicated to instrumentation.
-#define INSTRUMENTATION_INSTRUCTION_HANDLER(o, code, n, f, r, i, a, v) \
- instrumentation_op_##code: { \
- instrumentation->DexPcMovedEvent(self, shadow_frame.GetThisObject(code_item->ins_size_), \
- shadow_frame.GetMethod(), dex_pc); \
- goto *handlersTable[Instruction::code]; \
+#define INSTRUMENTATION_INSTRUCTION_HANDLER(o, code, n, f, r, i, a, v) \
+ alt_op_##code: { \
+ instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); \
+ if (UNLIKELY(instrumentation->HasDexPcListeners())) { \
+ instrumentation->DexPcMovedEvent(self, shadow_frame.GetThisObject(code_item->ins_size_), \
+ shadow_frame.GetMethod(), dex_pc); \
+ } \
+ UPDATE_HANDLER_TABLE(); \
+ goto *handlersTable[instrumentation::kMainHandlerTable][Instruction::code]; \
}
#include "dex_instruction_list.h"
DEX_INSTRUCTION_LIST(INSTRUMENTATION_INSTRUCTION_HANDLER)