# HG changeset patch # User rfield # Date 1381472816 25200 # Node ID 57913337d634e1f6f5f2aa4a90222f36830f5dfb # Parent ced599ab149514b00c8f965b51c6be3b44930f96 8012557: Implement lambda methods on interfaces as private 8016320: Method reference in subinterface of type I.super::foo produces exception at runtime Summary: Now that the VM supports interface instance private methods, lambda methods and lambda bridges are always private. Access is now through invokespecial. Reviewed-by: vromero, jlahoda diff -r ced599ab1495 -r 57913337d634 langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java --- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Thu Oct 10 20:57:27 2013 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Thu Oct 10 23:26:56 2013 -0700 @@ -128,10 +128,9 @@ private KlassInfo(Symbol kSym) { appendedMethodList = new ListBuffer<>(); deserializeCases = new HashMap>(); - long flags = PRIVATE | STATIC | SYNTHETIC; MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType, List.nil(), syms.methodClass); - deserMethodSym = makeSyntheticMethod(flags, names.deserializeLambda, type, kSym); + deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, kSym); deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"), syms.serializedLambdaType, deserMethodSym); } @@ -671,8 +670,8 @@ /** * Create new synthetic method with given flags, name, type, owner */ - private MethodSymbol makeSyntheticMethod(long flags, Name name, Type type, Symbol owner) { - return new MethodSymbol(flags | SYNTHETIC, name, type, owner); + private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) { + return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner); } /** @@ -1067,12 +1066,12 @@ } else { if (refSym.isStatic()) { return ClassFile.REF_invokeStatic; + } else if ((refSym.flags() & PRIVATE) != 0) { + return ClassFile.REF_invokeSpecial; } else if (refSym.enclClass().isInterface()) { return ClassFile.REF_invokeInterface; } else { - return (refSym.flags() & PRIVATE) != 0 ? - ClassFile.REF_invokeSpecial : - ClassFile.REF_invokeVirtual; + return ClassFile.REF_invokeVirtual; } } } @@ -1480,7 +1479,7 @@ //static clinits are generated in Gen - so we need to fake them Symbol clinit = clinits.get(csym); if (clinit == null) { - clinit = makeSyntheticMethod(STATIC, + clinit = makePrivateSyntheticMethod(STATIC, names.clinit, new MethodType(List.nil(), syms.voidType, List.nil(), syms.methodClass), csym); @@ -1729,7 +1728,7 @@ self = ((JCVariableDecl)frame.tree).sym; } Name name = isSerializable() ? serializedLambdaName(owner) : lambdaName(); - this.translatedSym = makeSyntheticMethod(0, name, null, owner.enclClass()); + this.translatedSym = makePrivateSyntheticMethod(0, name, null, owner.enclClass()); if (dumpLambdaToMethodStats) { log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym); } @@ -1845,9 +1844,9 @@ // If instance access isn't needed, make it static. // Interface instance methods must be default methods. - // Awaiting VM channges, default methods are public + // Lambda methods are private synthetic. translatedSym.flags_field = SYNTHETIC | - ((inInterface && thisReferenced)? PUBLIC : PRIVATE) | + PRIVATE | (thisReferenced? (inInterface? DEFAULT : 0) : STATIC); //compute synthetic params @@ -1890,7 +1889,7 @@ super(tree); this.isSuper = tree.hasKind(ReferenceKind.SUPER); this.bridgeSym = needsBridge() - ? makeSyntheticMethod(isSuper ? 0 : STATIC, + ? makePrivateSyntheticMethod(isSuper ? 0 : STATIC, lambdaName().append(names.fromString("$bridge")), null, owner.enclClass()) : null; diff -r ced599ab1495 -r 57913337d634 langtools/src/share/classes/com/sun/tools/javac/jvm/Pool.java --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Pool.java Thu Oct 10 20:57:27 2013 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Pool.java Thu Oct 10 23:26:56 2013 -0700 @@ -296,7 +296,10 @@ interfaceOwner = true; staticOk = true; case ClassFile.REF_invokeVirtual: + expectedKind = Kinds.MTH; + break; case ClassFile.REF_invokeSpecial: + interfaceOwner = true; expectedKind = Kinds.MTH; break; } diff -r ced599ab1495 -r 57913337d634 langtools/test/tools/javac/lambda/8012557/A.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/8012557/A.java Thu Oct 10 23:26:56 2013 -0700 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013, 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. + */ + +interface A { + default String u() { return "A"; } + default String name() { + SAM s = ()->u()+"A"; + return s.m(); + } +} diff -r ced599ab1495 -r 57913337d634 langtools/test/tools/javac/lambda/8012557/B.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/8012557/B.java Thu Oct 10 23:26:56 2013 -0700 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013, 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. + */ + +interface B { + default String u() { return "B"; } + default String name() { + SAM s = ()->u()+"B"; + return s.m(); + } +} diff -r ced599ab1495 -r 57913337d634 langtools/test/tools/javac/lambda/8012557/C.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/8012557/C.java Thu Oct 10 23:26:56 2013 -0700 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013, 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. + */ + +interface C { + default String u() { return "C"; } + default String name() { + SAM s = ()->u()+"C"; + return s.m(); + } +} diff -r ced599ab1495 -r 57913337d634 langtools/test/tools/javac/lambda/8012557/PrivateLambdas.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/8012557/PrivateLambdas.java Thu Oct 10 23:26:56 2013 -0700 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013, 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 8012557 + * @summary Check that 8012557 is fixed, that interface lambda + * methods are private + * @author Robert Field + * @compile SAM.java + * @compile A.java + * @compile B.java + * @compile C.java + * @run main PrivateLambdas + * + * Unless the lambda methods are private, this will fail with: + * AbstractMethodError: + * Conflicting default methods: A.lambda$0 B.lambda$0 C.lambda$0 + */ + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +interface X extends A, B, C { + default String u() { return " "; } + default String name() { + return A.super.name() + B.super.name() + C.super.name(); + } +} + +public class PrivateLambdas implements X { + public static void main(String[] args) throws Exception { + + // Check that all the lambda methods are private instance synthetic + for (Class k : new Class[] { A.class, B.class, C.class }) { + Method[] methods = k.getDeclaredMethods(); + int lambdaCount = 0; + for(Method m : methods) { + if (m.getName().startsWith("lambda$")) { + ++lambdaCount; + int mod = m.getModifiers(); + if ((mod & Modifier.PRIVATE) == 0) { + throw new Exception("Expected " + m + " to be private"); + } + if (!m.isSynthetic()) { + throw new Exception("Expected " + m + " to be synthetic"); + } + if ((mod & Modifier.STATIC) != 0) { + throw new Exception("Expected " + m + " to be instance method"); + } + } + } + if (lambdaCount == 0) { + throw new Exception("Expected at least one lambda method"); + } + } + + /* + * Unless the lambda methods are private, this will fail with: + * AbstractMethodError: + * Conflicting default methods: A.lambda$0 B.lambda$0 C.lambda$0 + */ + X x = new PrivateLambdas(); + if (!x.name().equals(" A B C")) { + throw new Exception("Expected ' A B C' got: " + x.name()); + } + } +} diff -r ced599ab1495 -r 57913337d634 langtools/test/tools/javac/lambda/8012557/SAM.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/8012557/SAM.java Thu Oct 10 23:26:56 2013 -0700 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013, 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. + */ + +interface SAM { + String m(); +} diff -r ced599ab1495 -r 57913337d634 langtools/test/tools/javac/lambda/8016320/IllegalBridgeModifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/8016320/IllegalBridgeModifier.java Thu Oct 10 23:26:56 2013 -0700 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013, 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 8016320 + * @summary Check that 8016320 is fixed, + * that bridges have valid modifier bits + * @author Robert Field + * @run main IllegalBridgeModifier + */ + +interface SAM { + int m(); +} + +interface SuperI { + public default int foo() { return 1234; } +} + +interface I extends SuperI { +} + +interface T extends I { + public default SAM boo() { return I.super::foo; } +} + +public class IllegalBridgeModifier { + public static void main(String argv[])throws Exception { + T t = new T(){}; + if (t.boo().m() != 1234) { + throw new Exception("Failed test"); + } + } +}