1 /*
2  * Copyright (C) 2014 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 "mir_method_info.h"
18 
19 #include "dex/compiler_ir.h"
20 #include "dex/quick/dex_file_method_inliner.h"
21 #include "dex/quick/dex_file_to_method_inliner_map.h"
22 #include "dex/verified_method.h"
23 #include "driver/compiler_driver.h"
24 #include "driver/dex_compilation_unit.h"
25 #include "driver/compiler_driver-inl.h"
26 #include "driver/compiler_options.h"
27 #include "mirror/class_loader.h"  // Only to allow casts in Handle<ClassLoader>.
28 #include "mirror/dex_cache.h"     // Only to allow casts in Handle<DexCache>.
29 #include "scoped_thread_state_change.h"
30 #include "handle_scope-inl.h"
31 
32 namespace art {
33 
Resolve(CompilerDriver * compiler_driver,const DexCompilationUnit * mUnit,MirMethodLoweringInfo * method_infos,size_t count)34 void MirMethodLoweringInfo::Resolve(CompilerDriver* compiler_driver,
35                                     const DexCompilationUnit* mUnit,
36                                     MirMethodLoweringInfo* method_infos, size_t count) {
37   if (kIsDebugBuild) {
38     DCHECK(method_infos != nullptr);
39     DCHECK_NE(count, 0u);
40     for (auto it = method_infos, end = method_infos + count; it != end; ++it) {
41       MirMethodLoweringInfo unresolved(it->MethodIndex(), it->GetInvokeType(), it->IsQuickened());
42       unresolved.declaring_dex_file_ = it->declaring_dex_file_;
43       unresolved.vtable_idx_ = it->vtable_idx_;
44       if (it->target_dex_file_ != nullptr) {
45         unresolved.target_dex_file_ = it->target_dex_file_;
46         unresolved.target_method_idx_ = it->target_method_idx_;
47       }
48       if (kIsDebugBuild) {
49         unresolved.CheckEquals(*it);
50       }
51     }
52   }
53 
54   // We're going to resolve methods and check access in a tight loop. It's better to hold
55   // the lock and needed references once than re-acquiring them again and again.
56   ScopedObjectAccess soa(Thread::Current());
57   StackHandleScope<4> hs(soa.Self());
58   Handle<mirror::DexCache> dex_cache(hs.NewHandle(compiler_driver->GetDexCache(mUnit)));
59   Handle<mirror::ClassLoader> class_loader(
60       hs.NewHandle(compiler_driver->GetClassLoader(soa, mUnit)));
61   Handle<mirror::Class> referrer_class(hs.NewHandle(
62       compiler_driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, mUnit)));
63   auto current_dex_cache(hs.NewHandle<mirror::DexCache>(nullptr));
64   // Even if the referrer class is unresolved (i.e. we're compiling a method without class
65   // definition) we still want to resolve methods and record all available info.
66   Runtime* const runtime = Runtime::Current();
67   const DexFile* const dex_file = mUnit->GetDexFile();
68   const bool use_jit = runtime->UseJit();
69   const VerifiedMethod* const verified_method = mUnit->GetVerifiedMethod();
70   DexFileToMethodInlinerMap* inliner_map = compiler_driver->GetMethodInlinerMap();
71   DexFileMethodInliner* default_inliner =
72       (inliner_map != nullptr) ? inliner_map->GetMethodInliner(dex_file) : nullptr;
73 
74   for (auto it = method_infos, end = method_infos + count; it != end; ++it) {
75     // For quickened invokes, the dex method idx is actually the mir offset.
76     if (it->IsQuickened()) {
77       const auto* dequicken_ref = verified_method->GetDequickenIndex(it->method_idx_);
78       CHECK(dequicken_ref != nullptr);
79       it->target_dex_file_ = dequicken_ref->dex_file;
80       it->target_method_idx_ = dequicken_ref->index;
81     }
82     // Remember devirtualized invoke target and set the called method to the default.
83     MethodReference devirt_ref(it->target_dex_file_, it->target_method_idx_);
84     MethodReference* devirt_target = (it->target_dex_file_ != nullptr) ? &devirt_ref : nullptr;
85     InvokeType invoke_type = it->GetInvokeType();
86     ArtMethod* resolved_method = nullptr;
87 
88     bool string_init = false;
89     if (default_inliner->IsStringInitMethodIndex(it->MethodIndex())) {
90       string_init = true;
91       invoke_type = kDirect;
92     }
93 
94     if (!it->IsQuickened()) {
95       it->target_dex_file_ = dex_file;
96       it->target_method_idx_ = it->MethodIndex();
97       current_dex_cache.Assign(dex_cache.Get());
98       resolved_method = compiler_driver->ResolveMethod(soa, dex_cache, class_loader, mUnit,
99                                                        it->target_method_idx_, invoke_type, true);
100     } else {
101       // The method index is actually the dex PC in this case.
102       // Calculate the proper dex file and target method idx.
103       CHECK(use_jit);
104       CHECK_EQ(invoke_type, kVirtual);
105       // Don't devirt if we are in a different dex file since we can't have direct invokes in
106       // another dex file unless we always put a direct / patch pointer.
107       devirt_target = nullptr;
108       current_dex_cache.Assign(runtime->GetClassLinker()->FindDexCache(*it->target_dex_file_));
109       CHECK(current_dex_cache.Get() != nullptr);
110       DexCompilationUnit cu(
111           mUnit->GetCompilationUnit(), mUnit->GetClassLoader(), mUnit->GetClassLinker(),
112           *it->target_dex_file_, nullptr /* code_item not used */, 0u /* class_def_idx not used */,
113           it->target_method_idx_, 0u /* access_flags not used */,
114           nullptr /* verified_method not used */);
115       resolved_method = compiler_driver->ResolveMethod(soa, current_dex_cache, class_loader, &cu,
116                                                        it->target_method_idx_, invoke_type, false);
117       if (resolved_method == nullptr) {
118         // If the method is null then it should be a miranda method, in this case try
119         // re-loading it, this time as an interface method. The actual miranda method is in the
120         // vtable, but it will resolve to an interface method.
121         resolved_method = compiler_driver->ResolveMethod(
122             soa, current_dex_cache, class_loader, &cu, it->target_method_idx_, kInterface, false);
123         CHECK(resolved_method != nullptr);
124       }
125       if (resolved_method != nullptr) {
126         // Since this was a dequickened virtual, it is guaranteed to be resolved. However, it may be
127         // resolved to an interface method. If this is the case then change the invoke type to
128         // interface with the assumption that sharp_type will be kVirtual.
129         if (resolved_method->GetInvokeType() == kInterface) {
130           it->flags_ = (it->flags_ & ~(kInvokeTypeMask << kBitInvokeTypeBegin)) |
131               (static_cast<uint16_t>(kInterface) << kBitInvokeTypeBegin);
132         }
133       }
134     }
135     if (UNLIKELY(resolved_method == nullptr)) {
136       continue;
137     }
138 
139     compiler_driver->GetResolvedMethodDexFileLocation(resolved_method,
140         &it->declaring_dex_file_, &it->declaring_class_idx_, &it->declaring_method_idx_);
141     if (!it->IsQuickened()) {
142       // For quickened invoke virtuals we may have desharpened to an interface method which
143       // wont give us the right method index, in this case blindly dispatch or else we can't
144       // compile the method. Converting the invoke to interface dispatch doesn't work since we
145       // have no way to get the dex method index for quickened invoke virtuals in the interface
146       // trampolines.
147       it->vtable_idx_ =
148           compiler_driver->GetResolvedMethodVTableIndex(resolved_method, invoke_type);
149     }
150 
151     MethodReference target_method(it->target_dex_file_, it->target_method_idx_);
152     int fast_path_flags = compiler_driver->IsFastInvoke(
153         soa, current_dex_cache, class_loader, mUnit, referrer_class.Get(), resolved_method,
154         &invoke_type, &target_method, devirt_target, &it->direct_code_, &it->direct_method_);
155     const bool is_referrers_class = referrer_class.Get() == resolved_method->GetDeclaringClass();
156     const bool is_class_initialized =
157         compiler_driver->IsMethodsClassInitialized(referrer_class.Get(), resolved_method);
158 
159     // Check if the target method is intrinsic or special.
160     InlineMethodFlags is_intrinsic_or_special = kNoInlineMethodFlags;
161     if (inliner_map != nullptr) {
162       auto* inliner = (target_method.dex_file == dex_file)
163           ? default_inliner
164           : inliner_map->GetMethodInliner(target_method.dex_file);
165       is_intrinsic_or_special = inliner->IsIntrinsicOrSpecial(target_method.dex_method_index);
166     }
167 
168     uint16_t other_flags = it->flags_ &
169         ~(kFlagFastPath | kFlagIsIntrinsic | kFlagIsSpecial | kFlagClassIsInitialized |
170             (kInvokeTypeMask << kBitSharpTypeBegin));
171     it->flags_ = other_flags |
172         // String init path is a special always-fast path.
173         (fast_path_flags != 0 || string_init ? kFlagFastPath : 0u) |
174         ((is_intrinsic_or_special & kInlineIntrinsic) != 0 ? kFlagIsIntrinsic : 0u) |
175         ((is_intrinsic_or_special & kInlineSpecial) != 0 ? kFlagIsSpecial : 0u) |
176         (static_cast<uint16_t>(invoke_type) << kBitSharpTypeBegin) |
177         (is_referrers_class ? kFlagIsReferrersClass : 0u) |
178         (is_class_initialized ? kFlagClassIsInitialized : 0u);
179     it->target_dex_file_ = target_method.dex_file;
180     it->target_method_idx_ = target_method.dex_method_index;
181     it->stats_flags_ = fast_path_flags;
182     if (string_init) {
183       it->direct_code_ = 0;
184     }
185   }
186 }
187 
188 }  // namespace art
189