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