diff options
| -rw-r--r-- | runtime/cha.cc | 8 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 5 | ||||
| -rw-r--r-- | test/966-default-conflict/expected.txt | 1 | ||||
| -rw-r--r-- | test/966-default-conflict/src/Main.java | 9 |
4 files changed, 20 insertions, 3 deletions
diff --git a/runtime/cha.cc b/runtime/cha.cc index 3ea920dff1..d8cb525719 100644 --- a/runtime/cha.cc +++ b/runtime/cha.cc @@ -507,7 +507,8 @@ void ClassHierarchyAnalysis::CheckInterfaceMethodSingleImplementationInfo( return; } DCHECK(!single_impl->IsAbstract()); - if (single_impl->GetDeclaringClass() == implementation_method->GetDeclaringClass()) { + if ((single_impl->GetDeclaringClass() == implementation_method->GetDeclaringClass()) && + !implementation_method->IsDefaultConflicting()) { // Same implementation. Since implementation_method may be a copy of a default // method, we need to check the declaring class for equality. return; @@ -543,7 +544,10 @@ void ClassHierarchyAnalysis::InitSingleImplementationFlag(Handle<mirror::Class> method->SetHasSingleImplementation(true); DCHECK(method->GetSingleImplementation(pointer_size) == nullptr); } - } else { + // Default conflicting methods cannot be treated with single implementations, + // as we need to call them (and not inline them) in case of ICCE. + // See class_linker.cc:EnsureThrowsInvocationError. + } else if (!method->IsDefaultConflicting()) { method->SetHasSingleImplementation(true); // Single implementation of non-abstract method is itself. DCHECK_EQ(method->GetSingleImplementation(pointer_size), method); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index e19dedcebd..489d602bc6 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -7039,9 +7039,12 @@ void ClassLinker::LinkInterfaceMethodsHelper::ReallocMethods() { // mark this as a default, non-abstract method, since thats what it is. Also clear the // kAccSkipAccessChecks bit since this class hasn't been verified yet it shouldn't have // methods that are skipping access checks. + // Also clear potential kAccSingleImplementation to avoid CHA trying to inline + // the default method. DCHECK_EQ(new_method.GetAccessFlags() & kAccNative, 0u); constexpr uint32_t kSetFlags = kAccDefault | kAccDefaultConflict | kAccCopied; - constexpr uint32_t kMaskFlags = ~(kAccAbstract | kAccSkipAccessChecks); + constexpr uint32_t kMaskFlags = + ~(kAccAbstract | kAccSkipAccessChecks | kAccSingleImplementation); new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags); DCHECK(new_method.IsDefaultConflicting()); // The actual method might or might not be marked abstract since we just copied it from a diff --git a/test/966-default-conflict/expected.txt b/test/966-default-conflict/expected.txt index fad2c25979..bbd733ca90 100644 --- a/test/966-default-conflict/expected.txt +++ b/test/966-default-conflict/expected.txt @@ -1,3 +1,4 @@ +JNI_OnLoad called Create Main instance Calling functions on concrete Main Calling non-conflicting function on Main diff --git a/test/966-default-conflict/src/Main.java b/test/966-default-conflict/src/Main.java index ce8cb47209..f4667155b5 100644 --- a/test/966-default-conflict/src/Main.java +++ b/test/966-default-conflict/src/Main.java @@ -15,6 +15,13 @@ */ class Main implements Iface, Iface2 { public static void main(String[] args) { + System.loadLibrary(args[0]); + // Ensure we JIT compile the methods to test CHA behavior with default + // methods. + ensureJitCompiled(Main.class, "callMain"); + ensureJitCompiled(Main.class, "callIface"); + ensureJitCompiled(Main.class, "callIface2"); + System.out.println("Create Main instance"); Main m = new Main(); System.out.println("Calling functions on concrete Main"); @@ -68,4 +75,6 @@ class Main implements Iface, Iface2 { } return; } + + private static native void ensureJitCompiled(Class<?> cls, String method_name); } |