Wed, 13 Feb 2013 19:59:30 +0530
8008103: Source object should maintain URL of the script source as a private field
Reviewed-by: lagergren, jlaskey
1.1 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Wed Feb 13 13:30:21 2013 +0100 1.2 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Wed Feb 13 19:59:30 2013 +0530 1.3 @@ -453,7 +453,7 @@ 1.4 setNashornGlobal(ctxtGlobal); 1.5 } 1.6 1.7 - return nashornContext.compileScript(source, ctxtGlobal, nashornContext._strict); 1.8 + return nashornContext.compileScript(source, ctxtGlobal); 1.9 } catch (final Exception e) { 1.10 throwAsScriptException(e); 1.11 throw new AssertionError("should not reach here");
2.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Wed Feb 13 13:30:21 2013 +0100 2.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Wed Feb 13 19:59:30 2013 +0530 2.3 @@ -492,29 +492,11 @@ 2.4 * 2.5 * @param source the source 2.6 * @param scope the scope 2.7 - * @param strict are we in strict mode 2.8 * 2.9 * @return top level function for script 2.10 */ 2.11 - public ScriptFunction compileScript(final Source source, final ScriptObject scope, final boolean strict) { 2.12 - return compileScript(source, scope, this.errors, strict); 2.13 - } 2.14 - 2.15 - /** 2.16 - * Compile a top level script - no Source given, but an URL to 2.17 - * load it from 2.18 - * 2.19 - * @param name name of script/source 2.20 - * @param url URL to source 2.21 - * @param scope the scope 2.22 - * @param strict are we in strict mode 2.23 - * 2.24 - * @return top level function for the script 2.25 - * 2.26 - * @throws IOException if URL cannot be resolved 2.27 - */ 2.28 - public ScriptFunction compileScript(final String name, final URL url, final ScriptObject scope, final boolean strict) throws IOException { 2.29 - return compileScript(name, url, scope, this.errors, strict); 2.30 + public ScriptFunction compileScript(final Source source, final ScriptObject scope) { 2.31 + return compileScript(source, scope, this.errors); 2.32 } 2.33 2.34 /** 2.35 @@ -591,26 +573,25 @@ 2.36 * expression 2.37 * 2.38 * @param scope the scope 2.39 - * @param source source expression for script 2.40 + * @param from source expression for script 2.41 * 2.42 * @return return value for load call (undefined) 2.43 * 2.44 * @throws IOException if source cannot be found or loaded 2.45 */ 2.46 - public Object load(final ScriptObject scope, final Object source) throws IOException { 2.47 - Object src = source; 2.48 - URL url = null; 2.49 - String srcName = null; 2.50 + public Object load(final ScriptObject scope, final Object from) throws IOException { 2.51 + Object src = (from instanceof ConsString)? from.toString() : from; 2.52 + Source source = null; 2.53 2.54 - if (src instanceof ConsString) { 2.55 - src = src.toString(); 2.56 - } 2.57 + // load accepts a String (which could be a URL or a file name), a File, a URL 2.58 + // or a ScriptObject that has "name" and "source" (string valued) properties. 2.59 if (src instanceof String) { 2.60 - srcName = (String)src; 2.61 + String srcStr = (String)src; 2.62 final File file = new File((String)src); 2.63 - if (srcName.indexOf(':') != -1) { 2.64 + if (srcStr.indexOf(':') != -1) { 2.65 try { 2.66 - url = new URL((String)src); 2.67 + final URL url = new URL((String)src); 2.68 + source = new Source(url.toString(), url); 2.69 } catch (final MalformedURLException e) { 2.70 // fallback URL - nashorn:foo.js - check under jdk/nashorn/internal/runtime/resources 2.71 final String str = (String)src; 2.72 @@ -618,7 +599,7 @@ 2.73 final String resource = "resources/" + str.substring("nashorn:".length()); 2.74 // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme 2.75 // These scripts are always available and are loaded from nashorn.jar's resources. 2.76 - final Source code = AccessController.doPrivileged( 2.77 + source = AccessController.doPrivileged( 2.78 new PrivilegedAction<Source>() { 2.79 @Override 2.80 public Source run() { 2.81 @@ -630,45 +611,32 @@ 2.82 } 2.83 } 2.84 }); 2.85 - if (code == null) { 2.86 - throw e; 2.87 - } 2.88 - return evaluateSource(code, scope, scope); 2.89 } else { 2.90 throw e; 2.91 } 2.92 } 2.93 } else if (file.isFile()) { 2.94 - url = file.toURI().toURL(); 2.95 + source = new Source(srcStr, file); 2.96 } 2.97 - src = url; 2.98 - } 2.99 - 2.100 - if (src instanceof File && ((File)src).isFile()) { 2.101 + } else if (src instanceof File && ((File)src).isFile()) { 2.102 final File file = (File)src; 2.103 - url = file.toURI().toURL(); 2.104 - if (srcName == null) { 2.105 - srcName = file.getCanonicalPath(); 2.106 - } 2.107 + source = new Source(file.getName(), file); 2.108 } else if (src instanceof URL) { 2.109 - url = (URL)src; 2.110 - if (srcName == null) { 2.111 - srcName = url.toString(); 2.112 - } 2.113 - } 2.114 - 2.115 - if (url != null) { 2.116 - assert srcName != null : "srcName null here!"; 2.117 - return evaluateSource(srcName, url, scope, scope); 2.118 + final URL url = (URL)src; 2.119 + source = new Source(url.toString(), url); 2.120 } else if (src instanceof ScriptObject) { 2.121 final ScriptObject sobj = (ScriptObject)src; 2.122 if (sobj.has("script") && sobj.has("name")) { 2.123 final String script = JSType.toString(sobj.get("script")); 2.124 final String name = JSType.toString(sobj.get("name")); 2.125 - return evaluateSource(new Source(name, script), scope, scope); 2.126 + source = new Source(name, script); 2.127 } 2.128 } 2.129 2.130 + if (source != null) { 2.131 + return evaluateSource(source, scope, scope); 2.132 + } 2.133 + 2.134 typeError("cant.load.script", ScriptRuntime.safeToString(source)); 2.135 2.136 return UNDEFINED; 2.137 @@ -850,23 +818,11 @@ 2.138 return (context != null) ? context : Context.getContextTrusted(); 2.139 } 2.140 2.141 - private Object evaluateSource(final String name, final URL url, final ScriptObject scope, final ScriptObject thiz) throws IOException { 2.142 - ScriptFunction script = null; 2.143 - 2.144 - try { 2.145 - script = compileScript(name, url, scope, new Context.ThrowErrorManager(), _strict); 2.146 - } catch (final ParserException e) { 2.147 - e.throwAsEcmaException(); 2.148 - } 2.149 - 2.150 - return ScriptRuntime.apply(script, thiz); 2.151 - } 2.152 - 2.153 private Object evaluateSource(final Source source, final ScriptObject scope, final ScriptObject thiz) { 2.154 ScriptFunction script = null; 2.155 2.156 try { 2.157 - script = compileScript(source, scope, new Context.ThrowErrorManager(), _strict); 2.158 + script = compileScript(source, scope, new Context.ThrowErrorManager()); 2.159 } catch (final ParserException e) { 2.160 e.throwAsEcmaException(); 2.161 } 2.162 @@ -902,19 +858,11 @@ 2.163 return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.tag(), runMethodHandle, scope, strict); 2.164 } 2.165 2.166 - private ScriptFunction compileScript(final String name, final URL url, final ScriptObject scope, final ErrorManager errMan, final boolean strict) throws IOException { 2.167 - return getRunScriptFunction(compile(new Source(name, url), url, errMan, strict), scope); 2.168 + private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) { 2.169 + return getRunScriptFunction(compile(source, errMan, this._strict), scope); 2.170 } 2.171 2.172 - private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan, final boolean strict) { 2.173 - return getRunScriptFunction(compile(source, null, errMan, strict), scope); 2.174 - } 2.175 - 2.176 - private Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) { 2.177 - return compile(source, null, errMan, strict); 2.178 - } 2.179 - 2.180 - private synchronized Class<?> compile(final Source source, final URL url, final ErrorManager errMan, final boolean strict) { 2.181 + private synchronized Class<?> compile(final Source source, final ErrorManager errMan, final boolean strict) { 2.182 // start with no errors, no warnings. 2.183 errMan.reset(); 2.184 2.185 @@ -935,6 +883,7 @@ 2.186 return null; 2.187 } 2.188 2.189 + final URL url = source.getURL(); 2.190 final ScriptLoader loader = _loader_per_compile ? createNewLoader() : scriptLoader; 2.191 final CodeSource cs = url == null ? null : new CodeSource(url, (CodeSigner[])null); 2.192
3.1 --- a/src/jdk/nashorn/internal/runtime/Source.java Wed Feb 13 13:30:21 2013 +0100 3.2 +++ b/src/jdk/nashorn/internal/runtime/Source.java Wed Feb 13 19:59:30 2013 +0530 3.3 @@ -71,13 +71,20 @@ 3.4 /** Cached hash code */ 3.5 private int hash; 3.6 3.7 + /** Source URL if available */ 3.8 + private final URL url; 3.9 + 3.10 private static final int BUFSIZE = 8 * 1024; 3.11 3.12 - private Source(final String name, final String base, final char[] content) { 3.13 + // Do *not* make this public ever! Trusts the URL and content. So has to be called 3.14 + // from other public constructors. Note that this can not be some init method as 3.15 + // we initialize final fields from here. 3.16 + private Source(final String name, final String base, final char[] content, final URL url) { 3.17 this.name = name; 3.18 this.base = base; 3.19 this.content = content; 3.20 this.length = content.length; 3.21 + this.url = url; 3.22 } 3.23 3.24 /** 3.25 @@ -87,7 +94,7 @@ 3.26 * @param content contents as char array 3.27 */ 3.28 public Source(final String name, final char[] content) { 3.29 - this(name, baseName(name, null), content); 3.30 + this(name, baseName(name, null), content, null); 3.31 } 3.32 3.33 /** 3.34 @@ -109,7 +116,7 @@ 3.35 * @throws IOException if source cannot be loaded 3.36 */ 3.37 public Source(final String name, final URL url) throws IOException { 3.38 - this(name, baseURL(url, null), readFully(url.openStream())); 3.39 + this(name, baseURL(url, null), readFully(url.openStream()), url); 3.40 } 3.41 3.42 /** 3.43 @@ -121,7 +128,7 @@ 3.44 * @throws IOException if source cannot be loaded 3.45 */ 3.46 public Source(final String name, final File file) throws IOException { 3.47 - this(name, dirName(file, null), readFully(file)); 3.48 + this(name, dirName(file, null), readFully(file), getURLFromFile(file)); 3.49 } 3.50 3.51 @Override 3.52 @@ -206,6 +213,16 @@ 3.53 } 3.54 3.55 /** 3.56 + * Returns the source URL of this script Source. Can be null if Source 3.57 + * was created from a String or a char[]. 3.58 + * 3.59 + * @return URL source or null 3.60 + */ 3.61 + public URL getURL() { 3.62 + return url; 3.63 + } 3.64 + 3.65 + /** 3.66 * Find the beginning of the line containing position. 3.67 * @param position Index to offending token. 3.68 * @return Index of first character of line. 3.69 @@ -288,7 +305,7 @@ 3.70 * @return content 3.71 */ 3.72 public char[] getContent() { 3.73 - return content; 3.74 + return content.clone(); 3.75 } 3.76 3.77 /** 3.78 @@ -433,4 +450,12 @@ 3.79 public String toString() { 3.80 return getName(); 3.81 } 3.82 + 3.83 + private static URL getURLFromFile(final File file) { 3.84 + try { 3.85 + return file.toURI().toURL(); 3.86 + } catch (final SecurityException | MalformedURLException ignored) { 3.87 + return null; 3.88 + } 3.89 + } 3.90 }
4.1 --- a/src/jdk/nashorn/tools/Shell.java Wed Feb 13 13:30:21 2013 +0100 4.2 +++ b/src/jdk/nashorn/tools/Shell.java Wed Feb 13 19:59:30 2013 +0530 4.3 @@ -282,7 +282,7 @@ 4.4 // For each file on the command line. 4.5 for (final String fileName : files) { 4.6 final File file = new File(fileName); 4.7 - ScriptFunction script = context.compileScript(fileName, file.toURI().toURL(), global, context._strict); 4.8 + ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global); 4.9 if (script == null || errors.getNumberOfErrors() != 0) { 4.10 return COMPILATION_ERROR; 4.11 }
5.1 --- a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Wed Feb 13 13:30:21 2013 +0100 5.2 +++ b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Wed Feb 13 19:59:30 2013 +0530 5.3 @@ -159,7 +159,7 @@ 5.4 Context.setGlobal(global); 5.5 } 5.6 final Source source = new Source(file.getAbsolutePath(), buffer); 5.7 - final ScriptFunction script = context.compileScript(source, global, context._strict); 5.8 + final ScriptFunction script = context.compileScript(source, global); 5.9 if (script == null || context.getErrorManager().getNumberOfErrors() > 0) { 5.10 log("Compile failed: " + file.getAbsolutePath()); 5.11 failed++;
6.1 --- a/test/src/jdk/nashorn/internal/runtime/ContextTest.java Wed Feb 13 13:30:21 2013 +0100 6.2 +++ b/test/src/jdk/nashorn/internal/runtime/ContextTest.java Wed Feb 13 19:59:30 2013 +0530 6.3 @@ -111,7 +111,7 @@ 6.4 private Object eval(final Context cx, final String name, final String code) { 6.5 final Source source = new Source(name, code); 6.6 final ScriptObject global = Context.getGlobal(); 6.7 - final ScriptFunction func = cx.compileScript(source, global, cx._strict); 6.8 + final ScriptFunction func = cx.compileScript(source, global); 6.9 return func != null ? ScriptRuntime.apply(func, global) : null; 6.10 } 6.11
7.1 --- a/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java Wed Feb 13 13:30:21 2013 +0100 7.2 +++ b/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java Wed Feb 13 19:59:30 2013 +0530 7.3 @@ -39,6 +39,7 @@ 7.4 import jdk.nashorn.internal.runtime.ScriptFunction; 7.5 import jdk.nashorn.internal.runtime.ScriptObject; 7.6 import jdk.nashorn.internal.runtime.ScriptRuntime; 7.7 +import jdk.nashorn.internal.runtime.Source; 7.8 import jdk.nashorn.internal.runtime.options.Options; 7.9 7.10 /** 7.11 @@ -124,7 +125,7 @@ 7.12 continue; 7.13 } 7.14 final File file = new File(fileName); 7.15 - ScriptFunction script = context.compileScript(fileName, file.toURI().toURL(), global, context._strict); 7.16 + ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global); 7.17 if (script == null || errors.getNumberOfErrors() != 0) { 7.18 return COMPILATION_ERROR; 7.19 }