summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nicolas Geoffray <ngeoffray@google.com> 2025-02-26 23:34:49 +0000
committer Nicolas Geoffray <ngeoffray@google.com> 2025-03-03 00:27:06 -0800
commite280e935f1faa066ab8c0e2ab5bf87d064065412 (patch)
treec1a5c20389213f51f4d06c6da69901b28f870bc7
parent3477cfd772c29976a705e70a9cbc20f6c3ecfc81 (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.h3
-rw-r--r--runtime/class_linker.cc3
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h2
-rw-r--r--runtime/interpreter/mterp/nterp.cc8
-rw-r--r--runtime/mirror/class-inl.h10
-rw-r--r--runtime/mirror/class.h3
-rw-r--r--runtime/vdex_file.cc1
-rw-r--r--runtime/verifier/verifier_deps.cc1
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.