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

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

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

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

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


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

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

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

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

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

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