1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Wed Apr 27 01:34:52 2016 +0800 1.3 @@ -0,0 +1,2254 @@ 1.4 +/* 1.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 +package com.sun.tools.javac.comp; 1.29 + 1.30 +import com.sun.tools.javac.tree.*; 1.31 +import com.sun.tools.javac.tree.JCTree.*; 1.32 +import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; 1.33 +import com.sun.tools.javac.tree.TreeMaker; 1.34 +import com.sun.tools.javac.tree.TreeTranslator; 1.35 +import com.sun.tools.javac.code.Attribute; 1.36 +import com.sun.tools.javac.code.Kinds; 1.37 +import com.sun.tools.javac.code.Scope; 1.38 +import com.sun.tools.javac.code.Symbol; 1.39 +import com.sun.tools.javac.code.Symbol.ClassSymbol; 1.40 +import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol; 1.41 +import com.sun.tools.javac.code.Symbol.MethodSymbol; 1.42 +import com.sun.tools.javac.code.Symbol.TypeSymbol; 1.43 +import com.sun.tools.javac.code.Symbol.VarSymbol; 1.44 +import com.sun.tools.javac.code.Symtab; 1.45 +import com.sun.tools.javac.code.Type; 1.46 +import com.sun.tools.javac.code.Type.MethodType; 1.47 +import com.sun.tools.javac.code.Types; 1.48 +import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*; 1.49 +import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector; 1.50 +import com.sun.tools.javac.jvm.*; 1.51 +import com.sun.tools.javac.util.*; 1.52 +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 1.53 +import com.sun.source.tree.MemberReferenceTree.ReferenceMode; 1.54 + 1.55 +import java.util.EnumMap; 1.56 +import java.util.HashMap; 1.57 +import java.util.HashSet; 1.58 +import java.util.LinkedHashMap; 1.59 +import java.util.Map; 1.60 +import java.util.Set; 1.61 + 1.62 +import static com.sun.tools.javac.comp.LambdaToMethod.LambdaSymbolKind.*; 1.63 +import static com.sun.tools.javac.code.Flags.*; 1.64 +import static com.sun.tools.javac.code.Kinds.*; 1.65 +import static com.sun.tools.javac.code.TypeTag.*; 1.66 +import static com.sun.tools.javac.tree.JCTree.Tag.*; 1.67 + 1.68 +/** 1.69 + * This pass desugars lambda expressions into static methods 1.70 + * 1.71 + * <p><b>This is NOT part of any supported API. 1.72 + * If you write code that depends on this, you do so at your own risk. 1.73 + * This code and its internal interfaces are subject to change or 1.74 + * deletion without notice.</b> 1.75 + */ 1.76 +public class LambdaToMethod extends TreeTranslator { 1.77 + 1.78 + private Attr attr; 1.79 + private JCDiagnostic.Factory diags; 1.80 + private Log log; 1.81 + private Lower lower; 1.82 + private Names names; 1.83 + private Symtab syms; 1.84 + private Resolve rs; 1.85 + private TreeMaker make; 1.86 + private Types types; 1.87 + private TransTypes transTypes; 1.88 + private Env<AttrContext> attrEnv; 1.89 + 1.90 + /** the analyzer scanner */ 1.91 + private LambdaAnalyzerPreprocessor analyzer; 1.92 + 1.93 + /** map from lambda trees to translation contexts */ 1.94 + private Map<JCTree, TranslationContext<?>> contextMap; 1.95 + 1.96 + /** current translation context (visitor argument) */ 1.97 + private TranslationContext<?> context; 1.98 + 1.99 + /** info about the current class being processed */ 1.100 + private KlassInfo kInfo; 1.101 + 1.102 + /** dump statistics about lambda code generation */ 1.103 + private boolean dumpLambdaToMethodStats; 1.104 + 1.105 + /** force serializable representation, for stress testing **/ 1.106 + private final boolean forceSerializable; 1.107 + 1.108 + /** Flag for alternate metafactories indicating the lambda object is intended to be serializable */ 1.109 + public static final int FLAG_SERIALIZABLE = 1 << 0; 1.110 + 1.111 + /** Flag for alternate metafactories indicating the lambda object has multiple targets */ 1.112 + public static final int FLAG_MARKERS = 1 << 1; 1.113 + 1.114 + /** Flag for alternate metafactories indicating the lambda object requires multiple bridges */ 1.115 + public static final int FLAG_BRIDGES = 1 << 2; 1.116 + 1.117 + // <editor-fold defaultstate="collapsed" desc="Instantiating"> 1.118 + protected static final Context.Key<LambdaToMethod> unlambdaKey = 1.119 + new Context.Key<LambdaToMethod>(); 1.120 + 1.121 + public static LambdaToMethod instance(Context context) { 1.122 + LambdaToMethod instance = context.get(unlambdaKey); 1.123 + if (instance == null) { 1.124 + instance = new LambdaToMethod(context); 1.125 + } 1.126 + return instance; 1.127 + } 1.128 + private LambdaToMethod(Context context) { 1.129 + context.put(unlambdaKey, this); 1.130 + diags = JCDiagnostic.Factory.instance(context); 1.131 + log = Log.instance(context); 1.132 + lower = Lower.instance(context); 1.133 + names = Names.instance(context); 1.134 + syms = Symtab.instance(context); 1.135 + rs = Resolve.instance(context); 1.136 + make = TreeMaker.instance(context); 1.137 + types = Types.instance(context); 1.138 + transTypes = TransTypes.instance(context); 1.139 + analyzer = new LambdaAnalyzerPreprocessor(); 1.140 + Options options = Options.instance(context); 1.141 + dumpLambdaToMethodStats = options.isSet("dumpLambdaToMethodStats"); 1.142 + attr = Attr.instance(context); 1.143 + forceSerializable = options.isSet("forceSerializable"); 1.144 + } 1.145 + // </editor-fold> 1.146 + 1.147 + private class KlassInfo { 1.148 + 1.149 + /** 1.150 + * list of methods to append 1.151 + */ 1.152 + private ListBuffer<JCTree> appendedMethodList; 1.153 + 1.154 + /** 1.155 + * list of deserialization cases 1.156 + */ 1.157 + private final Map<String, ListBuffer<JCStatement>> deserializeCases; 1.158 + 1.159 + /** 1.160 + * deserialize method symbol 1.161 + */ 1.162 + private final MethodSymbol deserMethodSym; 1.163 + 1.164 + /** 1.165 + * deserialize method parameter symbol 1.166 + */ 1.167 + private final VarSymbol deserParamSym; 1.168 + 1.169 + private final JCClassDecl clazz; 1.170 + 1.171 + private KlassInfo(JCClassDecl clazz) { 1.172 + this.clazz = clazz; 1.173 + appendedMethodList = new ListBuffer<>(); 1.174 + deserializeCases = new HashMap<String, ListBuffer<JCStatement>>(); 1.175 + MethodType type = new MethodType(List.of(syms.serializedLambdaType), syms.objectType, 1.176 + List.<Type>nil(), syms.methodClass); 1.177 + deserMethodSym = makePrivateSyntheticMethod(STATIC, names.deserializeLambda, type, clazz.sym); 1.178 + deserParamSym = new VarSymbol(FINAL, names.fromString("lambda"), 1.179 + syms.serializedLambdaType, deserMethodSym); 1.180 + } 1.181 + 1.182 + private void addMethod(JCTree decl) { 1.183 + appendedMethodList = appendedMethodList.prepend(decl); 1.184 + } 1.185 + } 1.186 + 1.187 + // <editor-fold defaultstate="collapsed" desc="translate methods"> 1.188 + @Override 1.189 + public <T extends JCTree> T translate(T tree) { 1.190 + TranslationContext<?> newContext = contextMap.get(tree); 1.191 + return translate(tree, newContext != null ? newContext : context); 1.192 + } 1.193 + 1.194 + <T extends JCTree> T translate(T tree, TranslationContext<?> newContext) { 1.195 + TranslationContext<?> prevContext = context; 1.196 + try { 1.197 + context = newContext; 1.198 + return super.translate(tree); 1.199 + } 1.200 + finally { 1.201 + context = prevContext; 1.202 + } 1.203 + } 1.204 + 1.205 + <T extends JCTree> List<T> translate(List<T> trees, TranslationContext<?> newContext) { 1.206 + ListBuffer<T> buf = new ListBuffer<>(); 1.207 + for (T tree : trees) { 1.208 + buf.append(translate(tree, newContext)); 1.209 + } 1.210 + return buf.toList(); 1.211 + } 1.212 + 1.213 + public JCTree translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) { 1.214 + this.make = make; 1.215 + this.attrEnv = env; 1.216 + this.context = null; 1.217 + this.contextMap = new HashMap<JCTree, TranslationContext<?>>(); 1.218 + return translate(cdef); 1.219 + } 1.220 + // </editor-fold> 1.221 + 1.222 + // <editor-fold defaultstate="collapsed" desc="visitor methods"> 1.223 + /** 1.224 + * Visit a class. 1.225 + * Maintain the translatedMethodList across nested classes. 1.226 + * Append the translatedMethodList to the class after it is translated. 1.227 + * @param tree 1.228 + */ 1.229 + @Override 1.230 + public void visitClassDef(JCClassDecl tree) { 1.231 + if (tree.sym.owner.kind == PCK) { 1.232 + //analyze class 1.233 + tree = analyzer.analyzeAndPreprocessClass(tree); 1.234 + } 1.235 + KlassInfo prevKlassInfo = kInfo; 1.236 + try { 1.237 + kInfo = new KlassInfo(tree); 1.238 + super.visitClassDef(tree); 1.239 + if (!kInfo.deserializeCases.isEmpty()) { 1.240 + int prevPos = make.pos; 1.241 + try { 1.242 + make.at(tree); 1.243 + kInfo.addMethod(makeDeserializeMethod(tree.sym)); 1.244 + } finally { 1.245 + make.at(prevPos); 1.246 + } 1.247 + } 1.248 + //add all translated instance methods here 1.249 + List<JCTree> newMethods = kInfo.appendedMethodList.toList(); 1.250 + tree.defs = tree.defs.appendList(newMethods); 1.251 + for (JCTree lambda : newMethods) { 1.252 + tree.sym.members().enter(((JCMethodDecl)lambda).sym); 1.253 + } 1.254 + result = tree; 1.255 + } finally { 1.256 + kInfo = prevKlassInfo; 1.257 + } 1.258 + } 1.259 + 1.260 + /** 1.261 + * Translate a lambda into a method to be inserted into the class. 1.262 + * Then replace the lambda site with an invokedynamic call of to lambda 1.263 + * meta-factory, which will use the lambda method. 1.264 + * @param tree 1.265 + */ 1.266 + @Override 1.267 + public void visitLambda(JCLambda tree) { 1.268 + LambdaTranslationContext localContext = (LambdaTranslationContext)context; 1.269 + MethodSymbol sym = (MethodSymbol)localContext.translatedSym; 1.270 + MethodType lambdaType = (MethodType) sym.type; 1.271 + 1.272 + { 1.273 + Symbol owner = localContext.owner; 1.274 + ListBuffer<Attribute.TypeCompound> ownerTypeAnnos = new ListBuffer<Attribute.TypeCompound>(); 1.275 + ListBuffer<Attribute.TypeCompound> lambdaTypeAnnos = new ListBuffer<Attribute.TypeCompound>(); 1.276 + 1.277 + for (Attribute.TypeCompound tc : owner.getRawTypeAttributes()) { 1.278 + if (tc.position.onLambda == tree) { 1.279 + lambdaTypeAnnos.append(tc); 1.280 + } else { 1.281 + ownerTypeAnnos.append(tc); 1.282 + } 1.283 + } 1.284 + if (lambdaTypeAnnos.nonEmpty()) { 1.285 + owner.setTypeAttributes(ownerTypeAnnos.toList()); 1.286 + sym.setTypeAttributes(lambdaTypeAnnos.toList()); 1.287 + } 1.288 + } 1.289 + 1.290 + //create the method declaration hoisting the lambda body 1.291 + JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field), 1.292 + sym.name, 1.293 + make.QualIdent(lambdaType.getReturnType().tsym), 1.294 + List.<JCTypeParameter>nil(), 1.295 + localContext.syntheticParams, 1.296 + lambdaType.getThrownTypes() == null ? 1.297 + List.<JCExpression>nil() : 1.298 + make.Types(lambdaType.getThrownTypes()), 1.299 + null, 1.300 + null); 1.301 + lambdaDecl.sym = sym; 1.302 + lambdaDecl.type = lambdaType; 1.303 + 1.304 + //translate lambda body 1.305 + //As the lambda body is translated, all references to lambda locals, 1.306 + //captured variables, enclosing members are adjusted accordingly 1.307 + //to refer to the static method parameters (rather than i.e. acessing to 1.308 + //captured members directly). 1.309 + lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl)); 1.310 + 1.311 + //Add the method to the list of methods to be added to this class. 1.312 + kInfo.addMethod(lambdaDecl); 1.313 + 1.314 + //now that we have generated a method for the lambda expression, 1.315 + //we can translate the lambda into a method reference pointing to the newly 1.316 + //created method. 1.317 + // 1.318 + //Note that we need to adjust the method handle so that it will match the 1.319 + //signature of the SAM descriptor - this means that the method reference 1.320 + //should be added the following synthetic arguments: 1.321 + // 1.322 + // * the "this" argument if it is an instance method 1.323 + // * enclosing locals captured by the lambda expression 1.324 + 1.325 + ListBuffer<JCExpression> syntheticInits = new ListBuffer<>(); 1.326 + 1.327 + if (!sym.isStatic()) { 1.328 + syntheticInits.append(makeThis( 1.329 + sym.owner.enclClass().asType(), 1.330 + localContext.owner.enclClass())); 1.331 + } 1.332 + 1.333 + //add captured locals 1.334 + for (Symbol fv : localContext.getSymbolMap(CAPTURED_VAR).keySet()) { 1.335 + if (fv != localContext.self) { 1.336 + JCTree captured_local = make.Ident(fv).setType(fv.type); 1.337 + syntheticInits.append((JCExpression) captured_local); 1.338 + } 1.339 + } 1.340 + 1.341 + //then, determine the arguments to the indy call 1.342 + List<JCExpression> indy_args = translate(syntheticInits.toList(), localContext.prev); 1.343 + 1.344 + //build a sam instance using an indy call to the meta-factory 1.345 + int refKind = referenceKind(sym); 1.346 + 1.347 + //convert to an invokedynamic call 1.348 + result = makeMetafactoryIndyCall(context, refKind, sym, indy_args); 1.349 + } 1.350 + 1.351 + private JCIdent makeThis(Type type, Symbol owner) { 1.352 + VarSymbol _this = new VarSymbol(PARAMETER | FINAL | SYNTHETIC, 1.353 + names._this, 1.354 + type, 1.355 + owner); 1.356 + return make.Ident(_this); 1.357 + } 1.358 + 1.359 + /** 1.360 + * Translate a method reference into an invokedynamic call to the 1.361 + * meta-factory. 1.362 + * @param tree 1.363 + */ 1.364 + @Override 1.365 + public void visitReference(JCMemberReference tree) { 1.366 + ReferenceTranslationContext localContext = (ReferenceTranslationContext)context; 1.367 + 1.368 + //first determine the method symbol to be used to generate the sam instance 1.369 + //this is either the method reference symbol, or the bridged reference symbol 1.370 + Symbol refSym = localContext.needsBridge() 1.371 + ? localContext.bridgeSym 1.372 + : localContext.isSignaturePolymorphic() 1.373 + ? localContext.sigPolySym 1.374 + : tree.sym; 1.375 + 1.376 + //build the bridge method, if needed 1.377 + if (localContext.needsBridge()) { 1.378 + bridgeMemberReference(tree, localContext); 1.379 + } 1.380 + 1.381 + //the qualifying expression is treated as a special captured arg 1.382 + JCExpression init; 1.383 + switch(tree.kind) { 1.384 + 1.385 + case IMPLICIT_INNER: /** Inner :: new */ 1.386 + case SUPER: /** super :: instMethod */ 1.387 + init = makeThis( 1.388 + localContext.owner.enclClass().asType(), 1.389 + localContext.owner.enclClass()); 1.390 + break; 1.391 + 1.392 + case BOUND: /** Expr :: instMethod */ 1.393 + init = tree.getQualifierExpression(); 1.394 + init = attr.makeNullCheck(init); 1.395 + break; 1.396 + 1.397 + case UNBOUND: /** Type :: instMethod */ 1.398 + case STATIC: /** Type :: staticMethod */ 1.399 + case TOPLEVEL: /** Top level :: new */ 1.400 + case ARRAY_CTOR: /** ArrayType :: new */ 1.401 + init = null; 1.402 + break; 1.403 + 1.404 + default: 1.405 + throw new InternalError("Should not have an invalid kind"); 1.406 + } 1.407 + 1.408 + List<JCExpression> indy_args = init==null? List.<JCExpression>nil() : translate(List.of(init), localContext.prev); 1.409 + 1.410 + 1.411 + //build a sam instance using an indy call to the meta-factory 1.412 + result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args); 1.413 + } 1.414 + 1.415 + /** 1.416 + * Translate identifiers within a lambda to the mapped identifier 1.417 + * @param tree 1.418 + */ 1.419 + @Override 1.420 + public void visitIdent(JCIdent tree) { 1.421 + if (context == null || !analyzer.lambdaIdentSymbolFilter(tree.sym)) { 1.422 + super.visitIdent(tree); 1.423 + } else { 1.424 + int prevPos = make.pos; 1.425 + try { 1.426 + make.at(tree); 1.427 + 1.428 + LambdaTranslationContext lambdaContext = (LambdaTranslationContext) context; 1.429 + JCTree ltree = lambdaContext.translate(tree); 1.430 + if (ltree != null) { 1.431 + result = ltree; 1.432 + } else { 1.433 + //access to untranslated symbols (i.e. compile-time constants, 1.434 + //members defined inside the lambda body, etc.) ) 1.435 + super.visitIdent(tree); 1.436 + } 1.437 + } finally { 1.438 + make.at(prevPos); 1.439 + } 1.440 + } 1.441 + } 1.442 + 1.443 + @Override 1.444 + public void visitVarDef(JCVariableDecl tree) { 1.445 + LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context; 1.446 + if (context != null && lambdaContext.getSymbolMap(LOCAL_VAR).containsKey(tree.sym)) { 1.447 + tree.init = translate(tree.init); 1.448 + tree.sym = (VarSymbol) lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym); 1.449 + result = tree; 1.450 + } else if (context != null && lambdaContext.getSymbolMap(TYPE_VAR).containsKey(tree.sym)) { 1.451 + JCExpression init = translate(tree.init); 1.452 + VarSymbol xsym = (VarSymbol)lambdaContext.getSymbolMap(TYPE_VAR).get(tree.sym); 1.453 + int prevPos = make.pos; 1.454 + try { 1.455 + result = make.at(tree).VarDef(xsym, init); 1.456 + } finally { 1.457 + make.at(prevPos); 1.458 + } 1.459 + // Replace the entered symbol for this variable 1.460 + Scope sc = tree.sym.owner.members(); 1.461 + if (sc != null) { 1.462 + sc.remove(tree.sym); 1.463 + sc.enter(xsym); 1.464 + } 1.465 + } else { 1.466 + super.visitVarDef(tree); 1.467 + } 1.468 + } 1.469 + 1.470 + // </editor-fold> 1.471 + 1.472 + // <editor-fold defaultstate="collapsed" desc="Translation helper methods"> 1.473 + 1.474 + private JCBlock makeLambdaBody(JCLambda tree, JCMethodDecl lambdaMethodDecl) { 1.475 + return tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION ? 1.476 + makeLambdaExpressionBody((JCExpression)tree.body, lambdaMethodDecl) : 1.477 + makeLambdaStatementBody((JCBlock)tree.body, lambdaMethodDecl, tree.canCompleteNormally); 1.478 + } 1.479 + 1.480 + private JCBlock makeLambdaExpressionBody(JCExpression expr, JCMethodDecl lambdaMethodDecl) { 1.481 + Type restype = lambdaMethodDecl.type.getReturnType(); 1.482 + boolean isLambda_void = expr.type.hasTag(VOID); 1.483 + boolean isTarget_void = restype.hasTag(VOID); 1.484 + boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type); 1.485 + int prevPos = make.pos; 1.486 + try { 1.487 + if (isTarget_void) { 1.488 + //target is void: 1.489 + // BODY; 1.490 + JCStatement stat = make.at(expr).Exec(expr); 1.491 + return make.Block(0, List.<JCStatement>of(stat)); 1.492 + } else if (isLambda_void && isTarget_Void) { 1.493 + //void to Void conversion: 1.494 + // BODY; return null; 1.495 + ListBuffer<JCStatement> stats = new ListBuffer<>(); 1.496 + stats.append(make.at(expr).Exec(expr)); 1.497 + stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType))); 1.498 + return make.Block(0, stats.toList()); 1.499 + } else { 1.500 + //non-void to non-void conversion: 1.501 + // return (TYPE)BODY; 1.502 + JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype); 1.503 + return make.at(retExpr).Block(0, List.<JCStatement>of(make.Return(retExpr))); 1.504 + } 1.505 + } finally { 1.506 + make.at(prevPos); 1.507 + } 1.508 + } 1.509 + 1.510 + private JCBlock makeLambdaStatementBody(JCBlock block, final JCMethodDecl lambdaMethodDecl, boolean completeNormally) { 1.511 + final Type restype = lambdaMethodDecl.type.getReturnType(); 1.512 + final boolean isTarget_void = restype.hasTag(VOID); 1.513 + boolean isTarget_Void = types.isSameType(restype, types.boxedClass(syms.voidType).type); 1.514 + 1.515 + class LambdaBodyTranslator extends TreeTranslator { 1.516 + 1.517 + @Override 1.518 + public void visitClassDef(JCClassDecl tree) { 1.519 + //do NOT recurse on any inner classes 1.520 + result = tree; 1.521 + } 1.522 + 1.523 + @Override 1.524 + public void visitLambda(JCLambda tree) { 1.525 + //do NOT recurse on any nested lambdas 1.526 + result = tree; 1.527 + } 1.528 + 1.529 + @Override 1.530 + public void visitReturn(JCReturn tree) { 1.531 + boolean isLambda_void = tree.expr == null; 1.532 + if (isTarget_void && !isLambda_void) { 1.533 + //Void to void conversion: 1.534 + // { TYPE $loc = RET-EXPR; return; } 1.535 + VarSymbol loc = makeSyntheticVar(0, names.fromString("$loc"), tree.expr.type, lambdaMethodDecl.sym); 1.536 + JCVariableDecl varDef = make.VarDef(loc, tree.expr); 1.537 + result = make.Block(0, List.<JCStatement>of(varDef, make.Return(null))); 1.538 + } else if (!isTarget_void || !isLambda_void) { 1.539 + //non-void to non-void conversion: 1.540 + // return (TYPE)RET-EXPR; 1.541 + tree.expr = transTypes.coerce(attrEnv, tree.expr, restype); 1.542 + result = tree; 1.543 + } else { 1.544 + result = tree; 1.545 + } 1.546 + 1.547 + } 1.548 + } 1.549 + 1.550 + JCBlock trans_block = new LambdaBodyTranslator().translate(block); 1.551 + if (completeNormally && isTarget_Void) { 1.552 + //there's no return statement and the lambda (possibly inferred) 1.553 + //return type is java.lang.Void; emit a synthetic return statement 1.554 + trans_block.stats = trans_block.stats.append(make.Return(make.Literal(BOT, null).setType(syms.botType))); 1.555 + } 1.556 + return trans_block; 1.557 + } 1.558 + 1.559 + private JCMethodDecl makeDeserializeMethod(Symbol kSym) { 1.560 + ListBuffer<JCCase> cases = new ListBuffer<>(); 1.561 + ListBuffer<JCBreak> breaks = new ListBuffer<>(); 1.562 + for (Map.Entry<String, ListBuffer<JCStatement>> entry : kInfo.deserializeCases.entrySet()) { 1.563 + JCBreak br = make.Break(null); 1.564 + breaks.add(br); 1.565 + List<JCStatement> stmts = entry.getValue().append(br).toList(); 1.566 + cases.add(make.Case(make.Literal(entry.getKey()), stmts)); 1.567 + } 1.568 + JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList()); 1.569 + for (JCBreak br : breaks) { 1.570 + br.target = sw; 1.571 + } 1.572 + JCBlock body = make.Block(0L, List.<JCStatement>of( 1.573 + sw, 1.574 + make.Throw(makeNewClass( 1.575 + syms.illegalArgumentExceptionType, 1.576 + List.<JCExpression>of(make.Literal("Invalid lambda deserialization")))))); 1.577 + JCMethodDecl deser = make.MethodDef(make.Modifiers(kInfo.deserMethodSym.flags()), 1.578 + names.deserializeLambda, 1.579 + make.QualIdent(kInfo.deserMethodSym.getReturnType().tsym), 1.580 + List.<JCTypeParameter>nil(), 1.581 + List.of(make.VarDef(kInfo.deserParamSym, null)), 1.582 + List.<JCExpression>nil(), 1.583 + body, 1.584 + null); 1.585 + deser.sym = kInfo.deserMethodSym; 1.586 + deser.type = kInfo.deserMethodSym.type; 1.587 + //System.err.printf("DESER: '%s'\n", deser); 1.588 + return deser; 1.589 + } 1.590 + 1.591 + /** Make an attributed class instance creation expression. 1.592 + * @param ctype The class type. 1.593 + * @param args The constructor arguments. 1.594 + * @param cons The constructor symbol 1.595 + */ 1.596 + JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) { 1.597 + JCNewClass tree = make.NewClass(null, 1.598 + null, make.QualIdent(ctype.tsym), args, null); 1.599 + tree.constructor = cons; 1.600 + tree.type = ctype; 1.601 + return tree; 1.602 + } 1.603 + 1.604 + /** Make an attributed class instance creation expression. 1.605 + * @param ctype The class type. 1.606 + * @param args The constructor arguments. 1.607 + */ 1.608 + JCNewClass makeNewClass(Type ctype, List<JCExpression> args) { 1.609 + return makeNewClass(ctype, args, 1.610 + rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil())); 1.611 + } 1.612 + 1.613 + private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym, 1.614 + DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) { 1.615 + String functionalInterfaceClass = classSig(targetType); 1.616 + String functionalInterfaceMethodName = samSym.getSimpleName().toString(); 1.617 + String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type)); 1.618 + String implClass = classSig(types.erasure(refSym.owner.type)); 1.619 + String implMethodName = refSym.getQualifiedName().toString(); 1.620 + String implMethodSignature = typeSig(types.erasure(refSym.type)); 1.621 + 1.622 + JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind)); 1.623 + ListBuffer<JCExpression> serArgs = new ListBuffer<>(); 1.624 + int i = 0; 1.625 + for (Type t : indyType.getParameterTypes()) { 1.626 + List<JCExpression> indexAsArg = new ListBuffer<JCExpression>().append(make.Literal(i)).toList(); 1.627 + List<Type> argTypes = new ListBuffer<Type>().append(syms.intType).toList(); 1.628 + serArgs.add(make.TypeCast(types.erasure(t), deserGetter("getCapturedArg", syms.objectType, argTypes, indexAsArg))); 1.629 + ++i; 1.630 + } 1.631 + JCStatement stmt = make.If( 1.632 + deserTest(deserTest(deserTest(deserTest(deserTest( 1.633 + kindTest, 1.634 + "getFunctionalInterfaceClass", functionalInterfaceClass), 1.635 + "getFunctionalInterfaceMethodName", functionalInterfaceMethodName), 1.636 + "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature), 1.637 + "getImplClass", implClass), 1.638 + "getImplMethodSignature", implMethodSignature), 1.639 + make.Return(makeIndyCall( 1.640 + pos, 1.641 + syms.lambdaMetafactory, 1.642 + names.altMetafactory, 1.643 + staticArgs, indyType, serArgs.toList(), samSym.name)), 1.644 + null); 1.645 + ListBuffer<JCStatement> stmts = kInfo.deserializeCases.get(implMethodName); 1.646 + if (stmts == null) { 1.647 + stmts = new ListBuffer<>(); 1.648 + kInfo.deserializeCases.put(implMethodName, stmts); 1.649 + } 1.650 + /**** 1.651 + System.err.printf("+++++++++++++++++\n"); 1.652 + System.err.printf("*functionalInterfaceClass: '%s'\n", functionalInterfaceClass); 1.653 + System.err.printf("*functionalInterfaceMethodName: '%s'\n", functionalInterfaceMethodName); 1.654 + System.err.printf("*functionalInterfaceMethodSignature: '%s'\n", functionalInterfaceMethodSignature); 1.655 + System.err.printf("*implMethodKind: %d\n", implMethodKind); 1.656 + System.err.printf("*implClass: '%s'\n", implClass); 1.657 + System.err.printf("*implMethodName: '%s'\n", implMethodName); 1.658 + System.err.printf("*implMethodSignature: '%s'\n", implMethodSignature); 1.659 + ****/ 1.660 + stmts.append(stmt); 1.661 + } 1.662 + 1.663 + private JCExpression eqTest(Type argType, JCExpression arg1, JCExpression arg2) { 1.664 + JCBinary testExpr = make.Binary(JCTree.Tag.EQ, arg1, arg2); 1.665 + testExpr.operator = rs.resolveBinaryOperator(null, JCTree.Tag.EQ, attrEnv, argType, argType); 1.666 + testExpr.setType(syms.booleanType); 1.667 + return testExpr; 1.668 + } 1.669 + 1.670 + private JCExpression deserTest(JCExpression prev, String func, String lit) { 1.671 + MethodType eqmt = new MethodType(List.of(syms.objectType), syms.booleanType, List.<Type>nil(), syms.methodClass); 1.672 + Symbol eqsym = rs.resolveQualifiedMethod(null, attrEnv, syms.objectType, names.equals, List.of(syms.objectType), List.<Type>nil()); 1.673 + JCMethodInvocation eqtest = make.Apply( 1.674 + List.<JCExpression>nil(), 1.675 + make.Select(deserGetter(func, syms.stringType), eqsym).setType(eqmt), 1.676 + List.<JCExpression>of(make.Literal(lit))); 1.677 + eqtest.setType(syms.booleanType); 1.678 + JCBinary compound = make.Binary(JCTree.Tag.AND, prev, eqtest); 1.679 + compound.operator = rs.resolveBinaryOperator(null, JCTree.Tag.AND, attrEnv, syms.booleanType, syms.booleanType); 1.680 + compound.setType(syms.booleanType); 1.681 + return compound; 1.682 + } 1.683 + 1.684 + private JCExpression deserGetter(String func, Type type) { 1.685 + return deserGetter(func, type, List.<Type>nil(), List.<JCExpression>nil()); 1.686 + } 1.687 + 1.688 + private JCExpression deserGetter(String func, Type type, List<Type> argTypes, List<JCExpression> args) { 1.689 + MethodType getmt = new MethodType(argTypes, type, List.<Type>nil(), syms.methodClass); 1.690 + Symbol getsym = rs.resolveQualifiedMethod(null, attrEnv, syms.serializedLambdaType, names.fromString(func), argTypes, List.<Type>nil()); 1.691 + return make.Apply( 1.692 + List.<JCExpression>nil(), 1.693 + make.Select(make.Ident(kInfo.deserParamSym).setType(syms.serializedLambdaType), getsym).setType(getmt), 1.694 + args).setType(type); 1.695 + } 1.696 + 1.697 + /** 1.698 + * Create new synthetic method with given flags, name, type, owner 1.699 + */ 1.700 + private MethodSymbol makePrivateSyntheticMethod(long flags, Name name, Type type, Symbol owner) { 1.701 + return new MethodSymbol(flags | SYNTHETIC | PRIVATE, name, type, owner); 1.702 + } 1.703 + 1.704 + /** 1.705 + * Create new synthetic variable with given flags, name, type, owner 1.706 + */ 1.707 + private VarSymbol makeSyntheticVar(long flags, String name, Type type, Symbol owner) { 1.708 + return makeSyntheticVar(flags, names.fromString(name), type, owner); 1.709 + } 1.710 + 1.711 + /** 1.712 + * Create new synthetic variable with given flags, name, type, owner 1.713 + */ 1.714 + private VarSymbol makeSyntheticVar(long flags, Name name, Type type, Symbol owner) { 1.715 + return new VarSymbol(flags | SYNTHETIC, name, type, owner); 1.716 + } 1.717 + 1.718 + /** 1.719 + * Set varargsElement field on a given tree (must be either a new class tree 1.720 + * or a method call tree) 1.721 + */ 1.722 + private void setVarargsIfNeeded(JCTree tree, Type varargsElement) { 1.723 + if (varargsElement != null) { 1.724 + switch (tree.getTag()) { 1.725 + case APPLY: ((JCMethodInvocation)tree).varargsElement = varargsElement; break; 1.726 + case NEWCLASS: ((JCNewClass)tree).varargsElement = varargsElement; break; 1.727 + default: throw new AssertionError(); 1.728 + } 1.729 + } 1.730 + } 1.731 + 1.732 + /** 1.733 + * Convert method/constructor arguments by inserting appropriate cast 1.734 + * as required by type-erasure - this is needed when bridging a lambda/method 1.735 + * reference, as the bridged signature might require downcast to be compatible 1.736 + * with the generated signature. 1.737 + */ 1.738 + private List<JCExpression> convertArgs(Symbol meth, List<JCExpression> args, Type varargsElement) { 1.739 + Assert.check(meth.kind == Kinds.MTH); 1.740 + List<Type> formals = types.erasure(meth.type).getParameterTypes(); 1.741 + if (varargsElement != null) { 1.742 + Assert.check((meth.flags() & VARARGS) != 0); 1.743 + } 1.744 + return transTypes.translateArgs(args, formals, varargsElement, attrEnv); 1.745 + } 1.746 + 1.747 + // </editor-fold> 1.748 + 1.749 + /** 1.750 + * Generate an adapter method "bridge" for a method reference which cannot 1.751 + * be used directly. 1.752 + */ 1.753 + private class MemberReferenceBridger { 1.754 + 1.755 + private final JCMemberReference tree; 1.756 + private final ReferenceTranslationContext localContext; 1.757 + private final ListBuffer<JCExpression> args = new ListBuffer<>(); 1.758 + private final ListBuffer<JCVariableDecl> params = new ListBuffer<>(); 1.759 + 1.760 + MemberReferenceBridger(JCMemberReference tree, ReferenceTranslationContext localContext) { 1.761 + this.tree = tree; 1.762 + this.localContext = localContext; 1.763 + } 1.764 + 1.765 + /** 1.766 + * Generate the bridge 1.767 + */ 1.768 + JCMethodDecl bridge() { 1.769 + int prevPos = make.pos; 1.770 + try { 1.771 + make.at(tree); 1.772 + Type samDesc = localContext.bridgedRefSig(); 1.773 + List<Type> samPTypes = samDesc.getParameterTypes(); 1.774 + 1.775 + //an extra argument is prepended to the signature of the bridge in case 1.776 + //the member reference is an instance method reference (in which case 1.777 + //the receiver expression is passed to the bridge itself). 1.778 + Type recType = null; 1.779 + switch (tree.kind) { 1.780 + case IMPLICIT_INNER: 1.781 + recType = tree.sym.owner.type.getEnclosingType(); 1.782 + break; 1.783 + case BOUND: 1.784 + recType = tree.getQualifierExpression().type; 1.785 + break; 1.786 + case UNBOUND: 1.787 + recType = samPTypes.head; 1.788 + samPTypes = samPTypes.tail; 1.789 + break; 1.790 + } 1.791 + 1.792 + //generate the parameter list for the bridged member reference - the 1.793 + //bridge signature will match the signature of the target sam descriptor 1.794 + 1.795 + VarSymbol rcvr = (recType == null) 1.796 + ? null 1.797 + : addParameter("rec$", recType, false); 1.798 + 1.799 + List<Type> refPTypes = tree.sym.type.getParameterTypes(); 1.800 + int refSize = refPTypes.size(); 1.801 + int samSize = samPTypes.size(); 1.802 + // Last parameter to copy from referenced method 1.803 + int last = localContext.needsVarArgsConversion() ? refSize - 1 : refSize; 1.804 + 1.805 + List<Type> l = refPTypes; 1.806 + // Use parameter types of the referenced method, excluding final var args 1.807 + for (int i = 0; l.nonEmpty() && i < last; ++i) { 1.808 + addParameter("x$" + i, l.head, true); 1.809 + l = l.tail; 1.810 + } 1.811 + // Flatten out the var args 1.812 + for (int i = last; i < samSize; ++i) { 1.813 + addParameter("xva$" + i, tree.varargsElement, true); 1.814 + } 1.815 + 1.816 + //generate the bridge method declaration 1.817 + JCMethodDecl bridgeDecl = make.MethodDef(make.Modifiers(localContext.bridgeSym.flags()), 1.818 + localContext.bridgeSym.name, 1.819 + make.QualIdent(samDesc.getReturnType().tsym), 1.820 + List.<JCTypeParameter>nil(), 1.821 + params.toList(), 1.822 + tree.sym.type.getThrownTypes() == null 1.823 + ? List.<JCExpression>nil() 1.824 + : make.Types(tree.sym.type.getThrownTypes()), 1.825 + null, 1.826 + null); 1.827 + bridgeDecl.sym = (MethodSymbol) localContext.bridgeSym; 1.828 + bridgeDecl.type = localContext.bridgeSym.type = 1.829 + types.createMethodTypeWithParameters(samDesc, TreeInfo.types(params.toList())); 1.830 + 1.831 + //bridge method body generation - this can be either a method call or a 1.832 + //new instance creation expression, depending on the member reference kind 1.833 + JCExpression bridgeExpr = (tree.getMode() == ReferenceMode.INVOKE) 1.834 + ? bridgeExpressionInvoke(makeReceiver(rcvr)) 1.835 + : bridgeExpressionNew(); 1.836 + 1.837 + //the body is either a return expression containing a method call, 1.838 + //or the method call itself, depending on whether the return type of 1.839 + //the bridge is non-void/void. 1.840 + bridgeDecl.body = makeLambdaExpressionBody(bridgeExpr, bridgeDecl); 1.841 + 1.842 + return bridgeDecl; 1.843 + } finally { 1.844 + make.at(prevPos); 1.845 + } 1.846 + } 1.847 + //where 1.848 + private JCExpression makeReceiver(VarSymbol rcvr) { 1.849 + if (rcvr == null) return null; 1.850 + JCExpression rcvrExpr = make.Ident(rcvr); 1.851 + Type rcvrType = tree.sym.enclClass().type; 1.852 + if (!rcvr.type.tsym.isSubClass(rcvrType.tsym, types)) { 1.853 + rcvrExpr = make.TypeCast(make.Type(rcvrType), rcvrExpr).setType(rcvrType); 1.854 + } 1.855 + return rcvrExpr; 1.856 + } 1.857 + 1.858 + /** 1.859 + * determine the receiver of the bridged method call - the receiver can 1.860 + * be either the synthetic receiver parameter or a type qualifier; the 1.861 + * original qualifier expression is never used here, as it might refer 1.862 + * to symbols not available in the static context of the bridge 1.863 + */ 1.864 + private JCExpression bridgeExpressionInvoke(JCExpression rcvr) { 1.865 + JCExpression qualifier = 1.866 + tree.sym.isStatic() ? 1.867 + make.Type(tree.sym.owner.type) : 1.868 + (rcvr != null) ? 1.869 + rcvr : 1.870 + tree.getQualifierExpression(); 1.871 + 1.872 + //create the qualifier expression 1.873 + JCFieldAccess select = make.Select(qualifier, tree.sym.name); 1.874 + select.sym = tree.sym; 1.875 + select.type = tree.sym.erasure(types); 1.876 + 1.877 + //create the method call expression 1.878 + JCExpression apply = make.Apply(List.<JCExpression>nil(), select, 1.879 + convertArgs(tree.sym, args.toList(), tree.varargsElement)). 1.880 + setType(tree.sym.erasure(types).getReturnType()); 1.881 + 1.882 + apply = transTypes.coerce(apply, localContext.generatedRefSig().getReturnType()); 1.883 + setVarargsIfNeeded(apply, tree.varargsElement); 1.884 + return apply; 1.885 + } 1.886 + 1.887 + /** 1.888 + * the enclosing expression is either 'null' (no enclosing type) or set 1.889 + * to the first bridge synthetic parameter 1.890 + */ 1.891 + private JCExpression bridgeExpressionNew() { 1.892 + if (tree.kind == ReferenceKind.ARRAY_CTOR) { 1.893 + //create the array creation expression 1.894 + JCNewArray newArr = make.NewArray( 1.895 + make.Type(types.elemtype(tree.getQualifierExpression().type)), 1.896 + List.of(make.Ident(params.first())), 1.897 + null); 1.898 + newArr.type = tree.getQualifierExpression().type; 1.899 + return newArr; 1.900 + } else { 1.901 + JCExpression encl = null; 1.902 + switch (tree.kind) { 1.903 + case UNBOUND: 1.904 + case IMPLICIT_INNER: 1.905 + encl = make.Ident(params.first()); 1.906 + } 1.907 + 1.908 + //create the instance creation expression 1.909 + JCNewClass newClass = make.NewClass(encl, 1.910 + List.<JCExpression>nil(), 1.911 + make.Type(tree.getQualifierExpression().type), 1.912 + convertArgs(tree.sym, args.toList(), tree.varargsElement), 1.913 + null); 1.914 + newClass.constructor = tree.sym; 1.915 + newClass.constructorType = tree.sym.erasure(types); 1.916 + newClass.type = tree.getQualifierExpression().type; 1.917 + setVarargsIfNeeded(newClass, tree.varargsElement); 1.918 + return newClass; 1.919 + } 1.920 + } 1.921 + 1.922 + private VarSymbol addParameter(String name, Type p, boolean genArg) { 1.923 + VarSymbol vsym = new VarSymbol(0, names.fromString(name), p, localContext.bridgeSym); 1.924 + params.append(make.VarDef(vsym, null)); 1.925 + if (genArg) { 1.926 + args.append(make.Ident(vsym)); 1.927 + } 1.928 + return vsym; 1.929 + } 1.930 + } 1.931 + 1.932 + /** 1.933 + * Bridges a member reference - this is needed when: 1.934 + * * Var args in the referenced method need to be flattened away 1.935 + * * super is used 1.936 + */ 1.937 + private void bridgeMemberReference(JCMemberReference tree, ReferenceTranslationContext localContext) { 1.938 + kInfo.addMethod(new MemberReferenceBridger(tree, localContext).bridge()); 1.939 + } 1.940 + 1.941 + private MethodType typeToMethodType(Type mt) { 1.942 + Type type = types.erasure(mt); 1.943 + return new MethodType(type.getParameterTypes(), 1.944 + type.getReturnType(), 1.945 + type.getThrownTypes(), 1.946 + syms.methodClass); 1.947 + } 1.948 + 1.949 + /** 1.950 + * Generate an indy method call to the meta factory 1.951 + */ 1.952 + private JCExpression makeMetafactoryIndyCall(TranslationContext<?> context, 1.953 + int refKind, Symbol refSym, List<JCExpression> indy_args) { 1.954 + JCFunctionalExpression tree = context.tree; 1.955 + //determine the static bsm args 1.956 + MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.type.tsym); 1.957 + List<Object> staticArgs = List.<Object>of( 1.958 + typeToMethodType(samSym.type), 1.959 + new Pool.MethodHandle(refKind, refSym, types), 1.960 + typeToMethodType(tree.getDescriptorType(types))); 1.961 + 1.962 + //computed indy arg types 1.963 + ListBuffer<Type> indy_args_types = new ListBuffer<>(); 1.964 + for (JCExpression arg : indy_args) { 1.965 + indy_args_types.append(arg.type); 1.966 + } 1.967 + 1.968 + //finally, compute the type of the indy call 1.969 + MethodType indyType = new MethodType(indy_args_types.toList(), 1.970 + tree.type, 1.971 + List.<Type>nil(), 1.972 + syms.methodClass); 1.973 + 1.974 + Name metafactoryName = context.needsAltMetafactory() ? 1.975 + names.altMetafactory : names.metafactory; 1.976 + 1.977 + if (context.needsAltMetafactory()) { 1.978 + ListBuffer<Object> markers = new ListBuffer<>(); 1.979 + for (Type t : tree.targets.tail) { 1.980 + if (t.tsym != syms.serializableType.tsym) { 1.981 + markers.append(t.tsym); 1.982 + } 1.983 + } 1.984 + int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0; 1.985 + boolean hasMarkers = markers.nonEmpty(); 1.986 + boolean hasBridges = context.bridges.nonEmpty(); 1.987 + if (hasMarkers) { 1.988 + flags |= FLAG_MARKERS; 1.989 + } 1.990 + if (hasBridges) { 1.991 + flags |= FLAG_BRIDGES; 1.992 + } 1.993 + staticArgs = staticArgs.append(flags); 1.994 + if (hasMarkers) { 1.995 + staticArgs = staticArgs.append(markers.length()); 1.996 + staticArgs = staticArgs.appendList(markers.toList()); 1.997 + } 1.998 + if (hasBridges) { 1.999 + staticArgs = staticArgs.append(context.bridges.length() - 1); 1.1000 + for (Symbol s : context.bridges) { 1.1001 + Type s_erasure = s.erasure(types); 1.1002 + if (!types.isSameType(s_erasure, samSym.erasure(types))) { 1.1003 + staticArgs = staticArgs.append(s.erasure(types)); 1.1004 + } 1.1005 + } 1.1006 + } 1.1007 + if (context.isSerializable()) { 1.1008 + int prevPos = make.pos; 1.1009 + try { 1.1010 + make.at(kInfo.clazz); 1.1011 + addDeserializationCase(refKind, refSym, tree.type, samSym, 1.1012 + tree, staticArgs, indyType); 1.1013 + } finally { 1.1014 + make.at(prevPos); 1.1015 + } 1.1016 + } 1.1017 + } 1.1018 + 1.1019 + return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name); 1.1020 + } 1.1021 + 1.1022 + /** 1.1023 + * Generate an indy method call with given name, type and static bootstrap 1.1024 + * arguments types 1.1025 + */ 1.1026 + private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName, 1.1027 + List<Object> staticArgs, MethodType indyType, List<JCExpression> indyArgs, 1.1028 + Name methName) { 1.1029 + int prevPos = make.pos; 1.1030 + try { 1.1031 + make.at(pos); 1.1032 + List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType, 1.1033 + syms.stringType, 1.1034 + syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs)); 1.1035 + 1.1036 + Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site, 1.1037 + bsmName, bsm_staticArgs, List.<Type>nil()); 1.1038 + 1.1039 + DynamicMethodSymbol dynSym = 1.1040 + new DynamicMethodSymbol(methName, 1.1041 + syms.noSymbol, 1.1042 + bsm.isStatic() ? 1.1043 + ClassFile.REF_invokeStatic : 1.1044 + ClassFile.REF_invokeVirtual, 1.1045 + (MethodSymbol)bsm, 1.1046 + indyType, 1.1047 + staticArgs.toArray()); 1.1048 + 1.1049 + JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName); 1.1050 + qualifier.sym = dynSym; 1.1051 + qualifier.type = indyType.getReturnType(); 1.1052 + 1.1053 + JCMethodInvocation proxyCall = make.Apply(List.<JCExpression>nil(), qualifier, indyArgs); 1.1054 + proxyCall.type = indyType.getReturnType(); 1.1055 + return proxyCall; 1.1056 + } finally { 1.1057 + make.at(prevPos); 1.1058 + } 1.1059 + } 1.1060 + //where 1.1061 + private List<Type> bsmStaticArgToTypes(List<Object> args) { 1.1062 + ListBuffer<Type> argtypes = new ListBuffer<>(); 1.1063 + for (Object arg : args) { 1.1064 + argtypes.append(bsmStaticArgToType(arg)); 1.1065 + } 1.1066 + return argtypes.toList(); 1.1067 + } 1.1068 + 1.1069 + private Type bsmStaticArgToType(Object arg) { 1.1070 + Assert.checkNonNull(arg); 1.1071 + if (arg instanceof ClassSymbol) { 1.1072 + return syms.classType; 1.1073 + } else if (arg instanceof Integer) { 1.1074 + return syms.intType; 1.1075 + } else if (arg instanceof Long) { 1.1076 + return syms.longType; 1.1077 + } else if (arg instanceof Float) { 1.1078 + return syms.floatType; 1.1079 + } else if (arg instanceof Double) { 1.1080 + return syms.doubleType; 1.1081 + } else if (arg instanceof String) { 1.1082 + return syms.stringType; 1.1083 + } else if (arg instanceof Pool.MethodHandle) { 1.1084 + return syms.methodHandleType; 1.1085 + } else if (arg instanceof MethodType) { 1.1086 + return syms.methodTypeType; 1.1087 + } else { 1.1088 + Assert.error("bad static arg " + arg.getClass()); 1.1089 + return null; 1.1090 + } 1.1091 + } 1.1092 + 1.1093 + /** 1.1094 + * Get the opcode associated with this method reference 1.1095 + */ 1.1096 + private int referenceKind(Symbol refSym) { 1.1097 + if (refSym.isConstructor()) { 1.1098 + return ClassFile.REF_newInvokeSpecial; 1.1099 + } else { 1.1100 + if (refSym.isStatic()) { 1.1101 + return ClassFile.REF_invokeStatic; 1.1102 + } else if ((refSym.flags() & PRIVATE) != 0) { 1.1103 + return ClassFile.REF_invokeSpecial; 1.1104 + } else if (refSym.enclClass().isInterface()) { 1.1105 + return ClassFile.REF_invokeInterface; 1.1106 + } else { 1.1107 + return ClassFile.REF_invokeVirtual; 1.1108 + } 1.1109 + } 1.1110 + } 1.1111 + 1.1112 + // <editor-fold defaultstate="collapsed" desc="Lambda/reference analyzer"> 1.1113 + /** 1.1114 + * This visitor collects information about translation of a lambda expression. 1.1115 + * More specifically, it keeps track of the enclosing contexts and captured locals 1.1116 + * accessed by the lambda being translated (as well as other useful info). 1.1117 + * It also translates away problems for LambdaToMethod. 1.1118 + */ 1.1119 + class LambdaAnalyzerPreprocessor extends TreeTranslator { 1.1120 + 1.1121 + /** the frame stack - used to reconstruct translation info about enclosing scopes */ 1.1122 + private List<Frame> frameStack; 1.1123 + 1.1124 + /** 1.1125 + * keep the count of lambda expression (used to generate unambiguous 1.1126 + * names) 1.1127 + */ 1.1128 + private int lambdaCount = 0; 1.1129 + 1.1130 + /** 1.1131 + * keep the count of lambda expression defined in given context (used to 1.1132 + * generate unambiguous names for serializable lambdas) 1.1133 + */ 1.1134 + private class SyntheticMethodNameCounter { 1.1135 + private Map<String, Integer> map = new HashMap<>(); 1.1136 + int getIndex(StringBuilder buf) { 1.1137 + String temp = buf.toString(); 1.1138 + Integer count = map.get(temp); 1.1139 + if (count == null) { 1.1140 + count = 0; 1.1141 + } 1.1142 + ++count; 1.1143 + map.put(temp, count); 1.1144 + return count; 1.1145 + } 1.1146 + } 1.1147 + private SyntheticMethodNameCounter syntheticMethodNameCounts = 1.1148 + new SyntheticMethodNameCounter(); 1.1149 + 1.1150 + private Map<Symbol, JCClassDecl> localClassDefs; 1.1151 + 1.1152 + /** 1.1153 + * maps for fake clinit symbols to be used as owners of lambda occurring in 1.1154 + * a static var init context 1.1155 + */ 1.1156 + private Map<ClassSymbol, Symbol> clinits = 1.1157 + new HashMap<ClassSymbol, Symbol>(); 1.1158 + 1.1159 + private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) { 1.1160 + frameStack = List.nil(); 1.1161 + localClassDefs = new HashMap<Symbol, JCClassDecl>(); 1.1162 + return translate(tree); 1.1163 + } 1.1164 + 1.1165 + @Override 1.1166 + public void visitBlock(JCBlock tree) { 1.1167 + List<Frame> prevStack = frameStack; 1.1168 + try { 1.1169 + if (frameStack.nonEmpty() && frameStack.head.tree.hasTag(CLASSDEF)) { 1.1170 + frameStack = frameStack.prepend(new Frame(tree)); 1.1171 + } 1.1172 + super.visitBlock(tree); 1.1173 + } 1.1174 + finally { 1.1175 + frameStack = prevStack; 1.1176 + } 1.1177 + } 1.1178 + 1.1179 + @Override 1.1180 + public void visitClassDef(JCClassDecl tree) { 1.1181 + List<Frame> prevStack = frameStack; 1.1182 + SyntheticMethodNameCounter prevSyntheticMethodNameCounts = 1.1183 + syntheticMethodNameCounts; 1.1184 + Map<ClassSymbol, Symbol> prevClinits = clinits; 1.1185 + DiagnosticSource prevSource = log.currentSource(); 1.1186 + try { 1.1187 + log.useSource(tree.sym.sourcefile); 1.1188 + syntheticMethodNameCounts = new SyntheticMethodNameCounter(); 1.1189 + prevClinits = new HashMap<ClassSymbol, Symbol>(); 1.1190 + if (tree.sym.owner.kind == MTH) { 1.1191 + localClassDefs.put(tree.sym, tree); 1.1192 + } 1.1193 + if (directlyEnclosingLambda() != null) { 1.1194 + tree.sym.owner = owner(); 1.1195 + if (tree.sym.hasOuterInstance()) { 1.1196 + //if a class is defined within a lambda, the lambda must capture 1.1197 + //its enclosing instance (if any) 1.1198 + TranslationContext<?> localContext = context(); 1.1199 + while (localContext != null) { 1.1200 + if (localContext.tree.getTag() == LAMBDA) { 1.1201 + ((LambdaTranslationContext)localContext) 1.1202 + .addSymbol(tree.sym.type.getEnclosingType().tsym, CAPTURED_THIS); 1.1203 + } 1.1204 + localContext = localContext.prev; 1.1205 + } 1.1206 + } 1.1207 + } 1.1208 + frameStack = frameStack.prepend(new Frame(tree)); 1.1209 + super.visitClassDef(tree); 1.1210 + } 1.1211 + finally { 1.1212 + log.useSource(prevSource.getFile()); 1.1213 + frameStack = prevStack; 1.1214 + syntheticMethodNameCounts = prevSyntheticMethodNameCounts; 1.1215 + clinits = prevClinits; 1.1216 + } 1.1217 + } 1.1218 + 1.1219 + @Override 1.1220 + public void visitIdent(JCIdent tree) { 1.1221 + if (context() != null && lambdaIdentSymbolFilter(tree.sym)) { 1.1222 + if (tree.sym.kind == VAR && 1.1223 + tree.sym.owner.kind == MTH && 1.1224 + tree.type.constValue() == null) { 1.1225 + TranslationContext<?> localContext = context(); 1.1226 + while (localContext != null) { 1.1227 + if (localContext.tree.getTag() == LAMBDA) { 1.1228 + JCTree block = capturedDecl(localContext.depth, tree.sym); 1.1229 + if (block == null) break; 1.1230 + ((LambdaTranslationContext)localContext) 1.1231 + .addSymbol(tree.sym, CAPTURED_VAR); 1.1232 + } 1.1233 + localContext = localContext.prev; 1.1234 + } 1.1235 + } else if (tree.sym.owner.kind == TYP) { 1.1236 + TranslationContext<?> localContext = context(); 1.1237 + while (localContext != null) { 1.1238 + if (localContext.tree.hasTag(LAMBDA)) { 1.1239 + JCTree block = capturedDecl(localContext.depth, tree.sym); 1.1240 + if (block == null) break; 1.1241 + switch (block.getTag()) { 1.1242 + case CLASSDEF: 1.1243 + JCClassDecl cdecl = (JCClassDecl)block; 1.1244 + ((LambdaTranslationContext)localContext) 1.1245 + .addSymbol(cdecl.sym, CAPTURED_THIS); 1.1246 + break; 1.1247 + default: 1.1248 + Assert.error("bad block kind"); 1.1249 + } 1.1250 + } 1.1251 + localContext = localContext.prev; 1.1252 + } 1.1253 + } 1.1254 + } 1.1255 + super.visitIdent(tree); 1.1256 + } 1.1257 + 1.1258 + @Override 1.1259 + public void visitLambda(JCLambda tree) { 1.1260 + List<Frame> prevStack = frameStack; 1.1261 + try { 1.1262 + LambdaTranslationContext context = (LambdaTranslationContext)makeLambdaContext(tree); 1.1263 + frameStack = frameStack.prepend(new Frame(tree)); 1.1264 + for (JCVariableDecl param : tree.params) { 1.1265 + context.addSymbol(param.sym, PARAM); 1.1266 + frameStack.head.addLocal(param.sym); 1.1267 + } 1.1268 + contextMap.put(tree, context); 1.1269 + super.visitLambda(tree); 1.1270 + context.complete(); 1.1271 + } 1.1272 + finally { 1.1273 + frameStack = prevStack; 1.1274 + } 1.1275 + } 1.1276 + 1.1277 + @Override 1.1278 + public void visitMethodDef(JCMethodDecl tree) { 1.1279 + List<Frame> prevStack = frameStack; 1.1280 + try { 1.1281 + frameStack = frameStack.prepend(new Frame(tree)); 1.1282 + super.visitMethodDef(tree); 1.1283 + } 1.1284 + finally { 1.1285 + frameStack = prevStack; 1.1286 + } 1.1287 + } 1.1288 + 1.1289 + @Override 1.1290 + public void visitNewClass(JCNewClass tree) { 1.1291 + TypeSymbol def = tree.type.tsym; 1.1292 + boolean inReferencedClass = currentlyInClass(def); 1.1293 + boolean isLocal = def.isLocal(); 1.1294 + if ((inReferencedClass && isLocal || lambdaNewClassFilter(context(), tree))) { 1.1295 + TranslationContext<?> localContext = context(); 1.1296 + while (localContext != null) { 1.1297 + if (localContext.tree.getTag() == LAMBDA) { 1.1298 + ((LambdaTranslationContext)localContext) 1.1299 + .addSymbol(tree.type.getEnclosingType().tsym, CAPTURED_THIS); 1.1300 + } 1.1301 + localContext = localContext.prev; 1.1302 + } 1.1303 + } 1.1304 + if (context() != null && !inReferencedClass && isLocal) { 1.1305 + LambdaTranslationContext lambdaContext = (LambdaTranslationContext)context(); 1.1306 + captureLocalClassDefs(def, lambdaContext); 1.1307 + } 1.1308 + super.visitNewClass(tree); 1.1309 + } 1.1310 + //where 1.1311 + void captureLocalClassDefs(Symbol csym, final LambdaTranslationContext lambdaContext) { 1.1312 + JCClassDecl localCDef = localClassDefs.get(csym); 1.1313 + if (localCDef != null && lambdaContext.freeVarProcessedLocalClasses.add(csym)) { 1.1314 + BasicFreeVarCollector fvc = lower.new BasicFreeVarCollector() { 1.1315 + @Override 1.1316 + void addFreeVars(ClassSymbol c) { 1.1317 + captureLocalClassDefs(c, lambdaContext); 1.1318 + } 1.1319 + @Override 1.1320 + void visitSymbol(Symbol sym) { 1.1321 + if (sym.kind == VAR && 1.1322 + sym.owner.kind == MTH && 1.1323 + ((VarSymbol)sym).getConstValue() == null) { 1.1324 + TranslationContext<?> localContext = context(); 1.1325 + while (localContext != null) { 1.1326 + if (localContext.tree.getTag() == LAMBDA) { 1.1327 + JCTree block = capturedDecl(localContext.depth, sym); 1.1328 + if (block == null) break; 1.1329 + ((LambdaTranslationContext)localContext).addSymbol(sym, CAPTURED_VAR); 1.1330 + } 1.1331 + localContext = localContext.prev; 1.1332 + } 1.1333 + } 1.1334 + } 1.1335 + }; 1.1336 + fvc.scan(localCDef); 1.1337 + } 1.1338 + } 1.1339 + //where 1.1340 + boolean currentlyInClass(Symbol csym) { 1.1341 + for (Frame frame : frameStack) { 1.1342 + if (frame.tree.hasTag(JCTree.Tag.CLASSDEF)) { 1.1343 + JCClassDecl cdef = (JCClassDecl) frame.tree; 1.1344 + if (cdef.sym == csym) { 1.1345 + return true; 1.1346 + } 1.1347 + } 1.1348 + } 1.1349 + return false; 1.1350 + } 1.1351 + 1.1352 + /** 1.1353 + * Method references to local class constructors, may, if the local 1.1354 + * class references local variables, have implicit constructor 1.1355 + * parameters added in Lower; As a result, the invokedynamic bootstrap 1.1356 + * information added in the LambdaToMethod pass will have the wrong 1.1357 + * signature. Hooks between Lower and LambdaToMethod have been added to 1.1358 + * handle normal "new" in this case. This visitor converts potentially 1.1359 + * effected method references into a lambda containing a normal "new" of 1.1360 + * the class. 1.1361 + * 1.1362 + * @param tree 1.1363 + */ 1.1364 + @Override 1.1365 + public void visitReference(JCMemberReference tree) { 1.1366 + if (tree.getMode() == ReferenceMode.NEW 1.1367 + && tree.kind != ReferenceKind.ARRAY_CTOR 1.1368 + && tree.sym.owner.isLocal()) { 1.1369 + MethodSymbol consSym = (MethodSymbol) tree.sym; 1.1370 + List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes(); 1.1371 + Type classType = consSym.owner.type; 1.1372 + 1.1373 + // Build lambda parameters 1.1374 + // partially cloned from TreeMaker.Params until 8014021 is fixed 1.1375 + Symbol owner = owner(); 1.1376 + ListBuffer<JCVariableDecl> paramBuff = new ListBuffer<JCVariableDecl>(); 1.1377 + int i = 0; 1.1378 + for (List<Type> l = ptypes; l.nonEmpty(); l = l.tail) { 1.1379 + JCVariableDecl param = make.Param(make.paramName(i++), l.head, owner); 1.1380 + param.sym.pos = tree.pos; 1.1381 + paramBuff.append(param); 1.1382 + } 1.1383 + List<JCVariableDecl> params = paramBuff.toList(); 1.1384 + 1.1385 + // Make new-class call 1.1386 + JCNewClass nc = makeNewClass(classType, make.Idents(params)); 1.1387 + nc.pos = tree.pos; 1.1388 + 1.1389 + // Make lambda holding the new-class call 1.1390 + JCLambda slam = make.Lambda(params, nc); 1.1391 + slam.targets = tree.targets; 1.1392 + slam.type = tree.type; 1.1393 + slam.pos = tree.pos; 1.1394 + 1.1395 + // Now it is a lambda, process as such 1.1396 + visitLambda(slam); 1.1397 + } else { 1.1398 + super.visitReference(tree); 1.1399 + contextMap.put(tree, makeReferenceContext(tree)); 1.1400 + } 1.1401 + } 1.1402 + 1.1403 + @Override 1.1404 + public void visitSelect(JCFieldAccess tree) { 1.1405 + if (context() != null && tree.sym.kind == VAR && 1.1406 + (tree.sym.name == names._this || 1.1407 + tree.sym.name == names._super)) { 1.1408 + // A select of this or super means, if we are in a lambda, 1.1409 + // we much have an instance context 1.1410 + TranslationContext<?> localContext = context(); 1.1411 + while (localContext != null) { 1.1412 + if (localContext.tree.hasTag(LAMBDA)) { 1.1413 + JCClassDecl clazz = (JCClassDecl)capturedDecl(localContext.depth, tree.sym); 1.1414 + if (clazz == null) break; 1.1415 + ((LambdaTranslationContext)localContext).addSymbol(clazz.sym, CAPTURED_THIS); 1.1416 + } 1.1417 + localContext = localContext.prev; 1.1418 + } 1.1419 + } 1.1420 + super.visitSelect(tree); 1.1421 + } 1.1422 + 1.1423 + @Override 1.1424 + public void visitVarDef(JCVariableDecl tree) { 1.1425 + TranslationContext<?> context = context(); 1.1426 + LambdaTranslationContext ltc = (context != null && context instanceof LambdaTranslationContext)? 1.1427 + (LambdaTranslationContext)context : 1.1428 + null; 1.1429 + if (ltc != null) { 1.1430 + if (frameStack.head.tree.hasTag(LAMBDA)) { 1.1431 + ltc.addSymbol(tree.sym, LOCAL_VAR); 1.1432 + } 1.1433 + // Check for type variables (including as type arguments). 1.1434 + // If they occur within class nested in a lambda, mark for erasure 1.1435 + Type type = tree.sym.asType(); 1.1436 + if (inClassWithinLambda() && !types.isSameType(types.erasure(type), type)) { 1.1437 + ltc.addSymbol(tree.sym, TYPE_VAR); 1.1438 + } 1.1439 + } 1.1440 + 1.1441 + List<Frame> prevStack = frameStack; 1.1442 + try { 1.1443 + if (tree.sym.owner.kind == MTH) { 1.1444 + frameStack.head.addLocal(tree.sym); 1.1445 + } 1.1446 + frameStack = frameStack.prepend(new Frame(tree)); 1.1447 + super.visitVarDef(tree); 1.1448 + } 1.1449 + finally { 1.1450 + frameStack = prevStack; 1.1451 + } 1.1452 + } 1.1453 + 1.1454 + /** 1.1455 + * Return a valid owner given the current declaration stack 1.1456 + * (required to skip synthetic lambda symbols) 1.1457 + */ 1.1458 + private Symbol owner() { 1.1459 + return owner(false); 1.1460 + } 1.1461 + 1.1462 + @SuppressWarnings("fallthrough") 1.1463 + private Symbol owner(boolean skipLambda) { 1.1464 + List<Frame> frameStack2 = frameStack; 1.1465 + while (frameStack2.nonEmpty()) { 1.1466 + switch (frameStack2.head.tree.getTag()) { 1.1467 + case VARDEF: 1.1468 + if (((JCVariableDecl)frameStack2.head.tree).sym.isLocal()) { 1.1469 + frameStack2 = frameStack2.tail; 1.1470 + break; 1.1471 + } 1.1472 + JCClassDecl cdecl = (JCClassDecl)frameStack2.tail.head.tree; 1.1473 + return initSym(cdecl.sym, 1.1474 + ((JCVariableDecl)frameStack2.head.tree).sym.flags() & STATIC); 1.1475 + case BLOCK: 1.1476 + JCClassDecl cdecl2 = (JCClassDecl)frameStack2.tail.head.tree; 1.1477 + return initSym(cdecl2.sym, 1.1478 + ((JCBlock)frameStack2.head.tree).flags & STATIC); 1.1479 + case CLASSDEF: 1.1480 + return ((JCClassDecl)frameStack2.head.tree).sym; 1.1481 + case METHODDEF: 1.1482 + return ((JCMethodDecl)frameStack2.head.tree).sym; 1.1483 + case LAMBDA: 1.1484 + if (!skipLambda) 1.1485 + return ((LambdaTranslationContext)contextMap 1.1486 + .get(frameStack2.head.tree)).translatedSym; 1.1487 + default: 1.1488 + frameStack2 = frameStack2.tail; 1.1489 + } 1.1490 + } 1.1491 + Assert.error(); 1.1492 + return null; 1.1493 + } 1.1494 + 1.1495 + private Symbol initSym(ClassSymbol csym, long flags) { 1.1496 + boolean isStatic = (flags & STATIC) != 0; 1.1497 + if (isStatic) { 1.1498 + /* static clinits are generated in Gen, so we need to use a fake 1.1499 + * one. Attr creates a fake clinit method while attributing 1.1500 + * lambda expressions used as initializers of static fields, so 1.1501 + * let's use that one. 1.1502 + */ 1.1503 + MethodSymbol clinit = attr.removeClinit(csym); 1.1504 + if (clinit != null) { 1.1505 + clinits.put(csym, clinit); 1.1506 + return clinit; 1.1507 + } 1.1508 + 1.1509 + /* if no clinit is found at Attr, then let's try at clinits. 1.1510 + */ 1.1511 + clinit = (MethodSymbol)clinits.get(csym); 1.1512 + if (clinit == null) { 1.1513 + /* no luck, let's create a new one 1.1514 + */ 1.1515 + clinit = makePrivateSyntheticMethod(STATIC, 1.1516 + names.clinit, 1.1517 + new MethodType(List.<Type>nil(), syms.voidType, 1.1518 + List.<Type>nil(), syms.methodClass), 1.1519 + csym); 1.1520 + clinits.put(csym, clinit); 1.1521 + } 1.1522 + return clinit; 1.1523 + } else { 1.1524 + //get the first constructor and treat it as the instance init sym 1.1525 + for (Symbol s : csym.members_field.getElementsByName(names.init)) { 1.1526 + return s; 1.1527 + } 1.1528 + } 1.1529 + Assert.error("init not found"); 1.1530 + return null; 1.1531 + } 1.1532 + 1.1533 + private JCTree directlyEnclosingLambda() { 1.1534 + if (frameStack.isEmpty()) { 1.1535 + return null; 1.1536 + } 1.1537 + List<Frame> frameStack2 = frameStack; 1.1538 + while (frameStack2.nonEmpty()) { 1.1539 + switch (frameStack2.head.tree.getTag()) { 1.1540 + case CLASSDEF: 1.1541 + case METHODDEF: 1.1542 + return null; 1.1543 + case LAMBDA: 1.1544 + return frameStack2.head.tree; 1.1545 + default: 1.1546 + frameStack2 = frameStack2.tail; 1.1547 + } 1.1548 + } 1.1549 + Assert.error(); 1.1550 + return null; 1.1551 + } 1.1552 + 1.1553 + private boolean inClassWithinLambda() { 1.1554 + if (frameStack.isEmpty()) { 1.1555 + return false; 1.1556 + } 1.1557 + List<Frame> frameStack2 = frameStack; 1.1558 + boolean classFound = false; 1.1559 + while (frameStack2.nonEmpty()) { 1.1560 + switch (frameStack2.head.tree.getTag()) { 1.1561 + case LAMBDA: 1.1562 + return classFound; 1.1563 + case CLASSDEF: 1.1564 + classFound = true; 1.1565 + frameStack2 = frameStack2.tail; 1.1566 + break; 1.1567 + default: 1.1568 + frameStack2 = frameStack2.tail; 1.1569 + } 1.1570 + } 1.1571 + // No lambda 1.1572 + return false; 1.1573 + } 1.1574 + 1.1575 + /** 1.1576 + * Return the declaration corresponding to a symbol in the enclosing 1.1577 + * scope; the depth parameter is used to filter out symbols defined 1.1578 + * in nested scopes (which do not need to undergo capture). 1.1579 + */ 1.1580 + private JCTree capturedDecl(int depth, Symbol sym) { 1.1581 + int currentDepth = frameStack.size() - 1; 1.1582 + for (Frame block : frameStack) { 1.1583 + switch (block.tree.getTag()) { 1.1584 + case CLASSDEF: 1.1585 + ClassSymbol clazz = ((JCClassDecl)block.tree).sym; 1.1586 + if (sym.isMemberOf(clazz, types)) { 1.1587 + return currentDepth > depth ? null : block.tree; 1.1588 + } 1.1589 + break; 1.1590 + case VARDEF: 1.1591 + if (((JCVariableDecl)block.tree).sym == sym && 1.1592 + sym.owner.kind == MTH) { //only locals are captured 1.1593 + return currentDepth > depth ? null : block.tree; 1.1594 + } 1.1595 + break; 1.1596 + case BLOCK: 1.1597 + case METHODDEF: 1.1598 + case LAMBDA: 1.1599 + if (block.locals != null && block.locals.contains(sym)) { 1.1600 + return currentDepth > depth ? null : block.tree; 1.1601 + } 1.1602 + break; 1.1603 + default: 1.1604 + Assert.error("bad decl kind " + block.tree.getTag()); 1.1605 + } 1.1606 + currentDepth--; 1.1607 + } 1.1608 + return null; 1.1609 + } 1.1610 + 1.1611 + private TranslationContext<?> context() { 1.1612 + for (Frame frame : frameStack) { 1.1613 + TranslationContext<?> context = contextMap.get(frame.tree); 1.1614 + if (context != null) { 1.1615 + return context; 1.1616 + } 1.1617 + } 1.1618 + return null; 1.1619 + } 1.1620 + 1.1621 + /** 1.1622 + * This is used to filter out those identifiers that needs to be adjusted 1.1623 + * when translating away lambda expressions 1.1624 + */ 1.1625 + private boolean lambdaIdentSymbolFilter(Symbol sym) { 1.1626 + return (sym.kind == VAR || sym.kind == MTH) 1.1627 + && !sym.isStatic() 1.1628 + && sym.name != names.init; 1.1629 + } 1.1630 + 1.1631 + /** 1.1632 + * This is used to filter out those new class expressions that need to 1.1633 + * be qualified with an enclosing tree 1.1634 + */ 1.1635 + private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) { 1.1636 + if (context != null 1.1637 + && tree.encl == null 1.1638 + && tree.def == null 1.1639 + && !tree.type.getEnclosingType().hasTag(NONE)) { 1.1640 + Type encl = tree.type.getEnclosingType(); 1.1641 + Type current = context.owner.enclClass().type; 1.1642 + while (!current.hasTag(NONE)) { 1.1643 + if (current.tsym.isSubClass(encl.tsym, types)) { 1.1644 + return true; 1.1645 + } 1.1646 + current = current.getEnclosingType(); 1.1647 + } 1.1648 + return false; 1.1649 + } else { 1.1650 + return false; 1.1651 + } 1.1652 + } 1.1653 + 1.1654 + private TranslationContext<JCLambda> makeLambdaContext(JCLambda tree) { 1.1655 + return new LambdaTranslationContext(tree); 1.1656 + } 1.1657 + 1.1658 + private TranslationContext<JCMemberReference> makeReferenceContext(JCMemberReference tree) { 1.1659 + return new ReferenceTranslationContext(tree); 1.1660 + } 1.1661 + 1.1662 + private class Frame { 1.1663 + final JCTree tree; 1.1664 + List<Symbol> locals; 1.1665 + 1.1666 + public Frame(JCTree tree) { 1.1667 + this.tree = tree; 1.1668 + } 1.1669 + 1.1670 + void addLocal(Symbol sym) { 1.1671 + if (locals == null) { 1.1672 + locals = List.nil(); 1.1673 + } 1.1674 + locals = locals.prepend(sym); 1.1675 + } 1.1676 + } 1.1677 + 1.1678 + /** 1.1679 + * This class is used to store important information regarding translation of 1.1680 + * lambda expression/method references (see subclasses). 1.1681 + */ 1.1682 + private abstract class TranslationContext<T extends JCFunctionalExpression> { 1.1683 + 1.1684 + /** the underlying (untranslated) tree */ 1.1685 + final T tree; 1.1686 + 1.1687 + /** points to the adjusted enclosing scope in which this lambda/mref expression occurs */ 1.1688 + final Symbol owner; 1.1689 + 1.1690 + /** the depth of this lambda expression in the frame stack */ 1.1691 + final int depth; 1.1692 + 1.1693 + /** the enclosing translation context (set for nested lambdas/mref) */ 1.1694 + final TranslationContext<?> prev; 1.1695 + 1.1696 + /** list of methods to be bridged by the meta-factory */ 1.1697 + final List<Symbol> bridges; 1.1698 + 1.1699 + TranslationContext(T tree) { 1.1700 + this.tree = tree; 1.1701 + this.owner = owner(); 1.1702 + this.depth = frameStack.size() - 1; 1.1703 + this.prev = context(); 1.1704 + ClassSymbol csym = 1.1705 + types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.targets, ABSTRACT | INTERFACE); 1.1706 + this.bridges = types.functionalInterfaceBridges(csym); 1.1707 + } 1.1708 + 1.1709 + /** does this functional expression need to be created using alternate metafactory? */ 1.1710 + boolean needsAltMetafactory() { 1.1711 + return tree.targets.length() > 1 || 1.1712 + isSerializable() || 1.1713 + bridges.length() > 1; 1.1714 + } 1.1715 + 1.1716 + /** does this functional expression require serialization support? */ 1.1717 + boolean isSerializable() { 1.1718 + if (forceSerializable) { 1.1719 + return true; 1.1720 + } 1.1721 + for (Type target : tree.targets) { 1.1722 + if (types.asSuper(target, syms.serializableType.tsym) != null) { 1.1723 + return true; 1.1724 + } 1.1725 + } 1.1726 + return false; 1.1727 + } 1.1728 + 1.1729 + /** 1.1730 + * @return Name of the enclosing method to be folded into synthetic 1.1731 + * method name 1.1732 + */ 1.1733 + String enclosingMethodName() { 1.1734 + return syntheticMethodNameComponent(owner.name); 1.1735 + } 1.1736 + 1.1737 + /** 1.1738 + * @return Method name in a form that can be folded into a 1.1739 + * component of a synthetic method name 1.1740 + */ 1.1741 + String syntheticMethodNameComponent(Name name) { 1.1742 + if (name == null) { 1.1743 + return "null"; 1.1744 + } 1.1745 + String methodName = name.toString(); 1.1746 + if (methodName.equals("<clinit>")) { 1.1747 + methodName = "static"; 1.1748 + } else if (methodName.equals("<init>")) { 1.1749 + methodName = "new"; 1.1750 + } 1.1751 + return methodName; 1.1752 + } 1.1753 + } 1.1754 + 1.1755 + /** 1.1756 + * This class retains all the useful information about a lambda expression; 1.1757 + * the contents of this class are filled by the LambdaAnalyzer visitor, 1.1758 + * and the used by the main translation routines in order to adjust references 1.1759 + * to captured locals/members, etc. 1.1760 + */ 1.1761 + private class LambdaTranslationContext extends TranslationContext<JCLambda> { 1.1762 + 1.1763 + /** variable in the enclosing context to which this lambda is assigned */ 1.1764 + final Symbol self; 1.1765 + 1.1766 + /** variable in the enclosing context to which this lambda is assigned */ 1.1767 + final Symbol assignedTo; 1.1768 + 1.1769 + Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols; 1.1770 + 1.1771 + /** the synthetic symbol for the method hoisting the translated lambda */ 1.1772 + Symbol translatedSym; 1.1773 + 1.1774 + List<JCVariableDecl> syntheticParams; 1.1775 + 1.1776 + /** 1.1777 + * to prevent recursion, track local classes processed 1.1778 + */ 1.1779 + final Set<Symbol> freeVarProcessedLocalClasses; 1.1780 + 1.1781 + LambdaTranslationContext(JCLambda tree) { 1.1782 + super(tree); 1.1783 + Frame frame = frameStack.head; 1.1784 + switch (frame.tree.getTag()) { 1.1785 + case VARDEF: 1.1786 + assignedTo = self = ((JCVariableDecl) frame.tree).sym; 1.1787 + break; 1.1788 + case ASSIGN: 1.1789 + self = null; 1.1790 + assignedTo = TreeInfo.symbol(((JCAssign) frame.tree).getVariable()); 1.1791 + break; 1.1792 + default: 1.1793 + assignedTo = self = null; 1.1794 + break; 1.1795 + } 1.1796 + 1.1797 + // This symbol will be filled-in in complete 1.1798 + this.translatedSym = makePrivateSyntheticMethod(0, null, null, owner.enclClass()); 1.1799 + 1.1800 + if (dumpLambdaToMethodStats) { 1.1801 + log.note(tree, "lambda.stat", needsAltMetafactory(), translatedSym); 1.1802 + } 1.1803 + translatedSymbols = new EnumMap<>(LambdaSymbolKind.class); 1.1804 + 1.1805 + translatedSymbols.put(PARAM, new LinkedHashMap<Symbol, Symbol>()); 1.1806 + translatedSymbols.put(LOCAL_VAR, new LinkedHashMap<Symbol, Symbol>()); 1.1807 + translatedSymbols.put(CAPTURED_VAR, new LinkedHashMap<Symbol, Symbol>()); 1.1808 + translatedSymbols.put(CAPTURED_THIS, new LinkedHashMap<Symbol, Symbol>()); 1.1809 + translatedSymbols.put(TYPE_VAR, new LinkedHashMap<Symbol, Symbol>()); 1.1810 + 1.1811 + freeVarProcessedLocalClasses = new HashSet<>(); 1.1812 + } 1.1813 + 1.1814 + /** 1.1815 + * For a serializable lambda, generate a disambiguating string 1.1816 + * which maximizes stability across deserialization. 1.1817 + * 1.1818 + * @return String to differentiate synthetic lambda method names 1.1819 + */ 1.1820 + private String serializedLambdaDisambiguation() { 1.1821 + StringBuilder buf = new StringBuilder(); 1.1822 + // Append the enclosing method signature to differentiate 1.1823 + // overloaded enclosing methods. For lambdas enclosed in 1.1824 + // lambdas, the generated lambda method will not have type yet, 1.1825 + // but the enclosing method's name will have been generated 1.1826 + // with this same method, so it will be unique and never be 1.1827 + // overloaded. 1.1828 + Assert.check( 1.1829 + owner.type != null || 1.1830 + directlyEnclosingLambda() != null); 1.1831 + if (owner.type != null) { 1.1832 + buf.append(typeSig(owner.type)); 1.1833 + buf.append(":"); 1.1834 + } 1.1835 + 1.1836 + // Add target type info 1.1837 + buf.append(types.findDescriptorSymbol(tree.type.tsym).owner.flatName()); 1.1838 + buf.append(" "); 1.1839 + 1.1840 + // Add variable assigned to 1.1841 + if (assignedTo != null) { 1.1842 + buf.append(assignedTo.flatName()); 1.1843 + buf.append("="); 1.1844 + } 1.1845 + //add captured locals info: type, name, order 1.1846 + for (Symbol fv : getSymbolMap(CAPTURED_VAR).keySet()) { 1.1847 + if (fv != self) { 1.1848 + buf.append(typeSig(fv.type)); 1.1849 + buf.append(" "); 1.1850 + buf.append(fv.flatName()); 1.1851 + buf.append(","); 1.1852 + } 1.1853 + } 1.1854 + 1.1855 + return buf.toString(); 1.1856 + } 1.1857 + 1.1858 + /** 1.1859 + * For a non-serializable lambda, generate a simple method. 1.1860 + * 1.1861 + * @return Name to use for the synthetic lambda method name 1.1862 + */ 1.1863 + private Name lambdaName() { 1.1864 + return names.lambda.append(names.fromString(enclosingMethodName() + "$" + lambdaCount++)); 1.1865 + } 1.1866 + 1.1867 + /** 1.1868 + * For a serializable lambda, generate a method name which maximizes 1.1869 + * name stability across deserialization. 1.1870 + * 1.1871 + * @return Name to use for the synthetic lambda method name 1.1872 + */ 1.1873 + private Name serializedLambdaName() { 1.1874 + StringBuilder buf = new StringBuilder(); 1.1875 + buf.append(names.lambda); 1.1876 + // Append the name of the method enclosing the lambda. 1.1877 + buf.append(enclosingMethodName()); 1.1878 + buf.append('$'); 1.1879 + // Append a hash of the disambiguating string : enclosing method 1.1880 + // signature, etc. 1.1881 + String disam = serializedLambdaDisambiguation(); 1.1882 + buf.append(Integer.toHexString(disam.hashCode())); 1.1883 + buf.append('$'); 1.1884 + // The above appended name components may not be unique, append 1.1885 + // a count based on the above name components. 1.1886 + buf.append(syntheticMethodNameCounts.getIndex(buf)); 1.1887 + String result = buf.toString(); 1.1888 + //System.err.printf("serializedLambdaName: %s -- %s\n", result, disam); 1.1889 + return names.fromString(result); 1.1890 + } 1.1891 + 1.1892 + /** 1.1893 + * Translate a symbol of a given kind into something suitable for the 1.1894 + * synthetic lambda body 1.1895 + */ 1.1896 + Symbol translate(Name name, final Symbol sym, LambdaSymbolKind skind) { 1.1897 + Symbol ret; 1.1898 + switch (skind) { 1.1899 + case CAPTURED_THIS: 1.1900 + ret = sym; // self represented 1.1901 + break; 1.1902 + case TYPE_VAR: 1.1903 + // Just erase the type var 1.1904 + ret = new VarSymbol(sym.flags(), name, 1.1905 + types.erasure(sym.type), sym.owner); 1.1906 + 1.1907 + /* this information should also be kept for LVT generation at Gen 1.1908 + * a Symbol with pos < startPos won't be tracked. 1.1909 + */ 1.1910 + ((VarSymbol)ret).pos = ((VarSymbol)sym).pos; 1.1911 + break; 1.1912 + case CAPTURED_VAR: 1.1913 + ret = new VarSymbol(SYNTHETIC | FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym) { 1.1914 + @Override 1.1915 + public Symbol baseSymbol() { 1.1916 + //keep mapping with original captured symbol 1.1917 + return sym; 1.1918 + } 1.1919 + }; 1.1920 + break; 1.1921 + case LOCAL_VAR: 1.1922 + ret = new VarSymbol(sym.flags() & FINAL, name, sym.type, translatedSym); 1.1923 + ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; 1.1924 + break; 1.1925 + case PARAM: 1.1926 + ret = new VarSymbol((sym.flags() & FINAL) | PARAMETER, name, types.erasure(sym.type), translatedSym); 1.1927 + ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; 1.1928 + break; 1.1929 + default: 1.1930 + ret = makeSyntheticVar(FINAL, name, types.erasure(sym.type), translatedSym); 1.1931 + ((VarSymbol) ret).pos = ((VarSymbol) sym).pos; 1.1932 + } 1.1933 + if (ret != sym) { 1.1934 + ret.setDeclarationAttributes(sym.getRawAttributes()); 1.1935 + ret.setTypeAttributes(sym.getRawTypeAttributes()); 1.1936 + } 1.1937 + return ret; 1.1938 + } 1.1939 + 1.1940 + void addSymbol(Symbol sym, LambdaSymbolKind skind) { 1.1941 + Map<Symbol, Symbol> transMap = getSymbolMap(skind); 1.1942 + Name preferredName; 1.1943 + switch (skind) { 1.1944 + case CAPTURED_THIS: 1.1945 + preferredName = names.fromString("encl$" + transMap.size()); 1.1946 + break; 1.1947 + case CAPTURED_VAR: 1.1948 + preferredName = names.fromString("cap$" + transMap.size()); 1.1949 + break; 1.1950 + case LOCAL_VAR: 1.1951 + preferredName = sym.name; 1.1952 + break; 1.1953 + case PARAM: 1.1954 + preferredName = sym.name; 1.1955 + break; 1.1956 + case TYPE_VAR: 1.1957 + preferredName = sym.name; 1.1958 + break; 1.1959 + default: throw new AssertionError(); 1.1960 + } 1.1961 + if (!transMap.containsKey(sym)) { 1.1962 + transMap.put(sym, translate(preferredName, sym, skind)); 1.1963 + } 1.1964 + } 1.1965 + 1.1966 + Map<Symbol, Symbol> getSymbolMap(LambdaSymbolKind skind) { 1.1967 + Map<Symbol, Symbol> m = translatedSymbols.get(skind); 1.1968 + Assert.checkNonNull(m); 1.1969 + return m; 1.1970 + } 1.1971 + 1.1972 + JCTree translate(JCIdent lambdaIdent) { 1.1973 + for (Map<Symbol, Symbol> m : translatedSymbols.values()) { 1.1974 + if (m.containsKey(lambdaIdent.sym)) { 1.1975 + Symbol tSym = m.get(lambdaIdent.sym); 1.1976 + JCTree t = make.Ident(tSym).setType(lambdaIdent.type); 1.1977 + tSym.setTypeAttributes(lambdaIdent.sym.getRawTypeAttributes()); 1.1978 + return t; 1.1979 + } 1.1980 + } 1.1981 + return null; 1.1982 + } 1.1983 + 1.1984 + /** 1.1985 + * The translatedSym is not complete/accurate until the analysis is 1.1986 + * finished. Once the analysis is finished, the translatedSym is 1.1987 + * "completed" -- updated with type information, access modifiers, 1.1988 + * and full parameter list. 1.1989 + */ 1.1990 + void complete() { 1.1991 + if (syntheticParams != null) { 1.1992 + return; 1.1993 + } 1.1994 + boolean inInterface = translatedSym.owner.isInterface(); 1.1995 + boolean thisReferenced = !getSymbolMap(CAPTURED_THIS).isEmpty(); 1.1996 + 1.1997 + // If instance access isn't needed, make it static. 1.1998 + // Interface instance methods must be default methods. 1.1999 + // Lambda methods are private synthetic. 1.2000 + translatedSym.flags_field = SYNTHETIC | LAMBDA_METHOD | 1.2001 + PRIVATE | 1.2002 + (thisReferenced? (inInterface? DEFAULT : 0) : STATIC); 1.2003 + 1.2004 + //compute synthetic params 1.2005 + ListBuffer<JCVariableDecl> params = new ListBuffer<>(); 1.2006 + 1.2007 + // The signature of the method is augmented with the following 1.2008 + // synthetic parameters: 1.2009 + // 1.2010 + // 1) reference to enclosing contexts captured by the lambda expression 1.2011 + // 2) enclosing locals captured by the lambda expression 1.2012 + for (Symbol thisSym : getSymbolMap(CAPTURED_VAR).values()) { 1.2013 + params.append(make.VarDef((VarSymbol) thisSym, null)); 1.2014 + } 1.2015 + for (Symbol thisSym : getSymbolMap(PARAM).values()) { 1.2016 + params.append(make.VarDef((VarSymbol) thisSym, null)); 1.2017 + } 1.2018 + syntheticParams = params.toList(); 1.2019 + 1.2020 + // Compute and set the lambda name 1.2021 + translatedSym.name = isSerializable() 1.2022 + ? serializedLambdaName() 1.2023 + : lambdaName(); 1.2024 + 1.2025 + //prepend synthetic args to translated lambda method signature 1.2026 + translatedSym.type = types.createMethodTypeWithParameters( 1.2027 + generatedLambdaSig(), 1.2028 + TreeInfo.types(syntheticParams)); 1.2029 + } 1.2030 + 1.2031 + Type generatedLambdaSig() { 1.2032 + return types.erasure(tree.getDescriptorType(types)); 1.2033 + } 1.2034 + } 1.2035 + 1.2036 + /** 1.2037 + * This class retains all the useful information about a method reference; 1.2038 + * the contents of this class are filled by the LambdaAnalyzer visitor, 1.2039 + * and the used by the main translation routines in order to adjust method 1.2040 + * references (i.e. in case a bridge is needed) 1.2041 + */ 1.2042 + private class ReferenceTranslationContext extends TranslationContext<JCMemberReference> { 1.2043 + 1.2044 + final boolean isSuper; 1.2045 + final Symbol bridgeSym; 1.2046 + final Symbol sigPolySym; 1.2047 + 1.2048 + ReferenceTranslationContext(JCMemberReference tree) { 1.2049 + super(tree); 1.2050 + this.isSuper = tree.hasKind(ReferenceKind.SUPER); 1.2051 + this.bridgeSym = needsBridge() 1.2052 + ? makePrivateSyntheticMethod(isSuper ? 0 : STATIC, 1.2053 + referenceBridgeName(), null, 1.2054 + owner.enclClass()) 1.2055 + : null; 1.2056 + this.sigPolySym = isSignaturePolymorphic() 1.2057 + ? makePrivateSyntheticMethod(tree.sym.flags(), 1.2058 + tree.sym.name, 1.2059 + bridgedRefSig(), 1.2060 + tree.sym.enclClass()) 1.2061 + : null; 1.2062 + if (dumpLambdaToMethodStats) { 1.2063 + String key = bridgeSym == null ? 1.2064 + "mref.stat" : "mref.stat.1"; 1.2065 + log.note(tree, key, needsAltMetafactory(), bridgeSym); 1.2066 + } 1.2067 + } 1.2068 + 1.2069 + /** 1.2070 + * Get the opcode associated with this method reference 1.2071 + */ 1.2072 + int referenceKind() { 1.2073 + return LambdaToMethod.this.referenceKind(needsBridge() 1.2074 + ? bridgeSym 1.2075 + : tree.sym); 1.2076 + } 1.2077 + 1.2078 + boolean needsVarArgsConversion() { 1.2079 + return tree.varargsElement != null; 1.2080 + } 1.2081 + 1.2082 + /** 1.2083 + * Generate a disambiguating string to increase stability (important 1.2084 + * if serialized) 1.2085 + * 1.2086 + * @return String to differentiate synthetic lambda method names 1.2087 + */ 1.2088 + private String referenceBridgeDisambiguation() { 1.2089 + StringBuilder buf = new StringBuilder(); 1.2090 + // Append the enclosing method signature to differentiate 1.2091 + // overloaded enclosing methods. 1.2092 + if (owner.type != null) { 1.2093 + buf.append(typeSig(owner.type)); 1.2094 + buf.append(":"); 1.2095 + } 1.2096 + 1.2097 + // Append qualifier type 1.2098 + buf.append(classSig(tree.sym.owner.type)); 1.2099 + 1.2100 + // Note static/instance 1.2101 + buf.append(tree.sym.isStatic()? " S " : " I "); 1.2102 + 1.2103 + // Append referenced signature 1.2104 + buf.append(typeSig(tree.sym.erasure(types))); 1.2105 + 1.2106 + return buf.toString(); 1.2107 + } 1.2108 + 1.2109 + /** 1.2110 + * Construct a unique stable name for the method reference bridge 1.2111 + * 1.2112 + * @return Name to use for the synthetic method name 1.2113 + */ 1.2114 + private Name referenceBridgeName() { 1.2115 + StringBuilder buf = new StringBuilder(); 1.2116 + // Append lambda ID, this is semantically significant 1.2117 + buf.append(names.lambda); 1.2118 + // Note that it is a method reference bridge 1.2119 + buf.append("MR$"); 1.2120 + // Append the enclosing method name 1.2121 + buf.append(enclosingMethodName()); 1.2122 + buf.append('$'); 1.2123 + // Append the referenced method name 1.2124 + buf.append(syntheticMethodNameComponent(tree.sym.name)); 1.2125 + buf.append('$'); 1.2126 + // Append a hash of the disambiguating string : enclosing method 1.2127 + // signature, etc. 1.2128 + String disam = referenceBridgeDisambiguation(); 1.2129 + buf.append(Integer.toHexString(disam.hashCode())); 1.2130 + buf.append('$'); 1.2131 + // The above appended name components may not be unique, append 1.2132 + // a count based on the above name components. 1.2133 + buf.append(syntheticMethodNameCounts.getIndex(buf)); 1.2134 + String result = buf.toString(); 1.2135 + return names.fromString(result); 1.2136 + } 1.2137 + 1.2138 + /** 1.2139 + * @return Is this an array operation like clone() 1.2140 + */ 1.2141 + boolean isArrayOp() { 1.2142 + return tree.sym.owner == syms.arrayClass; 1.2143 + } 1.2144 + 1.2145 + boolean receiverAccessible() { 1.2146 + //hack needed to workaround 292 bug (7087658) 1.2147 + //when 292 issue is fixed we should remove this and change the backend 1.2148 + //code to always generate a method handle to an accessible method 1.2149 + return tree.ownerAccessible; 1.2150 + } 1.2151 + 1.2152 + /** 1.2153 + * The VM does not support access across nested classes (8010319). 1.2154 + * Were that ever to change, this should be removed. 1.2155 + */ 1.2156 + boolean isPrivateInOtherClass() { 1.2157 + return (tree.sym.flags() & PRIVATE) != 0 && 1.2158 + !types.isSameType( 1.2159 + types.erasure(tree.sym.enclClass().asType()), 1.2160 + types.erasure(owner.enclClass().asType())); 1.2161 + } 1.2162 + 1.2163 + /** 1.2164 + * Signature polymorphic methods need special handling. 1.2165 + * e.g. MethodHandle.invoke() MethodHandle.invokeExact() 1.2166 + */ 1.2167 + final boolean isSignaturePolymorphic() { 1.2168 + return tree.sym.kind == MTH && 1.2169 + types.isSignaturePolymorphic((MethodSymbol)tree.sym); 1.2170 + } 1.2171 + 1.2172 + /** 1.2173 + * Does this reference needs a bridge (i.e. var args need to be 1.2174 + * expanded or "super" is used) 1.2175 + */ 1.2176 + final boolean needsBridge() { 1.2177 + return isSuper || needsVarArgsConversion() || isArrayOp() || 1.2178 + isPrivateInOtherClass() || 1.2179 + !receiverAccessible(); 1.2180 + } 1.2181 + 1.2182 + Type generatedRefSig() { 1.2183 + return types.erasure(tree.sym.type); 1.2184 + } 1.2185 + 1.2186 + Type bridgedRefSig() { 1.2187 + return types.erasure(types.findDescriptorSymbol(tree.targets.head.tsym).type); 1.2188 + } 1.2189 + } 1.2190 + } 1.2191 + // </editor-fold> 1.2192 + 1.2193 + /* 1.2194 + * These keys provide mappings for various translated lambda symbols 1.2195 + * and the prevailing order must be maintained. 1.2196 + */ 1.2197 + enum LambdaSymbolKind { 1.2198 + PARAM, // original to translated lambda parameters 1.2199 + LOCAL_VAR, // original to translated lambda locals 1.2200 + CAPTURED_VAR, // variables in enclosing scope to translated synthetic parameters 1.2201 + CAPTURED_THIS, // class symbols to translated synthetic parameters (for captured member access) 1.2202 + TYPE_VAR; // original to translated lambda type variables 1.2203 + } 1.2204 + 1.2205 + /** 1.2206 + * **************************************************************** 1.2207 + * Signature Generation 1.2208 + * **************************************************************** 1.2209 + */ 1.2210 + 1.2211 + private String typeSig(Type type) { 1.2212 + L2MSignatureGenerator sg = new L2MSignatureGenerator(); 1.2213 + sg.assembleSig(type); 1.2214 + return sg.toString(); 1.2215 + } 1.2216 + 1.2217 + private String classSig(Type type) { 1.2218 + L2MSignatureGenerator sg = new L2MSignatureGenerator(); 1.2219 + sg.assembleClassSig(type); 1.2220 + return sg.toString(); 1.2221 + } 1.2222 + 1.2223 + /** 1.2224 + * Signature Generation 1.2225 + */ 1.2226 + private class L2MSignatureGenerator extends Types.SignatureGenerator { 1.2227 + 1.2228 + /** 1.2229 + * An output buffer for type signatures. 1.2230 + */ 1.2231 + StringBuilder sb = new StringBuilder(); 1.2232 + 1.2233 + L2MSignatureGenerator() { 1.2234 + super(types); 1.2235 + } 1.2236 + 1.2237 + @Override 1.2238 + protected void append(char ch) { 1.2239 + sb.append(ch); 1.2240 + } 1.2241 + 1.2242 + @Override 1.2243 + protected void append(byte[] ba) { 1.2244 + sb.append(new String(ba)); 1.2245 + } 1.2246 + 1.2247 + @Override 1.2248 + protected void append(Name name) { 1.2249 + sb.append(name.toString()); 1.2250 + } 1.2251 + 1.2252 + @Override 1.2253 + public String toString() { 1.2254 + return sb.toString(); 1.2255 + } 1.2256 + } 1.2257 +}