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

Thu, 25 Jul 2013 11:56:12 +0200

author
hannesw
date
Thu, 25 Jul 2013 11:56:12 +0200
changeset 471
f74faac51bfb
parent 466
2a25917777f7
child 952
6d5471a497fb
child 962
ac62e33a99b0
permissions
-rw-r--r--

8021244: Inconsistent stackmap with splitter threshold set very low
Reviewed-by: sundar, lagergren

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

mercurial