--- old/src/share/classes/com/sun/tools/javac/comp/Lower.java 2010-06-28 12:16:15.000000000 -0700 +++ new/src/share/classes/com/sun/tools/javac/comp/Lower.java 2010-06-28 12:16:15.000000000 -0700 @@ -1400,6 +1400,107 @@ } } + /** Optionally replace a try statement with an automatic resource management + * (ARM) block. + * @param tree The try statement to inspect. + * @return An ARM block, or the original try block if there are no + * resources to manage. + */ + JCTree makeTry(JCTry tree) { + if (tree.resources.isEmpty()) { + return tree; + } + make_at(tree.pos()); + JCBlock armBlock = makeArmBlock(tree.resources, tree.body, 0); + if (tree.catchers.isEmpty() && tree.finalizer == null) + result = translate(armBlock); + else + result = translate(make.Try(armBlock, tree.catchers, tree.finalizer)); + return result; + } + + private JCBlock makeArmBlock(List resources, JCBlock block, int depth) { + if (resources.isEmpty()) + return block; + + // Add resource declaration or expression to block statements + ListBuffer stats = new ListBuffer(); + JCTree resource = resources.head; + JCExpression expr = null; + if (resource instanceof JCVariableDecl) { + JCVariableDecl var = (JCVariableDecl) resource; + var.sym.flags_field |= FINAL; + expr = make.Ident(var.sym); + stats.add(var); + } else { + assert resource instanceof JCExpression; + expr = (JCExpression)resource; + stats.add(make.at(resource.pos()).Exec(expr)); + } + + // Add primaryException declaration + VarSymbol primaryException = + new VarSymbol(0, names.fromString("#primaryException" + depth), + syms.throwableType, currentMethodSym); + JCVariableDecl primaryExceptionTreeDecl = make.VarDef(primaryException, makeNull()); + stats.add(primaryExceptionTreeDecl); + + // Create catch clause that saves exception and then rethrows it + VarSymbol param = + new VarSymbol(FINAL, names.fromString("t"), syms.throwableType, currentMethodSym); + JCVariableDecl paramTree = make.VarDef(param, null); + JCStatement assign = make.Assignment(primaryException, make.Ident(param)); + JCStatement rethrowStat = make.Throw(make.Ident(param)); + JCBlock catchBlock = make.Block(0L, List.of(assign, rethrowStat)); + JCCatch catchClause = make.Catch(paramTree, catchBlock); + + int oldPos = make.pos; + make.at(TreeInfo.endPos(block)); + JCBlock finallyClause = makeArmFinallyClause(primaryException, expr); + make.at(oldPos); + JCTry outerTry = make.Try(makeArmBlock(resources.tail, block, depth + 1), + List.of(catchClause), + finallyClause); + stats.add(outerTry); + return make.Block(0L, stats.toList()); + } + + private JCBlock makeArmFinallyClause(Symbol primaryException, JCExpression resource) { + // primaryException.addSuppressedException(catchException); + VarSymbol catchException = + new VarSymbol(0, make.paramName(2), + syms.throwableType, + currentMethodSym); + JCStatement addSuppressionStatement = + make.Exec(makeCall(make.Ident(primaryException), + names.fromString("addSuppressedException"), + List.of(make.Ident(catchException)))); + + // try { resource.close(); } catch (e) { primaryException.addSuppressedException(e); } + JCBlock tryBlock = make.Block(0L, List.of(makeResourceCloseInvocation(resource))); + JCVariableDecl catchExceptionDecl = make.VarDef(catchException, null); + JCBlock catchBlock = make.Block(0L, List.of(addSuppressionStatement)); + List catchClauses = List.of(make.Catch(catchExceptionDecl, catchBlock)); + JCTry tryTree = make.Try(tryBlock, catchClauses, null); + + // if (resource != null) resourceClose; + JCExpression nullCheck = makeBinary(JCTree.NE, make.Ident(primaryException), makeNull()); + JCIf closeIfStatement = make.If(nullCheck, tryTree, makeResourceCloseInvocation(resource)); + return make.Block(0L, List.of(closeIfStatement)); + } + + private JCStatement makeResourceCloseInvocation(JCExpression resource) { + // create resource.close() method invocation + Type autoCloseableType = types.asSuper(resource.type, syms.autoCloseableType.tsym); + Symbol closeMethod = autoCloseableType.tsym.members().lookup(names.close).sym; + JCExpression closeInvocation = make.Select(resource, closeMethod); + JCMethodInvocation resourceClose = make.Apply(List.nil(), + closeInvocation, + List.nil()); + resourceClose.type = closeMethod.type.getReturnType(); + return make.Exec(resourceClose); + } + /** Construct a tree that represents the outer instance * . Never pick the current `this'. * @param pos The source code position to be used for the tree. @@ -3405,6 +3506,12 @@ result = tree; } + @Override + public void visitTry(JCTry tree) { + super.visitTry(tree); + result = makeTry(tree); + } + /************************************************************************** * main method *************************************************************************/