1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "arch/context.h"
18 #include "art_method-inl.h"
19 #include "jni.h"
20 #include "oat_quick_method_header.h"
21 #include "scoped_thread_state_change-inl.h"
22 #include "stack.h"
23 #include "thread.h"
24 
25 namespace art {
26 
27 namespace {
28 
29 // Visit a proxy method Quick frame at a given depth.
30 class GetProxyQuickFrameVisitor FINAL : public StackVisitor {
31  public:
GetProxyQuickFrameVisitor(art::Thread * target,art::Context * ctx,size_t frame_depth)32   GetProxyQuickFrameVisitor(art::Thread* target, art::Context* ctx, size_t frame_depth)
33       REQUIRES_SHARED(art::Locks::mutator_lock_)
34       : art::StackVisitor(target, ctx, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames),
35         cur_depth_(0u),
36         frame_depth_(frame_depth),
37         quick_frame_(nullptr) {}
38 
VisitFrame()39   bool VisitFrame() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
40     if (GetMethod()->IsRuntimeMethod()) {
41       return true;
42     }
43     if (cur_depth_ == frame_depth_) {
44       // Found frame.
45       ShadowFrame* shadow_frame = GetCurrentShadowFrame();
46       if (shadow_frame != nullptr) {
47         // Nothing to do.
48       } else {
49         VisitQuickFrameAtSearchedDepth();
50       }
51       return false;
52     } else {
53       ++cur_depth_;
54       return true;
55     }
56   }
57 
VisitQuickFrameAtSearchedDepth()58   void VisitQuickFrameAtSearchedDepth() REQUIRES_SHARED(Locks::mutator_lock_) {
59     quick_frame_ = GetCurrentQuickFrame();
60     CHECK(quick_frame_ != nullptr);
61     ArtMethod* method = *quick_frame_;
62     CHECK(method != nullptr);
63     CHECK(method->IsProxyMethod()) << method->PrettyMethod();
64   }
65 
66   // Return the found Quick frame.
GetQuickFrame()67   ArtMethod** GetQuickFrame() {
68     return quick_frame_;
69   }
70 
71  private:
72   // The depth of the currently visited frame.
73   size_t cur_depth_;
74   // The depth of the currently searched frame.
75   size_t frame_depth_;
76   // The quick frame, if found.
77   ArtMethod** quick_frame_;
78   // Method name
79 
80   DISALLOW_COPY_AND_ASSIGN(GetProxyQuickFrameVisitor);
81 };
82 
83 extern "C" StackReference<mirror::Object>* artQuickGetProxyReferenceArgumentAt(size_t arg_pos,
84                                                                                ArtMethod** sp)
85     REQUIRES_SHARED(Locks::mutator_lock_);
86 
GetProxyReferenceArgument(size_t arg_pos,size_t proxy_method_frame_depth)87 jobject GetProxyReferenceArgument(size_t arg_pos, size_t proxy_method_frame_depth) {
88   Thread* self = Thread::Current();
89   ScopedObjectAccess soa(self);
90   std::unique_ptr<Context> context(Context::Create());
91 
92   GetProxyQuickFrameVisitor visitor(self, context.get(), proxy_method_frame_depth);
93   visitor.WalkStack();
94   ArtMethod** quick_frame = visitor.GetQuickFrame();
95   CHECK(quick_frame != nullptr);
96 
97   // Find reference argument in frame.
98   StackReference<mirror::Object>* ref_arg =
99       artQuickGetProxyReferenceArgumentAt(arg_pos, quick_frame);
100   CHECK(ref_arg != nullptr);
101   art::ObjPtr<mirror::Object> obj = ref_arg->AsMirrorPtr();
102 
103   return obj.IsNull() ? nullptr : soa.AddLocalReference<jobject>(obj);
104 }
105 
Java_TestInvocationHandler_getArgument(JNIEnv * env ATTRIBUTE_UNUSED,jobject thiz ATTRIBUTE_UNUSED,int arg_pos,int frame_depth)106 extern "C" JNIEXPORT jobject JNICALL Java_TestInvocationHandler_getArgument(
107     JNIEnv* env ATTRIBUTE_UNUSED, jobject thiz ATTRIBUTE_UNUSED, int arg_pos, int frame_depth) {
108   return GetProxyReferenceArgument(arg_pos, frame_depth);
109 }
110 
111 }  // namespace
112 
113 }  // namespace art
114