Fix compiling boot image extension with assume-verified.
The change https://android-review.googlesource.com/1246288
enabled AOT initialization of classes for the compiler
filter "assume-verified". However, this was untested and
broken because aborted transactions would leave created
array classes with partially rolled-back state on the heap.
Note that for other compiler filters, the verification step
creates those array classes outside of a transaction.
We fix this problem by making sure that the initialization
of an array class does not create any transaction records
for the class fields (we are keeping the defined class).
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: aosp_taimen-userdebug boots.
Test: adb root && \
adb shell stop && \
adb shell setprop dalvik.vm.boot-image \
'boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof' && \
adb shell setprop dalvik.vm.image-dex2oat-filter \
assume-verified && \
adb shell start # Starts correctly.
Test: Extract the boot image extension compilation command
from the verbose log, change compiler filter to
"assume-verified" and execute with no crashes.
Bug: 119800099
Change-Id: Id57a01af0a015c75a16eea12fd19599ae76ce49a
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index cde0432..e1dc544 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -139,6 +139,7 @@
#include "thread-inl.h"
#include "thread_list.h"
#include "trace.h"
+#include "transaction.h"
#include "utils/dex_cache_arrays_layout-inl.h"
#include "verifier/class_verifier.h"
#include "well_known_classes.h"
@@ -2179,7 +2180,7 @@
// class loader is only the initiating loader but not the defining loader.
// Avoid read barrier since we are comparing against null.
if (klass->GetClassLoader<kDefaultVerifyFlags, kWithoutReadBarrier>() != nullptr) {
- klass->SetClassLoader</*kCheckTransaction=*/ false>(loader);
+ klass->SetClassLoader(loader);
}
}
}
@@ -2636,7 +2637,7 @@
// Arrays are access-checks-clean and preverified.
access_flags |= kAccVerificationAttempted;
- array_class->SetAccessFlags(access_flags);
+ array_class->SetAccessFlagsDuringLinking(access_flags);
// Array classes are fully initialized either during single threaded startup,
// or from a pre-fence visitor, so visibly initialized.
@@ -3694,7 +3695,7 @@
klass->SetClass(GetClassRoot<mirror::Class>(this));
uint32_t access_flags = dex_class_def.GetJavaAccessFlags();
CHECK_EQ(access_flags & ~kAccJavaFlagsMask, 0U);
- klass->SetAccessFlags(access_flags);
+ klass->SetAccessFlagsDuringLinking(access_flags);
klass->SetClassLoader(class_loader);
DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
mirror::Class::SetStatus(klass, ClassStatus::kIdx, nullptr);
@@ -4245,7 +4246,7 @@
CHECK(primitive_class != nullptr) << "OOM for primitive class " << type;
// Do not hold lock on the primitive class object, the initialization of
// primitive classes is done while the process is still single threaded.
- primitive_class->SetAccessFlags(
+ primitive_class->SetAccessFlagsDuringLinking(
kAccPublic | kAccFinal | kAccAbstract | kAccVerificationAttempted);
primitive_class->SetPrimitiveType(type);
primitive_class->SetIfTable(GetClassRoot<mirror::Object>(this)->GetIfTable());
@@ -4362,6 +4363,7 @@
auto visitor = [this, array_class_size, component_type](ObjPtr<mirror::Object> obj,
size_t usable_size)
REQUIRES_SHARED(Locks::mutator_lock_) {
+ ScopedAssertNoNewTransactionRecords sanntr("CreateArrayClass");
mirror::Class::InitializeClassVisitor init_class(array_class_size);
init_class(obj, usable_size);
ObjPtr<mirror::Class> klass = ObjPtr<mirror::Class>::DownCast(obj);
@@ -4962,7 +4964,8 @@
temp_klass->SetObjectSize(sizeof(mirror::Proxy));
// Set the class access flags incl. VerificationAttempted, so we do not try to set the flag on
// the methods.
- temp_klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccVerificationAttempted);
+ temp_klass->SetAccessFlagsDuringLinking(
+ kAccClassIsProxy | kAccPublic | kAccFinal | kAccVerificationAttempted);
temp_klass->SetClassLoader(soa.Decode<mirror::ClassLoader>(loader));
DCHECK_EQ(temp_klass->GetPrimitiveType(), Primitive::kPrimNot);
temp_klass->SetName(soa.Decode<mirror::String>(name));