Support clinit for app image during compilation
Enabled compiler driver to start initialization process for classes with
static class initializers if debuggable flag is not setted because this
might change the behaviour of interpreter (although invisible to user),
e.g. the memory heap at startup will contains initialization results.
Updated two testcases to reflect the change of heap memory before
classes are initialized.
Enabled testcase 660-clinit to test whether class initializers are
executed.
This CL have to be submitted after /c/432328, /c/432154, /c/433242 and
/c/433342 because without that four this will break the build. Besides,
the other four CL will be tested in this CL.
Test: make test-art-host -j64
Change-Id: Ia25b9e18bdcd0fa3619be0058d459651f3b9a492
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index bd530ac..5eee7e0 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2251,6 +2251,7 @@
const char* descriptor = dex_file.StringDataByIdx(class_type_id.descriptor_idx_);
ScopedObjectAccessUnchecked soa(Thread::Current());
StackHandleScope<3> hs(soa.Self());
+ ClassLinker *class_linker = manager_->GetClassLinker();
const bool is_boot_image = manager_->GetCompiler()->GetCompilerOptions().IsBootImage();
const bool is_app_image = manager_->GetCompiler()->GetCompilerOptions().IsAppImage();
@@ -2264,7 +2265,7 @@
if (klass->IsVerified()) {
// Attempt to initialize the class but bail if we either need to initialize the super-class
// or static fields.
- manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, false);
+ class_linker->EnsureInitialized(soa.Self(), klass, false, false);
old_status = klass->GetStatus();
if (!klass->IsInitialized()) {
// We don't want non-trivial class initialization occurring on multiple threads due to
@@ -2283,7 +2284,7 @@
bool is_superclass_initialized = !is_app_image ? true :
InitializeDependencies(klass, class_loader, soa.Self());
if (!is_app_image || (is_app_image && is_superclass_initialized)) {
- manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, true);
+ class_linker->EnsureInitialized(soa.Self(), klass, false, true);
}
// Otherwise it's in app image but superclasses can't be initialized, no need to proceed.
old_status = klass->GetStatus();
@@ -2309,10 +2310,13 @@
CHECK(is_app_image);
// The boot image case doesn't need to recursively initialize the dependencies with
// special logic since the class linker already does this.
+ // Optimization will be disabled in debuggable build, because in debuggable mode we
+ // want the <clinit> behavior to be observable for the debugger, so we don't do the
+ // <clinit> at compile time.
can_init_static_fields =
+ !manager_->GetCompiler()->GetCompilerOptions().GetDebuggable() &&
!soa.Self()->IsExceptionPending() &&
- is_superclass_initialized &&
- NoClinitInDependency(klass, soa.Self(), &class_loader);
+ is_superclass_initialized;
// TODO The checking for clinit can be removed since it's already
// checked when init superclass. Currently keep it because it contains
// processing of intern strings. Will be removed later when intern strings
@@ -2326,6 +2330,18 @@
// a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity
// checks in Thread::AssertThreadSuspensionIsAllowable.
Runtime* const runtime = Runtime::Current();
+ // Resolve and initialize the exception type before enabling the transaction in case
+ // the transaction aborts and cannot resolve the type.
+ // TransactionAbortError is not initialized ant not in boot image, needed only by
+ // compiler and will be pruned by ImageWriter.
+ Handle<mirror::Class> exception_class =
+ hs.NewHandle(class_linker->FindClass(Thread::Current(),
+ Transaction::kAbortExceptionSignature,
+ class_loader));
+ bool exception_initialized =
+ class_linker->EnsureInitialized(soa.Self(), exception_class, true, true);
+ DCHECK(exception_initialized);
+
// Run the class initializer in transaction mode.
runtime->EnterTransactionMode(is_app_image, klass.Get());
bool success = manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, true,
@@ -2363,10 +2379,12 @@
}
}
- if (!success) {
+ if (!success && is_boot_image) {
// On failure, still intern strings of static fields and seen in <clinit>, as these
// will be created in the zygote. This is separated from the transaction code just
// above as we will allocate strings, so must be allowed to suspend.
+ // We only need to intern strings for boot image because classes that failed to be
+ // initialized will not appear in app image.
if (&klass->GetDexFile() == manager_->GetDexFile()) {
InternStrings(klass, class_loader);
} else {