--- old/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java 2020-04-15 18:48:10.000000000 +0530 +++ /dev/null 2020-04-15 18:48:10.000000000 +0530 @@ -1,328 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.nashorn.internal.ir; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import jdk.nashorn.internal.ir.annotations.Immutable; -import jdk.nashorn.internal.ir.visitor.NodeVisitor; - -/** - * IR representation of a TRY statement. - */ -@Immutable -public final class TryNode extends LexicalContextStatement implements JoinPredecessor { - private static final long serialVersionUID = 1L; - - /** Try statements. */ - private final Block body; - - /** List of catch clauses. */ - private final List catchBlocks; - - /** Finally clause. */ - private final Block finallyBody; - - /** - * List of inlined finally blocks. The structure of every inlined finally is: - * Block(LabelNode(label, Block(finally-statements, (JumpStatement|ReturnNode)?))). - * That is, the block has a single LabelNode statement with the label and a block containing the - * statements of the inlined finally block with the jump or return statement appended (if the finally - * block was not terminal; the original jump/return is simply ignored if the finally block itself - * terminates). The reason for this somewhat strange arrangement is that we didn't want to create a - * separate class for the (label, BlockStatement pair) but rather reused the already available LabelNode. - * However, if we simply used List<LabelNode> without wrapping the label nodes in an additional Block, - * that would've thrown off visitors relying on BlockLexicalContext -- same reason why we never use - * Statement as the type of bodies of e.g. IfNode, WhileNode etc. but rather blockify them even when they're - * single statements. - */ - private final List inlinedFinallies; - - /** Exception symbol. */ - private final Symbol exception; - - private final LocalVariableConversion conversion; - - /** - * Constructor - * - * @param lineNumber lineNumber - * @param token token - * @param finish finish - * @param body try node body - * @param catchBlocks list of catch blocks in order - * @param finallyBody body of finally block or null if none - */ - public TryNode(final int lineNumber, final long token, final int finish, final Block body, final List catchBlocks, final Block finallyBody) { - super(lineNumber, token, finish); - this.body = body; - this.catchBlocks = catchBlocks; - this.finallyBody = finallyBody; - this.conversion = null; - this.inlinedFinallies = Collections.emptyList(); - this.exception = null; - } - - private TryNode(final TryNode tryNode, final Block body, final List catchBlocks, final Block finallyBody, final LocalVariableConversion conversion, final List inlinedFinallies, final Symbol exception) { - super(tryNode); - this.body = body; - this.catchBlocks = catchBlocks; - this.finallyBody = finallyBody; - this.conversion = conversion; - this.inlinedFinallies = inlinedFinallies; - this.exception = exception; - } - - @Override - public Node ensureUniqueLabels(final LexicalContext lc) { - //try nodes are never in lex context - return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception); - } - - @Override - public boolean isTerminal() { - if (body.isTerminal()) { - for (final Block catchBlock : getCatchBlocks()) { - if (!catchBlock.isTerminal()) { - return false; - } - } - return true; - } - return false; - } - - /** - * Assist in IR navigation. - * @param visitor IR navigating visitor. - */ - @Override - public Node accept(final LexicalContext lc, final NodeVisitor visitor) { - if (visitor.enterTryNode(this)) { - // Need to do finallybody first for termination analysis. TODO still necessary? - final Block newFinallyBody = finallyBody == null ? null : (Block)finallyBody.accept(visitor); - final Block newBody = (Block)body.accept(visitor); - return visitor.leaveTryNode( - setBody(lc, newBody). - setFinallyBody(lc, newFinallyBody). - setCatchBlocks(lc, Node.accept(visitor, catchBlocks)). - setInlinedFinallies(lc, Node.accept(visitor, inlinedFinallies))); - } - - return this; - } - - @Override - public void toString(final StringBuilder sb, final boolean printType) { - sb.append("try "); - } - - /** - * Get the body for this try block - * @return body - */ - public Block getBody() { - return body; - } - - /** - * Reset the body of this try block - * @param lc current lexical context - * @param body new body - * @return new TryNode or same if unchanged - */ - public TryNode setBody(final LexicalContext lc, final Block body) { - if (this.body == body) { - return this; - } - return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception)); - } - - /** - * Get the catches for this try block - * @return a list of catch nodes - */ - public List getCatches() { - final List catches = new ArrayList<>(catchBlocks.size()); - for (final Block catchBlock : catchBlocks) { - catches.add(getCatchNodeFromBlock(catchBlock)); - } - return Collections.unmodifiableList(catches); - } - - private static CatchNode getCatchNodeFromBlock(final Block catchBlock) { - return (CatchNode)catchBlock.getStatements().get(0); - } - - /** - * Get the catch blocks for this try block - * @return a list of blocks - */ - public List getCatchBlocks() { - return Collections.unmodifiableList(catchBlocks); - } - - /** - * Set the catch blocks of this try - * @param lc current lexical context - * @param catchBlocks list of catch blocks - * @return new TryNode or same if unchanged - */ - public TryNode setCatchBlocks(final LexicalContext lc, final List catchBlocks) { - if (this.catchBlocks == catchBlocks) { - return this; - } - return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception)); - } - - /** - * Get the exception symbol for this try block - * @return a symbol for the compiler to store the exception in - */ - public Symbol getException() { - return exception; - } - /** - * Set the exception symbol for this try block - * @param lc lexical context - * @param exception a symbol for the compiler to store the exception in - * @return new TryNode or same if unchanged - */ - public TryNode setException(final LexicalContext lc, final Symbol exception) { - if (this.exception == exception) { - return this; - } - return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception)); - } - - /** - * Get the body of the finally clause for this try - * @return finally body, or null if no finally - */ - public Block getFinallyBody() { - return finallyBody; - } - - /** - * Get the inlined finally block with the given label name. This returns the actual finally block in the - * {@link LabelNode}, not the outer wrapper block for the {@link LabelNode}. - * @param labelName the name of the inlined finally's label - * @return the requested finally block, or null if no finally block's label matches the name. - */ - public Block getInlinedFinally(final String labelName) { - for(final Block inlinedFinally: inlinedFinallies) { - final LabelNode labelNode = getInlinedFinallyLabelNode(inlinedFinally); - if (labelNode.getLabelName().equals(labelName)) { - return labelNode.getBody(); - } - } - return null; - } - - private static LabelNode getInlinedFinallyLabelNode(final Block inlinedFinally) { - return (LabelNode)inlinedFinally.getStatements().get(0); - } - - /** - * Given an outer wrapper block for the {@link LabelNode} as returned by {@link #getInlinedFinallies()}, - * returns its actual inlined finally block. - * @param inlinedFinally the outer block for inlined finally, as returned as an element of - * {@link #getInlinedFinallies()}. - * @return the block contained in the {@link LabelNode} contained in the passed block. - */ - public static Block getLabelledInlinedFinallyBlock(final Block inlinedFinally) { - return getInlinedFinallyLabelNode(inlinedFinally).getBody(); - } - - /** - * Returns a list of inlined finally blocks. Note that this returns a list of {@link Block}s such that each one of - * them has a single {@link LabelNode}, which in turn contains the label name for the finally block and the - * actual finally block. To safely extract the actual finally block, use - * {@link #getLabelledInlinedFinallyBlock(Block)}. - * @return a list of inlined finally blocks. - */ - public List getInlinedFinallies() { - return Collections.unmodifiableList(inlinedFinallies); - } - - /** - * Set the finally body of this try - * @param lc current lexical context - * @param finallyBody new finally body - * @return new TryNode or same if unchanged - */ - public TryNode setFinallyBody(final LexicalContext lc, final Block finallyBody) { - if (this.finallyBody == finallyBody) { - return this; - } - return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception)); - } - - /** - * Set the inlined finally blocks of this try. Each element should be a block with a single statement that is a - * {@link LabelNode} with a unique label, and the block within the label node should contain the actual inlined - * finally block. - * @param lc current lexical context - * @param inlinedFinallies list of inlined finally blocks - * @return new TryNode or same if unchanged - */ - public TryNode setInlinedFinallies(final LexicalContext lc, final List inlinedFinallies) { - if (this.inlinedFinallies == inlinedFinallies) { - return this; - } - assert checkInlinedFinallies(inlinedFinallies); - return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception)); - } - - private static boolean checkInlinedFinallies(final List inlinedFinallies) { - if (!inlinedFinallies.isEmpty()) { - final Set labels = new HashSet<>(); - for (final Block inlinedFinally : inlinedFinallies) { - final List stmts = inlinedFinally.getStatements(); - assert stmts.size() == 1; - final LabelNode ln = getInlinedFinallyLabelNode(inlinedFinally); - assert labels.add(ln.getLabelName()); // unique label - } - } - return true; - } - - @Override - public JoinPredecessor setLocalVariableConversion(final LexicalContext lc, final LocalVariableConversion conversion) { - if(this.conversion == conversion) { - return this; - } - return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception); - } - - @Override - public LocalVariableConversion getLocalVariableConversion() { - return conversion; - } -}