langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
changeset 37638 aac00923d48e
parent 36526 3b41f1c69604
child 39806 d3a13ca6013e
equal deleted inserted replaced
37637:b47af0433922 37638:aac00923d48e
    84     private final Target target;
    84     private final Target target;
    85     private final Source source;
    85     private final Source source;
    86     private final TypeEnvs typeEnvs;
    86     private final TypeEnvs typeEnvs;
    87     private final Name dollarAssertionsDisabled;
    87     private final Name dollarAssertionsDisabled;
    88     private final Name classDollar;
    88     private final Name classDollar;
       
    89     private final Name dollarCloseResource;
    89     private final Types types;
    90     private final Types types;
    90     private final boolean debugLower;
    91     private final boolean debugLower;
    91     private final PkgInfo pkginfoOpt;
    92     private final PkgInfo pkginfoOpt;
    92 
    93 
    93     protected Lower(Context context) {
    94     protected Lower(Context context) {
   107         typeEnvs = TypeEnvs.instance(context);
   108         typeEnvs = TypeEnvs.instance(context);
   108         dollarAssertionsDisabled = names.
   109         dollarAssertionsDisabled = names.
   109             fromString(target.syntheticNameChar() + "assertionsDisabled");
   110             fromString(target.syntheticNameChar() + "assertionsDisabled");
   110         classDollar = names.
   111         classDollar = names.
   111             fromString("class" + target.syntheticNameChar());
   112             fromString("class" + target.syntheticNameChar());
       
   113         dollarCloseResource = names.
       
   114             fromString(target.syntheticNameChar() + "closeResource");
   112 
   115 
   113         types = Types.instance(context);
   116         types = Types.instance(context);
   114         Options options = Options.instance(context);
   117         Options options = Options.instance(context);
   115         debugLower = options.isSet("debuglower");
   118         debugLower = options.isSet("debuglower");
   116         pkginfoOpt = PkgInfo.get(options);
   119         pkginfoOpt = PkgInfo.get(options);
  1646 
  1649 
  1647         // Add resource declaration or expression to block statements
  1650         // Add resource declaration or expression to block statements
  1648         ListBuffer<JCStatement> stats = new ListBuffer<>();
  1651         ListBuffer<JCStatement> stats = new ListBuffer<>();
  1649         JCTree resource = resources.head;
  1652         JCTree resource = resources.head;
  1650         JCExpression expr = null;
  1653         JCExpression expr = null;
       
  1654         boolean resourceNonNull;
  1651         if (resource instanceof JCVariableDecl) {
  1655         if (resource instanceof JCVariableDecl) {
  1652             JCVariableDecl var = (JCVariableDecl) resource;
  1656             JCVariableDecl var = (JCVariableDecl) resource;
  1653             expr = make.Ident(var.sym).setType(resource.type);
  1657             expr = make.Ident(var.sym).setType(resource.type);
       
  1658             resourceNonNull = var.init != null && TreeInfo.skipParens(var.init).hasTag(NEWCLASS);
  1654             stats.add(var);
  1659             stats.add(var);
  1655         } else {
  1660         } else {
  1656             Assert.check(resource instanceof JCExpression);
  1661             Assert.check(resource instanceof JCExpression);
  1657             VarSymbol syntheticTwrVar =
  1662             VarSymbol syntheticTwrVar =
  1658             new VarSymbol(SYNTHETIC | FINAL,
  1663             new VarSymbol(SYNTHETIC | FINAL,
  1663                           currentMethodSym);
  1668                           currentMethodSym);
  1664             twrVars.enter(syntheticTwrVar);
  1669             twrVars.enter(syntheticTwrVar);
  1665             JCVariableDecl syntheticTwrVarDecl =
  1670             JCVariableDecl syntheticTwrVarDecl =
  1666                 make.VarDef(syntheticTwrVar, (JCExpression)resource);
  1671                 make.VarDef(syntheticTwrVar, (JCExpression)resource);
  1667             expr = (JCExpression)make.Ident(syntheticTwrVar);
  1672             expr = (JCExpression)make.Ident(syntheticTwrVar);
       
  1673             resourceNonNull = TreeInfo.skipParens(resource).hasTag(NEWCLASS);
  1668             stats.add(syntheticTwrVarDecl);
  1674             stats.add(syntheticTwrVarDecl);
  1669         }
  1675         }
  1670 
  1676 
  1671         // Add primaryException declaration
  1677         // Add primaryException declaration
  1672         VarSymbol primaryException =
  1678         VarSymbol primaryException =
  1692         JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(assign, rethrowStat));
  1698         JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(assign, rethrowStat));
  1693         JCCatch catchClause = make.Catch(paramTree, catchBlock);
  1699         JCCatch catchClause = make.Catch(paramTree, catchBlock);
  1694 
  1700 
  1695         int oldPos = make.pos;
  1701         int oldPos = make.pos;
  1696         make.at(TreeInfo.endPos(block));
  1702         make.at(TreeInfo.endPos(block));
  1697         JCBlock finallyClause = makeTwrFinallyClause(primaryException, expr);
  1703         JCBlock finallyClause = makeTwrFinallyClause(primaryException, expr, resourceNonNull);
  1698         make.at(oldPos);
  1704         make.at(oldPos);
  1699         JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block,
  1705         JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block,
  1700                                     finallyCanCompleteNormally, depth + 1),
  1706                                     finallyCanCompleteNormally, depth + 1),
  1701                                   List.<JCCatch>of(catchClause),
  1707                                   List.<JCCatch>of(catchClause),
  1702                                   finallyClause);
  1708                                   finallyClause);
  1704         stats.add(outerTry);
  1710         stats.add(outerTry);
  1705         JCBlock newBlock = make.Block(0L, stats.toList());
  1711         JCBlock newBlock = make.Block(0L, stats.toList());
  1706         return newBlock;
  1712         return newBlock;
  1707     }
  1713     }
  1708 
  1714 
  1709     private JCBlock makeTwrFinallyClause(Symbol primaryException, JCExpression resource) {
  1715     /**If the estimated number of copies the close resource code in a single class is above this
       
  1716      * threshold, generate and use a method for the close resource code, leading to smaller code.
       
  1717      * As generating a method has overhead on its own, generating the method for cases below the
       
  1718      * threshold could lead to an increase in code size.
       
  1719      */
       
  1720     public static final int USE_CLOSE_RESOURCE_METHOD_THRESHOLD = 4;
       
  1721 
       
  1722     private JCBlock makeTwrFinallyClause(Symbol primaryException, JCExpression resource,
       
  1723             boolean resourceNonNull) {
       
  1724         MethodSymbol closeResource = (MethodSymbol)lookupSynthetic(dollarCloseResource,
       
  1725                                                                    currentClass.members());
       
  1726 
       
  1727         if (closeResource == null && shouldUseCloseResourceMethod()) {
       
  1728             closeResource = new MethodSymbol(
       
  1729                 PRIVATE | STATIC | SYNTHETIC,
       
  1730                 dollarCloseResource,
       
  1731                 new MethodType(
       
  1732                     List.of(syms.throwableType, syms.autoCloseableType),
       
  1733                     syms.voidType,
       
  1734                     List.<Type>nil(),
       
  1735                     syms.methodClass),
       
  1736                 currentClass);
       
  1737             enterSynthetic(resource.pos(), closeResource, currentClass.members());
       
  1738 
       
  1739             JCMethodDecl md = make.MethodDef(closeResource, null);
       
  1740             List<JCVariableDecl> params = md.getParameters();
       
  1741             md.body = make.Block(0, List.<JCStatement>of(makeTwrCloseStatement(params.get(0).sym,
       
  1742                                                                                make.Ident(params.get(1)))));
       
  1743 
       
  1744             JCClassDecl currentClassDecl = classDef(currentClass);
       
  1745             currentClassDecl.defs = currentClassDecl.defs.prepend(md);
       
  1746         }
       
  1747 
       
  1748         JCStatement closeStatement;
       
  1749 
       
  1750         if (closeResource != null) {
       
  1751             //$closeResource(#primaryException, #resource)
       
  1752             closeStatement = make.Exec(make.Apply(List.<JCExpression>nil(),
       
  1753                                                   make.Ident(closeResource),
       
  1754                                                   List.of(make.Ident(primaryException),
       
  1755                                                           resource)
       
  1756                                                  ).setType(syms.voidType));
       
  1757         } else {
       
  1758             closeStatement = makeTwrCloseStatement(primaryException, resource);
       
  1759         }
       
  1760 
       
  1761         JCStatement finallyStatement;
       
  1762 
       
  1763         if (resourceNonNull) {
       
  1764             finallyStatement = closeStatement;
       
  1765         } else {
       
  1766             // if (#resource != null) { $closeResource(...); }
       
  1767             finallyStatement = make.If(makeNonNullCheck(resource),
       
  1768                                        closeStatement,
       
  1769                                        null);
       
  1770         }
       
  1771 
       
  1772         return make.Block(0L,
       
  1773                           List.<JCStatement>of(finallyStatement));
       
  1774     }
       
  1775         //where:
       
  1776         private boolean shouldUseCloseResourceMethod() {
       
  1777             class TryFinder extends TreeScanner {
       
  1778                 int closeCount;
       
  1779                 @Override
       
  1780                 public void visitTry(JCTry tree) {
       
  1781                     boolean empty = tree.body.stats.isEmpty();
       
  1782 
       
  1783                     for (JCTree r : tree.resources) {
       
  1784                         closeCount += empty ? 1 : 2;
       
  1785                         empty = false; //with multiple resources, only the innermost try can be empty.
       
  1786                     }
       
  1787                     super.visitTry(tree);
       
  1788                 }
       
  1789                 @Override
       
  1790                 public void scan(JCTree tree) {
       
  1791                     if (useCloseResourceMethod())
       
  1792                         return;
       
  1793                     super.scan(tree);
       
  1794                 }
       
  1795                 boolean useCloseResourceMethod() {
       
  1796                     return closeCount >= USE_CLOSE_RESOURCE_METHOD_THRESHOLD;
       
  1797                 }
       
  1798             }
       
  1799             TryFinder tryFinder = new TryFinder();
       
  1800             tryFinder.scan(classDef(currentClass));
       
  1801             return tryFinder.useCloseResourceMethod();
       
  1802         }
       
  1803 
       
  1804     private JCStatement makeTwrCloseStatement(Symbol primaryException, JCExpression resource) {
  1710         // primaryException.addSuppressed(catchException);
  1805         // primaryException.addSuppressed(catchException);
  1711         VarSymbol catchException =
  1806         VarSymbol catchException =
  1712             new VarSymbol(SYNTHETIC, make.paramName(2),
  1807             new VarSymbol(SYNTHETIC, make.paramName(2),
  1713                           syms.throwableType,
  1808                           syms.throwableType,
  1714                           currentMethodSym);
  1809                           currentMethodSym);
  1729         // if (primaryException != null) {try...} else resourceClose;
  1824         // if (primaryException != null) {try...} else resourceClose;
  1730         JCIf closeIfStatement = make.If(makeNonNullCheck(make.Ident(primaryException)),
  1825         JCIf closeIfStatement = make.If(makeNonNullCheck(make.Ident(primaryException)),
  1731                                         tryTree,
  1826                                         tryTree,
  1732                                         makeResourceCloseInvocation(resource));
  1827                                         makeResourceCloseInvocation(resource));
  1733 
  1828 
  1734         // if (#resource != null) { if (primaryException ...  }
  1829         return closeIfStatement;
  1735         return make.Block(0L,
       
  1736                           List.<JCStatement>of(make.If(makeNonNullCheck(resource),
       
  1737                                                        closeIfStatement,
       
  1738                                                        null)));
       
  1739     }
  1830     }
  1740 
  1831 
  1741     private JCStatement makeResourceCloseInvocation(JCExpression resource) {
  1832     private JCStatement makeResourceCloseInvocation(JCExpression resource) {
  1742         // convert to AutoCloseable if needed
  1833         // convert to AutoCloseable if needed
  1743         if (types.asSuper(resource.type, syms.autoCloseableType.tsym) == null) {
  1834         if (types.asSuper(resource.type, syms.autoCloseableType.tsym) == null) {