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 (Runtime::Current()->UseJitCompilation()) {
105     ScopedObjectAccess soa(Thread::Current());
106     if (Runtime::Current()->GetJit()->CanEncodeMethod(
107             callee,
108             codegen->GetGraph()->IsCompilingForSharedJitCode())) {
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 (codegen->GetGraph()->IsDebuggable()) {
128     // For debuggable apps always use the code pointer from ArtMethod
129     // so that we don't circumvent instrumentation stubs if installed.
130     code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
131   }
132 
133   HInvokeStaticOrDirect::DispatchInfo desired_dispatch_info = {
134       method_load_kind, code_ptr_location, method_load_data
135   };
136   return codegen->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info, callee);
137 }
138 
ComputeLoadClassKind(HLoadClass * load_class,CodeGenerator * codegen,const DexCompilationUnit & dex_compilation_unit)139 HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(
140     HLoadClass* load_class,
141     CodeGenerator* codegen,
142     const DexCompilationUnit& dex_compilation_unit) {
143   Handle<mirror::Class> klass = load_class->GetClass();
144   DCHECK(load_class->GetLoadKind() == HLoadClass::LoadKind::kRuntimeCall ||
145          load_class->GetLoadKind() == HLoadClass::LoadKind::kReferrersClass)
146       << load_class->GetLoadKind();
147   DCHECK(!load_class->IsInBootImage()) << "HLoadClass should not be optimized before sharpening.";
148 
149   HLoadClass::LoadKind load_kind = load_class->GetLoadKind();
150 
151   if (load_class->NeedsAccessCheck()) {
152     // We need to call the runtime anyway, so we simply get the class as that call's return value.
153   } else if (load_kind == HLoadClass::LoadKind::kReferrersClass) {
154     // Loading from the ArtMethod* is the most efficient retrieval in code size.
155     // TODO: This may not actually be true for all architectures and
156     // locations of target classes. The additional register pressure
157     // for using the ArtMethod* should be considered.
158   } else {
159     const DexFile& dex_file = load_class->GetDexFile();
160     dex::TypeIndex type_index = load_class->GetTypeIndex();
161 
162     bool is_in_boot_image = false;
163     HLoadClass::LoadKind desired_load_kind = HLoadClass::LoadKind::kInvalid;
164     Runtime* runtime = Runtime::Current();
165     const CompilerOptions& compiler_options = codegen->GetCompilerOptions();
166     if (compiler_options.IsBootImage() || compiler_options.IsBootImageExtension()) {
167       // Compiling boot image or boot image extension. Check if the class is a boot image class.
168       DCHECK(!runtime->UseJitCompilation());
169       if (!compiler_options.GetCompilePic()) {
170         // Test configuration, do not sharpen.
171         desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
172       } else if (klass != nullptr && runtime->GetHeap()->ObjectIsInBootImageSpace(klass.Get())) {
173         DCHECK(compiler_options.IsBootImageExtension());
174         is_in_boot_image = true;
175         desired_load_kind = HLoadClass::LoadKind::kBootImageRelRo;
176       } else if ((klass != nullptr) &&
177                  compiler_options.IsImageClass(dex_file.StringByTypeIdx(type_index))) {
178         is_in_boot_image = true;
179         desired_load_kind = HLoadClass::LoadKind::kBootImageLinkTimePcRelative;
180       } else {
181         // Not a boot image class.
182         desired_load_kind = HLoadClass::LoadKind::kBssEntry;
183       }
184     } else {
185       is_in_boot_image = (klass != nullptr) &&
186           runtime->GetHeap()->ObjectIsInBootImageSpace(klass.Get());
187       if (runtime->UseJitCompilation()) {
188         DCHECK(!compiler_options.GetCompilePic());
189         if (is_in_boot_image) {
190           desired_load_kind = HLoadClass::LoadKind::kJitBootImageAddress;
191         } else if (klass != nullptr) {
192           if (runtime->GetJit()->CanEncodeClass(
193                   klass.Get(),
194                   codegen->GetGraph()->IsCompilingForSharedJitCode())) {
195             desired_load_kind = HLoadClass::LoadKind::kJitTableAddress;
196           } else {
197             // Shared JIT code cannot encode a literal that the GC can move.
198             VLOG(jit) << "Unable to encode in shared region class literal: "
199                       << klass->PrettyClass();
200             desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
201           }
202         } else {
203           // Class not loaded yet. This happens when the dex code requesting
204           // this `HLoadClass` hasn't been executed in the interpreter.
205           // Fallback to the dex cache.
206           // TODO(ngeoffray): Generate HDeoptimize instead.
207           desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
208         }
209       } else if (is_in_boot_image) {
210         // AOT app compilation, boot image class.
211         desired_load_kind = HLoadClass::LoadKind::kBootImageRelRo;
212       } else {
213         // Not JIT and the klass is not in boot image.
214         desired_load_kind = HLoadClass::LoadKind::kBssEntry;
215       }
216     }
217     DCHECK_NE(desired_load_kind, HLoadClass::LoadKind::kInvalid);
218 
219     if (is_in_boot_image) {
220       load_class->MarkInBootImage();
221     }
222     load_kind = codegen->GetSupportedLoadClassKind(desired_load_kind);
223   }
224 
225   if (!IsSameDexFile(load_class->GetDexFile(), *dex_compilation_unit.GetDexFile())) {
226     if ((load_kind == HLoadClass::LoadKind::kRuntimeCall) ||
227         (load_kind == HLoadClass::LoadKind::kBssEntry)) {
228       // We actually cannot reference this class, we're forced to bail.
229       // We cannot reference this class with Bss, as the entrypoint will lookup the class
230       // in the caller's dex file, but that dex file does not reference the class.
231       return HLoadClass::LoadKind::kInvalid;
232     }
233   }
234   return load_kind;
235 }
236 
CanUseTypeCheckBitstring(ObjPtr<mirror::Class> klass,CodeGenerator * codegen)237 static inline bool CanUseTypeCheckBitstring(ObjPtr<mirror::Class> klass, CodeGenerator* codegen)
238     REQUIRES_SHARED(Locks::mutator_lock_) {
239   DCHECK(!klass->IsProxyClass());
240   DCHECK(!klass->IsArrayClass());
241 
242   if (Runtime::Current()->UseJitCompilation()) {
243     // If we're JITting, try to assign a type check bitstring (fall through).
244   } else if (codegen->GetCompilerOptions().IsBootImage()) {
245     const char* descriptor = klass->GetDexFile().StringByTypeIdx(klass->GetDexTypeIndex());
246     if (!codegen->GetCompilerOptions().IsImageClass(descriptor)) {
247       return false;
248     }
249     // If the target is a boot image class, try to assign a type check bitstring (fall through).
250     // (If --force-determinism, this was already done; repeating is OK and yields the same result.)
251   } else {
252     // TODO: Use the bitstring also for AOT app compilation if the target class has a bitstring
253     // already assigned in the boot image.
254     return false;
255   }
256 
257   // Try to assign a type check bitstring.
258   MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
259   if ((false) &&  // FIXME: Inliner does not respect CompilerDriver::ShouldCompileMethod()
260                   // and we're hitting an unassigned bitstring in dex2oat_image_test. b/26687569
261       kIsDebugBuild &&
262       codegen->GetCompilerOptions().IsBootImage() &&
263       codegen->GetCompilerOptions().IsForceDeterminism()) {
264     SubtypeCheckInfo::State old_state = SubtypeCheck<ObjPtr<mirror::Class>>::GetState(klass);
265     CHECK(old_state == SubtypeCheckInfo::kAssigned || old_state == SubtypeCheckInfo::kOverflowed)
266         << klass->PrettyDescriptor() << "/" << old_state
267         << " in " << codegen->GetGraph()->PrettyMethod();
268   }
269   SubtypeCheckInfo::State state = SubtypeCheck<ObjPtr<mirror::Class>>::EnsureAssigned(klass);
270   return state == SubtypeCheckInfo::kAssigned;
271 }
272 
ComputeTypeCheckKind(ObjPtr<mirror::Class> klass,CodeGenerator * codegen,bool needs_access_check)273 TypeCheckKind HSharpening::ComputeTypeCheckKind(ObjPtr<mirror::Class> klass,
274                                                 CodeGenerator* codegen,
275                                                 bool needs_access_check) {
276   if (klass == nullptr) {
277     return TypeCheckKind::kUnresolvedCheck;
278   } else if (klass->IsInterface()) {
279     return TypeCheckKind::kInterfaceCheck;
280   } else if (klass->IsArrayClass()) {
281     if (klass->GetComponentType()->IsObjectClass()) {
282       return TypeCheckKind::kArrayObjectCheck;
283     } else if (klass->CannotBeAssignedFromOtherTypes()) {
284       return TypeCheckKind::kExactCheck;
285     } else {
286       return TypeCheckKind::kArrayCheck;
287     }
288   } else if (klass->IsFinal()) {  // TODO: Consider using bitstring for final classes.
289     return TypeCheckKind::kExactCheck;
290   } else if (kBitstringSubtypeCheckEnabled &&
291              !needs_access_check &&
292              CanUseTypeCheckBitstring(klass, codegen)) {
293     // TODO: We should not need the `!needs_access_check` check but getting rid of that
294     // requires rewriting some optimizations in instruction simplifier.
295     return TypeCheckKind::kBitstringCheck;
296   } else if (klass->IsAbstract()) {
297     return TypeCheckKind::kAbstractClassCheck;
298   } else {
299     return TypeCheckKind::kClassHierarchyCheck;
300   }
301 }
302 
ProcessLoadString(HLoadString * load_string,CodeGenerator * codegen,const DexCompilationUnit & dex_compilation_unit,VariableSizedHandleScope * handles)303 void HSharpening::ProcessLoadString(
304     HLoadString* load_string,
305     CodeGenerator* codegen,
306     const DexCompilationUnit& dex_compilation_unit,
307     VariableSizedHandleScope* handles) {
308   DCHECK_EQ(load_string->GetLoadKind(), HLoadString::LoadKind::kRuntimeCall);
309 
310   const DexFile& dex_file = load_string->GetDexFile();
311   dex::StringIndex string_index = load_string->GetStringIndex();
312 
313   HLoadString::LoadKind desired_load_kind = static_cast<HLoadString::LoadKind>(-1);
314   {
315     Runtime* runtime = Runtime::Current();
316     ClassLinker* class_linker = runtime->GetClassLinker();
317     ScopedObjectAccess soa(Thread::Current());
318     StackHandleScope<1> hs(soa.Self());
319     Handle<mirror::DexCache> dex_cache = IsSameDexFile(dex_file, *dex_compilation_unit.GetDexFile())
320         ? dex_compilation_unit.GetDexCache()
321         : hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file));
322     ObjPtr<mirror::String> string = nullptr;
323 
324     const CompilerOptions& compiler_options = codegen->GetCompilerOptions();
325     if (compiler_options.IsBootImage() || compiler_options.IsBootImageExtension()) {
326       // Compiling boot image or boot image extension. Resolve the string and allocate it
327       // if needed, to ensure the string will be added to the boot image.
328       DCHECK(!runtime->UseJitCompilation());
329       if (compiler_options.GetCompilePic()) {
330         if (compiler_options.IsForceDeterminism()) {
331           // Strings for methods we're compiling should be pre-resolved but Strings in inlined
332           // methods may not be if these inlined methods are not in the boot image profile.
333           // Multiple threads allocating new Strings can cause non-deterministic boot image
334           // because of the image relying on the order of GC roots we walk. (We could fix that
335           // by ordering the roots we walk in ImageWriter.) Therefore we avoid allocating these
336           // strings even if that results in omitting them from the boot image and using the
337           // sub-optimal load kind kBssEntry.
338           string = class_linker->LookupString(string_index, dex_cache.Get());
339         } else {
340           string = class_linker->ResolveString(string_index, dex_cache);
341           CHECK(string != nullptr);
342         }
343         if (string != nullptr) {
344           if (runtime->GetHeap()->ObjectIsInBootImageSpace(string)) {
345             DCHECK(compiler_options.IsBootImageExtension());
346             desired_load_kind = HLoadString::LoadKind::kBootImageRelRo;
347           } else {
348             desired_load_kind = HLoadString::LoadKind::kBootImageLinkTimePcRelative;
349           }
350         } else {
351           desired_load_kind = HLoadString::LoadKind::kBssEntry;
352         }
353       } else {
354         // Test configuration, do not sharpen.
355         desired_load_kind = HLoadString::LoadKind::kRuntimeCall;
356       }
357     } else if (runtime->UseJitCompilation()) {
358       DCHECK(!codegen->GetCompilerOptions().GetCompilePic());
359       string = class_linker->LookupString(string_index, dex_cache.Get());
360       if (string != nullptr) {
361         gc::Heap* heap = runtime->GetHeap();
362         if (heap->ObjectIsInBootImageSpace(string)) {
363           desired_load_kind = HLoadString::LoadKind::kJitBootImageAddress;
364         } else if (runtime->GetJit()->CanEncodeString(
365                   string,
366                   codegen->GetGraph()->IsCompilingForSharedJitCode())) {
367           desired_load_kind = HLoadString::LoadKind::kJitTableAddress;
368         } else {
369           // Shared JIT code cannot encode a literal that the GC can move.
370           VLOG(jit) << "Unable to encode in shared region string literal: "
371                     << string->ToModifiedUtf8();
372           desired_load_kind = HLoadString::LoadKind::kRuntimeCall;
373         }
374       } else {
375         desired_load_kind = HLoadString::LoadKind::kRuntimeCall;
376       }
377     } else {
378       // AOT app compilation. Try to lookup the string without allocating if not found.
379       string = class_linker->LookupString(string_index, dex_cache.Get());
380       if (string != nullptr && runtime->GetHeap()->ObjectIsInBootImageSpace(string)) {
381         desired_load_kind = HLoadString::LoadKind::kBootImageRelRo;
382       } else {
383         desired_load_kind = HLoadString::LoadKind::kBssEntry;
384       }
385     }
386     if (string != nullptr) {
387       load_string->SetString(handles->NewHandle(string));
388     }
389   }
390   DCHECK_NE(desired_load_kind, static_cast<HLoadString::LoadKind>(-1));
391 
392   HLoadString::LoadKind load_kind = codegen->GetSupportedLoadStringKind(desired_load_kind);
393   load_string->SetLoadKind(load_kind);
394 }
395 
396 }  // namespace art
397