Fri, 25 Apr 2014 16:34:17 +0200
8040078: Avoid repeated reading of source for cached loads
Reviewed-by: jlaskey, lagergren
1.1 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Fri May 02 19:15:59 2014 +0530 1.2 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Fri Apr 25 16:34:17 2014 +0200 1.3 @@ -27,16 +27,14 @@ 1.4 1.5 import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError; 1.6 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 1.7 +import static jdk.nashorn.internal.runtime.Source.sourceFor; 1.8 1.9 import java.io.IOException; 1.10 -import java.io.InputStream; 1.11 -import java.io.InputStreamReader; 1.12 import java.io.Reader; 1.13 import java.lang.invoke.MethodHandles; 1.14 import java.lang.reflect.Method; 1.15 import java.lang.reflect.Modifier; 1.16 import java.net.URL; 1.17 -import java.nio.charset.Charset; 1.18 import java.security.AccessControlContext; 1.19 import java.security.AccessController; 1.20 import java.security.Permissions; 1.21 @@ -124,21 +122,21 @@ 1.22 } 1.23 } 1.24 1.25 - // load engine.js and return content as a char[] 1.26 + // load engine.js 1.27 @SuppressWarnings("resource") 1.28 - private static char[] loadEngineJSSource() { 1.29 + private static Source loadEngineJSSource() { 1.30 final String script = "resources/engine.js"; 1.31 try { 1.32 - final InputStream is = AccessController.doPrivileged( 1.33 - new PrivilegedExceptionAction<InputStream>() { 1.34 + return AccessController.doPrivileged( 1.35 + new PrivilegedExceptionAction<Source>() { 1.36 @Override 1.37 - public InputStream run() throws Exception { 1.38 + public Source run() throws IOException { 1.39 final URL url = NashornScriptEngine.class.getResource(script); 1.40 - return url.openStream(); 1.41 + return sourceFor(NashornException.ENGINE_SCRIPT_SOURCE_NAME, url); 1.42 } 1.43 - }); 1.44 - return Source.readFully(new InputStreamReader(is)); 1.45 - } catch (final PrivilegedActionException | IOException e) { 1.46 + } 1.47 + ); 1.48 + } catch (final PrivilegedActionException e) { 1.49 if (Context.DEBUG) { 1.50 e.printStackTrace(); 1.51 } 1.52 @@ -147,7 +145,7 @@ 1.53 } 1.54 1.55 // Source object for engine.js 1.56 - private static final Source ENGINE_SCRIPT_SRC = new Source(NashornException.ENGINE_SCRIPT_SOURCE_NAME, loadEngineJSSource()); 1.57 + private static final Source ENGINE_SCRIPT_SRC = loadEngineJSSource(); 1.58 1.59 NashornScriptEngine(final NashornScriptEngineFactory factory, final ClassLoader appLoader) { 1.60 this(factory, DEFAULT_OPTIONS, appLoader); 1.61 @@ -282,19 +280,14 @@ 1.62 1.63 private static Source makeSource(final Reader reader, final ScriptContext ctxt) throws ScriptException { 1.64 try { 1.65 - if (reader instanceof URLReader) { 1.66 - final URL url = ((URLReader)reader).getURL(); 1.67 - final Charset cs = ((URLReader)reader).getCharset(); 1.68 - return new Source(url.toString(), url, cs); 1.69 - } 1.70 - return new Source(getScriptName(ctxt), Source.readFully(reader)); 1.71 - } catch (final IOException e) { 1.72 + return sourceFor(getScriptName(ctxt), reader); 1.73 + } catch (IOException e) { 1.74 throw new ScriptException(e); 1.75 } 1.76 } 1.77 1.78 private static Source makeSource(final String src, final ScriptContext ctxt) { 1.79 - return new Source(getScriptName(ctxt), src); 1.80 + return sourceFor(getScriptName(ctxt), src); 1.81 } 1.82 1.83 private static String getScriptName(final ScriptContext ctxt) {
2.1 --- a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Fri May 02 19:15:59 2014 +0530 2.2 +++ b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Fri Apr 25 16:34:17 2014 +0200 2.3 @@ -25,6 +25,8 @@ 2.4 2.5 package jdk.nashorn.internal.ir.debug; 2.6 2.7 +import static jdk.nashorn.internal.runtime.Source.sourceFor; 2.8 + 2.9 import java.util.Arrays; 2.10 import java.util.List; 2.11 import java.util.ArrayList; 2.12 @@ -88,7 +90,7 @@ 2.13 * @return JSON string representation of AST of the supplied code 2.14 */ 2.15 public static String parse(final ScriptEnvironment env, final String code, final String name, final boolean includeLoc) { 2.16 - final Parser parser = new Parser(env, new Source(name, code), new Context.ThrowErrorManager(), env._strict); 2.17 + final Parser parser = new Parser(env, sourceFor(name, code), new Context.ThrowErrorManager(), env._strict); 2.18 final JSONWriter jsonWriter = new JSONWriter(includeLoc); 2.19 try { 2.20 final FunctionNode functionNode = parser.parse(CompilerConstants.RUN_SCRIPT.symbolName());
3.1 --- a/src/jdk/nashorn/internal/objects/NativeFunction.java Fri May 02 19:15:59 2014 +0530 3.2 +++ b/src/jdk/nashorn/internal/objects/NativeFunction.java Fri Apr 25 16:34:17 2014 +0200 3.3 @@ -27,6 +27,7 @@ 3.4 3.5 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 3.6 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 3.7 +import static jdk.nashorn.internal.runtime.Source.sourceFor; 3.8 3.9 import java.util.List; 3.10 3.11 @@ -257,7 +258,7 @@ 3.12 } 3.13 3.14 private static void checkFunctionParameters(final String params) { 3.15 - final Source src = new Source("<function>", params); 3.16 + final Source src = sourceFor("<function>", params); 3.17 final Parser parser = new Parser(Global.getEnv(), src, new Context.ThrowErrorManager()); 3.18 try { 3.19 parser.parseFormalParameterList(); 3.20 @@ -267,7 +268,7 @@ 3.21 } 3.22 3.23 private static void checkFunctionBody(final String funcBody) { 3.24 - final Source src = new Source("<function>", funcBody); 3.25 + final Source src = sourceFor("<function>", funcBody); 3.26 final Parser parser = new Parser(Global.getEnv(), src, new Context.ThrowErrorManager()); 3.27 try { 3.28 parser.parseFunctionBody();
4.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Fri May 02 19:15:59 2014 +0530 4.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Fri Apr 25 16:34:17 2014 +0200 4.3 @@ -32,6 +32,7 @@ 4.4 import static jdk.nashorn.internal.lookup.Lookup.MH; 4.5 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 4.6 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 4.7 +import static jdk.nashorn.internal.runtime.Source.sourceFor; 4.8 4.9 import java.io.File; 4.10 import java.io.IOException; 4.11 @@ -502,7 +503,7 @@ 4.12 */ 4.13 public Object eval(final ScriptObject initialScope, final String string, final Object callThis, final Object location, final boolean strict) { 4.14 final String file = (location == UNDEFINED || location == null) ? "<eval>" : location.toString(); 4.15 - final Source source = new Source(file, string); 4.16 + final Source source = sourceFor(file, string); 4.17 final boolean directEval = location != UNDEFINED; // is this direct 'eval' call or indirectly invoked eval? 4.18 final Global global = Context.getGlobal(); 4.19 4.20 @@ -569,7 +570,7 @@ 4.21 public Source run() { 4.22 try { 4.23 final URL resURL = Context.class.getResource(resource); 4.24 - return (resURL != null)? new Source(srcStr, resURL) : null; 4.25 + return (resURL != null)? sourceFor(srcStr, resURL) : null; 4.26 } catch (final IOException exp) { 4.27 return null; 4.28 } 4.29 @@ -601,7 +602,7 @@ 4.30 final String srcStr = (String)src; 4.31 if (srcStr.startsWith(LOAD_CLASSPATH)) { 4.32 URL url = getResourceURL(srcStr.substring(LOAD_CLASSPATH.length())); 4.33 - source = (url != null)? new Source(url.toString(), url) : null; 4.34 + source = (url != null)? sourceFor(url.toString(), url) : null; 4.35 } else { 4.36 final File file = new File(srcStr); 4.37 if (srcStr.indexOf(':') != -1) { 4.38 @@ -614,31 +615,31 @@ 4.39 } catch (final MalformedURLException e) { 4.40 url = file.toURI().toURL(); 4.41 } 4.42 - source = new Source(url.toString(), url); 4.43 + source = sourceFor(url.toString(), url); 4.44 } 4.45 } else if (file.isFile()) { 4.46 - source = new Source(srcStr, file); 4.47 + source = sourceFor(srcStr, file); 4.48 } 4.49 } 4.50 } else if (src instanceof File && ((File)src).isFile()) { 4.51 final File file = (File)src; 4.52 - source = new Source(file.getName(), file); 4.53 + source = sourceFor(file.getName(), file); 4.54 } else if (src instanceof URL) { 4.55 final URL url = (URL)src; 4.56 - source = new Source(url.toString(), url); 4.57 + source = sourceFor(url.toString(), url); 4.58 } else if (src instanceof ScriptObject) { 4.59 final ScriptObject sobj = (ScriptObject)src; 4.60 if (sobj.has("script") && sobj.has("name")) { 4.61 final String script = JSType.toString(sobj.get("script")); 4.62 final String name = JSType.toString(sobj.get("name")); 4.63 - source = new Source(name, script); 4.64 + source = sourceFor(name, script); 4.65 } 4.66 } else if (src instanceof Map) { 4.67 final Map<?,?> map = (Map<?,?>)src; 4.68 if (map.containsKey("script") && map.containsKey("name")) { 4.69 final String script = JSType.toString(map.get("script")); 4.70 final String name = JSType.toString(map.get("name")); 4.71 - source = new Source(name, script); 4.72 + source = sourceFor(name, script); 4.73 } 4.74 } 4.75
5.1 --- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java Fri May 02 19:15:59 2014 +0530 5.2 +++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java Fri Apr 25 16:34:17 2014 +0200 5.3 @@ -39,6 +39,8 @@ 5.4 import jdk.nashorn.internal.runtime.arrays.ArrayIndex; 5.5 import jdk.nashorn.internal.runtime.linker.Bootstrap; 5.6 5.7 +import static jdk.nashorn.internal.runtime.Source.sourceFor; 5.8 + 5.9 /** 5.10 * Utilities used by "JSON" object implementation. 5.11 */ 5.12 @@ -77,9 +79,7 @@ 5.13 */ 5.14 public static Object parse(final Object text, final Object reviver) { 5.15 final String str = JSType.toString(text); 5.16 - final JSONParser parser = new JSONParser( 5.17 - new Source("<json>", str), 5.18 - new Context.ThrowErrorManager()); 5.19 + final JSONParser parser = new JSONParser(sourceFor("<json>", str), new Context.ThrowErrorManager()); 5.20 5.21 Node node; 5.22
6.1 --- a/src/jdk/nashorn/internal/runtime/Source.java Fri May 02 19:15:59 2014 +0530 6.2 +++ b/src/jdk/nashorn/internal/runtime/Source.java Fri Apr 25 16:34:17 2014 +0200 6.3 @@ -27,13 +27,16 @@ 6.4 6.5 import java.io.ByteArrayOutputStream; 6.6 import java.io.File; 6.7 +import java.io.FileNotFoundException; 6.8 import java.io.IOError; 6.9 import java.io.IOException; 6.10 import java.io.InputStream; 6.11 import java.io.Reader; 6.12 +import java.lang.ref.WeakReference; 6.13 import java.net.MalformedURLException; 6.14 import java.net.URISyntaxException; 6.15 import java.net.URL; 6.16 +import java.net.URLConnection; 6.17 import java.nio.charset.Charset; 6.18 import java.nio.charset.StandardCharsets; 6.19 import java.nio.file.Files; 6.20 @@ -43,13 +46,19 @@ 6.21 import java.security.NoSuchAlgorithmException; 6.22 import java.util.Arrays; 6.23 import java.util.Objects; 6.24 +import java.util.WeakHashMap; 6.25 +import jdk.nashorn.api.scripting.URLReader; 6.26 import jdk.nashorn.internal.parser.Token; 6.27 6.28 /** 6.29 * Source objects track the origin of JavaScript entities. 6.30 - * 6.31 */ 6.32 public final class Source { 6.33 + 6.34 + private static final DebugLogger DEBUG = new DebugLogger("source"); 6.35 + private static final int BUF_SIZE = 8 * 1024; 6.36 + private static final Cache CACHE = new Cache(); 6.37 + 6.38 /** 6.39 * Descriptive name of the source as supplied by the user. Used for error 6.40 * reporting to the user. For example, SyntaxError will use this to print message. 6.41 @@ -64,11 +73,8 @@ 6.42 */ 6.43 private final String base; 6.44 6.45 - /** Cached source content. */ 6.46 - private final char[] content; 6.47 - 6.48 - /** Length of source content. */ 6.49 - private final int length; 6.50 + /** Source content */ 6.51 + private final Data data; 6.52 6.53 /** Cached hash code */ 6.54 private int hash; 6.55 @@ -76,40 +82,297 @@ 6.56 /** Message digest */ 6.57 private byte[] digest; 6.58 6.59 - /** Source URL if available */ 6.60 - private final URL url; 6.61 + // Do *not* make this public, ever! Trusts the URL and content. 6.62 + private Source(final String name, final String base, final Data data) { 6.63 + this.name = name; 6.64 + this.base = base; 6.65 + this.data = data; 6.66 + } 6.67 6.68 - private static final int BUFSIZE = 8 * 1024; 6.69 + private static synchronized Source sourceFor(final String name, final String base, final URLData data) throws IOException { 6.70 + try { 6.71 + final Source newSource = new Source(name, base, data); 6.72 + final Source existingSource = CACHE.get(newSource); 6.73 + if (existingSource != null) { 6.74 + // Force any access errors 6.75 + data.checkPermissionAndClose(); 6.76 + return existingSource; 6.77 + } else { 6.78 + // All sources in cache must be fully loaded 6.79 + data.load(); 6.80 + CACHE.put(newSource, newSource); 6.81 + return newSource; 6.82 + } 6.83 + } catch (RuntimeException e) { 6.84 + final Throwable cause = e.getCause(); 6.85 + if (cause instanceof IOException) { 6.86 + throw (IOException) cause; 6.87 + } 6.88 + throw e; 6.89 + } 6.90 + } 6.91 6.92 - // Do *not* make this public ever! Trusts the URL and content. So has to be called 6.93 - // from other public constructors. Note that this can not be some init method as 6.94 - // we initialize final fields from here. 6.95 - private Source(final String name, final String base, final char[] content, final URL url) { 6.96 - this.name = name; 6.97 - this.base = base; 6.98 - this.content = content; 6.99 - this.length = content.length; 6.100 - this.url = url; 6.101 + private static class Cache extends WeakHashMap<Source, WeakReference<Source>> { 6.102 + public Source get(final Source key) { 6.103 + final WeakReference<Source> ref = super.get(key); 6.104 + return ref == null ? null : ref.get(); 6.105 + } 6.106 + 6.107 + public void put(final Source key, final Source value) { 6.108 + assert !(value.data instanceof RawData); 6.109 + put(key, new WeakReference<>(value)); 6.110 + } 6.111 + } 6.112 + 6.113 + // Wrapper to manage lazy loading 6.114 + private static interface Data { 6.115 + 6.116 + URL url(); 6.117 + 6.118 + int length(); 6.119 + 6.120 + long lastModified(); 6.121 + 6.122 + char[] array(); 6.123 + } 6.124 + 6.125 + private static class RawData implements Data { 6.126 + private final char[] array; 6.127 + private int hash; 6.128 + 6.129 + private RawData(final char[] array) { 6.130 + this.array = Objects.requireNonNull(array); 6.131 + } 6.132 + 6.133 + private RawData(final String source) { 6.134 + this.array = Objects.requireNonNull(source).toCharArray(); 6.135 + } 6.136 + 6.137 + private RawData(final Reader reader) throws IOException { 6.138 + this(readFully(reader)); 6.139 + } 6.140 + 6.141 + @Override 6.142 + public int hashCode() { 6.143 + int h = hash; 6.144 + if (h == 0) { 6.145 + h = hash = Arrays.hashCode(array); 6.146 + } 6.147 + return h; 6.148 + } 6.149 + 6.150 + @Override 6.151 + public boolean equals(Object obj) { 6.152 + if (this == obj) { 6.153 + return true; 6.154 + } 6.155 + if (obj instanceof RawData) { 6.156 + return Arrays.equals(array, ((RawData)obj).array); 6.157 + } 6.158 + return false; 6.159 + } 6.160 + 6.161 + @Override 6.162 + public String toString() { 6.163 + return new String(array()); 6.164 + } 6.165 + 6.166 + @Override 6.167 + public URL url() { 6.168 + return null; 6.169 + } 6.170 + 6.171 + @Override 6.172 + public int length() { 6.173 + return array.length; 6.174 + } 6.175 + 6.176 + @Override 6.177 + public long lastModified() { 6.178 + return 0; 6.179 + } 6.180 + 6.181 + @Override 6.182 + public char[] array() { 6.183 + return array; 6.184 + } 6.185 + 6.186 + 6.187 + } 6.188 + 6.189 + private static class URLData implements Data { 6.190 + private final URL url; 6.191 + protected final Charset cs; 6.192 + private int hash; 6.193 + protected char[] array; 6.194 + protected int length; 6.195 + protected long lastModified; 6.196 + 6.197 + private URLData(final URL url, final Charset cs) { 6.198 + this.url = Objects.requireNonNull(url); 6.199 + this.cs = cs; 6.200 + } 6.201 + 6.202 + @Override 6.203 + public int hashCode() { 6.204 + int h = hash; 6.205 + if (h == 0) { 6.206 + h = hash = url.hashCode(); 6.207 + } 6.208 + return h; 6.209 + } 6.210 + 6.211 + @Override 6.212 + public boolean equals(Object other) { 6.213 + if (this == other) { 6.214 + return true; 6.215 + } 6.216 + if (!(other instanceof URLData)) { 6.217 + return false; 6.218 + } 6.219 + 6.220 + URLData otherData = (URLData) other; 6.221 + 6.222 + if (url.equals(otherData.url)) { 6.223 + // Make sure both have meta data loaded 6.224 + try { 6.225 + if (isDeferred()) { 6.226 + // Data in cache is always loaded, and we only compare to cached data. 6.227 + assert !otherData.isDeferred(); 6.228 + loadMeta(); 6.229 + } else if (otherData.isDeferred()) { 6.230 + otherData.loadMeta(); 6.231 + } 6.232 + } catch (IOException e) { 6.233 + throw new RuntimeException(e); 6.234 + } 6.235 + 6.236 + // Compare meta data 6.237 + return this.length == otherData.length && this.lastModified == otherData.lastModified; 6.238 + } 6.239 + return false; 6.240 + } 6.241 + 6.242 + @Override 6.243 + public String toString() { 6.244 + return new String(array()); 6.245 + } 6.246 + 6.247 + @Override 6.248 + public URL url() { 6.249 + return url; 6.250 + } 6.251 + 6.252 + @Override 6.253 + public int length() { 6.254 + return length; 6.255 + } 6.256 + 6.257 + @Override 6.258 + public long lastModified() { 6.259 + return lastModified; 6.260 + } 6.261 + 6.262 + @Override 6.263 + public char[] array() { 6.264 + assert !isDeferred(); 6.265 + return array; 6.266 + } 6.267 + 6.268 + boolean isDeferred() { 6.269 + return array == null; 6.270 + } 6.271 + 6.272 + protected void checkPermissionAndClose() throws IOException { 6.273 + try (InputStream in = url.openStream()) {} 6.274 + debug("permission checked for ", url); 6.275 + } 6.276 + 6.277 + protected void load() throws IOException { 6.278 + if (array == null) { 6.279 + final URLConnection c = url.openConnection(); 6.280 + try (InputStream in = c.getInputStream()) { 6.281 + array = cs == null ? readFully(in) : readFully(in, cs); 6.282 + length = array.length; 6.283 + lastModified = c.getLastModified(); 6.284 + debug("loaded content for ", url); 6.285 + } 6.286 + } 6.287 + } 6.288 + 6.289 + protected void loadMeta() throws IOException { 6.290 + if (length == 0 && lastModified == 0) { 6.291 + final URLConnection c = url.openConnection(); 6.292 + length = c.getContentLength(); 6.293 + lastModified = c.getLastModified(); 6.294 + debug("loaded metadata for ", url); 6.295 + } 6.296 + } 6.297 + } 6.298 + 6.299 + private static class FileData extends URLData { 6.300 + private final File file; 6.301 + 6.302 + private FileData(final File file, final Charset cs) { 6.303 + super(getURLFromFile(file), cs); 6.304 + this.file = file; 6.305 + 6.306 + } 6.307 + 6.308 + @Override 6.309 + protected void checkPermissionAndClose() throws IOException { 6.310 + if (!file.canRead()) { 6.311 + throw new FileNotFoundException(file + " (Permission Denied)"); 6.312 + } 6.313 + debug("permission checked for ", file); 6.314 + } 6.315 + 6.316 + @Override 6.317 + protected void loadMeta() { 6.318 + if (length == 0 && lastModified == 0) { 6.319 + length = (int) file.length(); 6.320 + lastModified = file.lastModified(); 6.321 + debug("loaded metadata for ", file); 6.322 + } 6.323 + } 6.324 + 6.325 + @Override 6.326 + protected void load() throws IOException { 6.327 + if (array == null) { 6.328 + array = cs == null ? readFully(file) : readFully(file, cs); 6.329 + length = array.length; 6.330 + lastModified = file.lastModified(); 6.331 + debug("loaded content for ", file); 6.332 + } 6.333 + } 6.334 + } 6.335 + 6.336 + private static void debug(final Object... msg) { 6.337 + DEBUG.info(msg); 6.338 + } 6.339 + 6.340 + private char[] data() { 6.341 + return data.array(); 6.342 } 6.343 6.344 /** 6.345 - * Constructor 6.346 + * Returns an instance 6.347 * 6.348 * @param name source name 6.349 * @param content contents as char array 6.350 */ 6.351 - public Source(final String name, final char[] content) { 6.352 - this(name, baseName(name, null), content, null); 6.353 + public static Source sourceFor(final String name, final char[] content) { 6.354 + return new Source(name, baseName(name), new RawData(content)); 6.355 } 6.356 6.357 /** 6.358 - * Constructor 6.359 + * Returns an instance 6.360 * 6.361 * @param name source name 6.362 * @param content contents as string 6.363 */ 6.364 - public Source(final String name, final String content) { 6.365 - this(name, content.toCharArray()); 6.366 + public static Source sourceFor(final String name, final String content) { 6.367 + return new Source(name, baseName(name), new RawData(content)); 6.368 } 6.369 6.370 /** 6.371 @@ -120,8 +383,8 @@ 6.372 * 6.373 * @throws IOException if source cannot be loaded 6.374 */ 6.375 - public Source(final String name, final URL url) throws IOException { 6.376 - this(name, baseURL(url, null), readFully(url), url); 6.377 + public static Source sourceFor(final String name, final URL url) throws IOException { 6.378 + return sourceFor(name, url, null); 6.379 } 6.380 6.381 /** 6.382 @@ -133,8 +396,8 @@ 6.383 * 6.384 * @throws IOException if source cannot be loaded 6.385 */ 6.386 - public Source(final String name, final URL url, final Charset cs) throws IOException { 6.387 - this(name, baseURL(url, null), readFully(url, cs), url); 6.388 + public static Source sourceFor(final String name, final URL url, final Charset cs) throws IOException { 6.389 + return sourceFor(name, baseURL(url), new URLData(url, cs)); 6.390 } 6.391 6.392 /** 6.393 @@ -145,8 +408,8 @@ 6.394 * 6.395 * @throws IOException if source cannot be loaded 6.396 */ 6.397 - public Source(final String name, final File file) throws IOException { 6.398 - this(name, dirName(file, null), readFully(file), getURLFromFile(file)); 6.399 + public static Source sourceFor(final String name, final File file) throws IOException { 6.400 + return sourceFor(name, file, null); 6.401 } 6.402 6.403 /** 6.404 @@ -158,8 +421,25 @@ 6.405 * 6.406 * @throws IOException if source cannot be loaded 6.407 */ 6.408 - public Source(final String name, final File file, final Charset cs) throws IOException { 6.409 - this(name, dirName(file, null), readFully(file, cs), getURLFromFile(file)); 6.410 + public static Source sourceFor(final String name, final File file, final Charset cs) throws IOException { 6.411 + final File absFile = file.getAbsoluteFile(); 6.412 + return sourceFor(name, dirName(absFile, null), new FileData(file, cs)); 6.413 + } 6.414 + 6.415 + /** 6.416 + * Returns an instance 6.417 + * 6.418 + * @param name source name 6.419 + * @param reader reader from which source can be loaded 6.420 + * @throws IOException if source cannot be loaded 6.421 + */ 6.422 + public static Source sourceFor(final String name, final Reader reader) throws IOException { 6.423 + // Extract URL from URLReader to defer loading and reuse cached data if available. 6.424 + if (reader instanceof URLReader) { 6.425 + final URLReader urlReader = (URLReader) reader; 6.426 + return sourceFor(name, urlReader.getURL(), urlReader.getCharset()); 6.427 + } 6.428 + return new Source(name, baseName(name), new RawData(reader)); 6.429 } 6.430 6.431 @Override 6.432 @@ -167,21 +447,18 @@ 6.433 if (this == obj) { 6.434 return true; 6.435 } 6.436 - 6.437 if (!(obj instanceof Source)) { 6.438 return false; 6.439 } 6.440 - 6.441 - final Source src = (Source)obj; 6.442 - // Only compare content as a last resort measure 6.443 - return length == src.length && Objects.equals(url, src.url) && Objects.equals(name, src.name) && Arrays.equals(content, src.content); 6.444 + final Source other = (Source) obj; 6.445 + return Objects.equals(name, other.name) && data.equals(other.data); 6.446 } 6.447 6.448 @Override 6.449 public int hashCode() { 6.450 int h = hash; 6.451 if (h == 0) { 6.452 - h = hash = Arrays.hashCode(content) ^ Objects.hashCode(name); 6.453 + h = hash = data.hashCode() ^ Objects.hashCode(name); 6.454 } 6.455 return h; 6.456 } 6.457 @@ -191,7 +468,7 @@ 6.458 * @return Source content. 6.459 */ 6.460 public String getString() { 6.461 - return new String(content, 0, length); 6.462 + return data.toString(); 6.463 } 6.464 6.465 /** 6.466 @@ -203,6 +480,14 @@ 6.467 } 6.468 6.469 /** 6.470 + * Get the last modified time of this script. 6.471 + * @return Last modified time. 6.472 + */ 6.473 + public long getLastModified() { 6.474 + return data.lastModified(); 6.475 + } 6.476 + 6.477 + /** 6.478 * Get the "directory" part of the file or "base" of the URL. 6.479 * @return base of file or URL. 6.480 */ 6.481 @@ -217,7 +502,7 @@ 6.482 * @return Source content portion. 6.483 */ 6.484 public String getString(final int start, final int len) { 6.485 - return new String(content, start, len); 6.486 + return new String(data(), start, len); 6.487 } 6.488 6.489 /** 6.490 @@ -228,7 +513,7 @@ 6.491 public String getString(final long token) { 6.492 final int start = Token.descPosition(token); 6.493 final int len = Token.descLength(token); 6.494 - return new String(content, start, len); 6.495 + return new String(data(), start, len); 6.496 } 6.497 6.498 /** 6.499 @@ -238,7 +523,7 @@ 6.500 * @return URL source or null 6.501 */ 6.502 public URL getURL() { 6.503 - return url; 6.504 + return data.url(); 6.505 } 6.506 6.507 /** 6.508 @@ -247,8 +532,9 @@ 6.509 * @return Index of first character of line. 6.510 */ 6.511 private int findBOLN(final int position) { 6.512 + final char[] data = data(); 6.513 for (int i = position - 1; i > 0; i--) { 6.514 - final char ch = content[i]; 6.515 + final char ch = data[i]; 6.516 6.517 if (ch == '\n' || ch == '\r') { 6.518 return i + 1; 6.519 @@ -264,8 +550,10 @@ 6.520 * @return Index of last character of line. 6.521 */ 6.522 private int findEOLN(final int position) { 6.523 - for (int i = position; i < length; i++) { 6.524 - final char ch = content[i]; 6.525 + final char[] data = data(); 6.526 + final int length = data.length; 6.527 + for (int i = position; i < length; i++) { 6.528 + final char ch = data[i]; 6.529 6.530 if (ch == '\n' || ch == '\r') { 6.531 return i - 1; 6.532 @@ -285,11 +573,12 @@ 6.533 * @return Line number. 6.534 */ 6.535 public int getLine(final int position) { 6.536 + final char[] data = data(); 6.537 // Line count starts at 1. 6.538 int line = 1; 6.539 6.540 for (int i = 0; i < position; i++) { 6.541 - final char ch = content[i]; 6.542 + final char ch = data[i]; 6.543 // Works for both \n and \r\n. 6.544 if (ch == '\n') { 6.545 line++; 6.546 @@ -320,7 +609,7 @@ 6.547 // Find end of this line. 6.548 final int last = findEOLN(position); 6.549 6.550 - return new String(content, first, last - first + 1); 6.551 + return new String(data(), first, last - first + 1); 6.552 } 6.553 6.554 /** 6.555 @@ -328,7 +617,7 @@ 6.556 * @return content 6.557 */ 6.558 public char[] getContent() { 6.559 - return content.clone(); 6.560 + return data().clone(); 6.561 } 6.562 6.563 /** 6.564 @@ -336,19 +625,18 @@ 6.565 * @return length 6.566 */ 6.567 public int getLength() { 6.568 - return length; 6.569 + return data.length(); 6.570 } 6.571 6.572 /** 6.573 * Read all of the source until end of file. Return it as char array 6.574 * 6.575 - * @param reader reader opened to source stream 6.576 + * @param reader reader opened to source stream 6.577 * @return source as content 6.578 - * 6.579 * @throws IOException if source could not be read 6.580 */ 6.581 public static char[] readFully(final Reader reader) throws IOException { 6.582 - final char[] arr = new char[BUFSIZE]; 6.583 + final char[] arr = new char[BUF_SIZE]; 6.584 final StringBuilder sb = new StringBuilder(); 6.585 6.586 try { 6.587 @@ -366,9 +654,8 @@ 6.588 /** 6.589 * Read all of the source until end of file. Return it as char array 6.590 * 6.591 - * @param file source file 6.592 + * @param file source file 6.593 * @return source as content 6.594 - * 6.595 * @throws IOException if source could not be read 6.596 */ 6.597 public static char[] readFully(final File file) throws IOException { 6.598 @@ -381,10 +668,9 @@ 6.599 /** 6.600 * Read all of the source until end of file. Return it as char array 6.601 * 6.602 - * @param file source file 6.603 + * @param file source file 6.604 * @param cs Charset used to convert bytes to chars 6.605 * @return source as content 6.606 - * 6.607 * @throws IOException if source could not be read 6.608 */ 6.609 public static char[] readFully(final File file, final Charset cs) throws IOException { 6.610 @@ -393,7 +679,7 @@ 6.611 } 6.612 6.613 final byte[] buf = Files.readAllBytes(file.toPath()); 6.614 - return (cs != null)? new String(buf, cs).toCharArray() : byteToCharArray(buf); 6.615 + return (cs != null) ? new String(buf, cs).toCharArray() : byteToCharArray(buf); 6.616 } 6.617 6.618 /** 6.619 @@ -401,7 +687,6 @@ 6.620 * 6.621 * @param url URL to read content from 6.622 * @return source as content 6.623 - * 6.624 * @throws IOException if source could not be read 6.625 */ 6.626 public static char[] readFully(final URL url) throws IOException { 6.627 @@ -414,7 +699,6 @@ 6.628 * @param url URL to read content from 6.629 * @param cs Charset used to convert bytes to chars 6.630 * @return source as content 6.631 - * 6.632 * @throws IOException if source could not be read 6.633 */ 6.634 public static char[] readFully(final URL url, final Charset cs) throws IOException { 6.635 @@ -428,7 +712,7 @@ 6.636 */ 6.637 public synchronized byte[] getDigest() { 6.638 if (digest == null) { 6.639 - 6.640 + final char[] content = data(); 6.641 final byte[] bytes = new byte[content.length * 2]; 6.642 6.643 for (int i = 0; i < content.length; i++) { 6.644 @@ -444,8 +728,8 @@ 6.645 if (base != null) { 6.646 md.update(base.getBytes(StandardCharsets.UTF_8)); 6.647 } 6.648 - if (url != null) { 6.649 - md.update(url.toString().getBytes(StandardCharsets.UTF_8)); 6.650 + if (getURL() != null) { 6.651 + md.update(getURL().toString().getBytes(StandardCharsets.UTF_8)); 6.652 } 6.653 digest = md.digest(bytes); 6.654 } catch (NoSuchAlgorithmException e) { 6.655 @@ -461,50 +745,46 @@ 6.656 * @return base URL for url 6.657 */ 6.658 public static String baseURL(final URL url) { 6.659 - return baseURL(url, null); 6.660 - } 6.661 - 6.662 - private static String baseURL(final URL url, final String defaultValue) { 6.663 if (url.getProtocol().equals("file")) { 6.664 try { 6.665 final Path path = Paths.get(url.toURI()); 6.666 final Path parent = path.getParent(); 6.667 - return (parent != null) ? (parent + File.separator) : defaultValue; 6.668 + return (parent != null) ? (parent + File.separator) : null; 6.669 } catch (final SecurityException | URISyntaxException | IOError e) { 6.670 - return defaultValue; 6.671 + return null; 6.672 } 6.673 } 6.674 6.675 // FIXME: is there a better way to find 'base' URL of a given URL? 6.676 String path = url.getPath(); 6.677 if (path.isEmpty()) { 6.678 - return defaultValue; 6.679 + return null; 6.680 } 6.681 path = path.substring(0, path.lastIndexOf('/') + 1); 6.682 final int port = url.getPort(); 6.683 try { 6.684 return new URL(url.getProtocol(), url.getHost(), port, path).toString(); 6.685 } catch (final MalformedURLException e) { 6.686 - return defaultValue; 6.687 + return null; 6.688 } 6.689 } 6.690 6.691 - private static String dirName(final File file, final String defaultValue) { 6.692 + private static String dirName(final File file, final String DEFAULT_BASE_NAME) { 6.693 final String res = file.getParent(); 6.694 - return (res != null)? (res + File.separator) : defaultValue; 6.695 + return (res != null) ? (res + File.separator) : DEFAULT_BASE_NAME; 6.696 } 6.697 6.698 // fake directory like name 6.699 - private static String baseName(final String name, final String defaultValue) { 6.700 + private static String baseName(final String name) { 6.701 int idx = name.lastIndexOf('/'); 6.702 if (idx == -1) { 6.703 idx = name.lastIndexOf('\\'); 6.704 } 6.705 - return (idx != -1)? name.substring(0, idx + 1) : defaultValue; 6.706 + return (idx != -1) ? name.substring(0, idx + 1) : null; 6.707 } 6.708 6.709 private static char[] readFully(final InputStream is, final Charset cs) throws IOException { 6.710 - return (cs != null)? new String(readBytes(is), cs).toCharArray() : readFully(is); 6.711 + return (cs != null) ? new String(readBytes(is), cs).toCharArray() : readFully(is); 6.712 } 6.713 6.714 private static char[] readFully(final InputStream is) throws IOException { 6.715 @@ -515,19 +795,19 @@ 6.716 Charset cs = StandardCharsets.UTF_8; 6.717 int start = 0; 6.718 // BOM detection. 6.719 - if (bytes.length > 1 && bytes[0] == (byte)0xFE && bytes[1] == (byte)0xFF) { 6.720 + if (bytes.length > 1 && bytes[0] == (byte) 0xFE && bytes[1] == (byte) 0xFF) { 6.721 start = 2; 6.722 cs = StandardCharsets.UTF_16BE; 6.723 - } else if (bytes.length > 1 && bytes[0] == (byte)0xFF && bytes[1] == (byte)0xFE) { 6.724 + } else if (bytes.length > 1 && bytes[0] == (byte) 0xFF && bytes[1] == (byte) 0xFE) { 6.725 start = 2; 6.726 cs = StandardCharsets.UTF_16LE; 6.727 - } else if (bytes.length > 2 && bytes[0] == (byte)0xEF && bytes[1] == (byte)0xBB && bytes[2] == (byte)0xBF) { 6.728 + } else if (bytes.length > 2 && bytes[0] == (byte) 0xEF && bytes[1] == (byte) 0xBB && bytes[2] == (byte) 0xBF) { 6.729 start = 3; 6.730 cs = StandardCharsets.UTF_8; 6.731 - } else if (bytes.length > 3 && bytes[0] == (byte)0xFF && bytes[1] == (byte)0xFE && bytes[2] == 0 && bytes[3] == 0) { 6.732 + } else if (bytes.length > 3 && bytes[0] == (byte) 0xFF && bytes[1] == (byte) 0xFE && bytes[2] == 0 && bytes[3] == 0) { 6.733 start = 4; 6.734 cs = Charset.forName("UTF-32LE"); 6.735 - } else if (bytes.length > 3 && bytes[0] == 0 && bytes[1] == 0 && bytes[2] == (byte)0xFE && bytes[3] == (byte)0xFF) { 6.736 + } else if (bytes.length > 3 && bytes[0] == 0 && bytes[1] == 0 && bytes[2] == (byte) 0xFE && bytes[3] == (byte) 0xFF) { 6.737 start = 4; 6.738 cs = Charset.forName("UTF-32BE"); 6.739 } 6.740 @@ -536,7 +816,7 @@ 6.741 } 6.742 6.743 static byte[] readBytes(final InputStream is) throws IOException { 6.744 - final byte[] arr = new byte[BUFSIZE]; 6.745 + final byte[] arr = new byte[BUF_SIZE]; 6.746 try { 6.747 try (ByteArrayOutputStream buf = new ByteArrayOutputStream()) { 6.748 int numBytes;
7.1 --- a/src/jdk/nashorn/tools/Shell.java Fri May 02 19:15:59 2014 +0530 7.2 +++ b/src/jdk/nashorn/tools/Shell.java Fri Apr 25 16:34:17 2014 +0200 7.3 @@ -25,6 +25,8 @@ 7.4 7.5 package jdk.nashorn.tools; 7.6 7.7 +import static jdk.nashorn.internal.runtime.Source.sourceFor; 7.8 + 7.9 import java.io.BufferedReader; 7.10 import java.io.File; 7.11 import java.io.FileReader; 7.12 @@ -50,7 +52,6 @@ 7.13 import jdk.nashorn.internal.runtime.Property; 7.14 import jdk.nashorn.internal.runtime.ScriptEnvironment; 7.15 import jdk.nashorn.internal.runtime.ScriptFunction; 7.16 -import jdk.nashorn.internal.runtime.ScriptObject; 7.17 import jdk.nashorn.internal.runtime.ScriptRuntime; 7.18 import jdk.nashorn.internal.runtime.Source; 7.19 import jdk.nashorn.internal.runtime.options.Options; 7.20 @@ -244,7 +245,7 @@ 7.21 7.22 // For each file on the command line. 7.23 for (final String fileName : files) { 7.24 - final FunctionNode functionNode = new Parser(env, new Source(fileName, new File(fileName)), errors).parse(); 7.25 + final FunctionNode functionNode = new Parser(env, sourceFor(fileName, new File(fileName)), errors).parse(); 7.26 7.27 if (errors.getNumberOfErrors() != 0) { 7.28 return COMPILATION_ERROR; 7.29 @@ -302,7 +303,7 @@ 7.30 } 7.31 7.32 final File file = new File(fileName); 7.33 - final ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global); 7.34 + final ScriptFunction script = context.compileScript(sourceFor(fileName, file), global); 7.35 if (script == null || errors.getNumberOfErrors() != 0) { 7.36 return COMPILATION_ERROR; 7.37 } 7.38 @@ -405,7 +406,7 @@ 7.39 7.40 // initialize with "shell.js" script 7.41 try { 7.42 - final Source source = new Source("<shell.js>", Shell.class.getResource("resources/shell.js")); 7.43 + final Source source = sourceFor("<shell.js>", Shell.class.getResource("resources/shell.js")); 7.44 context.eval(global, source.getString(), global, "<shell.js>", false); 7.45 } catch (final Exception e) { 7.46 err.println(e);
8.1 --- a/test/script/trusted/JDK-8006529.js Fri May 02 19:15:59 2014 +0530 8.2 +++ b/test/script/trusted/JDK-8006529.js Fri Apr 25 16:34:17 2014 +0200 8.3 @@ -113,7 +113,7 @@ 8.4 var getContextMethod = Context.class.getMethod("getContext") 8.5 var getEnvMethod = Context.class.getMethod("getEnv") 8.6 8.7 -var SourceConstructor = Source.class.getConstructor(java.lang.String.class, java.lang.String.class) 8.8 +var sourceForMethod = Source.class.getMethod("sourceFor", java.lang.String.class, java.lang.String.class) 8.9 var ParserConstructor = Parser.class.getConstructor(ScriptEnvironment.class, Source.class, ErrorManager.class) 8.10 var CompilerConstructor = Compiler.class.getConstructor(ScriptEnvironment.class) 8.11 8.12 @@ -121,7 +121,7 @@ 8.13 // source code, returns a jdk.nashorn.internal.ir.FunctionNode object 8.14 // representing it. 8.15 function compile(source) { 8.16 - var source = SourceConstructor.newInstance("<no name>", source); 8.17 + var source = sourceForMethod.invoke(null, "<no name>", source); 8.18 8.19 var env = getEnvMethod.invoke(getContextMethod.invoke(null)) 8.20
9.1 --- a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Fri May 02 19:15:59 2014 +0530 9.2 +++ b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Fri Apr 25 16:34:17 2014 +0200 9.3 @@ -25,6 +25,9 @@ 9.4 9.5 package jdk.nashorn.internal.codegen; 9.6 9.7 +import static jdk.nashorn.internal.runtime.Source.sourceFor; 9.8 +import static jdk.nashorn.internal.runtime.Source.readFully; 9.9 + 9.10 import java.io.File; 9.11 import java.io.PrintWriter; 9.12 import java.io.StringWriter; 9.13 @@ -32,7 +35,6 @@ 9.14 import jdk.nashorn.internal.runtime.Context; 9.15 import jdk.nashorn.internal.runtime.ErrorManager; 9.16 import jdk.nashorn.internal.runtime.ScriptFunction; 9.17 -import jdk.nashorn.internal.runtime.ScriptObject; 9.18 import jdk.nashorn.internal.runtime.Source; 9.19 import jdk.nashorn.internal.runtime.options.Options; 9.20 import org.testng.Assert; 9.21 @@ -152,7 +154,7 @@ 9.22 final boolean globalChanged = (oldGlobal != global); 9.23 9.24 try { 9.25 - final char[] buffer = Source.readFully(file); 9.26 + final char[] buffer = readFully(file); 9.27 boolean excluded = false; 9.28 9.29 if (filter != null) { 9.30 @@ -171,7 +173,7 @@ 9.31 if (globalChanged) { 9.32 Context.setGlobal(global); 9.33 } 9.34 - final Source source = new Source(file.getAbsolutePath(), buffer); 9.35 + final Source source = sourceFor(file.getAbsolutePath(), buffer); 9.36 final ScriptFunction script = context.compileScript(source, global); 9.37 if (script == null || context.getErrorManager().getNumberOfErrors() > 0) { 9.38 log("Compile failed: " + file.getAbsolutePath());
10.1 --- a/test/src/jdk/nashorn/internal/parser/ParserTest.java Fri May 02 19:15:59 2014 +0530 10.2 +++ b/test/src/jdk/nashorn/internal/parser/ParserTest.java Fri Apr 25 16:34:17 2014 +0200 10.3 @@ -25,6 +25,9 @@ 10.4 10.5 package jdk.nashorn.internal.parser; 10.6 10.7 +import static jdk.nashorn.internal.runtime.Source.sourceFor; 10.8 +import static jdk.nashorn.internal.runtime.Source.readFully; 10.9 + 10.10 import java.io.File; 10.11 import jdk.nashorn.internal.runtime.Context; 10.12 import jdk.nashorn.internal.runtime.ErrorManager; 10.13 @@ -132,7 +135,7 @@ 10.14 } 10.15 10.16 try { 10.17 - final char[] buffer = Source.readFully(file); 10.18 + final char[] buffer = readFully(file); 10.19 boolean excluded = false; 10.20 if (filter != null) { 10.21 final String content = new String(buffer); 10.22 @@ -154,7 +157,7 @@ 10.23 } 10.24 }; 10.25 errors.setLimit(0); 10.26 - final Source source = new Source(file.getAbsolutePath(), buffer); 10.27 + final Source source = sourceFor(file.getAbsolutePath(), buffer); 10.28 new Parser(context.getEnv(), source, errors).parse(); 10.29 if (errors.getNumberOfErrors() > 0) { 10.30 log("Parse failed: " + file.getAbsolutePath());
11.1 --- a/test/src/jdk/nashorn/internal/runtime/ContextTest.java Fri May 02 19:15:59 2014 +0530 11.2 +++ b/test/src/jdk/nashorn/internal/runtime/ContextTest.java Fri Apr 25 16:34:17 2014 +0200 11.3 @@ -25,6 +25,7 @@ 11.4 11.5 package jdk.nashorn.internal.runtime; 11.6 11.7 +import static jdk.nashorn.internal.runtime.Source.sourceFor; 11.8 import static org.testng.Assert.assertEquals; 11.9 import static org.testng.Assert.assertTrue; 11.10 11.11 @@ -107,7 +108,7 @@ 11.12 } 11.13 11.14 private Object eval(final Context cx, final String name, final String code) { 11.15 - final Source source = new Source(name, code); 11.16 + final Source source = sourceFor(name, code); 11.17 final ScriptObject global = Context.getGlobal(); 11.18 final ScriptFunction func = cx.compileScript(source, global); 11.19 return func != null ? ScriptRuntime.apply(func, global) : null;
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/test/src/jdk/nashorn/internal/runtime/SourceTest.java Fri Apr 25 16:34:17 2014 +0200 12.3 @@ -0,0 +1,128 @@ 12.4 +/* 12.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 12.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 12.7 + * 12.8 + * This code is free software; you can redistribute it and/or modify it 12.9 + * under the terms of the GNU General Public License version 2 only, as 12.10 + * published by the Free Software Foundation. Oracle designates this 12.11 + * particular file as subject to the "Classpath" exception as provided 12.12 + * by Oracle in the LICENSE file that accompanied this code. 12.13 + * 12.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 12.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12.17 + * version 2 for more details (a copy is included in the LICENSE file that 12.18 + * accompanied this code). 12.19 + * 12.20 + * You should have received a copy of the GNU General Public License version 12.21 + * 2 along with this work; if not, write to the Free Software Foundation, 12.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 12.23 + * 12.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 12.25 + * or visit www.oracle.com if you need additional information or have any 12.26 + * questions. 12.27 + */ 12.28 + 12.29 +package jdk.nashorn.internal.runtime; 12.30 + 12.31 +import jdk.nashorn.api.scripting.URLReader; 12.32 +import org.testng.annotations.Test; 12.33 + 12.34 +import java.io.File; 12.35 +import java.io.IOException; 12.36 +import java.io.InputStreamReader; 12.37 +import java.io.Reader; 12.38 +import java.net.URL; 12.39 +import java.util.Arrays; 12.40 + 12.41 +import static jdk.nashorn.internal.runtime.Source.sourceFor; 12.42 +import static org.testng.Assert.assertEquals; 12.43 +import static org.testng.Assert.assertTrue; 12.44 +import static org.testng.Assert.fail; 12.45 + 12.46 +/** 12.47 + * Tests different Source representations. 12.48 + */ 12.49 +public class SourceTest { 12.50 + 12.51 + final private static String SOURCE_NAME = "source.js"; 12.52 + final private static String SOURCE_STRING = "var x = 1;"; 12.53 + final private static char[] SOURCE_CHARS = SOURCE_STRING.toCharArray(); 12.54 + final private static String RESOURCE_PATH = "resources/load_test.js"; 12.55 + final private static File SOURCE_FILE = new File("build/test/classes/jdk/nashorn/internal/runtime/" + RESOURCE_PATH); 12.56 + final private static URL SOURCE_URL = SourceTest.class.getResource(RESOURCE_PATH); 12.57 + 12.58 + 12.59 + @Test 12.60 + public void testStringSource() { 12.61 + testSources(sourceFor(SOURCE_NAME, SOURCE_STRING), sourceFor(SOURCE_NAME, SOURCE_STRING)); 12.62 + testSources(sourceFor(SOURCE_NAME, SOURCE_STRING), sourceFor(SOURCE_NAME, SOURCE_CHARS)); 12.63 + } 12.64 + 12.65 + @Test 12.66 + public void testCharArraySource() { 12.67 + testSources(sourceFor(SOURCE_NAME, SOURCE_CHARS), sourceFor(SOURCE_NAME, SOURCE_CHARS)); 12.68 + testSources(sourceFor(SOURCE_NAME, SOURCE_CHARS), sourceFor(SOURCE_NAME, SOURCE_STRING)); 12.69 + } 12.70 + 12.71 + @Test 12.72 + public void testURLSource() { 12.73 + try { 12.74 + testSources(sourceFor(SOURCE_NAME, SOURCE_URL), sourceFor(SOURCE_NAME, SOURCE_URL)); 12.75 + testSources(sourceFor(SOURCE_NAME, SOURCE_URL), sourceFor(SOURCE_NAME, new URLReader(SOURCE_URL))); 12.76 + 12.77 + } catch (final IOException e) { 12.78 + fail(e.toString()); 12.79 + } 12.80 + } 12.81 + 12.82 + @Test 12.83 + public void testURLReaderSource() { 12.84 + try { 12.85 + System.err.println(SourceTest.class.getResource("")); 12.86 + testSources(sourceFor(SOURCE_NAME, new URLReader(SOURCE_URL)), sourceFor(SOURCE_NAME, new URLReader(SOURCE_URL))); 12.87 + testSources(sourceFor(SOURCE_NAME, new URLReader(SOURCE_URL)), sourceFor(SOURCE_NAME, SOURCE_URL)); 12.88 + } catch (final IOException e) { 12.89 + fail(e.toString()); 12.90 + } 12.91 + } 12.92 + 12.93 + @Test 12.94 + public void testReaderSource() { 12.95 + try { 12.96 + testSources(sourceFor(SOURCE_NAME, getReader(RESOURCE_PATH)), sourceFor(SOURCE_NAME, getReader(RESOURCE_PATH))); 12.97 + } catch (final IOException e) { 12.98 + fail(e.toString()); 12.99 + } 12.100 + } 12.101 + 12.102 + @Test 12.103 + public void testFileSource() { 12.104 + try { 12.105 + testSources(sourceFor(SOURCE_NAME, SOURCE_FILE), sourceFor(SOURCE_NAME, SOURCE_FILE)); 12.106 + } catch (final IOException e) { 12.107 + fail(e.toString()); 12.108 + } 12.109 + } 12.110 + 12.111 + private Reader getReader(final String path) { 12.112 + return new InputStreamReader(SourceTest.class.getResourceAsStream(path)); 12.113 + } 12.114 + 12.115 + private void testSources(final Source source1, final Source source2) { 12.116 + final char[] chars1 = source1.getContent(); 12.117 + final char[] chars2 = source2.getContent(); 12.118 + final String str1 = source1.getString(); 12.119 + final String str2 = source2.getString(); 12.120 + assertTrue(Arrays.equals(chars1, chars2)); 12.121 + assertEquals(str1, str2); 12.122 + assertEquals(source1.hashCode(), source2.hashCode()); 12.123 + assertTrue(source1.equals(source2)); 12.124 + // Test for immutability 12.125 + Arrays.fill(source1.getContent(), (char)0); 12.126 + Arrays.fill(source2.getContent(), (char)1); 12.127 + assertTrue(Arrays.equals(source1.getContent(), str1.toCharArray())); 12.128 + assertTrue(Arrays.equals(source1.getContent(), chars1)); 12.129 + assertTrue(Arrays.equals(source1.getContent(), source2.getContent())); 12.130 + } 12.131 +}
13.1 --- a/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java Fri May 02 19:15:59 2014 +0530 13.2 +++ b/test/src/jdk/nashorn/internal/test/framework/SharedContextEvaluator.java Fri Apr 25 16:34:17 2014 +0200 13.3 @@ -25,6 +25,7 @@ 13.4 13.5 package jdk.nashorn.internal.test.framework; 13.6 13.7 +import static jdk.nashorn.internal.runtime.Source.sourceFor; 13.8 import static jdk.nashorn.tools.Shell.COMPILATION_ERROR; 13.9 import static jdk.nashorn.tools.Shell.RUNTIME_ERROR; 13.10 import static jdk.nashorn.tools.Shell.SUCCESS; 13.11 @@ -39,7 +40,6 @@ 13.12 import jdk.nashorn.internal.runtime.ErrorManager; 13.13 import jdk.nashorn.internal.runtime.ScriptFunction; 13.14 import jdk.nashorn.internal.runtime.ScriptRuntime; 13.15 -import jdk.nashorn.internal.runtime.Source; 13.16 import jdk.nashorn.internal.runtime.options.Options; 13.17 13.18 /** 13.19 @@ -125,7 +125,7 @@ 13.20 continue; 13.21 } 13.22 final File file = new File(fileName); 13.23 - ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global); 13.24 + ScriptFunction script = context.compileScript(sourceFor(fileName, file.toURI().toURL()), global); 13.25 13.26 if (script == null || errors.getNumberOfErrors() != 0) { 13.27 return COMPILATION_ERROR;
14.1 --- a/test/src/jdk/nashorn/test/models/SourceHelper.java Fri May 02 19:15:59 2014 +0530 14.2 +++ b/test/src/jdk/nashorn/test/models/SourceHelper.java Fri Apr 25 16:34:17 2014 +0200 14.3 @@ -46,7 +46,7 @@ 14.4 } 14.5 14.6 public static String readFully(final URL url) throws IOException { 14.7 - return new Source(url.toString(), url).getString(); 14.8 + return Source.sourceFor(url.toString(), url).getString(); 14.9 } 14.10 14.11 public static String readFully(final Reader reader) throws IOException {