Merge "Support proxy method in StackVisitor::GetThisObject"
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index cb81629..9db1646 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -208,6 +208,22 @@
 #endif
 
  public:
+  // Special handling for proxy methods. Proxy methods are instance methods so the
+  // 'this' object is the 1st argument. They also have the same frame layout as the
+  // kRefAndArgs runtime method. Since 'this' is a reference, it is located in the
+  // 1st GPR.
+  static mirror::Object* GetProxyThisObject(StackReference<mirror::ArtMethod>* sp)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    CHECK(sp->AsMirrorPtr()->IsProxyMethod());
+    CHECK_EQ(kQuickCalleeSaveFrame_RefAndArgs_FrameSize, sp->AsMirrorPtr()->GetFrameSizeInBytes());
+    CHECK_GT(kNumQuickGprArgs, 0u);
+    constexpr uint32_t kThisGprIndex = 0u;  // 'this' is in the 1st GPR.
+    size_t this_arg_offset = kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset +
+        GprIndexToGprOffset(kThisGprIndex);
+    uint8_t* this_arg_address = reinterpret_cast<uint8_t*>(sp) + this_arg_offset;
+    return reinterpret_cast<StackReference<mirror::Object>*>(this_arg_address)->AsMirrorPtr();
+  }
+
   static mirror::ArtMethod* GetCallingMethod(StackReference<mirror::ArtMethod>* sp)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(sp->AsMirrorPtr()->IsCalleeSaveMethod());
@@ -435,6 +451,13 @@
   bool is_split_long_or_double_;
 };
 
+// Returns the 'this' object of a proxy method. This function is only used by StackVisitor. It
+// allows to use the QuickArgumentVisitor constants without moving all the code in its own module.
+extern "C" mirror::Object* artQuickGetProxyThisObject(StackReference<mirror::ArtMethod>* sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  return QuickArgumentVisitor::GetProxyThisObject(sp);
+}
+
 // Visits arguments on the stack placing them into the shadow frame.
 class BuildQuickShadowFrameVisitor FINAL : public QuickArgumentVisitor {
  public:
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 43714b9..aaa5b89 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -113,6 +113,9 @@
   }
 }
 
+extern "C" mirror::Object* artQuickGetProxyThisObject(StackReference<mirror::ArtMethod>* sp)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
 mirror::Object* StackVisitor::GetThisObject() const {
   mirror::ArtMethod* m = GetMethod();
   if (m->IsStatic()) {
@@ -125,6 +128,12 @@
     } else {
       return cur_shadow_frame_->GetVRegReference(0);
     }
+  } else if (m->IsProxyMethod()) {
+    if (cur_quick_frame_ != nullptr) {
+      return artQuickGetProxyThisObject(cur_quick_frame_);
+    } else {
+      return cur_shadow_frame_->GetVRegReference(0);
+    }
   } else if (m->IsOptimized(sizeof(void*))) {
     // TODO: Implement, currently only used for exceptions when jdwp is enabled.
     UNIMPLEMENTED(WARNING)