src/jdk/nashorn/internal/ir/TryNode.java

Fri, 05 Jun 2015 14:46:52 +0530

author
sundar
date
Fri, 05 Jun 2015 14:46:52 +0530
changeset 1397
19263eb2ff0c
parent 1372
644d9b9c97ed
child 1490
d85f981c8cf8
child 1536
bb0fac71c1da
permissions
-rw-r--r--

8081809: Missing final modifier in method parameters (nashorn code convention)
Reviewed-by: attila, lagergren

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.internal.ir;
jlaskey@3 27
jlaskey@3 28 import java.util.ArrayList;
jlaskey@3 29 import java.util.Collections;
attila@1226 30 import java.util.HashSet;
jlaskey@3 31 import java.util.List;
attila@1226 32 import java.util.Set;
lagergren@211 33 import jdk.nashorn.internal.ir.annotations.Immutable;
jlaskey@3 34 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
jlaskey@3 35
jlaskey@3 36 /**
jlaskey@3 37 * IR representation of a TRY statement.
jlaskey@3 38 */
lagergren@211 39 @Immutable
attila@1226 40 public final class TryNode extends LexicalContextStatement implements JoinPredecessor {
attila@1063 41 private static final long serialVersionUID = 1L;
attila@1063 42
jlaskey@3 43 /** Try statements. */
lagergren@211 44 private final Block body;
jlaskey@3 45
jlaskey@3 46 /** List of catch clauses. */
lagergren@211 47 private final List<Block> catchBlocks;
jlaskey@3 48
jlaskey@3 49 /** Finally clause. */
lagergren@211 50 private final Block finallyBody;
jlaskey@3 51
attila@1226 52 /**
attila@1226 53 * List of inlined finally blocks. The structure of every inlined finally is:
attila@1226 54 * Block(LabelNode(label, Block(finally-statements, (JumpStatement|ReturnNode)?))).
attila@1226 55 * That is, the block has a single LabelNode statement with the label and a block containing the
attila@1226 56 * statements of the inlined finally block with the jump or return statement appended (if the finally
attila@1226 57 * block was not terminal; the original jump/return is simply ignored if the finally block itself
attila@1226 58 * terminates). The reason for this somewhat strange arrangement is that we didn't want to create a
attila@1226 59 * separate class for the (label, BlockStatement pair) but rather reused the already available LabelNode.
sundar@1372 60 * However, if we simply used List&lt;LabelNode&gt; without wrapping the label nodes in an additional Block,
attila@1226 61 * that would've thrown off visitors relying on BlockLexicalContext -- same reason why we never use
attila@1226 62 * Statement as the type of bodies of e.g. IfNode, WhileNode etc. but rather blockify them even when they're
attila@1226 63 * single statements.
attila@1226 64 */
attila@1226 65 private final List<Block> inlinedFinallies;
attila@1226 66
jlaskey@3 67 /** Exception symbol. */
jlaskey@3 68 private Symbol exception;
jlaskey@3 69
attila@963 70 private final LocalVariableConversion conversion;
attila@963 71
jlaskey@3 72 /**
jlaskey@3 73 * Constructor
jlaskey@3 74 *
lagergren@253 75 * @param lineNumber lineNumber
lagergren@211 76 * @param token token
lagergren@211 77 * @param finish finish
lagergren@211 78 * @param body try node body
lagergren@211 79 * @param catchBlocks list of catch blocks in order
lagergren@211 80 * @param finallyBody body of finally block or null if none
jlaskey@3 81 */
lagergren@253 82 public TryNode(final int lineNumber, final long token, final int finish, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
lagergren@253 83 super(lineNumber, token, finish);
lagergren@253 84 this.body = body;
lagergren@211 85 this.catchBlocks = catchBlocks;
lagergren@211 86 this.finallyBody = finallyBody;
attila@963 87 this.conversion = null;
attila@1226 88 this.inlinedFinallies = Collections.emptyList();
jlaskey@3 89 }
jlaskey@3 90
attila@1226 91 private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody, final LocalVariableConversion conversion, final List<Block> inlinedFinallies) {
jlaskey@3 92 super(tryNode);
lagergren@253 93 this.body = body;
lagergren@211 94 this.catchBlocks = catchBlocks;
lagergren@211 95 this.finallyBody = finallyBody;
attila@963 96 this.conversion = conversion;
attila@1226 97 this.inlinedFinallies = inlinedFinallies;
attila@963 98 this.exception = tryNode.exception;
jlaskey@3 99 }
jlaskey@3 100
jlaskey@3 101 @Override
lagergren@211 102 public Node ensureUniqueLabels(final LexicalContext lc) {
lagergren@211 103 //try nodes are never in lex context
attila@1226 104 return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies);
lagergren@211 105 }
lagergren@211 106
lagergren@211 107 @Override
lagergren@211 108 public boolean isTerminal() {
lagergren@211 109 if (body.isTerminal()) {
lagergren@211 110 for (final Block catchBlock : getCatchBlocks()) {
lagergren@211 111 if (!catchBlock.isTerminal()) {
lagergren@211 112 return false;
lagergren@211 113 }
lagergren@211 114 }
lagergren@211 115 return true;
lagergren@211 116 }
lagergren@211 117 return false;
jlaskey@3 118 }
jlaskey@3 119
jlaskey@3 120 /**
jlaskey@3 121 * Assist in IR navigation.
jlaskey@3 122 * @param visitor IR navigating visitor.
jlaskey@3 123 */
jlaskey@3 124 @Override
sundar@1397 125 public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
lagergren@211 126 if (visitor.enterTryNode(this)) {
lagergren@211 127 // Need to do finallybody first for termination analysis. TODO still necessary?
lagergren@211 128 final Block newFinallyBody = finallyBody == null ? null : (Block)finallyBody.accept(visitor);
lagergren@211 129 final Block newBody = (Block)body.accept(visitor);
lagergren@211 130 return visitor.leaveTryNode(
attila@1226 131 setBody(lc, newBody).
attila@1226 132 setFinallyBody(lc, newFinallyBody).
attila@1226 133 setCatchBlocks(lc, Node.accept(visitor, catchBlocks)).
attila@1226 134 setInlinedFinallies(lc, Node.accept(visitor, inlinedFinallies)));
jlaskey@3 135 }
jlaskey@3 136
jlaskey@3 137 return this;
jlaskey@3 138 }
jlaskey@3 139
jlaskey@3 140 @Override
attila@963 141 public void toString(final StringBuilder sb, final boolean printType) {
lagergren@211 142 sb.append("try ");
jlaskey@3 143 }
jlaskey@3 144
jlaskey@3 145 /**
jlaskey@3 146 * Get the body for this try block
jlaskey@3 147 * @return body
jlaskey@3 148 */
jlaskey@3 149 public Block getBody() {
jlaskey@3 150 return body;
jlaskey@3 151 }
jlaskey@3 152
jlaskey@3 153 /**
jlaskey@3 154 * Reset the body of this try block
attila@1226 155 * @param lc current lexical context
jlaskey@3 156 * @param body new body
lagergren@211 157 * @return new TryNode or same if unchanged
jlaskey@3 158 */
attila@1226 159 public TryNode setBody(final LexicalContext lc, final Block body) {
lagergren@211 160 if (this.body == body) {
lagergren@211 161 return this;
lagergren@211 162 }
attila@1226 163 return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
jlaskey@3 164 }
jlaskey@3 165
jlaskey@3 166 /**
jlaskey@3 167 * Get the catches for this try block
jlaskey@3 168 * @return a list of catch nodes
jlaskey@3 169 */
jlaskey@3 170 public List<CatchNode> getCatches() {
jlaskey@3 171 final List<CatchNode> catches = new ArrayList<>(catchBlocks.size());
jlaskey@3 172 for (final Block catchBlock : catchBlocks) {
attila@963 173 catches.add(getCatchNodeFromBlock(catchBlock));
jlaskey@3 174 }
lagergren@211 175 return Collections.unmodifiableList(catches);
attila@144 176 }
attila@144 177
attila@963 178 private static CatchNode getCatchNodeFromBlock(final Block catchBlock) {
attila@963 179 return (CatchNode)catchBlock.getStatements().get(0);
attila@963 180 }
attila@963 181
attila@144 182 /**
jlaskey@3 183 * Get the catch blocks for this try block
jlaskey@3 184 * @return a list of blocks
jlaskey@3 185 */
jlaskey@3 186 public List<Block> getCatchBlocks() {
jlaskey@3 187 return Collections.unmodifiableList(catchBlocks);
jlaskey@3 188 }
jlaskey@3 189
jlaskey@3 190 /**
jlaskey@3 191 * Set the catch blocks of this try
attila@1226 192 * @param lc current lexical context
jlaskey@3 193 * @param catchBlocks list of catch blocks
lagergren@211 194 * @return new TryNode or same if unchanged
jlaskey@3 195 */
attila@1226 196 public TryNode setCatchBlocks(final LexicalContext lc, final List<Block> catchBlocks) {
lagergren@211 197 if (this.catchBlocks == catchBlocks) {
lagergren@211 198 return this;
lagergren@211 199 }
attila@1226 200 return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
jlaskey@3 201 }
jlaskey@3 202
jlaskey@3 203 /**
jlaskey@3 204 * Get the exception symbol for this try block
jlaskey@3 205 * @return a symbol for the compiler to store the exception in
jlaskey@3 206 */
jlaskey@3 207 public Symbol getException() {
jlaskey@3 208 return exception;
jlaskey@3 209 }
jlaskey@3 210 /**
jlaskey@3 211 * Set the exception symbol for this try block
jlaskey@3 212 * @param exception a symbol for the compiler to store the exception in
lagergren@211 213 * @return new TryNode or same if unchanged
jlaskey@3 214 */
lagergren@211 215 public TryNode setException(final Symbol exception) {
jlaskey@3 216 this.exception = exception;
lagergren@211 217 return this;
jlaskey@3 218 }
jlaskey@3 219
jlaskey@3 220 /**
jlaskey@3 221 * Get the body of the finally clause for this try
jlaskey@3 222 * @return finally body, or null if no finally
jlaskey@3 223 */
jlaskey@3 224 public Block getFinallyBody() {
jlaskey@3 225 return finallyBody;
jlaskey@3 226 }
jlaskey@3 227
jlaskey@3 228 /**
attila@1226 229 * Get the inlined finally block with the given label name. This returns the actual finally block in the
attila@1226 230 * {@link LabelNode}, not the outer wrapper block for the {@link LabelNode}.
attila@1226 231 * @param labelName the name of the inlined finally's label
attila@1226 232 * @return the requested finally block, or null if no finally block's label matches the name.
attila@1226 233 */
attila@1226 234 public Block getInlinedFinally(final String labelName) {
attila@1226 235 for(final Block inlinedFinally: inlinedFinallies) {
attila@1226 236 final LabelNode labelNode = getInlinedFinallyLabelNode(inlinedFinally);
attila@1226 237 if (labelNode.getLabelName().equals(labelName)) {
attila@1226 238 return labelNode.getBody();
attila@1226 239 }
attila@1226 240 }
attila@1226 241 return null;
attila@1226 242 }
attila@1226 243
attila@1226 244 private static LabelNode getInlinedFinallyLabelNode(final Block inlinedFinally) {
attila@1226 245 return (LabelNode)inlinedFinally.getStatements().get(0);
attila@1226 246 }
attila@1226 247
attila@1226 248 /**
attila@1226 249 * Given an outer wrapper block for the {@link LabelNode} as returned by {@link #getInlinedFinallies()},
attila@1226 250 * returns its actual inlined finally block.
attila@1226 251 * @param inlinedFinally the outer block for inlined finally, as returned as an element of
attila@1226 252 * {@link #getInlinedFinallies()}.
attila@1226 253 * @return the block contained in the {@link LabelNode} contained in the passed block.
attila@1226 254 */
attila@1226 255 public static Block getLabelledInlinedFinallyBlock(final Block inlinedFinally) {
attila@1226 256 return getInlinedFinallyLabelNode(inlinedFinally).getBody();
attila@1226 257 }
attila@1226 258
attila@1226 259 /**
attila@1226 260 * Returns a list of inlined finally blocks. Note that this returns a list of {@link Block}s such that each one of
attila@1226 261 * them has a single {@link LabelNode}, which in turn contains the label name for the finally block and the
attila@1226 262 * actual finally block. To safely extract the actual finally block, use
attila@1226 263 * {@link #getLabelledInlinedFinallyBlock(Block)}.
attila@1226 264 * @return a list of inlined finally blocks.
attila@1226 265 */
attila@1226 266 public List<Block> getInlinedFinallies() {
attila@1226 267 return Collections.unmodifiableList(inlinedFinallies);
attila@1226 268 }
attila@1226 269
attila@1226 270 /**
jlaskey@3 271 * Set the finally body of this try
attila@1226 272 * @param lc current lexical context
jlaskey@3 273 * @param finallyBody new finally body
lagergren@211 274 * @return new TryNode or same if unchanged
jlaskey@3 275 */
attila@1226 276 public TryNode setFinallyBody(final LexicalContext lc, final Block finallyBody) {
lagergren@211 277 if (this.finallyBody == finallyBody) {
lagergren@211 278 return this;
lagergren@211 279 }
attila@1226 280 return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
attila@1226 281 }
attila@1226 282
attila@1226 283 /**
attila@1226 284 * Set the inlined finally blocks of this try. Each element should be a block with a single statement that is a
attila@1226 285 * {@link LabelNode} with a unique label, and the block within the label node should contain the actual inlined
attila@1226 286 * finally block.
attila@1226 287 * @param lc current lexical context
attila@1226 288 * @param inlinedFinallies list of inlined finally blocks
attila@1226 289 * @return new TryNode or same if unchanged
attila@1226 290 */
attila@1226 291 public TryNode setInlinedFinallies(final LexicalContext lc, final List<Block> inlinedFinallies) {
attila@1226 292 if (this.inlinedFinallies == inlinedFinallies) {
attila@1226 293 return this;
attila@1226 294 }
attila@1226 295 assert checkInlinedFinallies(inlinedFinallies);
attila@1226 296 return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
attila@1226 297 }
attila@1226 298
attila@1226 299 private static boolean checkInlinedFinallies(final List<Block> inlinedFinallies) {
attila@1226 300 if (!inlinedFinallies.isEmpty()) {
attila@1226 301 final Set<String> labels = new HashSet<>();
attila@1226 302 for (final Block inlinedFinally : inlinedFinallies) {
attila@1226 303 final List<Statement> stmts = inlinedFinally.getStatements();
attila@1226 304 assert stmts.size() == 1;
attila@1226 305 final LabelNode ln = getInlinedFinallyLabelNode(inlinedFinally);
attila@1226 306 assert labels.add(ln.getLabelName()); // unique label
attila@1226 307 }
attila@1226 308 }
attila@1226 309 return true;
attila@963 310 }
attila@963 311
attila@963 312 @Override
attila@963 313 public JoinPredecessor setLocalVariableConversion(final LexicalContext lc, final LocalVariableConversion conversion) {
attila@963 314 if(this.conversion == conversion) {
attila@963 315 return this;
attila@963 316 }
attila@1226 317 return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies);
attila@963 318 }
attila@963 319
attila@963 320 @Override
attila@963 321 public LocalVariableConversion getLocalVariableConversion() {
attila@963 322 return conversion;
jlaskey@3 323 }
jlaskey@3 324 }

mercurial