1 /*
2 * Copyright (C) 2012 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 "reg_type_cache-inl.h"
18
19 #include <type_traits>
20
21 #include "base/aborting.h"
22 #include "base/arena_bit_vector.h"
23 #include "base/bit_vector-inl.h"
24 #include "base/casts.h"
25 #include "base/scoped_arena_allocator.h"
26 #include "base/stl_util.h"
27 #include "class_linker-inl.h"
28 #include "class_root-inl.h"
29 #include "dex/descriptors_names.h"
30 #include "dex/dex_file-inl.h"
31 #include "mirror/class-inl.h"
32 #include "mirror/object-inl.h"
33 #include "reg_type-inl.h"
34
35 namespace art HIDDEN {
36 namespace verifier {
37
FillPrimitiveAndConstantTypes()38 void RegTypeCache::FillPrimitiveAndConstantTypes() {
39 entries_.resize(kNumberOfFixedCacheIds);
40 ArrayRef<const RegType*> entries(entries_);
41
42 static constexpr UndefinedType constUndefinedType(kUndefinedCacheId);
43 entries[kUndefinedCacheId] = &constUndefinedType;
44 static constexpr ConflictType constConflictType(kConflictCacheId);
45 entries[kConflictCacheId] = &constConflictType;
46
47 #define CREATE_PRIMITIVE_TYPE(name, descriptor) \
48 static constexpr name##Type const##name(descriptor, k##name##CacheId); \
49 entries[k##name##CacheId] = &const##name;
50 CREATE_PRIMITIVE_TYPE(Boolean, "Z");
51 CREATE_PRIMITIVE_TYPE(Byte, "B");
52 CREATE_PRIMITIVE_TYPE(Short, "S");
53 CREATE_PRIMITIVE_TYPE(Char, "C");
54 CREATE_PRIMITIVE_TYPE(Integer, "I");
55 CREATE_PRIMITIVE_TYPE(LongLo, "J");
56 CREATE_PRIMITIVE_TYPE(LongHi, "J");
57 CREATE_PRIMITIVE_TYPE(Float, "F");
58 CREATE_PRIMITIVE_TYPE(DoubleLo, "D");
59 CREATE_PRIMITIVE_TYPE(DoubleHi, "D");
60 #undef CREATE_PRIMITIVE_TYPE
61
62 #define CREATE_CONSTANT_TYPE(name) \
63 static constexpr name##Type const##name(k##name##CacheId); \
64 entries[k##name##CacheId] = &const##name;
65 CREATE_CONSTANT_TYPE(Zero);
66 CREATE_CONSTANT_TYPE(BooleanConstant);
67 CREATE_CONSTANT_TYPE(PositiveByteConstant);
68 CREATE_CONSTANT_TYPE(PositiveShortConstant);
69 CREATE_CONSTANT_TYPE(CharConstant);
70 CREATE_CONSTANT_TYPE(ByteConstant);
71 CREATE_CONSTANT_TYPE(ShortConstant);
72 CREATE_CONSTANT_TYPE(IntegerConstant);
73 CREATE_CONSTANT_TYPE(ConstantLo);
74 CREATE_CONSTANT_TYPE(ConstantHi);
75 CREATE_CONSTANT_TYPE(Null);
76 #undef CREATE_CONSTANT_TYPE
77
78 // `JavaLangObjectType` must be initialized together with its uninitialized type.
79 struct JavaLangObjectPair {
80 constexpr JavaLangObjectPair()
81 : initialized("Ljava/lang/Object;", kJavaLangObjectCacheId, &uninitialized),
82 uninitialized(kUninitializedJavaLangObjectCacheId, &initialized) {}
83 JavaLangObjectType initialized;
84 UninitializedReferenceType uninitialized;
85 };
86 static constexpr JavaLangObjectPair constJavaLangObject;
87 entries[kJavaLangObjectCacheId] = &constJavaLangObject.initialized;
88 entries[kUninitializedJavaLangObjectCacheId] = &constJavaLangObject.uninitialized;
89 }
90
FromDescriptor(const char * descriptor)91 const RegType& RegTypeCache::FromDescriptor(const char* descriptor) {
92 if (descriptor[1] == '\0') {
93 switch (descriptor[0]) {
94 case 'Z':
95 return Boolean();
96 case 'B':
97 return Byte();
98 case 'S':
99 return Short();
100 case 'C':
101 return Char();
102 case 'I':
103 return Integer();
104 case 'J':
105 return LongLo();
106 case 'F':
107 return Float();
108 case 'D':
109 return DoubleLo();
110 case 'V': // For void types, conflict types.
111 default:
112 return Conflict();
113 }
114 } else if (descriptor[0] == 'L' || descriptor[0] == '[') {
115 return From(descriptor);
116 } else {
117 return Conflict();
118 }
119 }
120
FromTypeIndexUncached(dex::TypeIndex type_index)121 const RegType& RegTypeCache::FromTypeIndexUncached(dex::TypeIndex type_index) {
122 DCHECK_EQ(ids_for_type_index_[type_index.index_], kNoIdForTypeIndex);
123 const char* descriptor = dex_file_->GetTypeDescriptor(type_index);
124 const RegType& reg_type = FromDescriptor(descriptor);
125 DCHECK_NE(reg_type.GetId(), kNoIdForTypeIndex);
126 ids_for_type_index_[type_index.index_] = reg_type.GetId();
127 return reg_type;
128 }
129
RegTypeFromPrimitiveType(Primitive::Type prim_type) const130 const RegType& RegTypeCache::RegTypeFromPrimitiveType(Primitive::Type prim_type) const {
131 switch (prim_type) {
132 case Primitive::kPrimBoolean:
133 return Boolean();
134 case Primitive::kPrimByte:
135 return Byte();
136 case Primitive::kPrimShort:
137 return Short();
138 case Primitive::kPrimChar:
139 return Char();
140 case Primitive::kPrimInt:
141 return Integer();
142 case Primitive::kPrimLong:
143 return LongLo();
144 case Primitive::kPrimFloat:
145 return Float();
146 case Primitive::kPrimDouble:
147 return DoubleLo();
148 case Primitive::kPrimVoid:
149 default:
150 return *entries_[kConflictCacheId];
151 }
152 }
153
MatchDescriptor(size_t idx,const std::string_view & descriptor)154 bool RegTypeCache::MatchDescriptor(size_t idx, const std::string_view& descriptor) {
155 const RegType* entry = entries_[idx];
156 if (descriptor != entry->descriptor_) {
157 return false;
158 }
159 DCHECK(entry->IsJavaLangObject() || entry->IsReference() || entry->IsUnresolvedReference());
160 return true;
161 }
162
ResolveClass(const char * descriptor,size_t descriptor_length)163 ObjPtr<mirror::Class> RegTypeCache::ResolveClass(const char* descriptor, size_t descriptor_length) {
164 // Class was not found, must create new type.
165 // Try resolving class
166 Thread* self = Thread::Current();
167 ObjPtr<mirror::Class> klass = nullptr;
168 if (can_load_classes_) {
169 klass = class_linker_->FindClass(self, descriptor, descriptor_length, class_loader_);
170 } else {
171 std::string_view sv_descriptor(descriptor, descriptor_length);
172 klass = class_linker_->LookupClass(self, sv_descriptor, class_loader_.Get());
173 if (klass != nullptr && !klass->IsResolved()) {
174 // We found the class but without it being loaded its not safe for use.
175 klass = nullptr;
176 }
177 }
178 return klass;
179 }
180
AddString(const std::string_view & str)181 std::string_view RegTypeCache::AddString(const std::string_view& str) {
182 char* ptr = allocator_.AllocArray<char>(str.length());
183 memcpy(ptr, str.data(), str.length());
184 return std::string_view(ptr, str.length());
185 }
186
From(const char * descriptor)187 const RegType& RegTypeCache::From(const char* descriptor) {
188 // TODO: Avoid the implicit `strlen()` call for ASCII descriptors from the dex file.
189 std::string_view sv_descriptor(descriptor);
190 // Try looking up the class in the cache first. We use a std::string_view to avoid
191 // repeated strlen operations on the descriptor.
192 if (MatchDescriptor(kJavaLangObjectCacheId, sv_descriptor)) {
193 return *(entries_[kJavaLangObjectCacheId]);
194 }
195 for (size_t i = kNumberOfFixedCacheIds; i < entries_.size(); i++) {
196 if (MatchDescriptor(i, sv_descriptor)) {
197 return *(entries_[i]);
198 }
199 }
200 // Class not found in the cache, will create a new type for that.
201 // Try resolving class.
202 ObjPtr<mirror::Class> klass = ResolveClass(descriptor, sv_descriptor.length());
203 // TODO: Avoid copying the `descriptor` with `AddString()` below if the `descriptor`
204 // comes from the dex file, for example through `FromTypeIndex()`.
205 if (klass != nullptr) {
206 DCHECK(!klass->IsPrimitive());
207 if (klass->IsObjectClass()) {
208 return JavaLangObject();
209 }
210 const RegType* entry = new (&allocator_) ReferenceType(
211 handles_.NewHandle(klass), AddString(sv_descriptor), entries_.size());
212 return AddEntry(entry);
213 } else { // Class not resolved.
214 // We tried loading the class and failed, this might get an exception raised
215 // so we want to clear it before we go on.
216 if (can_load_classes_) {
217 DCHECK(Thread::Current()->IsExceptionPending());
218 Thread::Current()->ClearException();
219 } else {
220 DCHECK(!Thread::Current()->IsExceptionPending());
221 }
222 if (IsValidDescriptor(descriptor)) {
223 return AddEntry(new (&allocator_) UnresolvedReferenceType(AddString(sv_descriptor),
224 entries_.size()));
225 } else {
226 // The descriptor is broken return the unknown type as there's nothing sensible that
227 // could be done at runtime
228 return Conflict();
229 }
230 }
231 }
232
MakeUnresolvedReference()233 const RegType& RegTypeCache::MakeUnresolvedReference() {
234 // The descriptor is intentionally invalid so nothing else will match this type.
235 return AddEntry(new (&allocator_) UnresolvedReferenceType(AddString("a"), entries_.size()));
236 }
237
FromClass(ObjPtr<mirror::Class> klass)238 const RegType& RegTypeCache::FromClass(ObjPtr<mirror::Class> klass) {
239 DCHECK(klass != nullptr);
240 DCHECK(!klass->IsProxyClass());
241
242 if (klass->IsPrimitive()) {
243 return RegTypeFromPrimitiveType(klass->GetPrimitiveType());
244 }
245 if (klass->IsObjectClass()) {
246 return JavaLangObject();
247 }
248 if (!klass->IsArrayClass() && &klass->GetDexFile() == dex_file_) {
249 // Go through the `TypeIndex`-based cache. If the entry is not there yet, we shall
250 // fill it in now to make sure it's available for subsequent lookups.
251 std::optional<StackHandleScope<1u>> hs(std::nullopt);
252 if (kIsDebugBuild) {
253 hs.emplace(Thread::Current());
254 }
255 Handle<mirror::Class> h_class =
256 kIsDebugBuild ? hs->NewHandle(klass) : Handle<mirror::Class>();
257 const RegType& reg_type = FromTypeIndex(klass->GetDexTypeIndex());
258 DCHECK(reg_type.IsReference());
259 DCHECK(reg_type.GetClass() == h_class.Get());
260 return reg_type;
261 }
262 for (auto& pair : klass_entries_) {
263 const Handle<mirror::Class> entry_klass = pair.first;
264 const RegType* entry_reg_type = pair.second;
265 if (entry_klass.Get() == klass) {
266 return *entry_reg_type;
267 }
268 }
269
270 // No reference to the class was found, create new reference.
271 std::string_view descriptor;
272 if (klass->IsArrayClass()) {
273 std::string temp;
274 descriptor = AddString(std::string_view(klass->GetDescriptor(&temp)));
275 } else {
276 // Point `descriptor` to the string data in the dex file that defines the `klass`.
277 // That dex file cannot be unloaded while we hold a `Handle<>` to that `klass`.
278 descriptor = klass->GetDescriptorView();
279 }
280 Handle<mirror::Class> h_klass = handles_.NewHandle(klass);
281 const RegType* reg_type = new (&allocator_) ReferenceType(h_klass, descriptor, entries_.size());
282 return AddEntry(reg_type);
283 }
284
RegTypeCache(Thread * self,ClassLinker * class_linker,ArenaPool * arena_pool,Handle<mirror::ClassLoader> class_loader,const DexFile * dex_file,bool can_load_classes,bool can_suspend)285 RegTypeCache::RegTypeCache(Thread* self,
286 ClassLinker* class_linker,
287 ArenaPool* arena_pool,
288 Handle<mirror::ClassLoader> class_loader,
289 const DexFile* dex_file,
290 bool can_load_classes,
291 bool can_suspend)
292 : allocator_(arena_pool),
293 entries_(allocator_.Adapter(kArenaAllocVerifier)),
294 klass_entries_(allocator_.Adapter(kArenaAllocVerifier)),
295 handles_(self),
296 class_linker_(class_linker),
297 class_loader_(class_loader),
298 dex_file_(dex_file),
299 ids_for_type_index_(allocator_.AllocArray<uint16_t>(dex_file->NumTypeIds())),
300 last_uninitialized_this_type_(nullptr),
301 can_load_classes_(can_load_classes),
302 can_suspend_(can_suspend) {
303 DCHECK(can_suspend || !can_load_classes) << "Cannot load classes if suspension is disabled!";
304 if (kIsDebugBuild && can_suspend) {
305 Thread::Current()->AssertThreadSuspensionIsAllowable(gAborting == 0);
306 }
307 // `ArenaAllocator` guarantees zero-initialization.
308 static_assert(kNoIdForTypeIndex == 0u);
309 DCHECK(std::all_of(ids_for_type_index_,
310 ids_for_type_index_ + dex_file->NumTypeIds(),
311 [](uint16_t id) { return id == kNoIdForTypeIndex; }));
312 // The klass_entries_ array does not have primitives or constants.
313 static constexpr size_t kNumReserveEntries = 32;
314 klass_entries_.reserve(kNumReserveEntries);
315 // We want to have room for additional entries after inserting primitives and constants.
316 entries_.reserve(kNumReserveEntries + kNumberOfFixedCacheIds);
317 FillPrimitiveAndConstantTypes();
318 }
319
FromUnresolvedMerge(const RegType & left,const RegType & right,MethodVerifier * verifier)320 const RegType& RegTypeCache::FromUnresolvedMerge(const RegType& left,
321 const RegType& right,
322 MethodVerifier* verifier) {
323 ArenaBitVector types(&allocator_,
324 kDefaultArenaBitVectorBytes * kBitsPerByte, // Allocate at least 8 bytes.
325 true); // Is expandable.
326 const RegType* left_resolved;
327 bool left_unresolved_is_array;
328 if (left.IsUnresolvedMergedReference()) {
329 const UnresolvedMergedReferenceType& left_merge =
330 *down_cast<const UnresolvedMergedReferenceType*>(&left);
331
332 types.Copy(&left_merge.GetUnresolvedTypes());
333 left_resolved = &left_merge.GetResolvedPart();
334 left_unresolved_is_array = left.IsArrayTypes();
335 } else if (left.IsUnresolvedTypes()) {
336 types.SetBit(left.GetId());
337 left_resolved = &Zero();
338 left_unresolved_is_array = left.IsArrayTypes();
339 } else {
340 left_resolved = &left;
341 left_unresolved_is_array = false;
342 }
343
344 const RegType* right_resolved;
345 bool right_unresolved_is_array;
346 if (right.IsUnresolvedMergedReference()) {
347 const UnresolvedMergedReferenceType& right_merge =
348 *down_cast<const UnresolvedMergedReferenceType*>(&right);
349
350 types.Union(&right_merge.GetUnresolvedTypes());
351 right_resolved = &right_merge.GetResolvedPart();
352 right_unresolved_is_array = right.IsArrayTypes();
353 } else if (right.IsUnresolvedTypes()) {
354 types.SetBit(right.GetId());
355 right_resolved = &Zero();
356 right_unresolved_is_array = right.IsArrayTypes();
357 } else {
358 right_resolved = &right;
359 right_unresolved_is_array = false;
360 }
361
362 // Merge the resolved parts. Left and right might be equal, so use SafeMerge.
363 const RegType& resolved_parts_merged = left_resolved->SafeMerge(*right_resolved, this, verifier);
364 // If we get a conflict here, the merge result is a conflict, not an unresolved merge type.
365 if (resolved_parts_merged.IsConflict()) {
366 return Conflict();
367 }
368 if (resolved_parts_merged.IsJavaLangObject()) {
369 return resolved_parts_merged;
370 }
371
372 bool resolved_merged_is_array = resolved_parts_merged.IsArrayTypes();
373 if (left_unresolved_is_array || right_unresolved_is_array || resolved_merged_is_array) {
374 // Arrays involved, see if we need to merge to Object.
375
376 // Is the resolved part a primitive array?
377 if (resolved_merged_is_array && !resolved_parts_merged.IsObjectArrayTypes()) {
378 return JavaLangObject();
379 }
380
381 // Is any part not an array (but exists)?
382 if ((!left_unresolved_is_array && left_resolved != &left) ||
383 (!right_unresolved_is_array && right_resolved != &right) ||
384 !resolved_merged_is_array) {
385 return JavaLangObject();
386 }
387 }
388
389 // Check if entry already exists.
390 for (size_t i = kNumberOfFixedCacheIds; i < entries_.size(); i++) {
391 const RegType* cur_entry = entries_[i];
392 if (cur_entry->IsUnresolvedMergedReference()) {
393 const UnresolvedMergedReferenceType* cmp_type =
394 down_cast<const UnresolvedMergedReferenceType*>(cur_entry);
395 const RegType& resolved_part = cmp_type->GetResolvedPart();
396 const BitVector& unresolved_part = cmp_type->GetUnresolvedTypes();
397 // Use SameBitsSet. "types" is expandable to allow merging in the components, but the
398 // BitVector in the final RegType will be made non-expandable.
399 if (&resolved_part == &resolved_parts_merged && types.SameBitsSet(&unresolved_part)) {
400 return *cur_entry;
401 }
402 }
403 }
404 return AddEntry(new (&allocator_) UnresolvedMergedReferenceType(resolved_parts_merged,
405 types,
406 this,
407 entries_.size()));
408 }
409
Uninitialized(const RegType & type)410 const UninitializedType& RegTypeCache::Uninitialized(const RegType& type) {
411 auto get_or_create_uninitialized_type =
412 [&](auto& ref_type) REQUIRES_SHARED(Locks::mutator_lock_) {
413 using RefType = std::remove_const_t<std::remove_reference_t<decltype(ref_type)>>;
414 static_assert(std::is_same_v<RefType, ReferenceType> ||
415 std::is_same_v<RefType, UnresolvedReferenceType>);
416 using UninitRefType =
417 std::remove_const_t<std::remove_pointer_t<decltype(ref_type.GetUninitializedType())>>;
418 static_assert(std::is_same_v<RefType, ReferenceType>
419 ? std::is_same_v<UninitRefType, UninitializedReferenceType>
420 : std::is_same_v<UninitRefType, UnresolvedUninitializedReferenceType>);
421 const UninitRefType* uninit_ref_type = ref_type.GetUninitializedType();
422 if (uninit_ref_type == nullptr) {
423 uninit_ref_type = new (&allocator_) UninitRefType(entries_.size(), &ref_type);
424 AddEntry(uninit_ref_type);
425 ref_type.SetUninitializedType(uninit_ref_type);
426 }
427 return uninit_ref_type;
428 };
429
430 if (type.IsReference()) {
431 return *get_or_create_uninitialized_type(down_cast<const ReferenceType&>(type));
432 } else if (type.IsUnresolvedReference()) {
433 return *get_or_create_uninitialized_type(down_cast<const UnresolvedReferenceType&>(type));
434 } else {
435 DCHECK(type.IsJavaLangObject());
436 return *down_cast<const JavaLangObjectType&>(type).GetUninitializedType();
437 }
438 }
439
FromUninitialized(const RegType & uninit_type)440 const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) {
441 if (uninit_type.IsUninitializedReference()) {
442 return *down_cast<const UninitializedReferenceType&>(uninit_type).GetInitializedType();
443 } else if (uninit_type.IsUnresolvedUninitializedReference()) {
444 return *down_cast<const UnresolvedUninitializedReferenceType&>(
445 uninit_type).GetInitializedType();
446 } else if (uninit_type.IsUninitializedThisReference()) {
447 return *down_cast<const UninitializedThisReferenceType&>(uninit_type).GetInitializedType();
448 } else {
449 DCHECK(uninit_type.IsUnresolvedUninitializedThisReference()) << uninit_type;
450 return *down_cast<const UnresolvedUninitializedThisReferenceType&>(
451 uninit_type).GetInitializedType();
452 }
453 }
454
UninitializedThisArgument(const RegType & type)455 const UninitializedType& RegTypeCache::UninitializedThisArgument(const RegType& type) {
456 if (last_uninitialized_this_type_ != nullptr && last_uninitialized_this_type_->Equals(type)) {
457 return *last_uninitialized_this_type_;
458 }
459
460 UninitializedType* entry;
461 const std::string_view& descriptor(type.GetDescriptor());
462 if (type.IsUnresolvedReference()) {
463 for (size_t i = kNumberOfFixedCacheIds; i < entries_.size(); i++) {
464 const RegType* cur_entry = entries_[i];
465 if (cur_entry->IsUnresolvedUninitializedThisReference() &&
466 down_cast<const UnresolvedUninitializedThisReferenceType*>(cur_entry)
467 ->GetInitializedType() == &type) {
468 DCHECK_EQ(cur_entry->GetDescriptor(), type.GetDescriptor());
469 return *down_cast<const UninitializedType*>(cur_entry);
470 }
471 }
472 entry = new (&allocator_) UnresolvedUninitializedThisReferenceType(
473 entries_.size(), down_cast<const UnresolvedReferenceType*>(&type));
474 } else {
475 DCHECK(type.IsJavaLangObject() || type.IsReference());
476 for (size_t i = kNumberOfFixedCacheIds; i < entries_.size(); i++) {
477 const RegType* cur_entry = entries_[i];
478 if (cur_entry->IsUninitializedThisReference() &&
479 down_cast<const UninitializedThisReferenceType*>(cur_entry)
480 ->GetInitializedType() == &type) {
481 DCHECK_EQ(cur_entry->GetDescriptor(), type.GetDescriptor());
482 return *down_cast<const UninitializedType*>(cur_entry);
483 }
484 }
485 entry = new (&allocator_) UninitializedThisReferenceType(
486 entries_.size(), down_cast<const ReferenceType*>(&type));
487 }
488 last_uninitialized_this_type_ = entry;
489 return AddEntry(entry);
490 }
491
GetComponentType(const RegType & array)492 const RegType& RegTypeCache::GetComponentType(const RegType& array) {
493 if (!array.IsArrayTypes()) {
494 return Conflict();
495 } else if (array.IsUnresolvedTypes()) {
496 DCHECK(!array.IsUnresolvedMergedReference()); // Caller must make sure not to ask for this.
497 const std::string descriptor(array.GetDescriptor());
498 return FromDescriptor(descriptor.c_str() + 1);
499 } else {
500 ObjPtr<mirror::Class> klass = array.GetClass()->GetComponentType();
501 if (klass->IsErroneous()) {
502 // Arrays may have erroneous component types, use unresolved in that case.
503 // We assume that the primitive classes are not erroneous, so we know it is a
504 // reference type.
505 std::string temp;
506 const char* descriptor = klass->GetDescriptor(&temp);
507 return FromDescriptor(descriptor);
508 } else {
509 return FromClass(klass);
510 }
511 }
512 }
513
Dump(std::ostream & os)514 void RegTypeCache::Dump(std::ostream& os) {
515 for (size_t i = 0; i < entries_.size(); i++) {
516 const RegType* cur_entry = entries_[i];
517 if (cur_entry != nullptr) {
518 os << i << ": " << cur_entry->Dump() << "\n";
519 }
520 }
521 }
522
523 } // namespace verifier
524 } // namespace art
525