提交 cdb6c320 编写于 作者: C chegar

Merge

......@@ -33,10 +33,15 @@ import java.util.Map;
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 @@ public class Types {
final boolean allowDefaultMethods;
final ClassReader reader;
final Check chk;
final Enter enter;
JCDiagnostic.Factory diags;
List<Warner> warnStack = List.nil();
final Name capturedName;
......@@ -109,6 +115,7 @@ public class Types {
allowDefaultMethods = source.allowDefaultMethods();
reader = ClassReader.instance(context);
chk = Check.instance(context);
enter = Enter.instance(context);
capturedName = names.fromString("<captured wildcard>");
messages = JavacMessages.instance(context);
diags = JCDiagnostic.Factory.instance(context);
......@@ -603,6 +610,84 @@ public class Types {
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<AttrContext> env, Name name, List<Type> 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.<Type>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<Symbol> functionalInterfaceBridges(TypeSymbol origin) {
Assert.check(isFunctionalInterface(origin));
Symbol descSym = findDescriptorSymbol(origin);
CompoundScope members = membersClosure(origin.type, false);
ListBuffer<Symbol> 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<Symbol> bridgeFilter = new Filter<Symbol>() {
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;
}
// </editor-fold>
/**
......@@ -2643,6 +2728,7 @@ public class Types {
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));
}
......
......@@ -2314,13 +2314,12 @@ public class Attr extends JCTree.Visitor {
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 @@ public class Attr extends JCTree.Visitor {
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<Type> argtypes = desc.getParameterTypes();
Pair<Symbol, Resolve.ReferenceLookupHelper> refResult =
......@@ -2870,31 +2868,37 @@ public class Attr extends JCTree.Visitor {
* 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<AttrContext> 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<TypeSymbol> targets = ListBuffer.lb();
ListBuffer<Type> 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 @@ public class Attr extends JCTree.Visitor {
@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 @@ public class Attr extends JCTree.Visitor {
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();
}
......
......@@ -2267,24 +2267,6 @@ public class Check {
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.<Type>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.
......
......@@ -100,6 +100,9 @@ public class LambdaToMethod extends TreeTranslator {
/** 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 @@ public class LambdaToMethod extends TreeTranslator {
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 @@ public class LambdaToMethod extends TreeTranslator {
//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 @@ public class LambdaToMethod extends TreeTranslator {
/**
* Generate an indy method call to the meta factory
*/
private JCExpression makeMetaFactoryIndyCall(JCFunctionalExpression tree, boolean needsAltMetafactory,
boolean isSerializable, int refKind, Symbol refSym, List<JCExpression> indy_args) {
private JCExpression makeMetaFactoryIndyCall(TranslationContext<?> context,
int refKind, Symbol refSym, List<JCExpression> 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<Object> staticArgs = List.<Object>of(
new Pool.MethodHandle(ClassFile.REF_invokeInterface,
......@@ -934,25 +938,40 @@ public class LambdaToMethod extends TreeTranslator {
List.<Type>nil(),
syms.methodClass);
Name metafactoryName = needsAltMetafactory ?
Name metafactoryName = context.needsAltMetafactory() ?
names.altMetaFactory : names.metaFactory;
if (needsAltMetafactory) {
if (context.needsAltMetafactory()) {
ListBuffer<Object> 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 @@ public class LambdaToMethod extends TreeTranslator {
// 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 @@ public class LambdaToMethod extends TreeTranslator {
/** the enclosing translation context (set for nested lambdas/mref) */
TranslationContext<?> prev;
/** list of methods to be bridged by the meta-factory */
List<Symbol> 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 @@ public class LambdaToMethod extends TreeTranslator {
}
Type generatedLambdaSig() {
return types.erasure(tree.descriptorType);
return types.erasure(tree.getDescriptorType(types));
}
}
......@@ -1909,7 +1934,7 @@ public class LambdaToMethod extends TreeTranslator {
}
Type bridgedRefSig() {
return types.erasure(types.findDescriptorSymbol(tree.targets.head).type);
return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type);
}
}
}
......
......@@ -68,6 +68,7 @@ public class TransTypes extends TreeTranslator {
private TreeMaker make;
private Enter enter;
private boolean allowEnums;
private boolean allowInterfaceBridges;
private Types types;
private final Resolve resolve;
......@@ -91,6 +92,7 @@ public class TransTypes extends TreeTranslator {
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 @@ public class TransTypes extends TreeTranslator {
// 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 @@ public class TransTypes extends TreeTranslator {
}
}
// where
Filter<Symbol> overrideBridgeFilter = new Filter<Symbol>() {
private Filter<Symbol> overrideBridgeFilter = new Filter<Symbol>() {
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 @@ public class TransTypes extends TreeTranslator {
ListBuffer<JCTree> bridges = new ListBuffer<JCTree>();
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);
......
......@@ -641,10 +641,12 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
polyKind = PolyKind.POLY;
}
/** target descriptor inferred for this functional expression. */
public Type descriptorType;
/** list of target types inferred for this functional expression. */
public List<TypeSymbol> targets;
public List<Type> targets;
public Type getDescriptorType(Types types) {
return types.findDescriptorType(targets.head);
}
}
/**
......
......@@ -110,6 +110,8 @@ public class ElementScanner6<R, P> extends AbstractElementVisitor6<R, P> {
/**
* Constructor for concrete subclasses; uses the argument for the
* default value.
*
* @param defaultValue the default value
*/
protected ElementScanner6(R defaultValue){
DEFAULT_VALUE = defaultValue;
......
/*
* 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 @@ public class ElementScanner7<R, P> extends ElementScanner6<R, P> {
/**
* Constructor for concrete subclasses; uses the argument for the
* default value.
*
* @param defaultValue the default value
*/
protected ElementScanner7(R defaultValue){
super(defaultValue);
......
/*
* 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 @@ public class ElementScanner8<R, P> extends ElementScanner7<R, P> {
/**
* Constructor for concrete subclasses; uses the argument for the
* default value.
*
* @param defaultValue the default value
*/
protected ElementScanner8(R defaultValue){
super(defaultValue);
......
......@@ -118,6 +118,10 @@ public class SimpleTypeVisitor6<R, P> extends AbstractTypeVisitor6<R, P> {
* 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;
......
......@@ -105,7 +105,7 @@ public class LambdaTest6<T> {
Class returnType = m.getReturnType();
assertTrue(types.remove(returnType.getName()));
}
assertTrue(types.isEmpty());
assertTrue(types.size() == 1); //there's a bridge
}
......
......@@ -112,6 +112,6 @@ public class BridgeMethod {
Class<?> returnType = m.getReturnType();
assertTrue(types.remove(returnType.getName()));
}
assertTrue(types.isEmpty());
assertTrue(types.size() == 1); //there's a bridge
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册