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

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