1 /* 2 * Copyright (C) 2015 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 "sharpening.h" 18 19 #include "art_method-inl.h" 20 #include "base/casts.h" 21 #include "base/enums.h" 22 #include "class_linker.h" 23 #include "code_generator.h" 24 #include "driver/compiler_driver.h" 25 #include "driver/compiler_options.h" 26 #include "driver/dex_compilation_unit.h" 27 #include "gc/heap.h" 28 #include "gc/space/image_space.h" 29 #include "handle_scope-inl.h" 30 #include "mirror/dex_cache.h" 31 #include "mirror/string.h" 32 #include "nodes.h" 33 #include "runtime.h" 34 #include "scoped_thread_state_change-inl.h" 35 #include "utils/dex_cache_arrays_layout-inl.h" 36 37 namespace art { 38 39 void HSharpening::Run() { 40 // We don't care about the order of the blocks here. 41 for (HBasicBlock* block : graph_->GetReversePostOrder()) { 42 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { 43 HInstruction* instruction = it.Current(); 44 if (instruction->IsInvokeStaticOrDirect()) { 45 SharpenInvokeStaticOrDirect(instruction->AsInvokeStaticOrDirect(), 46 codegen_, 47 compiler_driver_); 48 } 49 // TODO: Move the sharpening of invoke-virtual/-interface/-super from HGraphBuilder 50 // here. Rewrite it to avoid the CompilerDriver's reliance on verifier data 51 // because we know the type better when inlining. 52 } 53 } 54 } 55 56 static bool IsInBootImage(ArtMethod* method) { 57 const std::vector<gc::space::ImageSpace*>& image_spaces = 58 Runtime::Current()->GetHeap()->GetBootImageSpaces(); 59 for (gc::space::ImageSpace* image_space : image_spaces) { 60 const ImageSection& method_section = image_space->GetImageHeader().GetMethodsSection(); 61 if (method_section.Contains(reinterpret_cast<uint8_t*>(method) - image_space->Begin())) { 62 return true; 63 } 64 } 65 return false; 66 } 67 68 static bool AOTCanEmbedMethod(ArtMethod* method, const CompilerOptions& options) { 69 return IsInBootImage(method) && !options.GetCompilePic(); 70 } 71 72 static bool BootImageAOTCanEmbedMethod(ArtMethod* method, CompilerDriver* compiler_driver) { 73 DCHECK(compiler_driver->GetCompilerOptions().IsBootImage()); 74 if (!compiler_driver->GetSupportBootImageFixup()) { 75 return false; 76 } 77 ScopedObjectAccess soa(Thread::Current()); 78 ObjPtr<mirror::Class> klass = method->GetDeclaringClass(); 79 DCHECK(klass != nullptr); 80 const DexFile& dex_file = klass->GetDexFile(); 81 return compiler_driver->IsImageClass(dex_file.StringByTypeIdx(klass->GetDexTypeIndex())); 82 } 83 84 void HSharpening::SharpenInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke, 85 CodeGenerator* codegen, 86 CompilerDriver* compiler_driver) { 87 if (invoke->IsStringInit()) { 88 // Not using the dex cache arrays. But we could still try to use a better dispatch... 89 // TODO: Use direct_method and direct_code for the appropriate StringFactory method. 90 return; 91 } 92 93 ArtMethod* callee = invoke->GetResolvedMethod(); 94 DCHECK(callee != nullptr); 95 96 HInvokeStaticOrDirect::MethodLoadKind method_load_kind; 97 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location; 98 uint64_t method_load_data = 0u; 99 100 // Note: we never call an ArtMethod through a known code pointer, as 101 // we do not want to keep on invoking it if it gets deoptimized. This 102 // applies to both AOT and JIT. 103 // This also avoids having to find out if the code pointer of an ArtMethod 104 // is the resolution trampoline (for ensuring the class is initialized), or 105 // the interpreter entrypoint. Such code pointers we do not want to call 106 // directly. 107 // Only in the case of a recursive call can we call directly, as we know the 108 // class is initialized already or being initialized, and the call will not 109 // be invoked once the method is deoptimized. 110 111 // We don't optimize for debuggable as it would prevent us from obsoleting the method in some 112 // situations. 113 if (callee == codegen->GetGraph()->GetArtMethod() && !codegen->GetGraph()->IsDebuggable()) { 114 // Recursive call. 115 method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kRecursive; 116 code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallSelf; 117 } else if (Runtime::Current()->UseJitCompilation() || 118 AOTCanEmbedMethod(callee, codegen->GetCompilerOptions())) { 119 // JIT or on-device AOT compilation referencing a boot image method. 120 // Use the method address directly. 121 method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress; 122 method_load_data = reinterpret_cast<uintptr_t>(callee); 123 code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod; 124 } else if (codegen->GetCompilerOptions().IsBootImage() && 125 BootImageAOTCanEmbedMethod(callee, compiler_driver)) { 126 method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative; 127 code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod; 128 } else { 129 // Use PC-relative access to the .bss methods arrays. 130 method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBssEntry; 131 code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod; 132 } 133 134 if (codegen->GetGraph()->IsDebuggable()) { 135 // For debuggable apps always use the code pointer from ArtMethod 136 // so that we don't circumvent instrumentation stubs if installed. 137 code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod; 138 } 139 140 HInvokeStaticOrDirect::DispatchInfo desired_dispatch_info = { 141 method_load_kind, code_ptr_location, method_load_data 142 }; 143 HInvokeStaticOrDirect::DispatchInfo dispatch_info = 144 codegen->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info, invoke); 145 invoke->SetDispatchInfo(dispatch_info); 146 } 147 148 HLoadClass::LoadKind HSharpening::ComputeLoadClassKind( 149 HLoadClass* load_class, 150 CodeGenerator* codegen, 151 CompilerDriver* compiler_driver, 152 const DexCompilationUnit& dex_compilation_unit) { 153 Handle<mirror::Class> klass = load_class->GetClass(); 154 DCHECK(load_class->GetLoadKind() == HLoadClass::LoadKind::kRuntimeCall || 155 load_class->GetLoadKind() == HLoadClass::LoadKind::kReferrersClass) 156 << load_class->GetLoadKind(); 157 DCHECK(!load_class->IsInBootImage()) << "HLoadClass should not be optimized before sharpening."; 158 159 HLoadClass::LoadKind load_kind = load_class->GetLoadKind(); 160 161 if (load_class->NeedsAccessCheck()) { 162 // We need to call the runtime anyway, so we simply get the class as that call's return value. 163 } else if (load_kind == HLoadClass::LoadKind::kReferrersClass) { 164 // Loading from the ArtMethod* is the most efficient retrieval in code size. 165 // TODO: This may not actually be true for all architectures and 166 // locations of target classes. The additional register pressure 167 // for using the ArtMethod* should be considered. 168 } else { 169 const DexFile& dex_file = load_class->GetDexFile(); 170 dex::TypeIndex type_index = load_class->GetTypeIndex(); 171 172 bool is_in_boot_image = false; 173 HLoadClass::LoadKind desired_load_kind = HLoadClass::LoadKind::kInvalid; 174 Runtime* runtime = Runtime::Current(); 175 if (codegen->GetCompilerOptions().IsBootImage()) { 176 // Compiling boot image. Check if the class is a boot image class. 177 DCHECK(!runtime->UseJitCompilation()); 178 if (!compiler_driver->GetSupportBootImageFixup()) { 179 // compiler_driver_test. Do not sharpen. 180 desired_load_kind = HLoadClass::LoadKind::kRuntimeCall; 181 } else if ((klass != nullptr) && 182 compiler_driver->IsImageClass(dex_file.StringByTypeIdx(type_index))) { 183 is_in_boot_image = true; 184 desired_load_kind = HLoadClass::LoadKind::kBootImageLinkTimePcRelative; 185 } else { 186 // Not a boot image class. 187 DCHECK(ContainsElement(compiler_driver->GetDexFilesForOatFile(), &dex_file)); 188 desired_load_kind = HLoadClass::LoadKind::kBssEntry; 189 } 190 } else { 191 is_in_boot_image = (klass != nullptr) && 192 runtime->GetHeap()->ObjectIsInBootImageSpace(klass.Get()); 193 if (runtime->UseJitCompilation()) { 194 DCHECK(!codegen->GetCompilerOptions().GetCompilePic()); 195 if (is_in_boot_image) { 196 // TODO: Use direct pointers for all non-moving spaces, not just boot image. Bug: 29530787 197 desired_load_kind = HLoadClass::LoadKind::kBootImageAddress; 198 } else if (klass != nullptr) { 199 desired_load_kind = HLoadClass::LoadKind::kJitTableAddress; 200 } else { 201 // Class not loaded yet. This happens when the dex code requesting 202 // this `HLoadClass` hasn't been executed in the interpreter. 203 // Fallback to the dex cache. 204 // TODO(ngeoffray): Generate HDeoptimize instead. 205 desired_load_kind = HLoadClass::LoadKind::kRuntimeCall; 206 } 207 } else if (is_in_boot_image) { 208 // AOT app compilation, boot image class. 209 if (codegen->GetCompilerOptions().GetCompilePic()) { 210 desired_load_kind = HLoadClass::LoadKind::kBootImageClassTable; 211 } else { 212 desired_load_kind = HLoadClass::LoadKind::kBootImageAddress; 213 } 214 } else { 215 // Not JIT and the klass is not in boot image. 216 desired_load_kind = HLoadClass::LoadKind::kBssEntry; 217 } 218 } 219 DCHECK_NE(desired_load_kind, HLoadClass::LoadKind::kInvalid); 220 221 if (is_in_boot_image) { 222 load_class->MarkInBootImage(); 223 } 224 load_kind = codegen->GetSupportedLoadClassKind(desired_load_kind); 225 } 226 227 if (!IsSameDexFile(load_class->GetDexFile(), *dex_compilation_unit.GetDexFile())) { 228 if ((load_kind == HLoadClass::LoadKind::kRuntimeCall) || 229 (load_kind == HLoadClass::LoadKind::kBssEntry)) { 230 // We actually cannot reference this class, we're forced to bail. 231 // We cannot reference this class with Bss, as the entrypoint will lookup the class 232 // in the caller's dex file, but that dex file does not reference the class. 233 return HLoadClass::LoadKind::kInvalid; 234 } 235 } 236 return load_kind; 237 } 238 239 void HSharpening::ProcessLoadString( 240 HLoadString* load_string, 241 CodeGenerator* codegen, 242 CompilerDriver* compiler_driver, 243 const DexCompilationUnit& dex_compilation_unit, 244 VariableSizedHandleScope* handles) { 245 DCHECK_EQ(load_string->GetLoadKind(), HLoadString::LoadKind::kRuntimeCall); 246 247 const DexFile& dex_file = load_string->GetDexFile(); 248 dex::StringIndex string_index = load_string->GetStringIndex(); 249 250 HLoadString::LoadKind desired_load_kind = static_cast<HLoadString::LoadKind>(-1); 251 { 252 Runtime* runtime = Runtime::Current(); 253 ClassLinker* class_linker = runtime->GetClassLinker(); 254 ScopedObjectAccess soa(Thread::Current()); 255 StackHandleScope<1> hs(soa.Self()); 256 Handle<mirror::DexCache> dex_cache = IsSameDexFile(dex_file, *dex_compilation_unit.GetDexFile()) 257 ? dex_compilation_unit.GetDexCache() 258 : hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file)); 259 ObjPtr<mirror::String> string = nullptr; 260 261 if (codegen->GetCompilerOptions().IsBootImage()) { 262 // Compiling boot image. Resolve the string and allocate it if needed, to ensure 263 // the string will be added to the boot image. 264 DCHECK(!runtime->UseJitCompilation()); 265 string = class_linker->ResolveString(string_index, dex_cache); 266 CHECK(string != nullptr); 267 if (compiler_driver->GetSupportBootImageFixup()) { 268 DCHECK(ContainsElement(compiler_driver->GetDexFilesForOatFile(), &dex_file)); 269 desired_load_kind = HLoadString::LoadKind::kBootImageLinkTimePcRelative; 270 } else { 271 // compiler_driver_test. Do not sharpen. 272 desired_load_kind = HLoadString::LoadKind::kRuntimeCall; 273 } 274 } else if (runtime->UseJitCompilation()) { 275 DCHECK(!codegen->GetCompilerOptions().GetCompilePic()); 276 string = class_linker->LookupString(string_index, dex_cache.Get()); 277 if (string != nullptr) { 278 if (runtime->GetHeap()->ObjectIsInBootImageSpace(string)) { 279 desired_load_kind = HLoadString::LoadKind::kBootImageAddress; 280 } else { 281 desired_load_kind = HLoadString::LoadKind::kJitTableAddress; 282 } 283 } else { 284 desired_load_kind = HLoadString::LoadKind::kRuntimeCall; 285 } 286 } else { 287 // AOT app compilation. Try to lookup the string without allocating if not found. 288 string = class_linker->LookupString(string_index, dex_cache.Get()); 289 if (string != nullptr && runtime->GetHeap()->ObjectIsInBootImageSpace(string)) { 290 if (codegen->GetCompilerOptions().GetCompilePic()) { 291 desired_load_kind = HLoadString::LoadKind::kBootImageInternTable; 292 } else { 293 desired_load_kind = HLoadString::LoadKind::kBootImageAddress; 294 } 295 } else { 296 desired_load_kind = HLoadString::LoadKind::kBssEntry; 297 } 298 } 299 if (string != nullptr) { 300 load_string->SetString(handles->NewHandle(string)); 301 } 302 } 303 DCHECK_NE(desired_load_kind, static_cast<HLoadString::LoadKind>(-1)); 304 305 HLoadString::LoadKind load_kind = codegen->GetSupportedLoadStringKind(desired_load_kind); 306 load_string->SetLoadKind(load_kind); 307 } 308 309 } // namespace art 310