template<VerifyObjectFlags kVerifyFlags> inline uint32_t Class::GetObjectSize() { // Note: Extra parentheses to avoid the comma being interpreted as macro parameter separator.
DCHECK((!IsVariableSize<kVerifyFlags>())) << "class=" << PrettyTypeOf(); return GetObjectSizeUnchecked<kVerifyFlags>();
}
template<VerifyObjectFlags kVerifyFlags> inline uint32_t Class::GetObjectSizeAllocFastPath() { // Note: Extra parentheses to avoid the comma being interpreted as macro parameter separator.
DCHECK((!IsVariableSize<kVerifyFlags>())) << "class=" << PrettyTypeOf(); return GetField32(ObjectSizeAllocFastPathOffset());
}
template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> inline ObjPtr<Class> Class::GetSuperClass() { // Can only get super class for loaded classes (hack for when runtime is // initializing)
DCHECK(IsLoaded<kVerifyFlags>() ||
IsErroneous<kVerifyFlags>() ||
!Runtime::Current()->IsStarted()) << IsLoaded(); return GetFieldObject<Class, kVerifyFlags, kReadBarrierOption>(
OFFSET_OF_OBJECT_MEMBER(Class, super_class_));
}
inlinevoidClass::SetSuperClass(ObjPtr<Class> new_super_class) { // Super class is assigned once, except during class linker initialization. if (kIsDebugBuild) {
ObjPtr<Class> old_super_class =
GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(Class, super_class_));
DCHECK(old_super_class == nullptr || old_super_class == new_super_class);
}
DCHECK(new_super_class != nullptr);
SetFieldObject</*kTransactionActive=*/ false, /*kCheckTransaction=*/ false>(
OFFSET_OF_OBJECT_MEMBER(Class, super_class_), new_super_class);
}
inlineboolClass::HasSuperClass() { // No read barrier is needed for comparing with null. See ReadBarrierOption. return GetSuperClass<kDefaultVerifyFlags, kWithoutReadBarrier>() != nullptr;
}
inlineboolClass::HasVTable() { // No read barrier is needed for comparing with null. See ReadBarrierOption. return GetVTable<kDefaultVerifyFlags, kWithoutReadBarrier>() != nullptr ||
ShouldHaveEmbeddedVTable();
}
template<VerifyObjectFlags kVerifyFlags> inline int32_t Class::GetVTableLength() { if (ShouldHaveEmbeddedVTable<kVerifyFlags>()) { return GetEmbeddedVTableLength();
} // We do not need a read barrier here as the length is constant, // both from-space and to-space vtables shall yield the same result.
ObjPtr<PointerArray> vtable = GetVTable<kVerifyFlags, kWithoutReadBarrier>(); return vtable != nullptr ? vtable->GetLength() : 0;
}
inlineboolClass::Implements(ObjPtr<Class> klass) {
DCHECK(klass != nullptr);
DCHECK(klass->IsInterface()) << PrettyClass(); // All interfaces implemented directly and by our superclass, and // recursively all super-interfaces of those interfaces, are listed // in iftable_, so we can just do a linear scan through that.
int32_t iftable_count = GetIfTableCount();
ObjPtr<IfTable> iftable = GetIfTable(); for (int32_t i = 0; i < iftable_count; i++) { if (iftable->GetInterface(i) == klass) { returntrue;
}
} returnfalse;
}
template<VerifyObjectFlags kVerifyFlags> inlineboolClass::IsVariableSize() { // Classes, arrays, and strings vary in size, and so the object_size_ field cannot // be used to Get their instance size return IsClassClass<kVerifyFlags>() ||
IsArrayClass<kVerifyFlags>() ||
IsStringClass<kVerifyFlags>();
}
inlinevoidClass::SetObjectSize(uint32_t new_object_size) {
DCHECK(!IsVariableSize()); // Not called within a transaction. return SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), new_object_size);
}
template<typename T> inlineboolClass::IsDiscoverable(bool public_only, const hiddenapi::AccessContext& access_context,
T* member) { // For `ObjPtr<>` poisoning, check access context's class validity even // in cases when the class is not actually needed.
access_context.GetClass().AssertValid(); if (public_only && ((member->GetAccessFlags() & kAccPublic) == 0)) { returnfalse;
}
// Determine whether "this" is assignable from "src", where both of these // are array classes. // // Consider an array class, e.g. Y[][], where Y is a subclass of X. // Y[][] = Y[][] --> true (identity) // X[][] = Y[][] --> true (element superclass) // Y = Y[][] --> false // Y[] = Y[][] --> false // Object = Y[][] --> true (everything is an object) // Object[] = Y[][] --> true // Object[][] = Y[][] --> true // Object[][][] = Y[][] --> false (too many []s) // Serializable = Y[][] --> true (all arrays are Serializable) // Serializable[] = Y[][] --> true // Serializable[][] = Y[][] --> false (unless Y is Serializable) // // Don't forget about primitive types. // Object[] = int[] --> false // inlineboolClass::IsArrayAssignableFromArray(ObjPtr<Class> src) {
DCHECK(IsArrayClass()) << PrettyClass();
DCHECK(src->IsArrayClass()) << src->PrettyClass(); return GetComponentType()->IsAssignableFrom(src->GetComponentType());
}
inlineboolClass::IsAssignableFromArray(ObjPtr<Class> src) {
DCHECK(!IsInterface()) << PrettyClass(); // handled first in IsAssignableFrom
DCHECK(src->IsArrayClass()) << src->PrettyClass(); if (!IsArrayClass()) { // If "this" is not also an array, it must be Object. // src's super should be java_lang_Object, since it is an array.
ObjPtr<Class> java_lang_Object = src->GetSuperClass();
DCHECK(java_lang_Object != nullptr) << src->PrettyClass();
DCHECK(java_lang_Object->GetSuperClass() == nullptr) << src->PrettyClass(); returnthis == java_lang_Object;
} return IsArrayAssignableFromArray(src);
}
template <bool throw_on_failure> inlineboolClass::ResolvedFieldAccessTest(ObjPtr<Class> access_to,
ArtField* field,
ObjPtr<DexCache> dex_cache,
uint32_t field_idx) {
DCHECK(dex_cache != nullptr); if (UNLIKELY(!this->CanAccess(access_to))) { // The referrer class can't access the field's declaring class but may still be able // to access the field if the FieldId specifies an accessible subclass of the declaring // class rather than the declaring class itself.
dex::TypeIndex class_idx = dex_cache->GetDexFile()->GetFieldId(field_idx).class_idx_; // The referenced class has already been resolved with the field, but may not be in the dex // cache. Use LookupResolveType here to search the class table if it is not in the dex cache. // should be no thread suspension due to the class being resolved.
ObjPtr<Class> dex_access_to = Runtime::Current()->GetClassLinker()->LookupResolvedType(
class_idx,
dex_cache,
GetClassLoader());
DCHECK(dex_access_to != nullptr); if (UNLIKELY(!this->CanAccess(dex_access_to))) { if (throw_on_failure) {
ThrowIllegalAccessErrorClass(this, dex_access_to);
} returnfalse;
}
} if (LIKELY(this->CanAccessMember(access_to, field->GetAccessFlags()))) { returntrue;
} if (throw_on_failure) {
ThrowIllegalAccessErrorField(this, field);
} returnfalse;
}
inlineboolClass::IsObsoleteVersionOf(ObjPtr<Class> klass) {
DCHECK(!klass->IsObsoleteObject()) << klass->PrettyClass() << " is obsolete!"; if (LIKELY(!IsObsoleteObject())) { returnfalse;
}
ObjPtr<Class> current(klass); do { if (UNLIKELY(current == this)) { returntrue;
} else {
current = current->GetObsoleteClass();
}
} while (!current.IsNull()); returnfalse;
}
inlineboolClass::IsSubClass(ObjPtr<Class> klass) { // Since the SubtypeCheck::IsSubtypeOf needs to lookup the Depth, // it is always O(Depth) in terms of speed to do the check. // // So always do the "slow" linear scan in normal release builds. // // Future note: If we could have the depth in O(1) we could use the 'fast' // method instead as it avoids a loop and a read barrier. bool result = false;
DCHECK(!IsInterface()) << PrettyClass();
DCHECK(!IsArrayClass()) << PrettyClass();
ObjPtr<Class> current = this; do { if (current == klass) {
result = true; break;
}
current = current->GetSuperClass();
} while (current != nullptr);
if (kIsDebugBuild && kBitstringSubtypeCheckEnabled) {
ObjPtr<mirror::Class> dis(this);
SubtypeCheckInfo::Result sc_result = SubtypeCheck<ObjPtr<Class>>::IsSubtypeOf(dis, klass); if (sc_result != SubtypeCheckInfo::kUnknownSubtypeOf) { // Note: The "kUnknownSubTypeOf" can be avoided if and only if: // SubtypeCheck::EnsureInitialized(source) // happens-before source.IsSubClass(target) // SubtypeCheck::EnsureAssigned(target).GetState() == Assigned // happens-before source.IsSubClass(target) // // When code generated by optimizing compiler executes this operation, both // happens-before are guaranteed, so there is no fallback code there.
SubtypeCheckInfo::Result expected_result =
result ? SubtypeCheckInfo::kSubtypeOf : SubtypeCheckInfo::kNotSubtypeOf;
DCHECK_EQ(expected_result, sc_result)
<< "source: " << PrettyClass() << "target: " << klass->PrettyClass();
}
}
return result;
}
inline ArtMethod* Class::FindVirtualMethodForInterface(ArtMethod* method,
PointerSize pointer_size) {
ObjPtr<Class> declaring_class = method->GetDeclaringClass();
DCHECK(declaring_class != nullptr) << PrettyClass(); if (UNLIKELY(!declaring_class->IsInterface())) {
DCHECK(declaring_class->IsObjectClass()) << method->PrettyMethod();
DCHECK(method->IsPublic() && !method->IsStatic()); return FindVirtualMethodForVirtual(method, pointer_size);
}
DCHECK(!method->IsCopied()); // TODO cache to improve lookup speed const int32_t iftable_count = GetIfTableCount();
ObjPtr<IfTable> iftable = GetIfTable(); for (int32_t i = 0; i < iftable_count; i++) { if (iftable->GetInterface(i) == declaring_class) { return iftable->GetMethodArray(i)->GetElementPtrSize<ArtMethod*>(
method->GetMethodIndex(), pointer_size);
}
} return nullptr;
}
inline ArtMethod* Class::FindVirtualMethodForVirtual(ArtMethod* method, PointerSize pointer_size) { // Only miranda or default methods may come from interfaces and be used as a virtual.
DCHECK_IMPLIES(method->GetDeclaringClass()->IsInterface(),
method->IsDefault() || method->IsMiranda());
DCHECK(method->GetDeclaringClass()->IsAssignableFrom(this))
<< "Method " << method->PrettyMethod()
<< " is not declared in " << PrettyDescriptor() << " or its super classes"; // The argument method may from a super class. // Use the index to a potentially overridden one for this instance's class. return GetVTableEntry(method->GetMethodIndex(), pointer_size);
}
inline ArtMethod* Class::FindVirtualMethodForSuper(ArtMethod* method, PointerSize pointer_size) {
DCHECK(!method->GetDeclaringClass()->IsInterface());
DCHECK(method->GetDeclaringClass()->IsAssignableFrom(this))
<< "Method " << method->PrettyMethod()
<< " is not declared in " << PrettyDescriptor() << " or its super classes"; return GetSuperClass()->GetVTableEntry(method->GetMethodIndex(), pointer_size);
}
template<VerifyObjectFlags kVerifyFlags> inline int32_t Class::GetIfTableCount() { // We do not need a read barrier here as the length is constant, // both from-space and to-space iftables shall yield the same result. return GetIfTable<kVerifyFlags, kWithoutReadBarrier>()->Count();
}
template <VerifyObjectFlags kVerifyFlags> inline MemberOffset Class::GetFirstReferenceStaticFieldOffset(PointerSize pointer_size) {
DCHECK(IsResolved<kVerifyFlags>());
uint32_t base = sizeof(Class); // Static fields come after the class. if (ShouldHaveEmbeddedVTable<kVerifyFlags>()) { // Static fields come after the embedded tables.
base = Class::ComputeClassSize( true, GetEmbeddedVTableLength<kVerifyFlags>(), 0, 0, 0, 0, 0, 0, pointer_size);
} return MemberOffset(base);
}
inline MemberOffset Class::GetFirstReferenceStaticFieldOffsetDuringLinking(
PointerSize pointer_size) {
DCHECK(IsLoaded());
uint32_t base = sizeof(Class); // Static fields come after the class. if (ShouldHaveEmbeddedVTable()) { // Static fields come after the embedded tables.
base = Class::ComputeClassSize( true, GetVTableDuringLinking()->GetLength(), 0, 0, 0, 0, 0, 0, pointer_size);
} return MemberOffset(base);
}
inlinevoidClass::SetClinitThreadId(pid_t new_clinit_thread_id) { if (kIsDebugBuild) { static std::once_flag of; auto check_unused_bits = []() { // Check that no tid value can use the bits in kTidUnusedBitsMask. "man proc_sys_kernel" // promises this anyway. We're a bit paranoid, but not enough to check in user builds, or to // check more than once. The DCHECK_EQ below arguably doesn't suffice, because it could only // fail for long-running devices. int fd = open("/proc/sys/kernel/pid_max", O_RDONLY); if (fd == -1) {
CHECK_EQ(errno, EACCES) << strerror(errno);
LOG(WARNING) << "Cannot read pid_max"; return;
}
constexpr int64_t kPidMaxLen = 20; char buf[kPidMaxLen + 1];
ssize_t res = read(fd, buf, kPidMaxLen);
CHECK_GT(res, 2);
buf[res] = '\0';
uint32_t pid_max = atoi(buf);
CHECK_GE(pid_max, 1024u); // Just another sanity check.
CHECK_EQ((pid_max - 1) & kTidUnusedBitsMask, 0u); // The real check.
close(fd);
};
std::call_once(of, check_unused_bits);
}
DCHECK_EQ(uint32_t(new_clinit_thread_id) & kTidUnusedBitsMask, 0u); // A relaxed store should be OK here, since we should be holding the class monitor. // Concurrent accesses to the descriptor hash will either retrieve a valid value, // or will fail without effect.
SetField32Transaction(ClinitThreadIdOffset(), new_clinit_thread_id);
}
inline pid_t Class::GetClinitThreadId() REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(IsIdxLoaded() || IsErroneous()) << PrettyClass();
uint32_t raw = GetField32Volatile(ClinitThreadIdOffset()); if ((raw & kTidUnusedBitsMask) != 0) { // Slot is used to store descriptor hash.
DCHECK_NE(GetStatus(), ClassStatus::kInitializing); return0;
} // Class was not yet initialized when we read `raw`. Thus the thread id is valid. return raw;
}
if (super_class != nullptr) {
std::vector<ObjPtr<Class>> klasses; for (; klass != nullptr; klass = super_class) {
super_class = klass->GetSuperClass<kVerifyFlags, kReadBarrierOption>(); if (super_class != nullptr) {
klasses.push_back(klass);
}
}
for (auto iter = klasses.rbegin(); iter != klasses.rend(); iter++) {
klass = *iter;
size_t idx = (klass->GetFirstReferenceInstanceFieldOffset<kVerifyFlags, kReadBarrierOption>()
.Uint32Value() -
mirror::kObjectHeaderSize) / sizeof(mirror::HeapReference<mirror::Object>);
uint32_t num_refs = klass->NumReferenceInstanceFields<kVerifyFlags>(); for (uint32_t i = 0; i < num_refs; i++) {
check_bitmap[idx++] = true;
}
CHECK_LE(idx, num_bits) << PrettyClass();
}
}
uint32_t ref_offsets =
GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_));
CHECK_NE(ref_offsets, 0u) << PrettyClass();
CHECK((ref_offsets & kVisitReferencesSlowpathMask) != 0) << PrettyClass();
uint32_t bitmap_num_words = ref_offsets & ~kVisitReferencesSlowpathMask;
uint32_t* overflow_bitmap = reinterpret_cast<uint32_t*>( reinterpret_cast<uint8_t*>(this) +
(GetClassSize<kVerifyFlags>() - bitmap_num_words * sizeof(uint32_t))); for (uint32_t i = 0, field_offset = 0; i < bitmap_num_words; i++, field_offset += 32) {
ref_offsets = overflow_bitmap[i];
uint32_t check_bitmap_idx = field_offset; // Confirm that all the bits in check_bitmap that ought to be set, are set. while (ref_offsets != 0) { if ((ref_offsets & 1) != 0) {
CHECK(check_bitmap[check_bitmap_idx])
<< PrettyClass() << " i:" << i << " field_offset:" << field_offset
<< " check_bitmap_idx:" << check_bitmap_idx << " bitmap_word:" << overflow_bitmap[i];
check_bitmap[check_bitmap_idx] = false;
}
ref_offsets >>= 1;
check_bitmap_idx++;
}
} // Confirm that there is no other bit set.
std::ostringstream oss; bool found = false; for (size_t i = 0; i < check_bitmap.size(); i++) { if (check_bitmap[i]) { if (!found) {
DumpClass(oss, kDumpClassFullDetail);
oss << " set-bits:";
}
found = true;
oss << i << ",";
}
} if (found) {
oss << " stored-bitmap:"; for (size_t i = 0; i < bitmap_num_words; i++) {
oss << overflow_bitmap[i] << ":";
}
LOG(FATAL) << oss.str();
}
}
inline size_t Class::AdjustClassSizeForReferenceOffsetBitmapDuringLinking(ObjPtr<Class> klass,
size_t class_size) { if (klass->IsInstantiable()) { // Find the first class with non-zero instance field count and its super-class' // object-size together will tell us the required size. for (ObjPtr<Class> k = klass; k != nullptr; k = k->GetSuperClass()) {
size_t num_reference_fields = k->NumReferenceInstanceFieldsDuringLinking(); if (num_reference_fields != 0) {
ObjPtr<Class> super = k->GetSuperClass(); // Leave it for mirror::Object (the class field is handled specially). if (super != nullptr) { // All of the fields that contain object references are guaranteed to be grouped in // memory starting at an appropriately aligned address after super class object data.
uint32_t start_offset =
RoundUp(super->GetObjectSize(), sizeof(mirror::HeapReference<mirror::Object>));
uint32_t start_bit = (start_offset - mirror::kObjectHeaderSize) / sizeof(mirror::HeapReference<mirror::Object>); if (start_bit + num_reference_fields > 31) { // Alignment that maybe required at the end of static fields smaller than 32-bit.
class_size = RoundUp(class_size, sizeof(uint32_t)); // 32-bit words required for the overflow bitmap.
class_size += RoundUp(start_bit + num_reference_fields, 32) / 32 * sizeof(uint32_t);
}
} break;
}
}
} return class_size;
}
inline uint32_t Class::ComputeClassSize(bool has_embedded_vtable,
uint32_t num_vtable_entries,
uint32_t num_8bit_static_fields,
uint32_t num_16bit_static_fields,
uint32_t num_32bit_static_fields,
uint32_t num_64bit_static_fields,
uint32_t num_ref_static_fields,
uint32_t num_ref_bitmap_entries,
PointerSize pointer_size) { // Space used by java.lang.Class and its instance fields.
uint32_t size = sizeof(Class); // Space used by embedded tables. if (has_embedded_vtable) {
size = RoundUp(size + sizeof(uint32_t), static_cast<size_t>(pointer_size));
size += static_cast<size_t>(pointer_size); // size of pointer to IMT
size += num_vtable_entries * VTableEntrySize(pointer_size);
}
// Space used by reference statics.
size += num_ref_static_fields * kHeapReferenceSize; if (!IsAligned<8>(size) && num_64bit_static_fields > 0) {
uint32_t gap = 8 - (size & 0x7);
size += gap; // will be padded // Shuffle 4-byte fields forward. while (gap >= sizeof(uint32_t) && num_32bit_static_fields != 0) {
--num_32bit_static_fields;
gap -= sizeof(uint32_t);
} // Shuffle 2-byte fields forward. while (gap >= sizeof(uint16_t) && num_16bit_static_fields != 0) {
--num_16bit_static_fields;
gap -= sizeof(uint16_t);
} // Shuffle byte fields forward. while (gap >= sizeof(uint8_t) && num_8bit_static_fields != 0) {
--num_8bit_static_fields;
gap -= sizeof(uint8_t);
}
} // Guaranteed to be at least 4 byte aligned. No need for further alignments. // Space used for primitive static fields.
size += num_8bit_static_fields * sizeof(uint8_t) + num_16bit_static_fields * sizeof(uint16_t) +
num_32bit_static_fields * sizeof(uint32_t) + num_64bit_static_fields * sizeof(uint64_t);
// Space used by reference-offset bitmap. if (num_ref_bitmap_entries > 0) {
size = RoundUp(size, sizeof(uint32_t));
size += num_ref_bitmap_entries * sizeof(uint32_t);
} return size;
}
template<VerifyObjectFlags kVerifyFlags> inlineboolClass::IsClassClass() { // OK to look at from-space copies since java.lang.Class.class is non-moveable // (even when running without boot image, see ClassLinker::InitWithoutImage()) // and we're reading it for comparison only. See ReadBarrierOption.
ObjPtr<Class> java_lang_Class = GetClass<kVerifyFlags, kWithoutReadBarrier>(); returnthis == java_lang_Class;
}
inlineconst DexFile& Class::GetDexFile() { // From-space version is the same as the to-space version since the dex file never changes. // Avoiding the read barrier here is important to prevent recursive AssertToSpaceInvariant issues // from PrettyTypeOf. return *GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>()->GetDexFile();
}
// An actual descriptor hash that has too many high 1-bits, will cause us to recompute each time. if ((raw_cached_hash & kTidUnusedBitsMask) != 0) {
uint32_t cached_hash = ~raw_cached_hash;
DCHECK_EQ(cached_hash, ComputeDescriptorHash()); return cached_hash;
}
uint32_t result = ComputeDescriptorHash(); if (raw_cached_hash == 0/* field unused */
&& (result & kTidUnusedBitsMask) != kTidUnusedBitsMask /* can safely be stored */) { // Be careful never to overwrite a thread id.
uint32_t expected = 0;
clinit_thread_id_or_hash_.compare_exchange_weak(expected, ~result);
} return result;
}
inlinevoidClass::CacheDescriptorHash(uint32_t hash) { if (hash == 0) { // Allowed, but not required, when the hash value cannot be safely cached.
DCHECK_EQ(ComputeDescriptorHash() & kTidUnusedBitsMask, kTidUnusedBitsMask);
} else {
DCHECK_EQ(hash, ComputeDescriptorHash());
}
uint32_t stored_hash; if ((hash & kTidUnusedBitsMask) != kTidUnusedBitsMask) {
stored_hash = ~hash;
} else { // Unsafe to store, since it would look like a tid. Recompute every time.
stored_hash = 0;
}
SetField32Transaction(ClinitThreadIdOffset(), stored_hash);
}
inlinevoidClass::AssertInitializedOrInitializingInThread(Thread* self) { if (kIsDebugBuild && !IsInitialized()) {
CHECK(IsInitializing()) << PrettyClass() << " is not initializing: " << GetStatus();
CHECK_EQ(GetClinitThreadId(), self->GetTid())
<< PrettyClass() << " is initializing in a different thread";
}
}
inlineboolClass::IsBootStrapClassLoaded() { // No read barrier is needed for comparing with null. See ReadBarrierOption. return GetClassLoader<kDefaultVerifyFlags, kWithoutReadBarrier>() == nullptr;
}
inlinevoidClass::InitializeClassVisitor::operator()(ObjPtr<Object> obj,
size_t usable_size) const {
DCHECK_LE(class_size_, usable_size); // Avoid AsClass as object is not yet in live bitmap or allocation stack.
ObjPtr<Class> klass = ObjPtr<Class>::DownCast(obj);
klass->SetClassSize(class_size_);
klass->SetPrimitiveType(Primitive::kPrimNot); // Default to not being primitive.
klass->SetDexClassDefIndex(DexFile::kDexNoIndex16); // Default to no valid class def index.
klass->SetDexTypeIndex(dex::TypeIndex(DexFile::kDexNoIndex16)); // Default to no valid type // index. // Default to force slow path until visibly initialized. // There is no need for release store (volatile) in pre-fence visitor.
klass->SetField32</*kTransactionActive=*/ false, /*kCheckTransaction=*/ false>(
ObjectSizeAllocFastPathOffset(), std::numeric_limits<uint32_t>::max());
}
inlinevoidClass::SetAccessFlags(uint32_t new_access_flags) { // Called inside a transaction when setting pre-verified flag during boot image compilation. if (Runtime::Current()->IsActiveTransaction()) {
SetField32<true>(AccessFlagsOffset(), new_access_flags);
} else {
SetField32<false>(AccessFlagsOffset(), new_access_flags);
}
}
inlineboolClass::IsObjectClass() { // No read barrier is needed for comparing with null. See ReadBarrierOption. return !IsPrimitive() && GetSuperClass<kDefaultVerifyFlags, kWithoutReadBarrier>() == nullptr;
}
template<VerifyObjectFlags kVerifyFlags> inlineboolClass::IsArrayClass() { // We do not need a read barrier for comparing with null. return GetComponentType<kVerifyFlags, kWithoutReadBarrier>() != nullptr;
}
template<VerifyObjectFlags kVerifyFlags> boolClass::IsPrimitiveArray() { // We do not need a read barrier here as the primitive type is constant, // both from-space and to-space component type classes shall yield the same result. const ObjPtr<Class> component_type = GetComponentType<kVerifyFlags, kWithoutReadBarrier>();
constexpr VerifyObjectFlags kNewFlags = RemoveThisFlags(kVerifyFlags); return component_type != nullptr && component_type->IsPrimitive<kNewFlags>();
}
inlineboolClass::IsAssignableFrom(ObjPtr<Class> src) {
DCHECK(src != nullptr); if (this == src) { // Can always assign to things of the same type. returntrue;
} elseif (IsObjectClass()) { // Can assign any reference to java.lang.Object. return !src->IsPrimitive();
} elseif (IsInterface()) { return src->Implements(this);
} elseif (src->IsArrayClass()) { return IsAssignableFromArray(src);
} else { return !src->IsInterface() && src->IsSubClass(this);
}
}
inline uint32_t Class::NumDirectMethods() { if (IsProxyClass()) { // Proxy classes have one constructor, and then only virtual methods. return1;
} if (IsArrayClass() || IsPrimitive()) { return0u;
}
ClassAccessor accessor(GetDexFile(), GetDexClassDefIndex()); return accessor.NumDirectMethods();
}
inline uint32_t Class::NumDeclaredVirtualMethods() { if (IsProxyClass()) { // Proxy classes have one constructor, and then only virtual methods. return NumMethods() - 1;
} if (IsArrayClass() || IsPrimitive()) { return0u;
}
ClassAccessor accessor(GetDexFile(), GetDexClassDefIndex()); return accessor.NumVirtualMethods();
}
inlineboolClass::CanAccessMember(ObjPtr<Class> access_to, uint32_t member_flags) { // Classes can access all of their own members if (this == access_to) { returntrue;
} // Public members are trivially accessible if (member_flags & kAccPublic) { returntrue;
} // Private members are trivially not accessible if (member_flags & kAccPrivate) { returnfalse;
} // Check for protected access from a sub-class, which may or may not be in the same package. if (member_flags & kAccProtected) { // This implementation is not compliant. We should actually check whether // the caller is a subclass of the static type of the receiver, instead of the declaring // class of the method we are trying to access. // // For example, a class outside of java.lang should not ne able to access `Object.clone`, // but this implementation allows it. // // To not break existing code, we decided not to fix this and accept the // leniency. if (access_to->IsAssignableFrom(this)) { returntrue;
}
} // Allow protected access from other classes in the same package. returnthis->IsInSamePackage(access_to);
}
inlinevoidClass::ClearFinalizable() { // We're clearing the finalizable flag only for `Object` and `Enum` // during early setup without the boot image.
DCHECK(IsObjectClass() ||
(IsBootStrapClassLoaded() && DescriptorEquals("Ljava/lang/Enum;")));
uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
SetAccessFlagsDuringLinking(flags & ~kAccClassIsFinalizable);
}
inline ImTable* Class::FindSuperImt(PointerSize pointer_size) {
ObjPtr<mirror::Class> klass = this; while (klass->HasSuperClass()) {
klass = klass->GetSuperClass(); if (klass->ShouldHaveImt()) { return klass->GetImt(pointer_size);
}
} return nullptr;
}
template <bool kOnlyLookAtIndex>
ALWAYS_INLINE FLATTEN inline ArtField* Class::FindDeclaredField(uint32_t dex_field_idx) {
LengthPrefixedArray<ArtField>* array = GetFieldsPtrUnchecked();
size_t size = array->size(); if (size == 0) { return nullptr;
} // The field array is an ordered list of fields where there may be missing // indices. For example, it could be [40, 42], but in 90% of cases cases we have // [40, 41, 42]. The latter is the case we are optimizing for, where for // example `dex_field_idx` is 41, and we can just substract it with the // first field index (40) and directly access the array with that index (1).
uint32_t index = dex_field_idx - array->At(0).GetDexFieldIndex(); if (index < size) {
ArtField& field = array->At(index); if (field.GetDexFieldIndex() == dex_field_idx) { return &field;
}
} else {
index = size;
} if (kOnlyLookAtIndex) { return nullptr;
} // If there is a field, it's down the array. The array is ordered by field // index, so we know we can stop the search if `dex_field_idx` is greater // than the current field's index. for (; index > 0; --index) {
ArtField& field = array->At(index - 1); if (field.GetDexFieldIndex() == dex_field_idx) { return &field;
} elseif (field.GetDexFieldIndex() < dex_field_idx) { break;
}
} return nullptr;
}
size_t size = array->size(); if (size == 0) { return nullptr;
} // The method array is an ordered list of methods where there may be missing // indices. For example, it could be [40, 42], but in 90% of cases cases we have // [40, 41, 42]. The latter is the case we are optimizing for, where for // example `dex_method_idx` is 41, and we can just substract it with the // first method index (40) and directly access the array with that index (1).
uint32_t index = dex_method_idx - array->At(0, kMethodSize, kMethodAlignment).GetDexMethodIndex(); if (index < size) {
ArtMethod& method = array->At(index, kMethodSize, kMethodAlignment); if (!method.IsCopied() && method.GetDexMethodIndex() == dex_method_idx) { return &method;
}
} if (kOnlyLookAtIndex) { return nullptr;
}
// Reset index to take a look at the whole array since we might have methods with the same dex // method index e.g. [120, 121, 122, 122, 123]. In this example, if we don't reset the index to // `size` we will start iterating from the second 122 and miss 123.
index = size; // If there is a method, it's down the array. The array is ordered by method // index, so we know we can stop the search if `dex_method_idx` is greater // than the current method's index. for (; index > 0; --index) {
ArtMethod& method = array->At(index - 1, kMethodSize, kMethodAlignment); if (method.IsCopied()) { continue;
} elseif (method.GetDexMethodIndex() == dex_method_idx) { return &method;
} elseif (method.GetDexMethodIndex() < dex_method_idx) { break;
}
} return nullptr;
}
inlinevoidClass::FixThreadId(Class* class_for_descr) { if (!IsInitialized()) { if (kIsDebugBuild) {
ClassStatus s = GetStatus(); if (s != ClassStatus::kVerified &&
s != ClassStatus::kRetryVerificationAtRuntime &&
s != ClassStatus::kVerifiedNeedsAccessChecks &&
s != ClassStatus::kResolved) {
LOG(FATAL_WITHOUT_ABORT) << "Unexpected status " << s
<< " when clearing tid: " << GetClinitThreadId();
std::string storage;
LOG(FATAL) << "\tfor class: " << class_for_descr->GetDescriptor(&storage); return;
}
} // This should not be called in the middle of initialization. And once the class is initialized, // the field should contain a hash code. Thus we should not have to do anything here. However // it may help to set the hash code, so we don't have to touch it later, even if the class is // never initialized.
uint32_t raw_cached_hash = clinit_thread_id_or_hash_.load(std::memory_order_relaxed); if (raw_cached_hash == 0) {
uint32_t hash = class_for_descr->ComputeDescriptorHash(); if ((hash & kTidUnusedBitsMask) != kTidUnusedBitsMask /* can safely be stored */) {
clinit_thread_id_or_hash_.store(~hash, std::memory_order_relaxed);
}
} else { // Should be cached descriptor hash, NOT a thread id.
DCHECK_NE(raw_cached_hash & kTidUnusedBitsMask, 0u)
<< " hash = " << raw_cached_hash << " status = " << GetStatus();
}
} // O.w. clinit_thread_id_or_hash_ already contains descriptor hash code or, rarely, zero.
}
} // namespace mirror
} // namespace art
#endif// ART_RUNTIME_MIRROR_CLASS_INL_H_
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.21 Sekunden
(vorverarbeitet am 2026-06-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.