# HG changeset patch # User chegar # Date 1371544606 -3600 # Node ID db6bf740a578ae2e162260c7c233291e7f87d2a2 # Parent 31e1151ef3cc5eb09512e8a2400bc447534ab668# Parent 455be95bd1b5c418b833fe665737c33f29b984b6 Merge diff -r 31e1151ef3cc -r db6bf740a578 src/share/classes/com/sun/tools/javac/code/Types.java --- a/src/share/classes/com/sun/tools/javac/code/Types.java Mon Jun 17 11:27:46 2013 +0100 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java Tue Jun 18 09:36:46 2013 +0100 @@ -33,10 +33,15 @@ import java.util.Set; import java.util.WeakHashMap; +import javax.tools.JavaFileObject; + import com.sun.tools.javac.code.Attribute.RetentionPolicy; import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Type.UndetVar.InferenceBound; +import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.Check; +import com.sun.tools.javac.comp.Enter; +import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.jvm.ClassReader; import com.sun.tools.javac.util.*; import static com.sun.tools.javac.code.BoundKind.*; @@ -83,6 +88,7 @@ final boolean allowDefaultMethods; final ClassReader reader; final Check chk; + final Enter enter; JCDiagnostic.Factory diags; List warnStack = List.nil(); final Name capturedName; @@ -109,6 +115,7 @@ allowDefaultMethods = source.allowDefaultMethods(); reader = ClassReader.instance(context); chk = Check.instance(context); + enter = Enter.instance(context); capturedName = names.fromString(""); messages = JavacMessages.instance(context); diags = JCDiagnostic.Factory.instance(context); @@ -603,6 +610,84 @@ return site; } } + + /** + * Create a symbol for a class that implements a given functional interface + * and overrides its functional descriptor. This routine is used for two + * main purposes: (i) checking well-formedness of a functional interface; + * (ii) perform functional interface bridge calculation. + */ + public ClassSymbol makeFunctionalInterfaceClass(Env env, Name name, List targets, long cflags) { + Assert.check(targets.nonEmpty() && isFunctionalInterface(targets.head)); + Symbol descSym = findDescriptorSymbol(targets.head.tsym); + Type descType = findDescriptorType(targets.head); + ClassSymbol csym = new ClassSymbol(cflags, name, env.enclClass.sym.outermostClass()); + csym.completer = null; + csym.members_field = new Scope(csym); + MethodSymbol instDescSym = new MethodSymbol(descSym.flags(), descSym.name, descType, csym); + csym.members_field.enter(instDescSym); + Type.ClassType ctype = new Type.ClassType(Type.noType, List.nil(), csym); + ctype.supertype_field = syms.objectType; + ctype.interfaces_field = targets; + csym.type = ctype; + csym.sourcefile = ((ClassSymbol)csym.owner).sourcefile; + return csym; + } + + /** + * Find the minimal set of methods that are overridden by the functional + * descriptor in 'origin'. All returned methods are assumed to have different + * erased signatures. + */ + public List functionalInterfaceBridges(TypeSymbol origin) { + Assert.check(isFunctionalInterface(origin)); + Symbol descSym = findDescriptorSymbol(origin); + CompoundScope members = membersClosure(origin.type, false); + ListBuffer overridden = ListBuffer.lb(); + outer: for (Symbol m2 : members.getElementsByName(descSym.name, bridgeFilter)) { + if (m2 == descSym) continue; + else if (descSym.overrides(m2, origin, Types.this, false)) { + for (Symbol m3 : overridden) { + if (isSameType(m3.erasure(Types.this), m2.erasure(Types.this)) || + (m3.overrides(m2, origin, Types.this, false) && + (pendingBridges((ClassSymbol)origin, m3.enclClass()) || + (((MethodSymbol)m2).binaryImplementation((ClassSymbol)m3.owner, Types.this) != null)))) { + continue outer; + } + } + overridden.add(m2); + } + } + return overridden.toList(); + } + //where + private Filter bridgeFilter = new Filter() { + public boolean accepts(Symbol t) { + return t.kind == Kinds.MTH && + t.name != names.init && + t.name != names.clinit && + (t.flags() & SYNTHETIC) == 0; + } + }; + private boolean pendingBridges(ClassSymbol origin, TypeSymbol s) { + //a symbol will be completed from a classfile if (a) symbol has + //an associated file object with CLASS kind and (b) the symbol has + //not been entered + if (origin.classfile != null && + origin.classfile.getKind() == JavaFileObject.Kind.CLASS && + enter.getEnv(origin) == null) { + return false; + } + if (origin == s) { + return true; + } + for (Type t : interfaces(origin.type)) { + if (pendingBridges((ClassSymbol)t.tsym, s)) { + return true; + } + } + return false; + } // /** @@ -2643,6 +2728,7 @@ public boolean accepts(Symbol s) { return s.kind == Kinds.MTH && s.name == msym.name && + (s.flags() & SYNTHETIC) == 0 && s.isInheritedIn(site.tsym, Types.this) && overrideEquivalent(memberType(site, s), memberType(site, msym)); } diff -r 31e1151ef3cc -r db6bf740a578 src/share/classes/com/sun/tools/javac/comp/Attr.java --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Mon Jun 17 11:27:46 2013 +0100 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Tue Jun 18 09:36:46 2013 +0100 @@ -2314,13 +2314,12 @@ if (pt() != Type.recoveryType) { target = targetChecker.visit(target, that); lambdaType = types.findDescriptorType(target); - chk.checkFunctionalInterface(that, target); } else { target = Type.recoveryType; lambdaType = fallbackDescriptorType(that); } - setFunctionalInfo(that, pt(), lambdaType, target, resultInfo.checkContext.inferenceContext()); + setFunctionalInfo(localEnv, that, pt(), lambdaType, target, resultInfo.checkContext); if (lambdaType.hasTag(FORALL)) { //lambda expression target desc cannot be a generic method @@ -2662,13 +2661,12 @@ if (pt() != Type.recoveryType) { target = targetChecker.visit(pt(), that); desc = types.findDescriptorType(target); - chk.checkFunctionalInterface(that, target); } else { target = Type.recoveryType; desc = fallbackDescriptorType(that); } - setFunctionalInfo(that, pt(), desc, target, resultInfo.checkContext.inferenceContext()); + setFunctionalInfo(localEnv, that, pt(), desc, target, resultInfo.checkContext); List argtypes = desc.getParameterTypes(); Pair refResult = @@ -2870,31 +2868,37 @@ * might contain inference variables, we might need to register an hook in the * current inference context. */ - private void setFunctionalInfo(final JCFunctionalExpression fExpr, final Type pt, - final Type descriptorType, final Type primaryTarget, InferenceContext inferenceContext) { - if (inferenceContext.free(descriptorType)) { - inferenceContext.addFreeTypeListener(List.of(pt, descriptorType), new FreeTypeListener() { + private void setFunctionalInfo(final Env env, final JCFunctionalExpression fExpr, + final Type pt, final Type descriptorType, final Type primaryTarget, final CheckContext checkContext) { + if (checkContext.inferenceContext().free(descriptorType)) { + checkContext.inferenceContext().addFreeTypeListener(List.of(pt, descriptorType), new FreeTypeListener() { public void typesInferred(InferenceContext inferenceContext) { - setFunctionalInfo(fExpr, pt, inferenceContext.asInstType(descriptorType), - inferenceContext.asInstType(primaryTarget), inferenceContext); + setFunctionalInfo(env, fExpr, pt, inferenceContext.asInstType(descriptorType), + inferenceContext.asInstType(primaryTarget), checkContext); } }); } else { - ListBuffer targets = ListBuffer.lb(); + ListBuffer targets = ListBuffer.lb(); if (pt.hasTag(CLASS)) { if (pt.isCompound()) { - targets.append(primaryTarget.tsym); //this goes first + targets.append(types.removeWildcards(primaryTarget)); //this goes first for (Type t : ((IntersectionClassType)pt()).interfaces_field) { if (t != primaryTarget) { - targets.append(t.tsym); + targets.append(types.removeWildcards(t)); } } } else { - targets.append(pt.tsym); + targets.append(types.removeWildcards(primaryTarget)); } } fExpr.targets = targets.toList(); - fExpr.descriptorType = descriptorType; + if (checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.CHECK && + pt != Type.recoveryType) { + //check that functional interface class is well-formed + ClassSymbol csym = types.makeFunctionalInterfaceClass(env, + names.empty, List.of(fExpr.targets.head), ABSTRACT); + chk.checkImplementations(env.tree, csym, csym); + } } } @@ -4550,9 +4554,6 @@ @Override public void visitLambda(JCLambda that) { super.visitLambda(that); - if (that.descriptorType == null) { - that.descriptorType = syms.unknownType; - } if (that.targets == null) { that.targets = List.nil(); } @@ -4564,9 +4565,6 @@ if (that.sym == null) { that.sym = new MethodSymbol(0, names.empty, syms.unknownType, syms.noSymbol); } - if (that.descriptorType == null) { - that.descriptorType = syms.unknownType; - } if (that.targets == null) { that.targets = List.nil(); } diff -r 31e1151ef3cc -r db6bf740a578 src/share/classes/com/sun/tools/javac/comp/Check.java --- a/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Jun 17 11:27:46 2013 +0100 +++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Tue Jun 18 09:36:46 2013 +0100 @@ -2267,24 +2267,6 @@ c.flags_field |= ACYCLIC; } - /** - * Check that functional interface methods would make sense when seen - * from the perspective of the implementing class - */ - void checkFunctionalInterface(JCTree tree, Type funcInterface) { - ClassType c = new ClassType(Type.noType, List.nil(), null); - ClassSymbol csym = new ClassSymbol(0, names.empty, c, syms.noSymbol); - c.interfaces_field = List.of(types.removeWildcards(funcInterface)); - c.supertype_field = syms.objectType; - c.tsym = csym; - csym.members_field = new Scope(csym); - Symbol descSym = types.findDescriptorSymbol(funcInterface.tsym); - Type descType = types.findDescriptorType(funcInterface); - csym.members_field.enter(new MethodSymbol(PUBLIC, descSym.name, descType, csym)); - csym.completer = null; - checkImplementations(tree, csym, csym); - } - /** Check that all methods which implement some * method conform to the method they implement. * @param tree The class definition whose members are checked. diff -r 31e1151ef3cc -r db6bf740a578 src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java --- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Mon Jun 17 11:27:46 2013 +0100 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Tue Jun 18 09:36:46 2013 +0100 @@ -100,6 +100,9 @@ /** Flag for alternate metafactories indicating the lambda object has multiple targets */ public static final int FLAG_MARKERS = 1 << 1; + /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */ + public static final int FLAG_BRIDGES = 1 << 2; + private class KlassInfo { /** @@ -321,7 +324,7 @@ int refKind = referenceKind(sym); //convert to an invokedynamic call - result = makeMetaFactoryIndyCall(tree, context.needsAltMetafactory(), context.isSerializable(), refKind, sym, indy_args); + result = makeMetaFactoryIndyCall(context, refKind, sym, indy_args); } private JCIdent makeThis(Type type, Symbol owner) { @@ -382,7 +385,7 @@ //build a sam instance using an indy call to the meta-factory - result = makeMetaFactoryIndyCall(tree, localContext.needsAltMetafactory(), localContext.isSerializable(), localContext.referenceKind(), refSym, indy_args); + result = makeMetaFactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args); } /** @@ -908,10 +911,11 @@ /** * Generate an indy method call to the meta factory */ - private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, boolean needsAltMetafactory, - boolean isSerializable, int refKind, Symbol refSym, List indy_args) { + private JCExpression makeMetaFactoryIndyCall(TranslationContext context, + int refKind, Symbol refSym, List indy_args) { + JCFunctionalExpression tree = context.tree; //determine the static bsm args - Type mtype = types.erasure(tree.descriptorType); + Type mtype = types.erasure(tree.getDescriptorType(types)); MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym); List staticArgs = List.of( new Pool.MethodHandle(ClassFile.REF_invokeInterface, @@ -934,25 +938,40 @@ List.nil(), syms.methodClass); - Name metafactoryName = needsAltMetafactory ? + Name metafactoryName = context.needsAltMetafactory() ? names.altMetaFactory : names.metaFactory; - if (needsAltMetafactory) { + if (context.needsAltMetafactory()) { ListBuffer markers = ListBuffer.lb(); - for (Symbol t : tree.targets.tail) { - if (t != syms.serializableType.tsym) { - markers.append(t); + for (Type t : tree.targets.tail) { + if (t.tsym != syms.serializableType.tsym) { + markers.append(t.tsym); } } - int flags = isSerializable? FLAG_SERIALIZABLE : 0; + int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0; boolean hasMarkers = markers.nonEmpty(); - flags |= hasMarkers ? FLAG_MARKERS : 0; + boolean hasBridges = context.bridges.nonEmpty(); + if (hasMarkers) { + flags |= FLAG_MARKERS; + } + if (hasBridges) { + flags |= FLAG_BRIDGES; + } staticArgs = staticArgs.append(flags); if (hasMarkers) { staticArgs = staticArgs.append(markers.length()); staticArgs = staticArgs.appendList(markers.toList()); } - if (isSerializable) { + if (hasBridges) { + staticArgs = staticArgs.append(context.bridges.length() - 1); + for (Symbol s : context.bridges) { + Type s_erasure = s.erasure(types); + if (!types.isSameType(s_erasure, samSym.erasure(types))) { + staticArgs = staticArgs.append(s.erasure(types)); + } + } + } + if (context.isSerializable()) { addDeserializationCase(refKind, refSym, tree.type, samSym, tree, staticArgs, indyType); } @@ -1299,7 +1318,6 @@ // Make lambda holding the new-class call JCLambda slam = make.Lambda(params, nc); - slam.descriptorType = tree.descriptorType; slam.targets = tree.targets; slam.type = tree.type; slam.pos = tree.pos; @@ -1634,23 +1652,30 @@ /** the enclosing translation context (set for nested lambdas/mref) */ TranslationContext prev; + /** list of methods to be bridged by the meta-factory */ + List bridges; + TranslationContext(T tree) { this.tree = tree; this.owner = owner(); this.depth = frameStack.size() - 1; this.prev = context(); + ClassSymbol csym = + types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE); + this.bridges = types.functionalInterfaceBridges(csym); } /** does this functional expression need to be created using alternate metafactory? */ boolean needsAltMetafactory() { - return (tree.targets.length() > 1 || - isSerializable()); + return tree.targets.length() > 1 || + isSerializable() || + bridges.length() > 1; } /** does this functional expression require serialization support? */ boolean isSerializable() { - for (Symbol target : tree.targets) { - if (types.asSuper(target.type, syms.serializableType.tsym) != null) { + for (Type target : tree.targets) { + if (types.asSuper(target, syms.serializableType.tsym) != null) { return true; } } @@ -1833,7 +1858,7 @@ } Type generatedLambdaSig() { - return types.erasure(tree.descriptorType); + return types.erasure(tree.getDescriptorType(types)); } } @@ -1909,7 +1934,7 @@ } Type bridgedRefSig() { - return types.erasure(types.findDescriptorSymbol(tree.targets.head).type); + return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type); } } } diff -r 31e1151ef3cc -r db6bf740a578 src/share/classes/com/sun/tools/javac/comp/TransTypes.java --- a/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Mon Jun 17 11:27:46 2013 +0100 +++ b/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Tue Jun 18 09:36:46 2013 +0100 @@ -68,6 +68,7 @@ private TreeMaker make; private Enter enter; private boolean allowEnums; + private boolean allowInterfaceBridges; private Types types; private final Resolve resolve; @@ -91,6 +92,7 @@ Source source = Source.instance(context); allowEnums = source.allowEnums(); addBridges = source.addBridges(); + allowInterfaceBridges = source.allowDefaultMethods(); types = Types.instance(context); make = TreeMaker.instance(context); resolve = Resolve.instance(context); @@ -252,7 +254,8 @@ // Create a bridge method symbol and a bridge definition without a body. Type bridgeType = meth.erasure(types); - long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE; + long flags = impl.flags() & AccessFlags | SYNTHETIC | BRIDGE | + (origin.isInterface() ? DEFAULT : 0); if (hypothetical) flags |= HYPOTHETICAL; MethodSymbol bridge = new MethodSymbol(flags, meth.name, @@ -387,11 +390,12 @@ } } // where - Filter overrideBridgeFilter = new Filter() { + private Filter overrideBridgeFilter = new Filter() { public boolean accepts(Symbol s) { return (s.flags() & (SYNTHETIC | OVERRIDE_BRIDGE)) != SYNTHETIC; } }; + /** * @param method The symbol for which a bridge might have to be added * @param impl The implementation of method @@ -999,8 +1003,9 @@ ListBuffer bridges = new ListBuffer(); if (false) //see CR: 6996415 bridges.appendList(addOverrideBridgesIfNeeded(tree, c)); - if ((tree.sym.flags() & INTERFACE) == 0) - addBridges(tree.pos(), tree.sym, bridges); + if (allowInterfaceBridges || (tree.sym.flags() & INTERFACE) == 0) { + addBridges(tree.pos(), c, bridges); + } tree.defs = bridges.toList().prependList(tree.defs); } tree.type = erasure(tree.type); diff -r 31e1151ef3cc -r db6bf740a578 src/share/classes/com/sun/tools/javac/tree/JCTree.java --- a/src/share/classes/com/sun/tools/javac/tree/JCTree.java Mon Jun 17 11:27:46 2013 +0100 +++ b/src/share/classes/com/sun/tools/javac/tree/JCTree.java Tue Jun 18 09:36:46 2013 +0100 @@ -641,10 +641,12 @@ polyKind = PolyKind.POLY; } - /** target descriptor inferred for this functional expression. */ - public Type descriptorType; /** list of target types inferred for this functional expression. */ - public List targets; + public List targets; + + public Type getDescriptorType(Types types) { + return types.findDescriptorType(targets.head); + } } /** diff -r 31e1151ef3cc -r db6bf740a578 src/share/classes/javax/lang/model/util/ElementScanner6.java --- a/src/share/classes/javax/lang/model/util/ElementScanner6.java Mon Jun 17 11:27:46 2013 +0100 +++ b/src/share/classes/javax/lang/model/util/ElementScanner6.java Tue Jun 18 09:36:46 2013 +0100 @@ -110,6 +110,8 @@ /** * Constructor for concrete subclasses; uses the argument for the * default value. + * + * @param defaultValue the default value */ protected ElementScanner6(R defaultValue){ DEFAULT_VALUE = defaultValue; diff -r 31e1151ef3cc -r db6bf740a578 src/share/classes/javax/lang/model/util/ElementScanner7.java --- a/src/share/classes/javax/lang/model/util/ElementScanner7.java Mon Jun 17 11:27:46 2013 +0100 +++ b/src/share/classes/javax/lang/model/util/ElementScanner7.java Tue Jun 18 09:36:46 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -101,6 +101,8 @@ /** * Constructor for concrete subclasses; uses the argument for the * default value. + * + * @param defaultValue the default value */ protected ElementScanner7(R defaultValue){ super(defaultValue); diff -r 31e1151ef3cc -r db6bf740a578 src/share/classes/javax/lang/model/util/ElementScanner8.java --- a/src/share/classes/javax/lang/model/util/ElementScanner8.java Mon Jun 17 11:27:46 2013 +0100 +++ b/src/share/classes/javax/lang/model/util/ElementScanner8.java Tue Jun 18 09:36:46 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -101,6 +101,8 @@ /** * Constructor for concrete subclasses; uses the argument for the * default value. + * + * @param defaultValue the default value */ protected ElementScanner8(R defaultValue){ super(defaultValue); diff -r 31e1151ef3cc -r db6bf740a578 src/share/classes/javax/lang/model/util/SimpleTypeVisitor6.java --- a/src/share/classes/javax/lang/model/util/SimpleTypeVisitor6.java Mon Jun 17 11:27:46 2013 +0100 +++ b/src/share/classes/javax/lang/model/util/SimpleTypeVisitor6.java Tue Jun 18 09:36:46 2013 +0100 @@ -118,6 +118,10 @@ * The default action for visit methods. The implementation in * this class just returns {@link #DEFAULT_VALUE}; subclasses will * commonly override this method. + * + * @param e the type to process + * @param p a visitor-specified parameter + * @return {@code DEFAULT_VALUE} unless overridden */ protected R defaultAction(TypeMirror e, P p) { return DEFAULT_VALUE; diff -r 31e1151ef3cc -r db6bf740a578 test/tools/javac/lambda/lambdaExpression/LambdaTest6.java --- a/test/tools/javac/lambda/lambdaExpression/LambdaTest6.java Mon Jun 17 11:27:46 2013 +0100 +++ b/test/tools/javac/lambda/lambdaExpression/LambdaTest6.java Tue Jun 18 09:36:46 2013 +0100 @@ -105,7 +105,7 @@ Class returnType = m.getReturnType(); assertTrue(types.remove(returnType.getName())); } - assertTrue(types.isEmpty()); + assertTrue(types.size() == 1); //there's a bridge } diff -r 31e1151ef3cc -r db6bf740a578 test/tools/javac/lambda/methodReference/BridgeMethod.java --- a/test/tools/javac/lambda/methodReference/BridgeMethod.java Mon Jun 17 11:27:46 2013 +0100 +++ b/test/tools/javac/lambda/methodReference/BridgeMethod.java Tue Jun 18 09:36:46 2013 +0100 @@ -112,6 +112,6 @@ Class returnType = m.getReturnType(); assertTrue(types.remove(returnType.getName())); } - assertTrue(types.isEmpty()); + assertTrue(types.size() == 1); //there's a bridge } }