diff options
Diffstat (limited to 'src/jdk/nashorn/internal/ir/LexicalContext.java')
-rw-r--r-- | src/jdk/nashorn/internal/ir/LexicalContext.java | 151 |
1 files changed, 95 insertions, 56 deletions
diff --git a/src/jdk/nashorn/internal/ir/LexicalContext.java b/src/jdk/nashorn/internal/ir/LexicalContext.java index 1b380d38..487d6aeb 100644 --- a/src/jdk/nashorn/internal/ir/LexicalContext.java +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java @@ -27,7 +27,6 @@ package jdk.nashorn.internal.ir; import java.io.File; import java.util.Iterator; import java.util.NoSuchElementException; -import jdk.nashorn.internal.codegen.Label; import jdk.nashorn.internal.runtime.Debug; import jdk.nashorn.internal.runtime.Source; @@ -148,6 +147,7 @@ public class LexicalContext { * @return the node that was pushed */ public <T extends LexicalContextNode> T push(final T node) { + assert !contains(node); if (sp == stack.length) { final LexicalContextNode[] newStack = new LexicalContextNode[sp * 2]; System.arraycopy(stack, 0, newStack, 0, sp); @@ -201,6 +201,18 @@ public class LexicalContext { return (T)popped; } + /** + * Explicitly apply flags to the topmost element on the stack. This is only valid to use from a + * {@code NodeVisitor.leaveXxx()} method and only on the node being exited at the time. It is not mandatory to use, + * as {@link #pop(LexicalContextNode)} will apply the flags automatically, but this method can be used to apply them + * during the {@code leaveXxx()} method in case its logic depends on the value of the flags. + * @param node the node to apply the flags to. Must be the topmost node on the stack. + * @return the passed in node, or a modified node (if any flags were modified) + */ + public <T extends LexicalContextNode & Flags<T>> T applyTopFlags(final T node) { + assert node == peek(); + return node.setFlag(this, flags[sp - 1]); + } /** * Return the top element in the context @@ -233,10 +245,9 @@ public class LexicalContext { * @return the new node */ public LexicalContextNode replace(final LexicalContextNode oldNode, final LexicalContextNode newNode) { - //System.err.println("REPLACE old=" + Debug.id(oldNode) + " new=" + Debug.id(newNode)); for (int i = sp - 1; i >= 0; i--) { if (stack[i] == oldNode) { - assert i == (sp - 1) : "violation of contract - we always expect to find the replacement node on top of the lexical context stack: " + newNode + " has " + stack[i + 1].getClass() + " above it"; + assert i == sp - 1 : "violation of contract - we always expect to find the replacement node on top of the lexical context stack: " + newNode + " has " + stack[i + 1].getClass() + " above it"; stack[i] = newNode; break; } @@ -271,6 +282,31 @@ public class LexicalContext { } /** + * Gets the label node of the current block. + * @return the label node of the current block, if it is labeled. Otherwise returns null. + */ + public LabelNode getCurrentBlockLabelNode() { + assert stack[sp - 1] instanceof Block; + if(sp < 2) { + return null; + } + final LexicalContextNode parent = stack[sp - 2]; + return parent instanceof LabelNode ? (LabelNode)parent : null; + } + + + /* + public FunctionNode getProgram() { + final Iterator<FunctionNode> iter = getFunctions(); + FunctionNode last = null; + while (iter.hasNext()) { + last = iter.next(); + } + assert last != null; + return last; + }*/ + + /** * Returns an iterator over all ancestors block of the given block, with its parent block first. * @param block the block whose ancestors are returned * @return an iterator over all ancestors block of the given block. @@ -315,8 +351,7 @@ public class LexicalContext { } /** - * Get the function for this block. If the block is itself a function - * this returns identity + * Get the function for this block. * @param block block for which to get function * @return function for block */ @@ -364,9 +399,6 @@ public class LexicalContext { * @return block in which the symbol is defined, assert if no such block in context */ public Block getDefiningBlock(final Symbol symbol) { - if (symbol.isTemp()) { - return null; - } final String name = symbol.getName(); for (final Iterator<Block> it = getBlocks(); it.hasNext();) { final Block next = it.next(); @@ -382,10 +414,7 @@ public class LexicalContext { * @param symbol symbol * @return function node in which this symbol is defined, assert if no such symbol exists in context */ - public FunctionNode getDefiningFunction(Symbol symbol) { - if (symbol.isTemp()) { - return null; - } + public FunctionNode getDefiningFunction(final Symbol symbol) { final String name = symbol.getName(); for (final Iterator<LexicalContextNode> iter = new NodeIterator<>(LexicalContextNode.class); iter.hasNext();) { final LexicalContextNode next = iter.next(); @@ -393,7 +422,7 @@ public class LexicalContext { while (iter.hasNext()) { final LexicalContextNode next2 = iter.next(); if (next2 instanceof FunctionNode) { - return ((FunctionNode)next2); + return (FunctionNode)next2; } } throw new AssertionError("Defining block for symbol " + name + " has no function in the context"); @@ -411,19 +440,11 @@ public class LexicalContext { } /** - * Returns true if the expression defining the function is a callee of a CallNode that should be the second - * element on the stack, e.g. <code>(function(){})()</code>. That is, if the stack ends with - * {@code [..., CallNode, FunctionNode]} then {@code callNode.getFunction()} should be equal to - * {@code functionNode}, and the top of the stack should itself be a variant of {@code functionNode}. - * @param functionNode the function node being tested - * @return true if the expression defining the current function is a callee of a call expression. + * Is the topmost lexical context element body of a SplitNode? + * @return true if it's the body of a split node. */ - public boolean isFunctionDefinedInCurrentCall(FunctionNode functionNode) { - final LexicalContextNode parent = stack[sp - 2]; - if (parent instanceof CallNode && ((CallNode)parent).getFunction() == functionNode) { - return true; - } - return false; + public boolean isSplitBody() { + return sp >= 2 && stack[sp - 1] instanceof Block && stack[sp - 2] instanceof SplitNode; } /** @@ -444,15 +465,26 @@ public class LexicalContext { } /** - * Count the number of with scopes until a given node - * @param until node to stop counting at, or null if all nodes should be counted + * Count the number of scopes until a given node. Note that this method is solely used to figure out the number of + * scopes that need to be explicitly popped in order to perform a break or continue jump within the current bytecode + * method. For this reason, the method returns 0 if it encounters a {@code SplitNode} between the current location + * and the break/continue target. + * @param until node to stop counting at. Must be within the current function * @return number of with scopes encountered in the context */ public int getScopeNestingLevelTo(final LexicalContextNode until) { + assert until != null; //count the number of with nodes until "until" is hit int n = 0; - for (final Iterator<WithNode> iter = new NodeIterator<>(WithNode.class, until); iter.hasNext(); iter.next()) { - n++; + for (final Iterator<LexicalContextNode> iter = getAllNodes(); iter.hasNext();) { + final LexicalContextNode node = iter.next(); + if (node == until) { + break; + } + assert !(node instanceof FunctionNode); // Can't go outside current function + if (node instanceof WithNode || node instanceof Block && ((Block)node).needsScope()) { + n++; + } } return n; } @@ -486,12 +518,13 @@ public class LexicalContext { /** * Find the breakable node corresponding to this label. - * @param label label to search for, if null the closest breakable node will be returned unconditionally, e.g. a while loop with no label + * @param labelName name of the label to search for. If null, the closest breakable node will be returned + * unconditionally, e.g. a while loop with no label * @return closest breakable node */ - public BreakableNode getBreakable(final IdentNode label) { - if (label != null) { - final LabelNode foundLabel = findLabel(label.getName()); + public BreakableNode getBreakable(final String labelName) { + if (labelName != null) { + final LabelNode foundLabel = findLabel(labelName); if (foundLabel != null) { // iterate to the nearest breakable to the foundLabel BreakableNode breakable = null; @@ -511,12 +544,13 @@ public class LexicalContext { /** * Find the continue target node corresponding to this label. - * @param label label to search for, if null the closest loop node will be returned unconditionally, e.g. a while loop with no label + * @param labelName label name to search for. If null the closest loop node will be returned unconditionally, e.g. a + * while loop with no label * @return closest continue target node */ - public LoopNode getContinueTo(final IdentNode label) { - if (label != null) { - final LabelNode foundLabel = findLabel(label.getName()); + public LoopNode getContinueTo(final String labelName) { + if (labelName != null) { + final LabelNode foundLabel = findLabel(labelName); if (foundLabel != null) { // iterate to the nearest loop to the foundLabel LoopNode loop = null; @@ -538,7 +572,7 @@ public class LexicalContext { public LabelNode findLabel(final String name) { for (final Iterator<LabelNode> iter = new NodeIterator<>(LabelNode.class, getCurrentFunction()); iter.hasNext(); ) { final LabelNode next = iter.next(); - if (next.getLabel().getName().equals(name)) { + if (next.getLabelName().equals(name)) { return next; } } @@ -546,30 +580,34 @@ public class LexicalContext { } /** - * Checks whether a given label is a jump destination that lies outside a given - * split node + * Checks whether a given target is a jump destination that lies outside a given split node * @param splitNode the split node - * @param label the label - * @return true if label resides outside the split node + * @param target the target node + * @return true if target resides outside the split node */ - public boolean isExternalTarget(final SplitNode splitNode, final Label label) { - boolean targetFound = false; - for (int i = sp - 1; i >= 0; i--) { + public boolean isExternalTarget(final SplitNode splitNode, final BreakableNode target) { + for (int i = sp; i-- > 0;) { final LexicalContextNode next = stack[i]; if (next == splitNode) { - return !targetFound; + return true; + } else if (next == target) { + return false; } + } + throw new AssertionError(target + " was expected in lexical context " + LexicalContext.this + " but wasn't"); + } - if (next instanceof BreakableNode) { - for (final Label l : ((BreakableNode)next).getLabels()) { - if (l == label) { - targetFound = true; - break; - } - } + /** + * Checks whether the current context is inside a switch statement without explicit blocks (curly braces). + * @return true if in unprotected switch statement + */ + public boolean inUnprotectedSwitchContext() { + for (int i = sp; i > 0; i--) { + final LexicalContextNode next = stack[i]; + if (next instanceof Block) { + return stack[i - 1] instanceof SwitchNode; } } - assert false : label + " was expected in lexical context " + LexicalContext.this + " but wasn't"; return false; } @@ -627,11 +665,12 @@ public class LexicalContext { if (next == null) { throw new NoSuchElementException(); } - T lnext = next; + final T lnext = next; next = findNext(); return lnext; } + @SuppressWarnings("unchecked") private T findNext() { for (int i = index; i >= 0; i--) { final Object node = stack[i]; @@ -640,7 +679,7 @@ public class LexicalContext { } if (clazz.isAssignableFrom(node.getClass())) { index = i - 1; - return clazz.cast(node); + return (T)node; } } return null; |