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 32namespace art { 33 34void 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