• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "intrinsics.h"
18 
19 #include "art_field-inl.h"
20 #include "art_method-inl.h"
21 #include "base/utils.h"
22 #include "class_linker.h"
23 #include "class_root.h"
24 #include "dex/invoke_type.h"
25 #include "driver/compiler_options.h"
26 #include "gc/space/image_space.h"
27 #include "image-inl.h"
28 #include "intrinsic_objects.h"
29 #include "nodes.h"
30 #include "obj_ptr-inl.h"
31 #include "scoped_thread_state_change-inl.h"
32 #include "thread-current-inl.h"
33 
34 namespace art {
35 
operator <<(std::ostream & os,const Intrinsics & intrinsic)36 std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) {
37   switch (intrinsic) {
38     case Intrinsics::kNone:
39       os << "None";
40       break;
41 #define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
42     case Intrinsics::k ## Name: \
43       os << # Name; \
44       break;
45 #include "intrinsics_list.h"
46       INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
47 #undef STATIC_INTRINSICS_LIST
48 #undef VIRTUAL_INTRINSICS_LIST
49 #undef OPTIMIZING_INTRINSICS
50   }
51   return os;
52 }
53 
54 static const char kIntegerCacheDescriptor[] = "Ljava/lang/Integer$IntegerCache;";
55 static const char kIntegerDescriptor[] = "Ljava/lang/Integer;";
56 static const char kIntegerArrayDescriptor[] = "[Ljava/lang/Integer;";
57 static const char kLowFieldName[] = "low";
58 static const char kHighFieldName[] = "high";
59 static const char kValueFieldName[] = "value";
60 
GetBootImageLiveObjects()61 static ObjPtr<mirror::ObjectArray<mirror::Object>> GetBootImageLiveObjects()
62     REQUIRES_SHARED(Locks::mutator_lock_) {
63   gc::Heap* heap = Runtime::Current()->GetHeap();
64   const std::vector<gc::space::ImageSpace*>& boot_image_spaces = heap->GetBootImageSpaces();
65   DCHECK(!boot_image_spaces.empty());
66   const ImageHeader& main_header = boot_image_spaces[0]->GetImageHeader();
67   ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects =
68       ObjPtr<mirror::ObjectArray<mirror::Object>>::DownCast(
69           main_header.GetImageRoot<kWithoutReadBarrier>(ImageHeader::kBootImageLiveObjects));
70   DCHECK(boot_image_live_objects != nullptr);
71   DCHECK(heap->ObjectIsInBootImageSpace(boot_image_live_objects));
72   return boot_image_live_objects;
73 }
74 
LookupInitializedClass(Thread * self,ClassLinker * class_linker,const char * descriptor)75 static ObjPtr<mirror::Class> LookupInitializedClass(Thread* self,
76                                                     ClassLinker* class_linker,
77                                                     const char* descriptor)
78         REQUIRES_SHARED(Locks::mutator_lock_) {
79   ObjPtr<mirror::Class> klass =
80       class_linker->LookupClass(self, descriptor, /* class_loader= */ nullptr);
81   DCHECK(klass != nullptr);
82   DCHECK(klass->IsInitialized());
83   return klass;
84 }
85 
GetIntegerCacheArray(ObjPtr<mirror::Class> cache_class)86 static ObjPtr<mirror::ObjectArray<mirror::Object>> GetIntegerCacheArray(
87     ObjPtr<mirror::Class> cache_class) REQUIRES_SHARED(Locks::mutator_lock_) {
88   ArtField* cache_field = cache_class->FindDeclaredStaticField("cache", kIntegerArrayDescriptor);
89   DCHECK(cache_field != nullptr);
90   return ObjPtr<mirror::ObjectArray<mirror::Object>>::DownCast(cache_field->GetObject(cache_class));
91 }
92 
GetIntegerCacheField(ObjPtr<mirror::Class> cache_class,const char * field_name)93 static int32_t GetIntegerCacheField(ObjPtr<mirror::Class> cache_class, const char* field_name)
94     REQUIRES_SHARED(Locks::mutator_lock_) {
95   ArtField* field = cache_class->FindDeclaredStaticField(field_name, "I");
96   DCHECK(field != nullptr);
97   return field->GetInt(cache_class);
98 }
99 
CheckIntegerCache(Thread * self,ClassLinker * class_linker,ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects,ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_cache)100 static bool CheckIntegerCache(Thread* self,
101                               ClassLinker* class_linker,
102                               ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects,
103                               ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_cache)
104     REQUIRES_SHARED(Locks::mutator_lock_) {
105   DCHECK(boot_image_cache != nullptr);
106 
107   // Since we have a cache in the boot image, both java.lang.Integer and
108   // java.lang.Integer$IntegerCache must be initialized in the boot image.
109   ObjPtr<mirror::Class> cache_class =
110       LookupInitializedClass(self, class_linker, kIntegerCacheDescriptor);
111   ObjPtr<mirror::Class> integer_class =
112       LookupInitializedClass(self, class_linker, kIntegerDescriptor);
113 
114   // Check that the current cache is the same as the `boot_image_cache`.
115   ObjPtr<mirror::ObjectArray<mirror::Object>> current_cache = GetIntegerCacheArray(cache_class);
116   if (current_cache != boot_image_cache) {
117     return false;  // Messed up IntegerCache.cache.
118   }
119 
120   // Check that the range matches the boot image cache length.
121   int32_t low = GetIntegerCacheField(cache_class, kLowFieldName);
122   int32_t high = GetIntegerCacheField(cache_class, kHighFieldName);
123   if (boot_image_cache->GetLength() != high - low + 1) {
124     return false;  // Messed up IntegerCache.low or IntegerCache.high.
125   }
126 
127   // Check that the elements match the boot image intrinsic objects and check their values as well.
128   ArtField* value_field = integer_class->FindDeclaredInstanceField(kValueFieldName, "I");
129   DCHECK(value_field != nullptr);
130   for (int32_t i = 0, len = boot_image_cache->GetLength(); i != len; ++i) {
131     ObjPtr<mirror::Object> boot_image_object =
132         IntrinsicObjects::GetIntegerValueOfObject(boot_image_live_objects, i);
133     DCHECK(Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(boot_image_object));
134     // No need for read barrier for comparison with a boot image object.
135     ObjPtr<mirror::Object> current_object =
136         boot_image_cache->GetWithoutChecks<kVerifyNone, kWithoutReadBarrier>(i);
137     if (boot_image_object != current_object) {
138       return false;  // Messed up IntegerCache.cache[i]
139     }
140     if (value_field->GetInt(boot_image_object) != low + i) {
141       return false;  // Messed up IntegerCache.cache[i].value.
142     }
143   }
144 
145   return true;
146 }
147 
ComputeIntegerValueOfLocations(HInvoke * invoke,CodeGenerator * codegen,Location return_location,Location first_argument_location)148 void IntrinsicVisitor::ComputeIntegerValueOfLocations(HInvoke* invoke,
149                                                       CodeGenerator* codegen,
150                                                       Location return_location,
151                                                       Location first_argument_location) {
152   // The intrinsic will call if it needs to allocate a j.l.Integer.
153   LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly;
154   const CompilerOptions& compiler_options = codegen->GetCompilerOptions();
155   if (compiler_options.IsBootImage()) {
156     // Piggyback on the method load kind to determine whether we can use PC-relative addressing.
157     // This should cover both the testing config (non-PIC boot image) and codegens that reject
158     // PC-relative load kinds and fall back to the runtime call.
159     if (!invoke->AsInvokeStaticOrDirect()->HasPcRelativeMethodLoadKind()) {
160       return;
161     }
162     if (!compiler_options.IsImageClass(kIntegerCacheDescriptor) ||
163         !compiler_options.IsImageClass(kIntegerDescriptor)) {
164       return;
165     }
166     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
167     Thread* self = Thread::Current();
168     ScopedObjectAccess soa(self);
169     ObjPtr<mirror::Class> cache_class = class_linker->LookupClass(
170         self, kIntegerCacheDescriptor, /* class_loader= */ nullptr);
171     DCHECK(cache_class != nullptr);
172     if (UNLIKELY(!cache_class->IsInitialized())) {
173       LOG(WARNING) << "Image class " << cache_class->PrettyDescriptor() << " is uninitialized.";
174       return;
175     }
176     ObjPtr<mirror::Class> integer_class =
177         class_linker->LookupClass(self, kIntegerDescriptor, /* class_loader= */ nullptr);
178     DCHECK(integer_class != nullptr);
179     if (UNLIKELY(!integer_class->IsInitialized())) {
180       LOG(WARNING) << "Image class " << integer_class->PrettyDescriptor() << " is uninitialized.";
181       return;
182     }
183     int32_t low = GetIntegerCacheField(cache_class, kLowFieldName);
184     int32_t high = GetIntegerCacheField(cache_class, kHighFieldName);
185     if (kIsDebugBuild) {
186       ObjPtr<mirror::ObjectArray<mirror::Object>> current_cache = GetIntegerCacheArray(cache_class);
187       CHECK(current_cache != nullptr);
188       CHECK_EQ(current_cache->GetLength(), high - low + 1);
189       ArtField* value_field = integer_class->FindDeclaredInstanceField(kValueFieldName, "I");
190       CHECK(value_field != nullptr);
191       for (int32_t i = 0, len = current_cache->GetLength(); i != len; ++i) {
192         ObjPtr<mirror::Object> current_object = current_cache->GetWithoutChecks(i);
193         CHECK(current_object != nullptr);
194         CHECK_EQ(value_field->GetInt(current_object), low + i);
195       }
196     }
197     if (invoke->InputAt(0)->IsIntConstant()) {
198       int32_t value = invoke->InputAt(0)->AsIntConstant()->GetValue();
199       if (static_cast<uint32_t>(value) - static_cast<uint32_t>(low) <
200           static_cast<uint32_t>(high - low + 1)) {
201         // No call, we shall use direct pointer to the Integer object.
202         call_kind = LocationSummary::kNoCall;
203       }
204     }
205   } else {
206     Runtime* runtime = Runtime::Current();
207     if (runtime->GetHeap()->GetBootImageSpaces().empty()) {
208       return;  // Running without boot image, cannot use required boot image objects.
209     }
210     Thread* self = Thread::Current();
211     ScopedObjectAccess soa(self);
212     ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects = GetBootImageLiveObjects();
213     ObjPtr<mirror::ObjectArray<mirror::Object>> cache =
214         IntrinsicObjects::GetIntegerValueOfCache(boot_image_live_objects);
215     if (cache == nullptr) {
216       return;  // No cache in the boot image.
217     }
218     if (runtime->UseJitCompilation()) {
219       if (!CheckIntegerCache(self, runtime->GetClassLinker(), boot_image_live_objects, cache)) {
220         return;  // The cache was somehow messed up, probably by using reflection.
221       }
222     } else {
223       DCHECK(runtime->IsAotCompiler());
224       DCHECK(CheckIntegerCache(self, runtime->GetClassLinker(), boot_image_live_objects, cache));
225       if (invoke->InputAt(0)->IsIntConstant()) {
226         int32_t value = invoke->InputAt(0)->AsIntConstant()->GetValue();
227         // Retrieve the `value` from the lowest cached Integer.
228         ObjPtr<mirror::Object> low_integer =
229             IntrinsicObjects::GetIntegerValueOfObject(boot_image_live_objects, 0u);
230         ObjPtr<mirror::Class> integer_class =
231             low_integer->GetClass<kVerifyNone, kWithoutReadBarrier>();
232         ArtField* value_field = integer_class->FindDeclaredInstanceField(kValueFieldName, "I");
233         DCHECK(value_field != nullptr);
234         int32_t low = value_field->GetInt(low_integer);
235         if (static_cast<uint32_t>(value) - static_cast<uint32_t>(low) <
236             static_cast<uint32_t>(cache->GetLength())) {
237           // No call, we shall use direct pointer to the Integer object. Note that we cannot
238           // do this for JIT as the "low" can change through reflection before emitting the code.
239           call_kind = LocationSummary::kNoCall;
240         }
241       }
242     }
243   }
244 
245   ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator();
246   LocationSummary* locations = new (allocator) LocationSummary(invoke, call_kind, kIntrinsified);
247   if (call_kind == LocationSummary::kCallOnMainOnly) {
248     locations->SetInAt(0, Location::RegisterOrConstant(invoke->InputAt(0)));
249     locations->AddTemp(first_argument_location);
250     locations->SetOut(return_location);
251   } else {
252     locations->SetInAt(0, Location::ConstantLocation(invoke->InputAt(0)->AsConstant()));
253     locations->SetOut(Location::RequiresRegister());
254   }
255 }
256 
GetIntegerCacheLowFromIntegerCache(Thread * self,ClassLinker * class_linker)257 static int32_t GetIntegerCacheLowFromIntegerCache(Thread* self, ClassLinker* class_linker)
258     REQUIRES_SHARED(Locks::mutator_lock_) {
259   ObjPtr<mirror::Class> cache_class =
260       LookupInitializedClass(self, class_linker, kIntegerCacheDescriptor);
261   return GetIntegerCacheField(cache_class, kLowFieldName);
262 }
263 
CalculateBootImageOffset(ObjPtr<mirror::Object> object)264 static uint32_t CalculateBootImageOffset(ObjPtr<mirror::Object> object)
265     REQUIRES_SHARED(Locks::mutator_lock_) {
266   gc::Heap* heap = Runtime::Current()->GetHeap();
267   DCHECK(heap->ObjectIsInBootImageSpace(object));
268   return reinterpret_cast<const uint8_t*>(object.Ptr()) - heap->GetBootImageSpaces()[0]->Begin();
269 }
270 
IntegerValueOfInfo()271 inline IntrinsicVisitor::IntegerValueOfInfo::IntegerValueOfInfo()
272     : value_offset(0),
273       low(0),
274       length(0u),
275       integer_boot_image_offset(kInvalidReference),
276       value_boot_image_reference(kInvalidReference) {}
277 
ComputeIntegerValueOfInfo(HInvoke * invoke,const CompilerOptions & compiler_options)278 IntrinsicVisitor::IntegerValueOfInfo IntrinsicVisitor::ComputeIntegerValueOfInfo(
279     HInvoke* invoke, const CompilerOptions& compiler_options) {
280   // Note that we could cache all of the data looked up here. but there's no good
281   // location for it. We don't want to add it to WellKnownClasses, to avoid creating global
282   // jni values. Adding it as state to the compiler singleton seems like wrong
283   // separation of concerns.
284   // The need for this data should be pretty rare though.
285 
286   // Note that at this point we can no longer abort the code generation. Therefore,
287   // we need to provide data that shall not lead to a crash even if the fields were
288   // modified through reflection since ComputeIntegerValueOfLocations() when JITting.
289 
290   Runtime* runtime = Runtime::Current();
291   ClassLinker* class_linker = runtime->GetClassLinker();
292   Thread* self = Thread::Current();
293   ScopedObjectAccess soa(self);
294 
295   IntegerValueOfInfo info;
296   if (compiler_options.IsBootImage()) {
297     ObjPtr<mirror::Class> integer_class =
298         LookupInitializedClass(self, class_linker, kIntegerDescriptor);
299     ArtField* value_field = integer_class->FindDeclaredInstanceField(kValueFieldName, "I");
300     DCHECK(value_field != nullptr);
301     info.value_offset = value_field->GetOffset().Uint32Value();
302     ObjPtr<mirror::Class> cache_class =
303         LookupInitializedClass(self, class_linker, kIntegerCacheDescriptor);
304     info.low = GetIntegerCacheField(cache_class, kLowFieldName);
305     int32_t high = GetIntegerCacheField(cache_class, kHighFieldName);
306     info.length = dchecked_integral_cast<uint32_t>(high - info.low + 1);
307 
308     info.integer_boot_image_offset = IntegerValueOfInfo::kInvalidReference;
309     if (invoke->InputAt(0)->IsIntConstant()) {
310       int32_t input_value = invoke->InputAt(0)->AsIntConstant()->GetValue();
311       uint32_t index = static_cast<uint32_t>(input_value) - static_cast<uint32_t>(info.low);
312       if (index < static_cast<uint32_t>(info.length)) {
313         info.value_boot_image_reference = IntrinsicObjects::EncodePatch(
314             IntrinsicObjects::PatchType::kIntegerValueOfObject, index);
315       } else {
316         // Not in the cache.
317         info.value_boot_image_reference = IntegerValueOfInfo::kInvalidReference;
318       }
319     } else {
320       info.array_data_boot_image_reference =
321           IntrinsicObjects::EncodePatch(IntrinsicObjects::PatchType::kIntegerValueOfArray);
322     }
323   } else {
324     ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects = GetBootImageLiveObjects();
325     ObjPtr<mirror::Object> low_integer =
326         IntrinsicObjects::GetIntegerValueOfObject(boot_image_live_objects, 0u);
327     ObjPtr<mirror::Class> integer_class = low_integer->GetClass<kVerifyNone, kWithoutReadBarrier>();
328     ArtField* value_field = integer_class->FindDeclaredInstanceField(kValueFieldName, "I");
329     DCHECK(value_field != nullptr);
330     info.value_offset = value_field->GetOffset().Uint32Value();
331     if (runtime->UseJitCompilation()) {
332       // Use the current `IntegerCache.low` for JIT to avoid truly surprising behavior if the
333       // code messes up the `value` field in the lowest cached Integer using reflection.
334       info.low = GetIntegerCacheLowFromIntegerCache(self, class_linker);
335     } else {
336       // For app AOT, the `low_integer->value` should be the same as `IntegerCache.low`.
337       info.low = value_field->GetInt(low_integer);
338       DCHECK_EQ(info.low, GetIntegerCacheLowFromIntegerCache(self, class_linker));
339     }
340     // Do not look at `IntegerCache.high`, use the immutable length of the cache array instead.
341     info.length = dchecked_integral_cast<uint32_t>(
342         IntrinsicObjects::GetIntegerValueOfCache(boot_image_live_objects)->GetLength());
343 
344     info.integer_boot_image_offset = CalculateBootImageOffset(integer_class);
345     if (invoke->InputAt(0)->IsIntConstant()) {
346       int32_t input_value = invoke->InputAt(0)->AsIntConstant()->GetValue();
347       uint32_t index = static_cast<uint32_t>(input_value) - static_cast<uint32_t>(info.low);
348       if (index < static_cast<uint32_t>(info.length)) {
349         ObjPtr<mirror::Object> integer =
350             IntrinsicObjects::GetIntegerValueOfObject(boot_image_live_objects, index);
351         info.value_boot_image_reference = CalculateBootImageOffset(integer);
352       } else {
353         // Not in the cache.
354         info.value_boot_image_reference = IntegerValueOfInfo::kInvalidReference;
355       }
356     } else {
357       info.array_data_boot_image_reference =
358           CalculateBootImageOffset(boot_image_live_objects) +
359           IntrinsicObjects::GetIntegerValueOfArrayDataOffset(boot_image_live_objects).Uint32Value();
360     }
361   }
362 
363   return info;
364 }
365 
AssertNonMovableStringClass()366 void IntrinsicVisitor::AssertNonMovableStringClass() {
367   if (kIsDebugBuild) {
368     ScopedObjectAccess soa(Thread::Current());
369     ObjPtr<mirror::Class> string_class = GetClassRoot<art::mirror::String>();
370     CHECK(!art::Runtime::Current()->GetHeap()->IsMovableObject(string_class));
371   }
372 }
373 
374 }  // namespace art
375