< 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);

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

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

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

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


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

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

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

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

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

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