8008103: Source object should maintain URL of the script source as a private field
authorsundar
Wed, 13 Feb 2013 19:59:30 +0530
changeset 16230 c38c724d82e7
parent 16229 cab69ca3490d
child 16231 9c8790061bee
8008103: Source object should maintain URL of the script source as a private field Reviewed-by: lagergren, jlaskey
nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
nashorn/src/jdk/nashorn/internal/runtime/Context.java
nashorn/src/jdk/nashorn/internal/runtime/Source.java
nashorn/src/jdk/nashorn/tools/Shell.java
nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java
nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java
nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Wed Feb 13 13:30:21 2013 +0100
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Wed Feb 13 19:59:30 2013 +0530
@@ -453,7 +453,7 @@
                 setNashornGlobal(ctxtGlobal);
             }
 
-            return nashornContext.compileScript(source, ctxtGlobal, nashornContext._strict);
+            return nashornContext.compileScript(source, ctxtGlobal);
         } catch (final Exception e) {
             throwAsScriptException(e);
             throw new AssertionError("should not reach here");
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Wed Feb 13 13:30:21 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Wed Feb 13 19:59:30 2013 +0530
@@ -492,29 +492,11 @@
      *
      * @param source the source
      * @param scope  the scope
-     * @param strict are we in strict mode
      *
      * @return top level function for script
      */
-    public ScriptFunction compileScript(final Source source, final ScriptObject scope, final boolean strict) {
-        return compileScript(source, scope, this.errors, strict);
-    }
-
-    /**
-     * Compile a top level script - no Source given, but an URL to
-     * load it from
-     *
-     * @param name    name of script/source
-     * @param url     URL to source
-     * @param scope   the scope
-     * @param strict  are we in strict mode
-     *
-     * @return top level function for the script
-     *
-     * @throws IOException if URL cannot be resolved
-     */
-    public ScriptFunction compileScript(final String name, final URL url, final ScriptObject scope, final boolean strict) throws IOException {
-        return compileScript(name, url, scope, this.errors, strict);
+    public ScriptFunction compileScript(final Source source, final ScriptObject scope) {
+        return compileScript(source, scope, this.errors);
     }
 
     /**
@@ -591,26 +573,25 @@
      * expression
      *
      * @param scope  the scope
-     * @param source source expression for script
+     * @param from   source expression for script
      *
      * @return return value for load call (undefined)
      *
      * @throws IOException if source cannot be found or loaded
      */
-    public Object load(final ScriptObject scope, final Object source) throws IOException {
-        Object src = source;
-        URL url = null;
-        String srcName = null;
+    public Object load(final ScriptObject scope, final Object from) throws IOException {
+        Object src = (from instanceof ConsString)?  from.toString() : from;
+        Source source = null;
 
-        if (src instanceof ConsString) {
-            src = src.toString();
-        }
+        // load accepts a String (which could be a URL or a file name), a File, a URL
+        // or a ScriptObject that has "name" and "source" (string valued) properties.
         if (src instanceof String) {
-            srcName = (String)src;
+            String srcStr = (String)src;
             final File file = new File((String)src);
-            if (srcName.indexOf(':') != -1) {
+            if (srcStr.indexOf(':') != -1) {
                 try {
-                    url = new URL((String)src);
+                    final URL url = new URL((String)src);
+                    source = new Source(url.toString(), url);
                 } catch (final MalformedURLException e) {
                     // fallback URL - nashorn:foo.js - check under jdk/nashorn/internal/runtime/resources
                     final String str = (String)src;
@@ -618,7 +599,7 @@
                         final String resource = "resources/" + str.substring("nashorn:".length());
                         // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme
                         // These scripts are always available and are loaded from nashorn.jar's resources.
-                        final Source code = AccessController.doPrivileged(
+                        source = AccessController.doPrivileged(
                                 new PrivilegedAction<Source>() {
                                     @Override
                                     public Source run() {
@@ -630,45 +611,32 @@
                                         }
                                     }
                                 });
-                        if (code == null) {
-                            throw e;
-                        }
-                        return evaluateSource(code, scope, scope);
                     } else {
                         throw e;
                     }
                 }
             } else if (file.isFile()) {
-                url = file.toURI().toURL();
-            }
-            src = url;
-        }
-
-        if (src instanceof File && ((File)src).isFile()) {
-            final File file = (File)src;
-            url = file.toURI().toURL();
-            if (srcName == null) {
-                srcName = file.getCanonicalPath();
+                source = new Source(srcStr, file);
             }
+        } else if (src instanceof File && ((File)src).isFile()) {
+            final File file = (File)src;
+            source = new Source(file.getName(), file);
         } else if (src instanceof URL) {
-            url = (URL)src;
-            if (srcName == null) {
-                srcName = url.toString();
-            }
-        }
-
-        if (url != null) {
-            assert srcName != null : "srcName null here!";
-            return evaluateSource(srcName, url, scope, scope);
+            final URL url = (URL)src;
+            source = new Source(url.toString(), url);
         } else if (src instanceof ScriptObject) {
             final ScriptObject sobj = (ScriptObject)src;
             if (sobj.has("script") && sobj.has("name")) {
                 final String script = JSType.toString(sobj.get("script"));
                 final String name   = JSType.toString(sobj.get("name"));
-                return evaluateSource(new Source(name, script), scope, scope);
+                source = new Source(name, script);
             }
         }
 
+        if (source != null) {
+            return evaluateSource(source, scope, scope);
+        }
+
         typeError("cant.load.script", ScriptRuntime.safeToString(source));
 
         return UNDEFINED;
@@ -850,23 +818,11 @@
         return (context != null) ? context : Context.getContextTrusted();
     }
 
-    private Object evaluateSource(final String name, final URL url, final ScriptObject scope, final ScriptObject thiz) throws IOException {
-        ScriptFunction script = null;
-
-        try {
-            script = compileScript(name, url, scope, new Context.ThrowErrorManager(), _strict);
-        } catch (final ParserException e) {
-            e.throwAsEcmaException();
-        }
-
-        return ScriptRuntime.apply(script, thiz);
-    }
-
     private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) {
         ScriptFunction script = null;
 
         try {
-            script = compileScript(source, scope, new Context.ThrowErrorManager(), _strict);
+            script = compileScript(source, scope, new Context.ThrowErrorManager());
         } catch (final ParserException e) {
             e.throwAsEcmaException();
         }
@@ -902,19 +858,11 @@
         return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.tag(), runMethodHandle, scope, strict);
     }
 
-    private ScriptFunction compileScript(final String name, final URL url, final ScriptObject scope, final ErrorManager errMan, final boolean strict) throws IOException {
-        return getRunScriptFunction(compile(new Source(name, url), url, errMan, strict), scope);
+    private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) {
+        return getRunScriptFunction(compile(source, errMan, this._strict), scope);
     }
 
-    private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan, final boolean strict) {
-        return getRunScriptFunction(compile(source, null, errMan, strict), scope);
-    }
-
-    private Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) {
-        return compile(source, null, errMan, strict);
-    }
-
-   private synchronized Class<?> compile(final Source source, final URL url, final ErrorManager errMan, final boolean strict) {
+    private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) {
         // start with no errors, no warnings.
         errMan.reset();
 
@@ -935,6 +883,7 @@
             return null;
         }
 
+        final URL url = source.getURL();
         final ScriptLoader loader = _loader_per_compile ? createNewLoader() : scriptLoader;
         final CodeSource   cs     = url == null ? null : new CodeSource(url, (CodeSigner[])null);
 
--- a/nashorn/src/jdk/nashorn/internal/runtime/Source.java	Wed Feb 13 13:30:21 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Source.java	Wed Feb 13 19:59:30 2013 +0530
@@ -71,13 +71,20 @@
     /** Cached hash code */
     private int hash;
 
+    /** Source URL if available */
+    private final URL url;
+
     private static final int BUFSIZE = 8 * 1024;
 
-    private Source(final String name, final String base, final char[] content) {
+    // Do *not* make this public ever! Trusts the URL and content. So has to be called
+    // from other public constructors. Note that this can not be some init method as
+    // we initialize final fields from here.
+    private Source(final String name, final String base, final char[] content, final URL url) {
         this.name    = name;
         this.base    = base;
         this.content = content;
         this.length  = content.length;
+        this.url     = url;
     }
 
     /**
@@ -87,7 +94,7 @@
      * @param content contents as char array
      */
     public Source(final String name, final char[] content) {
-        this(name, baseName(name, null), content);
+        this(name, baseName(name, null), content, null);
     }
 
     /**
@@ -109,7 +116,7 @@
      * @throws IOException if source cannot be loaded
      */
     public Source(final String name, final URL url) throws IOException {
-        this(name, baseURL(url, null), readFully(url.openStream()));
+        this(name, baseURL(url, null), readFully(url.openStream()), url);
     }
 
     /**
@@ -121,7 +128,7 @@
      * @throws IOException if source cannot be loaded
      */
     public Source(final String name, final File file) throws IOException {
-        this(name, dirName(file, null), readFully(file));
+        this(name, dirName(file, null), readFully(file), getURLFromFile(file));
     }
 
     @Override
@@ -206,6 +213,16 @@
     }
 
     /**
+     * Returns the source URL of this script Source. Can be null if Source
+     * was created from a String or a char[].
+     *
+     * @return URL source or null
+     */
+    public URL getURL() {
+        return url;
+    }
+
+    /**
      * Find the beginning of the line containing position.
      * @param position Index to offending token.
      * @return Index of first character of line.
@@ -288,7 +305,7 @@
      * @return content
      */
     public char[] getContent() {
-        return content;
+        return content.clone();
     }
 
     /**
@@ -433,4 +450,12 @@
     public String toString() {
         return getName();
     }
+
+    private static URL getURLFromFile(final File file) {
+        try {
+            return file.toURI().toURL();
+        } catch (final SecurityException | MalformedURLException ignored) {
+            return null;
+        }
+    }
 }
--- a/nashorn/src/jdk/nashorn/tools/Shell.java	Wed Feb 13 13:30:21 2013 +0100
+++ b/nashorn/src/jdk/nashorn/tools/Shell.java	Wed Feb 13 19:59:30 2013 +0530
@@ -282,7 +282,7 @@
             // For each file on the command line.
             for (final String fileName : files) {
                 final File file = new File(fileName);
-                ScriptFunction script = context.compileScript(fileName, file.toURI().toURL(), global, context._strict);
+                ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global);
                 if (script == null || errors.getNumberOfErrors() != 0) {
                     return COMPILATION_ERROR;
                 }
--- a/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java	Wed Feb 13 13:30:21 2013 +0100
+++ b/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java	Wed Feb 13 19:59:30 2013 +0530
@@ -159,7 +159,7 @@
                 Context.setGlobal(global);
             }
             final Source source = new Source(file.getAbsolutePath(), buffer);
-            final ScriptFunction script = context.compileScript(source, global, context._strict);
+            final ScriptFunction script = context.compileScript(source, global);
             if (script == null || context.getErrorManager().getNumberOfErrors() > 0) {
                 log("Compile failed: " + file.getAbsolutePath());
                 failed++;
--- a/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java	Wed Feb 13 13:30:21 2013 +0100
+++ b/nashorn/test/src/jdk/nashorn/internal/runtime/ContextTest.java	Wed Feb 13 19:59:30 2013 +0530
@@ -111,7 +111,7 @@
     private Object eval(final Context cx, final String name, final String code) {
         final Source source = new Source(name, code);
         final ScriptObject global = Context.getGlobal();
-        final ScriptFunction func = cx.compileScript(source, global, cx._strict);
+        final ScriptFunction func = cx.compileScript(source, global);
         return func != null ? ScriptRuntime.apply(func, global) : null;
     }
 
--- a/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java	Wed Feb 13 13:30:21 2013 +0100
+++ b/nashorn/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java	Wed Feb 13 19:59:30 2013 +0530
@@ -39,6 +39,7 @@
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.runtime.Source;
 import jdk.nashorn.internal.runtime.options.Options;
 
 /**
@@ -124,7 +125,7 @@
                     continue;
                 }
                 final File file = new File(fileName);
-                ScriptFunction script = context.compileScript(fileName, file.toURI().toURL(), global, context._strict);
+                ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global);
                 if (script == null || errors.getNumberOfErrors() != 0) {
                     return COMPILATION_ERROR;
                 }