aboutsummaryrefslogtreecommitdiff
path: root/src/jdk/nashorn/internal/ir/LexicalContext.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jdk/nashorn/internal/ir/LexicalContext.java')
-rw-r--r--src/jdk/nashorn/internal/ir/LexicalContext.java151
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;