TryNode.java revision 1068:34ef988d5959
1/* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.nashorn.internal.ir; 27 28import java.util.ArrayList; 29import java.util.Collections; 30import java.util.List; 31import jdk.nashorn.internal.ir.annotations.Immutable; 32import jdk.nashorn.internal.ir.visitor.NodeVisitor; 33 34/** 35 * IR representation of a TRY statement. 36 */ 37@Immutable 38public final class TryNode extends Statement implements JoinPredecessor { 39 private static final long serialVersionUID = 1L; 40 41 /** Try statements. */ 42 private final Block body; 43 44 /** List of catch clauses. */ 45 private final List<Block> catchBlocks; 46 47 /** Finally clause. */ 48 private final Block finallyBody; 49 50 /** Exception symbol. */ 51 private Symbol exception; 52 53 /** Catchall exception for finally expansion, where applicable */ 54 private Symbol finallyCatchAll; 55 56 private final LocalVariableConversion conversion; 57 58 /** 59 * Constructor 60 * 61 * @param lineNumber lineNumber 62 * @param token token 63 * @param finish finish 64 * @param body try node body 65 * @param catchBlocks list of catch blocks in order 66 * @param finallyBody body of finally block or null if none 67 */ 68 public TryNode(final int lineNumber, final long token, final int finish, final Block body, final List<Block> catchBlocks, final Block finallyBody) { 69 super(lineNumber, token, finish); 70 this.body = body; 71 this.catchBlocks = catchBlocks; 72 this.finallyBody = finallyBody; 73 this.conversion = null; 74 } 75 76 private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody, final LocalVariableConversion conversion) { 77 super(tryNode); 78 this.body = body; 79 this.catchBlocks = catchBlocks; 80 this.finallyBody = finallyBody; 81 this.conversion = conversion; 82 this.exception = tryNode.exception; 83 } 84 85 @Override 86 public Node ensureUniqueLabels(final LexicalContext lc) { 87 //try nodes are never in lex context 88 return new TryNode(this, body, catchBlocks, finallyBody, conversion); 89 } 90 91 @Override 92 public boolean isTerminal() { 93 if (body.isTerminal()) { 94 for (final Block catchBlock : getCatchBlocks()) { 95 if (!catchBlock.isTerminal()) { 96 return false; 97 } 98 } 99 return true; 100 } 101 return false; 102 } 103 104 /** 105 * Assist in IR navigation. 106 * @param visitor IR navigating visitor. 107 */ 108 @Override 109 public Node accept(final NodeVisitor<? extends LexicalContext> visitor) { 110 if (visitor.enterTryNode(this)) { 111 // Need to do finallybody first for termination analysis. TODO still necessary? 112 final Block newFinallyBody = finallyBody == null ? null : (Block)finallyBody.accept(visitor); 113 final Block newBody = (Block)body.accept(visitor); 114 return visitor.leaveTryNode( 115 setBody(newBody). 116 setFinallyBody(newFinallyBody). 117 setCatchBlocks(Node.accept(visitor, catchBlocks)). 118 setFinallyCatchAll(finallyCatchAll)); 119 } 120 121 return this; 122 } 123 124 @Override 125 public void toString(final StringBuilder sb, final boolean printType) { 126 sb.append("try "); 127 } 128 129 /** 130 * Get the body for this try block 131 * @return body 132 */ 133 public Block getBody() { 134 return body; 135 } 136 137 /** 138 * Reset the body of this try block 139 * @param body new body 140 * @return new TryNode or same if unchanged 141 */ 142 public TryNode setBody(final Block body) { 143 if (this.body == body) { 144 return this; 145 } 146 return new TryNode(this, body, catchBlocks, finallyBody, conversion); 147 } 148 149 /** 150 * Get the catches for this try block 151 * @return a list of catch nodes 152 */ 153 public List<CatchNode> getCatches() { 154 final List<CatchNode> catches = new ArrayList<>(catchBlocks.size()); 155 for (final Block catchBlock : catchBlocks) { 156 catches.add(getCatchNodeFromBlock(catchBlock)); 157 } 158 return Collections.unmodifiableList(catches); 159 } 160 161 private static CatchNode getCatchNodeFromBlock(final Block catchBlock) { 162 return (CatchNode)catchBlock.getStatements().get(0); 163 } 164 165 /** 166 * Get the catch blocks for this try block 167 * @return a list of blocks 168 */ 169 public List<Block> getCatchBlocks() { 170 return Collections.unmodifiableList(catchBlocks); 171 } 172 173 /** 174 * Set the catch blocks of this try 175 * @param catchBlocks list of catch blocks 176 * @return new TryNode or same if unchanged 177 */ 178 public TryNode setCatchBlocks(final List<Block> catchBlocks) { 179 if (this.catchBlocks == catchBlocks) { 180 return this; 181 } 182 return new TryNode(this, body, catchBlocks, finallyBody, conversion); 183 } 184 185 /** 186 * Get the exception symbol for this try block 187 * @return a symbol for the compiler to store the exception in 188 */ 189 public Symbol getException() { 190 return exception; 191 } 192 /** 193 * Set the exception symbol for this try block 194 * @param exception a symbol for the compiler to store the exception in 195 * @return new TryNode or same if unchanged 196 */ 197 public TryNode setException(final Symbol exception) { 198 this.exception = exception; 199 return this; 200 } 201 202 /** 203 * Get the catch all symbol for this try block 204 * @return catch all symbol 205 */ 206 public Symbol getFinallyCatchAll() { 207 return this.finallyCatchAll; 208 } 209 210 /** 211 * If a finally block exists, the synthetic catchall needs another symbol to 212 * store its throwable 213 * @param finallyCatchAll a symbol for the finally catch all exception 214 * @return new TryNode or same if unchanged 215 * 216 * TODO can this still be stateful? 217 */ 218 public TryNode setFinallyCatchAll(final Symbol finallyCatchAll) { 219 this.finallyCatchAll = finallyCatchAll; 220 return this; 221 } 222 223 /** 224 * Get the body of the finally clause for this try 225 * @return finally body, or null if no finally 226 */ 227 public Block getFinallyBody() { 228 return finallyBody; 229 } 230 231 /** 232 * Set the finally body of this try 233 * @param finallyBody new finally body 234 * @return new TryNode or same if unchanged 235 */ 236 public TryNode setFinallyBody(final Block finallyBody) { 237 if (this.finallyBody == finallyBody) { 238 return this; 239 } 240 return new TryNode(this, body, catchBlocks, finallyBody, conversion); 241 } 242 243 @Override 244 public JoinPredecessor setLocalVariableConversion(final LexicalContext lc, final LocalVariableConversion conversion) { 245 if(this.conversion == conversion) { 246 return this; 247 } 248 return new TryNode(this, body, catchBlocks, finallyBody, conversion); 249 } 250 251 @Override 252 public LocalVariableConversion getLocalVariableConversion() { 253 return conversion; 254 } 255} 256