| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "arch/context.h" |
| #include "art_method-inl.h" |
| #include "jni.h" |
| #include "oat_quick_method_header.h" |
| #include "scoped_thread_state_change-inl.h" |
| #include "stack.h" |
| #include "thread.h" |
| |
| namespace art { |
| |
| namespace { |
| |
| // Visit a proxy method Quick frame at a given depth. |
| class GetProxyQuickFrameVisitor final : public StackVisitor { |
| public: |
| GetProxyQuickFrameVisitor(art::Thread* target, art::Context* ctx, size_t frame_depth) |
| REQUIRES_SHARED(art::Locks::mutator_lock_) |
| : art::StackVisitor(target, ctx, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames), |
| cur_depth_(0u), |
| frame_depth_(frame_depth), |
| quick_frame_(nullptr) {} |
| |
| bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) { |
| if (GetMethod()->IsRuntimeMethod()) { |
| return true; |
| } |
| if (cur_depth_ == frame_depth_) { |
| // Found frame. |
| ShadowFrame* shadow_frame = GetCurrentShadowFrame(); |
| if (shadow_frame != nullptr) { |
| // Nothing to do. |
| } else { |
| VisitQuickFrameAtSearchedDepth(); |
| } |
| return false; |
| } else { |
| ++cur_depth_; |
| return true; |
| } |
| } |
| |
| void VisitQuickFrameAtSearchedDepth() REQUIRES_SHARED(Locks::mutator_lock_) { |
| quick_frame_ = GetCurrentQuickFrame(); |
| CHECK(quick_frame_ != nullptr); |
| ArtMethod* method = *quick_frame_; |
| CHECK(method != nullptr); |
| CHECK(method->IsProxyMethod()) << method->PrettyMethod(); |
| } |
| |
| // Return the found Quick frame. |
| ArtMethod** GetQuickFrame() { |
| return quick_frame_; |
| } |
| |
| private: |
| // The depth of the currently visited frame. |
| size_t cur_depth_; |
| // The depth of the currently searched frame. |
| size_t frame_depth_; |
| // The quick frame, if found. |
| ArtMethod** quick_frame_; |
| // Method name |
| |
| DISALLOW_COPY_AND_ASSIGN(GetProxyQuickFrameVisitor); |
| }; |
| |
| extern "C" StackReference<mirror::Object>* artQuickGetProxyReferenceArgumentAt(size_t arg_pos, |
| ArtMethod** sp) |
| REQUIRES_SHARED(Locks::mutator_lock_); |
| |
| jobject GetProxyReferenceArgument(size_t arg_pos, size_t proxy_method_frame_depth) { |
| Thread* self = Thread::Current(); |
| ScopedObjectAccess soa(self); |
| std::unique_ptr<Context> context(Context::Create()); |
| |
| GetProxyQuickFrameVisitor visitor(self, context.get(), proxy_method_frame_depth); |
| visitor.WalkStack(); |
| ArtMethod** quick_frame = visitor.GetQuickFrame(); |
| CHECK(quick_frame != nullptr); |
| |
| // Find reference argument in frame. |
| StackReference<mirror::Object>* ref_arg = |
| artQuickGetProxyReferenceArgumentAt(arg_pos, quick_frame); |
| CHECK(ref_arg != nullptr); |
| art::ObjPtr<mirror::Object> obj = ref_arg->AsMirrorPtr(); |
| |
| return obj.IsNull() ? nullptr : soa.AddLocalReference<jobject>(obj); |
| } |
| |
| extern "C" JNIEXPORT jobject JNICALL Java_TestInvocationHandler_getArgument( |
| JNIEnv* env ATTRIBUTE_UNUSED, jobject thiz ATTRIBUTE_UNUSED, int arg_pos, int frame_depth) { |
| return GetProxyReferenceArgument(arg_pos, frame_depth); |
| } |
| |
| } // namespace |
| |
| } // namespace art |