src/share/classes/com/sun/tools/javac/comp/Lower.java

Print this page

        

*** 603,612 **** --- 603,629 ---- */ private void enterSynthetic(DiagnosticPosition pos, Symbol sym, Scope s) { s.enter(sym); } + /** Create a fresh synthetic name within a given scope - the unique name is + * obtained by appending '$' chars at the end of the name until no match + * is found. + * + * @param name base name + * @param s scope in which the name has to be unique + * @return fresh synthetic name + */ + private Name makeSyntheticName(Name name, Scope s) { + do { + name = name.append( + target.syntheticNameChar(), + names.empty); + } while (lookupSynthetic(name, s) != null); + return name; + } + /** Check whether synthetic symbols generated during lowering conflict * with user-defined symbols. * * @param translatedTrees lowered class trees */
*** 1297,1306 **** --- 1314,1328 ---- * in an additional innermost scope, where they represent the constructor * parameters. */ Scope proxies; + /** A scope containing all unnamed resource variables/saved + * exception variables for translated TWR blocks + */ + Scope twrVars; + /** A stack containing the this$n field of the currently translated * classes (if needed) in innermost first order. * Inside a constructor, proxies and any this$n symbol are duplicated * in an additional innermost scope, where they represent the constructor * parameters.
*** 1398,1407 **** --- 1420,1545 ---- // need to go via this$n return makeOuterThis(pos, c); } } + /** 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 makeArmTry(JCTry tree) { + make_at(tree.pos()); + twrVars = twrVars.dup(); + 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)); + twrVars = twrVars.leave(); + return result; + } + + private JCBlock makeArmBlock(List<JCTree> resources, JCBlock block, int depth) { + if (resources.isEmpty()) + return block; + + // Add resource declaration or expression to block statements + ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>(); + JCTree resource = resources.head; + JCExpression expr = null; + if (resource instanceof JCVariableDecl) { + JCVariableDecl var = (JCVariableDecl) resource; + expr = make.Ident(var.sym).setType(resource.type); + stats.add(var); + } else { + assert resource instanceof JCExpression; + VarSymbol syntheticTwrVar = + new VarSymbol(SYNTHETIC | FINAL, + makeSyntheticName(names.fromString("twrVar" + + depth), twrVars), + (resource.type.tag == TypeTags.BOT) ? + syms.autoCloseableType : resource.type, + currentMethodSym); + twrVars.enter(syntheticTwrVar); + JCVariableDecl syntheticTwrVarDecl = + make.VarDef(syntheticTwrVar, (JCExpression)resource); + expr = (JCExpression)make.Ident(syntheticTwrVar); + stats.add(syntheticTwrVarDecl); + } + + // Add primaryException declaration + VarSymbol primaryException = + new VarSymbol(SYNTHETIC, + makeSyntheticName(names.fromString("primaryException" + + depth), twrVars), + syms.throwableType, + currentMethodSym); + twrVars.enter(primaryException); + JCVariableDecl primaryExceptionTreeDecl = make.VarDef(primaryException, makeNull()); + stats.add(primaryExceptionTreeDecl); + + // Create catch clause that saves exception and then rethrows it + VarSymbol param = + new VarSymbol(FINAL|SYNTHETIC, + names.fromString("t" + + target.syntheticNameChar()), + 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.<JCStatement>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.<JCCatch>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.<JCExpression>of(make.Ident(catchException)))); + + // try { resource.close(); } catch (e) { primaryException.addSuppressedException(e); } + JCBlock tryBlock = + make.Block(0L, List.<JCStatement>of(makeResourceCloseInvocation(resource))); + JCVariableDecl catchExceptionDecl = make.VarDef(catchException, null); + JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(addSuppressionStatement)); + List<JCCatch> catchClauses = List.<JCCatch>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.<JCStatement>of(closeIfStatement)); + } + + private JCStatement makeResourceCloseInvocation(JCExpression resource) { + // create resource.close() method invocation + JCExpression resourceClose = makeCall(resource, names.close, List.<JCExpression>nil()); + return make.Exec(resourceClose); + } + /** Construct a tree that represents the outer instance * <C.this>. Never pick the current `this'. * @param pos The source code position to be used for the tree. * @param c The qualifier class. */
*** 3403,3412 **** --- 3541,3559 ---- // we don't generate code. public void visitAnnotation(JCAnnotation tree) { result = tree; } + @Override + public void visitTry(JCTry tree) { + if (tree.resources.isEmpty()) { + super.visitTry(tree); + } else { + result = makeArmTry(tree); + } + } + /************************************************************************** * main method *************************************************************************/ /** Translate a toplevel class and return a list consisting of
*** 3428,3437 **** --- 3575,3585 ---- this.translated = new ListBuffer<JCTree>(); classdefs = new HashMap<ClassSymbol,JCClassDecl>(); actualSymbols = new HashMap<Symbol,Symbol>(); freevarCache = new HashMap<ClassSymbol,List<VarSymbol>>(); proxies = new Scope(syms.noSymbol); + twrVars = new Scope(syms.noSymbol); outerThisStack = List.nil(); accessNums = new HashMap<Symbol,Integer>(); accessSyms = new HashMap<Symbol,MethodSymbol[]>(); accessConstrs = new HashMap<Symbol,MethodSymbol>(); accessConstrTags = List.nil();