rfield@1380: /* ksrini@2251: * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. rfield@1380: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. rfield@1380: * rfield@1380: * This code is free software; you can redistribute it and/or modify it rfield@1380: * under the terms of the GNU General Public License version 2 only, as rfield@1380: * published by the Free Software Foundation. Oracle designates this rfield@1380: * particular file as subject to the "Classpath" exception as provided rfield@1380: * by Oracle in the LICENSE file that accompanied this code. rfield@1380: * rfield@1380: * This code is distributed in the hope that it will be useful, but WITHOUT rfield@1380: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or rfield@1380: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License rfield@1380: * version 2 for more details (a copy is included in the LICENSE file that rfield@1380: * accompanied this code). rfield@1380: * rfield@1380: * You should have received a copy of the GNU General Public License version rfield@1380: * 2 along with this work; if not, write to the Free Software Foundation, rfield@1380: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. rfield@1380: * rfield@1380: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA rfield@1380: * or visit www.oracle.com if you need additional information or have any rfield@1380: * questions. rfield@1380: */ rfield@1380: package com.sun.tools.javac.comp; rfield@1380: rfield@1380: import com.sun.tools.javac.tree.*; rfield@1380: import com.sun.tools.javac.tree.JCTree.*; rfield@1380: import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; rfield@1380: import com.sun.tools.javac.tree.TreeMaker; rfield@1380: import com.sun.tools.javac.tree.TreeTranslator; jjg@1755: import com.sun.tools.javac.code.Attribute; rfield@1380: import com.sun.tools.javac.code.Kinds; rfield@1587: import com.sun.tools.javac.code.Scope; rfield@1380: import com.sun.tools.javac.code.Symbol; rfield@1380: import com.sun.tools.javac.code.Symbol.ClassSymbol; rfield@1380: import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol; rfield@1380: import com.sun.tools.javac.code.Symbol.MethodSymbol; rfield@2381: import com.sun.tools.javac.code.Symbol.TypeSymbol; rfield@1380: import com.sun.tools.javac.code.Symbol.VarSymbol; rfield@1380: import com.sun.tools.javac.code.Symtab; rfield@1380: import com.sun.tools.javac.code.Type; rfield@1380: import com.sun.tools.javac.code.Type.MethodType; rfield@2614: import com.sun.tools.javac.code.Type.TypeVar; rfield@1380: import com.sun.tools.javac.code.Types; rfield@1717: import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*; mcimadamore@1612: import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector; rfield@1380: import com.sun.tools.javac.jvm.*; rfield@1380: import com.sun.tools.javac.util.*; rfield@1380: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; rfield@1380: import com.sun.source.tree.MemberReferenceTree.ReferenceMode; rfield@1380: ksrini@2155: import java.util.EnumMap; rfield@1380: import java.util.HashMap; rfield@2381: import java.util.HashSet; rfield@1380: import java.util.LinkedHashMap; rfield@1380: import java.util.Map; rfield@2381: import java.util.Set; rfield@1380: rfield@1380: import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*; rfield@1380: import static com.sun.tools.javac.code.Flags.*; rfield@1380: import static com.sun.tools.javac.code.Kinds.*; rfield@1587: import static com.sun.tools.javac.code.TypeTag.*; rfield@1380: import static com.sun.tools.javac.tree.JCTree.Tag.*; rfield@2614: import javax.lang.model.type.TypeKind; rfield@1380: rfield@1380: /** rfield@1380: * This pass desugars lambda expressions into static methods rfield@1380: * rfield@1380: *

This is NOT part of any supported API. rfield@1380: * If you write code that depends on this, you do so at your own risk. rfield@1380: * This code and its internal interfaces are subject to change or rfield@1380: * deletion without notice. rfield@1380: */ rfield@1380: public class LambdaToMethod extends TreeTranslator { rfield@1380: ksrini@2155: private Attr attr; mcimadamore@1817: private JCDiagnostic.Factory diags; mcimadamore@1817: private Log log; mcimadamore@1612: private Lower lower; rfield@1380: private Names names; rfield@1380: private Symtab syms; rfield@1380: private Resolve rs; rfield@1380: private TreeMaker make; rfield@1380: private Types types; rfield@1380: private TransTypes transTypes; rfield@1380: private Env attrEnv; rfield@1380: rfield@1380: /** the analyzer scanner */ rfield@1717: private LambdaAnalyzerPreprocessor analyzer; rfield@1380: rfield@1380: /** map from lambda trees to translation contexts */ rfield@1380: private Map> contextMap; rfield@1380: rfield@1380: /** current translation context (visitor argument) */ rfield@1380: private TranslationContext context; rfield@1380: rfield@1587: /** info about the current class being processed */ rfield@1587: private KlassInfo kInfo; rfield@1587: mcimadamore@1817: /** dump statistics about lambda code generation */ mcimadamore@1817: private boolean dumpLambdaToMethodStats; mcimadamore@1817: ksrini@2251: /** force serializable representation, for stress testing **/ ksrini@2251: private final boolean forceSerializable; ksrini@2251: rfield@1587: /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */ rfield@1587: public static final int FLAG_SERIALIZABLE = 1 << 0; rfield@1587: rfield@1587: /** Flag for alternate metafactories indicating the lambda object has multiple targets */ rfield@1587: public static final int FLAG_MARKERS = 1 << 1; rfield@1587: mcimadamore@1882: /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */ mcimadamore@1882: public static final int FLAG_BRIDGES = 1 << 2; mcimadamore@1882: ksrini@2155: // ksrini@2155: protected static final Context.Key unlambdaKey = ksrini@2155: new Context.Key(); ksrini@2155: ksrini@2155: public static LambdaToMethod instance(Context context) { ksrini@2155: LambdaToMethod instance = context.get(unlambdaKey); ksrini@2155: if (instance == null) { ksrini@2155: instance = new LambdaToMethod(context); ksrini@2155: } ksrini@2155: return instance; ksrini@2155: } ksrini@2155: private LambdaToMethod(Context context) { ksrini@2155: context.put(unlambdaKey, this); ksrini@2155: diags = JCDiagnostic.Factory.instance(context); ksrini@2155: log = Log.instance(context); ksrini@2155: lower = Lower.instance(context); ksrini@2155: names = Names.instance(context); ksrini@2155: syms = Symtab.instance(context); ksrini@2155: rs = Resolve.instance(context); ksrini@2155: make = TreeMaker.instance(context); ksrini@2155: types = Types.instance(context); ksrini@2155: transTypes = TransTypes.instance(context); ksrini@2155: analyzer = new LambdaAnalyzerPreprocessor(); ksrini@2155: Options options = Options.instance(context); ksrini@2155: dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats"); ksrini@2155: attr = Attr.instance(context); ksrini@2251: forceSerializable = options.isSet("forceSerializable"); ksrini@2155: } ksrini@2155: // ksrini@2155: rfield@1587: private class KlassInfo { rfield@1587: rfield@1587: /** rfield@1587: * list of methods to append rfield@1587: */ rfield@1587: private ListBuffer appendedMethodList; rfield@1587: rfield@1587: /** rfield@1587: * list of deserialization cases rfield@1587: */ rfield@1587: private final Map> deserializeCases; rfield@1587: rfield@1587: /** rfield@1587: * deserialize method symbol rfield@1587: */ rfield@1587: private final MethodSymbol deserMethodSym; rfield@1587: rfield@1587: /** rfield@1587: * deserialize method parameter symbol rfield@1587: */ rfield@1587: private final VarSymbol deserParamSym; rfield@1587: jlahoda@2165: private final JCClassDecl clazz; jlahoda@2165: jlahoda@2165: private KlassInfo(JCClassDecl clazz) { jlahoda@2165: this.clazz = clazz; alundblad@2047: appendedMethodList = new ListBuffer<>(); rfield@1587: deserializeCases = new HashMap>(); rfield@1587: MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType, rfield@1587: List.nil(), syms.methodClass); jlahoda@2165: deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym); mcimadamore@1595: deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"), mcimadamore@1595: syms.serializedLambdaType, deserMethodSym); rfield@1587: } rfield@1587: rfield@1587: private void addMethod(JCTree decl) { rfield@1587: appendedMethodList = appendedMethodList.prepend(decl); rfield@1587: } rfield@1587: } rfield@1380: rfield@1380: // rfield@1380: @Override rfield@1380: public T translate(T tree) { rfield@1380: TranslationContext newContext = contextMap.get(tree); rfield@1380: return translate(tree, newContext != null ? newContext : context); rfield@1380: } rfield@1380: rfield@1762: T translate(T tree, TranslationContext newContext) { rfield@1380: TranslationContext prevContext = context; rfield@1380: try { rfield@1380: context = newContext; rfield@1380: return super.translate(tree); rfield@1380: } rfield@1380: finally { rfield@1380: context = prevContext; rfield@1380: } rfield@1380: } rfield@1380: rfield@1762: List translate(List trees, TranslationContext newContext) { alundblad@2047: ListBuffer buf = new ListBuffer<>(); rfield@1380: for (T tree : trees) { rfield@1380: buf.append(translate(tree, newContext)); rfield@1380: } rfield@1380: return buf.toList(); rfield@1380: } rfield@1380: rfield@1380: public JCTree translateTopLevelClass(Env env, JCTree cdef, TreeMaker make) { rfield@1380: this.make = make; rfield@1380: this.attrEnv = env; rfield@1380: this.context = null; rfield@1380: this.contextMap = new HashMap>(); rfield@1380: return translate(cdef); rfield@1380: } rfield@1380: // rfield@1380: rfield@1380: // rfield@1380: /** rfield@1380: * Visit a class. rfield@1380: * Maintain the translatedMethodList across nested classes. rfield@1380: * Append the translatedMethodList to the class after it is translated. rfield@1380: * @param tree rfield@1380: */ rfield@1380: @Override rfield@1380: public void visitClassDef(JCClassDecl tree) { rfield@1380: if (tree.sym.owner.kind == PCK) { rfield@1380: //analyze class rfield@1717: tree = analyzer.analyzeAndPreprocessClass(tree); rfield@1380: } rfield@1587: KlassInfo prevKlassInfo = kInfo; rfield@1380: try { jlahoda@2165: kInfo = new KlassInfo(tree); rfield@1380: super.visitClassDef(tree); rfield@1587: if (!kInfo.deserializeCases.isEmpty()) { jlahoda@2165: int prevPos = make.pos; jlahoda@2165: try { jlahoda@2165: make.at(tree); jlahoda@2165: kInfo.addMethod(makeDeserializeMethod(tree.sym)); jlahoda@2165: } finally { jlahoda@2165: make.at(prevPos); jlahoda@2165: } rfield@1587: } rfield@1380: //add all translated instance methods here rfield@1587: List newMethods = kInfo.appendedMethodList.toList(); rfield@1587: tree.defs = tree.defs.appendList(newMethods); rfield@1587: for (JCTree lambda : newMethods) { rfield@1380: tree.sym.members().enter(((JCMethodDecl)lambda).sym); rfield@1380: } rfield@1380: result = tree; rfield@1380: } finally { rfield@1587: kInfo = prevKlassInfo; rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * Translate a lambda into a method to be inserted into the class. rfield@1380: * Then replace the lambda site with an invokedynamic call of to lambda rfield@1380: * meta-factory, which will use the lambda method. rfield@1380: * @param tree rfield@1380: */ rfield@1380: @Override rfield@1380: public void visitLambda(JCLambda tree) { rfield@1380: LambdaTranslationContext localContext = (LambdaTranslationContext)context; jlahoda@2733: MethodSymbol sym = localContext.translatedSym; rfield@1380: MethodType lambdaType = (MethodType) sym.type; rfield@1380: jjg@1755: { jjg@1969: Symbol owner = localContext.owner; jjg@1755: ListBuffer ownerTypeAnnos = new ListBuffer(); jjg@1755: ListBuffer lambdaTypeAnnos = new ListBuffer(); jjg@1755: jjg@1755: for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) { jjg@1755: if (tc.position.onLambda == tree) { jjg@1755: lambdaTypeAnnos.append(tc); jjg@1755: } else { jjg@1755: ownerTypeAnnos.append(tc); jjg@1755: } jjg@1755: } jjg@1755: if (lambdaTypeAnnos.nonEmpty()) { jjg@1802: owner.setTypeAttributes(ownerTypeAnnos.toList()); jjg@1802: sym.setTypeAttributes(lambdaTypeAnnos.toList()); jjg@1755: } jjg@1755: } jjg@1755: rfield@1380: //create the method declaration hoisting the lambda body rfield@1380: JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field), rfield@1380: sym.name, rfield@1380: make.QualIdent(lambdaType.getReturnType().tsym), rfield@1380: List.nil(), rfield@1380: localContext.syntheticParams, rfield@1380: lambdaType.getThrownTypes() == null ? rfield@1380: List.nil() : rfield@1380: make.Types(lambdaType.getThrownTypes()), rfield@1380: null, rfield@1380: null); rfield@1380: lambdaDecl.sym = sym; rfield@1380: lambdaDecl.type = lambdaType; rfield@1380: rfield@1380: //translate lambda body rfield@1380: //As the lambda body is translated, all references to lambda locals, rfield@1380: //captured variables, enclosing members are adjusted accordingly rfield@1380: //to refer to the static method parameters (rather than i.e. acessing to rfield@1380: //captured members directly). rfield@1380: lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl)); rfield@1380: rfield@1380: //Add the method to the list of methods to be added to this class. rfield@1587: kInfo.addMethod(lambdaDecl); rfield@1380: rfield@1380: //now that we have generated a method for the lambda expression, rfield@1380: //we can translate the lambda into a method reference pointing to the newly rfield@1380: //created method. rfield@1380: // rfield@1380: //Note that we need to adjust the method handle so that it will match the rfield@1380: //signature of the SAM descriptor - this means that the method reference rfield@1380: //should be added the following synthetic arguments: rfield@1380: // rfield@1380: // * the "this" argument if it is an instance method rfield@1380: // * enclosing locals captured by the lambda expression rfield@1380: alundblad@2047: ListBuffer syntheticInits = new ListBuffer<>(); rfield@1380: rfield@2607: if (localContext.methodReferenceReceiver != null) { rfield@2607: syntheticInits.append(localContext.methodReferenceReceiver); rfield@2607: } else if (!sym.isStatic()) { rfield@1380: syntheticInits.append(makeThis( rfield@1587: sym.owner.enclClass().asType(), rfield@1380: localContext.owner.enclClass())); rfield@1380: } rfield@1380: rfield@1380: //add captured locals rfield@1380: for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) { rfield@1380: if (fv != localContext.self) { rfield@1380: JCTree captured_local = make.Ident(fv).setType(fv.type); rfield@1380: syntheticInits.append((JCExpression) captured_local); rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: //then, determine the arguments to the indy call rfield@1380: List indy_args = translate(syntheticInits.toList(), localContext.prev); rfield@1380: rfield@1380: //build a sam instance using an indy call to the meta-factory rfield@1380: int refKind = referenceKind(sym); rfield@1380: rfield@1380: //convert to an invokedynamic call mcimadamore@1882: result = makeMetafactoryIndyCall(context, refKind, sym, indy_args); rfield@1380: } rfield@1380: rfield@1380: private JCIdent makeThis(Type type, Symbol owner) { rfield@1380: VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC, rfield@1380: names._this, rfield@1380: type, rfield@1380: owner); rfield@1380: return make.Ident(_this); rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * Translate a method reference into an invokedynamic call to the rfield@1380: * meta-factory. rfield@1380: * @param tree rfield@1380: */ rfield@1380: @Override rfield@1380: public void visitReference(JCMemberReference tree) { rfield@1380: ReferenceTranslationContext localContext = (ReferenceTranslationContext)context; rfield@1380: rfield@1380: //first determine the method symbol to be used to generate the sam instance rfield@1380: //this is either the method reference symbol, or the bridged reference symbol rfield@2607: Symbol refSym = localContext.isSignaturePolymorphic() rfield@2202: ? localContext.sigPolySym rfield@2202: : tree.sym; rfield@1380: rfield@1380: //the qualifying expression is treated as a special captured arg rfield@1380: JCExpression init; rfield@1380: switch(tree.kind) { rfield@1380: mcimadamore@1435: case IMPLICIT_INNER: /** Inner :: new */ mcimadamore@1435: case SUPER: /** super :: instMethod */ rfield@1380: init = makeThis( rfield@1587: localContext.owner.enclClass().asType(), rfield@1587: localContext.owner.enclClass()); rfield@1380: break; rfield@1380: mcimadamore@1435: case BOUND: /** Expr :: instMethod */ rfield@1380: init = tree.getQualifierExpression(); vromero@2043: init = attr.makeNullCheck(init); rfield@1380: break; rfield@1380: mcimadamore@1435: case UNBOUND: /** Type :: instMethod */ mcimadamore@1435: case STATIC: /** Type :: staticMethod */ mcimadamore@1435: case TOPLEVEL: /** Top level :: new */ mcimadamore@1496: case ARRAY_CTOR: /** ArrayType :: new */ rfield@1380: init = null; rfield@1380: break; rfield@1380: rfield@1380: default: rfield@1380: throw new InternalError("Should not have an invalid kind"); rfield@1380: } rfield@1380: rfield@1380: List indy_args = init==null? List.nil() : translate(List.of(init), localContext.prev); rfield@1380: rfield@1380: rfield@1380: //build a sam instance using an indy call to the meta-factory mcimadamore@1882: result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args); rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * Translate identifiers within a lambda to the mapped identifier rfield@1380: * @param tree rfield@1380: */ rfield@1380: @Override rfield@1380: public void visitIdent(JCIdent tree) { rfield@1380: if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) { rfield@1380: super.visitIdent(tree); rfield@1380: } else { jlahoda@2165: int prevPos = make.pos; jlahoda@2165: try { jlahoda@2165: make.at(tree); jlahoda@2165: jlahoda@2165: LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context; jlahoda@2165: JCTree ltree = lambdaContext.translate(tree); jlahoda@2165: if (ltree != null) { jlahoda@2165: result = ltree; jlahoda@2165: } else { jlahoda@2165: //access to untranslated symbols (i.e. compile-time constants, jlahoda@2165: //members defined inside the lambda body, etc.) ) jlahoda@2165: super.visitIdent(tree); jlahoda@2165: } jlahoda@2165: } finally { jlahoda@2165: make.at(prevPos); rfield@1380: } rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: @Override rfield@1380: public void visitVarDef(JCVariableDecl tree) { rfield@1380: LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context; rfield@1380: if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) { rfield@2380: tree.init = translate(tree.init); rfield@2380: tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym); rfield@2380: result = tree; rfield@1587: } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) { rfield@1587: JCExpression init = translate(tree.init); rfield@1587: VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym); jlahoda@2165: int prevPos = make.pos; jlahoda@2165: try { jlahoda@2165: result = make.at(tree).VarDef(xsym, init); jlahoda@2165: } finally { jlahoda@2165: make.at(prevPos); jlahoda@2165: } rfield@1587: // Replace the entered symbol for this variable rfield@1587: Scope sc = tree.sym.owner.members(); rfield@1587: if (sc != null) { rfield@1587: sc.remove(tree.sym); rfield@1587: sc.enter(xsym); rfield@1587: } rfield@1380: } else { rfield@1380: super.visitVarDef(tree); rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: // rfield@1380: rfield@1380: // rfield@1380: rfield@1380: private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) { rfield@1380: return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ? rfield@1380: makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) : rfield@1380: makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally); rfield@1380: } rfield@1380: rfield@1380: private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) { rfield@1380: Type restype = lambdaMethodDecl.type.getReturnType(); rfield@1380: boolean isLambda_void = expr.type.hasTag(VOID); rfield@1380: boolean isTarget_void = restype.hasTag(VOID); rfield@1380: boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type); jlahoda@2165: int prevPos = make.pos; jlahoda@2165: try { jlahoda@2165: if (isTarget_void) { jlahoda@2165: //target is void: jlahoda@2165: // BODY; jlahoda@2165: JCStatement stat = make.at(expr).Exec(expr); jlahoda@2165: return make.Block(0, List.of(stat)); jlahoda@2165: } else if (isLambda_void && isTarget_Void) { jlahoda@2165: //void to Void conversion: jlahoda@2165: // BODY; return null; jlahoda@2165: ListBuffer stats = new ListBuffer<>(); jlahoda@2165: stats.append(make.at(expr).Exec(expr)); jlahoda@2165: stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType))); jlahoda@2165: return make.Block(0, stats.toList()); jlahoda@2165: } else { jlahoda@2165: //non-void to non-void conversion: jlahoda@2165: // return (TYPE)BODY; jlahoda@2165: JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype); jlahoda@2165: return make.at(retExpr).Block(0, List.of(make.Return(retExpr))); jlahoda@2165: } jlahoda@2165: } finally { jlahoda@2165: make.at(prevPos); rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) { rfield@1380: final Type restype = lambdaMethodDecl.type.getReturnType(); rfield@1380: final boolean isTarget_void = restype.hasTag(VOID); rfield@1380: boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type); rfield@1380: rfield@1380: class LambdaBodyTranslator extends TreeTranslator { rfield@1380: rfield@1380: @Override rfield@1380: public void visitClassDef(JCClassDecl tree) { rfield@1380: //do NOT recurse on any inner classes rfield@1380: result = tree; rfield@1380: } rfield@1380: rfield@1380: @Override rfield@1380: public void visitLambda(JCLambda tree) { rfield@1380: //do NOT recurse on any nested lambdas rfield@1380: result = tree; rfield@1380: } rfield@1380: rfield@1380: @Override rfield@1380: public void visitReturn(JCReturn tree) { rfield@1380: boolean isLambda_void = tree.expr == null; rfield@1380: if (isTarget_void && !isLambda_void) { rfield@1380: //Void to void conversion: rfield@1380: // { TYPE $loc = RET-EXPR; return; } rfield@1380: VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym); rfield@1380: JCVariableDecl varDef = make.VarDef(loc, tree.expr); rfield@1380: result = make.Block(0, List.of(varDef, make.Return(null))); rfield@1380: } else if (!isTarget_void || !isLambda_void) { rfield@1380: //non-void to non-void conversion: rfield@1380: // return (TYPE)RET-EXPR; rfield@1380: tree.expr = transTypes.coerce(attrEnv, tree.expr, restype); rfield@1380: result = tree; rfield@1380: } else { rfield@1380: result = tree; rfield@1380: } rfield@1380: rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: JCBlock trans_block = new LambdaBodyTranslator().translate(block); rfield@1380: if (completeNormally && isTarget_Void) { rfield@1380: //there's no return statement and the lambda (possibly inferred) rfield@1380: //return type is java.lang.Void; emit a synthetic return statement rfield@1380: trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType))); rfield@1380: } rfield@1380: return trans_block; rfield@1380: } rfield@1380: rfield@1587: private JCMethodDecl makeDeserializeMethod(Symbol kSym) { alundblad@2047: ListBuffer cases = new ListBuffer<>(); alundblad@2047: ListBuffer breaks = new ListBuffer<>(); rfield@1587: for (Map.Entry> entry : kInfo.deserializeCases.entrySet()) { rfield@1587: JCBreak br = make.Break(null); rfield@1587: breaks.add(br); rfield@1587: List stmts = entry.getValue().append(br).toList(); rfield@1587: cases.add(make.Case(make.Literal(entry.getKey()), stmts)); rfield@1587: } rfield@1587: JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList()); rfield@1587: for (JCBreak br : breaks) { rfield@1587: br.target = sw; rfield@1587: } rfield@1587: JCBlock body = make.Block(0L, List.of( rfield@1587: sw, rfield@1587: make.Throw(makeNewClass( rfield@1587: syms.illegalArgumentExceptionType, rfield@1587: List.of(make.Literal("Invalid lambda deserialization")))))); rfield@1587: JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()), rfield@1587: names.deserializeLambda, rfield@1587: make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym), rfield@1587: List.nil(), rfield@1587: List.of(make.VarDef(kInfo.deserParamSym, null)), rfield@1587: List.nil(), rfield@1587: body, rfield@1587: null); rfield@1587: deser.sym = kInfo.deserMethodSym; rfield@1587: deser.type = kInfo.deserMethodSym.type; rfield@1587: //System.err.printf("DESER: '%s'\n", deser); rfield@1587: return deser; rfield@1587: } rfield@1587: rfield@1587: /** Make an attributed class instance creation expression. rfield@1587: * @param ctype The class type. rfield@1587: * @param args The constructor arguments. rfield@1717: * @param cons The constructor symbol rfield@1587: */ rfield@1717: JCNewClass makeNewClass(Type ctype, List args, Symbol cons) { rfield@1587: JCNewClass tree = make.NewClass(null, rfield@1587: null, make.QualIdent(ctype.tsym), args, null); rfield@1717: tree.constructor = cons; rfield@1587: tree.type = ctype; rfield@1587: return tree; rfield@1587: } rfield@1587: rfield@1717: /** Make an attributed class instance creation expression. rfield@1717: * @param ctype The class type. rfield@1717: * @param args The constructor arguments. rfield@1717: */ rfield@1717: JCNewClass makeNewClass(Type ctype, List args) { rfield@1717: return makeNewClass(ctype, args, rfield@1717: rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil())); rfield@1717: } rfield@1717: rfield@1587: private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym, rfield@1587: DiagnosticPosition pos, List staticArgs, MethodType indyType) { rfield@1587: String functionalInterfaceClass = classSig(targetType); rfield@1587: String functionalInterfaceMethodName = samSym.getSimpleName().toString(); rfield@2158: String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type)); rfield@1622: String implClass = classSig(types.erasure(refSym.owner.type)); rfield@1587: String implMethodName = refSym.getQualifiedName().toString(); rfield@2158: String implMethodSignature = typeSig(types.erasure(refSym.type)); rfield@1587: rfield@1587: JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind)); alundblad@2047: ListBuffer serArgs = new ListBuffer<>(); rfield@1587: int i = 0; rfield@1587: for (Type t : indyType.getParameterTypes()) { alundblad@2047: List indexAsArg = new ListBuffer().append(make.Literal(i)).toList(); alundblad@2047: List argTypes = new ListBuffer().append(syms.intType).toList(); rfield@1587: serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg))); rfield@1587: ++i; rfield@1587: } rfield@1587: JCStatement stmt = make.If( rfield@1587: deserTest(deserTest(deserTest(deserTest(deserTest( rfield@1587: kindTest, rfield@1587: "getFunctionalInterfaceClass", functionalInterfaceClass), rfield@1587: "getFunctionalInterfaceMethodName", functionalInterfaceMethodName), rfield@1587: "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature), rfield@1587: "getImplClass", implClass), rfield@1587: "getImplMethodSignature", implMethodSignature), rfield@1587: make.Return(makeIndyCall( rfield@1587: pos, rfield@1587: syms.lambdaMetafactory, mcimadamore@1882: names.altMetafactory, mcimadamore@1882: staticArgs, indyType, serArgs.toList(), samSym.name)), rfield@1587: null); rfield@1587: ListBuffer stmts = kInfo.deserializeCases.get(implMethodName); rfield@1587: if (stmts == null) { alundblad@2047: stmts = new ListBuffer<>(); rfield@1587: kInfo.deserializeCases.put(implMethodName, stmts); rfield@1587: } rfield@1587: /**** rfield@1587: System.err.printf("+++++++++++++++++\n"); rfield@1587: System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass); rfield@1587: System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName); rfield@1587: System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature); rfield@1587: System.err.printf("*implMethodKind: %d\n", implMethodKind); rfield@1587: System.err.printf("*implClass: '%s'\n", implClass); rfield@1587: System.err.printf("*implMethodName: '%s'\n", implMethodName); rfield@1587: System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature); rfield@1587: ****/ rfield@1587: stmts.append(stmt); rfield@1587: } rfield@1587: rfield@1587: private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) { rfield@1587: JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2); rfield@1587: testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType); rfield@1587: testExpr.setType(syms.booleanType); rfield@1587: return testExpr; rfield@1587: } rfield@1587: rfield@1587: private JCExpression deserTest(JCExpression prev, String func, String lit) { rfield@1587: MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.nil(), syms.methodClass); rfield@1587: Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.nil()); rfield@1587: JCMethodInvocation eqtest = make.Apply( rfield@1587: List.nil(), rfield@1587: make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt), rfield@1587: List.of(make.Literal(lit))); rfield@1587: eqtest.setType(syms.booleanType); rfield@1587: JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest); rfield@1587: compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType); rfield@1587: compound.setType(syms.booleanType); rfield@1587: return compound; rfield@1587: } rfield@1587: rfield@1587: private JCExpression deserGetter(String func, Type type) { rfield@1587: return deserGetter(func, type, List.nil(), List.nil()); rfield@1587: } rfield@1587: rfield@1587: private JCExpression deserGetter(String func, Type type, List argTypes, List args) { rfield@1587: MethodType getmt = new MethodType(argTypes, type, List.nil(), syms.methodClass); rfield@1587: Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.nil()); rfield@1587: return make.Apply( rfield@1587: List.nil(), rfield@1587: make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt), rfield@1587: args).setType(type); rfield@1587: } rfield@1587: rfield@1380: /** rfield@1380: * Create new synthetic method with given flags, name, type, owner rfield@1380: */ rfield@2107: private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) { rfield@2107: return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner); rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * Create new synthetic variable with given flags, name, type, owner rfield@1380: */ rfield@1380: private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) { rfield@1380: return makeSyntheticVar(flags, names.fromString(name), type, owner); rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * Create new synthetic variable with given flags, name, type, owner rfield@1380: */ rfield@1380: private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) { rfield@1380: return new VarSymbol(flags | SYNTHETIC, name, type, owner); rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * Set varargsElement field on a given tree (must be either a new class tree rfield@1380: * or a method call tree) rfield@1380: */ rfield@1380: private void setVarargsIfNeeded(JCTree tree, Type varargsElement) { rfield@1380: if (varargsElement != null) { rfield@1380: switch (tree.getTag()) { rfield@1380: case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break; rfield@1380: case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break; rfield@1380: default: throw new AssertionError(); rfield@1380: } rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * Convert method/constructor arguments by inserting appropriate cast rfield@1380: * as required by type-erasure - this is needed when bridging a lambda/method rfield@1380: * reference, as the bridged signature might require downcast to be compatible rfield@1380: * with the generated signature. rfield@1380: */ rfield@1380: private List convertArgs(Symbol meth, List args, Type varargsElement) { rfield@1380: Assert.check(meth.kind == Kinds.MTH); rfield@1380: List formals = types.erasure(meth.type).getParameterTypes(); rfield@1380: if (varargsElement != null) { rfield@1380: Assert.check((meth.flags() & VARARGS) != 0); rfield@1380: } rfield@1380: return transTypes.translateArgs(args, formals, varargsElement, attrEnv); rfield@1380: } rfield@1380: rfield@1380: // rfield@1380: rfield@1380: /** rfield@2607: * Converts a method reference which cannot be used directly into a lambda rfield@1380: */ rfield@2607: private class MemberReferenceToLambda { rfield@1380: rfield@1380: private final JCMemberReference tree; rfield@1380: private final ReferenceTranslationContext localContext; rfield@2607: private final Symbol owner; alundblad@2047: private final ListBuffer args = new ListBuffer<>(); alundblad@2047: private final ListBuffer params = new ListBuffer<>(); rfield@1380: rfield@2607: private JCExpression receiverExpression = null; rfield@2607: rfield@2607: MemberReferenceToLambda(JCMemberReference tree, ReferenceTranslationContext localContext, Symbol owner) { rfield@1380: this.tree = tree; rfield@1380: this.localContext = localContext; rfield@2607: this.owner = owner; rfield@1380: } rfield@1380: rfield@2607: JCLambda lambda() { rfield@1380: int prevPos = make.pos; rfield@1380: try { rfield@1380: make.at(tree); rfield@1380: rfield@2607: //body generation - this can be either a method call or a rfield@2607: //new instance creation expression, depending on the member reference kind rfield@2614: VarSymbol rcvr = addParametersReturnReceiver(); rfield@2607: JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE) rfield@2607: ? expressionInvoke(rcvr) rfield@2607: : expressionNew(); rfield@1380: rfield@2607: JCLambda slam = make.Lambda(params.toList(), expr); rfield@2607: slam.targets = tree.targets; rfield@2607: slam.type = tree.type; rfield@2607: slam.pos = tree.pos; rfield@2607: return slam; rfield@1380: } finally { rfield@1380: make.at(prevPos); rfield@1380: } rfield@1380: } rfield@2607: rfield@2614: /** rfield@2614: * Generate the parameter list for the converted member reference. rfield@2614: * rfield@2614: * @return The receiver variable symbol, if any rfield@2614: */ rfield@2614: VarSymbol addParametersReturnReceiver() { rfield@2614: Type samDesc = localContext.bridgedRefSig(); rfield@2614: List samPTypes = samDesc.getParameterTypes(); rfield@2614: List descPTypes = tree.getDescriptorType(types).getParameterTypes(); rfield@2614: rfield@2614: // Determine the receiver, if any rfield@2614: VarSymbol rcvr; rfield@2614: switch (tree.kind) { rfield@2614: case BOUND: rfield@2614: // The receiver is explicit in the method reference rfield@2614: rcvr = addParameter("rec$", tree.getQualifierExpression().type, false); rfield@2614: receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); rfield@2614: break; rfield@2614: case UNBOUND: rfield@2614: // The receiver is the first parameter, extract it and rfield@2614: // adjust the SAM and unerased type lists accordingly rfield@2614: rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false); rfield@2614: samPTypes = samPTypes.tail; rfield@2614: descPTypes = descPTypes.tail; rfield@2614: break; rfield@2614: default: rfield@2614: rcvr = null; rfield@2614: break; rfield@2614: } rfield@2614: List implPTypes = tree.sym.type.getParameterTypes(); rfield@2614: int implSize = implPTypes.size(); rfield@2614: int samSize = samPTypes.size(); rfield@2614: // Last parameter to copy from referenced method, exclude final var args rfield@2614: int last = localContext.needsVarArgsConversion() ? implSize - 1 : implSize; rfield@2614: rfield@2614: // Failsafe -- assure match-up rfield@2614: boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size(); rfield@2614: rfield@2614: // Use parameter types of the implementation method unless the unerased rfield@2614: // SAM parameter type is an intersection type, in that case use the rfield@2614: // erased SAM parameter type so that the supertype relationship rfield@2614: // the implementation method parameters is not obscured. rfield@2614: // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes rfield@2614: // are used as pointers to the current parameter type information rfield@2614: // and are thus not usable afterwards. rfield@2614: for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) { rfield@2614: // By default use the implementation method parmeter type rfield@2614: Type parmType = implPTypes.head; rfield@2614: // If the unerased parameter type is a type variable whose rfield@2614: // bound is an intersection (eg. ) then rfield@2614: // use the SAM parameter type rfield@2614: if (checkForIntersection && descPTypes.head.getKind() == TypeKind.TYPEVAR) { rfield@2614: TypeVar tv = (TypeVar) descPTypes.head; rfield@2614: if (tv.bound.getKind() == TypeKind.INTERSECTION) { rfield@2614: parmType = samPTypes.head; rfield@2614: } rfield@2614: } rfield@2614: addParameter("x$" + i, parmType, true); rfield@2614: rfield@2614: // Advance to the next parameter rfield@2614: implPTypes = implPTypes.tail; rfield@2614: samPTypes = samPTypes.tail; rfield@2614: descPTypes = descPTypes.tail; rfield@2614: } rfield@2614: // Flatten out the var args rfield@2614: for (int i = last; i < samSize; ++i) { rfield@2614: addParameter("xva$" + i, tree.varargsElement, true); rfield@2614: } rfield@2614: rfield@2614: return rcvr; rfield@2614: } rfield@2614: rfield@2607: JCExpression getReceiverExpression() { rfield@2607: return receiverExpression; rfield@2607: } rfield@2607: rfield@2607: private JCExpression makeReceiver(VarSymbol rcvr) { rfield@2607: if (rcvr == null) return null; rfield@2607: JCExpression rcvrExpr = make.Ident(rcvr); dbuck@3102: Type rcvrType = tree.ownerAccessible ? tree.sym.enclClass().type : tree.expr.type; rfield@2607: if (rcvrType == syms.arrayClass.type) { rfield@2607: // Map the receiver type to the actually type, not just "array" rfield@2607: rcvrType = tree.getQualifierExpression().type; mcimadamore@1614: } rfield@2607: if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) { rfield@2607: rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType); rfield@2607: } rfield@2607: return rcvrExpr; rfield@2607: } rfield@1380: rfield@1380: /** rfield@2607: * determine the receiver of the method call - the receiver can rfield@2607: * be a type qualifier, the synthetic receiver parameter or 'super'. rfield@1380: */ rfield@2607: private JCExpression expressionInvoke(VarSymbol rcvr) { rfield@1380: JCExpression qualifier = aefimov@3076: (rcvr != null) ? aefimov@3076: makeReceiver(rcvr) : aefimov@3076: tree.getQualifierExpression(); rfield@1380: rfield@1380: //create the qualifier expression rfield@1380: JCFieldAccess select = make.Select(qualifier, tree.sym.name); rfield@1380: select.sym = tree.sym; rfield@1380: select.type = tree.sym.erasure(types); rfield@1380: rfield@1380: //create the method call expression rfield@1380: JCExpression apply = make.Apply(List.nil(), select, mcimadamore@1595: convertArgs(tree.sym, args.toList(), tree.varargsElement)). mcimadamore@1595: setType(tree.sym.erasure(types).getReturnType()); rfield@1380: rfield@1380: apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType()); rfield@1380: setVarargsIfNeeded(apply, tree.varargsElement); rfield@1380: return apply; rfield@1380: } rfield@1380: rfield@1380: /** rfield@2607: * Lambda body to use for a 'new'. rfield@1380: */ rfield@2607: private JCExpression expressionNew() { mcimadamore@1496: if (tree.kind == ReferenceKind.ARRAY_CTOR) { mcimadamore@1496: //create the array creation expression mcimadamore@1595: JCNewArray newArr = make.NewArray( mcimadamore@1595: make.Type(types.elemtype(tree.getQualifierExpression().type)), mcimadamore@1496: List.of(make.Ident(params.first())), mcimadamore@1496: null); mcimadamore@1496: newArr.type = tree.getQualifierExpression().type; mcimadamore@1496: return newArr; mcimadamore@1496: } else { mcimadamore@1496: //create the instance creation expression rfield@2607: //note that method reference syntax does not allow an explicit rfield@2607: //enclosing class (so the enclosing class is null) rfield@2607: JCNewClass newClass = make.NewClass(null, mcimadamore@1496: List.nil(), mcimadamore@1496: make.Type(tree.getQualifierExpression().type), mcimadamore@1496: convertArgs(tree.sym, args.toList(), tree.varargsElement), mcimadamore@1496: null); mcimadamore@1496: newClass.constructor = tree.sym; mcimadamore@1496: newClass.constructorType = tree.sym.erasure(types); mcimadamore@1496: newClass.type = tree.getQualifierExpression().type; mcimadamore@1496: setVarargsIfNeeded(newClass, tree.varargsElement); mcimadamore@1496: return newClass; rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: private VarSymbol addParameter(String name, Type p, boolean genArg) { rfield@2607: VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner); rfield@2607: vsym.pos = tree.pos; rfield@1380: params.append(make.VarDef(vsym, null)); rfield@1380: if (genArg) { rfield@1380: args.append(make.Ident(vsym)); rfield@1380: } rfield@1380: return vsym; rfield@1380: } rfield@1380: } rfield@1380: mcimadamore@1882: private MethodType typeToMethodType(Type mt) { mcimadamore@1882: Type type = types.erasure(mt); mcimadamore@1882: return new MethodType(type.getParameterTypes(), mcimadamore@1882: type.getReturnType(), mcimadamore@1882: type.getThrownTypes(), mcimadamore@1882: syms.methodClass); mcimadamore@1882: } mcimadamore@1882: rfield@1380: /** rfield@1380: * Generate an indy method call to the meta factory rfield@1380: */ mcimadamore@1882: private JCExpression makeMetafactoryIndyCall(TranslationContext context, mcimadamore@1882: int refKind, Symbol refSym, List indy_args) { mcimadamore@1882: JCFunctionalExpression tree = context.tree; rfield@1380: //determine the static bsm args mcimadamore@1510: MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym); rfield@1380: List staticArgs = List.of( mcimadamore@1882: typeToMethodType(samSym.type), vromero@1452: new Pool.MethodHandle(refKind, refSym, types), mcimadamore@1882: typeToMethodType(tree.getDescriptorType(types))); rfield@1380: rfield@1380: //computed indy arg types alundblad@2047: ListBuffer indy_args_types = new ListBuffer<>(); rfield@1380: for (JCExpression arg : indy_args) { rfield@1380: indy_args_types.append(arg.type); rfield@1380: } rfield@1380: rfield@1380: //finally, compute the type of the indy call rfield@1380: MethodType indyType = new MethodType(indy_args_types.toList(), rfield@1380: tree.type, rfield@1380: List.nil(), rfield@1380: syms.methodClass); rfield@1380: mcimadamore@1882: Name metafactoryName = context.needsAltMetafactory() ? mcimadamore@1882: names.altMetafactory : names.metafactory; rfield@1587: mcimadamore@1882: if (context.needsAltMetafactory()) { alundblad@2047: ListBuffer markers = new ListBuffer<>(); mcimadamore@1882: for (Type t : tree.targets.tail) { mcimadamore@1882: if (t.tsym != syms.serializableType.tsym) { mcimadamore@1882: markers.append(t.tsym); rfield@1587: } rfield@1587: } mcimadamore@1882: int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0; rfield@1587: boolean hasMarkers = markers.nonEmpty(); mcimadamore@1882: boolean hasBridges = context.bridges.nonEmpty(); mcimadamore@1882: if (hasMarkers) { mcimadamore@1882: flags |= FLAG_MARKERS; mcimadamore@1882: } mcimadamore@1882: if (hasBridges) { mcimadamore@1882: flags |= FLAG_BRIDGES; mcimadamore@1882: } rfield@1587: staticArgs = staticArgs.append(flags); rfield@1587: if (hasMarkers) { rfield@1587: staticArgs = staticArgs.append(markers.length()); rfield@1587: staticArgs = staticArgs.appendList(markers.toList()); rfield@1587: } mcimadamore@1882: if (hasBridges) { mcimadamore@1882: staticArgs = staticArgs.append(context.bridges.length() - 1); mcimadamore@1882: for (Symbol s : context.bridges) { mcimadamore@1882: Type s_erasure = s.erasure(types); mcimadamore@1882: if (!types.isSameType(s_erasure, samSym.erasure(types))) { mcimadamore@1882: staticArgs = staticArgs.append(s.erasure(types)); mcimadamore@1882: } mcimadamore@1882: } mcimadamore@1882: } mcimadamore@1882: if (context.isSerializable()) { jlahoda@2165: int prevPos = make.pos; jlahoda@2165: try { jlahoda@2165: make.at(kInfo.clazz); jlahoda@2165: addDeserializationCase(refKind, refSym, tree.type, samSym, jlahoda@2165: tree, staticArgs, indyType); jlahoda@2165: } finally { jlahoda@2165: make.at(prevPos); jlahoda@2165: } rfield@1587: } rfield@1587: } rfield@1587: mcimadamore@1882: return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name); rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * Generate an indy method call with given name, type and static bootstrap rfield@1380: * arguments types rfield@1380: */ mcimadamore@1595: private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName, mcimadamore@1882: List staticArgs, MethodType indyType, List indyArgs, mcimadamore@1882: Name methName) { rfield@1380: int prevPos = make.pos; rfield@1380: try { rfield@1380: make.at(pos); rfield@1380: List bsm_staticArgs = List.of(syms.methodHandleLookupType, rfield@1380: syms.stringType, rfield@1380: syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs)); rfield@1380: rfield@1380: Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site, rfield@1380: bsmName, bsm_staticArgs, List.nil()); rfield@1380: rfield@1380: DynamicMethodSymbol dynSym = mcimadamore@1882: new DynamicMethodSymbol(methName, rfield@1380: syms.noSymbol, mcimadamore@1595: bsm.isStatic() ? mcimadamore@1595: ClassFile.REF_invokeStatic : mcimadamore@1595: ClassFile.REF_invokeVirtual, rfield@1380: (MethodSymbol)bsm, rfield@1380: indyType, rfield@1380: staticArgs.toArray()); rfield@1380: rfield@1380: JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName); rfield@1380: qualifier.sym = dynSym; rfield@1380: qualifier.type = indyType.getReturnType(); rfield@1380: rfield@1380: JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, indyArgs); rfield@1380: proxyCall.type = indyType.getReturnType(); rfield@1380: return proxyCall; rfield@1380: } finally { rfield@1380: make.at(prevPos); rfield@1380: } rfield@1380: } rfield@1380: //where rfield@1380: private List bsmStaticArgToTypes(List args) { alundblad@2047: ListBuffer argtypes = new ListBuffer<>(); rfield@1380: for (Object arg : args) { rfield@1380: argtypes.append(bsmStaticArgToType(arg)); rfield@1380: } rfield@1380: return argtypes.toList(); rfield@1380: } rfield@1380: rfield@1380: private Type bsmStaticArgToType(Object arg) { rfield@1380: Assert.checkNonNull(arg); rfield@1380: if (arg instanceof ClassSymbol) { rfield@1380: return syms.classType; rfield@1380: } else if (arg instanceof Integer) { rfield@1380: return syms.intType; rfield@1380: } else if (arg instanceof Long) { rfield@1380: return syms.longType; rfield@1380: } else if (arg instanceof Float) { rfield@1380: return syms.floatType; rfield@1380: } else if (arg instanceof Double) { rfield@1380: return syms.doubleType; rfield@1380: } else if (arg instanceof String) { rfield@1380: return syms.stringType; rfield@1380: } else if (arg instanceof Pool.MethodHandle) { rfield@1380: return syms.methodHandleType; rfield@1380: } else if (arg instanceof MethodType) { rfield@1380: return syms.methodTypeType; rfield@1380: } else { rfield@1380: Assert.error("bad static arg " + arg.getClass()); rfield@1380: return null; rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * Get the opcode associated with this method reference rfield@1380: */ rfield@1380: private int referenceKind(Symbol refSym) { rfield@1380: if (refSym.isConstructor()) { rfield@1380: return ClassFile.REF_newInvokeSpecial; rfield@1380: } else { rfield@1380: if (refSym.isStatic()) { rfield@1380: return ClassFile.REF_invokeStatic; rfield@2107: } else if ((refSym.flags() & PRIVATE) != 0) { rfield@2107: return ClassFile.REF_invokeSpecial; rfield@1380: } else if (refSym.enclClass().isInterface()) { rfield@1380: return ClassFile.REF_invokeInterface; rfield@1380: } else { rfield@2107: return ClassFile.REF_invokeVirtual; rfield@1380: } rfield@1380: } rfield@1380: } rfield@1587: mcimadamore@1652: // rfield@1380: /** rfield@1380: * This visitor collects information about translation of a lambda expression. rfield@1380: * More specifically, it keeps track of the enclosing contexts and captured locals rfield@1380: * accessed by the lambda being translated (as well as other useful info). rfield@1717: * It also translates away problems for LambdaToMethod. rfield@1380: */ rfield@1717: class LambdaAnalyzerPreprocessor extends TreeTranslator { rfield@1380: rfield@1380: /** the frame stack - used to reconstruct translation info about enclosing scopes */ rfield@1380: private List frameStack; rfield@1380: rfield@1380: /** rfield@1380: * keep the count of lambda expression (used to generate unambiguous rfield@1380: * names) rfield@1380: */ rfield@1380: private int lambdaCount = 0; rfield@1380: rfield@1587: /** rfield@1587: * keep the count of lambda expression defined in given context (used to rfield@1587: * generate unambiguous names for serializable lambdas) rfield@1587: */ rfield@2158: private class SyntheticMethodNameCounter { rfield@2158: private Map map = new HashMap<>(); rfield@2158: int getIndex(StringBuilder buf) { rfield@2158: String temp = buf.toString(); rfield@2158: Integer count = map.get(temp); rfield@2158: if (count == null) { rfield@2158: count = 0; rfield@2158: } rfield@2158: ++count; rfield@2158: map.put(temp, count); rfield@2158: return count; rfield@2158: } rfield@2158: } rfield@2158: private SyntheticMethodNameCounter syntheticMethodNameCounts = rfield@2158: new SyntheticMethodNameCounter(); rfield@1587: mcimadamore@1612: private Map localClassDefs; mcimadamore@1612: rfield@1587: /** rfield@1587: * maps for fake clinit symbols to be used as owners of lambda occurring in rfield@1587: * a static var init context rfield@1587: */ rfield@1587: private Map clinits = rfield@1587: new HashMap(); rfield@1587: rfield@1717: private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) { rfield@1380: frameStack = List.nil(); mcimadamore@1612: localClassDefs = new HashMap(); rfield@1717: return translate(tree); rfield@1380: } rfield@1380: rfield@1380: @Override rfield@1380: public void visitBlock(JCBlock tree) { rfield@1380: List prevStack = frameStack; rfield@1380: try { rfield@1380: if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) { rfield@1380: frameStack = frameStack.prepend(new Frame(tree)); rfield@1380: } rfield@1380: super.visitBlock(tree); rfield@1380: } rfield@1380: finally { rfield@1380: frameStack = prevStack; rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: @Override rfield@1380: public void visitClassDef(JCClassDecl tree) { rfield@1380: List prevStack = frameStack; jlahoda@2905: int prevLambdaCount = lambdaCount; rfield@2158: SyntheticMethodNameCounter prevSyntheticMethodNameCounts = rfield@2158: syntheticMethodNameCounts; rfield@1587: Map prevClinits = clinits; mcimadamore@1817: DiagnosticSource prevSource = log.currentSource(); rfield@1380: try { mcimadamore@1817: log.useSource(tree.sym.sourcefile); jlahoda@2905: lambdaCount = 0; rfield@2158: syntheticMethodNameCounts = new SyntheticMethodNameCounter(); rfield@1587: prevClinits = new HashMap(); mcimadamore@1612: if (tree.sym.owner.kind == MTH) { mcimadamore@1612: localClassDefs.put(tree.sym, tree); mcimadamore@1612: } rfield@1587: if (directlyEnclosingLambda() != null) { rfield@1380: tree.sym.owner = owner(); mcimadamore@1595: if (tree.sym.hasOuterInstance()) { mcimadamore@1595: //if a class is defined within a lambda, the lambda must capture mcimadamore@1595: //its enclosing instance (if any) mcimadamore@1612: TranslationContext localContext = context(); mcimadamore@1612: while (localContext != null) { mcimadamore@1612: if (localContext.tree.getTag() == LAMBDA) { mcimadamore@1612: ((LambdaTranslationContext)localContext) mcimadamore@1612: .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS); mcimadamore@1612: } mcimadamore@1612: localContext = localContext.prev; mcimadamore@1612: } rfield@1380: } rfield@1380: } rfield@1380: frameStack = frameStack.prepend(new Frame(tree)); rfield@1380: super.visitClassDef(tree); rfield@1380: } rfield@1380: finally { mcimadamore@1817: log.useSource(prevSource.getFile()); rfield@1380: frameStack = prevStack; jlahoda@2905: lambdaCount = prevLambdaCount; rfield@2158: syntheticMethodNameCounts = prevSyntheticMethodNameCounts; rfield@1587: clinits = prevClinits; rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: @Override rfield@1380: public void visitIdent(JCIdent tree) { rfield@1587: if (context() != null && lambdaIdentSymbolFilter(tree.sym)) { rfield@1380: if (tree.sym.kind == VAR && rfield@1380: tree.sym.owner.kind == MTH && rfield@1380: tree.type.constValue() == null) { rfield@1380: TranslationContext localContext = context(); rfield@1380: while (localContext != null) { rfield@1380: if (localContext.tree.getTag() == LAMBDA) { rfield@1380: JCTree block = capturedDecl(localContext.depth, tree.sym); rfield@1380: if (block == null) break; mcimadamore@1595: ((LambdaTranslationContext)localContext) mcimadamore@1595: .addSymbol(tree.sym, CAPTURED_VAR); rfield@1380: } rfield@1380: localContext = localContext.prev; rfield@1380: } rfield@1380: } else if (tree.sym.owner.kind == TYP) { rfield@1380: TranslationContext localContext = context(); rfield@1380: while (localContext != null) { rfield@1380: if (localContext.tree.hasTag(LAMBDA)) { rfield@1380: JCTree block = capturedDecl(localContext.depth, tree.sym); rfield@1380: if (block == null) break; rfield@1380: switch (block.getTag()) { rfield@1380: case CLASSDEF: rfield@1380: JCClassDecl cdecl = (JCClassDecl)block; mcimadamore@1595: ((LambdaTranslationContext)localContext) mcimadamore@1595: .addSymbol(cdecl.sym, CAPTURED_THIS); rfield@1380: break; rfield@1380: default: rfield@1380: Assert.error("bad block kind"); rfield@1380: } rfield@1380: } rfield@1380: localContext = localContext.prev; rfield@1380: } rfield@1380: } rfield@1380: } rfield@1587: super.visitIdent(tree); rfield@1380: } rfield@1380: rfield@1380: @Override rfield@1380: public void visitLambda(JCLambda tree) { rfield@2607: analyzeLambda(tree, "lambda.stat"); rfield@2607: } rfield@2607: rfield@2607: private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) { rfield@2607: // Translation of the receiver expression must occur first rfield@2607: JCExpression rcvr = translate(methodReferenceReceiver); rfield@2607: LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1"); rfield@2607: if (rcvr != null) { rfield@2607: context.methodReferenceReceiver = rcvr; rfield@2607: } rfield@2607: } rfield@2607: rfield@2607: private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) { rfield@1380: List prevStack = frameStack; rfield@1380: try { rfield@2607: LambdaTranslationContext context = new LambdaTranslationContext(tree); rfield@2607: if (dumpLambdaToMethodStats) { rfield@2607: log.note(tree, statKey, context.needsAltMetafactory(), context.translatedSym); rfield@2607: } rfield@1380: frameStack = frameStack.prepend(new Frame(tree)); rfield@1380: for (JCVariableDecl param : tree.params) { rfield@1380: context.addSymbol(param.sym, PARAM); rfield@1380: frameStack.head.addLocal(param.sym); rfield@1380: } rfield@1380: contextMap.put(tree, context); rfield@1717: super.visitLambda(tree); rfield@1380: context.complete(); rfield@2607: return context; rfield@1380: } rfield@1380: finally { rfield@1380: frameStack = prevStack; rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: @Override rfield@1380: public void visitMethodDef(JCMethodDecl tree) { rfield@1380: List prevStack = frameStack; rfield@1380: try { rfield@1380: frameStack = frameStack.prepend(new Frame(tree)); rfield@1380: super.visitMethodDef(tree); rfield@1380: } rfield@1380: finally { rfield@1380: frameStack = prevStack; rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: @Override rfield@1380: public void visitNewClass(JCNewClass tree) { rfield@2381: TypeSymbol def = tree.type.tsym; rfield@2381: boolean inReferencedClass = currentlyInClass(def); rfield@2381: boolean isLocal = def.isLocal(); rfield@2381: if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) { mcimadamore@1612: TranslationContext localContext = context(); mcimadamore@1612: while (localContext != null) { mcimadamore@1612: if (localContext.tree.getTag() == LAMBDA) { mcimadamore@1612: ((LambdaTranslationContext)localContext) mcimadamore@1612: .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS); mcimadamore@1612: } mcimadamore@1612: localContext = localContext.prev; mcimadamore@1612: } mcimadamore@1612: } rfield@2381: if (context() != null && !inReferencedClass && isLocal) { mcimadamore@1612: LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context(); rfield@2381: captureLocalClassDefs(def, lambdaContext); rfield@1380: } rfield@1380: super.visitNewClass(tree); rfield@1380: } mcimadamore@1612: //where mcimadamore@1612: void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) { mcimadamore@1612: JCClassDecl localCDef = localClassDefs.get(csym); rfield@2381: if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) { mcimadamore@1612: BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() { mcimadamore@1612: @Override mcimadamore@1612: void addFreeVars(ClassSymbol c) { mcimadamore@1612: captureLocalClassDefs(c, lambdaContext); mcimadamore@1612: } mcimadamore@1612: @Override mcimadamore@1612: void visitSymbol(Symbol sym) { mcimadamore@1612: if (sym.kind == VAR && mcimadamore@1612: sym.owner.kind == MTH && mcimadamore@1612: ((VarSymbol)sym).getConstValue() == null) { mcimadamore@1612: TranslationContext localContext = context(); mcimadamore@1612: while (localContext != null) { mcimadamore@1612: if (localContext.tree.getTag() == LAMBDA) { mcimadamore@1612: JCTree block = capturedDecl(localContext.depth, sym); mcimadamore@1612: if (block == null) break; mcimadamore@1612: ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR); mcimadamore@1612: } mcimadamore@1612: localContext = localContext.prev; mcimadamore@1612: } mcimadamore@1612: } mcimadamore@1612: } mcimadamore@1612: }; mcimadamore@1612: fvc.scan(localCDef); mcimadamore@1612: } rfield@1717: } rfield@2381: //where rfield@2381: boolean currentlyInClass(Symbol csym) { rfield@2381: for (Frame frame : frameStack) { rfield@2381: if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) { rfield@2381: JCClassDecl cdef = (JCClassDecl) frame.tree; rfield@2381: if (cdef.sym == csym) { rfield@2381: return true; rfield@2381: } rfield@2381: } rfield@2381: } rfield@2381: return false; rfield@2381: } rfield@1380: rfield@1717: /** rfield@1717: * Method references to local class constructors, may, if the local rfield@1717: * class references local variables, have implicit constructor rfield@1717: * parameters added in Lower; As a result, the invokedynamic bootstrap rfield@1717: * information added in the LambdaToMethod pass will have the wrong rfield@1717: * signature. Hooks between Lower and LambdaToMethod have been added to rfield@1717: * handle normal "new" in this case. This visitor converts potentially rfield@2607: * affected method references into a lambda containing a normal rfield@2607: * expression. rfield@1717: * rfield@1717: * @param tree rfield@1717: */ rfield@1380: @Override rfield@1380: public void visitReference(JCMemberReference tree) { rfield@2607: ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree); rfield@2607: contextMap.put(tree, rcontext); rfield@2607: if (rcontext.needsConversionToLambda()) { rfield@2607: // Convert to a lambda, and process as such rfield@2607: MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner()); rfield@2607: analyzeLambda(conv.lambda(), conv.getReceiverExpression()); rfield@1717: } else { rfield@1717: super.visitReference(tree); rfield@2607: if (dumpLambdaToMethodStats) { rfield@2607: log.note(tree, "mref.stat", rcontext.needsAltMetafactory(), null); rfield@2607: } rfield@1717: } rfield@1380: } rfield@1380: rfield@1380: @Override rfield@1380: public void visitSelect(JCFieldAccess tree) { rfield@1762: if (context() != null && tree.sym.kind == VAR && rfield@1762: (tree.sym.name == names._this || rfield@1762: tree.sym.name == names._super)) { rfield@1762: // A select of this or super means, if we are in a lambda, rfield@1762: // we much have an instance context rfield@1380: TranslationContext localContext = context(); rfield@1380: while (localContext != null) { rfield@1380: if (localContext.tree.hasTag(LAMBDA)) { rfield@1380: JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym); rfield@1380: if (clazz == null) break; rfield@1380: ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS); rfield@1380: } rfield@1380: localContext = localContext.prev; rfield@1380: } rfield@1380: } rfield@1717: super.visitSelect(tree); rfield@1380: } rfield@1380: rfield@1380: @Override rfield@1380: public void visitVarDef(JCVariableDecl tree) { rfield@1587: TranslationContext context = context(); rfield@1587: LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)? rfield@1587: (LambdaTranslationContext)context : rfield@1587: null; rfield@1587: if (ltc != null) { rfield@1587: if (frameStack.head.tree.hasTag(LAMBDA)) { rfield@1587: ltc.addSymbol(tree.sym, LOCAL_VAR); rfield@1587: } rfield@1587: // Check for type variables (including as type arguments). rfield@1587: // If they occur within class nested in a lambda, mark for erasure rfield@1587: Type type = tree.sym.asType(); rfield@1587: if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) { rfield@1587: ltc.addSymbol(tree.sym, TYPE_VAR); rfield@1587: } rfield@1380: } rfield@1587: rfield@1380: List prevStack = frameStack; rfield@1380: try { rfield@1380: if (tree.sym.owner.kind == MTH) { rfield@1380: frameStack.head.addLocal(tree.sym); rfield@1380: } rfield@1380: frameStack = frameStack.prepend(new Frame(tree)); rfield@1380: super.visitVarDef(tree); rfield@1380: } rfield@1380: finally { rfield@1380: frameStack = prevStack; rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * Return a valid owner given the current declaration stack rfield@1380: * (required to skip synthetic lambda symbols) rfield@1380: */ rfield@1380: private Symbol owner() { mcimadamore@1515: return owner(false); mcimadamore@1515: } mcimadamore@1515: mcimadamore@1515: @SuppressWarnings("fallthrough") mcimadamore@1515: private Symbol owner(boolean skipLambda) { rfield@1380: List frameStack2 = frameStack; rfield@1380: while (frameStack2.nonEmpty()) { rfield@1380: switch (frameStack2.head.tree.getTag()) { rfield@1380: case VARDEF: rfield@1380: if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) { rfield@1380: frameStack2 = frameStack2.tail; rfield@1380: break; rfield@1380: } rfield@1380: JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree; rfield@1587: return initSym(cdecl.sym, rfield@1587: ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC); rfield@1380: case BLOCK: rfield@1380: JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree; rfield@1587: return initSym(cdecl2.sym, rfield@1587: ((JCBlock)frameStack2.head.tree).flags & STATIC); rfield@1380: case CLASSDEF: rfield@1380: return ((JCClassDecl)frameStack2.head.tree).sym; rfield@1380: case METHODDEF: rfield@1380: return ((JCMethodDecl)frameStack2.head.tree).sym; rfield@1380: case LAMBDA: mcimadamore@1515: if (!skipLambda) mcimadamore@1595: return ((LambdaTranslationContext)contextMap mcimadamore@1595: .get(frameStack2.head.tree)).translatedSym; rfield@1380: default: rfield@1380: frameStack2 = frameStack2.tail; rfield@1380: } rfield@1380: } rfield@1380: Assert.error(); rfield@1380: return null; rfield@1380: } rfield@1380: rfield@1587: private Symbol initSym(ClassSymbol csym, long flags) { rfield@1587: boolean isStatic = (flags & STATIC) != 0; rfield@1587: if (isStatic) { vromero@2222: /* static clinits are generated in Gen, so we need to use a fake vromero@2222: * one. Attr creates a fake clinit method while attributing vromero@2222: * lambda expressions used as initializers of static fields, so vromero@2222: * let's use that one. vromero@2222: */ vromero@2222: MethodSymbol clinit = attr.removeClinit(csym); vromero@2222: if (clinit != null) { vromero@2222: clinits.put(csym, clinit); vromero@2222: return clinit; vromero@2222: } vromero@2222: vromero@2222: /* if no clinit is found at Attr, then let's try at clinits. vromero@2222: */ vromero@2222: clinit = (MethodSymbol)clinits.get(csym); rfield@1587: if (clinit == null) { vromero@2222: /* no luck, let's create a new one vromero@2222: */ rfield@2107: clinit = makePrivateSyntheticMethod(STATIC, rfield@1587: names.clinit, vromero@2222: new MethodType(List.nil(), syms.voidType, vromero@2222: List.nil(), syms.methodClass), rfield@1587: csym); rfield@1587: clinits.put(csym, clinit); rfield@1587: } rfield@1587: return clinit; rfield@1587: } else { rfield@1587: //get the first constructor and treat it as the instance init sym rfield@1587: for (Symbol s : csym.members_field.getElementsByName(names.init)) { rfield@1587: return s; rfield@1587: } rfield@1587: } rfield@1587: Assert.error("init not found"); rfield@1587: return null; rfield@1587: } rfield@1587: rfield@1587: private JCTree directlyEnclosingLambda() { rfield@1587: if (frameStack.isEmpty()) { rfield@1587: return null; rfield@1587: } rfield@1380: List frameStack2 = frameStack; rfield@1380: while (frameStack2.nonEmpty()) { rfield@1380: switch (frameStack2.head.tree.getTag()) { rfield@1380: case CLASSDEF: rfield@1380: case METHODDEF: rfield@1380: return null; rfield@1380: case LAMBDA: rfield@1380: return frameStack2.head.tree; rfield@1380: default: rfield@1380: frameStack2 = frameStack2.tail; rfield@1380: } rfield@1380: } rfield@1380: Assert.error(); rfield@1380: return null; rfield@1380: } rfield@1380: rfield@1587: private boolean inClassWithinLambda() { rfield@1587: if (frameStack.isEmpty()) { rfield@1587: return false; rfield@1587: } rfield@1587: List frameStack2 = frameStack; rfield@1587: boolean classFound = false; rfield@1587: while (frameStack2.nonEmpty()) { rfield@1587: switch (frameStack2.head.tree.getTag()) { rfield@1587: case LAMBDA: rfield@1587: return classFound; rfield@1587: case CLASSDEF: rfield@1587: classFound = true; rfield@1587: frameStack2 = frameStack2.tail; rfield@1587: break; rfield@1587: default: rfield@1587: frameStack2 = frameStack2.tail; rfield@1587: } rfield@1587: } rfield@1587: // No lambda rfield@1587: return false; rfield@1587: } rfield@1587: rfield@1380: /** rfield@1380: * Return the declaration corresponding to a symbol in the enclosing rfield@1380: * scope; the depth parameter is used to filter out symbols defined rfield@1380: * in nested scopes (which do not need to undergo capture). rfield@1380: */ rfield@1380: private JCTree capturedDecl(int depth, Symbol sym) { rfield@1380: int currentDepth = frameStack.size() - 1; rfield@1380: for (Frame block : frameStack) { rfield@1380: switch (block.tree.getTag()) { rfield@1380: case CLASSDEF: rfield@1380: ClassSymbol clazz = ((JCClassDecl)block.tree).sym; rfield@1380: if (sym.isMemberOf(clazz, types)) { rfield@1380: return currentDepth > depth ? null : block.tree; rfield@1380: } rfield@1380: break; rfield@1380: case VARDEF: rfield@1380: if (((JCVariableDecl)block.tree).sym == sym && rfield@1380: sym.owner.kind == MTH) { //only locals are captured rfield@1380: return currentDepth > depth ? null : block.tree; rfield@1380: } rfield@1380: break; rfield@1380: case BLOCK: rfield@1380: case METHODDEF: rfield@1380: case LAMBDA: rfield@1380: if (block.locals != null && block.locals.contains(sym)) { rfield@1380: return currentDepth > depth ? null : block.tree; rfield@1380: } rfield@1380: break; rfield@1380: default: rfield@1380: Assert.error("bad decl kind " + block.tree.getTag()); rfield@1380: } rfield@1380: currentDepth--; rfield@1380: } rfield@1380: return null; rfield@1380: } rfield@1380: rfield@1380: private TranslationContext context() { rfield@1380: for (Frame frame : frameStack) { rfield@1380: TranslationContext context = contextMap.get(frame.tree); rfield@1380: if (context != null) { rfield@1380: return context; rfield@1380: } rfield@1380: } rfield@1380: return null; rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * This is used to filter out those identifiers that needs to be adjusted rfield@1380: * when translating away lambda expressions rfield@1380: */ rfield@1380: private boolean lambdaIdentSymbolFilter(Symbol sym) { rfield@1380: return (sym.kind == VAR || sym.kind == MTH) rfield@1380: && !sym.isStatic() rfield@1380: && sym.name != names.init; rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * This is used to filter out those new class expressions that need to rfield@1380: * be qualified with an enclosing tree rfield@1380: */ rfield@1380: private boolean lambdaNewClassFilter(TranslationContext context, JCNewClass tree) { rfield@1380: if (context != null rfield@1380: && tree.encl == null rfield@1380: && tree.def == null rfield@1405: && !tree.type.getEnclosingType().hasTag(NONE)) { rfield@1380: Type encl = tree.type.getEnclosingType(); rfield@1380: Type current = context.owner.enclClass().type; rfield@1405: while (!current.hasTag(NONE)) { rfield@1380: if (current.tsym.isSubClass(encl.tsym, types)) { rfield@1380: return true; rfield@1380: } rfield@1380: current = current.getEnclosingType(); rfield@1380: } rfield@1380: return false; rfield@1380: } else { rfield@1380: return false; rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: private class Frame { rfield@1380: final JCTree tree; rfield@1380: List locals; rfield@1380: rfield@1380: public Frame(JCTree tree) { rfield@1380: this.tree = tree; rfield@1380: } rfield@1380: rfield@1380: void addLocal(Symbol sym) { rfield@1380: if (locals == null) { rfield@1380: locals = List.nil(); rfield@1380: } rfield@1380: locals = locals.prepend(sym); rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * This class is used to store important information regarding translation of rfield@1380: * lambda expression/method references (see subclasses). rfield@1380: */ mcimadamore@1510: private abstract class TranslationContext { rfield@1380: rfield@1380: /** the underlying (untranslated) tree */ rfield@2158: final T tree; rfield@1380: rfield@1380: /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */ rfield@2158: final Symbol owner; rfield@1380: rfield@1380: /** the depth of this lambda expression in the frame stack */ rfield@2158: final int depth; rfield@1380: rfield@1380: /** the enclosing translation context (set for nested lambdas/mref) */ rfield@2158: final TranslationContext prev; rfield@1380: mcimadamore@1882: /** list of methods to be bridged by the meta-factory */ rfield@2158: final List bridges; mcimadamore@1882: rfield@1380: TranslationContext(T tree) { rfield@1380: this.tree = tree; rfield@1380: this.owner = owner(); rfield@1380: this.depth = frameStack.size() - 1; rfield@1380: this.prev = context(); mcimadamore@1882: ClassSymbol csym = mcimadamore@1882: types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE); mcimadamore@1882: this.bridges = types.functionalInterfaceBridges(csym); rfield@1380: } rfield@1587: rfield@1587: /** does this functional expression need to be created using alternate metafactory? */ rfield@1587: boolean needsAltMetafactory() { mcimadamore@1882: return tree.targets.length() > 1 || mcimadamore@1882: isSerializable() || mcimadamore@1882: bridges.length() > 1; rfield@1587: } rfield@1587: rfield@1587: /** does this functional expression require serialization support? */ rfield@1587: boolean isSerializable() { ksrini@2251: if (forceSerializable) { ksrini@2251: return true; ksrini@2251: } mcimadamore@1882: for (Type target : tree.targets) { mcimadamore@1882: if (types.asSuper(target, syms.serializableType.tsym) != null) { rfield@1587: return true; rfield@1587: } rfield@1587: } rfield@1587: return false; rfield@1587: } rfield@2158: rfield@2158: /** rfield@2158: * @return Name of the enclosing method to be folded into synthetic rfield@2158: * method name rfield@2158: */ rfield@2158: String enclosingMethodName() { rfield@2158: return syntheticMethodNameComponent(owner.name); rfield@2158: } rfield@2158: rfield@2158: /** rfield@2158: * @return Method name in a form that can be folded into a rfield@2158: * component of a synthetic method name rfield@2158: */ rfield@2158: String syntheticMethodNameComponent(Name name) { rfield@2158: if (name == null) { rfield@2158: return "null"; rfield@2158: } rfield@2158: String methodName = name.toString(); rfield@2158: if (methodName.equals("")) { rfield@2158: methodName = "static"; rfield@2158: } else if (methodName.equals("")) { rfield@2158: methodName = "new"; rfield@2158: } rfield@2158: return methodName; rfield@2158: } rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * This class retains all the useful information about a lambda expression; rfield@1380: * the contents of this class are filled by the LambdaAnalyzer visitor, rfield@1380: * and the used by the main translation routines in order to adjust references rfield@1380: * to captured locals/members, etc. rfield@1380: */ rfield@1380: private class LambdaTranslationContext extends TranslationContext { rfield@1380: rfield@1380: /** variable in the enclosing context to which this lambda is assigned */ rfield@2158: final Symbol self; rfield@2158: rfield@2158: /** variable in the enclosing context to which this lambda is assigned */ rfield@2158: final Symbol assignedTo; rfield@1380: ksrini@2155: Map> translatedSymbols; rfield@1587: rfield@1380: /** the synthetic symbol for the method hoisting the translated lambda */ jlahoda@2733: MethodSymbol translatedSym; rfield@1380: rfield@1380: List syntheticParams; rfield@1380: rfield@2381: /** rfield@2381: * to prevent recursion, track local classes processed rfield@2381: */ rfield@2381: final Set freeVarProcessedLocalClasses; rfield@2381: rfield@2607: /** rfield@2607: * For method references converted to lambdas. The method rfield@2607: * reference receiver expression. Must be treated like a captured rfield@2607: * variable. rfield@2607: */ rfield@2607: JCExpression methodReferenceReceiver; rfield@2607: rfield@1380: LambdaTranslationContext(JCLambda tree) { rfield@1380: super(tree); rfield@1380: Frame frame = frameStack.head; rfield@2158: switch (frame.tree.getTag()) { rfield@2158: case VARDEF: rfield@2158: assignedTo = self = ((JCVariableDecl) frame.tree).sym; rfield@2158: break; rfield@2158: case ASSIGN: rfield@2158: self = null; rfield@2158: assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable()); rfield@2158: break; rfield@2158: default: rfield@2158: assignedTo = self = null; rfield@2158: break; rfield@2158: } rfield@2158: rfield@2158: // This symbol will be filled-in in complete rfield@2158: this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass()); rfield@2158: ksrini@2155: translatedSymbols = new EnumMap<>(LambdaSymbolKind.class); ksrini@2155: ksrini@2155: translatedSymbols.put(PARAM, new LinkedHashMap()); ksrini@2155: translatedSymbols.put(LOCAL_VAR, new LinkedHashMap()); ksrini@2155: translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap()); ksrini@2155: translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap()); ksrini@2155: translatedSymbols.put(TYPE_VAR, new LinkedHashMap()); rfield@2381: rfield@2381: freeVarProcessedLocalClasses = new HashSet<>(); rfield@1380: } rfield@1380: rfield@2158: /** rfield@2158: * For a serializable lambda, generate a disambiguating string rfield@2158: * which maximizes stability across deserialization. rfield@2158: * rfield@2158: * @return String to differentiate synthetic lambda method names rfield@2158: */ rfield@2158: private String serializedLambdaDisambiguation() { rfield@2158: StringBuilder buf = new StringBuilder(); rfield@2158: // Append the enclosing method signature to differentiate rfield@2158: // overloaded enclosing methods. For lambdas enclosed in rfield@2158: // lambdas, the generated lambda method will not have type yet, rfield@2158: // but the enclosing method's name will have been generated rfield@2158: // with this same method, so it will be unique and never be rfield@2158: // overloaded. rfield@2158: Assert.check( rfield@2158: owner.type != null || rfield@2158: directlyEnclosingLambda() != null); rfield@2158: if (owner.type != null) { rfield@2158: buf.append(typeSig(owner.type)); rfield@2158: buf.append(":"); rfield@2158: } rfield@2158: rfield@2158: // Add target type info rfield@2158: buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName()); rfield@2158: buf.append(" "); rfield@2158: rfield@2158: // Add variable assigned to rfield@2158: if (assignedTo != null) { rfield@2158: buf.append(assignedTo.flatName()); rfield@2158: buf.append("="); rfield@2158: } rfield@2158: //add captured locals info: type, name, order rfield@2158: for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) { rfield@2158: if (fv != self) { rfield@2158: buf.append(typeSig(fv.type)); rfield@2158: buf.append(" "); rfield@2158: buf.append(fv.flatName()); rfield@2158: buf.append(","); rfield@2158: } rfield@2158: } rfield@2158: rfield@2158: return buf.toString(); rfield@2158: } rfield@2158: rfield@2158: /** rfield@2158: * For a non-serializable lambda, generate a simple method. rfield@2158: * rfield@2158: * @return Name to use for the synthetic lambda method name rfield@2158: */ rfield@2158: private Name lambdaName() { rfield@2158: return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++)); rfield@2158: } rfield@2158: rfield@2158: /** rfield@2158: * For a serializable lambda, generate a method name which maximizes rfield@2158: * name stability across deserialization. rfield@2158: * rfield@2158: * @return Name to use for the synthetic lambda method name rfield@2158: */ rfield@2158: private Name serializedLambdaName() { rfield@2158: StringBuilder buf = new StringBuilder(); rfield@2158: buf.append(names.lambda); rfield@2158: // Append the name of the method enclosing the lambda. rfield@2158: buf.append(enclosingMethodName()); rfield@2158: buf.append('$'); rfield@2158: // Append a hash of the disambiguating string : enclosing method rfield@2158: // signature, etc. rfield@2158: String disam = serializedLambdaDisambiguation(); rfield@2158: buf.append(Integer.toHexString(disam.hashCode())); rfield@2158: buf.append('$'); rfield@2158: // The above appended name components may not be unique, append rfield@2158: // a count based on the above name components. rfield@2158: buf.append(syntheticMethodNameCounts.getIndex(buf)); rfield@2158: String result = buf.toString(); rfield@2158: //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam); rfield@2158: return names.fromString(result); rfield@2158: } rfield@2158: rfield@1380: /** rfield@1380: * Translate a symbol of a given kind into something suitable for the rfield@1380: * synthetic lambda body rfield@1380: */ jlahoda@2734: Symbol translate(final Symbol sym, LambdaSymbolKind skind) { jjg@1755: Symbol ret; rfield@1587: switch (skind) { rfield@1587: case CAPTURED_THIS: jjg@1755: ret = sym; // self represented jjg@1755: break; rfield@1587: case TYPE_VAR: rfield@1587: // Just erase the type var jlahoda@2734: ret = new VarSymbol(sym.flags(), sym.name, mcimadamore@1595: types.erasure(sym.type), sym.owner); vromero@2027: vromero@2027: /* this information should also be kept for LVT generation at Gen vromero@2027: * a Symbol with pos < startPos won't be tracked. vromero@2027: */ vromero@2027: ((VarSymbol)ret).pos = ((VarSymbol)sym).pos; jjg@1755: break; mcimadamore@1612: case CAPTURED_VAR: jlahoda@2734: ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, sym.name, types.erasure(sym.type), translatedSym) { mcimadamore@1612: @Override mcimadamore@1612: public Symbol baseSymbol() { mcimadamore@1612: //keep mapping with original captured symbol mcimadamore@1612: return sym; mcimadamore@1612: } mcimadamore@1612: }; jjg@1755: break; jjg@2146: case LOCAL_VAR: jlahoda@2734: ret = new VarSymbol(sym.flags() & FINAL, sym.name, sym.type, translatedSym); jjg@2146: ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; jjg@2146: break; jjg@2146: case PARAM: jlahoda@2734: ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, sym.name, types.erasure(sym.type), translatedSym); jjg@2146: ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; jjg@2146: break; rfield@1587: default: jlahoda@2734: Assert.error(skind.name()); jlahoda@2734: throw new AssertionError(); rfield@1380: } jjg@1755: if (ret != sym) { jjg@1802: ret.setDeclarationAttributes(sym.getRawAttributes()); jjg@1802: ret.setTypeAttributes(sym.getRawTypeAttributes()); jjg@1755: } jjg@1755: return ret; rfield@1380: } rfield@1380: rfield@1380: void addSymbol(Symbol sym, LambdaSymbolKind skind) { ksrini@2155: Map transMap = getSymbolMap(skind); rfield@1380: if (!transMap.containsKey(sym)) { jlahoda@2734: transMap.put(sym, translate(sym, skind)); rfield@1380: } rfield@1380: } rfield@1380: ksrini@2155: Map getSymbolMap(LambdaSymbolKind skind) { ksrini@2155: Map m = translatedSymbols.get(skind); ksrini@2155: Assert.checkNonNull(m); ksrini@2155: return m; ksrini@2155: } ksrini@2155: ksrini@2155: JCTree translate(JCIdent lambdaIdent) { ksrini@2155: for (Map m : translatedSymbols.values()) { ksrini@2155: if (m.containsKey(lambdaIdent.sym)) { ksrini@2155: Symbol tSym = m.get(lambdaIdent.sym); ksrini@2155: JCTree t = make.Ident(tSym).setType(lambdaIdent.type); ksrini@2155: tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes()); ksrini@2155: return t; rfield@1380: } rfield@1380: } ksrini@2155: return null; rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * The translatedSym is not complete/accurate until the analysis is rfield@1380: * finished. Once the analysis is finished, the translatedSym is rfield@1380: * "completed" -- updated with type information, access modifiers, rfield@1380: * and full parameter list. rfield@1380: */ rfield@1380: void complete() { rfield@1380: if (syntheticParams != null) { rfield@1380: return; rfield@1380: } rfield@1380: boolean inInterface = translatedSym.owner.isInterface(); rfield@1380: boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty(); rfield@1380: rfield@1752: // If instance access isn't needed, make it static. rfield@1752: // Interface instance methods must be default methods. rfield@2107: // Lambda methods are private synthetic. rfield@2528: // Inherit ACC_STRICT from the enclosing method, or, for clinit, rfield@2528: // from the class. jjg@2146: translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD | rfield@2528: owner.flags_field & STRICTFP | rfield@2528: owner.owner.flags_field & STRICTFP | rfield@2107: PRIVATE | rfield@1752: (thisReferenced? (inInterface? DEFAULT : 0) : STATIC); rfield@1380: rfield@1380: //compute synthetic params alundblad@2047: ListBuffer params = new ListBuffer<>(); jlahoda@2733: ListBuffer parameterSymbols = new ListBuffer<>(); rfield@1380: rfield@1380: // The signature of the method is augmented with the following rfield@1380: // synthetic parameters: rfield@1380: // rfield@1380: // 1) reference to enclosing contexts captured by the lambda expression rfield@1380: // 2) enclosing locals captured by the lambda expression ksrini@2155: for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) { rfield@1380: params.append(make.VarDef((VarSymbol) thisSym, null)); jlahoda@2733: parameterSymbols.append((VarSymbol) thisSym); rfield@2607: } ksrini@2155: for (Symbol thisSym : getSymbolMap(PARAM).values()) { ksrini@2155: params.append(make.VarDef((VarSymbol) thisSym, null)); jlahoda@2733: parameterSymbols.append((VarSymbol) thisSym); ksrini@2155: } rfield@1380: syntheticParams = params.toList(); rfield@1380: jlahoda@2733: translatedSym.params = parameterSymbols.toList(); jlahoda@2733: rfield@2158: // Compute and set the lambda name rfield@2158: translatedSym.name = isSerializable() rfield@2158: ? serializedLambdaName() rfield@2158: : lambdaName(); rfield@2158: rfield@1380: //prepend synthetic args to translated lambda method signature rfield@1587: translatedSym.type = types.createMethodTypeWithParameters( rfield@1587: generatedLambdaSig(), rfield@1380: TreeInfo.types(syntheticParams)); rfield@1380: } rfield@1380: rfield@1380: Type generatedLambdaSig() { mcimadamore@1882: return types.erasure(tree.getDescriptorType(types)); rfield@1380: } rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * This class retains all the useful information about a method reference; rfield@1380: * the contents of this class are filled by the LambdaAnalyzer visitor, rfield@1380: * and the used by the main translation routines in order to adjust method rfield@1380: * references (i.e. in case a bridge is needed) rfield@1380: */ rfield@2607: private final class ReferenceTranslationContext extends TranslationContext { rfield@1380: rfield@1380: final boolean isSuper; rfield@2202: final Symbol sigPolySym; rfield@1380: rfield@1380: ReferenceTranslationContext(JCMemberReference tree) { rfield@1380: super(tree); rfield@1380: this.isSuper = tree.hasKind(ReferenceKind.SUPER); rfield@2202: this.sigPolySym = isSignaturePolymorphic() rfield@2202: ? makePrivateSyntheticMethod(tree.sym.flags(), rfield@2202: tree.sym.name, rfield@2202: bridgedRefSig(), rfield@2202: tree.sym.enclClass()) rfield@2202: : null; rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * Get the opcode associated with this method reference rfield@1380: */ rfield@1380: int referenceKind() { rfield@2607: return LambdaToMethod.this.referenceKind(tree.sym); rfield@1380: } rfield@1380: rfield@1380: boolean needsVarArgsConversion() { rfield@1380: return tree.varargsElement != null; rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * @return Is this an array operation like clone() rfield@1380: */ rfield@1380: boolean isArrayOp() { rfield@1380: return tree.sym.owner == syms.arrayClass; rfield@1380: } rfield@1380: mcimadamore@1615: boolean receiverAccessible() { mcimadamore@1615: //hack needed to workaround 292 bug (7087658) mcimadamore@1615: //when 292 issue is fixed we should remove this and change the backend mcimadamore@1615: //code to always generate a method handle to an accessible method mcimadamore@1615: return tree.ownerAccessible; mcimadamore@1615: } mcimadamore@1615: rfield@1380: /** rfield@2162: * The VM does not support access across nested classes (8010319). rfield@2162: * Were that ever to change, this should be removed. rfield@2162: */ rfield@2162: boolean isPrivateInOtherClass() { rfield@2162: return (tree.sym.flags() & PRIVATE) != 0 && rfield@2162: !types.isSameType( rfield@2162: types.erasure(tree.sym.enclClass().asType()), rfield@2162: types.erasure(owner.enclClass().asType())); rfield@2162: } rfield@2162: rfield@2162: /** rfield@2202: * Signature polymorphic methods need special handling. rfield@2202: * e.g. MethodHandle.invoke() MethodHandle.invokeExact() rfield@2202: */ rfield@2202: final boolean isSignaturePolymorphic() { rfield@2202: return tree.sym.kind == MTH && rfield@2202: types.isSignaturePolymorphic((MethodSymbol)tree.sym); rfield@2202: } rfield@2202: rfield@2202: /** rfield@2614: * Erasure destroys the implementation parameter subtype rfield@2614: * relationship for intersection types rfield@2614: */ rfield@2614: boolean interfaceParameterIsIntersectionType() { rfield@2614: List tl = tree.getDescriptorType(types).getParameterTypes(); rfield@2614: if (tree.kind == ReferenceKind.UNBOUND) { rfield@2614: tl = tl.tail; rfield@2614: } rfield@2614: for (; tl.nonEmpty(); tl = tl.tail) { rfield@2614: Type pt = tl.head; rfield@2614: if (pt.getKind() == TypeKind.TYPEVAR) { rfield@2614: TypeVar tv = (TypeVar) pt; rfield@2614: if (tv.bound.getKind() == TypeKind.INTERSECTION) { rfield@2614: return true; rfield@2614: } rfield@2614: } rfield@2614: } rfield@2614: return false; rfield@2614: } rfield@2614: rfield@2614: /** rfield@2607: * Does this reference need to be converted to a lambda rfield@2607: * (i.e. var args need to be expanded or "super" is used) rfield@1380: */ rfield@2607: final boolean needsConversionToLambda() { rfield@2614: return interfaceParameterIsIntersectionType() || rfield@2614: isSuper || rfield@2614: needsVarArgsConversion() || rfield@2614: isArrayOp() || rfield@2162: isPrivateInOtherClass() || rfield@2607: !receiverAccessible() || rfield@2607: (tree.getMode() == ReferenceMode.NEW && rfield@2607: tree.kind != ReferenceKind.ARRAY_CTOR && rfield@2607: (tree.sym.owner.isLocal() || tree.sym.owner.isInner())); rfield@1380: } rfield@1380: rfield@1380: Type generatedRefSig() { rfield@1380: return types.erasure(tree.sym.type); rfield@1380: } rfield@1380: rfield@1380: Type bridgedRefSig() { mcimadamore@1882: return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type); rfield@1380: } rfield@1380: } rfield@1380: } rfield@1380: // rfield@1380: ksrini@2155: /* ksrini@2155: * These keys provide mappings for various translated lambda symbols ksrini@2155: * and the prevailing order must be maintained. ksrini@2155: */ rfield@1380: enum LambdaSymbolKind { ksrini@2155: PARAM, // original to translated lambda parameters ksrini@2155: LOCAL_VAR, // original to translated lambda locals ksrini@2155: CAPTURED_VAR, // variables in enclosing scope to translated synthetic parameters ksrini@2155: CAPTURED_THIS, // class symbols to translated synthetic parameters (for captured member access) ksrini@2155: TYPE_VAR; // original to translated lambda type variables rfield@1587: } rfield@1587: rfield@1587: /** rfield@1587: * **************************************************************** rfield@1587: * Signature Generation rfield@1587: * **************************************************************** rfield@1587: */ rfield@1587: rfield@2158: private String typeSig(Type type) { rfield@1587: L2MSignatureGenerator sg = new L2MSignatureGenerator(); rfield@1587: sg.assembleSig(type); rfield@1587: return sg.toString(); rfield@1587: } rfield@1587: rfield@1587: private String classSig(Type type) { rfield@1587: L2MSignatureGenerator sg = new L2MSignatureGenerator(); rfield@1587: sg.assembleClassSig(type); rfield@1587: return sg.toString(); rfield@1587: } rfield@1587: rfield@1587: /** rfield@1587: * Signature Generation rfield@1587: */ rfield@1587: private class L2MSignatureGenerator extends Types.SignatureGenerator { rfield@1587: rfield@1587: /** rfield@1587: * An output buffer for type signatures. rfield@1587: */ rfield@1587: StringBuilder sb = new StringBuilder(); rfield@1587: rfield@1587: L2MSignatureGenerator() { rfield@1587: super(types); rfield@1587: } rfield@1587: rfield@1587: @Override rfield@1587: protected void append(char ch) { rfield@1587: sb.append(ch); rfield@1587: } rfield@1587: rfield@1587: @Override rfield@1587: protected void append(byte[] ba) { rfield@1587: sb.append(new String(ba)); rfield@1587: } rfield@1587: rfield@1587: @Override rfield@1587: protected void append(Name name) { rfield@1587: sb.append(name.toString()); rfield@1587: } rfield@1587: rfield@1587: @Override rfield@1587: public String toString() { rfield@1587: return sb.toString(); rfield@1587: } rfield@1380: } rfield@1380: }