summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/driver/compiler_driver.cc28
-rw-r--r--runtime/aot_class_linker.cc22
-rw-r--r--runtime/aot_class_linker.h7
-rw-r--r--runtime/class_linker.cc6
-rw-r--r--runtime/class_linker.h6
-rw-r--r--test/660-clinit/expected.txt1
-rw-r--r--test/660-clinit/profile5
-rw-r--r--test/660-clinit/src/Main.java63
-rw-r--r--test/906-iterate-heap/expected.txt2
-rw-r--r--test/906-iterate-heap/src/art/Test906.java29
-rw-r--r--test/913-heaps/expected.txt2
-rw-r--r--test/913-heaps/src/art/Test913.java29
-rw-r--r--test/knownfailures.json6
13 files changed, 173 insertions, 33 deletions
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 <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 @@ 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<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 @@ class InitializeClassVisitor : public CompilationVisitor {
}
}
- 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 {
diff --git a/runtime/aot_class_linker.cc b/runtime/aot_class_linker.cc
index b1bc3f8f2e..d8f9e22962 100644
--- a/runtime/aot_class_linker.cc
+++ b/runtime/aot_class_linker.cc
@@ -27,6 +27,16 @@ AotClassLinker::AotClassLinker(InternTable *intern_table) : ClassLinker(intern_t
AotClassLinker::~AotClassLinker() {}
+bool AotClassLinker::CanAllocClass() {
+ // AllocClass doesn't work under transaction, so we abort.
+ if (Runtime::Current()->IsActiveTransaction()) {
+ Runtime::Current()->AbortTransactionAndThrowAbortError(Thread::Current(), "Can't resolve this "
+ "type within a transaction.");
+ return false;
+ }
+ return ClassLinker::CanAllocClass();
+}
+
// Wrap the original InitializeClass with creation of transaction when in strict mode.
bool AotClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
bool can_init_statics, bool can_init_parents) {
@@ -38,6 +48,13 @@ bool AotClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
return ClassLinker::InitializeClass(self, klass, can_init_statics, can_init_parents);
}
+ // When in strict_mode, don't initialize a class if it belongs to boot but not initialized.
+ if (strict_mode_ && klass->IsBootStrapClassLoaded()) {
+ runtime->AbortTransactionAndThrowAbortError(self, "Can't resolve "
+ + klass->PrettyTypeOf() + " because it is an uninitialized boot class.");
+ return false;
+ }
+
// Don't initialize klass if it's superclass is not initialized, because superclass might abort
// the transaction and rolled back after klass's change is commited.
if (strict_mode_ && !klass->IsInterface() && klass->HasSuperClass()) {
@@ -58,9 +75,8 @@ bool AotClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
// Exit Transaction if success.
runtime->ExitTransactionMode();
} else {
- // If not successfully initialized, the last transaction must abort. Don't rollback
- // immediately, leave the cleanup to compiler driver which needs abort message and exception.
- DCHECK(runtime->IsTransactionAborted());
+ // If not successfully initialized, don't rollback immediately, leave the cleanup to compiler
+ // driver which needs abort message and exception.
DCHECK(self->IsExceptionPending());
}
}
diff --git a/runtime/aot_class_linker.h b/runtime/aot_class_linker.h
index 11bea86fc4..e9a96fae20 100644
--- a/runtime/aot_class_linker.h
+++ b/runtime/aot_class_linker.h
@@ -27,6 +27,13 @@ class AotClassLinker : public ClassLinker {
explicit AotClassLinker(InternTable *intern_table);
~AotClassLinker();
+ // Override AllocClass because aot compiler will need to perform a transaction check to determine
+ // can we allocate class from heap.
+ bool CanAllocClass()
+ OVERRIDE
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Roles::uninterruptible_);
+
bool InitializeClass(Thread *self,
Handle<mirror::Class> klass,
bool can_run_clinit,
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 3ac87c5137..46b0113cdd 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2854,7 +2854,11 @@ mirror::Class* ClassLinker::DefineClass(Thread* self,
// Interface object should get the right size here. Regular class will
// figure out the right size later and be replaced with one of the right
// size when the class becomes resolved.
- klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));
+ if (CanAllocClass()) {
+ klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));
+ } else {
+ return nullptr;
+ }
}
if (UNLIKELY(klass == nullptr)) {
self->AssertPendingOOMException();
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index bf14aebb52..584bd1d5ce 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -710,6 +710,12 @@ class ClassLinker {
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::dex_lock_);
+ virtual bool CanAllocClass()
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!Locks::dex_lock_) {
+ return true;
+ }
+
private:
class LinkInterfaceMethodsHelper;
diff --git a/test/660-clinit/expected.txt b/test/660-clinit/expected.txt
index 9eb4941276..ee1b47929e 100644
--- a/test/660-clinit/expected.txt
+++ b/test/660-clinit/expected.txt
@@ -1,4 +1,5 @@
JNI_OnLoad called
+hello world
A.a: 5
A.a: 10
B.b: 10
diff --git a/test/660-clinit/profile b/test/660-clinit/profile
index 0239f22039..9eb4924ab1 100644
--- a/test/660-clinit/profile
+++ b/test/660-clinit/profile
@@ -4,7 +4,10 @@ LDay;
LA;
LB;
LC;
+LE;
LG;
LGs;
LObjectRef;
-
+LInvokeStatic;
+LClinitE;
+LPrint;
diff --git a/test/660-clinit/src/Main.java b/test/660-clinit/src/Main.java
index f9b068e110..51b4d604f5 100644
--- a/test/660-clinit/src/Main.java
+++ b/test/660-clinit/src/Main.java
@@ -24,19 +24,28 @@ public class Main {
if (!checkAppImageLoaded()) {
System.out.println("AppImage not loaded.");
}
+ if (!checkAppImageContains(ClInit.class)) {
+ System.out.println("ClInit class is not in app image!");
+ }
- expectNotPreInit(Day.class);
- expectNotPreInit(ClInit.class); // should pass
- expectNotPreInit(A.class); // should pass
- expectNotPreInit(B.class); // should fail
- expectNotPreInit(C.class); // should fail
- expectNotPreInit(G.class); // should fail
- expectNotPreInit(Gs.class); // should fail
- expectNotPreInit(Gss.class); // should fail
+ expectPreInit(ClInit.class);
+ expectPreInit(A.class);
+ expectPreInit(E.class);
+ expectNotPreInit(B.class);
+ expectNotPreInit(C.class);
+ expectNotPreInit(G.class);
+ expectNotPreInit(Gs.class);
+ expectNotPreInit(Gss.class);
+ expectPreInit(InvokeStatic.class);
+ expectNotPreInit(ClinitE.class);
expectNotPreInit(Add.class);
expectNotPreInit(Mul.class);
expectNotPreInit(ObjectRef.class);
+ expectNotPreInit(Print.class);
+
+ Print p = new Print();
+ Gs gs = new Gs();
A x = new A();
System.out.println("A.a: " + A.a);
@@ -62,6 +71,10 @@ public class Main {
System.out.println("a != 101");
}
+ try {
+ ClinitE e = new ClinitE();
+ } catch (Error err) { }
+
return;
}
@@ -154,6 +167,13 @@ class C {
}
}
+class E {
+ public static final int e;
+ static {
+ e = 100;
+ }
+}
+
class G {
static G g;
static int i;
@@ -182,9 +202,36 @@ class Add {
}
}
+// test of INVOKE_STATIC instruction
+class InvokeStatic {
+ static int a;
+ static int b;
+ static {
+ a = Add.exec(10, 20);
+ b = Mul.exec(10, 20);
+ }
+}
+
// non-image
class Mul {
static int exec(int a, int b) {
return a * b;
}
}
+
+class ClinitE {
+ static {
+ if (Math.sin(3) < 0.5) {
+ // throw anyway, can't initialized
+ throw new ExceptionInInitializerError("Can't initialize this class!");
+ }
+ }
+}
+
+// fail because JNI
+class Print {
+ static {
+ System.out.println("hello world");
+ }
+}
+
diff --git a/test/906-iterate-heap/expected.txt b/test/906-iterate-heap/expected.txt
index 73b7129bba..85391fa25a 100644
--- a/test/906-iterate-heap/expected.txt
+++ b/test/906-iterate-heap/expected.txt
@@ -19,9 +19,7 @@
1@0 (32, 2xD '0000000000000000000000000000f03f')
2
doTestPrimitiveFieldsClasses
-10000@0 (static, int, index=3) 0000000000000000
10001
-10000@0 (static, int, index=11) 0000000000000000
10001
10001
10001
diff --git a/test/906-iterate-heap/src/art/Test906.java b/test/906-iterate-heap/src/art/Test906.java
index 65c2c8c560..1878687e26 100644
--- a/test/906-iterate-heap/src/art/Test906.java
+++ b/test/906-iterate-heap/src/art/Test906.java
@@ -143,19 +143,40 @@ public class Test906 {
private static void doTestPrimitiveFieldsClasses() {
System.out.println("doTestPrimitiveFieldsClasses");
+ boolean correctHeapValue = false;
+
setTag(IntObject.class, 10000);
- System.out.println(iterateThroughHeapPrimitiveFields(10000));
+ String heapTrace = iterateThroughHeapPrimitiveFields(10000);
+
+ if (!checkInitialized(IntObject.class)) {
+ correctHeapValue = heapTrace.equals("10000@0 (static, int, index=3) 0000000000000000");
+ } else {
+ correctHeapValue = heapTrace.equals("10000@0 (static, int, index=3) 0000000000000005");
+ }
+
+ if (!correctHeapValue)
+ System.out.println("Heap Trace for IntObject is not as expected:\n" + heapTrace);
+
System.out.println(getTag(IntObject.class));
setTag(IntObject.class, 0);
setTag(FloatObject.class, 10000);
- System.out.println(iterateThroughHeapPrimitiveFields(10000));
+ heapTrace = iterateThroughHeapPrimitiveFields(10000);
+
+ if (!checkInitialized(FloatObject.class)) {
+ correctHeapValue = heapTrace.equals("10000@0 (static, int, index=11) 0000000000000000");
+ } else {
+ correctHeapValue = heapTrace.equals("10000@0 (static, int, index=11) 0000000000000006");
+ }
+
+ if (!correctHeapValue)
+ System.out.println("Heap Trace for FloatObject is not as expected:\n" + heapTrace);
+
System.out.println(getTag(FloatObject.class));
setTag(FloatObject.class, 0);
- boolean correctHeapValue = false;
setTag(Inf1.class, 10000);
- String heapTrace = iterateThroughHeapPrimitiveFields(10000);
+ heapTrace = iterateThroughHeapPrimitiveFields(10000);
if (!checkInitialized(Inf1.class)) {
correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000000");
diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt
index 6144881a55..844afe8172 100644
--- a/test/913-heaps/expected.txt
+++ b/test/913-heaps/expected.txt
@@ -136,9 +136,7 @@ root@root --(thread)--> 3000@0 [size=136, length=-1]
4@0 (18, 3xS '010002000300')
1@0 (14, 2xZ '0001')
23456789
-10000@0 (static, int, index=3) 0000000000000000
10001
-10000@0 (static, int, index=11) 0000000000000000
10001
10001
10001
diff --git a/test/913-heaps/src/art/Test913.java b/test/913-heaps/src/art/Test913.java
index b9990010ff..28f9546d95 100644
--- a/test/913-heaps/src/art/Test913.java
+++ b/test/913-heaps/src/art/Test913.java
@@ -185,19 +185,40 @@ public class Test913 {
}
private static void doTestPrimitiveFieldsClasses() {
+ boolean correctHeapValue = false;
+
setTag(IntObject.class, 10000);
- System.out.println(followReferencesPrimitiveFields(IntObject.class));
+ String heapTrace = followReferencesPrimitiveFields(IntObject.class);
+
+ if (!checkInitialized(IntObject.class)) {
+ correctHeapValue = heapTrace.equals("10000@0 (static, int, index=3) 0000000000000000");
+ } else {
+ correctHeapValue = heapTrace.equals("10000@0 (static, int, index=3) 0000000000000005");
+ }
+
+ if (!correctHeapValue)
+ System.out.println("Heap Trace for IntObject is not as expected:\n" + heapTrace);
+
System.out.println(getTag(IntObject.class));
setTag(IntObject.class, 0);
setTag(FloatObject.class, 10000);
- System.out.println(followReferencesPrimitiveFields(FloatObject.class));
+ heapTrace = followReferencesPrimitiveFields(FloatObject.class);
+
+ if (!checkInitialized(FloatObject.class)) {
+ correctHeapValue = heapTrace.equals("10000@0 (static, int, index=11) 0000000000000000");
+ } else {
+ correctHeapValue = heapTrace.equals("10000@0 (static, int, index=11) 0000000000000006");
+ }
+
+ if (!correctHeapValue)
+ System.out.println("Heap Trace for FloatObject is not as expected:\n" + heapTrace);
+
System.out.println(getTag(FloatObject.class));
setTag(FloatObject.class, 0);
- boolean correctHeapValue = false;
setTag(Inf1.class, 10000);
- String heapTrace = followReferencesPrimitiveFields(Inf1.class);
+ heapTrace = followReferencesPrimitiveFields(Inf1.class);
if (!checkInitialized(Inf1.class)) {
correctHeapValue = heapTrace.equals("10000@0 (static, int, index=0) 0000000000000000");
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 5a67fbcc45..04de7a1a74 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -708,8 +708,8 @@
},
{
"tests": "660-clinit",
- "variant": "no-image | no-dex2oat | no-prebuild",
- "description": ["Tests <clinit> for app images, which --no-image, --no-prebuild and",
- "--no-dex2oat do not create"]
+ "variant": "no-image | no-dex2oat | no-prebuild | interp-ac",
+ "description": ["Tests <clinit> for app images, which --no-image, --no-prebuild, interp-ac",
+ "and --no-dex2oat do not create"]
}
]