8043275: Fix interface initialization for default methods
Initialize interfaces that declare concrete instance methods. Reviewed-by: kamg, coleenp, psandoz
This commit is contained in:
parent
209ffcd9a5
commit
0e1283a811
@ -2557,7 +2557,7 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
|
|||||||
Array<Method*>* ClassFileParser::parse_methods(bool is_interface,
|
Array<Method*>* ClassFileParser::parse_methods(bool is_interface,
|
||||||
AccessFlags* promoted_flags,
|
AccessFlags* promoted_flags,
|
||||||
bool* has_final_method,
|
bool* has_final_method,
|
||||||
bool* has_default_methods,
|
bool* declares_default_methods,
|
||||||
TRAPS) {
|
TRAPS) {
|
||||||
ClassFileStream* cfs = stream();
|
ClassFileStream* cfs = stream();
|
||||||
cfs->guarantee_more(2, CHECK_NULL); // length
|
cfs->guarantee_more(2, CHECK_NULL); // length
|
||||||
@ -2576,11 +2576,11 @@ Array<Method*>* ClassFileParser::parse_methods(bool is_interface,
|
|||||||
if (method->is_final()) {
|
if (method->is_final()) {
|
||||||
*has_final_method = true;
|
*has_final_method = true;
|
||||||
}
|
}
|
||||||
if (is_interface && !(*has_default_methods)
|
// declares_default_methods: declares concrete instance methods, any access flags
|
||||||
&& !method->is_abstract() && !method->is_static()
|
// used for interface initialization, and default method inheritance analysis
|
||||||
&& !method->is_private()) {
|
if (is_interface && !(*declares_default_methods)
|
||||||
// default method
|
&& !method->is_abstract() && !method->is_static()) {
|
||||||
*has_default_methods = true;
|
*declares_default_methods = true;
|
||||||
}
|
}
|
||||||
_methods->at_put(index, method());
|
_methods->at_put(index, method());
|
||||||
}
|
}
|
||||||
@ -3739,6 +3739,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
|
|||||||
JvmtiCachedClassFileData *cached_class_file = NULL;
|
JvmtiCachedClassFileData *cached_class_file = NULL;
|
||||||
Handle class_loader(THREAD, loader_data->class_loader());
|
Handle class_loader(THREAD, loader_data->class_loader());
|
||||||
bool has_default_methods = false;
|
bool has_default_methods = false;
|
||||||
|
bool declares_default_methods = false;
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
|
|
||||||
ClassFileStream* cfs = stream();
|
ClassFileStream* cfs = stream();
|
||||||
@ -3976,9 +3977,13 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
|
|||||||
Array<Method*>* methods = parse_methods(access_flags.is_interface(),
|
Array<Method*>* methods = parse_methods(access_flags.is_interface(),
|
||||||
&promoted_flags,
|
&promoted_flags,
|
||||||
&has_final_method,
|
&has_final_method,
|
||||||
&has_default_methods,
|
&declares_default_methods,
|
||||||
CHECK_(nullHandle));
|
CHECK_(nullHandle));
|
||||||
|
|
||||||
|
if (declares_default_methods) {
|
||||||
|
has_default_methods = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Additional attributes
|
// Additional attributes
|
||||||
ClassAnnotationCollector parsed_annotations;
|
ClassAnnotationCollector parsed_annotations;
|
||||||
parse_classfile_attributes(&parsed_annotations, CHECK_(nullHandle));
|
parse_classfile_attributes(&parsed_annotations, CHECK_(nullHandle));
|
||||||
@ -4120,6 +4125,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
|
|||||||
this_klass->set_minor_version(minor_version);
|
this_klass->set_minor_version(minor_version);
|
||||||
this_klass->set_major_version(major_version);
|
this_klass->set_major_version(major_version);
|
||||||
this_klass->set_has_default_methods(has_default_methods);
|
this_klass->set_has_default_methods(has_default_methods);
|
||||||
|
this_klass->set_declares_default_methods(declares_default_methods);
|
||||||
|
|
||||||
if (!host_klass.is_null()) {
|
if (!host_klass.is_null()) {
|
||||||
assert (this_klass->is_anonymous(), "should be the same");
|
assert (this_klass->is_anonymous(), "should be the same");
|
||||||
|
5274
hotspot/src/share/vm/classfile/classFileParser.cpp.orig
Normal file
5274
hotspot/src/share/vm/classfile/classFileParser.cpp.orig
Normal file
File diff suppressed because it is too large
Load Diff
@ -247,7 +247,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
|||||||
Array<Method*>* parse_methods(bool is_interface,
|
Array<Method*>* parse_methods(bool is_interface,
|
||||||
AccessFlags* promoted_flags,
|
AccessFlags* promoted_flags,
|
||||||
bool* has_final_method,
|
bool* has_final_method,
|
||||||
bool* has_default_method,
|
bool* declares_default_methods,
|
||||||
TRAPS);
|
TRAPS);
|
||||||
intArray* sort_methods(Array<Method*>* methods);
|
intArray* sort_methods(Array<Method*>* methods);
|
||||||
|
|
||||||
|
@ -736,6 +736,41 @@ void InstanceKlass::link_methods(TRAPS) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Eagerly initialize superinterfaces that declare default methods (concrete instance: any access)
|
||||||
|
void InstanceKlass::initialize_super_interfaces(instanceKlassHandle this_k, TRAPS) {
|
||||||
|
if (this_k->has_default_methods()) {
|
||||||
|
for (int i = 0; i < this_k->local_interfaces()->length(); ++i) {
|
||||||
|
Klass* iface = this_k->local_interfaces()->at(i);
|
||||||
|
InstanceKlass* ik = InstanceKlass::cast(iface);
|
||||||
|
if (ik->should_be_initialized()) {
|
||||||
|
if (ik->has_default_methods()) {
|
||||||
|
ik->initialize_super_interfaces(ik, THREAD);
|
||||||
|
}
|
||||||
|
// Only initialize() interfaces that "declare" concrete methods.
|
||||||
|
// has_default_methods drives searching superinterfaces since it
|
||||||
|
// means has_default_methods in its superinterface hierarchy
|
||||||
|
if (!HAS_PENDING_EXCEPTION && ik->declares_default_methods()) {
|
||||||
|
ik->initialize(THREAD);
|
||||||
|
}
|
||||||
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
|
Handle e(THREAD, PENDING_EXCEPTION);
|
||||||
|
CLEAR_PENDING_EXCEPTION;
|
||||||
|
{
|
||||||
|
EXCEPTION_MARK;
|
||||||
|
// Locks object, set state, and notify all waiting threads
|
||||||
|
this_k->set_initialization_state_and_notify(
|
||||||
|
initialization_error, THREAD);
|
||||||
|
|
||||||
|
// ignore any exception thrown, superclass initialization error is
|
||||||
|
// thrown below
|
||||||
|
CLEAR_PENDING_EXCEPTION;
|
||||||
|
}
|
||||||
|
THROW_OOP(e());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void InstanceKlass::initialize_impl(instanceKlassHandle this_k, TRAPS) {
|
void InstanceKlass::initialize_impl(instanceKlassHandle this_k, TRAPS) {
|
||||||
// Make sure klass is linked (verified) before initialization
|
// Make sure klass is linked (verified) before initialization
|
||||||
@ -815,33 +850,11 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_k, TRAPS) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recursively initialize any superinterfaces that declare default methods
|
||||||
|
// Only need to recurse if has_default_methods which includes declaring and
|
||||||
|
// inheriting default methods
|
||||||
if (this_k->has_default_methods()) {
|
if (this_k->has_default_methods()) {
|
||||||
// Step 7.5: initialize any interfaces which have default methods
|
this_k->initialize_super_interfaces(this_k, CHECK);
|
||||||
for (int i = 0; i < this_k->local_interfaces()->length(); ++i) {
|
|
||||||
Klass* iface = this_k->local_interfaces()->at(i);
|
|
||||||
InstanceKlass* ik = InstanceKlass::cast(iface);
|
|
||||||
if (ik->has_default_methods() && ik->should_be_initialized()) {
|
|
||||||
ik->initialize(THREAD);
|
|
||||||
|
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
|
||||||
Handle e(THREAD, PENDING_EXCEPTION);
|
|
||||||
CLEAR_PENDING_EXCEPTION;
|
|
||||||
{
|
|
||||||
EXCEPTION_MARK;
|
|
||||||
// Locks object, set state, and notify all waiting threads
|
|
||||||
this_k->set_initialization_state_and_notify(
|
|
||||||
initialization_error, THREAD);
|
|
||||||
|
|
||||||
// ignore any exception thrown, superclass initialization error is
|
|
||||||
// thrown below
|
|
||||||
CLEAR_PENDING_EXCEPTION;
|
|
||||||
}
|
|
||||||
DTRACE_CLASSINIT_PROBE_WAIT(
|
|
||||||
super__failed, InstanceKlass::cast(this_k()), -1, wait);
|
|
||||||
THROW_OOP(e());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 8
|
// Step 8
|
||||||
|
@ -205,7 +205,8 @@ class InstanceKlass: public Klass {
|
|||||||
_misc_is_anonymous = 1 << 3, // has embedded _host_klass field
|
_misc_is_anonymous = 1 << 3, // has embedded _host_klass field
|
||||||
_misc_is_contended = 1 << 4, // marked with contended annotation
|
_misc_is_contended = 1 << 4, // marked with contended annotation
|
||||||
_misc_has_default_methods = 1 << 5, // class/superclass/implemented interfaces has default methods
|
_misc_has_default_methods = 1 << 5, // class/superclass/implemented interfaces has default methods
|
||||||
_misc_has_been_redefined = 1 << 6 // class has been redefined
|
_misc_declares_default_methods = 1 << 6, // directly declares default methods (any access)
|
||||||
|
_misc_has_been_redefined = 1 << 7 // class has been redefined
|
||||||
};
|
};
|
||||||
u2 _misc_flags;
|
u2 _misc_flags;
|
||||||
u2 _minor_version; // minor version number of class file
|
u2 _minor_version; // minor version number of class file
|
||||||
@ -651,6 +652,17 @@ class InstanceKlass: public Klass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool declares_default_methods() const {
|
||||||
|
return (_misc_flags & _misc_declares_default_methods) != 0;
|
||||||
|
}
|
||||||
|
void set_declares_default_methods(bool b) {
|
||||||
|
if (b) {
|
||||||
|
_misc_flags |= _misc_declares_default_methods;
|
||||||
|
} else {
|
||||||
|
_misc_flags &= ~_misc_declares_default_methods;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// for adding methods, ConstMethod::UNSET_IDNUM means no more ids available
|
// for adding methods, ConstMethod::UNSET_IDNUM means no more ids available
|
||||||
inline u2 next_method_idnum();
|
inline u2 next_method_idnum();
|
||||||
void set_initial_method_idnum(u2 value) { _idnum_allocated_count = value; }
|
void set_initial_method_idnum(u2 value) { _idnum_allocated_count = value; }
|
||||||
@ -1022,6 +1034,7 @@ private:
|
|||||||
static bool link_class_impl (instanceKlassHandle this_k, bool throw_verifyerror, TRAPS);
|
static bool link_class_impl (instanceKlassHandle this_k, bool throw_verifyerror, TRAPS);
|
||||||
static bool verify_code (instanceKlassHandle this_k, bool throw_verifyerror, TRAPS);
|
static bool verify_code (instanceKlassHandle this_k, bool throw_verifyerror, TRAPS);
|
||||||
static void initialize_impl (instanceKlassHandle this_k, TRAPS);
|
static void initialize_impl (instanceKlassHandle this_k, TRAPS);
|
||||||
|
static void initialize_super_interfaces (instanceKlassHandle this_k, TRAPS);
|
||||||
static void eager_initialize_impl (instanceKlassHandle this_k);
|
static void eager_initialize_impl (instanceKlassHandle this_k);
|
||||||
static void set_initialization_state_and_notify_impl (instanceKlassHandle this_k, ClassState state, TRAPS);
|
static void set_initialization_state_and_notify_impl (instanceKlassHandle this_k, ClassState state, TRAPS);
|
||||||
static void call_class_initializer_impl (instanceKlassHandle this_k, TRAPS);
|
static void call_class_initializer_impl (instanceKlassHandle this_k, TRAPS);
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
/* This file contains dummy provider probes needed when compiling a hotspot
|
/* This file contains dummy provider probes needed when compiling a hotspot
|
||||||
* that does not support dtrace probes. This could be because we're building
|
* that does not support dtrace probes. This could be because we're building
|
||||||
* on a system that doesn't suuport dtrace or because we're bulding a variant
|
* on a system that doesn't support dtrace or because we're bulding a variant
|
||||||
* of hotspot (like core) where we do not support dtrace
|
* of hotspot (like core) where we do not support dtrace
|
||||||
*/
|
*/
|
||||||
#if !defined(DTRACE_ENABLED)
|
#if !defined(DTRACE_ENABLED)
|
||||||
|
@ -33,11 +33,12 @@
|
|||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
public class InvokespecialInterface {
|
||||||
interface I {
|
interface I {
|
||||||
default void imethod() { System.out.println("I::imethod"); }
|
default void imethod() { System.out.println("I::imethod"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
class C implements I {
|
static class C implements I {
|
||||||
public void foo() { I.super.imethod(); } // invokespecial InterfaceMethod
|
public void foo() { I.super.imethod(); } // invokespecial InterfaceMethod
|
||||||
public void bar() { I i = this; i.imethod(); } // invokeinterface same
|
public void bar() { I i = this; i.imethod(); } // invokeinterface same
|
||||||
public void doSomeInvokedynamic() {
|
public void doSomeInvokedynamic() {
|
||||||
@ -48,7 +49,6 @@ class C implements I {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InvokespecialInterface {
|
|
||||||
public static void main(java.lang.String[] unused) {
|
public static void main(java.lang.String[] unused) {
|
||||||
// need to create C and call I::foo()
|
// need to create C and call I::foo()
|
||||||
C c = new C();
|
C c = new C();
|
||||||
|
87
hotspot/test/runtime/lambda-features/TestInterfaceInit.java
Normal file
87
hotspot/test/runtime/lambda-features/TestInterfaceInit.java
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8034275
|
||||||
|
* @summary [JDK 8u40] Test interface initialization: only for interfaces declaring default methods
|
||||||
|
* @run main TestInterfaceInit
|
||||||
|
*/
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class TestInterfaceInit {
|
||||||
|
|
||||||
|
static List<Class<?>> cInitOrder = new ArrayList<>();
|
||||||
|
|
||||||
|
// Declares a default method and initializes
|
||||||
|
interface I {
|
||||||
|
boolean v = TestInterfaceInit.out(I.class);
|
||||||
|
default void x() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Declares a default method and initializes
|
||||||
|
interface J extends I {
|
||||||
|
boolean v = TestInterfaceInit.out(J.class);
|
||||||
|
default void x() {}
|
||||||
|
}
|
||||||
|
// No default method, does not initialize
|
||||||
|
interface JN extends J {
|
||||||
|
boolean v = TestInterfaceInit.out(JN.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Declares a default method and initializes
|
||||||
|
interface K extends I {
|
||||||
|
boolean v = TestInterfaceInit.out(K.class);
|
||||||
|
default void x() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No default method, does not initialize
|
||||||
|
interface KN extends K {
|
||||||
|
boolean v = TestInterfaceInit.out(KN.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface L extends JN, KN {
|
||||||
|
boolean v = TestInterfaceInit.out(L.class);
|
||||||
|
default void x() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// Trigger initialization
|
||||||
|
boolean v = L.v;
|
||||||
|
|
||||||
|
List<Class<?>> expectedCInitOrder = Arrays.asList(I.class,J.class,K.class,L.class);
|
||||||
|
if (!cInitOrder.equals(expectedCInitOrder)) {
|
||||||
|
throw new RuntimeException(String.format("Class initialization array %s not equal to expected array %s", cInitOrder, expectedCInitOrder));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean out(Class c) {
|
||||||
|
System.out.println("#: initializing " + c.getName());
|
||||||
|
cInitOrder.add(c);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
88
hotspot/test/runtime/lambda-features/TestInterfaceOrder.java
Normal file
88
hotspot/test/runtime/lambda-features/TestInterfaceOrder.java
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8034275
|
||||||
|
* @summary [JDK 8u40] Test interface initialization order
|
||||||
|
* @run main TestInterfaceOrder
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class TestInterfaceOrder {
|
||||||
|
static List<Class<?>> cInitOrder = new ArrayList<>();
|
||||||
|
|
||||||
|
public static void main(java.lang.String[] args) {
|
||||||
|
//Trigger initialization
|
||||||
|
C c = new C();
|
||||||
|
|
||||||
|
List<Class<?>> expectedCInitOrder = Arrays.asList(I.class, J.class, A.class, K.class, B.class, L.class, C.class);
|
||||||
|
if (!cInitOrder.equals(expectedCInitOrder)) {
|
||||||
|
throw new RuntimeException(String.format("Class initialization order %s not equal to expected order %s", cInitOrder, expectedCInitOrder));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
boolean v = TestInterfaceOrder.out(I.class);
|
||||||
|
default void i() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface J extends I {
|
||||||
|
boolean v = TestInterfaceOrder.out(J.class);
|
||||||
|
default void j() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class A implements J {
|
||||||
|
static boolean v = TestInterfaceOrder.out(A.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface K extends I {
|
||||||
|
boolean v = TestInterfaceOrder.out(K.class);
|
||||||
|
default void k() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class B extends A implements K {
|
||||||
|
static boolean v = TestInterfaceOrder.out(B.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface L {
|
||||||
|
boolean v = TestInterfaceOrder.out(L.class);
|
||||||
|
default void l() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class C extends B implements L {
|
||||||
|
static boolean v = TestInterfaceOrder.out(C.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static boolean out(Class c) {
|
||||||
|
System.out.println("#: initializing " + c.getName());
|
||||||
|
cInitOrder.add(c);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user