Roland Levillain | ad0777d | 2018-02-12 20:00:18 +0000 | [diff] [blame] | 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. |
Roland Levillain | bbc6e7e | 2018-08-24 16:58:47 +0100 | [diff] [blame] | 30 | class GetProxyQuickFrameVisitor final : public StackVisitor { |
Roland Levillain | ad0777d | 2018-02-12 20:00:18 +0000 | [diff] [blame] | 31 | public: |
| 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 | |
Roland Levillain | bbc6e7e | 2018-08-24 16:58:47 +0100 | [diff] [blame] | 39 | bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) { |
Roland Levillain | ad0777d | 2018-02-12 20:00:18 +0000 | [diff] [blame] | 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 | |
| 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. |
| 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 | |
| 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 | |
| 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 |