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