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.
      *