src/jdk/nashorn/internal/ir/FunctionNode.java
Print this page
rev 750 : 8032068: implement @sourceURL and #sourceURL directives
Reviewed-by: hannesw, lagergren
rev 758 : 8021350: Share script classes between threads/globals within context
Reviewed-by: lagergren, sundar
@@ -27,10 +27,11 @@
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.Namespace;
@@ -136,10 +137,13 @@
private HashSet<String> thisProperties;
/** Function flags. */
private final int flags;
+ /** //@ sourceURL or //# sourceURL for program function nodes */
+ private final String sourceURL;
+
private final int lineNumber;
/** Is anonymous function flag. */
public static final int IS_ANONYMOUS = 1 << 0;
@@ -191,10 +195,13 @@
public static final int HAS_FUNCTION_DECLARATIONS = 1 << 13;
/** Can this function be specialized? */
public static final int CAN_SPECIALIZE = 1 << 14;
+ /** Does this function use the "this" keyword? */
+ public static final int USES_THIS = 1 << 15;
+
/** Does this function or any nested functions contain an eval? */
private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
/** Does this function need to store all its variables in scope? */
private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_EVAL | IS_SPLIT | HAS_LAZY_CHILDREN;
@@ -221,10 +228,11 @@
* @param ident the identifier
* @param name the name of the function
* @param parameters parameter list
* @param kind kind of function as in {@link FunctionNode.Kind}
* @param flags initial flags
+ * @param sourceURL sourceURL specified in script (optional)
*/
public FunctionNode(
final Source source,
final int lineNumber,
final long token,
@@ -233,11 +241,12 @@
final Namespace namespace,
final IdentNode ident,
final String name,
final List<IdentNode> parameters,
final FunctionNode.Kind kind,
- final int flags) {
+ final int flags,
+ final String sourceURL) {
super(token, finish);
this.source = source;
this.lineNumber = lineNumber;
this.ident = ident;
@@ -248,20 +257,22 @@
this.lastToken = token;
this.namespace = namespace;
this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
this.declaredSymbols = new HashSet<>();
this.flags = flags;
+ this.sourceURL = sourceURL;
this.compileUnit = null;
this.body = null;
this.snapshot = null;
this.hints = null;
}
private FunctionNode(
final FunctionNode functionNode,
final long lastToken,
final int flags,
+ final String sourceURL,
final String name,
final Type returnType,
final CompileUnit compileUnit,
final EnumSet<CompilationState> compilationState,
final Block body,
@@ -269,10 +280,11 @@
final FunctionNode snapshot,
final Compiler.Hints hints) {
super(functionNode);
this.lineNumber = functionNode.lineNumber;
this.flags = flags;
+ this.sourceURL = sourceURL;
this.name = name;
this.returnType = returnType;
this.compileUnit = compileUnit;
this.lastToken = lastToken;
this.compilationState = compilationState;
@@ -306,10 +318,42 @@
public Source getSource() {
return source;
}
/**
+ * get source name - sourceURL or name derived from Source.
+ *
+ * @return name for the script source
+ */
+ public String getSourceName() {
+ return (sourceURL != null)? sourceURL : source.getName();
+ }
+
+ /**
+ * get the sourceURL
+ * @return the sourceURL
+ */
+ public String getSourceURL() {
+ return sourceURL;
+ }
+
+ /**
+ * Set the sourceURL
+ *
+ * @param lc lexical context
+ * @param newSourceURL source url string to set
+ * @return function node or a new one if state was changed
+ */
+ public FunctionNode setSourceURL(final LexicalContext lc, final String newSourceURL) {
+ if (Objects.equals(sourceURL, newSourceURL)) {
+ return this;
+ }
+
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, newSourceURL, name, returnType, compileUnit, compilationState, body, parameters, null, hints));
+ }
+
+ /**
* Returns the line number.
* @return the line number.
*/
public int getLineNumber() {
return lineNumber;
@@ -333,11 +377,11 @@
*/
public FunctionNode clearSnapshot(final LexicalContext lc) {
if (this.snapshot == null) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, null, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, null, hints));
}
/**
* Take a snapshot of this function node at a given point in time
* and store it in the function node
@@ -349,11 +393,11 @@
return this;
}
if (isProgram() || parameters.isEmpty()) {
return this; //never specialize anything that won't be recompiled
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, this, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, this, hints));
}
/**
* Can this function node be regenerated with more specific type args?
* @return true if specialization is possible
@@ -407,11 +451,11 @@
if (this.compilationState.contains(state)) {
return this;
}
final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
newState.add(state);
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, newState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, newState, body, parameters, snapshot, hints));
}
/**
* Get any compiler hints that may associated with the function
* @return compiler hints
@@ -428,11 +472,11 @@
*/
public FunctionNode setHints(final LexicalContext lc, final Compiler.Hints hints) {
if (this.hints == hints) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
* Create a unique name in the namespace of this FunctionNode
* @param base prefix for name
@@ -481,11 +525,11 @@
@Override
public FunctionNode setFlags(final LexicalContext lc, int flags) {
if (this.flags == flags) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
@Override
public FunctionNode clearFlag(final LexicalContext lc, final int flag) {
return setFlags(lc, flags & ~flag);
@@ -548,10 +592,19 @@
public boolean needsCallee() {
return needsParentScope() || needsSelfSymbol() || isSplit() || (needsArguments() && !isStrict());
}
/**
+ * Return {@code true} if this function makes use of the {@code this} object.
+ *
+ * @return true if function uses {@code this} object
+ */
+ public boolean usesThis() {
+ return getFlag(USES_THIS);
+ }
+
+ /**
* Get the identifier for this function, this is its symbol.
* @return the identifier as an IdentityNode
*/
public IdentNode getIdent() {
return ident;
@@ -591,11 +644,11 @@
*/
public FunctionNode setBody(final LexicalContext lc, final Block body) {
if(this.body == body) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags | (body.needsScope() ? FunctionNode.HAS_SCOPE_BLOCK : 0), name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags | (body.needsScope() ? FunctionNode.HAS_SCOPE_BLOCK : 0), sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
* Does this function's method needs to be variable arity (gather all script-declared parameters in a final
* {@code Object[]} parameter. Functions that need to have the "arguments" object as well as functions that simply
@@ -686,11 +739,11 @@
*/
public FunctionNode setLastToken(final LexicalContext lc, final long lastToken) {
if (this.lastToken == lastToken) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
* Get the name of this function
* @return the name
@@ -708,11 +761,11 @@
*/
public FunctionNode setName(final LexicalContext lc, final String name) {
if (this.name.equals(name)) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
* Check if this function should have all its variables in its own scope. Scripts, split sub-functions, and
* functions having with and/or eval blocks are such.
@@ -758,11 +811,11 @@
*/
public FunctionNode setParameters(final LexicalContext lc, final List<IdentNode> parameters) {
if (this.parameters == parameters) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
* Check if this function is created as a function declaration (as opposed to function expression)
* @return true if function is declared.
@@ -823,10 +876,11 @@
this,
new FunctionNode(
this,
lastToken,
flags,
+ sourceURL,
name,
type,
compileUnit,
compilationState,
body.setReturnType(type),
@@ -861,11 +915,11 @@
*/
public FunctionNode setCompileUnit(final LexicalContext lc, final CompileUnit compileUnit) {
if (this.compileUnit == compileUnit) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
+ return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
}
/**
* Create a temporary variable to the current frame.
*