rfield@1380: /* mcimadamore@1595: * Copyright (c) 2010, 2013, 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@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@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@1380: import java.util.LinkedHashMap; rfield@1380: import java.util.Map; 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@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: 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@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; rfield@1380: MethodSymbol sym = (MethodSymbol)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@1380: 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@2202: Symbol refSym = localContext.needsBridge() rfield@2202: ? localContext.bridgeSym rfield@2202: : localContext.isSignaturePolymorphic() rfield@2202: ? localContext.sigPolySym rfield@2202: : tree.sym; rfield@1380: rfield@1380: //build the bridge method, if needed rfield@1380: if (localContext.needsBridge()) { rfield@1380: bridgeMemberReference(tree, localContext); rfield@1380: } 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@1380: JCExpression init = translate(tree.init); jlahoda@2165: int prevPos = make.pos; jlahoda@2165: try { jlahoda@2165: result = make.at(tree).VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init); jlahoda@2165: } finally { jlahoda@2165: make.at(prevPos); jlahoda@2165: } 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@1380: * Generate an adapter method "bridge" for a method reference which cannot rfield@1380: * be used directly. rfield@1380: */ rfield@1380: private class MemberReferenceBridger { rfield@1380: rfield@1380: private final JCMemberReference tree; rfield@1380: private final ReferenceTranslationContext localContext; alundblad@2047: private final ListBuffer args = new ListBuffer<>(); alundblad@2047: private final ListBuffer params = new ListBuffer<>(); rfield@1380: rfield@1380: MemberReferenceBridger(JCMemberReference tree, ReferenceTranslationContext localContext) { rfield@1380: this.tree = tree; rfield@1380: this.localContext = localContext; rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * Generate the bridge rfield@1380: */ rfield@1380: JCMethodDecl bridge() { rfield@1380: int prevPos = make.pos; rfield@1380: try { rfield@1380: make.at(tree); rfield@1380: Type samDesc = localContext.bridgedRefSig(); rfield@1380: List samPTypes = samDesc.getParameterTypes(); rfield@1380: rfield@1380: //an extra argument is prepended to the signature of the bridge in case rfield@1380: //the member reference is an instance method reference (in which case rfield@1380: //the receiver expression is passed to the bridge itself). rfield@1380: Type recType = null; rfield@1380: switch (tree.kind) { rfield@1380: case IMPLICIT_INNER: rfield@1380: recType = tree.sym.owner.type.getEnclosingType(); rfield@1380: break; rfield@1380: case BOUND: rfield@1380: recType = tree.getQualifierExpression().type; rfield@1380: break; rfield@1380: case UNBOUND: rfield@1380: recType = samPTypes.head; rfield@1380: samPTypes = samPTypes.tail; rfield@1380: break; rfield@1380: } rfield@1380: rfield@1380: //generate the parameter list for the bridged member reference - the rfield@1380: //bridge signature will match the signature of the target sam descriptor rfield@1380: rfield@1380: VarSymbol rcvr = (recType == null) rfield@1380: ? null rfield@1380: : addParameter("rec$", recType, false); rfield@1380: rfield@1380: List refPTypes = tree.sym.type.getParameterTypes(); rfield@1380: int refSize = refPTypes.size(); rfield@1380: int samSize = samPTypes.size(); mcimadamore@1595: // Last parameter to copy from referenced method mcimadamore@1595: int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize; rfield@1380: rfield@1380: List l = refPTypes; rfield@1380: // Use parameter types of the referenced method, excluding final var args rfield@1380: for (int i = 0; l.nonEmpty() && i < last; ++i) { rfield@1380: addParameter("x$" + i, l.head, true); rfield@1380: l = l.tail; rfield@1380: } rfield@1380: // Flatten out the var args rfield@1380: for (int i = last; i < samSize; ++i) { rfield@1380: addParameter("xva$" + i, tree.varargsElement, true); rfield@1380: } rfield@1380: rfield@1380: //generate the bridge method declaration rfield@1380: JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(localContext.bridgeSym.flags()), rfield@1380: localContext.bridgeSym.name, rfield@1380: make.QualIdent(samDesc.getReturnType().tsym), rfield@1380: List.nil(), rfield@1380: params.toList(), rfield@1380: tree.sym.type.getThrownTypes() == null rfield@1380: ? List.nil() rfield@1380: : make.Types(tree.sym.type.getThrownTypes()), rfield@1380: null, rfield@1380: null); rfield@1380: bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym; mcimadamore@1595: bridgeDecl.type = localContext.bridgeSym.type = mcimadamore@1595: types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList())); rfield@1380: rfield@1380: //bridge method body generation - this can be either a method call or a rfield@1380: //new instance creation expression, depending on the member reference kind rfield@1380: JCExpression bridgeExpr = (tree.getMode() == ReferenceMode.INVOKE) mcimadamore@1614: ? bridgeExpressionInvoke(makeReceiver(rcvr)) rfield@1380: : bridgeExpressionNew(); rfield@1380: rfield@1380: //the body is either a return expression containing a method call, rfield@1380: //or the method call itself, depending on whether the return type of rfield@1380: //the bridge is non-void/void. rfield@1380: bridgeDecl.body = makeLambdaExpressionBody(bridgeExpr, bridgeDecl); rfield@1380: rfield@1380: return bridgeDecl; rfield@1380: } finally { rfield@1380: make.at(prevPos); rfield@1380: } rfield@1380: } mcimadamore@1614: //where mcimadamore@1614: private JCExpression makeReceiver(VarSymbol rcvr) { mcimadamore@1614: if (rcvr == null) return null; mcimadamore@1614: JCExpression rcvrExpr = make.Ident(rcvr); mcimadamore@1614: Type rcvrType = tree.sym.enclClass().type; mcimadamore@1614: if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) { mcimadamore@1614: rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType); mcimadamore@1614: } mcimadamore@1614: return rcvrExpr; mcimadamore@1614: } rfield@1380: rfield@1380: /** rfield@1380: * determine the receiver of the bridged method call - the receiver can rfield@1380: * be either the synthetic receiver parameter or a type qualifier; the rfield@1380: * original qualifier expression is never used here, as it might refer rfield@1380: * to symbols not available in the static context of the bridge rfield@1380: */ mcimadamore@1614: private JCExpression bridgeExpressionInvoke(JCExpression rcvr) { rfield@1380: JCExpression qualifier = rfield@1380: tree.sym.isStatic() ? rfield@1380: make.Type(tree.sym.owner.type) : rfield@1380: (rcvr != null) ? mcimadamore@1614: rcvr : rfield@1380: 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@1380: * the enclosing expression is either 'null' (no enclosing type) or set rfield@1380: * to the first bridge synthetic parameter rfield@1380: */ rfield@1380: private JCExpression bridgeExpressionNew() { 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: JCExpression encl = null; mcimadamore@1496: switch (tree.kind) { mcimadamore@1496: case UNBOUND: mcimadamore@1496: case IMPLICIT_INNER: mcimadamore@1496: encl = make.Ident(params.first()); mcimadamore@1496: } mcimadamore@1496: mcimadamore@1496: //create the instance creation expression mcimadamore@1496: JCNewClass newClass = make.NewClass(encl, 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@1380: VarSymbol vsym = new VarSymbol(0, names.fromString(name), p, localContext.bridgeSym); 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: rfield@1380: /** rfield@1380: * Bridges a member reference - this is needed when: rfield@1380: * * Var args in the referenced method need to be flattened away rfield@1380: * * super is used rfield@1380: */ rfield@1380: private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) { rfield@1587: kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge()); 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; 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); 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; 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@1380: List prevStack = frameStack; rfield@1380: try { rfield@1380: LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree); 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@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@1380: if (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: } mcimadamore@1612: if (context() != null && tree.type.tsym.owner.kind == MTH) { mcimadamore@1612: LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context(); mcimadamore@1612: captureLocalClassDefs(tree.type.tsym, 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); mcimadamore@1612: if (localCDef != null && localCDef.pos < lambdaContext.tree.pos) { 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@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@1717: * effected method references into a lambda containing a normal "new" of rfield@1717: * the class. rfield@1717: * rfield@1717: * @param tree rfield@1717: */ rfield@1380: @Override rfield@1380: public void visitReference(JCMemberReference tree) { rfield@1717: if (tree.getMode() == ReferenceMode.NEW rfield@1717: && tree.kind != ReferenceKind.ARRAY_CTOR rfield@1717: && tree.sym.owner.isLocal()) { rfield@1717: MethodSymbol consSym = (MethodSymbol) tree.sym; rfield@1717: List ptypes = ((MethodType) consSym.type).getParameterTypes(); rfield@1717: Type classType = consSym.owner.type; rfield@1717: rfield@1727: // Build lambda parameters rfield@1727: // partially cloned from TreeMaker.Params until 8014021 is fixed rfield@1727: Symbol owner = owner(); rfield@1727: ListBuffer paramBuff = new ListBuffer(); rfield@1727: int i = 0; rfield@1727: for (List l = ptypes; l.nonEmpty(); l = l.tail) { jjg@2146: JCVariableDecl param = make.Param(make.paramName(i++), l.head, owner); jjg@2146: param.sym.pos = tree.pos; jjg@2146: paramBuff.append(param); rfield@1727: } rfield@1727: List params = paramBuff.toList(); rfield@1727: rfield@1717: // Make new-class call rfield@1717: JCNewClass nc = makeNewClass(classType, make.Idents(params)); rfield@1717: nc.pos = tree.pos; rfield@1717: rfield@1717: // Make lambda holding the new-class call rfield@1717: JCLambda slam = make.Lambda(params, nc); rfield@1717: slam.targets = tree.targets; rfield@1717: slam.type = tree.type; rfield@1717: slam.pos = tree.pos; rfield@1717: rfield@1717: // Now it is a lambda, process as such rfield@1717: visitLambda(slam); rfield@1717: } else { rfield@1717: super.visitReference(tree); rfield@1717: contextMap.put(tree, makeReferenceContext(tree)); 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 TranslationContext makeLambdaContext(JCLambda tree) { rfield@1380: return new LambdaTranslationContext(tree); rfield@1380: } rfield@1380: rfield@1380: private TranslationContext makeReferenceContext(JCMemberReference tree) { rfield@1380: return new ReferenceTranslationContext(tree); 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() { 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 */ rfield@1380: Symbol translatedSym; rfield@1380: rfield@1380: List syntheticParams; rfield@1380: 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: mcimadamore@1817: if (dumpLambdaToMethodStats) { mcimadamore@1817: log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym); mcimadamore@1817: } 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@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: */ mcimadamore@1652: Symbol translate(Name name, 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 jjg@1755: ret = new VarSymbol(sym.flags(), 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: jjg@2146: ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, 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: jjg@2146: ret = new VarSymbol(FINAL, name, types.erasure(sym.type), translatedSym); jjg@2146: ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; jjg@2146: break; jjg@2146: case PARAM: jjg@2146: ret = new VarSymbol(FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym); jjg@2146: ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; jjg@2146: break; rfield@1587: default: jjg@1755: ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym); jjg@2146: ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; 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); mcimadamore@1652: Name preferredName; rfield@1380: switch (skind) { rfield@1380: case CAPTURED_THIS: ksrini@2155: preferredName = names.fromString("encl$" + transMap.size()); rfield@1380: break; rfield@1380: case CAPTURED_VAR: ksrini@2155: preferredName = names.fromString("cap$" + transMap.size()); rfield@1380: break; rfield@1380: case LOCAL_VAR: mcimadamore@1652: preferredName = sym.name; rfield@1380: break; rfield@1380: case PARAM: mcimadamore@1652: preferredName = sym.name; rfield@1380: break; rfield@1587: case TYPE_VAR: mcimadamore@1652: preferredName = sym.name; rfield@1587: break; rfield@1380: default: throw new AssertionError(); rfield@1380: } rfield@1380: if (!transMap.containsKey(sym)) { rfield@1380: transMap.put(sym, translate(preferredName, 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. jjg@2146: translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD | rfield@2107: PRIVATE | rfield@1752: (thisReferenced? (inInterface? DEFAULT : 0) : STATIC); rfield@1380: rfield@1380: //compute synthetic params alundblad@2047: ListBuffer params = 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)); rfield@1380: } ksrini@2155: for (Symbol thisSym : getSymbolMap(PARAM).values()) { ksrini@2155: params.append(make.VarDef((VarSymbol) thisSym, null)); ksrini@2155: } rfield@1380: syntheticParams = params.toList(); rfield@1380: 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@1380: private class ReferenceTranslationContext extends TranslationContext { rfield@1380: rfield@1380: final boolean isSuper; rfield@1380: final Symbol bridgeSym; 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@1380: this.bridgeSym = needsBridge() rfield@2107: ? makePrivateSyntheticMethod(isSuper ? 0 : STATIC, rfield@2158: referenceBridgeName(), null, rfield@1380: owner.enclClass()) rfield@1380: : null; 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; mcimadamore@1817: if (dumpLambdaToMethodStats) { mcimadamore@1817: String key = bridgeSym == null ? mcimadamore@1817: "mref.stat" : "mref.stat.1"; mcimadamore@1817: log.note(tree, key, needsAltMetafactory(), bridgeSym); mcimadamore@1817: } rfield@1380: } rfield@1380: rfield@1380: /** rfield@1380: * Get the opcode associated with this method reference rfield@1380: */ rfield@1380: int referenceKind() { rfield@2158: return LambdaToMethod.this.referenceKind(needsBridge() rfield@2158: ? bridgeSym rfield@2158: : tree.sym); rfield@1380: } rfield@1380: rfield@1380: boolean needsVarArgsConversion() { rfield@1380: return tree.varargsElement != null; rfield@1380: } rfield@1380: rfield@1380: /** rfield@2158: * Generate a disambiguating string to increase stability (important rfield@2158: * if serialized) rfield@2158: * rfield@2158: * @return String to differentiate synthetic lambda method names rfield@2158: */ rfield@2158: private String referenceBridgeDisambiguation() { rfield@2158: StringBuilder buf = new StringBuilder(); rfield@2158: // Append the enclosing method signature to differentiate rfield@2158: // overloaded enclosing methods. rfield@2158: if (owner.type != null) { rfield@2158: buf.append(typeSig(owner.type)); rfield@2158: buf.append(":"); rfield@2158: } rfield@2158: rfield@2158: // Append qualifier type rfield@2158: buf.append(classSig(tree.sym.owner.type)); rfield@2158: rfield@2158: // Note static/instance rfield@2158: buf.append(tree.sym.isStatic()? " S " : " I "); rfield@2158: rfield@2158: // Append referenced signature rfield@2158: buf.append(typeSig(tree.sym.erasure(types))); rfield@2158: rfield@2158: return buf.toString(); rfield@2158: } rfield@2158: rfield@2158: /** rfield@2158: * Construct a unique stable name for the method reference bridge rfield@2158: * rfield@2158: * @return Name to use for the synthetic method name rfield@2158: */ rfield@2158: private Name referenceBridgeName() { rfield@2158: StringBuilder buf = new StringBuilder(); rfield@2158: // Append lambda ID, this is semantically significant rfield@2158: buf.append(names.lambda); rfield@2158: // Note that it is a method reference bridge rfield@2158: buf.append("MR$"); rfield@2158: // Append the enclosing method name rfield@2158: buf.append(enclosingMethodName()); rfield@2158: buf.append('$'); rfield@2158: // Append the referenced method name rfield@2158: buf.append(syntheticMethodNameComponent(tree.sym.name)); rfield@2158: buf.append('$'); rfield@2158: // Append a hash of the disambiguating string : enclosing method rfield@2158: // signature, etc. rfield@2158: String disam = referenceBridgeDisambiguation(); 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: return names.fromString(result); rfield@2158: } rfield@2158: rfield@2158: /** 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@1380: * Does this reference needs a bridge (i.e. var args need to be rfield@1380: * expanded or "super" is used) rfield@1380: */ rfield@1380: final boolean needsBridge() { mcimadamore@1615: return isSuper || needsVarArgsConversion() || isArrayOp() || rfield@2162: isPrivateInOtherClass() || rfield@2162: !receiverAccessible(); 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: }