Mercurial > hg > openjdk > jigsaw > nashorn
view src/jdk/nashorn/internal/ir/Block.java @ 143:4be452026847
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
Reviewed-by: jlaskey, lagergren
author | attila |
---|---|
date | Sat, 23 Mar 2013 00:58:39 +0100 |
parents | e15806b9d716 |
children |
line wrap: on
line source
/* * 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.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import jdk.nashorn.internal.codegen.Frame; import jdk.nashorn.internal.codegen.Label; import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.runtime.Source; /** * IR representation for a list of statements and functions. All provides the * basis for script body. */ public class Block extends Node { /** List of statements */ protected List<Node> statements; /** Symbol table. */ protected final HashMap<String, Symbol> symbols; /** Variable frame. */ protected Frame frame; /** Entry label. */ protected final Label entryLabel; /** Break label. */ protected final Label breakLabel; /** Does the block/function need a new scope? */ protected boolean needsScope; /** * Constructor * * @param source source code * @param token token * @param finish finish */ public Block(final Source source, final long token, final int finish) { super(source, token, finish); this.statements = new ArrayList<>(); this.symbols = new HashMap<>(); this.entryLabel = new Label("block_entry"); this.breakLabel = new Label("block_break"); } /** * Internal copy constructor * * @param block the source block * @param cs the copy state */ protected Block(final Block block, final CopyState cs) { super(block); this.statements = new ArrayList<>(); for (final Node statement : block.getStatements()) { statements.add(cs.existingOrCopy(statement)); } this.symbols = new HashMap<>(); this.frame = block.frame == null ? null : block.frame.copy(); this.entryLabel = new Label(block.entryLabel); this.breakLabel = new Label(block.breakLabel); assert block.symbols.isEmpty() : "must not clone with symbols"; } @Override protected Node copy(final CopyState cs) { return new Block(this, cs); } /** * Add a new statement to the statement list. * * @param statement Statement node to add. */ public void addStatement(final Node statement) { if (statement != null) { statements.add(statement); if (getFinish() < statement.getFinish()) { setFinish(statement.getFinish()); } } } /** * Prepend statements to the statement list * * @param prepended statement to add */ public void prependStatements(final List<Node> prepended) { statements.addAll(0, prepended); } /** * Add a list of statements to the statement list. * * @param statementList Statement nodes to add. */ public void addStatements(final List<Node> statementList) { statements.addAll(statementList); } /** * Assist in IR navigation. * * @param visitor IR navigating visitor. * @return new or same node */ @Override public Node accept(final NodeVisitor visitor) { final Block saveBlock = visitor.getCurrentBlock(); visitor.setCurrentBlock(this); try { // Ignore parent to avoid recursion. if (visitor.enterBlock(this) != null) { visitStatements(visitor); return visitor.leaveBlock(this); } } finally { visitor.setCurrentBlock(saveBlock); } return this; } /** * Get an iterator for all the symbols defined in this block * @return symbol iterator */ public Iterator<Symbol> symbolIterator() { return symbols.values().iterator(); } /** * Retrieves an existing symbol defined in the current block. * @param name the name of the symbol * @return an existing symbol with the specified name defined in the current block, or null if this block doesn't * define a symbol with this name. */ public Symbol getExistingSymbol(final String name) { return symbols.get(name); } /** * Test if this block represents a <tt>catch</tt> block in a <tt>try</tt> statement. * This is used by the Splitter as catch blocks are not be subject to splitting. * * @return true if this block represents a catch block in a try statement. */ public boolean isCatchBlock() { return statements.size() == 1 && statements.get(0) instanceof CatchNode; } @Override public void toString(final StringBuilder sb) { for (final Node statement : statements) { statement.toString(sb); sb.append(';'); } } /** * Print symbols in block in alphabetical order, sorted on name * Used for debugging, see the --print-symbols flag * * @param stream print writer to output symbols to * * @return true if symbols were found */ public boolean printSymbols(final PrintWriter stream) { final List<Symbol> values = new ArrayList<>(symbols.values()); Collections.sort(values, new Comparator<Symbol>() { @Override public int compare(final Symbol s0, final Symbol s1) { return s0.getName().compareTo(s1.getName()); } }); for (final Symbol symbol : values) { symbol.print(stream); } return !values.isEmpty(); } /** * Get the break label for this block * @return the break label */ public Label getBreakLabel() { return breakLabel; } /** * Get the entry label for this block * @return the entry label */ public Label getEntryLabel() { return entryLabel; } /** * Get the frame for this block * @return the frame */ public Frame getFrame() { return frame; } /** * Reset the frame for this block * * @param frame the new frame */ public void setFrame(final Frame frame) { this.frame = frame; } /** * Get the list of statements in this block * * @return a list of statements */ public List<Node> getStatements() { return Collections.unmodifiableList(statements); } /** * Applies the specified visitor to all statements in the block. * @param visitor the visitor. */ public void visitStatements(NodeVisitor visitor) { for (ListIterator<Node> stmts = statements.listIterator(); stmts.hasNext();) { stmts.set(stmts.next().accept(visitor)); } } /** * Reset the statement list for this block * * @param statements new statement list */ public void setStatements(final List<Node> statements) { this.statements = statements; } /** * Add or overwrite an existing symbol in the block * * @param name name of symbol * @param symbol symbol */ public void putSymbol(final String name, final Symbol symbol) { symbols.put(name, symbol); } /** * Check whether scope is necessary for this Block * * @return true if this function needs a scope */ public boolean needsScope() { return needsScope; } /** * Set the needs scope flag. */ public void setNeedsScope() { needsScope = true; } /** * Marks this block as using a specified scoped symbol. The block and its parent blocks up to but not * including the block defining the symbol will be marked as needing parent scope. The block defining the symbol * will be marked as one that needs to have its own scope. * @param symbol the symbol being used. * @param ancestors the iterator over block's containing lexical context */ public void setUsesScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) { if(symbol.getBlock() == this) { setNeedsScope(); } else { setUsesParentScopeSymbol(symbol, ancestors); } } /** * Invoked when this block uses a scope symbol defined in one of its ancestors. * @param symbol the scope symbol being used * @param ancestors iterator over ancestor blocks */ void setUsesParentScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) { if(ancestors.hasNext()) { ancestors.next().setUsesScopeSymbol(symbol, ancestors); } } }