Support unwinding though the switch interpreter.
Wrap the switch interpreter in small assembly method which defines
DEX PC in CFI and thus it allows libunwind to backtrace through it.
Bug: 22414682
Test: testrunner.py --host -t 137
Test: testrunner.py --target -t 137
Change-Id: I31dad9f0fb446151baaa99234b64f25c8ca2fa87
diff --git a/runtime/interpreter/interpreter_switch_impl.h b/runtime/interpreter/interpreter_switch_impl.h
index 50db337..9fc4239 100644
--- a/runtime/interpreter/interpreter_switch_impl.h
+++ b/runtime/interpreter/interpreter_switch_impl.h
@@ -20,23 +20,59 @@
#include "base/macros.h"
#include "base/mutex.h"
#include "dex/dex_file.h"
+#include "dex/code_item_accessors.h"
#include "jvalue.h"
#include "obj_ptr.h"
namespace art {
-class CodeItemDataAccessor;
class ShadowFrame;
class Thread;
namespace interpreter {
+// Group all the data that is needed in the switch interpreter.
+// We need to pass it to the hand-written assembly and back,
+// so it is easier to pass it through a single pointer.
+// Similarly, returning the JValue type would be non-trivial.
+struct SwitchImplContext {
+ Thread* self;
+ const CodeItemDataAccessor& accessor;
+ ShadowFrame& shadow_frame;
+ JValue& result_register;
+ bool interpret_one_instruction;
+ JValue result;
+};
+
+// The actual internal implementation of the switch interpreter.
template<bool do_access_check, bool transaction_active>
-JValue ExecuteSwitchImpl(Thread* self,
- const CodeItemDataAccessor& accessor,
- ShadowFrame& shadow_frame,
- JValue result_register,
- bool interpret_one_instruction) REQUIRES_SHARED(Locks::mutator_lock_);
+void ExecuteSwitchImplCpp(SwitchImplContext* ctx)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+// Hand-written assembly method which wraps the C++ implementation,
+// while defining the DEX PC in the CFI so that libunwind can resolve it.
+extern "C" void ExecuteSwitchImplAsm(SwitchImplContext* ctx, void* impl, const uint16_t* dexpc)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+// Wrapper around the switch interpreter which ensures we can unwind through it.
+template<bool do_access_check, bool transaction_active>
+ALWAYS_INLINE JValue ExecuteSwitchImpl(Thread* self, const CodeItemDataAccessor& accessor,
+ ShadowFrame& shadow_frame, JValue result_register,
+ bool interpret_one_instruction)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ SwitchImplContext ctx {
+ .self = self,
+ .accessor = accessor,
+ .shadow_frame = shadow_frame,
+ .result_register = result_register,
+ .interpret_one_instruction = interpret_one_instruction,
+ .result = JValue(),
+ };
+ void* impl = reinterpret_cast<void*>(&ExecuteSwitchImplCpp<do_access_check, transaction_active>);
+ const uint16_t* dex_pc = ctx.accessor.Insns();
+ ExecuteSwitchImplAsm(&ctx, impl, dex_pc);
+ return ctx.result;
+}
} // namespace interpreter
} // namespace art