提交 5724a929 编写于 作者: A acorn

8043275: 8u40 backport: Fix interface initialization for default methods.

Reviewed-by: dcubed, coleenp
上级 9839aaf9
......@@ -2529,7 +2529,7 @@ methodHandle ClassFileParser::parse_method(bool is_interface,
Array<Method*>* ClassFileParser::parse_methods(bool is_interface,
AccessFlags* promoted_flags,
bool* has_final_method,
bool* has_default_methods,
bool* declares_default_methods,
TRAPS) {
ClassFileStream* cfs = stream();
cfs->guarantee_more(2, CHECK_NULL); // length
......@@ -2548,11 +2548,11 @@ Array<Method*>* ClassFileParser::parse_methods(bool is_interface,
if (method->is_final()) {
*has_final_method = true;
}
if (is_interface && !(*has_default_methods)
&& !method->is_abstract() && !method->is_static()
&& !method->is_private()) {
// default method
*has_default_methods = true;
// declares_default_methods: declares concrete instance methods, any access flags
// used for interface initialization, and default method inheritance analysis
if (is_interface && !(*declares_default_methods)
&& !method->is_abstract() && !method->is_static()) {
*declares_default_methods = true;
}
_methods->at_put(index, method());
}
......@@ -3691,6 +3691,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
JvmtiCachedClassFileData *cached_class_file = NULL;
Handle class_loader(THREAD, loader_data->class_loader());
bool has_default_methods = false;
bool declares_default_methods = false;
ResourceMark rm(THREAD);
ClassFileStream* cfs = stream();
......@@ -3928,8 +3929,11 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
Array<Method*>* methods = parse_methods(access_flags.is_interface(),
&promoted_flags,
&has_final_method,
&has_default_methods,
&declares_default_methods,
CHECK_(nullHandle));
if (declares_default_methods) {
has_default_methods = true;
}
// Additional attributes
ClassAnnotationCollector parsed_annotations;
......@@ -4072,6 +4076,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
this_klass->set_minor_version(minor_version);
this_klass->set_major_version(major_version);
this_klass->set_has_default_methods(has_default_methods);
this_klass->set_declares_default_methods(declares_default_methods);
if (!host_klass.is_null()) {
assert (this_klass->is_anonymous(), "should be the same");
......
......@@ -247,7 +247,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
Array<Method*>* parse_methods(bool is_interface,
AccessFlags* promoted_flags,
bool* has_final_method,
bool* has_default_method,
bool* declares_default_methods,
TRAPS);
intArray* sort_methods(Array<Method*>* methods);
......
......@@ -780,6 +780,41 @@ void InstanceKlass::link_methods(TRAPS) {
}
}
// Eagerly initialize superinterfaces that declare default methods (concrete instance: any access)
void InstanceKlass::initialize_super_interfaces(instanceKlassHandle this_oop, TRAPS) {
if (this_oop->has_default_methods()) {
for (int i = 0; i < this_oop->local_interfaces()->length(); ++i) {
Klass* iface = this_oop->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_oop->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_oop, TRAPS) {
// Make sure klass is linked (verified) before initialization
......@@ -859,33 +894,11 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, 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_oop->has_default_methods()) {
// Step 7.5: initialize any interfaces which have default methods
for (int i = 0; i < this_oop->local_interfaces()->length(); ++i) {
Klass* iface = this_oop->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_oop->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_oop()), -1, wait);
THROW_OOP(e());
}
}
}
this_oop->initialize_super_interfaces(this_oop, CHECK);
}
// Step 8
......
......@@ -229,12 +229,13 @@ class InstanceKlass: public Klass {
bool _has_unloaded_dependent;
enum {
_misc_rewritten = 1 << 0, // methods rewritten.
_misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops
_misc_should_verify_class = 1 << 2, // allow caching of preverification
_misc_is_anonymous = 1 << 3, // has embedded _host_klass field
_misc_is_contended = 1 << 4, // marked with contended annotation
_misc_has_default_methods = 1 << 5 // class/superclass/implemented interfaces has default methods
_misc_rewritten = 1 << 0, // methods rewritten.
_misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops
_misc_should_verify_class = 1 << 2, // allow caching of preverification
_misc_is_anonymous = 1 << 3, // has embedded _host_klass field
_misc_is_contended = 1 << 4, // marked with contended annotation
_misc_has_default_methods = 1 << 5, // class/superclass/implemented interfaces has default methods
_misc_declares_default_methods = 1 << 6 // directly declares default methods (any access)
};
u2 _misc_flags;
u2 _minor_version; // minor version number of class file
......@@ -680,6 +681,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
inline u2 next_method_idnum();
void set_initial_method_idnum(u2 value) { _idnum_allocated_count = value; }
......@@ -1046,6 +1058,7 @@ private:
static bool link_class_impl (instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS);
static bool verify_code (instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS);
static void initialize_impl (instanceKlassHandle this_oop, TRAPS);
static void initialize_super_interfaces (instanceKlassHandle this_oop, TRAPS);
static void eager_initialize_impl (instanceKlassHandle this_oop);
static void set_initialization_state_and_notify_impl (instanceKlassHandle this_oop, ClassState state, TRAPS);
static void call_class_initializer_impl (instanceKlassHandle this_oop, TRAPS);
......
......@@ -33,11 +33,12 @@
import java.util.function.*;
import java.util.*;
public class InvokespecialInterface {
interface I {
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 bar() { I i = this; i.imethod(); } // invokeinterface same
public void doSomeInvokedynamic() {
......@@ -48,7 +49,6 @@ class C implements I {
}
}
public class InvokespecialInterface {
public static void main(java.lang.String[] unused) {
// need to create C and call I::foo()
C c = new C();
......
/*
* 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;
}
}
/*
* 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;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册