diff options
Diffstat (limited to 'src/jdk/nashorn/internal/ir/CallNode.java')
-rw-r--r-- | src/jdk/nashorn/internal/ir/CallNode.java | 165 |
1 files changed, 82 insertions, 83 deletions
diff --git a/src/jdk/nashorn/internal/ir/CallNode.java b/src/jdk/nashorn/internal/ir/CallNode.java index 3410709c..9a730aa8 100644 --- a/src/jdk/nashorn/internal/ir/CallNode.java +++ b/src/jdk/nashorn/internal/ir/CallNode.java @@ -25,49 +25,48 @@ package jdk.nashorn.internal.ir; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.annotations.Ignore; +import jdk.nashorn.internal.ir.annotations.Immutable; import jdk.nashorn.internal.ir.visitor.NodeVisitor; import jdk.nashorn.internal.runtime.Source; /** * IR representation for a function call. - * */ -public class CallNode extends Node implements TypeOverride<CallNode> { +@Immutable +public final class CallNode extends LexicalContextNode implements TypeOverride<CallNode> { - private Type type; + private final Type type; /** Function identifier or function body. */ - private Node function; + private final Node function; /** Call arguments. */ - private List<Node> args; + private final List<Node> args; - /** flag - is new expression */ - private boolean isNew; + /** Is this a "new" operation */ + public static final int IS_NEW = 0x1; - /** flag - is in with block */ - private boolean inWithBlock; + private final int flags; /** * Arguments to be passed to builtin {@code eval} function */ public static class EvalArgs { /** evaluated code */ - private Node code; + private final Node code; /** 'this' passed to evaluated code */ - private IdentNode evalThis; + private final IdentNode evalThis; /** location string for the eval call */ - final private String location; + private final String location; /** is this call from a strict context? */ - final private boolean strictMode; + private final boolean strictMode; /** * Constructor @@ -92,12 +91,11 @@ public class CallNode extends Node implements TypeOverride<CallNode> { return code; } - /** - * Set the code that is to be eval.ed by this eval function - * @param code the code as an AST node - */ - public void setCode(final Node code) { - this.code = code; + private EvalArgs setCode(final Node code) { + if (this.code == code) { + return this; + } + return new EvalArgs(code, evalThis, location, strictMode); } /** @@ -108,12 +106,11 @@ public class CallNode extends Node implements TypeOverride<CallNode> { return this.evalThis; } - /** - * Set the {@code this} symbol used to invoke this eval call - * @param evalThis the {@code this} symbol - */ - public void setThis(final IdentNode evalThis) { - this.evalThis = evalThis; + private EvalArgs setThis(final IdentNode evalThis) { + if (this.evalThis == evalThis) { + return this; + } + return new EvalArgs(code, evalThis, location, strictMode); } /** @@ -135,7 +132,7 @@ public class CallNode extends Node implements TypeOverride<CallNode> { /** arguments for 'eval' call. Non-null only if this call node is 'eval' */ @Ignore - private EvalArgs evalArgs; + private final EvalArgs evalArgs; /** * Constructors @@ -149,28 +146,22 @@ public class CallNode extends Node implements TypeOverride<CallNode> { public CallNode(final Source source, final long token, final int finish, final Node function, final List<Node> args) { super(source, token, finish); - setStart(function.getStart()); - - this.function = function; - this.args = args; + this.function = function; + this.args = args; + this.flags = 0; + this.type = null; + this.evalArgs = null; } - private CallNode(final CallNode callNode, final CopyState cs) { + private CallNode(final CallNode callNode, final Node function, final List<Node> args, final int flags, final Type type, final EvalArgs evalArgs) { super(callNode); - - final List<Node> newArgs = new ArrayList<>(); - - for (final Node arg : callNode.args) { - newArgs.add(cs.existingOrCopy(arg)); - } - - this.function = cs.existingOrCopy(callNode.function); //TODO existing or same? - this.args = newArgs; - this.isNew = callNode.isNew; - this.inWithBlock = callNode.inWithBlock; + this.function = function; + this.args = args; + this.flags = flags; + this.type = type; + this.evalArgs = evalArgs; } - @Override public Type getType() { if (hasCallSiteType()) { @@ -181,8 +172,10 @@ public class CallNode extends Node implements TypeOverride<CallNode> { @Override public CallNode setType(final Type type) { - this.type = type; - return this; + if (this.type == type) { + return this; + } + return new CallNode(this, function, args, flags, type, evalArgs); } private boolean hasCallSiteType() { @@ -194,11 +187,6 @@ public class CallNode extends Node implements TypeOverride<CallNode> { return true; } - @Override - protected Node copy(final CopyState cs) { - return new CallNode(this, cs); - } - /** * Assist in IR navigation. * @@ -207,15 +195,22 @@ public class CallNode extends Node implements TypeOverride<CallNode> { * @return node or replacement */ @Override - public Node accept(final NodeVisitor visitor) { - if (visitor.enterCallNode(this) != null) { - function = function.accept(visitor); - - for (int i = 0, count = args.size(); i < count; i++) { - args.set(i, args.get(i).accept(visitor)); + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { + if (visitor.enterCallNode(this)) { + final CallNode newCallNode = (CallNode)visitor.leaveCallNode( + setFunction(function.accept(visitor)). + setArgs(Node.accept(visitor, Node.class, args)). + setFlags(flags). + setType(type). + setEvalArgs(evalArgs == null ? + null : + evalArgs.setCode(evalArgs.getCode().accept(visitor)). + setThis((IdentNode)evalArgs.getThis().accept(visitor)))); + // Theoretically, we'd need to instead pass lc to every setter and do a replacement on each. In practice, + // setType from TypeOverride can't accept a lc, and we don't necessarily want to go there now. + if(this != newCallNode) { + return Node.replaceInLexicalContext(lc, this, newCallNode); } - - return visitor.leaveCallNode(this); } return this; @@ -226,7 +221,7 @@ public class CallNode extends Node implements TypeOverride<CallNode> { if (hasCallSiteType()) { sb.append('{'); final String desc = getType().getDescriptor(); - sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor()); + sb.append(desc.charAt(desc.length() - 1) == ';' ? 'O' : getType().getDescriptor()); sb.append('}'); } @@ -261,8 +256,11 @@ public class CallNode extends Node implements TypeOverride<CallNode> { * Reset the arguments for the call * @param args new arguments list */ - public void setArgs(final List<Node> args) { - this.args = args; + private CallNode setArgs(final List<Node> args) { + if (this.args == args) { + return this; + } + return new CallNode(this, function, args, flags, type, evalArgs); } /** @@ -278,9 +276,13 @@ public class CallNode extends Node implements TypeOverride<CallNode> { * {@code eval} * * @param evalArgs eval args + * @return same node or new one on state change */ - public void setEvalArgs(final EvalArgs evalArgs) { - this.evalArgs = evalArgs; + public CallNode setEvalArgs(final EvalArgs evalArgs) { + if (this.evalArgs == evalArgs) { + return this; + } + return new CallNode(this, function, args, flags, type, evalArgs); } /** @@ -301,10 +303,14 @@ public class CallNode extends Node implements TypeOverride<CallNode> { /** * Reset the function expression that this call invokes - * @param node the function + * @param function the function + * @return same node or new one on state change */ - public void setFunction(final Node node) { - function = node; + public CallNode setFunction(final Node function) { + if (this.function == function) { + return this; + } + return new CallNode(this, function, args, flags, type, evalArgs); } /** @@ -312,28 +318,21 @@ public class CallNode extends Node implements TypeOverride<CallNode> { * @return true if this a new operation */ public boolean isNew() { - return isNew; + return (flags & IS_NEW) == IS_NEW; } /** * Flag this call as a new operation + * @return same node or new one on state change */ - public void setIsNew() { - this.isNew = true; + public CallNode setIsNew() { + return setFlags(IS_NEW); } - /** - * Check if this call is inside a {@code with} block - * @return true if the call is inside a {@code with} block - */ - public boolean inWithBlock() { - return inWithBlock; - } - - /** - * Flag this call to be inside a {@code with} block - */ - public void setInWithBlock() { - this.inWithBlock = true; + private CallNode setFlags(final int flags) { + if (this.flags == flags) { + return this; + } + return new CallNode(this, function, args, flags, type, evalArgs); } } |