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 "base/logging.h"
23 #include "class_linker.h"
24 #include "code_generator.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 "jit/jit.h"
31 #include "mirror/dex_cache.h"
32 #include "mirror/string.h"
33 #include "nodes.h"
34 #include "runtime.h"
35 #include "scoped_thread_state_change-inl.h"
36 
37 namespace art {
38 
IsInBootImage(ArtMethod * method)39 static bool IsInBootImage(ArtMethod* method) {
40   gc::Heap* heap = Runtime::Current()->GetHeap();
41   DCHECK_EQ(heap->IsBootImageAddress(method),
42             std::any_of(heap->GetBootImageSpaces().begin(),
43                         heap->GetBootImageSpaces().end(),
44                         [=](gc::space::ImageSpace* space) REQUIRES_SHARED(Locks::mutator_lock_) {
45                           return space->GetImageHeader().GetMethodsSection().Contains(
46                               reinterpret_cast<uint8_t*>(method) - space->Begin());
47                         }));
48   return heap->IsBootImageAddress(method);
49 }
50 
BootImageAOTCanEmbedMethod(ArtMethod * method,const CompilerOptions & compiler_options)51 static bool BootImageAOTCanEmbedMethod(ArtMethod* method, const CompilerOptions& compiler_options) {
52   DCHECK(compiler_options.IsBootImage() || compiler_options.IsBootImageExtension());
53   ScopedObjectAccess soa(Thread::Current());
54   ObjPtr<mirror::Class> klass = method->GetDeclaringClass();
55   DCHECK(klass != nullptr);
56   const DexFile& dex_file = klass->GetDexFile();
57   return compiler_options.IsImageClass(dex_file.StringByTypeIdx(klass->GetDexTypeIndex()));
58 }
59 
SharpenInvokeStaticOrDirect(ArtMethod * callee,CodeGenerator * codegen)60 HInvokeStaticOrDirect::DispatchInfo HSharpening::SharpenInvokeStaticOrDirect(
61     ArtMethod* callee, CodeGenerator* codegen) {
62   if (kIsDebugBuild) {
63     ScopedObjectAccess soa(Thread::Current());  // Required for GetDeclaringClass below.
64     DCHECK(callee != nullptr);
65     DCHECK(!(callee->IsConstructor() && callee->GetDeclaringClass()->IsStringClass()));
66   }
67 
68   HInvokeStaticOrDirect::MethodLoadKind method_load_kind;
69   HInvokeStaticOrDirect::CodePtrLocation code_ptr_location;
70   uint64_t method_load_data = 0u;
71 
72   // Note: we never call an ArtMethod through a known code pointer, as
73   // we do not want to keep on invoking it if it gets deoptimized. This
74   // applies to both AOT and JIT.
75   // This also avoids having to find out if the code pointer of an ArtMethod
76   // is the resolution trampoline (for ensuring the class is initialized), or
77   // the interpreter entrypoint. Such code pointers we do not want to call
78   // directly.
79   // Only in the case of a recursive call can we call directly, as we know the
80   // class is initialized already or being initialized, and the call will not
81   // be invoked once the method is deoptimized.
82 
83   // We don't optimize for debuggable as it would prevent us from obsoleting the method in some
84   // situations.
85   const CompilerOptions& compiler_options = codegen->GetCompilerOptions();
86   if (callee == codegen->GetGraph()->GetArtMethod() && !codegen->GetGraph()->IsDebuggable()) {
87     // Recursive call.
88     method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kRecursive;
89     code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallSelf;
90   } else if (compiler_options.IsBootImage() || compiler_options.IsBootImageExtension()) {
91     if (!compiler_options.GetCompilePic()) {
92       // Test configuration, do not sharpen.
93       method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall;
94     } else if (IsInBootImage(callee)) {
95       DCHECK(compiler_options.IsBootImageExtension());
96       method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBootImageRelRo;
97     } else if (BootImageAOTCanEmbedMethod(callee, compiler_options)) {
98       method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative;
99     } else {
100       // Use PC-relative access to the .bss methods array.
101       method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBssEntry;
102     }
103     code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
104   } else if (compiler_options.IsJitCompiler()) {
105     ScopedObjectAccess soa(Thread::Current());
106     if (Runtime::Current()->GetJit()->CanEncodeMethod(
107             callee,
108             compiler_options.IsJitCompilerForSharedCode())) {
109       method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kJitDirectAddress;
110       method_load_data = reinterpret_cast<uintptr_t>(callee);
111       code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
112     } else {
113       // Do not sharpen.
114       method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall;
115       code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
116     }
117   } else if (IsInBootImage(callee)) {
118     // Use PC-relative access to the .data.bimg.rel.ro methods array.
119     method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBootImageRelRo;
120     code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
121   } else {
122     // Use PC-relative access to the .bss methods array.
123     method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBssEntry;
124     code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
125   }
126 
127   if (method_load_kind != HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall &&
128       callee->IsCriticalNative()) {
129     DCHECK_NE(method_load_kind, HInvokeStaticOrDirect::MethodLoadKind::kRecursive);
130     DCHECK(callee->IsStatic());
131     code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallCriticalNative;
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   return codegen->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info, callee);
144 }
145 
ComputeLoadClassKind(HLoadClass * load_class,CodeGenerator * codegen,const DexCompilationUnit & dex_compilation_unit)146 HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(
147     HLoadClass* load_class,
148     CodeGenerator* codegen,
149     const DexCompilationUnit& dex_compilation_unit) {
150   Handle<mirror::Class> klass = load_class->GetClass();
151   DCHECK(load_class->GetLoadKind() == HLoadClass::LoadKind::kRuntimeCall ||
152          load_class->GetLoadKind() == HLoadClass::LoadKind::kReferrersClass)
153       << load_class->GetLoadKind();
154   DCHECK(!load_class->IsInBootImage()) << "HLoadClass should not be optimized before sharpening.";
155 
156   HLoadClass::LoadKind load_kind = load_class->GetLoadKind();
157 
158   if (load_class->NeedsAccessCheck()) {
159     // We need to call the runtime anyway, so we simply get the class as that call's return value.
160   } else if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
161     // Loading from the ArtMethod* is the most efficient retrieval in code size.
162     // TODO: This may not actually be true for all architectures and
163     // locations of target classes. The additional register pressure
164     // for using the ArtMethod* should be considered.
165   } else {
166     const DexFile& dex_file = load_class->GetDexFile();
167     dex::TypeIndex type_index = load_class->GetTypeIndex();
168 
169     bool is_in_boot_image = false;
170     HLoadClass::LoadKind desired_load_kind = HLoadClass::LoadKind::kInvalid;
171     Runtime* runtime = Runtime::Current();
172     const CompilerOptions& compiler_options = codegen->GetCompilerOptions();
173     if (compiler_options.IsBootImage() || compiler_options.IsBootImageExtension()) {
174       // Compiling boot image or boot image extension. Check if the class is a boot image class.
175       DCHECK(!compiler_options.IsJitCompiler());
176       if (!compiler_options.GetCompilePic()) {
177         // Test configuration, do not sharpen.
178         desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
179       } else if (klass != nullptr && runtime->GetHeap()->ObjectIsInBootImageSpace(klass.Get())) {
180         DCHECK(compiler_options.IsBootImageExtension());
181         is_in_boot_image = true;
182         desired_load_kind = HLoadClass::LoadKind::kBootImageRelRo;
183       } else if ((klass != nullptr) &&
184                  compiler_options.IsImageClass(dex_file.StringByTypeIdx(type_index))) {
185         is_in_boot_image = true;
186         desired_load_kind = HLoadClass::LoadKind::kBootImageLinkTimePcRelative;
187       } else {
188         // Not a boot image class.
189         desired_load_kind = HLoadClass::LoadKind::kBssEntry;
190       }
191     } else {
192       is_in_boot_image = (klass != nullptr) &&
193           runtime->GetHeap()->ObjectIsInBootImageSpace(klass.Get());
194       if (compiler_options.IsJitCompiler()) {
195         DCHECK(!compiler_options.GetCompilePic());
196         if (is_in_boot_image) {
197           desired_load_kind = HLoadClass::LoadKind::kJitBootImageAddress;
198         } else if (klass != nullptr) {
199           if (runtime->GetJit()->CanEncodeClass(
200                   klass.Get(),
201                   compiler_options.IsJitCompilerForSharedCode())) {
202             desired_load_kind = HLoadClass::LoadKind::kJitTableAddress;
203           } else {
204             // Shared JIT code cannot encode a literal that the GC can move.
205             VLOG(jit) << "Unable to encode in shared region class literal: "
206                       << klass->PrettyClass();
207             desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
208           }
209         } else {
210           // Class not loaded yet. This happens when the dex code requesting
211           // this `HLoadClass` hasn't been executed in the interpreter.
212           // Fallback to the dex cache.
213           // TODO(ngeoffray): Generate HDeoptimize instead.
214           desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
215         }
216       } else if (is_in_boot_image) {
217         // AOT app compilation, boot image class.
218         desired_load_kind = HLoadClass::LoadKind::kBootImageRelRo;
219       } else {
220         // Not JIT and the klass is not in boot image.
221         desired_load_kind = HLoadClass::LoadKind::kBssEntry;
222       }
223     }
224     DCHECK_NE(desired_load_kind, HLoadClass::LoadKind::kInvalid);
225 
226     if (is_in_boot_image) {
227       load_class->MarkInBootImage();
228     }
229     load_kind = codegen->GetSupportedLoadClassKind(desired_load_kind);
230   }
231 
232   if (!IsSameDexFile(load_class->GetDexFile(), *dex_compilation_unit.GetDexFile())) {
233     if ((load_kind == HLoadClass::LoadKind::kRuntimeCall) ||
234         (load_kind == HLoadClass::LoadKind::kBssEntry)) {
235       // We actually cannot reference this class, we're forced to bail.
236       // We cannot reference this class with Bss, as the entrypoint will lookup the class
237       // in the caller's dex file, but that dex file does not reference the class.
238       return HLoadClass::LoadKind::kInvalid;
239     }
240   }
241   return load_kind;
242 }
243 
CanUseTypeCheckBitstring(ObjPtr<mirror::Class> klass,CodeGenerator * codegen)244 static inline bool CanUseTypeCheckBitstring(ObjPtr<mirror::Class> klass, CodeGenerator* codegen)
245     REQUIRES_SHARED(Locks::mutator_lock_) {
246   DCHECK(!klass->IsProxyClass());
247   DCHECK(!klass->IsArrayClass());
248 
249   const CompilerOptions& compiler_options = codegen->GetCompilerOptions();
250   if (compiler_options.IsJitCompiler()) {
251     // If we're JITting, try to assign a type check bitstring (fall through).
252   } else if (codegen->GetCompilerOptions().IsBootImage()) {
253     const char* descriptor = klass->GetDexFile().StringByTypeIdx(klass->GetDexTypeIndex());
254     if (!codegen->GetCompilerOptions().IsImageClass(descriptor)) {
255       return false;
256     }
257     // If the target is a boot image class, try to assign a type check bitstring (fall through).
258     // (If --force-determinism, this was already done; repeating is OK and yields the same result.)
259   } else {
260     // TODO: Use the bitstring also for AOT app compilation if the target class has a bitstring
261     // already assigned in the boot image.
262     return false;
263   }
264 
265   // Try to assign a type check bitstring.
266   MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
267   if ((false) &&  // FIXME: Inliner does not respect CompilerDriver::ShouldCompileMethod()
268                   // and we're hitting an unassigned bitstring in dex2oat_image_test. b/26687569
269       kIsDebugBuild &&
270       compiler_options.IsBootImage() &&
271       compiler_options.IsForceDeterminism()) {
272     SubtypeCheckInfo::State old_state = SubtypeCheck<ObjPtr<mirror::Class>>::GetState(klass);
273     CHECK(old_state == SubtypeCheckInfo::kAssigned || old_state == SubtypeCheckInfo::kOverflowed)
274         << klass->PrettyDescriptor() << "/" << old_state
275         << " in " << codegen->GetGraph()->PrettyMethod();
276   }
277   SubtypeCheckInfo::State state = SubtypeCheck<ObjPtr<mirror::Class>>::EnsureAssigned(klass);
278   return state == SubtypeCheckInfo::kAssigned;
279 }
280 
ComputeTypeCheckKind(ObjPtr<mirror::Class> klass,CodeGenerator * codegen,bool needs_access_check)281 TypeCheckKind HSharpening::ComputeTypeCheckKind(ObjPtr<mirror::Class> klass,
282                                                 CodeGenerator* codegen,
283                                                 bool needs_access_check) {
284   if (klass == nullptr) {
285     return TypeCheckKind::kUnresolvedCheck;
286   } else if (klass->IsInterface()) {
287     return TypeCheckKind::kInterfaceCheck;
288   } else if (klass->IsArrayClass()) {
289     if (klass->GetComponentType()->IsObjectClass()) {
290       return TypeCheckKind::kArrayObjectCheck;
291     } else if (klass->CannotBeAssignedFromOtherTypes()) {
292       return TypeCheckKind::kExactCheck;
293     } else {
294       return TypeCheckKind::kArrayCheck;
295     }
296   } else if (klass->IsFinal()) {  // TODO: Consider using bitstring for final classes.
297     return TypeCheckKind::kExactCheck;
298   } else if (kBitstringSubtypeCheckEnabled &&
299              !needs_access_check &&
300              CanUseTypeCheckBitstring(klass, codegen)) {
301     // TODO: We should not need the `!needs_access_check` check but getting rid of that
302     // requires rewriting some optimizations in instruction simplifier.
303     return TypeCheckKind::kBitstringCheck;
304   } else if (klass->IsAbstract()) {
305     return TypeCheckKind::kAbstractClassCheck;
306   } else {
307     return TypeCheckKind::kClassHierarchyCheck;
308   }
309 }
310 
ProcessLoadString(HLoadString * load_string,CodeGenerator * codegen,const DexCompilationUnit & dex_compilation_unit,VariableSizedHandleScope * handles)311 void HSharpening::ProcessLoadString(
312     HLoadString* load_string,
313     CodeGenerator* codegen,
314     const DexCompilationUnit& dex_compilation_unit,
315     VariableSizedHandleScope* handles) {
316   DCHECK_EQ(load_string->GetLoadKind(), HLoadString::LoadKind::kRuntimeCall);
317 
318   const DexFile& dex_file = load_string->GetDexFile();
319   dex::StringIndex string_index = load_string->GetStringIndex();
320 
321   HLoadString::LoadKind desired_load_kind = static_cast<HLoadString::LoadKind>(-1);
322   {
323     Runtime* runtime = Runtime::Current();
324     ClassLinker* class_linker = runtime->GetClassLinker();
325     ScopedObjectAccess soa(Thread::Current());
326     StackHandleScope<1> hs(soa.Self());
327     Handle<mirror::DexCache> dex_cache = IsSameDexFile(dex_file, *dex_compilation_unit.GetDexFile())
328         ? dex_compilation_unit.GetDexCache()
329         : hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file));
330     ObjPtr<mirror::String> string = nullptr;
331 
332     const CompilerOptions& compiler_options = codegen->GetCompilerOptions();
333     if (compiler_options.IsBootImage() || compiler_options.IsBootImageExtension()) {
334       // Compiling boot image or boot image extension. Resolve the string and allocate it
335       // if needed, to ensure the string will be added to the boot image.
336       DCHECK(!compiler_options.IsJitCompiler());
337       if (compiler_options.GetCompilePic()) {
338         if (compiler_options.IsForceDeterminism()) {
339           // Strings for methods we're compiling should be pre-resolved but Strings in inlined
340           // methods may not be if these inlined methods are not in the boot image profile.
341           // Multiple threads allocating new Strings can cause non-deterministic boot image
342           // because of the image relying on the order of GC roots we walk. (We could fix that
343           // by ordering the roots we walk in ImageWriter.) Therefore we avoid allocating these
344           // strings even if that results in omitting them from the boot image and using the
345           // sub-optimal load kind kBssEntry.
346           string = class_linker->LookupString(string_index, dex_cache.Get());
347         } else {
348           string = class_linker->ResolveString(string_index, dex_cache);
349           CHECK(string != nullptr);
350         }
351         if (string != nullptr) {
352           if (runtime->GetHeap()->ObjectIsInBootImageSpace(string)) {
353             DCHECK(compiler_options.IsBootImageExtension());
354             desired_load_kind = HLoadString::LoadKind::kBootImageRelRo;
355           } else {
356             desired_load_kind = HLoadString::LoadKind::kBootImageLinkTimePcRelative;
357           }
358         } else {
359           desired_load_kind = HLoadString::LoadKind::kBssEntry;
360         }
361       } else {
362         // Test configuration, do not sharpen.
363         desired_load_kind = HLoadString::LoadKind::kRuntimeCall;
364       }
365     } else if (compiler_options.IsJitCompiler()) {
366       DCHECK(!codegen->GetCompilerOptions().GetCompilePic());
367       string = class_linker->LookupString(string_index, dex_cache.Get());
368       if (string != nullptr) {
369         gc::Heap* heap = runtime->GetHeap();
370         if (heap->ObjectIsInBootImageSpace(string)) {
371           desired_load_kind = HLoadString::LoadKind::kJitBootImageAddress;
372         } else if (runtime->GetJit()->CanEncodeString(
373                   string,
374                   compiler_options.IsJitCompilerForSharedCode())) {
375           desired_load_kind = HLoadString::LoadKind::kJitTableAddress;
376         } else {
377           // Shared JIT code cannot encode a literal that the GC can move.
378           VLOG(jit) << "Unable to encode in shared region string literal: "
379                     << string->ToModifiedUtf8();
380           desired_load_kind = HLoadString::LoadKind::kRuntimeCall;
381         }
382       } else {
383         desired_load_kind = HLoadString::LoadKind::kRuntimeCall;
384       }
385     } else {
386       // AOT app compilation. Try to lookup the string without allocating if not found.
387       string = class_linker->LookupString(string_index, dex_cache.Get());
388       if (string != nullptr && runtime->GetHeap()->ObjectIsInBootImageSpace(string)) {
389         desired_load_kind = HLoadString::LoadKind::kBootImageRelRo;
390       } else {
391         desired_load_kind = HLoadString::LoadKind::kBssEntry;
392       }
393     }
394     if (string != nullptr) {
395       load_string->SetString(handles->NewHandle(string));
396     }
397   }
398   DCHECK_NE(desired_load_kind, static_cast<HLoadString::LoadKind>(-1));
399 
400   HLoadString::LoadKind load_kind = codegen->GetSupportedLoadStringKind(desired_load_kind);
401   load_string->SetLoadKind(load_kind);
402 }
403 
404 }  // namespace art
405