summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/instruction_builder.cc15
-rw-r--r--test/174-escaping-instance-of-bad-class/expected.txt2
-rw-r--r--test/174-escaping-instance-of-bad-class/src/Main.java21
-rw-r--r--test/551-checker-clinit/src/Main.java22
4 files changed, 54 insertions, 6 deletions
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index bd94789144..63b2705b43 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1304,15 +1304,18 @@ bool HInstructionBuilder::IsInitialized(ScopedObjectAccess& soa, Handle<mirror::
}
}
- // We can avoid the class initialization check for `cls` in static methods in the
- // very same class. Instance methods of the same class can run on an escaped instance
+ // We can avoid the class initialization check for `cls` in static methods and constructors
+ // in the very same class; invoking a static method involves a class initialization check
+ // and so does the instance allocation that must be executed before invoking a constructor.
+ // Other instance methods of the same class can run on an escaped instance
// of an erroneous class. Even a superclass may need to be checked as the subclass
// can be completely initialized while the superclass is initializing and the subclass
// remains initialized when the superclass initializer throws afterwards. b/62478025
// Note: The HClinitCheck+HInvokeStaticOrDirect merging can still apply.
ObjPtr<mirror::Class> outermost_cls = ResolveOutermostCompilingClass(soa);
- bool is_static = (dex_compilation_unit_->GetAccessFlags() & kAccStatic) != 0u;
- if (is_static && outermost_cls == cls.Get()) {
+ bool is_outer_static_or_constructor =
+ (outer_compilation_unit_->GetAccessFlags() & (kAccStatic | kAccConstructor)) != 0u;
+ if (is_outer_static_or_constructor && outermost_cls == cls.Get()) {
return true;
}
// Remember if the compiled class is a subclass of `cls`. By the time this is used
@@ -1325,7 +1328,9 @@ bool HInstructionBuilder::IsInitialized(ScopedObjectAccess& soa, Handle<mirror::
// TODO: We should walk over the entire inlined method chain, but we don't pass that
// information to the builder.
ObjPtr<mirror::Class> innermost_cls = ResolveCompilingClass(soa);
- if (is_static && innermost_cls == cls.Get()) {
+ bool is_inner_static_or_constructor =
+ (dex_compilation_unit_->GetAccessFlags() & (kAccStatic | kAccConstructor)) != 0u;
+ if (is_inner_static_or_constructor && innermost_cls == cls.Get()) {
return true;
}
is_subclass = is_subclass || IsSubClass(innermost_cls, cls.Get());
diff --git a/test/174-escaping-instance-of-bad-class/expected.txt b/test/174-escaping-instance-of-bad-class/expected.txt
index e287759d44..611d698f1a 100644
--- a/test/174-escaping-instance-of-bad-class/expected.txt
+++ b/test/174-escaping-instance-of-bad-class/expected.txt
@@ -1,6 +1,8 @@
Bad.foo()
Bad.instanceValue = 33
Caught NoClassDefFoundError.
+Bad.bar()
+Caught NoClassDefFoundError.
BadSuper.foo()
BadSuper.superInstanceValue = 1
Caught NoClassDefFoundError.
diff --git a/test/174-escaping-instance-of-bad-class/src/Main.java b/test/174-escaping-instance-of-bad-class/src/Main.java
index 4346152f6c..4f66a31837 100644
--- a/test/174-escaping-instance-of-bad-class/src/Main.java
+++ b/test/174-escaping-instance-of-bad-class/src/Main.java
@@ -39,6 +39,17 @@ public class Main {
ncdfe.printStackTrace();
}
}
+ // Call bar() on the escaped instance of Bad.
+ try {
+ bad.bar();
+ } catch (NoClassDefFoundError ncdfe) {
+ // On RI, the NCDFE has no cause. On ART, the badClinit is the cause.
+ if (ncdfe.getCause() == badClinit || ncdfe.getCause() == null) {
+ System.out.println("Caught NoClassDefFoundError.");
+ } else {
+ ncdfe.printStackTrace();
+ }
+ }
}
public static void hierarchyTest() {
@@ -117,9 +128,19 @@ class Bad {
System.out.println("Bad.instanceValue = " + instanceValue);
System.out.println("Bad.staticValue = " + staticValue);
}
+ public void bar() {
+ System.out.println("Bad.bar()");
+ System.out.println("Bad.staticValue [indirect] = " + Helper.$inline$getBadStaticValue());
+ }
public Bad(int iv) { instanceValue = iv; }
public int instanceValue;
public static int staticValue;
+
+ public static class Helper {
+ public static int $inline$getBadStaticValue() {
+ return Bad.staticValue;
+ }
+ }
}
class BadSuper {
diff --git a/test/551-checker-clinit/src/Main.java b/test/551-checker-clinit/src/Main.java
index ab92cd03fd..0eea8009a6 100644
--- a/test/551-checker-clinit/src/Main.java
+++ b/test/551-checker-clinit/src/Main.java
@@ -57,7 +57,7 @@ class Sub extends Main {
}
/// CHECK-START: void Sub.invokeSubClass() builder (after)
- /// CHECK: ClinitCheck
+ /// CHECK: ClinitCheck
public void invokeSubClass() {
int a = SubSub.foo;
}
@@ -71,3 +71,23 @@ class SubSub {
}
public static int foo = 42;
}
+
+class NonTrivial {
+ public static int staticFoo = 42;
+ public int instanceFoo;
+
+ static {
+ System.out.println("NonTrivial.<clinit>");
+ }
+
+ /// CHECK-START: void NonTrivial.<init>() builder (after)
+ /// CHECK-NOT: ClinitCheck
+
+ /// CHECK-START: void NonTrivial.<init>() builder (after)
+ /// CHECK: StaticFieldGet
+ public NonTrivial() {
+ // ClinitCheck is eliminated because this is a constructor and therefore the
+ // corresponding new-instance in the caller must have performed the check.
+ instanceFoo = staticFoo;
+ }
+}