LambdaToMethod.java revision 2787:441711fd360d
137535Sdes/* 263012Sdes * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 337535Sdes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 437535Sdes * 537535Sdes * This code is free software; you can redistribute it and/or modify it 637535Sdes * under the terms of the GNU General Public License version 2 only, as 737535Sdes * published by the Free Software Foundation. Oracle designates this 837535Sdes * particular file as subject to the "Classpath" exception as provided 937535Sdes * by Oracle in the LICENSE file that accompanied this code. 1037535Sdes * 1137535Sdes * This code is distributed in the hope that it will be useful, but WITHOUT 1237535Sdes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1337535Sdes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1437535Sdes * version 2 for more details (a copy is included in the LICENSE file that 1563012Sdes * accompanied this code). 1637535Sdes * 1737535Sdes * You should have received a copy of the GNU General Public License version 1837535Sdes * 2 along with this work; if not, write to the Free Software Foundation, 1937535Sdes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2037535Sdes * 2137535Sdes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2237535Sdes * or visit www.oracle.com if you need additional information or have any 2337535Sdes * questions. 2437535Sdes */ 2537535Sdespackage com.sun.tools.javac.comp; 2637535Sdes 2737535Sdesimport com.sun.tools.javac.tree.*; 2837535Sdesimport com.sun.tools.javac.tree.JCTree.*; 2984203Sdillonimport com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; 3084203Sdillonimport com.sun.tools.javac.tree.TreeMaker; 3184203Sdillonimport com.sun.tools.javac.tree.TreeTranslator; 3263236Sdesimport com.sun.tools.javac.code.Attribute; 3363236Sdesimport com.sun.tools.javac.code.Scope.WriteableScope; 3463236Sdesimport com.sun.tools.javac.code.Symbol; 3563236Sdesimport com.sun.tools.javac.code.Symbol.ClassSymbol; 3663236Sdesimport com.sun.tools.javac.code.Symbol.DynamicMethodSymbol; 3763236Sdesimport com.sun.tools.javac.code.Symbol.MethodSymbol; 3863236Sdesimport com.sun.tools.javac.code.Symbol.TypeSymbol; 3963236Sdesimport com.sun.tools.javac.code.Symbol.VarSymbol; 4063236Sdesimport com.sun.tools.javac.code.Symtab; 4163236Sdesimport com.sun.tools.javac.code.Type; 4263236Sdesimport com.sun.tools.javac.code.Type.MethodType; 4363236Sdesimport com.sun.tools.javac.code.Type.TypeVar; 4463236Sdesimport com.sun.tools.javac.code.Types; 4563236Sdesimport com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*; 4663236Sdesimport com.sun.tools.javac.comp.Lower.BasicFreeVarCollector; 4763236Sdesimport com.sun.tools.javac.jvm.*; 4863236Sdesimport com.sun.tools.javac.util.*; 4990267Sdesimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 5063236Sdesimport com.sun.source.tree.MemberReferenceTree.ReferenceMode; 5163236Sdes 5263236Sdesimport java.util.EnumMap; 5363236Sdesimport java.util.HashMap; 5463236Sdesimport java.util.HashSet; 5563236Sdesimport java.util.LinkedHashMap; 5663236Sdesimport java.util.Map; 5763236Sdesimport java.util.Set; 5863236Sdes 5963236Sdesimport static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*; 6063236Sdesimport static com.sun.tools.javac.code.Flags.*; 6163236Sdesimport static com.sun.tools.javac.code.Kinds.Kind.*; 6263236Sdesimport static com.sun.tools.javac.code.TypeTag.*; 6363236Sdesimport static com.sun.tools.javac.tree.JCTree.Tag.*; 6437535Sdesimport javax.lang.model.type.TypeKind; 6560737Sume 6637535Sdes/** 6763012Sdes * This pass desugars lambda expressions into static methods 6837535Sdes * 6963012Sdes * <p><b>This is NOT part of any supported API. 7060376Sdes * If you write code that depends on this, you do so at your own risk. 7160189Sdes * This code and its internal interfaces are subject to change or 7237608Sdes * deletion without notice.</b> 7337535Sdes */ 7437535Sdespublic class LambdaToMethod extends TreeTranslator { 7537535Sdes 7660376Sdes private Attr attr; 7737535Sdes private JCDiagnostic.Factory diags; 7837535Sdes private Log log; 7937535Sdes private Lower lower; 8040939Sdes private Names names; 8141862Sdes private Symtab syms; 8237535Sdes private Resolve rs; 8363012Sdes private TreeMaker make; 8463012Sdes private Types types; 8537535Sdes private TransTypes transTypes; 8663012Sdes private Env<AttrContext> attrEnv; 8763012Sdes 8863012Sdes /** the analyzer scanner */ 8963012Sdes private LambdaAnalyzerPreprocessor analyzer; 9063012Sdes 9163012Sdes /** map from lambda trees to translation contexts */ 9263012Sdes private Map<JCTree, TranslationContext<?>> contextMap; 9387317Sdes 9463012Sdes /** current translation context (visitor argument) */ 9560196Sdes private TranslationContext<?> context; 9663012Sdes 9790267Sdes /** info about the current class being processed */ 9890267Sdes private KlassInfo kInfo; 9963012Sdes 10088771Sdes /** dump statistics about lambda code generation */ 10163012Sdes private boolean dumpLambdaToMethodStats; 10290267Sdes 10363012Sdes /** force serializable representation, for stress testing **/ 10463012Sdes private final boolean forceSerializable; 10563012Sdes 10663012Sdes /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */ 10797859Sdes public static final int FLAG_SERIALIZABLE = 1 << 0; 10837535Sdes 10997858Sdes /** Flag for alternate metafactories indicating the lambda object has multiple targets */ 11097866Sdes public static final int FLAG_MARKERS = 1 << 1; 11197858Sdes 11297866Sdes /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */ 11397866Sdes public static final int FLAG_BRIDGES = 1 << 2; 11497866Sdes 11597858Sdes // <editor-fold defaultstate="collapsed" desc="Instantiating"> 11697858Sdes protected static final Context.Key<LambdaToMethod> unlambdaKey = new Context.Key<>(); 11797858Sdes 11863281Sdes public static LambdaToMethod instance(Context context) { 11990267Sdes LambdaToMethod instance = context.get(unlambdaKey); 12063012Sdes if (instance == null) { 12137535Sdes instance = new LambdaToMethod(context); 12237535Sdes } 12337608Sdes return instance; 12463012Sdes } 12537608Sdes private LambdaToMethod(Context context) { 12637608Sdes context.put(unlambdaKey, this); 12797859Sdes diags = JCDiagnostic.Factory.instance(context); 12837608Sdes log = Log.instance(context); 12990267Sdes lower = Lower.instance(context); 13090267Sdes names = Names.instance(context); 13197859Sdes syms = Symtab.instance(context); 13290267Sdes rs = Resolve.instance(context); 13390267Sdes make = TreeMaker.instance(context); 13497859Sdes types = Types.instance(context); 13590267Sdes transTypes = TransTypes.instance(context); 13690267Sdes analyzer = new LambdaAnalyzerPreprocessor(); 13797859Sdes Options options = Options.instance(context); 13890267Sdes dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats"); 13990267Sdes attr = Attr.instance(context); 14090267Sdes forceSerializable = options.isSet("forceSerializable"); 14190267Sdes } 14290267Sdes // </editor-fold> 14397859Sdes 14490267Sdes private class KlassInfo { 14590267Sdes 14697859Sdes /** 14790267Sdes * list of methods to append 14890267Sdes */ 14990267Sdes private ListBuffer<JCTree> appendedMethodList; 15090267Sdes 15163281Sdes /** 15290267Sdes * list of deserialization cases 15397859Sdes */ 15497859Sdes private final Map<String, ListBuffer<JCStatement>> deserializeCases; 155106207Sdes 15690267Sdes /** 157106207Sdes * deserialize method symbol 158106207Sdes */ 159106207Sdes private final MethodSymbol deserMethodSym; 16090267Sdes 16163012Sdes /** 16290267Sdes * deserialize method parameter symbol 16397859Sdes */ 16437608Sdes private final VarSymbol deserParamSym; 16537608Sdes 16637608Sdes private final JCClassDecl clazz; 16797866Sdes 16897866Sdes private KlassInfo(JCClassDecl clazz) { 16997866Sdes this.clazz = clazz; 17097866Sdes appendedMethodList = new ListBuffer<>(); 17197866Sdes deserializeCases = new HashMap<>(); 17297866Sdes MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType, 17397866Sdes List.<Type>nil(), syms.methodClass); 17497866Sdes deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym); 17597866Sdes deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"), 17697866Sdes syms.serializedLambdaType, deserMethodSym); 17797866Sdes } 17897866Sdes 17997866Sdes private void addMethod(JCTree decl) { 18097866Sdes appendedMethodList = appendedMethodList.prepend(decl); 181106044Sdes } 18297866Sdes } 18397866Sdes 18497866Sdes // <editor-fold defaultstate="collapsed" desc="translate methods"> 18537608Sdes @Override 18637608Sdes public <T extends JCTree> T translate(T tree) { 18763012Sdes TranslationContext<?> newContext = contextMap.get(tree); 18897866Sdes return translate(tree, newContext != null ? newContext : context); 18937535Sdes } 19097859Sdes 19190267Sdes <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) { 19297859Sdes TranslationContext<?> prevContext = context; 19390267Sdes try { 19490267Sdes context = newContext; 19597866Sdes return super.translate(tree); 19697866Sdes } 19797866Sdes finally { 198106185Sdes context = prevContext; 199106185Sdes } 20097866Sdes } 201106185Sdes 20297866Sdes <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) { 20397866Sdes ListBuffer<T> buf = new ListBuffer<>(); 20497866Sdes for (T tree : trees) { 20597866Sdes buf.append(translate(tree, newContext)); 20697859Sdes } 20797859Sdes return buf.toList(); 20890267Sdes } 20997859Sdes 21090267Sdes public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) { 21190267Sdes this.make = make; 21297859Sdes this.attrEnv = env; 21390267Sdes this.context = null; 21490267Sdes this.contextMap = new HashMap<>(); 21537535Sdes return translate(cdef); 21663012Sdes } 21797866Sdes // </editor-fold> 21897866Sdes 21997866Sdes // <editor-fold defaultstate="collapsed" desc="visitor methods"> 22090267Sdes /** 221106185Sdes * Visit a class. 222106185Sdes * Maintain the translatedMethodList across nested classes. 22397866Sdes * Append the translatedMethodList to the class after it is translated. 224106185Sdes * @param tree 22597866Sdes */ 22690267Sdes @Override 22797859Sdes public void visitClassDef(JCClassDecl tree) { 22897856Sdes if (tree.sym.owner.kind == PCK) { 22997856Sdes //analyze class 23097866Sdes tree = analyzer.analyzeAndPreprocessClass(tree); 23197856Sdes } 23290267Sdes KlassInfo prevKlassInfo = kInfo; 23390267Sdes try { 23490267Sdes kInfo = new KlassInfo(tree); 23597866Sdes super.visitClassDef(tree); 23690267Sdes if (!kInfo.deserializeCases.isEmpty()) { 23797866Sdes int prevPos = make.pos; 23837535Sdes try { 23937535Sdes make.at(tree); 24037608Sdes kInfo.addMethod(makeDeserializeMethod(tree.sym)); 24137608Sdes } finally { 24237608Sdes make.at(prevPos); 24337535Sdes } 24463012Sdes } 24537535Sdes //add all translated instance methods here 24697859Sdes List<JCTree> newMethods = kInfo.appendedMethodList.toList(); 24790267Sdes tree.defs = tree.defs.appendList(newMethods); 24863012Sdes for (JCTree lambda : newMethods) { 24997859Sdes tree.sym.members().enter(((JCMethodDecl)lambda).sym); 25090267Sdes } 25197859Sdes result = tree; 25290267Sdes } finally { 25363012Sdes kInfo = prevKlassInfo; 25490267Sdes } 25590267Sdes } 25697866Sdes 25797866Sdes /** 25890267Sdes * Translate a lambda into a method to be inserted into the class. 25997866Sdes * Then replace the lambda site with an invokedynamic call of to lambda 26090267Sdes * meta-factory, which will use the lambda method. 26190267Sdes * @param tree 26297866Sdes */ 26397866Sdes @Override 26490267Sdes public void visitLambda(JCLambda tree) { 26537535Sdes LambdaTranslationContext localContext = (LambdaTranslationContext)context; 26697859Sdes MethodSymbol sym = localContext.translatedSym; 26790267Sdes MethodType lambdaType = (MethodType) sym.type; 26890267Sdes 26937535Sdes { 27037535Sdes Symbol owner = localContext.owner; 27137608Sdes ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<>(); 27237608Sdes ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<>(); 27337608Sdes 27437535Sdes for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) { 27563012Sdes if (tc.position.onLambda == tree) { 27637535Sdes lambdaTypeAnnos.append(tc); 27797859Sdes } else { 27890267Sdes ownerTypeAnnos.append(tc); 27997866Sdes } 28037535Sdes } 28137535Sdes if (lambdaTypeAnnos.nonEmpty()) { 28237608Sdes owner.setTypeAttributes(ownerTypeAnnos.toList()); 28337608Sdes sym.setTypeAttributes(lambdaTypeAnnos.toList()); 28437608Sdes } 28537535Sdes } 28663012Sdes 28737535Sdes //create the method declaration hoisting the lambda body 28897859Sdes JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field), 28990267Sdes sym.name, 29063012Sdes make.QualIdent(lambdaType.getReturnType().tsym), 29197859Sdes List.<JCTypeParameter>nil(), 29297859Sdes localContext.syntheticParams, 29397859Sdes lambdaType.getThrownTypes() == null ? 29497859Sdes List.<JCExpression>nil() : 29590267Sdes make.Types(lambdaType.getThrownTypes()), 29637535Sdes null, 29737535Sdes null); 29837608Sdes lambdaDecl.sym = sym; 29963012Sdes lambdaDecl.type = lambdaType; 30037608Sdes 30163012Sdes //translate lambda body 30297866Sdes //As the lambda body is translated, all references to lambda locals, 30337535Sdes //captured variables, enclosing members are adjusted accordingly 30497859Sdes //to refer to the static method parameters (rather than i.e. acessing to 30590267Sdes //captured members directly). 30663012Sdes lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl)); 30797859Sdes 30890267Sdes //Add the method to the list of methods to be added to this class. 30990267Sdes kInfo.addMethod(lambdaDecl); 31090267Sdes 31197859Sdes //now that we have generated a method for the lambda expression, 31297866Sdes //we can translate the lambda into a method reference pointing to the newly 31397859Sdes //created method. 31490267Sdes // 31590267Sdes //Note that we need to adjust the method handle so that it will match the 31697859Sdes //signature of the SAM descriptor - this means that the method reference 31790267Sdes //should be added the following synthetic arguments: 31890267Sdes // 31990267Sdes // * the "this" argument if it is an instance method 32063012Sdes // * enclosing locals captured by the lambda expression 32163012Sdes 32290267Sdes ListBuffer<JCExpression> syntheticInits = new ListBuffer<>(); 32363012Sdes 32463012Sdes if (localContext.methodReferenceReceiver != null) { 32563012Sdes syntheticInits.append(localContext.methodReferenceReceiver); 32663012Sdes } else if (!sym.isStatic()) { 32763012Sdes syntheticInits.append(makeThis( 32863012Sdes sym.owner.enclClass().asType(), 32990267Sdes localContext.owner.enclClass())); 33090267Sdes } 33190267Sdes 33290267Sdes //add captured locals 33390267Sdes for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) { 33490267Sdes if (fv != localContext.self) { 33590267Sdes JCTree captured_local = make.Ident(fv).setType(fv.type); 33690267Sdes syntheticInits.append((JCExpression) captured_local); 33790267Sdes } 33890267Sdes } 33985093Sdes 34063012Sdes //then, determine the arguments to the indy call 34163012Sdes List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev); 34263012Sdes 34390267Sdes //build a sam instance using an indy call to the meta-factory 34490267Sdes int refKind = referenceKind(sym); 34563012Sdes 34690267Sdes //convert to an invokedynamic call 34790267Sdes result = makeMetafactoryIndyCall(context, refKind, sym, indy_args); 34890267Sdes } 34990267Sdes 35090267Sdes private JCIdent makeThis(Type type, Symbol owner) { 35190267Sdes VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC, 35290267Sdes names._this, 35363012Sdes type, 35463012Sdes owner); 35563012Sdes return make.Ident(_this); 35663012Sdes } 35763012Sdes 35863012Sdes /** 35997856Sdes * Translate a method reference into an invokedynamic call to the 36063012Sdes * meta-factory. 36190267Sdes * @param tree 36290267Sdes */ 36390267Sdes @Override 36490267Sdes public void visitReference(JCMemberReference tree) { 36563012Sdes ReferenceTranslationContext localContext = (ReferenceTranslationContext)context; 36690267Sdes 36790267Sdes //first determine the method symbol to be used to generate the sam instance 36890267Sdes //this is either the method reference symbol, or the bridged reference symbol 36990267Sdes Symbol refSym = localContext.isSignaturePolymorphic() 37090267Sdes ? localContext.sigPolySym 37190267Sdes : tree.sym; 37290267Sdes 37390267Sdes //the qualifying expression is treated as a special captured arg 37490267Sdes JCExpression init; 37590267Sdes switch(tree.kind) { 37697856Sdes 37790267Sdes case IMPLICIT_INNER: /** Inner :: new */ 37890267Sdes case SUPER: /** super :: instMethod */ 37990267Sdes init = makeThis( 38090267Sdes localContext.owner.enclClass().asType(), 38190267Sdes localContext.owner.enclClass()); 38290267Sdes break; 38390267Sdes 38490267Sdes case BOUND: /** Expr :: instMethod */ 38563012Sdes init = tree.getQualifierExpression(); 38663012Sdes init = attr.makeNullCheck(init); 38763012Sdes break; 38863012Sdes 38963012Sdes case UNBOUND: /** Type :: instMethod */ 39063012Sdes case STATIC: /** Type :: staticMethod */ 39197856Sdes case TOPLEVEL: /** Top level :: new */ 39263012Sdes case ARRAY_CTOR: /** ArrayType :: new */ 39390267Sdes init = null; 39490267Sdes break; 39597856Sdes 39690267Sdes default: 39790267Sdes throw new InternalError("Should not have an invalid kind"); 39890267Sdes } 39990267Sdes 40090267Sdes List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev); 40190267Sdes 40290267Sdes 40390267Sdes //build a sam instance using an indy call to the meta-factory 40490267Sdes result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args); 40590267Sdes } 40697856Sdes 40790267Sdes /** 40897856Sdes * Translate identifiers within a lambda to the mapped identifier 40990267Sdes * @param tree 41090267Sdes */ 41190267Sdes @Override 41290267Sdes public void visitIdent(JCIdent tree) { 41390267Sdes if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) { 41490267Sdes super.visitIdent(tree); 41590267Sdes } else { 41690267Sdes int prevPos = make.pos; 41797856Sdes try { 41897856Sdes make.at(tree); 41937535Sdes 42037535Sdes LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context; 42137608Sdes JCTree ltree = lambdaContext.translate(tree); 42290267Sdes if (ltree != null) { 42390267Sdes result = ltree; 42463012Sdes } else { 42575891Sarchie //access to untranslated symbols (i.e. compile-time constants, 42675891Sarchie //members defined inside the lambda body, etc.) ) 42763012Sdes super.visitIdent(tree); 42890267Sdes } 42990267Sdes } finally { 43090267Sdes make.at(prevPos); 43190267Sdes } 43290267Sdes } 43390267Sdes } 43490267Sdes 43563012Sdes @Override 43663012Sdes public void visitVarDef(JCVariableDecl tree) { 43763012Sdes LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context; 43863012Sdes if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) { 43963012Sdes tree.init = translate(tree.init); 44085093Sdes tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym); 44197856Sdes result = tree; 44263012Sdes } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) { 44390267Sdes JCExpression init = translate(tree.init); 44490267Sdes VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym); 44597856Sdes int prevPos = make.pos; 44690267Sdes try { 44797856Sdes result = make.at(tree).VarDef(xsym, init); 44897856Sdes } finally { 44997856Sdes make.at(prevPos); 45097856Sdes } 45197856Sdes // Replace the entered symbol for this variable 45290267Sdes WriteableScope sc = tree.sym.owner.members(); 45390267Sdes if (sc != null) { 45490267Sdes sc.remove(tree.sym); 45590267Sdes sc.enter(xsym); 45690267Sdes } 45790267Sdes } else { 45890267Sdes super.visitVarDef(tree); 45997856Sdes } 46090267Sdes } 46190267Sdes 46263012Sdes // </editor-fold> 46363012Sdes 46463012Sdes // <editor-fold defaultstate="collapsed" desc="Translation helper methods"> 46563012Sdes 46663012Sdes private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) { 46763716Sdes return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ? 46875891Sarchie makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) : 46963012Sdes makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally); 47090267Sdes } 47190267Sdes 47263012Sdes private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) { 47390267Sdes Type restype = lambdaMethodDecl.type.getReturnType(); 47490267Sdes boolean isLambda_void = expr.type.hasTag(VOID); 47590267Sdes boolean isTarget_void = restype.hasTag(VOID); 47690267Sdes boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type); 47790267Sdes int prevPos = make.pos; 47890267Sdes try { 47990267Sdes if (isTarget_void) { 48090267Sdes //target is void: 48188769Sdes // BODY; 48263012Sdes JCStatement stat = make.at(expr).Exec(expr); 48363012Sdes return make.Block(0, List.<JCStatement>of(stat)); 48490267Sdes } else if (isLambda_void && isTarget_Void) { 48590267Sdes //void to Void conversion: 48663012Sdes // BODY; return null; 48763012Sdes ListBuffer<JCStatement> stats = new ListBuffer<>(); 48863012Sdes stats.append(make.at(expr).Exec(expr)); 48963012Sdes stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType))); 49063012Sdes return make.Block(0, stats.toList()); 49163716Sdes } else { 49275891Sarchie //non-void to non-void conversion: 49363012Sdes // return (TYPE)BODY; 49490267Sdes JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype); 49590267Sdes return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr))); 49690267Sdes } 49790267Sdes } finally { 49890267Sdes make.at(prevPos); 49990267Sdes } 50090267Sdes } 50190267Sdes 50290267Sdes private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) { 50390267Sdes final Type restype = lambdaMethodDecl.type.getReturnType(); 50463012Sdes final boolean isTarget_void = restype.hasTag(VOID); 50563012Sdes boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type); 50663012Sdes 50763012Sdes class LambdaBodyTranslator extends TreeTranslator { 50863012Sdes 50963716Sdes @Override 51075891Sarchie public void visitClassDef(JCClassDecl tree) { 51163012Sdes //do NOT recurse on any inner classes 51290267Sdes result = tree; 51363716Sdes } 51490267Sdes 51590267Sdes @Override 51690267Sdes public void visitLambda(JCLambda tree) { 51790267Sdes //do NOT recurse on any nested lambdas 51890267Sdes result = tree; 51990267Sdes } 52090267Sdes 52190267Sdes @Override 52290267Sdes public void visitReturn(JCReturn tree) { 52390267Sdes boolean isLambda_void = tree.expr == null; 52490267Sdes if (isTarget_void && !isLambda_void) { 52590267Sdes //Void to void conversion: 52690267Sdes // { TYPE $loc = RET-EXPR; return; } 52790267Sdes VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym); 52890267Sdes JCVariableDecl varDef = make.VarDef(loc, tree.expr); 52990267Sdes result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null))); 53090267Sdes } else if (!isTarget_void || !isLambda_void) { 53190267Sdes //non-void to non-void conversion: 53290267Sdes // return (TYPE)RET-EXPR; 53390267Sdes tree.expr = transTypes.coerce(attrEnv, tree.expr, restype); 53463012Sdes result = tree; 53563012Sdes } else { 53690267Sdes result = tree; 53763012Sdes } 53863012Sdes 53963012Sdes } 54063012Sdes } 54163012Sdes 54237608Sdes JCBlock trans_block = new LambdaBodyTranslator().translate(block); 54337608Sdes if (completeNormally && isTarget_Void) { 54462965Sdes //there's no return statement and the lambda (possibly inferred) 54590267Sdes //return type is java.lang.Void; emit a synthetic return statement 54637608Sdes trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType))); 54790267Sdes } 54890267Sdes return trans_block; 54990267Sdes } 55090267Sdes 55190267Sdes private JCMethodDecl makeDeserializeMethod(Symbol kSym) { 55290267Sdes ListBuffer<JCCase> cases = new ListBuffer<>(); 55390267Sdes ListBuffer<JCBreak> breaks = new ListBuffer<>(); 55462965Sdes for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) { 55590267Sdes JCBreak br = make.Break(null); 55690267Sdes breaks.add(br); 55790267Sdes List<JCStatement> stmts = entry.getValue().append(br).toList(); 55890267Sdes cases.add(make.Case(make.Literal(entry.getKey()), stmts)); 55990267Sdes } 56037608Sdes JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList()); 56190267Sdes for (JCBreak br : breaks) { 56290267Sdes br.target = sw; 56390267Sdes } 56490267Sdes JCBlock body = make.Block(0L, List.<JCStatement>of( 56590267Sdes sw, 56690267Sdes make.Throw(makeNewClass( 56790267Sdes syms.illegalArgumentExceptionType, 56890267Sdes List.<JCExpression>of(make.Literal("Invalid lambda deserialization")))))); 56990267Sdes JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()), 57037608Sdes names.deserializeLambda, 57190267Sdes make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym), 57290267Sdes List.<JCTypeParameter>nil(), 57390267Sdes List.of(make.VarDef(kInfo.deserParamSym, null)), 57490267Sdes List.<JCExpression>nil(), 57590267Sdes body, 57690267Sdes null); 57790267Sdes deser.sym = kInfo.deserMethodSym; 57890267Sdes deser.type = kInfo.deserMethodSym.type; 57990267Sdes //System.err.printf("DESER: '%s'\n", deser); 58090267Sdes return deser; 58190267Sdes } 58290267Sdes 58390267Sdes /** Make an attributed class instance creation expression. 58490267Sdes * @param ctype The class type. 58590267Sdes * @param args The constructor arguments. 58690267Sdes * @param cons The constructor symbol 58790267Sdes */ 58890267Sdes JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) { 58990267Sdes JCNewClass tree = make.NewClass(null, 59090267Sdes null, make.QualIdent(ctype.tsym), args, null); 59190267Sdes tree.constructor = cons; 59290267Sdes tree.type = ctype; 59390267Sdes return tree; 59490267Sdes } 59537608Sdes 59637608Sdes /** Make an attributed class instance creation expression. 59737608Sdes * @param ctype The class type. 59837608Sdes * @param args The constructor arguments. 59937608Sdes */ 60062965Sdes JCNewClass makeNewClass(Type ctype, List<JCExpression> args) { 60197856Sdes return makeNewClass(ctype, args, 60237608Sdes rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil())); 60390267Sdes } 60490267Sdes 60537608Sdes private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym, 60690267Sdes DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) { 60790267Sdes String functionalInterfaceClass = classSig(targetType); 60890267Sdes String functionalInterfaceMethodName = samSym.getSimpleName().toString(); 60990267Sdes String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type)); 61090267Sdes String implClass = classSig(types.erasure(refSym.owner.type)); 61190267Sdes String implMethodName = refSym.getQualifiedName().toString(); 61290267Sdes String implMethodSignature = typeSig(types.erasure(refSym.type)); 61390267Sdes 61497856Sdes JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind)); 61590267Sdes ListBuffer<JCExpression> serArgs = new ListBuffer<>(); 61690267Sdes int i = 0; 61762965Sdes for (Type t : indyType.getParameterTypes()) { 61862965Sdes List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList(); 61962965Sdes List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList(); 62062965Sdes serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg))); 62162965Sdes ++i; 62262965Sdes } 62397856Sdes JCStatement stmt = make.If( 62462965Sdes deserTest(deserTest(deserTest(deserTest(deserTest( 62590267Sdes kindTest, 62690267Sdes "getFunctionalInterfaceClass", functionalInterfaceClass), 62790267Sdes "getFunctionalInterfaceMethodName", functionalInterfaceMethodName), 62890267Sdes "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature), 62962965Sdes "getImplClass", implClass), 63090267Sdes "getImplMethodSignature", implMethodSignature), 63190267Sdes make.Return(makeIndyCall( 63290267Sdes pos, 63390267Sdes syms.lambdaMetafactory, 63490267Sdes names.altMetafactory, 63590267Sdes staticArgs, indyType, serArgs.toList(), samSym.name)), 63690267Sdes null); 63790267Sdes ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName); 63890267Sdes if (stmts == null) { 63990267Sdes stmts = new ListBuffer<>(); 64097856Sdes kInfo.deserializeCases.put(implMethodName, stmts); 64190267Sdes } 64290267Sdes /**** 64390267Sdes System.err.printf("+++++++++++++++++\n"); 64490267Sdes System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass); 64537608Sdes System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName); 64637608Sdes System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature); 64790267Sdes System.err.printf("*implMethodKind: %d\n", implMethodKind); 64863012Sdes System.err.printf("*implClass: '%s'\n", implClass); 64963012Sdes System.err.printf("*implMethodName: '%s'\n", implMethodName); 65063012Sdes System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature); 65163012Sdes ****/ 65237608Sdes stmts.append(stmt); 65390267Sdes } 65463012Sdes 65597856Sdes private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) { 65675891Sarchie JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2); 65763012Sdes testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType); 65897856Sdes testExpr.setType(syms.booleanType); 65990267Sdes return testExpr; 66097856Sdes } 66190267Sdes 66263012Sdes private JCExpression deserTest(JCExpression prev, String func, String lit) { 66390267Sdes MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass); 66460737Sume Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil()); 66590267Sdes JCMethodInvocation eqtest = make.Apply( 66660737Sume List.<JCExpression>nil(), 66790267Sdes make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt), 66890267Sdes List.<JCExpression>of(make.Literal(lit))); 66990267Sdes eqtest.setType(syms.booleanType); 67090267Sdes JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest); 67167043Sdes compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType); 67290267Sdes compound.setType(syms.booleanType); 67390267Sdes return compound; 67467043Sdes } 67567043Sdes 67697868Sdes private JCExpression deserGetter(String func, Type type) { 67790267Sdes return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil()); 67890267Sdes } 67990267Sdes 68090267Sdes private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) { 68197856Sdes MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass); 68290267Sdes Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil()); 68390267Sdes return make.Apply( 68497856Sdes List.<JCExpression>nil(), 68590267Sdes make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt), 68697856Sdes args).setType(type); 68797868Sdes } 68897868Sdes 68997868Sdes /** 69097891Sdes * Create new synthetic method with given flags, name, type, owner 69197891Sdes */ 69297891Sdes private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) { 69397868Sdes return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner); 69497868Sdes } 69597856Sdes 69667043Sdes /** 69767043Sdes * Create new synthetic variable with given flags, name, type, owner 69867043Sdes */ 69975891Sarchie private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) { 70067043Sdes return makeSyntheticVar(flags, names.fromString(name), type, owner); 70190267Sdes } 70290267Sdes 70390267Sdes /** 70490267Sdes * Create new synthetic variable with given flags, name, type, owner 70590267Sdes */ 70690267Sdes private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) { 70790267Sdes return new VarSymbol(flags | SYNTHETIC, name, type, owner); 70890267Sdes } 70990267Sdes 71090267Sdes /** 71190267Sdes * Set varargsElement field on a given tree (must be either a new class tree 71290267Sdes * or a method call tree) 71390267Sdes */ 71490267Sdes private void setVarargsIfNeeded(JCTree tree, Type varargsElement) { 71560376Sdes if (varargsElement != null) { 71660376Sdes switch (tree.getTag()) { 71788771Sdes case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break; 71888771Sdes case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break; 71988771Sdes default: throw new AssertionError(); 72090267Sdes } 72190267Sdes } 72290267Sdes } 72388771Sdes 72490267Sdes /** 72590267Sdes * Convert method/constructor arguments by inserting appropriate cast 72690267Sdes * as required by type-erasure - this is needed when bridging a lambda/method 72790267Sdes * reference, as the bridged signature might require downcast to be compatible 72890267Sdes * with the generated signature. 72990267Sdes */ 73090267Sdes private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) { 73190267Sdes Assert.check(meth.kind == MTH); 73290267Sdes List<Type> formals = types.erasure(meth.type).getParameterTypes(); 73390267Sdes if (varargsElement != null) { 73490267Sdes Assert.check((meth.flags() & VARARGS) != 0); 73590267Sdes } 73690267Sdes return transTypes.translateArgs(args, formals, varargsElement, attrEnv); 73790267Sdes } 73890267Sdes 73990267Sdes // </editor-fold> 74090267Sdes 74190267Sdes /** 74290267Sdes * Converts a method reference which cannot be used directly into a lambda 74390267Sdes */ 74490267Sdes private class MemberReferenceToLambda { 74590267Sdes 74690267Sdes private final JCMemberReference tree; 74790267Sdes private final ReferenceTranslationContext localContext; 74888771Sdes private final Symbol owner; 74990267Sdes private final ListBuffer<JCExpression> args = new ListBuffer<>(); 75090267Sdes private final ListBuffer<JCVariableDecl> params = new ListBuffer<>(); 75190267Sdes 75288771Sdes private JCExpression receiverExpression = null; 75388771Sdes 75488771Sdes MemberReferenceToLambda(JCMemberReference tree, ReferenceTranslationContext localContext, Symbol owner) { 75590267Sdes this.tree = tree; 75663012Sdes this.localContext = localContext; 75763012Sdes this.owner = owner; 75860954Sdes } 75960954Sdes 76060954Sdes JCLambda lambda() { 76163012Sdes int prevPos = make.pos; 76297866Sdes try { 76397866Sdes make.at(tree); 76497866Sdes 76560376Sdes //body generation - this can be either a method call or a 76667043Sdes //new instance creation expression, depending on the member reference kind 76775891Sarchie VarSymbol rcvr = addParametersReturnReceiver(); 76890267Sdes JCExpression expr = (tree.getMode() == ReferenceMode.INVOKE) 76960376Sdes ? expressionInvoke(rcvr) 77097856Sdes : expressionNew(); 77190267Sdes 77290267Sdes JCLambda slam = make.Lambda(params.toList(), expr); 77398422Sdes slam.targets = tree.targets; 77490267Sdes slam.type = tree.type; 77590267Sdes slam.pos = tree.pos; 77690267Sdes return slam; 77790267Sdes } finally { 77890267Sdes make.at(prevPos); 779107372Sdes } 78063012Sdes } 78190267Sdes 78290267Sdes /** 78390267Sdes * Generate the parameter list for the converted member reference. 78460737Sume * 78590267Sdes * @return The receiver variable symbol, if any 78690267Sdes */ 78790267Sdes VarSymbol addParametersReturnReceiver() { 78890267Sdes Type samDesc = localContext.bridgedRefSig(); 78963716Sdes List<Type> samPTypes = samDesc.getParameterTypes(); 79090267Sdes List<Type> descPTypes = tree.getDescriptorType(types).getParameterTypes(); 79190267Sdes 79263012Sdes // Determine the receiver, if any 79390267Sdes VarSymbol rcvr; 79490267Sdes switch (tree.kind) { 79590267Sdes case BOUND: 79663012Sdes // The receiver is explicit in the method reference 79798422Sdes rcvr = addParameter("rec$", tree.getQualifierExpression().type, false); 79890267Sdes receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); 79990267Sdes break; 80090267Sdes case UNBOUND: 80190267Sdes // The receiver is the first parameter, extract it and 80290267Sdes // adjust the SAM and unerased type lists accordingly 80390267Sdes rcvr = addParameter("rec$", samDesc.getParameterTypes().head, false); 80490267Sdes samPTypes = samPTypes.tail; 80590267Sdes descPTypes = descPTypes.tail; 80690267Sdes break; 80790267Sdes default: 80890267Sdes rcvr = null; 80990267Sdes break; 81090267Sdes } 81190267Sdes List<Type> implPTypes = tree.sym.type.getParameterTypes(); 81290267Sdes int implSize = implPTypes.size(); 81390267Sdes int samSize = samPTypes.size(); 81490267Sdes // Last parameter to copy from referenced method, exclude final var args 81590267Sdes int last = localContext.needsVarArgsConversion() ? implSize - 1 : implSize; 81690267Sdes 81790267Sdes // Failsafe -- assure match-up 81890267Sdes boolean checkForIntersection = tree.varargsElement != null || implSize == descPTypes.size(); 81990267Sdes 82090267Sdes // Use parameter types of the implementation method unless the unerased 82197856Sdes // SAM parameter type is an intersection type, in that case use the 82290267Sdes // erased SAM parameter type so that the supertype relationship 82390267Sdes // the implementation method parameters is not obscured. 82490267Sdes // Note: in this loop, the lists implPTypes, samPTypes, and descPTypes 82560737Sume // are used as pointers to the current parameter type information 82690267Sdes // and are thus not usable afterwards. 82790267Sdes for (int i = 0; implPTypes.nonEmpty() && i < last; ++i) { 82890267Sdes // By default use the implementation method parmeter type 82990267Sdes Type parmType = implPTypes.head; 83060737Sume // If the unerased parameter type is a type variable whose 831107372Sdes // bound is an intersection (eg. <T extends A & B>) then 832107372Sdes // use the SAM parameter type 833107372Sdes if (checkForIntersection && descPTypes.head.getKind() == TypeKind.TYPEVAR) { 834107372Sdes TypeVar tv = (TypeVar) descPTypes.head; 835107372Sdes if (tv.bound.getKind() == TypeKind.INTERSECTION) { 836107372Sdes parmType = samPTypes.head; 837107372Sdes } 838107372Sdes } 83937535Sdes addParameter("x$" + i, parmType, true); 84090267Sdes 84190267Sdes // Advance to the next parameter 842107372Sdes implPTypes = implPTypes.tail; 843107372Sdes samPTypes = samPTypes.tail; 84490267Sdes descPTypes = descPTypes.tail; 845107372Sdes } 846107372Sdes // Flatten out the var args 84790267Sdes for (int i = last; i < samSize; ++i) { 84897856Sdes addParameter("xva$" + i, tree.varargsElement, true); 84990267Sdes } 85090267Sdes 85137535Sdes return rcvr; 85290267Sdes } 853107372Sdes 85490267Sdes JCExpression getReceiverExpression() { 85590267Sdes return receiverExpression; 85690267Sdes } 85790267Sdes 85897856Sdes private JCExpression makeReceiver(VarSymbol rcvr) { 85990267Sdes if (rcvr == null) return null; 86090267Sdes JCExpression rcvrExpr = make.Ident(rcvr); 86197856Sdes Type rcvrType = tree.sym.enclClass().type; 86290267Sdes if (rcvrType == syms.arrayClass.type) { 86390267Sdes // Map the receiver type to the actually type, not just "array" 86490267Sdes rcvrType = tree.getQualifierExpression().type; 86590267Sdes } 86690267Sdes if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) { 86797856Sdes rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType); 86890267Sdes } 86997856Sdes return rcvrExpr; 87090267Sdes } 87197856Sdes 87290267Sdes /** 87390267Sdes * determine the receiver of the method call - the receiver can 87490267Sdes * be a type qualifier, the synthetic receiver parameter or 'super'. 87590267Sdes */ 87690267Sdes private JCExpression expressionInvoke(VarSymbol rcvr) { 87790267Sdes JCExpression qualifier = 87890267Sdes tree.sym.isStatic() ? 879107372Sdes make.Type(tree.sym.owner.type) : 880107372Sdes (rcvr != null) ? 881107372Sdes makeReceiver(rcvr) : 882107372Sdes tree.getQualifierExpression(); 883107372Sdes 884107372Sdes //create the qualifier expression 885107372Sdes JCFieldAccess select = make.Select(qualifier, tree.sym.name); 88690267Sdes select.sym = tree.sym; 88797856Sdes select.type = tree.sym.erasure(types); 88890267Sdes 88997856Sdes //create the method call expression 89090267Sdes JCExpression apply = make.Apply(List.<JCExpression>nil(), select, 89197856Sdes convertArgs(tree.sym, args.toList(), tree.varargsElement)). 89297856Sdes setType(tree.sym.erasure(types).getReturnType()); 89397856Sdes 89490267Sdes apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType()); 89590267Sdes setVarargsIfNeeded(apply, tree.varargsElement); 89697856Sdes return apply; 89790267Sdes } 89890267Sdes 89990267Sdes /** 90090267Sdes * Lambda body to use for a 'new'. 90190267Sdes */ 90290267Sdes private JCExpression expressionNew() { 90390267Sdes if (tree.kind == ReferenceKind.ARRAY_CTOR) { 90490267Sdes //create the array creation expression 90590267Sdes JCNewArray newArr = make.NewArray( 90690267Sdes make.Type(types.elemtype(tree.getQualifierExpression().type)), 90790267Sdes List.of(make.Ident(params.first())), 90890267Sdes null); 90990267Sdes newArr.type = tree.getQualifierExpression().type; 91090267Sdes return newArr; 91190267Sdes } else { 91290267Sdes //create the instance creation expression 91390267Sdes //note that method reference syntax does not allow an explicit 91490267Sdes //enclosing class (so the enclosing class is null) 91597856Sdes JCNewClass newClass = make.NewClass(null, 91690267Sdes List.<JCExpression>nil(), 91790267Sdes make.Type(tree.getQualifierExpression().type), 91890267Sdes convertArgs(tree.sym, args.toList(), tree.varargsElement), 91990267Sdes null); 92090267Sdes newClass.constructor = tree.sym; 92190267Sdes newClass.constructorType = tree.sym.erasure(types); 92290267Sdes newClass.type = tree.getQualifierExpression().type; 92390267Sdes setVarargsIfNeeded(newClass, tree.varargsElement); 92490267Sdes return newClass; 92590267Sdes } 92690267Sdes } 92797856Sdes 92890267Sdes private VarSymbol addParameter(String name, Type p, boolean genArg) { 92990267Sdes VarSymbol vsym = new VarSymbol(PARAMETER | SYNTHETIC, names.fromString(name), p, owner); 93090267Sdes vsym.pos = tree.pos; 93190267Sdes params.append(make.VarDef(vsym, null)); 93290267Sdes if (genArg) { 93390267Sdes args.append(make.Ident(vsym)); 93490267Sdes } 93597856Sdes return vsym; 93690267Sdes } 93790267Sdes } 93890267Sdes 93990267Sdes private MethodType typeToMethodType(Type mt) { 94090267Sdes Type type = types.erasure(mt); 94190267Sdes return new MethodType(type.getParameterTypes(), 94290267Sdes type.getReturnType(), 94397856Sdes type.getThrownTypes(), 94490267Sdes syms.methodClass); 94590267Sdes } 94690267Sdes 94790267Sdes /** 94890267Sdes * Generate an indy method call to the meta factory 94990267Sdes */ 95090267Sdes private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context, 95190267Sdes int refKind, Symbol refSym, List<JCExpression> indy_args) { 95290267Sdes JCFunctionalExpression tree = context.tree; 95390267Sdes //determine the static bsm args 95490267Sdes MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym); 95590267Sdes List<Object> staticArgs = List.<Object>of( 95690267Sdes typeToMethodType(samSym.type), 95790267Sdes new Pool.MethodHandle(refKind, refSym, types), 95890267Sdes typeToMethodType(tree.getDescriptorType(types))); 95990267Sdes 96097856Sdes //computed indy arg types 96190267Sdes ListBuffer<Type> indy_args_types = new ListBuffer<>(); 96290267Sdes for (JCExpression arg : indy_args) { 96390267Sdes indy_args_types.append(arg.type); 96490267Sdes } 96597856Sdes 96690267Sdes //finally, compute the type of the indy call 96790267Sdes MethodType indyType = new MethodType(indy_args_types.toList(), 96890267Sdes tree.type, 96990267Sdes List.<Type>nil(), 97090267Sdes syms.methodClass); 97190267Sdes 97290267Sdes Name metafactoryName = context.needsAltMetafactory() ? 97390267Sdes names.altMetafactory : names.metafactory; 97490267Sdes 97590267Sdes if (context.needsAltMetafactory()) { 97690267Sdes ListBuffer<Object> markers = new ListBuffer<>(); 97790267Sdes for (Type t : tree.targets.tail) { 97890267Sdes if (t.tsym != syms.serializableType.tsym) { 97990267Sdes markers.append(t.tsym); 98090267Sdes } 98190267Sdes } 98290267Sdes int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0; 98390267Sdes boolean hasMarkers = markers.nonEmpty(); 98490267Sdes boolean hasBridges = context.bridges.nonEmpty(); 98590267Sdes if (hasMarkers) { 98690267Sdes flags |= FLAG_MARKERS; 98790267Sdes } 98890267Sdes if (hasBridges) { 98997856Sdes flags |= FLAG_BRIDGES; 99090267Sdes } 99190267Sdes staticArgs = staticArgs.append(flags); 99290267Sdes if (hasMarkers) { 99390267Sdes staticArgs = staticArgs.append(markers.length()); 99490267Sdes staticArgs = staticArgs.appendList(markers.toList()); 99590267Sdes } 99690267Sdes if (hasBridges) { 99790267Sdes staticArgs = staticArgs.append(context.bridges.length() - 1); 99890267Sdes for (Symbol s : context.bridges) { 99990267Sdes Type s_erasure = s.erasure(types); 100090267Sdes if (!types.isSameType(s_erasure, samSym.erasure(types))) { 100190267Sdes staticArgs = staticArgs.append(s.erasure(types)); 100297856Sdes } 100398422Sdes } 100490267Sdes } 100597856Sdes if (context.isSerializable()) { 100697856Sdes int prevPos = make.pos; 100790267Sdes try { 100890267Sdes make.at(kInfo.clazz); 100990267Sdes addDeserializationCase(refKind, refSym, tree.type, samSym, 1010104404Sru tree, staticArgs, indyType); 1011104404Sru } finally { 1012104404Sru make.at(prevPos); 1013104404Sru } 101490267Sdes } 101598422Sdes } 101690267Sdes 101797856Sdes return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name); 101897856Sdes } 101990267Sdes 102090267Sdes /** 102190267Sdes * Generate an indy method call with given name, type and static bootstrap 102290267Sdes * arguments types 102390267Sdes */ 102490267Sdes private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName, 102590267Sdes List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs, 102690267Sdes Name methName) { 102790267Sdes int prevPos = make.pos; 102890267Sdes try { 102997856Sdes make.at(pos); 103098422Sdes List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType, 103163012Sdes syms.stringType, 103263012Sdes syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs)); 103360376Sdes 103490267Sdes Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site, 103590267Sdes bsmName, bsm_staticArgs, List.<Type>nil()); 103690267Sdes 103790267Sdes DynamicMethodSymbol dynSym = 103860376Sdes new DynamicMethodSymbol(methName, 103990267Sdes syms.noSymbol, 104090267Sdes bsm.isStatic() ? 104190267Sdes ClassFile.REF_invokeStatic : 104263012Sdes ClassFile.REF_invokeVirtual, 104363012Sdes (MethodSymbol)bsm, 104490267Sdes indyType, 104590267Sdes staticArgs.toArray()); 104690267Sdes 104790267Sdes JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName); 104890267Sdes qualifier.sym = dynSym; 104963012Sdes qualifier.type = indyType.getReturnType(); 105063012Sdes 105190267Sdes JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs); 105290267Sdes proxyCall.type = indyType.getReturnType(); 105390267Sdes return proxyCall; 105460376Sdes } finally { 105590267Sdes make.at(prevPos); 105690267Sdes } 105790267Sdes } 105890267Sdes //where 105990267Sdes private List<Type> bsmStaticArgToTypes(List<Object> args) { 106063069Sdes ListBuffer<Type> argtypes = new ListBuffer<>(); 106190267Sdes for (Object arg : args) { 106290267Sdes argtypes.append(bsmStaticArgToType(arg)); 106390267Sdes } 106490267Sdes return argtypes.toList(); 106577238Sdes } 106660376Sdes 106790267Sdes private Type bsmStaticArgToType(Object arg) { 106890267Sdes Assert.checkNonNull(arg); 106990267Sdes if (arg instanceof ClassSymbol) { 107037535Sdes return syms.classType; 107190267Sdes } else if (arg instanceof Integer) { 107297866Sdes return syms.intType; 107390267Sdes } else if (arg instanceof Long) { 107490267Sdes return syms.longType; 107590267Sdes } else if (arg instanceof Float) { 107663716Sdes return syms.floatType; 107790267Sdes } else if (arg instanceof Double) { 107890267Sdes return syms.doubleType; 107990267Sdes } else if (arg instanceof String) { 108090267Sdes return syms.stringType; 108163567Sdes } else if (arg instanceof Pool.MethodHandle) { 108297856Sdes return syms.methodHandleType; 108390267Sdes } else if (arg instanceof MethodType) { 108490267Sdes return syms.methodTypeType; 108590267Sdes } else { 108690267Sdes Assert.error("bad static arg " + arg.getClass()); 108763012Sdes return null; 108890267Sdes } 108988771Sdes } 109090267Sdes 109190267Sdes /** 109290267Sdes * Get the opcode associated with this method reference 109390267Sdes */ 109490267Sdes private int referenceKind(Symbol refSym) { 109597856Sdes if (refSym.isConstructor()) { 109697856Sdes return ClassFile.REF_newInvokeSpecial; 109790267Sdes } else { 109863012Sdes if (refSym.isStatic()) { 109960189Sdes return ClassFile.REF_invokeStatic; 110090267Sdes } else if ((refSym.flags() & PRIVATE) != 0) { 110163012Sdes return ClassFile.REF_invokeSpecial; 110263012Sdes } else if (refSym.enclClass().isInterface()) { 110363012Sdes return ClassFile.REF_invokeInterface; 110463012Sdes } else { 110563012Sdes return ClassFile.REF_invokeVirtual; 110663340Sdes } 110763340Sdes } 110863340Sdes } 110975891Sarchie 111063340Sdes // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer"> 111190267Sdes /** 111263340Sdes * This visitor collects information about translation of a lambda expression. 111363340Sdes * More specifically, it keeps track of the enclosing contexts and captured locals 111463340Sdes * accessed by the lambda being translated (as well as other useful info). 111563012Sdes * It also translates away problems for LambdaToMethod. 111663012Sdes */ 111763012Sdes class LambdaAnalyzerPreprocessor extends TreeTranslator { 111875891Sarchie 111963012Sdes /** the frame stack - used to reconstruct translation info about enclosing scopes */ 112090267Sdes private List<Frame> frameStack; 112137535Sdes 112237535Sdes /** 112363340Sdes * keep the count of lambda expression (used to generate unambiguous 112463340Sdes * names) 112563340Sdes */ 112637535Sdes private int lambdaCount = 0; 112785093Sdes 112837535Sdes /** 112990267Sdes * keep the count of lambda expression defined in given context (used to 113090267Sdes * generate unambiguous names for serializable lambdas) 113137535Sdes */ 113240975Sdes private class SyntheticMethodNameCounter { 113340975Sdes private Map<String, Integer> map = new HashMap<>(); 113440975Sdes int getIndex(StringBuilder buf) { 113540975Sdes String temp = buf.toString(); 113640975Sdes Integer count = map.get(temp); 113775891Sarchie if (count == null) { 113840975Sdes count = 0; 113990267Sdes } 114090267Sdes ++count; 114190267Sdes map.put(temp, count); 114290267Sdes return count; 114390267Sdes } 114490267Sdes } 114540975Sdes private SyntheticMethodNameCounter syntheticMethodNameCounts = 114641989Sdes new SyntheticMethodNameCounter(); 114741989Sdes 114841989Sdes private Map<Symbol, JCClassDecl> localClassDefs; 114941989Sdes 115041989Sdes /** 115185093Sdes * maps for fake clinit symbols to be used as owners of lambda occurring in 115241989Sdes * a static var init context 115390267Sdes */ 115490267Sdes private Map<ClassSymbol, Symbol> clinits = new HashMap<>(); 115541989Sdes 1156 private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) { 1157 frameStack = List.nil(); 1158 localClassDefs = new HashMap<>(); 1159 return translate(tree); 1160 } 1161 1162 @Override 1163 public void visitBlock(JCBlock tree) { 1164 List<Frame> prevStack = frameStack; 1165 try { 1166 if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) { 1167 frameStack = frameStack.prepend(new Frame(tree)); 1168 } 1169 super.visitBlock(tree); 1170 } 1171 finally { 1172 frameStack = prevStack; 1173 } 1174 } 1175 1176 @Override 1177 public void visitClassDef(JCClassDecl tree) { 1178 List<Frame> prevStack = frameStack; 1179 int prevLambdaCount = lambdaCount; 1180 SyntheticMethodNameCounter prevSyntheticMethodNameCounts = 1181 syntheticMethodNameCounts; 1182 Map<ClassSymbol, Symbol> prevClinits = clinits; 1183 DiagnosticSource prevSource = log.currentSource(); 1184 try { 1185 log.useSource(tree.sym.sourcefile); 1186 lambdaCount = 0; 1187 syntheticMethodNameCounts = new SyntheticMethodNameCounter(); 1188 prevClinits = new HashMap<>(); 1189 if (tree.sym.owner.kind == MTH) { 1190 localClassDefs.put(tree.sym, tree); 1191 } 1192 if (directlyEnclosingLambda() != null) { 1193 tree.sym.owner = owner(); 1194 if (tree.sym.hasOuterInstance()) { 1195 //if a class is defined within a lambda, the lambda must capture 1196 //its enclosing instance (if any) 1197 TranslationContext<?> localContext = context(); 1198 while (localContext != null) { 1199 if (localContext.tree.getTag() == LAMBDA) { 1200 ((LambdaTranslationContext)localContext) 1201 .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS); 1202 } 1203 localContext = localContext.prev; 1204 } 1205 } 1206 } 1207 frameStack = frameStack.prepend(new Frame(tree)); 1208 super.visitClassDef(tree); 1209 } 1210 finally { 1211 log.useSource(prevSource.getFile()); 1212 frameStack = prevStack; 1213 lambdaCount = prevLambdaCount; 1214 syntheticMethodNameCounts = prevSyntheticMethodNameCounts; 1215 clinits = prevClinits; 1216 } 1217 } 1218 1219 @Override 1220 public void visitIdent(JCIdent tree) { 1221 if (context() != null && lambdaIdentSymbolFilter(tree.sym)) { 1222 if (tree.sym.kind == VAR && 1223 tree.sym.owner.kind == MTH && 1224 tree.type.constValue() == null) { 1225 TranslationContext<?> localContext = context(); 1226 while (localContext != null) { 1227 if (localContext.tree.getTag() == LAMBDA) { 1228 JCTree block = capturedDecl(localContext.depth, tree.sym); 1229 if (block == null) break; 1230 ((LambdaTranslationContext)localContext) 1231 .addSymbol(tree.sym, CAPTURED_VAR); 1232 } 1233 localContext = localContext.prev; 1234 } 1235 } else if (tree.sym.owner.kind == TYP) { 1236 TranslationContext<?> localContext = context(); 1237 while (localContext != null) { 1238 if (localContext.tree.hasTag(LAMBDA)) { 1239 JCTree block = capturedDecl(localContext.depth, tree.sym); 1240 if (block == null) break; 1241 switch (block.getTag()) { 1242 case CLASSDEF: 1243 JCClassDecl cdecl = (JCClassDecl)block; 1244 ((LambdaTranslationContext)localContext) 1245 .addSymbol(cdecl.sym, CAPTURED_THIS); 1246 break; 1247 default: 1248 Assert.error("bad block kind"); 1249 } 1250 } 1251 localContext = localContext.prev; 1252 } 1253 } 1254 } 1255 super.visitIdent(tree); 1256 } 1257 1258 @Override 1259 public void visitLambda(JCLambda tree) { 1260 analyzeLambda(tree, "lambda.stat"); 1261 } 1262 1263 private void analyzeLambda(JCLambda tree, JCExpression methodReferenceReceiver) { 1264 // Translation of the receiver expression must occur first 1265 JCExpression rcvr = translate(methodReferenceReceiver); 1266 LambdaTranslationContext context = analyzeLambda(tree, "mref.stat.1"); 1267 if (rcvr != null) { 1268 context.methodReferenceReceiver = rcvr; 1269 } 1270 } 1271 1272 private LambdaTranslationContext analyzeLambda(JCLambda tree, String statKey) { 1273 List<Frame> prevStack = frameStack; 1274 try { 1275 LambdaTranslationContext context = new LambdaTranslationContext(tree); 1276 if (dumpLambdaToMethodStats) { 1277 log.note(tree, statKey, context.needsAltMetafactory(), context.translatedSym); 1278 } 1279 frameStack = frameStack.prepend(new Frame(tree)); 1280 for (JCVariableDecl param : tree.params) { 1281 context.addSymbol(param.sym, PARAM); 1282 frameStack.head.addLocal(param.sym); 1283 } 1284 contextMap.put(tree, context); 1285 super.visitLambda(tree); 1286 context.complete(); 1287 return context; 1288 } 1289 finally { 1290 frameStack = prevStack; 1291 } 1292 } 1293 1294 @Override 1295 public void visitMethodDef(JCMethodDecl tree) { 1296 List<Frame> prevStack = frameStack; 1297 try { 1298 frameStack = frameStack.prepend(new Frame(tree)); 1299 super.visitMethodDef(tree); 1300 } 1301 finally { 1302 frameStack = prevStack; 1303 } 1304 } 1305 1306 @Override 1307 public void visitNewClass(JCNewClass tree) { 1308 TypeSymbol def = tree.type.tsym; 1309 boolean inReferencedClass = currentlyInClass(def); 1310 boolean isLocal = def.isLocal(); 1311 if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) { 1312 TranslationContext<?> localContext = context(); 1313 while (localContext != null) { 1314 if (localContext.tree.getTag() == LAMBDA) { 1315 ((LambdaTranslationContext)localContext) 1316 .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS); 1317 } 1318 localContext = localContext.prev; 1319 } 1320 } 1321 if (context() != null && !inReferencedClass && isLocal) { 1322 LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context(); 1323 captureLocalClassDefs(def, lambdaContext); 1324 } 1325 super.visitNewClass(tree); 1326 } 1327 //where 1328 void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) { 1329 JCClassDecl localCDef = localClassDefs.get(csym); 1330 if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) { 1331 BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() { 1332 @Override 1333 void addFreeVars(ClassSymbol c) { 1334 captureLocalClassDefs(c, lambdaContext); 1335 } 1336 @Override 1337 void visitSymbol(Symbol sym) { 1338 if (sym.kind == VAR && 1339 sym.owner.kind == MTH && 1340 ((VarSymbol)sym).getConstValue() == null) { 1341 TranslationContext<?> localContext = context(); 1342 while (localContext != null) { 1343 if (localContext.tree.getTag() == LAMBDA) { 1344 JCTree block = capturedDecl(localContext.depth, sym); 1345 if (block == null) break; 1346 ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR); 1347 } 1348 localContext = localContext.prev; 1349 } 1350 } 1351 } 1352 }; 1353 fvc.scan(localCDef); 1354 } 1355 } 1356 //where 1357 boolean currentlyInClass(Symbol csym) { 1358 for (Frame frame : frameStack) { 1359 if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) { 1360 JCClassDecl cdef = (JCClassDecl) frame.tree; 1361 if (cdef.sym == csym) { 1362 return true; 1363 } 1364 } 1365 } 1366 return false; 1367 } 1368 1369 /** 1370 * Method references to local class constructors, may, if the local 1371 * class references local variables, have implicit constructor 1372 * parameters added in Lower; As a result, the invokedynamic bootstrap 1373 * information added in the LambdaToMethod pass will have the wrong 1374 * signature. Hooks between Lower and LambdaToMethod have been added to 1375 * handle normal "new" in this case. This visitor converts potentially 1376 * affected method references into a lambda containing a normal 1377 * expression. 1378 * 1379 * @param tree 1380 */ 1381 @Override 1382 public void visitReference(JCMemberReference tree) { 1383 ReferenceTranslationContext rcontext = new ReferenceTranslationContext(tree); 1384 contextMap.put(tree, rcontext); 1385 if (rcontext.needsConversionToLambda()) { 1386 // Convert to a lambda, and process as such 1387 MemberReferenceToLambda conv = new MemberReferenceToLambda(tree, rcontext, owner()); 1388 analyzeLambda(conv.lambda(), conv.getReceiverExpression()); 1389 } else { 1390 super.visitReference(tree); 1391 if (dumpLambdaToMethodStats) { 1392 log.note(tree, "mref.stat", rcontext.needsAltMetafactory(), null); 1393 } 1394 } 1395 } 1396 1397 @Override 1398 public void visitSelect(JCFieldAccess tree) { 1399 if (context() != null && tree.sym.kind == VAR && 1400 (tree.sym.name == names._this || 1401 tree.sym.name == names._super)) { 1402 // A select of this or super means, if we are in a lambda, 1403 // we much have an instance context 1404 TranslationContext<?> localContext = context(); 1405 while (localContext != null) { 1406 if (localContext.tree.hasTag(LAMBDA)) { 1407 JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym); 1408 if (clazz == null) break; 1409 ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS); 1410 } 1411 localContext = localContext.prev; 1412 } 1413 } 1414 super.visitSelect(tree); 1415 } 1416 1417 @Override 1418 public void visitVarDef(JCVariableDecl tree) { 1419 TranslationContext<?> context = context(); 1420 LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)? 1421 (LambdaTranslationContext)context : 1422 null; 1423 if (ltc != null) { 1424 if (frameStack.head.tree.hasTag(LAMBDA)) { 1425 ltc.addSymbol(tree.sym, LOCAL_VAR); 1426 } 1427 // Check for type variables (including as type arguments). 1428 // If they occur within class nested in a lambda, mark for erasure 1429 Type type = tree.sym.asType(); 1430 if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) { 1431 ltc.addSymbol(tree.sym, TYPE_VAR); 1432 } 1433 } 1434 1435 List<Frame> prevStack = frameStack; 1436 try { 1437 if (tree.sym.owner.kind == MTH) { 1438 frameStack.head.addLocal(tree.sym); 1439 } 1440 frameStack = frameStack.prepend(new Frame(tree)); 1441 super.visitVarDef(tree); 1442 } 1443 finally { 1444 frameStack = prevStack; 1445 } 1446 } 1447 1448 /** 1449 * Return a valid owner given the current declaration stack 1450 * (required to skip synthetic lambda symbols) 1451 */ 1452 private Symbol owner() { 1453 return owner(false); 1454 } 1455 1456 @SuppressWarnings("fallthrough") 1457 private Symbol owner(boolean skipLambda) { 1458 List<Frame> frameStack2 = frameStack; 1459 while (frameStack2.nonEmpty()) { 1460 switch (frameStack2.head.tree.getTag()) { 1461 case VARDEF: 1462 if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) { 1463 frameStack2 = frameStack2.tail; 1464 break; 1465 } 1466 JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree; 1467 return initSym(cdecl.sym, 1468 ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC); 1469 case BLOCK: 1470 JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree; 1471 return initSym(cdecl2.sym, 1472 ((JCBlock)frameStack2.head.tree).flags & STATIC); 1473 case CLASSDEF: 1474 return ((JCClassDecl)frameStack2.head.tree).sym; 1475 case METHODDEF: 1476 return ((JCMethodDecl)frameStack2.head.tree).sym; 1477 case LAMBDA: 1478 if (!skipLambda) 1479 return ((LambdaTranslationContext)contextMap 1480 .get(frameStack2.head.tree)).translatedSym; 1481 default: 1482 frameStack2 = frameStack2.tail; 1483 } 1484 } 1485 Assert.error(); 1486 return null; 1487 } 1488 1489 private Symbol initSym(ClassSymbol csym, long flags) { 1490 boolean isStatic = (flags & STATIC) != 0; 1491 if (isStatic) { 1492 /* static clinits are generated in Gen, so we need to use a fake 1493 * one. Attr creates a fake clinit method while attributing 1494 * lambda expressions used as initializers of static fields, so 1495 * let's use that one. 1496 */ 1497 MethodSymbol clinit = attr.removeClinit(csym); 1498 if (clinit != null) { 1499 clinits.put(csym, clinit); 1500 return clinit; 1501 } 1502 1503 /* if no clinit is found at Attr, then let's try at clinits. 1504 */ 1505 clinit = (MethodSymbol)clinits.get(csym); 1506 if (clinit == null) { 1507 /* no luck, let's create a new one 1508 */ 1509 clinit = makePrivateSyntheticMethod(STATIC, 1510 names.clinit, 1511 new MethodType(List.<Type>nil(), syms.voidType, 1512 List.<Type>nil(), syms.methodClass), 1513 csym); 1514 clinits.put(csym, clinit); 1515 } 1516 return clinit; 1517 } else { 1518 //get the first constructor and treat it as the instance init sym 1519 for (Symbol s : csym.members_field.getSymbolsByName(names.init)) { 1520 return s; 1521 } 1522 } 1523 Assert.error("init not found"); 1524 return null; 1525 } 1526 1527 private JCTree directlyEnclosingLambda() { 1528 if (frameStack.isEmpty()) { 1529 return null; 1530 } 1531 List<Frame> frameStack2 = frameStack; 1532 while (frameStack2.nonEmpty()) { 1533 switch (frameStack2.head.tree.getTag()) { 1534 case CLASSDEF: 1535 case METHODDEF: 1536 return null; 1537 case LAMBDA: 1538 return frameStack2.head.tree; 1539 default: 1540 frameStack2 = frameStack2.tail; 1541 } 1542 } 1543 Assert.error(); 1544 return null; 1545 } 1546 1547 private boolean inClassWithinLambda() { 1548 if (frameStack.isEmpty()) { 1549 return false; 1550 } 1551 List<Frame> frameStack2 = frameStack; 1552 boolean classFound = false; 1553 while (frameStack2.nonEmpty()) { 1554 switch (frameStack2.head.tree.getTag()) { 1555 case LAMBDA: 1556 return classFound; 1557 case CLASSDEF: 1558 classFound = true; 1559 frameStack2 = frameStack2.tail; 1560 break; 1561 default: 1562 frameStack2 = frameStack2.tail; 1563 } 1564 } 1565 // No lambda 1566 return false; 1567 } 1568 1569 /** 1570 * Return the declaration corresponding to a symbol in the enclosing 1571 * scope; the depth parameter is used to filter out symbols defined 1572 * in nested scopes (which do not need to undergo capture). 1573 */ 1574 private JCTree capturedDecl(int depth, Symbol sym) { 1575 int currentDepth = frameStack.size() - 1; 1576 for (Frame block : frameStack) { 1577 switch (block.tree.getTag()) { 1578 case CLASSDEF: 1579 ClassSymbol clazz = ((JCClassDecl)block.tree).sym; 1580 if (sym.isMemberOf(clazz, types)) { 1581 return currentDepth > depth ? null : block.tree; 1582 } 1583 break; 1584 case VARDEF: 1585 if (((JCVariableDecl)block.tree).sym == sym && 1586 sym.owner.kind == MTH) { //only locals are captured 1587 return currentDepth > depth ? null : block.tree; 1588 } 1589 break; 1590 case BLOCK: 1591 case METHODDEF: 1592 case LAMBDA: 1593 if (block.locals != null && block.locals.contains(sym)) { 1594 return currentDepth > depth ? null : block.tree; 1595 } 1596 break; 1597 default: 1598 Assert.error("bad decl kind " + block.tree.getTag()); 1599 } 1600 currentDepth--; 1601 } 1602 return null; 1603 } 1604 1605 private TranslationContext<?> context() { 1606 for (Frame frame : frameStack) { 1607 TranslationContext<?> context = contextMap.get(frame.tree); 1608 if (context != null) { 1609 return context; 1610 } 1611 } 1612 return null; 1613 } 1614 1615 /** 1616 * This is used to filter out those identifiers that needs to be adjusted 1617 * when translating away lambda expressions 1618 */ 1619 private boolean lambdaIdentSymbolFilter(Symbol sym) { 1620 return (sym.kind == VAR || sym.kind == MTH) 1621 && !sym.isStatic() 1622 && sym.name != names.init; 1623 } 1624 1625 /** 1626 * This is used to filter out those new class expressions that need to 1627 * be qualified with an enclosing tree 1628 */ 1629 private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) { 1630 if (context != null 1631 && tree.encl == null 1632 && tree.def == null 1633 && !tree.type.getEnclosingType().hasTag(NONE)) { 1634 Type encl = tree.type.getEnclosingType(); 1635 Type current = context.owner.enclClass().type; 1636 while (!current.hasTag(NONE)) { 1637 if (current.tsym.isSubClass(encl.tsym, types)) { 1638 return true; 1639 } 1640 current = current.getEnclosingType(); 1641 } 1642 return false; 1643 } else { 1644 return false; 1645 } 1646 } 1647 1648 private class Frame { 1649 final JCTree tree; 1650 List<Symbol> locals; 1651 1652 public Frame(JCTree tree) { 1653 this.tree = tree; 1654 } 1655 1656 void addLocal(Symbol sym) { 1657 if (locals == null) { 1658 locals = List.nil(); 1659 } 1660 locals = locals.prepend(sym); 1661 } 1662 } 1663 1664 /** 1665 * This class is used to store important information regarding translation of 1666 * lambda expression/method references (see subclasses). 1667 */ 1668 private abstract class TranslationContext<T extends JCFunctionalExpression> { 1669 1670 /** the underlying (untranslated) tree */ 1671 final T tree; 1672 1673 /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */ 1674 final Symbol owner; 1675 1676 /** the depth of this lambda expression in the frame stack */ 1677 final int depth; 1678 1679 /** the enclosing translation context (set for nested lambdas/mref) */ 1680 final TranslationContext<?> prev; 1681 1682 /** list of methods to be bridged by the meta-factory */ 1683 final List<Symbol> bridges; 1684 1685 TranslationContext(T tree) { 1686 this.tree = tree; 1687 this.owner = owner(); 1688 this.depth = frameStack.size() - 1; 1689 this.prev = context(); 1690 ClassSymbol csym = 1691 types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE); 1692 this.bridges = types.functionalInterfaceBridges(csym); 1693 } 1694 1695 /** does this functional expression need to be created using alternate metafactory? */ 1696 boolean needsAltMetafactory() { 1697 return tree.targets.length() > 1 || 1698 isSerializable() || 1699 bridges.length() > 1; 1700 } 1701 1702 /** does this functional expression require serialization support? */ 1703 boolean isSerializable() { 1704 if (forceSerializable) { 1705 return true; 1706 } 1707 for (Type target : tree.targets) { 1708 if (types.asSuper(target, syms.serializableType.tsym) != null) { 1709 return true; 1710 } 1711 } 1712 return false; 1713 } 1714 1715 /** 1716 * @return Name of the enclosing method to be folded into synthetic 1717 * method name 1718 */ 1719 String enclosingMethodName() { 1720 return syntheticMethodNameComponent(owner.name); 1721 } 1722 1723 /** 1724 * @return Method name in a form that can be folded into a 1725 * component of a synthetic method name 1726 */ 1727 String syntheticMethodNameComponent(Name name) { 1728 if (name == null) { 1729 return "null"; 1730 } 1731 String methodName = name.toString(); 1732 if (methodName.equals("<clinit>")) { 1733 methodName = "static"; 1734 } else if (methodName.equals("<init>")) { 1735 methodName = "new"; 1736 } 1737 return methodName; 1738 } 1739 } 1740 1741 /** 1742 * This class retains all the useful information about a lambda expression; 1743 * the contents of this class are filled by the LambdaAnalyzer visitor, 1744 * and the used by the main translation routines in order to adjust references 1745 * to captured locals/members, etc. 1746 */ 1747 private class LambdaTranslationContext extends TranslationContext<JCLambda> { 1748 1749 /** variable in the enclosing context to which this lambda is assigned */ 1750 final Symbol self; 1751 1752 /** variable in the enclosing context to which this lambda is assigned */ 1753 final Symbol assignedTo; 1754 1755 Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols; 1756 1757 /** the synthetic symbol for the method hoisting the translated lambda */ 1758 MethodSymbol translatedSym; 1759 1760 List<JCVariableDecl> syntheticParams; 1761 1762 /** 1763 * to prevent recursion, track local classes processed 1764 */ 1765 final Set<Symbol> freeVarProcessedLocalClasses; 1766 1767 /** 1768 * For method references converted to lambdas. The method 1769 * reference receiver expression. Must be treated like a captured 1770 * variable. 1771 */ 1772 JCExpression methodReferenceReceiver; 1773 1774 LambdaTranslationContext(JCLambda tree) { 1775 super(tree); 1776 Frame frame = frameStack.head; 1777 switch (frame.tree.getTag()) { 1778 case VARDEF: 1779 assignedTo = self = ((JCVariableDecl) frame.tree).sym; 1780 break; 1781 case ASSIGN: 1782 self = null; 1783 assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable()); 1784 break; 1785 default: 1786 assignedTo = self = null; 1787 break; 1788 } 1789 1790 // This symbol will be filled-in in complete 1791 this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass()); 1792 1793 translatedSymbols = new EnumMap<>(LambdaSymbolKind.class); 1794 1795 translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>()); 1796 translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>()); 1797 translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>()); 1798 translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>()); 1799 translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>()); 1800 1801 freeVarProcessedLocalClasses = new HashSet<>(); 1802 } 1803 1804 /** 1805 * For a serializable lambda, generate a disambiguating string 1806 * which maximizes stability across deserialization. 1807 * 1808 * @return String to differentiate synthetic lambda method names 1809 */ 1810 private String serializedLambdaDisambiguation() { 1811 StringBuilder buf = new StringBuilder(); 1812 // Append the enclosing method signature to differentiate 1813 // overloaded enclosing methods. For lambdas enclosed in 1814 // lambdas, the generated lambda method will not have type yet, 1815 // but the enclosing method's name will have been generated 1816 // with this same method, so it will be unique and never be 1817 // overloaded. 1818 Assert.check( 1819 owner.type != null || 1820 directlyEnclosingLambda() != null); 1821 if (owner.type != null) { 1822 buf.append(typeSig(owner.type)); 1823 buf.append(":"); 1824 } 1825 1826 // Add target type info 1827 buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName()); 1828 buf.append(" "); 1829 1830 // Add variable assigned to 1831 if (assignedTo != null) { 1832 buf.append(assignedTo.flatName()); 1833 buf.append("="); 1834 } 1835 //add captured locals info: type, name, order 1836 for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) { 1837 if (fv != self) { 1838 buf.append(typeSig(fv.type)); 1839 buf.append(" "); 1840 buf.append(fv.flatName()); 1841 buf.append(","); 1842 } 1843 } 1844 1845 return buf.toString(); 1846 } 1847 1848 /** 1849 * For a non-serializable lambda, generate a simple method. 1850 * 1851 * @return Name to use for the synthetic lambda method name 1852 */ 1853 private Name lambdaName() { 1854 return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++)); 1855 } 1856 1857 /** 1858 * For a serializable lambda, generate a method name which maximizes 1859 * name stability across deserialization. 1860 * 1861 * @return Name to use for the synthetic lambda method name 1862 */ 1863 private Name serializedLambdaName() { 1864 StringBuilder buf = new StringBuilder(); 1865 buf.append(names.lambda); 1866 // Append the name of the method enclosing the lambda. 1867 buf.append(enclosingMethodName()); 1868 buf.append('$'); 1869 // Append a hash of the disambiguating string : enclosing method 1870 // signature, etc. 1871 String disam = serializedLambdaDisambiguation(); 1872 buf.append(Integer.toHexString(disam.hashCode())); 1873 buf.append('$'); 1874 // The above appended name components may not be unique, append 1875 // a count based on the above name components. 1876 buf.append(syntheticMethodNameCounts.getIndex(buf)); 1877 String result = buf.toString(); 1878 //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam); 1879 return names.fromString(result); 1880 } 1881 1882 /** 1883 * Translate a symbol of a given kind into something suitable for the 1884 * synthetic lambda body 1885 */ 1886 Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) { 1887 Symbol ret; 1888 switch (skind) { 1889 case CAPTURED_THIS: 1890 ret = sym; // self represented 1891 break; 1892 case TYPE_VAR: 1893 // Just erase the type var 1894 ret = new VarSymbol(sym.flags(), name, 1895 types.erasure(sym.type), sym.owner); 1896 1897 /* this information should also be kept for LVT generation at Gen 1898 * a Symbol with pos < startPos won't be tracked. 1899 */ 1900 ((VarSymbol)ret).pos = ((VarSymbol)sym).pos; 1901 break; 1902 case CAPTURED_VAR: 1903 ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) { 1904 @Override 1905 public Symbol baseSymbol() { 1906 //keep mapping with original captured symbol 1907 return sym; 1908 } 1909 }; 1910 break; 1911 case LOCAL_VAR: 1912 ret = new VarSymbol(sym.flags() & FINAL, name, sym.type, translatedSym); 1913 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; 1914 break; 1915 case PARAM: 1916 ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, name, types.erasure(sym.type), translatedSym); 1917 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; 1918 break; 1919 default: 1920 ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym); 1921 ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; 1922 } 1923 if (ret != sym) { 1924 ret.setDeclarationAttributes(sym.getRawAttributes()); 1925 ret.setTypeAttributes(sym.getRawTypeAttributes()); 1926 } 1927 return ret; 1928 } 1929 1930 void addSymbol(Symbol sym, LambdaSymbolKind skind) { 1931 Map<Symbol, Symbol> transMap = getSymbolMap(skind); 1932 Name preferredName; 1933 switch (skind) { 1934 case CAPTURED_THIS: 1935 preferredName = names.fromString("encl$" + transMap.size()); 1936 break; 1937 case CAPTURED_VAR: 1938 preferredName = names.fromString("cap$" + transMap.size()); 1939 break; 1940 case LOCAL_VAR: 1941 preferredName = sym.name; 1942 break; 1943 case PARAM: 1944 preferredName = sym.name; 1945 break; 1946 case TYPE_VAR: 1947 preferredName = sym.name; 1948 break; 1949 default: throw new AssertionError(); 1950 } 1951 if (!transMap.containsKey(sym)) { 1952 transMap.put(sym, translate(preferredName, sym, skind)); 1953 } 1954 } 1955 1956 Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) { 1957 Map<Symbol, Symbol> m = translatedSymbols.get(skind); 1958 Assert.checkNonNull(m); 1959 return m; 1960 } 1961 1962 JCTree translate(JCIdent lambdaIdent) { 1963 for (Map<Symbol, Symbol> m : translatedSymbols.values()) { 1964 if (m.containsKey(lambdaIdent.sym)) { 1965 Symbol tSym = m.get(lambdaIdent.sym); 1966 JCTree t = make.Ident(tSym).setType(lambdaIdent.type); 1967 tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes()); 1968 return t; 1969 } 1970 } 1971 return null; 1972 } 1973 1974 /** 1975 * The translatedSym is not complete/accurate until the analysis is 1976 * finished. Once the analysis is finished, the translatedSym is 1977 * "completed" -- updated with type information, access modifiers, 1978 * and full parameter list. 1979 */ 1980 void complete() { 1981 if (syntheticParams != null) { 1982 return; 1983 } 1984 boolean inInterface = translatedSym.owner.isInterface(); 1985 boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty(); 1986 1987 // If instance access isn't needed, make it static. 1988 // Interface instance methods must be default methods. 1989 // Lambda methods are private synthetic. 1990 // Inherit ACC_STRICT from the enclosing method, or, for clinit, 1991 // from the class. 1992 translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD | 1993 owner.flags_field & STRICTFP | 1994 owner.owner.flags_field & STRICTFP | 1995 PRIVATE | 1996 (thisReferenced? (inInterface? DEFAULT : 0) : STATIC); 1997 1998 //compute synthetic params 1999 ListBuffer<JCVariableDecl> params = new ListBuffer<>(); 2000 ListBuffer<VarSymbol> parameterSymbols = new ListBuffer<>(); 2001 2002 // The signature of the method is augmented with the following 2003 // synthetic parameters: 2004 // 2005 // 1) reference to enclosing contexts captured by the lambda expression 2006 // 2) enclosing locals captured by the lambda expression 2007 for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) { 2008 params.append(make.VarDef((VarSymbol) thisSym, null)); 2009 parameterSymbols.append((VarSymbol) thisSym); 2010 } 2011 for (Symbol thisSym : getSymbolMap(PARAM).values()) { 2012 params.append(make.VarDef((VarSymbol) thisSym, null)); 2013 parameterSymbols.append((VarSymbol) thisSym); 2014 } 2015 syntheticParams = params.toList(); 2016 2017 translatedSym.params = parameterSymbols.toList(); 2018 2019 // Compute and set the lambda name 2020 translatedSym.name = isSerializable() 2021 ? serializedLambdaName() 2022 : lambdaName(); 2023 2024 //prepend synthetic args to translated lambda method signature 2025 translatedSym.type = types.createMethodTypeWithParameters( 2026 generatedLambdaSig(), 2027 TreeInfo.types(syntheticParams)); 2028 } 2029 2030 Type generatedLambdaSig() { 2031 return types.erasure(tree.getDescriptorType(types)); 2032 } 2033 } 2034 2035 /** 2036 * This class retains all the useful information about a method reference; 2037 * the contents of this class are filled by the LambdaAnalyzer visitor, 2038 * and the used by the main translation routines in order to adjust method 2039 * references (i.e. in case a bridge is needed) 2040 */ 2041 private final class ReferenceTranslationContext extends TranslationContext<JCMemberReference> { 2042 2043 final boolean isSuper; 2044 final Symbol sigPolySym; 2045 2046 ReferenceTranslationContext(JCMemberReference tree) { 2047 super(tree); 2048 this.isSuper = tree.hasKind(ReferenceKind.SUPER); 2049 this.sigPolySym = isSignaturePolymorphic() 2050 ? makePrivateSyntheticMethod(tree.sym.flags(), 2051 tree.sym.name, 2052 bridgedRefSig(), 2053 tree.sym.enclClass()) 2054 : null; 2055 } 2056 2057 /** 2058 * Get the opcode associated with this method reference 2059 */ 2060 int referenceKind() { 2061 return LambdaToMethod.this.referenceKind(tree.sym); 2062 } 2063 2064 boolean needsVarArgsConversion() { 2065 return tree.varargsElement != null; 2066 } 2067 2068 /** 2069 * @return Is this an array operation like clone() 2070 */ 2071 boolean isArrayOp() { 2072 return tree.sym.owner == syms.arrayClass; 2073 } 2074 2075 boolean receiverAccessible() { 2076 //hack needed to workaround 292 bug (7087658) 2077 //when 292 issue is fixed we should remove this and change the backend 2078 //code to always generate a method handle to an accessible method 2079 return tree.ownerAccessible; 2080 } 2081 2082 /** 2083 * The VM does not support access across nested classes (8010319). 2084 * Were that ever to change, this should be removed. 2085 */ 2086 boolean isPrivateInOtherClass() { 2087 return (tree.sym.flags() & PRIVATE) != 0 && 2088 !types.isSameType( 2089 types.erasure(tree.sym.enclClass().asType()), 2090 types.erasure(owner.enclClass().asType())); 2091 } 2092 2093 /** 2094 * Signature polymorphic methods need special handling. 2095 * e.g. MethodHandle.invoke() MethodHandle.invokeExact() 2096 */ 2097 final boolean isSignaturePolymorphic() { 2098 return tree.sym.kind == MTH && 2099 types.isSignaturePolymorphic((MethodSymbol)tree.sym); 2100 } 2101 2102 /** 2103 * Erasure destroys the implementation parameter subtype 2104 * relationship for intersection types 2105 */ 2106 boolean interfaceParameterIsIntersectionType() { 2107 List<Type> tl = tree.getDescriptorType(types).getParameterTypes(); 2108 if (tree.kind == ReferenceKind.UNBOUND) { 2109 tl = tl.tail; 2110 } 2111 for (; tl.nonEmpty(); tl = tl.tail) { 2112 Type pt = tl.head; 2113 if (pt.getKind() == TypeKind.TYPEVAR) { 2114 TypeVar tv = (TypeVar) pt; 2115 if (tv.bound.getKind() == TypeKind.INTERSECTION) { 2116 return true; 2117 } 2118 } 2119 } 2120 return false; 2121 } 2122 2123 /** 2124 * Does this reference need to be converted to a lambda 2125 * (i.e. var args need to be expanded or "super" is used) 2126 */ 2127 final boolean needsConversionToLambda() { 2128 return interfaceParameterIsIntersectionType() || 2129 isSuper || 2130 needsVarArgsConversion() || 2131 isArrayOp() || 2132 isPrivateInOtherClass() || 2133 !receiverAccessible() || 2134 (tree.getMode() == ReferenceMode.NEW && 2135 tree.kind != ReferenceKind.ARRAY_CTOR && 2136 (tree.sym.owner.isLocal() || tree.sym.owner.isInner())); 2137 } 2138 2139 Type generatedRefSig() { 2140 return types.erasure(tree.sym.type); 2141 } 2142 2143 Type bridgedRefSig() { 2144 return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type); 2145 } 2146 } 2147 } 2148 // </editor-fold> 2149 2150 /* 2151 * These keys provide mappings for various translated lambda symbols 2152 * and the prevailing order must be maintained. 2153 */ 2154 enum LambdaSymbolKind { 2155 PARAM, // original to translated lambda parameters 2156 LOCAL_VAR, // original to translated lambda locals 2157 CAPTURED_VAR, // variables in enclosing scope to translated synthetic parameters 2158 CAPTURED_THIS, // class symbols to translated synthetic parameters (for captured member access) 2159 TYPE_VAR // original to translated lambda type variables 2160 } 2161 2162 /** 2163 * **************************************************************** 2164 * Signature Generation 2165 * **************************************************************** 2166 */ 2167 2168 private String typeSig(Type type) { 2169 L2MSignatureGenerator sg = new L2MSignatureGenerator(); 2170 sg.assembleSig(type); 2171 return sg.toString(); 2172 } 2173 2174 private String classSig(Type type) { 2175 L2MSignatureGenerator sg = new L2MSignatureGenerator(); 2176 sg.assembleClassSig(type); 2177 return sg.toString(); 2178 } 2179 2180 /** 2181 * Signature Generation 2182 */ 2183 private class L2MSignatureGenerator extends Types.SignatureGenerator { 2184 2185 /** 2186 * An output buffer for type signatures. 2187 */ 2188 StringBuilder sb = new StringBuilder(); 2189 2190 L2MSignatureGenerator() { 2191 super(types); 2192 } 2193 2194 @Override 2195 protected void append(char ch) { 2196 sb.append(ch); 2197 } 2198 2199 @Override 2200 protected void append(byte[] ba) { 2201 sb.append(new String(ba)); 2202 } 2203 2204 @Override 2205 protected void append(Name name) { 2206 sb.append(name.toString()); 2207 } 2208 2209 @Override 2210 public String toString() { 2211 return sb.toString(); 2212 } 2213 } 2214} 2215