src/share/classes/com/sun/tools/javac/comp/Lower.java
Print this page
@@ -603,10 +603,28 @@
*/
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,10 +1315,15 @@
* 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 ARM blocks
+ */
+ Scope armVars;
+
/** 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,10 +1421,126 @@
// 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());
+ armVars = armVars.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));
+ armVars = armVars.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 syntheticArmVar =
+ new VarSymbol(SYNTHETIC | FINAL,
+ makeSyntheticName(names.fromString("armVar" +
+ depth), armVars),
+ (resource.type.tag == TypeTags.BOT) ?
+ syms.autoCloseableType : resource.type,
+ currentMethodSym);
+ armVars.enter(syntheticArmVar);
+ JCVariableDecl syntheticArmVarDecl =
+ make.VarDef(syntheticArmVar, (JCExpression)resource);
+ expr = (JCExpression)make.Ident(syntheticArmVar);
+ stats.add(syntheticArmVarDecl);
+ }
+
+ // Add primaryException declaration
+ VarSymbol primaryException =
+ new VarSymbol(SYNTHETIC,
+ makeSyntheticName(names.fromString("primaryException" +
+ depth), armVars),
+ syms.throwableType,
+ currentMethodSym);
+ armVars.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,10 +3542,19 @@
// 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,10 +3576,11 @@
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);
+ armVars = 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();