diff options
author | 2025-02-26 23:34:49 +0000 | |
---|---|---|
committer | 2025-03-03 00:27:06 -0800 | |
commit | e280e935f1faa066ab8c0e2ab5bf87d064065412 (patch) | |
tree | c1a5c20389213f51f4d06c6da69901b28f870bc7 | |
parent | 3477cfd772c29976a705e70a9cbc20f6c3ecfc81 (diff) |
Flag classes that have unresolved type checks.
This allows skipping resolving the field type when setting a field.
Test: test.py
Change-Id: I1945deca5fdcccca7e67297eca8765b1f2f516f3
-rw-r--r-- | libdexfile/dex/modifiers.h | 3 | ||||
-rw-r--r-- | runtime/class_linker.cc | 3 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils-inl.h | 2 | ||||
-rw-r--r-- | runtime/interpreter/mterp/nterp.cc | 8 | ||||
-rw-r--r-- | runtime/mirror/class-inl.h | 10 | ||||
-rw-r--r-- | runtime/mirror/class.h | 3 | ||||
-rw-r--r-- | runtime/vdex_file.cc | 1 | ||||
-rw-r--r-- | runtime/verifier/verifier_deps.cc | 1 |
8 files changed, 28 insertions, 3 deletions
diff --git a/libdexfile/dex/modifiers.h b/libdexfile/dex/modifiers.h index 94e25e8e6e..ad6472df57 100644 --- a/libdexfile/dex/modifiers.h +++ b/libdexfile/dex/modifiers.h @@ -59,6 +59,9 @@ static constexpr uint32_t kAccObsoleteObject = 0x00200000; // class (run // Set during boot image compilation to indicate that the class is // not initialized at compile time and not in the list of preloaded classes. static constexpr uint32_t kAccInBootImageAndNotInPreloadedClasses = 0x00400000; // class (runtime) +// Set after verification if at least one of the class's method has unresolved +// type checks failures. +static constexpr uint32_t kAccHasTypeChecksFailure = 0x00800000; // class (runtime) // This is set by the class linker during LinkInterfaceMethods. It is used by a method // to represent that it was copied from its declaring class into another class. // We need copies of the original method because the method may end up in different diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index b4720c2dbc..70eea2d268 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -5311,6 +5311,9 @@ verifier::FailureKind ClassLinker::VerifyClass(Thread* self, Runtime::Current()->GetCompilerCallbacks()->UpdateClassState( ClassReference(&klass->GetDexFile(), klass->GetDexClassDefIndex()), klass->GetStatus()); } else { + if (verifier_failure == verifier::FailureKind::kTypeChecksFailure) { + klass->SetHasTypeChecksFailure(); + } mirror::Class::SetStatus(klass, ClassStatus::kVerified, self); } diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index f0f8f8dce3..77bf24f80b 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -416,7 +416,7 @@ inline ArtField* ResolveFieldWithAccessChecks(Thread* self, return nullptr; } - if (resolve_field_type != 0u) { + if (resolve_field_type != 0u && caller->GetDeclaringClass()->HasTypeChecksFailure()) { StackArtFieldHandleScope<1> rhs(self); ReflectiveHandle<ArtField> field_handle(rhs.NewHandle(resolved_field)); if (resolved_field->ResolveType().IsNull()) { diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc index a66ecd0855..95cfe7fb7d 100644 --- a/runtime/interpreter/mterp/nterp.cc +++ b/runtime/interpreter/mterp/nterp.cc @@ -464,7 +464,9 @@ extern "C" size_t NterpGetStaticField(Thread* self, // fail to resolve the type, we clear the exception to keep interpreter // semantics of not throwing when null is stored. bool update_cache = true; - if (opcode == Instruction::SPUT_OBJECT && resolved_field->ResolveType() == nullptr) { + if (opcode == Instruction::SPUT_OBJECT && + caller->GetDeclaringClass()->HasTypeChecksFailure() && + resolved_field->ResolveType() == nullptr) { DCHECK(self->IsExceptionPending()); if (resolve_field_type) { return 0; @@ -513,7 +515,9 @@ extern "C" uint32_t NterpGetInstanceFieldOffset(Thread* self, // fail to resolve the type, we clear the exception to keep interpreter // semantics of not throwing when null is stored. bool update_cache = true; - if (opcode == Instruction::IPUT_OBJECT && resolved_field->ResolveType() == nullptr) { + if (opcode == Instruction::IPUT_OBJECT && + caller->GetDeclaringClass()->HasTypeChecksFailure() && + resolved_field->ResolveType() == nullptr) { DCHECK(self->IsExceptionPending()); if (resolve_field_type != 0u) { return 0; diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 373b9b3105..06b5cf5e9f 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -1336,6 +1336,16 @@ inline void Class::SetHasDefaultMethods() { SetAccessFlagsDuringLinking(flags | kAccHasDefaultMethod); } +inline void Class::SetHasTypeChecksFailure() { + uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_)); + SetAccessFlags(flags | kAccHasTypeChecksFailure); +} + +inline bool Class::HasTypeChecksFailure() { + uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_)); + return (flags & kAccHasTypeChecksFailure) != 0u; +} + inline void Class::ClearFinalizable() { // We're clearing the finalizable flag only for `Object` and `Enum` // during early setup without the boot image. diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 6e72a41592..c8b234b789 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -288,6 +288,9 @@ class EXPORT MANAGED Class final : public Object { ALWAYS_INLINE void SetHasDefaultMethods() REQUIRES_SHARED(Locks::mutator_lock_); + ALWAYS_INLINE void SetHasTypeChecksFailure() REQUIRES_SHARED(Locks::mutator_lock_); + ALWAYS_INLINE bool HasTypeChecksFailure() REQUIRES_SHARED(Locks::mutator_lock_); + ALWAYS_INLINE void SetFinalizable() REQUIRES_SHARED(Locks::mutator_lock_) { uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_)); SetAccessFlagsDuringLinking(flags | kAccClassIsFinalizable); diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc index c8f1bfd810..32a83f0e05 100644 --- a/runtime/vdex_file.cc +++ b/runtime/vdex_file.cc @@ -569,6 +569,7 @@ ClassStatus VdexFile::ComputeClassStatus(Thread* self, Handle<mirror::Class> cls class_linker, self, source_desc, source_desc_length, class_loader)); if (destination == nullptr || source == nullptr) { + cls->SetHasTypeChecksFailure(); // The interpreter / compiler can handle a missing class. continue; } diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc index ed7629f805..5cb36db679 100644 --- a/runtime/verifier/verifier_deps.cc +++ b/runtime/verifier/verifier_deps.cc @@ -746,6 +746,7 @@ bool VerifierDeps::VerifyDexFileAndUpdateStatus( class_linker, self, source_desc, source_desc_length, class_loader)); if (destination == nullptr || source == nullptr) { + deps.verified_classes_[class_def_index] = false; // We currently don't use assignability information for unresolved // types, as the status of the class using unresolved types will be soft // fail in the vdex. |