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

Fri, 03 May 2013 15:33:54 +0200

author
lagergren
date
Fri, 03 May 2013 15:33:54 +0200
changeset 247
5a3f7867e19c
parent 211
3a209cbd1d8f
child 252
544e17632e96
permissions
-rw-r--r--

8013477: Node.setSymbol needs to be copy on write - enable IR snapshots for recompilation based on callsite type specialization. [not enabled by default, hidden by a flag for now]
Reviewed-by: jlaskey, hannesw

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.io.PrintWriter;
jlaskey@3 29 import java.util.ArrayList;
lagergren@211 30 import java.util.Arrays;
jlaskey@3 31 import java.util.Collections;
lagergren@57 32 import java.util.Comparator;
lagergren@211 33 import java.util.LinkedHashMap;
jlaskey@3 34 import java.util.List;
lagergren@211 35 import java.util.Map;
lagergren@96 36 import jdk.nashorn.internal.codegen.Label;
lagergren@211 37 import jdk.nashorn.internal.ir.annotations.Immutable;
jlaskey@3 38 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
jlaskey@3 39 import jdk.nashorn.internal.runtime.Source;
jlaskey@3 40
jlaskey@3 41 /**
jlaskey@3 42 * IR representation for a list of statements and functions. All provides the
jlaskey@3 43 * basis for script body.
jlaskey@3 44 */
lagergren@211 45 @Immutable
lagergren@211 46 public class Block extends BreakableNode implements Flags<Block> {
jlaskey@3 47 /** List of statements */
lagergren@211 48 protected final List<Node> statements;
jlaskey@3 49
lagergren@211 50 /** Symbol table - keys must be returned in the order they were put in. */
lagergren@211 51 protected final Map<String, Symbol> symbols;
jlaskey@3 52
jlaskey@3 53 /** Entry label. */
jlaskey@3 54 protected final Label entryLabel;
jlaskey@3 55
lagergren@211 56 /** Does the block/function need a new scope? */
lagergren@211 57 protected final int flags;
jlaskey@3 58
lagergren@211 59 /** Flag indicating that this block needs scope */
lagergren@211 60 public static final int NEEDS_SCOPE = 1 << 0;
lagergren@211 61
lagergren@211 62 /**
lagergren@211 63 * Flag indicating whether this block needs
lagergren@211 64 * self symbol assignment at the start. This is used only for
lagergren@211 65 * blocks that are the bodies of function nodes who refer to themselves
lagergren@211 66 * by name. It causes codegen to insert a var [fn_name] = __callee__
lagergren@211 67 * at the start of the body
lagergren@211 68 */
lagergren@211 69 public static final int NEEDS_SELF_SYMBOL = 1 << 1;
lagergren@211 70
lagergren@211 71 /**
lagergren@211 72 * Is this block tagged as terminal based on its contents
lagergren@211 73 * (usually the last statement)
lagergren@211 74 */
lagergren@211 75 public static final int IS_TERMINAL = 1 << 2;
jlaskey@3 76
jlaskey@3 77 /**
jlaskey@3 78 * Constructor
jlaskey@3 79 *
lagergren@211 80 * @param source source code
lagergren@211 81 * @param token token
lagergren@211 82 * @param finish finish
lagergren@211 83 * @param statements statements
jlaskey@3 84 */
lagergren@211 85 public Block(final Source source, final long token, final int finish, final Node... statements) {
lagergren@211 86 super(source, token, finish, new Label("block_break"));
jlaskey@3 87
lagergren@211 88 this.statements = Arrays.asList(statements);
lagergren@211 89 this.symbols = new LinkedHashMap<>();
jlaskey@3 90 this.entryLabel = new Label("block_entry");
lagergren@211 91 this.flags = 0;
jlaskey@3 92 }
jlaskey@3 93
jlaskey@3 94 /**
lagergren@211 95 * Constructor
jlaskey@3 96 *
lagergren@211 97 * @param source source code
lagergren@211 98 * @param token token
lagergren@211 99 * @param finish finish
lagergren@211 100 * @param statements statements
jlaskey@3 101 */
lagergren@211 102 public Block(final Source source, final long token, final int finish, final List<Node> statements) {
lagergren@211 103 this(source, token, finish, statements.toArray(new Node[statements.size()]));
lagergren@211 104 }
lagergren@211 105
lagergren@247 106 private Block(final Block block, final int finish, final List<Node> statements, final int flags, final Map<String, Symbol> symbols) {
jlaskey@3 107 super(block);
lagergren@211 108 this.statements = statements;
lagergren@211 109 this.flags = flags;
lagergren@247 110 this.symbols = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
lagergren@96 111 this.entryLabel = new Label(block.entryLabel);
lagergren@247 112 this.finish = finish;
lagergren@247 113 }
lagergren@247 114
lagergren@247 115 /**
lagergren@247 116 * Clear the symbols in a block
lagergren@247 117 * TODO: make this immutable
lagergren@247 118 */
lagergren@247 119 public void clearSymbols() {
lagergren@247 120 symbols.clear();
jlaskey@3 121 }
jlaskey@3 122
jlaskey@3 123 @Override
lagergren@211 124 public Node ensureUniqueLabels(final LexicalContext lc) {
lagergren@247 125 return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols));
jlaskey@3 126 }
jlaskey@3 127
jlaskey@3 128 /**
jlaskey@3 129 * Assist in IR navigation.
jlaskey@3 130 *
jlaskey@3 131 * @param visitor IR navigating visitor.
jlaskey@3 132 * @return new or same node
jlaskey@3 133 */
jlaskey@3 134 @Override
lagergren@211 135 public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
lagergren@211 136 if (visitor.enterBlock(this)) {
lagergren@211 137 return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Node.class, statements)));
jlaskey@3 138 }
jlaskey@3 139
jlaskey@3 140 return this;
jlaskey@3 141 }
jlaskey@3 142
jlaskey@3 143 /**
lagergren@137 144 * Get an iterator for all the symbols defined in this block
lagergren@137 145 * @return symbol iterator
lagergren@137 146 */
lagergren@247 147 public List<Symbol> getSymbols() {
lagergren@247 148 return Collections.unmodifiableList(new ArrayList<>(symbols.values()));
lagergren@137 149 }
lagergren@137 150
lagergren@137 151 /**
attila@144 152 * Retrieves an existing symbol defined in the current block.
attila@144 153 * @param name the name of the symbol
attila@144 154 * @return an existing symbol with the specified name defined in the current block, or null if this block doesn't
lagergren@247 155 * define a symbol with this name.T
jlaskey@3 156 */
attila@144 157 public Symbol getExistingSymbol(final String name) {
attila@144 158 return symbols.get(name);
jlaskey@3 159 }
jlaskey@3 160
jlaskey@3 161 /**
jlaskey@3 162 * Test if this block represents a <tt>catch</tt> block in a <tt>try</tt> statement.
jlaskey@3 163 * This is used by the Splitter as catch blocks are not be subject to splitting.
jlaskey@3 164 *
jlaskey@3 165 * @return true if this block represents a catch block in a try statement.
jlaskey@3 166 */
jlaskey@3 167 public boolean isCatchBlock() {
jlaskey@3 168 return statements.size() == 1 && statements.get(0) instanceof CatchNode;
jlaskey@3 169 }
jlaskey@3 170
jlaskey@3 171 @Override
jlaskey@3 172 public void toString(final StringBuilder sb) {
jlaskey@3 173 for (final Node statement : statements) {
jlaskey@3 174 statement.toString(sb);
jlaskey@3 175 sb.append(';');
jlaskey@3 176 }
jlaskey@3 177 }
jlaskey@3 178
jlaskey@3 179 /**
lagergren@57 180 * Print symbols in block in alphabetical order, sorted on name
lagergren@57 181 * Used for debugging, see the --print-symbols flag
jlaskey@3 182 *
jlaskey@3 183 * @param stream print writer to output symbols to
jlaskey@3 184 *
jlaskey@3 185 * @return true if symbols were found
jlaskey@3 186 */
jlaskey@3 187 public boolean printSymbols(final PrintWriter stream) {
lagergren@57 188 final List<Symbol> values = new ArrayList<>(symbols.values());
lagergren@57 189
lagergren@57 190 Collections.sort(values, new Comparator<Symbol>() {
lagergren@57 191 @Override
lagergren@57 192 public int compare(final Symbol s0, final Symbol s1) {
lagergren@57 193 return s0.getName().compareTo(s1.getName());
lagergren@57 194 }
lagergren@57 195 });
jlaskey@3 196
jlaskey@3 197 for (final Symbol symbol : values) {
jlaskey@3 198 symbol.print(stream);
jlaskey@3 199 }
jlaskey@3 200
jlaskey@3 201 return !values.isEmpty();
jlaskey@3 202 }
jlaskey@3 203
jlaskey@3 204 /**
lagergren@211 205 * Tag block as terminal or non terminal
lagergren@211 206 * @param lc lexical context
lagergren@211 207 * @param isTerminal is block terminal
lagergren@211 208 * @return same block, or new if flag changed
jlaskey@3 209 */
lagergren@211 210 public Block setIsTerminal(final LexicalContext lc, final boolean isTerminal) {
lagergren@211 211 return isTerminal ? setFlag(lc, IS_TERMINAL) : clearFlag(lc, IS_TERMINAL);
lagergren@211 212 }
lagergren@211 213
lagergren@211 214 @Override
lagergren@211 215 public boolean isTerminal() {
lagergren@211 216 return getFlag(IS_TERMINAL);
jlaskey@3 217 }
jlaskey@3 218
jlaskey@3 219 /**
jlaskey@3 220 * Get the entry label for this block
jlaskey@3 221 * @return the entry label
jlaskey@3 222 */
jlaskey@3 223 public Label getEntryLabel() {
jlaskey@3 224 return entryLabel;
jlaskey@3 225 }
jlaskey@3 226
jlaskey@3 227 /**
jlaskey@3 228 * Get the list of statements in this block
jlaskey@3 229 *
jlaskey@3 230 * @return a list of statements
jlaskey@3 231 */
jlaskey@3 232 public List<Node> getStatements() {
jlaskey@3 233 return Collections.unmodifiableList(statements);
jlaskey@3 234 }
jlaskey@3 235
jlaskey@3 236 /**
jlaskey@3 237 * Reset the statement list for this block
jlaskey@3 238 *
lagergren@211 239 * @param lc lexical context
lagergren@211 240 * @param statements new statement list
lagergren@211 241 * @return new block if statements changed, identity of statements == block.statements
jlaskey@3 242 */
lagergren@211 243 public Block setStatements(final LexicalContext lc, final List<Node> statements) {
lagergren@211 244 if (this.statements == statements) {
lagergren@211 245 return this;
lagergren@211 246 }
lagergren@211 247 int lastFinish = 0;
lagergren@211 248 if (!statements.isEmpty()) {
lagergren@211 249 lastFinish = statements.get(statements.size() - 1).getFinish();
lagergren@211 250 }
lagergren@247 251 return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags, symbols));
jlaskey@3 252 }
jlaskey@3 253
jlaskey@3 254 /**
jlaskey@3 255 * Add or overwrite an existing symbol in the block
jlaskey@3 256 *
lagergren@247 257 * @param lc get lexical context
jlaskey@3 258 * @param symbol symbol
jlaskey@3 259 */
lagergren@247 260 public void putSymbol(final LexicalContext lc, final Symbol symbol) {
lagergren@247 261 symbols.put(symbol.getName(), symbol);
jlaskey@3 262 }
jlaskey@3 263
jlaskey@3 264 /**
jlaskey@3 265 * Check whether scope is necessary for this Block
jlaskey@3 266 *
jlaskey@3 267 * @return true if this function needs a scope
jlaskey@3 268 */
jlaskey@3 269 public boolean needsScope() {
lagergren@211 270 return (flags & NEEDS_SCOPE) == NEEDS_SCOPE;
lagergren@211 271 }
lagergren@211 272
lagergren@211 273 @Override
lagergren@211 274 public Block setFlags(final LexicalContext lc, int flags) {
lagergren@211 275 if (this.flags == flags) {
lagergren@211 276 return this;
lagergren@211 277 }
lagergren@247 278 return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols));
lagergren@211 279 }
lagergren@211 280
lagergren@211 281 @Override
lagergren@211 282 public Block clearFlag(final LexicalContext lc, int flag) {
lagergren@211 283 return setFlags(lc, flags & ~flag);
lagergren@211 284 }
lagergren@211 285
lagergren@211 286 @Override
lagergren@211 287 public Block setFlag(final LexicalContext lc, int flag) {
lagergren@211 288 return setFlags(lc, flags | flag);
lagergren@211 289 }
lagergren@211 290
lagergren@211 291 @Override
lagergren@211 292 public boolean getFlag(final int flag) {
lagergren@211 293 return (flags & flag) == flag;
jlaskey@3 294 }
jlaskey@3 295
jlaskey@3 296 /**
lagergren@24 297 * Set the needs scope flag.
lagergren@211 298 * @param lc lexicalContext
lagergren@211 299 * @return new block if state changed, otherwise this
jlaskey@3 300 */
lagergren@211 301 public Block setNeedsScope(final LexicalContext lc) {
lagergren@211 302 if (needsScope()) {
lagergren@211 303 return this;
lagergren@211 304 }
lagergren@211 305
lagergren@247 306 return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE, symbols));
jlaskey@3 307 }
jlaskey@3 308
attila@144 309 /**
lagergren@211 310 * Computationally determine the next slot for this block,
lagergren@211 311 * indexed from 0. Use this as a relative base when computing
lagergren@211 312 * frames
lagergren@211 313 * @return next slot
attila@144 314 */
lagergren@211 315 public int nextSlot() {
lagergren@211 316 int next = 0;
lagergren@247 317 for (final Symbol symbol : getSymbols()) {
lagergren@247 318 if (symbol.hasSlot()) {
lagergren@247 319 next += symbol.slotCount();
lagergren@247 320 }
lagergren@211 321 }
lagergren@211 322 return next;
attila@144 323 }
attila@144 324
lagergren@211 325 @Override
lagergren@211 326 protected boolean isBreakableWithoutLabel() {
lagergren@211 327 return false;
attila@144 328 }
jlaskey@3 329 }

mercurial