< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java

Print this page

 336     public void visitLambda(JCLambda tree) {
 337         LambdaTranslationContext localContext = (LambdaTranslationContext)context;
 338         MethodSymbol sym = localContext.translatedSym;
 339         MethodType lambdaType = (MethodType) sym.type;
 340 
 341         {   /* Type annotation management: Based on where the lambda features, type annotations that
 342                are interior to it, may at this point be attached to the enclosing method, or the first
 343                constructor in the class, or in the enclosing class symbol or in the field whose
 344                initializer is the lambda. In any event, gather up the annotations that belong to the
 345                lambda and attach it to the implementation method.
 346             */
 347 
 348             Symbol owner = localContext.owner;
 349             apportionTypeAnnotations(tree,
 350                     owner::getRawTypeAttributes,
 351                     owner::setTypeAttributes,
 352                     sym::setTypeAttributes);
 353 
 354 
 355             boolean init;
 356             if ((init = (owner.name == names.init)) || owner.name == names.clinit) {

 357                 owner = owner.owner;
 358                 apportionTypeAnnotations(tree,
 359                         init ? owner::getInitTypeAttributes : owner::getClassInitTypeAttributes,
 360                         init ? owner::setInitTypeAttributes : owner::setClassInitTypeAttributes,
 361                         sym::appendUniqueTypeAttributes);
 362             }
 363             if (localContext.self != null && localContext.self.getKind() == ElementKind.FIELD) {
 364                 owner = localContext.self;
 365                 apportionTypeAnnotations(tree,
 366                         owner::getRawTypeAttributes,
 367                         owner::setTypeAttributes,
 368                         sym::appendUniqueTypeAttributes);
 369             }
 370         }
 371 
 372         //create the method declaration hoisting the lambda body
 373         JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
 374                 sym.name,
 375                 make.QualIdent(lambdaType.getReturnType().tsym),
 376                 List.nil(),
 377                 localContext.syntheticParams,
 378                 lambdaType.getThrownTypes() == null ?
 379                     List.nil() :
 380                     make.Types(lambdaType.getThrownTypes()),
 381                 null,
 382                 null);
 383         lambdaDecl.sym = sym;
 384         lambdaDecl.type = lambdaType;
 385 
 386         //translate lambda body
 387         //As the lambda body is translated, all references to lambda locals,
 388         //captured variables, enclosing members are adjusted accordingly
 389         //to refer to the static method parameters (rather than i.e. accessing
 390         //captured members directly).
 391         lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
 392 
 393         boolean dedupe = false;
 394         if (deduplicateLambdas && !debugLinesOrVars && !localContext.isSerializable()) {
 395             DedupedLambda dedupedLambda = new DedupedLambda(lambdaDecl.sym, lambdaDecl.body);

1647                     clinits.put(csym, clinit);
1648                     return clinit;
1649                 }
1650 
1651                 /* if no clinit is found at Attr, then let's try at clinits.
1652                  */
1653                 clinit = (MethodSymbol)clinits.get(csym);
1654                 if (clinit == null) {
1655                     /* no luck, let's create a new one
1656                      */
1657                     clinit = makePrivateSyntheticMethod(STATIC,
1658                             names.clinit,
1659                             new MethodType(List.nil(), syms.voidType,
1660                                 List.nil(), syms.methodClass),
1661                             csym);
1662                     clinits.put(csym, clinit);
1663                 }
1664                 return clinit;
1665             } else {
1666                 //get the first constructor and treat it as the instance init sym
1667                 for (Symbol s : csym.members_field.getSymbolsByName(names.init)) {

1668                     return s;
1669                 }
1670             }
1671             Assert.error("init not found");
1672             return null;
1673         }
1674 
1675         private JCTree directlyEnclosingLambda() {
1676             if (frameStack.isEmpty()) {
1677                 return null;
1678             }
1679             List<Frame> frameStack2 = frameStack;
1680             while (frameStack2.nonEmpty()) {
1681                 switch (frameStack2.head.tree.getTag()) {
1682                     case CLASSDEF:
1683                     case METHODDEF:
1684                         return null;
1685                     case LAMBDA:
1686                         return frameStack2.head.tree;
1687                     default:

1751             return null;
1752         }
1753 
1754         private TranslationContext<?> context() {
1755             for (Frame frame : frameStack) {
1756                 TranslationContext<?> context = contextMap.get(frame.tree);
1757                 if (context != null) {
1758                     return context;
1759                 }
1760             }
1761             return null;
1762         }
1763 
1764         /**
1765          *  This is used to filter out those identifiers that needs to be adjusted
1766          *  when translating away lambda expressions
1767          */
1768         private boolean lambdaIdentSymbolFilter(Symbol sym) {
1769             return (sym.kind == VAR || sym.kind == MTH)
1770                     && !sym.isStatic()
1771                     && sym.name != names.init;
1772         }
1773 
1774         /**
1775          *  This is used to filter out those select nodes that need to be adjusted
1776          *  when translating away lambda expressions - at the moment, this is the
1777          *  set of nodes that select `this' (qualified this)
1778          */
1779         private boolean lambdaFieldAccessFilter(JCFieldAccess fAccess) {
1780             return (context instanceof LambdaTranslationContext lambdaContext)
1781                     && !fAccess.sym.isStatic()
1782                     && fAccess.name == names._this
1783                     && (fAccess.sym.owner.kind == TYP)
1784                     && !lambdaContext.translatedSymbols.get(CAPTURED_OUTER_THIS).isEmpty();
1785         }
1786 
1787         /**
1788          * This is used to filter out those new class expressions that need to
1789          * be qualified with an enclosing tree
1790          */
1791         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {

1849                 this.owner = owner(true);
1850                 this.depth = frameStack.size() - 1;
1851                 this.prev = context();
1852                 ClassSymbol csym =
1853                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE);
1854                 this.bridges = types.functionalInterfaceBridges(csym);
1855             }
1856 
1857             /** does this functional expression need to be created using alternate metafactory? */
1858             boolean needsAltMetafactory() {
1859                 return tree.target.isIntersection() ||
1860                         isSerializable() ||
1861                         bridges.length() > 1;
1862             }
1863 
1864             /** does this functional expression require serialization support? */
1865             boolean isSerializable() {
1866                 if (forceSerializable) {
1867                     return true;
1868                 }
1869                 return types.asSuper(tree.target, syms.serializableType.tsym) != null;
1870             }
1871 
1872             /**
1873              * @return Name of the enclosing method to be folded into synthetic
1874              * method name
1875              */
1876             String enclosingMethodName() {
1877                 return syntheticMethodNameComponent(owner.name);
1878             }
1879 
1880             /**
1881              * @return Method name in a form that can be folded into a
1882              * component of a synthetic method name
1883              */
1884             String syntheticMethodNameComponent(Name name) {
1885                 if (name == null) {
1886                     return "null";
1887                 }
1888                 String methodName = name.toString();
1889                 if (methodName.equals("<clinit>")) {
1890                     methodName = "static";
1891                 } else if (methodName.equals("<init>")) {
1892                     methodName = "new";


1893                 }
1894                 return methodName;
1895             }
1896         }
1897 
1898         /**
1899          * This class retains all the useful information about a lambda expression;
1900          * the contents of this class are filled by the LambdaAnalyzer visitor,
1901          * and the used by the main translation routines in order to adjust references
1902          * to captured locals/members, etc.
1903          */
1904         class LambdaTranslationContext extends TranslationContext<JCLambda> {
1905 
1906             /** variable in the enclosing context to which this lambda is assigned */
1907             final Symbol self;
1908 
1909             /** variable in the enclosing context to which this lambda is assigned */
1910             final Symbol assignedTo;
1911 
1912             Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;

2327                         TypeVar tv = (TypeVar) t;
2328                         return isIntersectionOrUnionType(tv.getUpperBound());
2329                 }
2330                 return false;
2331             }
2332 
2333             /**
2334              * Does this reference need to be converted to a lambda
2335              * (i.e. var args need to be expanded or "super" is used)
2336              */
2337             final boolean needsConversionToLambda() {
2338                 return interfaceParameterIsIntersectionOrUnionType() ||
2339                         isSuper ||
2340                         needsVarArgsConversion() ||
2341                         isArrayOp() ||
2342                         (!nestmateLambdas && isPrivateInOtherClass()) ||
2343                         isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, owner) ||
2344                         !receiverAccessible() ||
2345                         (tree.getMode() == ReferenceMode.NEW &&
2346                           tree.kind != ReferenceKind.ARRAY_CTOR &&
2347                           (tree.sym.owner.isDirectlyOrIndirectlyLocal() || tree.sym.owner.isInner()));
2348             }
2349 
2350             Type generatedRefSig() {
2351                 return types.erasure(tree.sym.type);
2352             }
2353 
2354             Type bridgedRefSig() {
2355                 return types.erasure(types.findDescriptorSymbol(tree.target.tsym).type);
2356             }
2357         }
2358     }
2359     // </editor-fold>
2360 
2361     /*
2362      * These keys provide mappings for various translated lambda symbols
2363      * and the prevailing order must be maintained.
2364      */
2365     enum LambdaSymbolKind {
2366         PARAM,          // original to translated lambda parameters
2367         LOCAL_VAR,      // original to translated lambda locals

 336     public void visitLambda(JCLambda tree) {
 337         LambdaTranslationContext localContext = (LambdaTranslationContext)context;
 338         MethodSymbol sym = localContext.translatedSym;
 339         MethodType lambdaType = (MethodType) sym.type;
 340 
 341         {   /* Type annotation management: Based on where the lambda features, type annotations that
 342                are interior to it, may at this point be attached to the enclosing method, or the first
 343                constructor in the class, or in the enclosing class symbol or in the field whose
 344                initializer is the lambda. In any event, gather up the annotations that belong to the
 345                lambda and attach it to the implementation method.
 346             */
 347 
 348             Symbol owner = localContext.owner;
 349             apportionTypeAnnotations(tree,
 350                     owner::getRawTypeAttributes,
 351                     owner::setTypeAttributes,
 352                     sym::setTypeAttributes);
 353 
 354 
 355             boolean init;
 356             // TODO - can <vnew> exist in this context?
 357             if ((init = names.isInitOrVNew(owner.name)) || owner.name == names.clinit) {
 358                 owner = owner.owner;
 359                 apportionTypeAnnotations(tree,
 360                         init ? owner::getInitTypeAttributes : owner::getClassInitTypeAttributes,
 361                         init ? owner::setInitTypeAttributes : owner::setClassInitTypeAttributes,
 362                         sym::appendUniqueTypeAttributes);
 363             }
 364             if (localContext.self != null && localContext.self.getKind() == ElementKind.FIELD) {
 365                 owner = localContext.self;
 366                 apportionTypeAnnotations(tree,
 367                         owner::getRawTypeAttributes,
 368                         owner::setTypeAttributes,
 369                         sym::appendUniqueTypeAttributes);
 370             }
 371         }
 372 
 373         //create the method declaration hoisting the lambda body
 374         JCMethodDecl lambdaDecl = make.MethodDef(make.Modifiers(sym.flags_field),
 375                 sym.name,
 376                 make.QualIdent(lambdaType.getReturnType().tsym).setType(lambdaType.getReturnType()),
 377                 List.nil(),
 378                 localContext.syntheticParams,
 379                 lambdaType.getThrownTypes() == null ?
 380                     List.nil() :
 381                     make.Types(lambdaType.getThrownTypes()),
 382                 null,
 383                 null);
 384         lambdaDecl.sym = sym;
 385         lambdaDecl.type = lambdaType;
 386 
 387         //translate lambda body
 388         //As the lambda body is translated, all references to lambda locals,
 389         //captured variables, enclosing members are adjusted accordingly
 390         //to refer to the static method parameters (rather than i.e. accessing
 391         //captured members directly).
 392         lambdaDecl.body = translate(makeLambdaBody(tree, lambdaDecl));
 393 
 394         boolean dedupe = false;
 395         if (deduplicateLambdas && !debugLinesOrVars && !localContext.isSerializable()) {
 396             DedupedLambda dedupedLambda = new DedupedLambda(lambdaDecl.sym, lambdaDecl.body);

1648                     clinits.put(csym, clinit);
1649                     return clinit;
1650                 }
1651 
1652                 /* if no clinit is found at Attr, then let's try at clinits.
1653                  */
1654                 clinit = (MethodSymbol)clinits.get(csym);
1655                 if (clinit == null) {
1656                     /* no luck, let's create a new one
1657                      */
1658                     clinit = makePrivateSyntheticMethod(STATIC,
1659                             names.clinit,
1660                             new MethodType(List.nil(), syms.voidType,
1661                                 List.nil(), syms.methodClass),
1662                             csym);
1663                     clinits.put(csym, clinit);
1664                 }
1665                 return clinit;
1666             } else {
1667                 //get the first constructor and treat it as the instance init sym
1668                 Name constructorName = csym.isConcreteValueClass() ? names.vnew : names.init;
1669                 for (Symbol s : csym.members_field.getSymbolsByName(constructorName)) {
1670                     return s;
1671                 }
1672             }
1673             Assert.error("init not found");
1674             return null;
1675         }
1676 
1677         private JCTree directlyEnclosingLambda() {
1678             if (frameStack.isEmpty()) {
1679                 return null;
1680             }
1681             List<Frame> frameStack2 = frameStack;
1682             while (frameStack2.nonEmpty()) {
1683                 switch (frameStack2.head.tree.getTag()) {
1684                     case CLASSDEF:
1685                     case METHODDEF:
1686                         return null;
1687                     case LAMBDA:
1688                         return frameStack2.head.tree;
1689                     default:

1753             return null;
1754         }
1755 
1756         private TranslationContext<?> context() {
1757             for (Frame frame : frameStack) {
1758                 TranslationContext<?> context = contextMap.get(frame.tree);
1759                 if (context != null) {
1760                     return context;
1761                 }
1762             }
1763             return null;
1764         }
1765 
1766         /**
1767          *  This is used to filter out those identifiers that needs to be adjusted
1768          *  when translating away lambda expressions
1769          */
1770         private boolean lambdaIdentSymbolFilter(Symbol sym) {
1771             return (sym.kind == VAR || sym.kind == MTH)
1772                     && !sym.isStatic()
1773                     && !names.isInitOrVNew(sym.name);
1774         }
1775 
1776         /**
1777          *  This is used to filter out those select nodes that need to be adjusted
1778          *  when translating away lambda expressions - at the moment, this is the
1779          *  set of nodes that select `this' (qualified this)
1780          */
1781         private boolean lambdaFieldAccessFilter(JCFieldAccess fAccess) {
1782             return (context instanceof LambdaTranslationContext lambdaContext)
1783                     && !fAccess.sym.isStatic()
1784                     && fAccess.name == names._this
1785                     && (fAccess.sym.owner.kind == TYP)
1786                     && !lambdaContext.translatedSymbols.get(CAPTURED_OUTER_THIS).isEmpty();
1787         }
1788 
1789         /**
1790          * This is used to filter out those new class expressions that need to
1791          * be qualified with an enclosing tree
1792          */
1793         private boolean lambdaNewClassFilter(TranslationContext<?> context, JCNewClass tree) {

1851                 this.owner = owner(true);
1852                 this.depth = frameStack.size() - 1;
1853                 this.prev = context();
1854                 ClassSymbol csym =
1855                         types.makeFunctionalInterfaceClass(attrEnv, names.empty, tree.target, ABSTRACT | INTERFACE);
1856                 this.bridges = types.functionalInterfaceBridges(csym);
1857             }
1858 
1859             /** does this functional expression need to be created using alternate metafactory? */
1860             boolean needsAltMetafactory() {
1861                 return tree.target.isIntersection() ||
1862                         isSerializable() ||
1863                         bridges.length() > 1;
1864             }
1865 
1866             /** does this functional expression require serialization support? */
1867             boolean isSerializable() {
1868                 if (forceSerializable) {
1869                     return true;
1870                 }
1871                 return types.asSuper(tree.target.referenceProjectionOrSelf(), syms.serializableType.tsym) != null;
1872             }
1873 
1874             /**
1875              * @return Name of the enclosing method to be folded into synthetic
1876              * method name
1877              */
1878             String enclosingMethodName() {
1879                 return syntheticMethodNameComponent(owner.name);
1880             }
1881 
1882             /**
1883              * @return Method name in a form that can be folded into a
1884              * component of a synthetic method name
1885              */
1886             String syntheticMethodNameComponent(Name name) {
1887                 if (name == null) {
1888                     return "null";
1889                 }
1890                 String methodName = name.toString();
1891                 if (methodName.equals("<clinit>")) {
1892                     methodName = "static";
1893                 } else if (methodName.equals("<init>")) {
1894                     methodName = "new";
1895                 } else if (methodName.equals("<vnew>")) {
1896                     methodName = "vnew";
1897                 }
1898                 return methodName;
1899             }
1900         }
1901 
1902         /**
1903          * This class retains all the useful information about a lambda expression;
1904          * the contents of this class are filled by the LambdaAnalyzer visitor,
1905          * and the used by the main translation routines in order to adjust references
1906          * to captured locals/members, etc.
1907          */
1908         class LambdaTranslationContext extends TranslationContext<JCLambda> {
1909 
1910             /** variable in the enclosing context to which this lambda is assigned */
1911             final Symbol self;
1912 
1913             /** variable in the enclosing context to which this lambda is assigned */
1914             final Symbol assignedTo;
1915 
1916             Map<LambdaSymbolKind, Map<Symbol, Symbol>> translatedSymbols;

2331                         TypeVar tv = (TypeVar) t;
2332                         return isIntersectionOrUnionType(tv.getUpperBound());
2333                 }
2334                 return false;
2335             }
2336 
2337             /**
2338              * Does this reference need to be converted to a lambda
2339              * (i.e. var args need to be expanded or "super" is used)
2340              */
2341             final boolean needsConversionToLambda() {
2342                 return interfaceParameterIsIntersectionOrUnionType() ||
2343                         isSuper ||
2344                         needsVarArgsConversion() ||
2345                         isArrayOp() ||
2346                         (!nestmateLambdas && isPrivateInOtherClass()) ||
2347                         isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, owner) ||
2348                         !receiverAccessible() ||
2349                         (tree.getMode() == ReferenceMode.NEW &&
2350                           tree.kind != ReferenceKind.ARRAY_CTOR &&
2351                           (tree.sym.owner.isDirectlyOrIndirectlyLocal() || tree.sym.owner.isInner() || tree.sym.owner.isValueClass()));
2352             }
2353 
2354             Type generatedRefSig() {
2355                 return types.erasure(tree.sym.type);
2356             }
2357 
2358             Type bridgedRefSig() {
2359                 return types.erasure(types.findDescriptorSymbol(tree.target.tsym).type);
2360             }
2361         }
2362     }
2363     // </editor-fold>
2364 
2365     /*
2366      * These keys provide mappings for various translated lambda symbols
2367      * and the prevailing order must be maintained.
2368      */
2369     enum LambdaSymbolKind {
2370         PARAM,          // original to translated lambda parameters
2371         LOCAL_VAR,      // original to translated lambda locals
< prev index next >