8040078: Avoid repeated reading of source for cached loads

Reviewed-by: jlaskey, lagergren
This commit is contained in:
Hannes Wallnöfer 2014-04-25 16:34:17 +02:00
parent 8fb1f303f7
commit 60a0f257df
14 changed files with 544 additions and 132 deletions

View File

@ -27,16 +27,14 @@ package jdk.nashorn.api.scripting;
import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError; import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import static jdk.nashorn.internal.runtime.Source.sourceFor;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.net.URL; import java.net.URL;
import java.nio.charset.Charset;
import java.security.AccessControlContext; import java.security.AccessControlContext;
import java.security.AccessController; import java.security.AccessController;
import java.security.Permissions; import java.security.Permissions;
@ -124,21 +122,21 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
} }
} }
// load engine.js and return content as a char[] // load engine.js
@SuppressWarnings("resource") @SuppressWarnings("resource")
private static char[] loadEngineJSSource() { private static Source loadEngineJSSource() {
final String script = "resources/engine.js"; final String script = "resources/engine.js";
try { try {
final InputStream is = AccessController.doPrivileged( return AccessController.doPrivileged(
new PrivilegedExceptionAction<InputStream>() { new PrivilegedExceptionAction<Source>() {
@Override @Override
public InputStream run() throws Exception { public Source run() throws IOException {
final URL url = NashornScriptEngine.class.getResource(script); final URL url = NashornScriptEngine.class.getResource(script);
return url.openStream(); return sourceFor(NashornException.ENGINE_SCRIPT_SOURCE_NAME, url);
} }
}); }
return Source.readFully(new InputStreamReader(is)); );
} catch (final PrivilegedActionException | IOException e) { } catch (final PrivilegedActionException e) {
if (Context.DEBUG) { if (Context.DEBUG) {
e.printStackTrace(); e.printStackTrace();
} }
@ -147,7 +145,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
} }
// Source object for engine.js // Source object for engine.js
private static final Source ENGINE_SCRIPT_SRC = new Source(NashornException.ENGINE_SCRIPT_SOURCE_NAME, loadEngineJSSource()); private static final Source ENGINE_SCRIPT_SRC = loadEngineJSSource();
NashornScriptEngine(final NashornScriptEngineFactory factory, final ClassLoader appLoader) { NashornScriptEngine(final NashornScriptEngineFactory factory, final ClassLoader appLoader) {
this(factory, DEFAULT_OPTIONS, appLoader); this(factory, DEFAULT_OPTIONS, appLoader);
@ -282,19 +280,14 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
private static Source makeSource(final Reader reader, final ScriptContext ctxt) throws ScriptException { private static Source makeSource(final Reader reader, final ScriptContext ctxt) throws ScriptException {
try { try {
if (reader instanceof URLReader) { return sourceFor(getScriptName(ctxt), reader);
final URL url = ((URLReader)reader).getURL(); } catch (IOException e) {
final Charset cs = ((URLReader)reader).getCharset();
return new Source(url.toString(), url, cs);
}
return new Source(getScriptName(ctxt), Source.readFully(reader));
} catch (final IOException e) {
throw new ScriptException(e); throw new ScriptException(e);
} }
} }
private static Source makeSource(final String src, final ScriptContext ctxt) { private static Source makeSource(final String src, final ScriptContext ctxt) {
return new Source(getScriptName(ctxt), src); return sourceFor(getScriptName(ctxt), src);
} }
private static String getScriptName(final ScriptContext ctxt) { private static String getScriptName(final ScriptContext ctxt) {

View File

@ -25,6 +25,8 @@
package jdk.nashorn.internal.ir.debug; package jdk.nashorn.internal.ir.debug;
import static jdk.nashorn.internal.runtime.Source.sourceFor;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
@ -88,7 +90,7 @@ public final class JSONWriter extends NodeVisitor<LexicalContext> {
* @return JSON string representation of AST of the supplied code * @return JSON string representation of AST of the supplied code
*/ */
public static String parse(final ScriptEnvironment env, final String code, final String name, final boolean includeLoc) { public static String parse(final ScriptEnvironment env, final String code, final String name, final boolean includeLoc) {
final Parser parser = new Parser(env, new Source(name, code), new Context.ThrowErrorManager(), env._strict); final Parser parser = new Parser(env, sourceFor(name, code), new Context.ThrowErrorManager(), env._strict);
final JSONWriter jsonWriter = new JSONWriter(includeLoc); final JSONWriter jsonWriter = new JSONWriter(includeLoc);
try { try {
final FunctionNode functionNode = parser.parse(CompilerConstants.RUN_SCRIPT.symbolName()); final FunctionNode functionNode = parser.parse(CompilerConstants.RUN_SCRIPT.symbolName());

View File

@ -27,6 +27,7 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import static jdk.nashorn.internal.runtime.Source.sourceFor;
import java.util.List; import java.util.List;
@ -257,7 +258,7 @@ public final class NativeFunction {
} }
private static void checkFunctionParameters(final String params) { private static void checkFunctionParameters(final String params) {
final Source src = new Source("<function>", params); final Source src = sourceFor("<function>", params);
final Parser parser = new Parser(Global.getEnv(), src, new Context.ThrowErrorManager()); final Parser parser = new Parser(Global.getEnv(), src, new Context.ThrowErrorManager());
try { try {
parser.parseFormalParameterList(); parser.parseFormalParameterList();
@ -267,7 +268,7 @@ public final class NativeFunction {
} }
private static void checkFunctionBody(final String funcBody) { private static void checkFunctionBody(final String funcBody) {
final Source src = new Source("<function>", funcBody); final Source src = sourceFor("<function>", funcBody);
final Parser parser = new Parser(Global.getEnv(), src, new Context.ThrowErrorManager()); final Parser parser = new Parser(Global.getEnv(), src, new Context.ThrowErrorManager());
try { try {
parser.parseFunctionBody(); parser.parseFunctionBody();

View File

@ -32,6 +32,7 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import static jdk.nashorn.internal.runtime.Source.sourceFor;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -501,7 +502,7 @@ public final class Context {
*/ */
public Object eval(final ScriptObject initialScope, final String string, final Object callThis, final Object location, final boolean strict) { public Object eval(final ScriptObject initialScope, final String string, final Object callThis, final Object location, final boolean strict) {
final String file = (location == UNDEFINED || location == null) ? "<eval>" : location.toString(); final String file = (location == UNDEFINED || location == null) ? "<eval>" : location.toString();
final Source source = new Source(file, string); final Source source = sourceFor(file, string);
final boolean directEval = location != UNDEFINED; // is this direct 'eval' call or indirectly invoked eval? final boolean directEval = location != UNDEFINED; // is this direct 'eval' call or indirectly invoked eval?
final Global global = Context.getGlobal(); final Global global = Context.getGlobal();
@ -568,7 +569,7 @@ public final class Context {
public Source run() { public Source run() {
try { try {
final URL resURL = Context.class.getResource(resource); final URL resURL = Context.class.getResource(resource);
return (resURL != null)? new Source(srcStr, resURL) : null; return (resURL != null)? sourceFor(srcStr, resURL) : null;
} catch (final IOException exp) { } catch (final IOException exp) {
return null; return null;
} }
@ -600,7 +601,7 @@ public final class Context {
final String srcStr = (String)src; final String srcStr = (String)src;
if (srcStr.startsWith(LOAD_CLASSPATH)) { if (srcStr.startsWith(LOAD_CLASSPATH)) {
URL url = getResourceURL(srcStr.substring(LOAD_CLASSPATH.length())); URL url = getResourceURL(srcStr.substring(LOAD_CLASSPATH.length()));
source = (url != null)? new Source(url.toString(), url) : null; source = (url != null)? sourceFor(url.toString(), url) : null;
} else { } else {
final File file = new File(srcStr); final File file = new File(srcStr);
if (srcStr.indexOf(':') != -1) { if (srcStr.indexOf(':') != -1) {
@ -613,31 +614,31 @@ public final class Context {
} catch (final MalformedURLException e) { } catch (final MalformedURLException e) {
url = file.toURI().toURL(); url = file.toURI().toURL();
} }
source = new Source(url.toString(), url); source = sourceFor(url.toString(), url);
} }
} else if (file.isFile()) { } else if (file.isFile()) {
source = new Source(srcStr, file); source = sourceFor(srcStr, file);
} }
} }
} else if (src instanceof File && ((File)src).isFile()) { } else if (src instanceof File && ((File)src).isFile()) {
final File file = (File)src; final File file = (File)src;
source = new Source(file.getName(), file); source = sourceFor(file.getName(), file);
} else if (src instanceof URL) { } else if (src instanceof URL) {
final URL url = (URL)src; final URL url = (URL)src;
source = new Source(url.toString(), url); source = sourceFor(url.toString(), url);
} else if (src instanceof ScriptObject) { } else if (src instanceof ScriptObject) {
final ScriptObject sobj = (ScriptObject)src; final ScriptObject sobj = (ScriptObject)src;
if (sobj.has("script") && sobj.has("name")) { if (sobj.has("script") && sobj.has("name")) {
final String script = JSType.toString(sobj.get("script")); final String script = JSType.toString(sobj.get("script"));
final String name = JSType.toString(sobj.get("name")); final String name = JSType.toString(sobj.get("name"));
source = new Source(name, script); source = sourceFor(name, script);
} }
} else if (src instanceof Map) { } else if (src instanceof Map) {
final Map<?,?> map = (Map<?,?>)src; final Map<?,?> map = (Map<?,?>)src;
if (map.containsKey("script") && map.containsKey("name")) { if (map.containsKey("script") && map.containsKey("name")) {
final String script = JSType.toString(map.get("script")); final String script = JSType.toString(map.get("script"));
final String name = JSType.toString(map.get("name")); final String name = JSType.toString(map.get("name"));
source = new Source(name, script); source = sourceFor(name, script);
} }
} }

View File

@ -39,6 +39,8 @@ import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex; import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.Bootstrap;
import static jdk.nashorn.internal.runtime.Source.sourceFor;
/** /**
* Utilities used by "JSON" object implementation. * Utilities used by "JSON" object implementation.
*/ */
@ -77,9 +79,7 @@ public final class JSONFunctions {
*/ */
public static Object parse(final Object text, final Object reviver) { public static Object parse(final Object text, final Object reviver) {
final String str = JSType.toString(text); final String str = JSType.toString(text);
final JSONParser parser = new JSONParser( final JSONParser parser = new JSONParser(sourceFor("<json>", str), new Context.ThrowErrorManager());
new Source("<json>", str),
new Context.ThrowErrorManager());
Node node; Node node;

View File

@ -27,13 +27,16 @@ package jdk.nashorn.internal.runtime;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOError; import java.io.IOError;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Reader; import java.io.Reader;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
@ -43,13 +46,19 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects; import java.util.Objects;
import java.util.WeakHashMap;
import jdk.nashorn.api.scripting.URLReader;
import jdk.nashorn.internal.parser.Token; import jdk.nashorn.internal.parser.Token;
/** /**
* Source objects track the origin of JavaScript entities. * Source objects track the origin of JavaScript entities.
*
*/ */
public final class Source { public final class Source {
private static final DebugLogger DEBUG = new DebugLogger("source");
private static final int BUF_SIZE = 8 * 1024;
private static final Cache CACHE = new Cache();
/** /**
* Descriptive name of the source as supplied by the user. Used for error * Descriptive name of the source as supplied by the user. Used for error
* reporting to the user. For example, SyntaxError will use this to print message. * reporting to the user. For example, SyntaxError will use this to print message.
@ -64,11 +73,8 @@ public final class Source {
*/ */
private final String base; private final String base;
/** Cached source content. */ /** Source content */
private final char[] content; private final Data data;
/** Length of source content. */
private final int length;
/** Cached hash code */ /** Cached hash code */
private int hash; private int hash;
@ -76,40 +82,297 @@ public final class Source {
/** Message digest */ /** Message digest */
private byte[] digest; private byte[] digest;
/** Source URL if available */ // Do *not* make this public, ever! Trusts the URL and content.
private final URL url; private Source(final String name, final String base, final Data data) {
this.name = name;
this.base = base;
this.data = data;
}
private static final int BUFSIZE = 8 * 1024; private static synchronized Source sourceFor(final String name, final String base, final URLData data) throws IOException {
try {
final Source newSource = new Source(name, base, data);
final Source existingSource = CACHE.get(newSource);
if (existingSource != null) {
// Force any access errors
data.checkPermissionAndClose();
return existingSource;
} else {
// All sources in cache must be fully loaded
data.load();
CACHE.put(newSource, newSource);
return newSource;
}
} catch (RuntimeException e) {
final Throwable cause = e.getCause();
if (cause instanceof IOException) {
throw (IOException) cause;
}
throw e;
}
}
// Do *not* make this public ever! Trusts the URL and content. So has to be called private static class Cache extends WeakHashMap<Source, WeakReference<Source>> {
// from other public constructors. Note that this can not be some init method as public Source get(final Source key) {
// we initialize final fields from here. final WeakReference<Source> ref = super.get(key);
private Source(final String name, final String base, final char[] content, final URL url) { return ref == null ? null : ref.get();
this.name = name; }
this.base = base;
this.content = content; public void put(final Source key, final Source value) {
this.length = content.length; assert !(value.data instanceof RawData);
this.url = url; put(key, new WeakReference<>(value));
}
}
// Wrapper to manage lazy loading
private static interface Data {
URL url();
int length();
long lastModified();
char[] array();
}
private static class RawData implements Data {
private final char[] array;
private int hash;
private RawData(final char[] array) {
this.array = Objects.requireNonNull(array);
}
private RawData(final String source) {
this.array = Objects.requireNonNull(source).toCharArray();
}
private RawData(final Reader reader) throws IOException {
this(readFully(reader));
}
@Override
public int hashCode() {
int h = hash;
if (h == 0) {
h = hash = Arrays.hashCode(array);
}
return h;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof RawData) {
return Arrays.equals(array, ((RawData)obj).array);
}
return false;
}
@Override
public String toString() {
return new String(array());
}
@Override
public URL url() {
return null;
}
@Override
public int length() {
return array.length;
}
@Override
public long lastModified() {
return 0;
}
@Override
public char[] array() {
return array;
}
}
private static class URLData implements Data {
private final URL url;
protected final Charset cs;
private int hash;
protected char[] array;
protected int length;
protected long lastModified;
private URLData(final URL url, final Charset cs) {
this.url = Objects.requireNonNull(url);
this.cs = cs;
}
@Override
public int hashCode() {
int h = hash;
if (h == 0) {
h = hash = url.hashCode();
}
return h;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof URLData)) {
return false;
}
URLData otherData = (URLData) other;
if (url.equals(otherData.url)) {
// Make sure both have meta data loaded
try {
if (isDeferred()) {
// Data in cache is always loaded, and we only compare to cached data.
assert !otherData.isDeferred();
loadMeta();
} else if (otherData.isDeferred()) {
otherData.loadMeta();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
// Compare meta data
return this.length == otherData.length && this.lastModified == otherData.lastModified;
}
return false;
}
@Override
public String toString() {
return new String(array());
}
@Override
public URL url() {
return url;
}
@Override
public int length() {
return length;
}
@Override
public long lastModified() {
return lastModified;
}
@Override
public char[] array() {
assert !isDeferred();
return array;
}
boolean isDeferred() {
return array == null;
}
protected void checkPermissionAndClose() throws IOException {
try (InputStream in = url.openStream()) {}
debug("permission checked for ", url);
}
protected void load() throws IOException {
if (array == null) {
final URLConnection c = url.openConnection();
try (InputStream in = c.getInputStream()) {
array = cs == null ? readFully(in) : readFully(in, cs);
length = array.length;
lastModified = c.getLastModified();
debug("loaded content for ", url);
}
}
}
protected void loadMeta() throws IOException {
if (length == 0 && lastModified == 0) {
final URLConnection c = url.openConnection();
length = c.getContentLength();
lastModified = c.getLastModified();
debug("loaded metadata for ", url);
}
}
}
private static class FileData extends URLData {
private final File file;
private FileData(final File file, final Charset cs) {
super(getURLFromFile(file), cs);
this.file = file;
}
@Override
protected void checkPermissionAndClose() throws IOException {
if (!file.canRead()) {
throw new FileNotFoundException(file + " (Permission Denied)");
}
debug("permission checked for ", file);
}
@Override
protected void loadMeta() {
if (length == 0 && lastModified == 0) {
length = (int) file.length();
lastModified = file.lastModified();
debug("loaded metadata for ", file);
}
}
@Override
protected void load() throws IOException {
if (array == null) {
array = cs == null ? readFully(file) : readFully(file, cs);
length = array.length;
lastModified = file.lastModified();
debug("loaded content for ", file);
}
}
}
private static void debug(final Object... msg) {
DEBUG.info(msg);
}
private char[] data() {
return data.array();
} }
/** /**
* Constructor * Returns an instance
* *
* @param name source name * @param name source name
* @param content contents as char array * @param content contents as char array
*/ */
public Source(final String name, final char[] content) { public static Source sourceFor(final String name, final char[] content) {
this(name, baseName(name, null), content, null); return new Source(name, baseName(name), new RawData(content));
} }
/** /**
* Constructor * Returns an instance
* *
* @param name source name * @param name source name
* @param content contents as string * @param content contents as string
*/ */
public Source(final String name, final String content) { public static Source sourceFor(final String name, final String content) {
this(name, content.toCharArray()); return new Source(name, baseName(name), new RawData(content));
} }
/** /**
@ -120,8 +383,8 @@ public final class Source {
* *
* @throws IOException if source cannot be loaded * @throws IOException if source cannot be loaded
*/ */
public Source(final String name, final URL url) throws IOException { public static Source sourceFor(final String name, final URL url) throws IOException {
this(name, baseURL(url, null), readFully(url), url); return sourceFor(name, url, null);
} }
/** /**
@ -133,8 +396,8 @@ public final class Source {
* *
* @throws IOException if source cannot be loaded * @throws IOException if source cannot be loaded
*/ */
public Source(final String name, final URL url, final Charset cs) throws IOException { public static Source sourceFor(final String name, final URL url, final Charset cs) throws IOException {
this(name, baseURL(url, null), readFully(url, cs), url); return sourceFor(name, baseURL(url), new URLData(url, cs));
} }
/** /**
@ -145,8 +408,8 @@ public final class Source {
* *
* @throws IOException if source cannot be loaded * @throws IOException if source cannot be loaded
*/ */
public Source(final String name, final File file) throws IOException { public static Source sourceFor(final String name, final File file) throws IOException {
this(name, dirName(file, null), readFully(file), getURLFromFile(file)); return sourceFor(name, file, null);
} }
/** /**
@ -158,8 +421,25 @@ public final class Source {
* *
* @throws IOException if source cannot be loaded * @throws IOException if source cannot be loaded
*/ */
public Source(final String name, final File file, final Charset cs) throws IOException { public static Source sourceFor(final String name, final File file, final Charset cs) throws IOException {
this(name, dirName(file, null), readFully(file, cs), getURLFromFile(file)); final File absFile = file.getAbsoluteFile();
return sourceFor(name, dirName(absFile, null), new FileData(file, cs));
}
/**
* Returns an instance
*
* @param name source name
* @param reader reader from which source can be loaded
* @throws IOException if source cannot be loaded
*/
public static Source sourceFor(final String name, final Reader reader) throws IOException {
// Extract URL from URLReader to defer loading and reuse cached data if available.
if (reader instanceof URLReader) {
final URLReader urlReader = (URLReader) reader;
return sourceFor(name, urlReader.getURL(), urlReader.getCharset());
}
return new Source(name, baseName(name), new RawData(reader));
} }
@Override @Override
@ -167,21 +447,18 @@ public final class Source {
if (this == obj) { if (this == obj) {
return true; return true;
} }
if (!(obj instanceof Source)) { if (!(obj instanceof Source)) {
return false; return false;
} }
final Source other = (Source) obj;
final Source src = (Source)obj; return Objects.equals(name, other.name) && data.equals(other.data);
// Only compare content as a last resort measure
return length == src.length && Objects.equals(url, src.url) && Objects.equals(name, src.name) && Arrays.equals(content, src.content);
} }
@Override @Override
public int hashCode() { public int hashCode() {
int h = hash; int h = hash;
if (h == 0) { if (h == 0) {
h = hash = Arrays.hashCode(content) ^ Objects.hashCode(name); h = hash = data.hashCode() ^ Objects.hashCode(name);
} }
return h; return h;
} }
@ -191,7 +468,7 @@ public final class Source {
* @return Source content. * @return Source content.
*/ */
public String getString() { public String getString() {
return new String(content, 0, length); return data.toString();
} }
/** /**
@ -202,6 +479,14 @@ public final class Source {
return name; return name;
} }
/**
* Get the last modified time of this script.
* @return Last modified time.
*/
public long getLastModified() {
return data.lastModified();
}
/** /**
* Get the "directory" part of the file or "base" of the URL. * Get the "directory" part of the file or "base" of the URL.
* @return base of file or URL. * @return base of file or URL.
@ -217,7 +502,7 @@ public final class Source {
* @return Source content portion. * @return Source content portion.
*/ */
public String getString(final int start, final int len) { public String getString(final int start, final int len) {
return new String(content, start, len); return new String(data(), start, len);
} }
/** /**
@ -228,7 +513,7 @@ public final class Source {
public String getString(final long token) { public String getString(final long token) {
final int start = Token.descPosition(token); final int start = Token.descPosition(token);
final int len = Token.descLength(token); final int len = Token.descLength(token);
return new String(content, start, len); return new String(data(), start, len);
} }
/** /**
@ -238,7 +523,7 @@ public final class Source {
* @return URL source or null * @return URL source or null
*/ */
public URL getURL() { public URL getURL() {
return url; return data.url();
} }
/** /**
@ -247,8 +532,9 @@ public final class Source {
* @return Index of first character of line. * @return Index of first character of line.
*/ */
private int findBOLN(final int position) { private int findBOLN(final int position) {
final char[] data = data();
for (int i = position - 1; i > 0; i--) { for (int i = position - 1; i > 0; i--) {
final char ch = content[i]; final char ch = data[i];
if (ch == '\n' || ch == '\r') { if (ch == '\n' || ch == '\r') {
return i + 1; return i + 1;
@ -264,8 +550,10 @@ public final class Source {
* @return Index of last character of line. * @return Index of last character of line.
*/ */
private int findEOLN(final int position) { private int findEOLN(final int position) {
for (int i = position; i < length; i++) { final char[] data = data();
final char ch = content[i]; final int length = data.length;
for (int i = position; i < length; i++) {
final char ch = data[i];
if (ch == '\n' || ch == '\r') { if (ch == '\n' || ch == '\r') {
return i - 1; return i - 1;
@ -285,11 +573,12 @@ public final class Source {
* @return Line number. * @return Line number.
*/ */
public int getLine(final int position) { public int getLine(final int position) {
final char[] data = data();
// Line count starts at 1. // Line count starts at 1.
int line = 1; int line = 1;
for (int i = 0; i < position; i++) { for (int i = 0; i < position; i++) {
final char ch = content[i]; final char ch = data[i];
// Works for both \n and \r\n. // Works for both \n and \r\n.
if (ch == '\n') { if (ch == '\n') {
line++; line++;
@ -320,7 +609,7 @@ public final class Source {
// Find end of this line. // Find end of this line.
final int last = findEOLN(position); final int last = findEOLN(position);
return new String(content, first, last - first + 1); return new String(data(), first, last - first + 1);
} }
/** /**
@ -328,7 +617,7 @@ public final class Source {
* @return content * @return content
*/ */
public char[] getContent() { public char[] getContent() {
return content.clone(); return data().clone();
} }
/** /**
@ -336,19 +625,18 @@ public final class Source {
* @return length * @return length
*/ */
public int getLength() { public int getLength() {
return length; return data.length();
} }
/** /**
* Read all of the source until end of file. Return it as char array * Read all of the source until end of file. Return it as char array
* *
* @param reader reader opened to source stream * @param reader reader opened to source stream
* @return source as content * @return source as content
*
* @throws IOException if source could not be read * @throws IOException if source could not be read
*/ */
public static char[] readFully(final Reader reader) throws IOException { public static char[] readFully(final Reader reader) throws IOException {
final char[] arr = new char[BUFSIZE]; final char[] arr = new char[BUF_SIZE];
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
try { try {
@ -366,9 +654,8 @@ public final class Source {
/** /**
* Read all of the source until end of file. Return it as char array * Read all of the source until end of file. Return it as char array
* *
* @param file source file * @param file source file
* @return source as content * @return source as content
*
* @throws IOException if source could not be read * @throws IOException if source could not be read
*/ */
public static char[] readFully(final File file) throws IOException { public static char[] readFully(final File file) throws IOException {
@ -381,10 +668,9 @@ public final class Source {
/** /**
* Read all of the source until end of file. Return it as char array * Read all of the source until end of file. Return it as char array
* *
* @param file source file * @param file source file
* @param cs Charset used to convert bytes to chars * @param cs Charset used to convert bytes to chars
* @return source as content * @return source as content
*
* @throws IOException if source could not be read * @throws IOException if source could not be read
*/ */
public static char[] readFully(final File file, final Charset cs) throws IOException { public static char[] readFully(final File file, final Charset cs) throws IOException {
@ -393,7 +679,7 @@ public final class Source {
} }
final byte[] buf = Files.readAllBytes(file.toPath()); final byte[] buf = Files.readAllBytes(file.toPath());
return (cs != null)? new String(buf, cs).toCharArray() : byteToCharArray(buf); return (cs != null) ? new String(buf, cs).toCharArray() : byteToCharArray(buf);
} }
/** /**
@ -401,7 +687,6 @@ public final class Source {
* *
* @param url URL to read content from * @param url URL to read content from
* @return source as content * @return source as content
*
* @throws IOException if source could not be read * @throws IOException if source could not be read
*/ */
public static char[] readFully(final URL url) throws IOException { public static char[] readFully(final URL url) throws IOException {
@ -414,7 +699,6 @@ public final class Source {
* @param url URL to read content from * @param url URL to read content from
* @param cs Charset used to convert bytes to chars * @param cs Charset used to convert bytes to chars
* @return source as content * @return source as content
*
* @throws IOException if source could not be read * @throws IOException if source could not be read
*/ */
public static char[] readFully(final URL url, final Charset cs) throws IOException { public static char[] readFully(final URL url, final Charset cs) throws IOException {
@ -428,7 +712,7 @@ public final class Source {
*/ */
public synchronized byte[] getDigest() { public synchronized byte[] getDigest() {
if (digest == null) { if (digest == null) {
final char[] content = data();
final byte[] bytes = new byte[content.length * 2]; final byte[] bytes = new byte[content.length * 2];
for (int i = 0; i < content.length; i++) { for (int i = 0; i < content.length; i++) {
@ -444,8 +728,8 @@ public final class Source {
if (base != null) { if (base != null) {
md.update(base.getBytes(StandardCharsets.UTF_8)); md.update(base.getBytes(StandardCharsets.UTF_8));
} }
if (url != null) { if (getURL() != null) {
md.update(url.toString().getBytes(StandardCharsets.UTF_8)); md.update(getURL().toString().getBytes(StandardCharsets.UTF_8));
} }
digest = md.digest(bytes); digest = md.digest(bytes);
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
@ -461,50 +745,46 @@ public final class Source {
* @return base URL for url * @return base URL for url
*/ */
public static String baseURL(final URL url) { public static String baseURL(final URL url) {
return baseURL(url, null);
}
private static String baseURL(final URL url, final String defaultValue) {
if (url.getProtocol().equals("file")) { if (url.getProtocol().equals("file")) {
try { try {
final Path path = Paths.get(url.toURI()); final Path path = Paths.get(url.toURI());
final Path parent = path.getParent(); final Path parent = path.getParent();
return (parent != null) ? (parent + File.separator) : defaultValue; return (parent != null) ? (parent + File.separator) : null;
} catch (final SecurityException | URISyntaxException | IOError e) { } catch (final SecurityException | URISyntaxException | IOError e) {
return defaultValue; return null;
} }
} }
// FIXME: is there a better way to find 'base' URL of a given URL? // FIXME: is there a better way to find 'base' URL of a given URL?
String path = url.getPath(); String path = url.getPath();
if (path.isEmpty()) { if (path.isEmpty()) {
return defaultValue; return null;
} }
path = path.substring(0, path.lastIndexOf('/') + 1); path = path.substring(0, path.lastIndexOf('/') + 1);
final int port = url.getPort(); final int port = url.getPort();
try { try {
return new URL(url.getProtocol(), url.getHost(), port, path).toString(); return new URL(url.getProtocol(), url.getHost(), port, path).toString();
} catch (final MalformedURLException e) { } catch (final MalformedURLException e) {
return defaultValue; return null;
} }
} }
private static String dirName(final File file, final String defaultValue) { private static String dirName(final File file, final String DEFAULT_BASE_NAME) {
final String res = file.getParent(); final String res = file.getParent();
return (res != null)? (res + File.separator) : defaultValue; return (res != null) ? (res + File.separator) : DEFAULT_BASE_NAME;
} }
// fake directory like name // fake directory like name
private static String baseName(final String name, final String defaultValue) { private static String baseName(final String name) {
int idx = name.lastIndexOf('/'); int idx = name.lastIndexOf('/');
if (idx == -1) { if (idx == -1) {
idx = name.lastIndexOf('\\'); idx = name.lastIndexOf('\\');
} }
return (idx != -1)? name.substring(0, idx + 1) : defaultValue; return (idx != -1) ? name.substring(0, idx + 1) : null;
} }
private static char[] readFully(final InputStream is, final Charset cs) throws IOException { private static char[] readFully(final InputStream is, final Charset cs) throws IOException {
return (cs != null)? new String(readBytes(is), cs).toCharArray() : readFully(is); return (cs != null) ? new String(readBytes(is), cs).toCharArray() : readFully(is);
} }
private static char[] readFully(final InputStream is) throws IOException { private static char[] readFully(final InputStream is) throws IOException {
@ -515,19 +795,19 @@ public final class Source {
Charset cs = StandardCharsets.UTF_8; Charset cs = StandardCharsets.UTF_8;
int start = 0; int start = 0;
// BOM detection. // BOM detection.
if (bytes.length > 1 && bytes[0] == (byte)0xFE && bytes[1] == (byte)0xFF) { if (bytes.length > 1 && bytes[0] == (byte) 0xFE && bytes[1] == (byte) 0xFF) {
start = 2; start = 2;
cs = StandardCharsets.UTF_16BE; cs = StandardCharsets.UTF_16BE;
} else if (bytes.length > 1 && bytes[0] == (byte)0xFF && bytes[1] == (byte)0xFE) { } else if (bytes.length > 1 && bytes[0] == (byte) 0xFF && bytes[1] == (byte) 0xFE) {
start = 2; start = 2;
cs = StandardCharsets.UTF_16LE; cs = StandardCharsets.UTF_16LE;
} else if (bytes.length > 2 && bytes[0] == (byte)0xEF && bytes[1] == (byte)0xBB && bytes[2] == (byte)0xBF) { } else if (bytes.length > 2 && bytes[0] == (byte) 0xEF && bytes[1] == (byte) 0xBB && bytes[2] == (byte) 0xBF) {
start = 3; start = 3;
cs = StandardCharsets.UTF_8; cs = StandardCharsets.UTF_8;
} else if (bytes.length > 3 && bytes[0] == (byte)0xFF && bytes[1] == (byte)0xFE && bytes[2] == 0 && bytes[3] == 0) { } else if (bytes.length > 3 && bytes[0] == (byte) 0xFF && bytes[1] == (byte) 0xFE && bytes[2] == 0 && bytes[3] == 0) {
start = 4; start = 4;
cs = Charset.forName("UTF-32LE"); cs = Charset.forName("UTF-32LE");
} else if (bytes.length > 3 && bytes[0] == 0 && bytes[1] == 0 && bytes[2] == (byte)0xFE && bytes[3] == (byte)0xFF) { } else if (bytes.length > 3 && bytes[0] == 0 && bytes[1] == 0 && bytes[2] == (byte) 0xFE && bytes[3] == (byte) 0xFF) {
start = 4; start = 4;
cs = Charset.forName("UTF-32BE"); cs = Charset.forName("UTF-32BE");
} }
@ -536,7 +816,7 @@ public final class Source {
} }
static byte[] readBytes(final InputStream is) throws IOException { static byte[] readBytes(final InputStream is) throws IOException {
final byte[] arr = new byte[BUFSIZE]; final byte[] arr = new byte[BUF_SIZE];
try { try {
try (ByteArrayOutputStream buf = new ByteArrayOutputStream()) { try (ByteArrayOutputStream buf = new ByteArrayOutputStream()) {
int numBytes; int numBytes;

View File

@ -25,6 +25,8 @@
package jdk.nashorn.tools; package jdk.nashorn.tools;
import static jdk.nashorn.internal.runtime.Source.sourceFor;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
@ -50,7 +52,6 @@ import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.ScriptEnvironment; import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.options.Options; import jdk.nashorn.internal.runtime.options.Options;
@ -244,7 +245,7 @@ public class Shell {
// For each file on the command line. // For each file on the command line.
for (final String fileName : files) { for (final String fileName : files) {
final FunctionNode functionNode = new Parser(env, new Source(fileName, new File(fileName)), errors).parse(); final FunctionNode functionNode = new Parser(env, sourceFor(fileName, new File(fileName)), errors).parse();
if (errors.getNumberOfErrors() != 0) { if (errors.getNumberOfErrors() != 0) {
return COMPILATION_ERROR; return COMPILATION_ERROR;
@ -302,7 +303,7 @@ public class Shell {
} }
final File file = new File(fileName); final File file = new File(fileName);
final ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global); final ScriptFunction script = context.compileScript(sourceFor(fileName, file), global);
if (script == null || errors.getNumberOfErrors() != 0) { if (script == null || errors.getNumberOfErrors() != 0) {
return COMPILATION_ERROR; return COMPILATION_ERROR;
} }
@ -405,7 +406,7 @@ public class Shell {
// initialize with "shell.js" script // initialize with "shell.js" script
try { try {
final Source source = new Source("<shell.js>", Shell.class.getResource("resources/shell.js")); final Source source = sourceFor("<shell.js>", Shell.class.getResource("resources/shell.js"));
context.eval(global, source.getString(), global, "<shell.js>", false); context.eval(global, source.getString(), global, "<shell.js>", false);
} catch (final Exception e) { } catch (final Exception e) {
err.println(e); err.println(e);

View File

@ -113,7 +113,7 @@ function findFunction(node) {
var getContextMethod = Context.class.getMethod("getContext") var getContextMethod = Context.class.getMethod("getContext")
var getEnvMethod = Context.class.getMethod("getEnv") var getEnvMethod = Context.class.getMethod("getEnv")
var SourceConstructor = Source.class.getConstructor(java.lang.String.class, java.lang.String.class) var sourceForMethod = Source.class.getMethod("sourceFor", java.lang.String.class, java.lang.String.class)
var ParserConstructor = Parser.class.getConstructor(ScriptEnvironment.class, Source.class, ErrorManager.class) var ParserConstructor = Parser.class.getConstructor(ScriptEnvironment.class, Source.class, ErrorManager.class)
var CompilerConstructor = Compiler.class.getConstructor(ScriptEnvironment.class) var CompilerConstructor = Compiler.class.getConstructor(ScriptEnvironment.class)
@ -121,7 +121,7 @@ var CompilerConstructor = Compiler.class.getConstructor(ScriptEnvironment.class)
// source code, returns a jdk.nashorn.internal.ir.FunctionNode object // source code, returns a jdk.nashorn.internal.ir.FunctionNode object
// representing it. // representing it.
function compile(source) { function compile(source) {
var source = SourceConstructor.newInstance("<no name>", source); var source = sourceForMethod.invoke(null, "<no name>", source);
var env = getEnvMethod.invoke(getContextMethod.invoke(null)) var env = getEnvMethod.invoke(getContextMethod.invoke(null))

View File

@ -25,6 +25,9 @@
package jdk.nashorn.internal.codegen; package jdk.nashorn.internal.codegen;
import static jdk.nashorn.internal.runtime.Source.sourceFor;
import static jdk.nashorn.internal.runtime.Source.readFully;
import java.io.File; import java.io.File;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
@ -32,7 +35,6 @@ import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.ErrorManager;
import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.options.Options; import jdk.nashorn.internal.runtime.options.Options;
import org.testng.Assert; import org.testng.Assert;
@ -151,7 +153,7 @@ public class CompilerTest {
final boolean globalChanged = (oldGlobal != global); final boolean globalChanged = (oldGlobal != global);
try { try {
final char[] buffer = Source.readFully(file); final char[] buffer = readFully(file);
boolean excluded = false; boolean excluded = false;
if (filter != null) { if (filter != null) {
@ -170,7 +172,7 @@ public class CompilerTest {
if (globalChanged) { if (globalChanged) {
Context.setGlobal(global); Context.setGlobal(global);
} }
final Source source = new Source(file.getAbsolutePath(), buffer); final Source source = sourceFor(file.getAbsolutePath(), buffer);
final ScriptFunction script = context.compileScript(source, global); final ScriptFunction script = context.compileScript(source, global);
if (script == null || context.getErrorManager().getNumberOfErrors() > 0) { if (script == null || context.getErrorManager().getNumberOfErrors() > 0) {
log("Compile failed: " + file.getAbsolutePath()); log("Compile failed: " + file.getAbsolutePath());

View File

@ -25,6 +25,9 @@
package jdk.nashorn.internal.parser; package jdk.nashorn.internal.parser;
import static jdk.nashorn.internal.runtime.Source.sourceFor;
import static jdk.nashorn.internal.runtime.Source.readFully;
import java.io.File; import java.io.File;
import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.ErrorManager;
@ -131,7 +134,7 @@ public class ParserTest {
} }
try { try {
final char[] buffer = Source.readFully(file); final char[] buffer = readFully(file);
boolean excluded = false; boolean excluded = false;
if (filter != null) { if (filter != null) {
final String content = new String(buffer); final String content = new String(buffer);
@ -153,7 +156,7 @@ public class ParserTest {
} }
}; };
errors.setLimit(0); errors.setLimit(0);
final Source source = new Source(file.getAbsolutePath(), buffer); final Source source = sourceFor(file.getAbsolutePath(), buffer);
new Parser(context.getEnv(), source, errors).parse(); new Parser(context.getEnv(), source, errors).parse();
if (errors.getNumberOfErrors() > 0) { if (errors.getNumberOfErrors() > 0) {
log("Parse failed: " + file.getAbsolutePath()); log("Parse failed: " + file.getAbsolutePath());

View File

@ -25,6 +25,7 @@
package jdk.nashorn.internal.runtime; package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.runtime.Source.sourceFor;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertTrue;
@ -107,7 +108,7 @@ public class ContextTest {
} }
private Object eval(final Context cx, final String name, final String code) { private Object eval(final Context cx, final String name, final String code) {
final Source source = new Source(name, code); final Source source = sourceFor(name, code);
final ScriptObject global = Context.getGlobal(); final ScriptObject global = Context.getGlobal();
final ScriptFunction func = cx.compileScript(source, global); final ScriptFunction func = cx.compileScript(source, global);
return func != null ? ScriptRuntime.apply(func, global) : null; return func != null ? ScriptRuntime.apply(func, global) : null;

View File

@ -0,0 +1,128 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.runtime;
import jdk.nashorn.api.scripting.URLReader;
import org.testng.annotations.Test;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.util.Arrays;
import static jdk.nashorn.internal.runtime.Source.sourceFor;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
/**
* Tests different Source representations.
*/
public class SourceTest {
final private static String SOURCE_NAME = "source.js";
final private static String SOURCE_STRING = "var x = 1;";
final private static char[] SOURCE_CHARS = SOURCE_STRING.toCharArray();
final private static String RESOURCE_PATH = "resources/load_test.js";
final private static File SOURCE_FILE = new File("build/test/classes/jdk/nashorn/internal/runtime/" + RESOURCE_PATH);
final private static URL SOURCE_URL = SourceTest.class.getResource(RESOURCE_PATH);
@Test
public void testStringSource() {
testSources(sourceFor(SOURCE_NAME, SOURCE_STRING), sourceFor(SOURCE_NAME, SOURCE_STRING));
testSources(sourceFor(SOURCE_NAME, SOURCE_STRING), sourceFor(SOURCE_NAME, SOURCE_CHARS));
}
@Test
public void testCharArraySource() {
testSources(sourceFor(SOURCE_NAME, SOURCE_CHARS), sourceFor(SOURCE_NAME, SOURCE_CHARS));
testSources(sourceFor(SOURCE_NAME, SOURCE_CHARS), sourceFor(SOURCE_NAME, SOURCE_STRING));
}
@Test
public void testURLSource() {
try {
testSources(sourceFor(SOURCE_NAME, SOURCE_URL), sourceFor(SOURCE_NAME, SOURCE_URL));
testSources(sourceFor(SOURCE_NAME, SOURCE_URL), sourceFor(SOURCE_NAME, new URLReader(SOURCE_URL)));
} catch (final IOException e) {
fail(e.toString());
}
}
@Test
public void testURLReaderSource() {
try {
System.err.println(SourceTest.class.getResource(""));
testSources(sourceFor(SOURCE_NAME, new URLReader(SOURCE_URL)), sourceFor(SOURCE_NAME, new URLReader(SOURCE_URL)));
testSources(sourceFor(SOURCE_NAME, new URLReader(SOURCE_URL)), sourceFor(SOURCE_NAME, SOURCE_URL));
} catch (final IOException e) {
fail(e.toString());
}
}
@Test
public void testReaderSource() {
try {
testSources(sourceFor(SOURCE_NAME, getReader(RESOURCE_PATH)), sourceFor(SOURCE_NAME, getReader(RESOURCE_PATH)));
} catch (final IOException e) {
fail(e.toString());
}
}
@Test
public void testFileSource() {
try {
testSources(sourceFor(SOURCE_NAME, SOURCE_FILE), sourceFor(SOURCE_NAME, SOURCE_FILE));
} catch (final IOException e) {
fail(e.toString());
}
}
private Reader getReader(final String path) {
return new InputStreamReader(SourceTest.class.getResourceAsStream(path));
}
private void testSources(final Source source1, final Source source2) {
final char[] chars1 = source1.getContent();
final char[] chars2 = source2.getContent();
final String str1 = source1.getString();
final String str2 = source2.getString();
assertTrue(Arrays.equals(chars1, chars2));
assertEquals(str1, str2);
assertEquals(source1.hashCode(), source2.hashCode());
assertTrue(source1.equals(source2));
// Test for immutability
Arrays.fill(source1.getContent(), (char)0);
Arrays.fill(source2.getContent(), (char)1);
assertTrue(Arrays.equals(source1.getContent(), str1.toCharArray()));
assertTrue(Arrays.equals(source1.getContent(), chars1));
assertTrue(Arrays.equals(source1.getContent(), source2.getContent()));
}
}

View File

@ -25,6 +25,7 @@
package jdk.nashorn.internal.test.framework; package jdk.nashorn.internal.test.framework;
import static jdk.nashorn.internal.runtime.Source.sourceFor;
import static jdk.nashorn.tools.Shell.COMPILATION_ERROR; import static jdk.nashorn.tools.Shell.COMPILATION_ERROR;
import static jdk.nashorn.tools.Shell.RUNTIME_ERROR; import static jdk.nashorn.tools.Shell.RUNTIME_ERROR;
import static jdk.nashorn.tools.Shell.SUCCESS; import static jdk.nashorn.tools.Shell.SUCCESS;
@ -39,7 +40,6 @@ import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.ErrorManager;
import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.options.Options; import jdk.nashorn.internal.runtime.options.Options;
/** /**
@ -125,7 +125,7 @@ public final class SharedContextEvaluator implements ScriptEvaluator {
continue; continue;
} }
final File file = new File(fileName); final File file = new File(fileName);
ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global); ScriptFunction script = context.compileScript(sourceFor(fileName, file.toURI().toURL()), global);
if (script == null || errors.getNumberOfErrors() != 0) { if (script == null || errors.getNumberOfErrors() != 0) {
return COMPILATION_ERROR; return COMPILATION_ERROR;

View File

@ -46,7 +46,7 @@ public final class SourceHelper {
} }
public static String readFully(final URL url) throws IOException { public static String readFully(final URL url) throws IOException {
return new Source(url.toString(), url).getString(); return Source.sourceFor(url.toString(), url).getString();
} }
public static String readFully(final Reader reader) throws IOException { public static String readFully(final Reader reader) throws IOException {