Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 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 | |
Jeff Hao | 848f70a | 2014-01-15 13:49:50 -0800 | [diff] [blame] | 19 | #include "dex/compiler_ir.h" |
Vladimir Marko | 87b7c52 | 2015-04-08 10:01:01 +0100 | [diff] [blame] | 20 | #include "dex/quick/dex_file_method_inliner.h" |
| 21 | #include "dex/quick/dex_file_to_method_inliner_map.h" |
Vladimir Marko | 20f8559 | 2015-03-19 10:07:02 +0000 | [diff] [blame] | 22 | #include "dex/verified_method.h" |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 23 | #include "driver/compiler_driver.h" |
| 24 | #include "driver/dex_compilation_unit.h" |
| 25 | #include "driver/compiler_driver-inl.h" |
Vladimir Marko | 20f8559 | 2015-03-19 10:07:02 +0000 | [diff] [blame] | 26 | #include "driver/compiler_options.h" |
Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 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>. |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 29 | #include "scoped_thread_state_change.h" |
Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 30 | #include "handle_scope-inl.h" |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 31 | |
| 32 | namespace art { |
| 33 | |
| 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) { |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 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_; |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 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 | } |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 48 | if (kIsDebugBuild) { |
| 49 | unresolved.CheckEquals(*it); |
| 50 | } |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 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()); |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 57 | StackHandleScope<4> hs(soa.Self()); |
Mathieu Chartier | eb8167a | 2014-05-07 15:43:14 -0700 | [diff] [blame] | 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))); |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 63 | auto current_dex_cache(hs.NewHandle<mirror::DexCache>(nullptr)); |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 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. |
Mathieu Chartier | 091d238 | 2015-03-06 10:59:06 -0800 | [diff] [blame] | 66 | Runtime* const runtime = Runtime::Current(); |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 67 | const DexFile* const dex_file = mUnit->GetDexFile(); |
Mathieu Chartier | 091d238 | 2015-03-06 10:59:06 -0800 | [diff] [blame] | 68 | const bool use_jit = runtime->UseJit(); |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 69 | const VerifiedMethod* const verified_method = mUnit->GetVerifiedMethod(); |
Vladimir Marko | 87b7c52 | 2015-04-08 10:01:01 +0100 | [diff] [blame] | 70 | DexFileToMethodInlinerMap* inliner_map = compiler_driver->GetMethodInlinerMap(); |
| 71 | DexFileMethodInliner* default_inliner = |
| 72 | (inliner_map != nullptr) ? inliner_map->GetMethodInliner(dex_file) : nullptr; |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 73 | |
| 74 | for (auto it = method_infos, end = method_infos + count; it != end; ++it) { |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 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 | } |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 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; |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 85 | InvokeType invoke_type = it->GetInvokeType(); |
Mathieu Chartier | e401d14 | 2015-04-22 13:56:20 -0700 | [diff] [blame] | 86 | ArtMethod* resolved_method = nullptr; |
Jeff Hao | 848f70a | 2014-01-15 13:49:50 -0800 | [diff] [blame] | 87 | |
| 88 | bool string_init = false; |
| 89 | if (default_inliner->IsStringInitMethodIndex(it->MethodIndex())) { |
| 90 | string_init = true; |
| 91 | invoke_type = kDirect; |
| 92 | } |
| 93 | |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 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, |
Mathieu Chartier | 091d238 | 2015-03-06 10:59:06 -0800 | [diff] [blame] | 99 | it->target_method_idx_, invoke_type, true); |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 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; |
Mathieu Chartier | 673ed3d | 2015-08-28 14:56:43 -0700 | [diff] [blame] | 108 | current_dex_cache.Assign(runtime->GetClassLinker()->FindDexCache( |
| 109 | soa.Self(), *it->target_dex_file_)); |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 110 | CHECK(current_dex_cache.Get() != nullptr); |
| 111 | DexCompilationUnit cu( |
| 112 | mUnit->GetCompilationUnit(), mUnit->GetClassLoader(), mUnit->GetClassLinker(), |
| 113 | *it->target_dex_file_, nullptr /* code_item not used */, 0u /* class_def_idx not used */, |
| 114 | it->target_method_idx_, 0u /* access_flags not used */, |
Mathieu Chartier | 736b560 | 2015-09-02 14:54:11 -0700 | [diff] [blame] | 115 | nullptr /* verified_method not used */, |
| 116 | current_dex_cache); |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 117 | resolved_method = compiler_driver->ResolveMethod(soa, current_dex_cache, class_loader, &cu, |
| 118 | it->target_method_idx_, invoke_type, false); |
Mathieu Chartier | 091d238 | 2015-03-06 10:59:06 -0800 | [diff] [blame] | 119 | if (resolved_method == nullptr) { |
| 120 | // If the method is null then it should be a miranda method, in this case try |
| 121 | // re-loading it, this time as an interface method. The actual miranda method is in the |
| 122 | // vtable, but it will resolve to an interface method. |
| 123 | resolved_method = compiler_driver->ResolveMethod( |
| 124 | soa, current_dex_cache, class_loader, &cu, it->target_method_idx_, kInterface, false); |
| 125 | CHECK(resolved_method != nullptr); |
| 126 | } |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 127 | if (resolved_method != nullptr) { |
| 128 | // Since this was a dequickened virtual, it is guaranteed to be resolved. However, it may be |
| 129 | // resolved to an interface method. If this is the case then change the invoke type to |
| 130 | // interface with the assumption that sharp_type will be kVirtual. |
| 131 | if (resolved_method->GetInvokeType() == kInterface) { |
| 132 | it->flags_ = (it->flags_ & ~(kInvokeTypeMask << kBitInvokeTypeBegin)) | |
| 133 | (static_cast<uint16_t>(kInterface) << kBitInvokeTypeBegin); |
| 134 | } |
| 135 | } |
| 136 | } |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 137 | if (UNLIKELY(resolved_method == nullptr)) { |
| 138 | continue; |
| 139 | } |
Vladimir Marko | 87b7c52 | 2015-04-08 10:01:01 +0100 | [diff] [blame] | 140 | |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 141 | compiler_driver->GetResolvedMethodDexFileLocation(resolved_method, |
| 142 | &it->declaring_dex_file_, &it->declaring_class_idx_, &it->declaring_method_idx_); |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 143 | if (!it->IsQuickened()) { |
| 144 | // For quickened invoke virtuals we may have desharpened to an interface method which |
| 145 | // wont give us the right method index, in this case blindly dispatch or else we can't |
| 146 | // compile the method. Converting the invoke to interface dispatch doesn't work since we |
| 147 | // have no way to get the dex method index for quickened invoke virtuals in the interface |
| 148 | // trampolines. |
| 149 | it->vtable_idx_ = |
| 150 | compiler_driver->GetResolvedMethodVTableIndex(resolved_method, invoke_type); |
| 151 | } |
Vladimir Marko | 87b7c52 | 2015-04-08 10:01:01 +0100 | [diff] [blame] | 152 | |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 153 | MethodReference target_method(it->target_dex_file_, it->target_method_idx_); |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 154 | int fast_path_flags = compiler_driver->IsFastInvoke( |
Mathieu Chartier | 091d238 | 2015-03-06 10:59:06 -0800 | [diff] [blame] | 155 | soa, current_dex_cache, class_loader, mUnit, referrer_class.Get(), resolved_method, |
Mathieu Chartier | e5f13e5 | 2015-02-24 09:37:21 -0800 | [diff] [blame] | 156 | &invoke_type, &target_method, devirt_target, &it->direct_code_, &it->direct_method_); |
| 157 | const bool is_referrers_class = referrer_class.Get() == resolved_method->GetDeclaringClass(); |
| 158 | const bool is_class_initialized = |
Vladimir Marko | 66c6d7b | 2014-10-16 15:41:48 +0100 | [diff] [blame] | 159 | compiler_driver->IsMethodsClassInitialized(referrer_class.Get(), resolved_method); |
Vladimir Marko | 87b7c52 | 2015-04-08 10:01:01 +0100 | [diff] [blame] | 160 | |
| 161 | // Check if the target method is intrinsic or special. |
| 162 | InlineMethodFlags is_intrinsic_or_special = kNoInlineMethodFlags; |
| 163 | if (inliner_map != nullptr) { |
| 164 | auto* inliner = (target_method.dex_file == dex_file) |
| 165 | ? default_inliner |
| 166 | : inliner_map->GetMethodInliner(target_method.dex_file); |
| 167 | is_intrinsic_or_special = inliner->IsIntrinsicOrSpecial(target_method.dex_method_index); |
| 168 | } |
| 169 | |
Vladimir Marko | 9820b7c | 2014-01-02 16:40:37 +0000 | [diff] [blame] | 170 | uint16_t other_flags = it->flags_ & |
Vladimir Marko | 87b7c52 | 2015-04-08 10:01:01 +0100 | [diff] [blame] | 171 | ~(kFlagFastPath | kFlagIsIntrinsic | kFlagIsSpecial | kFlagClassIsInitialized | |
| 172 | (kInvokeTypeMask << kBitSharpTypeBegin)); |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 173 | it->flags_ = other_flags | |
Jeff Hao | a412964 | 2015-05-06 17:41:32 -0700 | [diff] [blame] | 174 | // String init path is a special always-fast path. |
| 175 | (fast_path_flags != 0 || string_init ? kFlagFastPath : 0u) | |
Vladimir Marko | 87b7c52 | 2015-04-08 10:01:01 +0100 | [diff] [blame] | 176 | ((is_intrinsic_or_special & kInlineIntrinsic) != 0 ? kFlagIsIntrinsic : 0u) | |
| 177 | ((is_intrinsic_or_special & kInlineSpecial) != 0 ? kFlagIsSpecial : 0u) | |
Vladimir Marko | 9820b7c | 2014-01-02 16:40:37 +0000 | [diff] [blame] | 178 | (static_cast<uint16_t>(invoke_type) << kBitSharpTypeBegin) | |
Vladimir Marko | 66c6d7b | 2014-10-16 15:41:48 +0100 | [diff] [blame] | 179 | (is_referrers_class ? kFlagIsReferrersClass : 0u) | |
| 180 | (is_class_initialized ? kFlagClassIsInitialized : 0u); |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 181 | it->target_dex_file_ = target_method.dex_file; |
| 182 | it->target_method_idx_ = target_method.dex_method_index; |
| 183 | it->stats_flags_ = fast_path_flags; |
Jeff Hao | 848f70a | 2014-01-15 13:49:50 -0800 | [diff] [blame] | 184 | if (string_init) { |
| 185 | it->direct_code_ = 0; |
| 186 | } |
Vladimir Marko | f096aad | 2014-01-23 15:51:58 +0000 | [diff] [blame] | 187 | } |
| 188 | } |
| 189 | |
| 190 | } // namespace art |