From 50ce4414a6154ee2d9eeaa27237d80b685e5acf1 Mon Sep 17 00:00:00 2001 From: Chang Xing Date: Fri, 21 Jul 2017 12:21:26 -0700 Subject: 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 --- compiler/driver/compiler_driver.cc | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index bd530ac6a6..5eee7e003b 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -2251,6 +2251,7 @@ class InitializeClassVisitor : public CompilationVisitor { 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 @@ class InitializeClassVisitor : public CompilationVisitor { 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 @@ class InitializeClassVisitor : public CompilationVisitor { 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 @@ class InitializeClassVisitor : public CompilationVisitor { 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 behavior to be observable for the debugger, so we don't do the + // 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 @@ class InitializeClassVisitor : public CompilationVisitor { // 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 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 @@ class InitializeClassVisitor : public CompilationVisitor { } } - if (!success) { + if (!success && is_boot_image) { // On failure, still intern strings of static fields and seen in , 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 { -- cgit v1.2.3-59-g8ed1b