This commit is contained in:
Lana Steuck 2015-06-04 18:49:16 -07:00
commit 13a3f9e134
72 changed files with 773 additions and 198 deletions

View File

@ -72,14 +72,11 @@ after which you can view the generated documentation at dist/javadoc/index.html.
- Running tests - Running tests
Nashorn tests are TestNG based. Running tests requires downloading the Nashorn tests are TestNG based. Running tests requires downloading the
TestNG library and placing its jar file into the lib subdirectory: TestNG library and placing its jar file into the test/lib subdirectory. This is
done automatically when executing the "ant externals" command to get external
test suites (see below).
# download and install TestNG Once TestNG is properly installed, you can run the tests using:
wget http://testng.org/testng-x.y.z.zip
unzip testng-x.y.z.zip
cp testng-x.y.z/testng-x.y.z.jar test/lib/testng.jar
After that, you can run the tests using:
cd make cd make
ant clean test ant clean test

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- <!--
Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it This code is free software; you can redistribute it and/or modify it
@ -396,7 +396,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</target> </target>
<target name="check-testng" unless="testng.available"> <target name="check-testng" unless="testng.available">
<echo message="WARNING: TestNG not available, will not run tests. Please copy testng.jar under test/lib directory."/> <echo message="WARNING: TestNG not available, will not run tests. Please copy testng.jar under ${test.lib} directory."/>
</target> </target>
<!-- only to be invoked as dependency of "test" target --> <!-- only to be invoked as dependency of "test" target -->
@ -469,7 +469,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</testng> </testng>
</target> </target>
<target name="test" depends="javadoc, test-pessimistic, test-optimistic"/> <target name="test" depends="get-testng, javadoc, test-pessimistic, test-optimistic"/>
<target name="test-optimistic" depends="jar, -test-classes-all,-test-classes-single, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available"> <target name="test-optimistic" depends="jar, -test-classes-all,-test-classes-single, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<echo message="Running test suite in OPTIMISTIC mode..."/> <echo message="Running test suite in OPTIMISTIC mode..."/>
@ -499,7 +499,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<echo message="WARNING: Jemmy or JavaFX or TestNG not available, will not run tests. Please copy testng.jar, JemmyCore.jar, JemmyFX.jar, JemmyAWTInput.jar under test${file.separator}lib directory. And make sure you have jfxrt.jar in ${java.home}${file.separator}lib${file.separator}ext dir."/> <echo message="WARNING: Jemmy or JavaFX or TestNG not available, will not run tests. Please copy testng.jar, JemmyCore.jar, JemmyFX.jar, JemmyAWTInput.jar under test${file.separator}lib directory. And make sure you have jfxrt.jar in ${java.home}${file.separator}lib${file.separator}ext dir."/>
</target> </target>
<target name="testjfx" depends="jar, check-jemmy.jfx.testng, compile-test" if="jemmy.jfx.testng.available"> <target name="testjfx" depends="jar, get-testng, check-jemmy.jfx.testng, compile-test" if="jemmy.jfx.testng.available">
<fileset id="test.classes" dir="${build.test.classes.dir}"> <fileset id="test.classes" dir="${build.test.classes.dir}">
<include name="**/framework/*Test.class"/> <include name="**/framework/*Test.class"/>
</fileset> </fileset>
@ -527,7 +527,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</testng> </testng>
</target> </target>
<target name="testmarkdown" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available"> <target name="testmarkdown" depends="jar, get-testng, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<fileset id="test.classes" dir="${build.test.classes.dir}"> <fileset id="test.classes" dir="${build.test.classes.dir}">
<include name="**/framework/*Test.class"/> <include name="**/framework/*Test.class"/>
</fileset> </fileset>
@ -546,7 +546,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</testng> </testng>
</target> </target>
<target name="test262" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available"> <target name="test262" depends="jar, get-testng, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<fileset id="test.classes" dir="${build.test.classes.dir}"> <fileset id="test.classes" dir="${build.test.classes.dir}">
<include name="**/framework/*Test.class"/> <include name="**/framework/*Test.class"/>
</fileset> </fileset>
@ -570,7 +570,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<target name="test262parallel" depends="test262-parallel"/> <target name="test262parallel" depends="test262-parallel"/>
<target name="test262-parallel" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available"> <target name="test262-parallel" depends="jar, get-testng, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<!-- use just build.test.classes.dir to avoid referring to TestNG --> <!-- use just build.test.classes.dir to avoid referring to TestNG -->
<java classname="${parallel.test.runner}" dir="${basedir}" fork="true"> <java classname="${parallel.test.runner}" dir="${basedir}" fork="true">
<jvmarg line="${boot.class.path}"/> <jvmarg line="${boot.class.path}"/>
@ -589,7 +589,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<target name="testparallel" depends="test-parallel"/> <target name="testparallel" depends="test-parallel"/>
<target name="test-parallel" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available"> <target name="test-parallel" depends="jar, get-testng, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<!-- use just build.test.classes.dir to avoid referring to TestNG --> <!-- use just build.test.classes.dir to avoid referring to TestNG -->
<java classname="${parallel.test.runner}" dir="${basedir}" <java classname="${parallel.test.runner}" dir="${basedir}"
failonerror="true" failonerror="true"
@ -694,7 +694,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</target> </target>
<!-- get all external test scripts --> <!-- get all external test scripts -->
<target name="externals" depends="init, check-external-tests, get-test262, get-octane, get-sunspider"> <target name="externals" depends="init, check-external-tests, get-test262, get-octane, get-sunspider, get-testng">
<!-- make external test dir --> <!-- make external test dir -->
<mkdir dir="${test.external.dir}"/> <mkdir dir="${test.external.dir}"/>
@ -719,8 +719,8 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<!-- showdown --> <!-- showdown -->
<mkdir dir="${test.external.dir}/showdown"/> <mkdir dir="${test.external.dir}/showdown"/>
<get src="https://raw.github.com/coreyti/showdown/master/src/showdown.js" dest="${test.external.dir}/showdown" skipexisting="true" ignoreerrors="true"/> <get src="https://raw.githubusercontent.com/showdownjs/showdown/0.5.4/src/showdown.js" dest="${test.external.dir}/showdown" skipexisting="true" ignoreerrors="true"/>
<get src="https://raw.github.com/coreyti/showdown/master/src/extensions/table.js" dest="${test.external.dir}/showdown" skipexisting="true" ignoreerrors="true"/> <get src="https://raw.githubusercontent.com/showdownjs/showdown/0.5.4/src/extensions/table.js" dest="${test.external.dir}/showdown" skipexisting="true" ignoreerrors="true"/>
</target> </target>
@ -730,12 +730,20 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<!-- run all perf tests --> <!-- run all perf tests -->
<target name="perf" depends="externals, update-externals, sunspider, octane"/> <target name="perf" depends="externals, update-externals, sunspider, octane"/>
<!-- run all tests --> <!-- download and install testng.jar -->
<target name="exit-if-no-testng" depends="init, check-testng" unless="${testng.available}"> <target name="get-testng" depends="prepare" unless="testng.available">
<fail message="Exiting.."/> <get src="http://testng.org/testng-6.8.zip" dest="${test.lib}" skipexisting="true" ignoreerrors="true"/>
<unzip src="${test.lib}${file.separator}testng-6.8.zip" dest="${test.lib}">
<patternset>
<include name="testng-6.8/testng-6.8.jar"/>
</patternset>
</unzip>
<move file="${test.lib}${file.separator}testng-6.8${file.separator}testng-6.8.jar" tofile="${test.lib}${file.separator}testng.jar"/>
<delete dir="${test.lib}${file.separator}testng-6.8"/>
</target> </target>
<target name="alltests" depends="exit-if-no-testng, externals, update-externals, test, test262parallel, perf"/> <!-- run all tests -->
<target name="alltests" depends="get-testng, externals, update-externals, test, test262parallel, testmarkdown, perf"/>
<import file="build-benchmark.xml"/> <import file="build-benchmark.xml"/>

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -77,8 +77,11 @@ fxshell.jar = ${dist.dir}/nashornfx.jar
# configuration for java flight recorder # configuration for java flight recorder
run.test.jvmargs.jfr=-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=${build.dir},stackdepth=128 run.test.jvmargs.jfr=-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=${build.dir},stackdepth=128
# test library location
test.lib=${basedir}${file.separator}test${file.separator}lib
# jars refererred # jars refererred
file.reference.testng.jar=test/lib/testng.jar file.reference.testng.jar=${test.lib}${file.separator}testng.jar
# Set testng verbose level # Set testng verbose level
# From TestNG docs: "the verbosity level (0 to 10 where 10 is most detailed) # From TestNG docs: "the verbosity level (0 to 10 where 10 is most detailed)
@ -243,9 +246,9 @@ testjfx-test-sys-prop.test.js.framework=\
-fx \ -fx \
${test.script.dir}${file.separator}jfx.js ${test.script.dir}${file.separator}jfx.js
file.reference.jemmyfx.jar=test${file.separator}lib${file.separator}JemmyFX.jar file.reference.jemmyfx.jar=${test.lib}${file.separator}JemmyFX.jar
file.reference.jemmycore.jar=test${file.separator}lib${file.separator}JemmyCore.jar file.reference.jemmycore.jar=${test.lib}${file.separator}JemmyCore.jar
file.reference.jemmyawtinput.jar=test${file.separator}lib${file.separator}JemmyAWTInput.jar file.reference.jemmyawtinput.jar=${test.lib}${file.separator}JemmyAWTInput.jar
file.reference.jfxrt.jar=${java.home}${file.separator}lib${file.separator}ext${file.separator}jfxrt.jar file.reference.jfxrt.jar=${java.home}${file.separator}lib${file.separator}ext${file.separator}jfxrt.jar
testjfx.run.test.classpath=\ testjfx.run.test.classpath=\
${file.reference.jemmyfx.jar}${path.separator}\ ${file.reference.jemmyfx.jar}${path.separator}\

View File

@ -39,6 +39,7 @@
var Class = Java.type("java.lang.Class"); var Class = Java.type("java.lang.Class");
var System = Java.type("java.lang.System"); var System = Java.type("java.lang.System");
var Thread = Java.type("java.lang.Thread");
var File = Java.type("java.io.File"); var File = Java.type("java.io.File");
var JarFile = Java.type("java.util.jar.JarFile"); var JarFile = Java.type("java.util.jar.JarFile");
var Modifier = Java.type("java.lang.reflect.Modifier"); var Modifier = Java.type("java.lang.reflect.Modifier");
@ -58,6 +59,10 @@ function findNashorn() {
function analyzeClass(cls) { function analyzeClass(cls) {
var methods = cls.getDeclaredMethods(); var methods = cls.getDeclaredMethods();
for each (var method in methods) { for each (var method in methods) {
var methodModifiers = method.modifiers;
if (Modifier.isAbstract(methodModifiers) || Modifier.isNative(methodModifiers)) {
continue;
}
// this requires -parameters option when compiling java sources // this requires -parameters option when compiling java sources
var params = method.parameters; var params = method.parameters;
for each (var p in params) { for each (var p in params) {
@ -73,6 +78,8 @@ function analyzeClass(cls) {
} }
var jarFile = findNashorn(); var jarFile = findNashorn();
var ctxtLoader = Thread.currentThread().contextClassLoader;
// load each class and use reflection to analyze each Class // load each class and use reflection to analyze each Class
new JarFile(jarFile).stream().forEach( new JarFile(jarFile).stream().forEach(
function(entry) { function(entry) {
@ -80,8 +87,15 @@ new JarFile(jarFile).stream().forEach(
if (name.endsWith(".class")) { if (name.endsWith(".class")) {
var clsName = name.substring(0, name.lastIndexOf('.class')); var clsName = name.substring(0, name.lastIndexOf('.class'));
clsName = clsName.replace(/\//g, '.'); clsName = clsName.replace(/\//g, '.');
var cls = Class.forName(clsName); try {
// don't initialize to avoid for possible initialization errors
var cls = Class.forName(clsName, false, ctxtLoader);
analyzeClass(cls); analyzeClass(cls);
} catch (e) {
// print exception and continue analysis for other classes
print("Failed to analyze " + clsName);
e.printStackTrace();
}
} }
} }
) )

View File

@ -354,8 +354,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
} }
}, CREATE_GLOBAL_ACC_CTXT); }, CREATE_GLOBAL_ACC_CTXT);
nashornContext.initGlobal(newGlobal, this); nashornContext.initGlobal(newGlobal, this, ctxt);
newGlobal.setScriptContext(ctxt);
return newGlobal; return newGlobal;
} }
@ -404,7 +403,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
return evalImpl(script, ctxt, getNashornGlobalFrom(ctxt)); return evalImpl(script, ctxt, getNashornGlobalFrom(ctxt));
} }
private static Object evalImpl(final Context.MultiGlobalCompiledScript mgcs, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException { private Object evalImpl(final Context.MultiGlobalCompiledScript mgcs, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
final Global oldGlobal = Context.getGlobal(); final Global oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != ctxtGlobal); final boolean globalChanged = (oldGlobal != ctxtGlobal);
try { try {
@ -413,8 +412,13 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
} }
final ScriptFunction script = mgcs.getFunction(ctxtGlobal); final ScriptFunction script = mgcs.getFunction(ctxtGlobal);
final ScriptContext oldCtxt = ctxtGlobal.getScriptContext();
ctxtGlobal.setScriptContext(ctxt); ctxtGlobal.setScriptContext(ctxt);
try {
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal)); return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
} finally {
ctxtGlobal.setScriptContext(oldCtxt);
}
} catch (final Exception e) { } catch (final Exception e) {
throwAsScriptException(e, ctxtGlobal); throwAsScriptException(e, ctxtGlobal);
throw new AssertionError("should not reach here"); throw new AssertionError("should not reach here");
@ -425,7 +429,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
} }
} }
private static Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException { private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
if (script == null) { if (script == null) {
return null; return null;
} }
@ -436,8 +440,13 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
Context.setGlobal(ctxtGlobal); Context.setGlobal(ctxtGlobal);
} }
final ScriptContext oldCtxt = ctxtGlobal.getScriptContext();
ctxtGlobal.setScriptContext(ctxt); ctxtGlobal.setScriptContext(ctxt);
try {
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal)); return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
} finally {
ctxtGlobal.setScriptContext(oldCtxt);
}
} catch (final Exception e) { } catch (final Exception e) {
throwAsScriptException(e, ctxtGlobal); throwAsScriptException(e, ctxtGlobal);
throw new AssertionError("should not reach here"); throw new AssertionError("should not reach here");

View File

@ -47,6 +47,7 @@ import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.ConsString; import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ECMAException; import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.JSONListAdapter;
import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptObject;
@ -72,6 +73,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
private final ScriptObject sobj; private final ScriptObject sobj;
private final Global global; private final Global global;
private final boolean strict; private final boolean strict;
private final boolean jsonCompatible;
@Override @Override
public boolean equals(final Object other) { public boolean equals(final Object other) {
@ -110,9 +112,9 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
} }
if (sobj instanceof ScriptFunction) { if (sobj instanceof ScriptFunction) {
final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args; final Object[] modArgs = globalChanged? wrapArrayLikeMe(args, oldGlobal) : args;
final Object self = globalChanged? wrap(thiz, oldGlobal) : thiz; final Object self = globalChanged? wrapLikeMe(thiz, oldGlobal) : thiz;
return wrap(ScriptRuntime.apply((ScriptFunction)sobj, unwrap(self, global), unwrapArray(modArgs, global)), global); return wrapLikeMe(ScriptRuntime.apply((ScriptFunction)sobj, unwrap(self, global), unwrapArray(modArgs, global)));
} }
throw new RuntimeException("not a function: " + toString()); throw new RuntimeException("not a function: " + toString());
@ -140,8 +142,8 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
} }
if (sobj instanceof ScriptFunction) { if (sobj instanceof ScriptFunction) {
final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args; final Object[] modArgs = globalChanged? wrapArrayLikeMe(args, oldGlobal) : args;
return wrap(ScriptRuntime.construct((ScriptFunction)sobj, unwrapArray(modArgs, global)), global); return wrapLikeMe(ScriptRuntime.construct((ScriptFunction)sobj, unwrapArray(modArgs, global)));
} }
throw new RuntimeException("not a constructor: " + toString()); throw new RuntimeException("not a constructor: " + toString());
@ -170,7 +172,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
return Context.getContext(); return Context.getContext();
} }
}, GET_CONTEXT_ACC_CTXT); }, GET_CONTEXT_ACC_CTXT);
return wrap(context.eval(global, s, sobj, null, false), global); return wrapLikeMe(context.eval(global, s, sobj, null, false));
} }
}); });
} }
@ -193,8 +195,8 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
final Object val = sobj.get(functionName); final Object val = sobj.get(functionName);
if (val instanceof ScriptFunction) { if (val instanceof ScriptFunction) {
final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args; final Object[] modArgs = globalChanged? wrapArrayLikeMe(args, oldGlobal) : args;
return wrap(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global); return wrapLikeMe(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)));
} else if (val instanceof JSObject && ((JSObject)val).isFunction()) { } else if (val instanceof JSObject && ((JSObject)val).isFunction()) {
return ((JSObject)val).call(sobj, args); return ((JSObject)val).call(sobj, args);
} }
@ -218,7 +220,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
Objects.requireNonNull(name); Objects.requireNonNull(name);
return inGlobal(new Callable<Object>() { return inGlobal(new Callable<Object>() {
@Override public Object call() { @Override public Object call() {
return wrap(sobj.get(name), global); return wrapLikeMe(sobj.get(name));
} }
}); });
} }
@ -227,7 +229,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
public Object getSlot(final int index) { public Object getSlot(final int index) {
return inGlobal(new Callable<Object>() { return inGlobal(new Callable<Object>() {
@Override public Object call() { @Override public Object call() {
return wrap(sobj.get(index), global); return wrapLikeMe(sobj.get(index));
} }
}); });
} }
@ -368,7 +370,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
while (iter.hasNext()) { while (iter.hasNext()) {
final String key = iter.next(); final String key = iter.next();
final Object value = translateUndefined(wrap(sobj.get(key), global)); final Object value = translateUndefined(wrapLikeMe(sobj.get(key)));
entries.add(new AbstractMap.SimpleImmutableEntry<>(key, value)); entries.add(new AbstractMap.SimpleImmutableEntry<>(key, value));
} }
@ -382,7 +384,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
checkKey(key); checkKey(key);
return inGlobal(new Callable<Object>() { return inGlobal(new Callable<Object>() {
@Override public Object call() { @Override public Object call() {
return translateUndefined(wrap(sobj.get(key), global)); return translateUndefined(wrapLikeMe(sobj.get(key)));
} }
}); });
} }
@ -419,8 +421,8 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
final boolean globalChanged = (oldGlobal != global); final boolean globalChanged = (oldGlobal != global);
return inGlobal(new Callable<Object>() { return inGlobal(new Callable<Object>() {
@Override public Object call() { @Override public Object call() {
final Object modValue = globalChanged? wrap(value, oldGlobal) : value; final Object modValue = globalChanged? wrapLikeMe(value, oldGlobal) : value;
return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global), strict), global)); return translateUndefined(wrapLikeMe(sobj.put(key, unwrap(modValue, global), strict)));
} }
}); });
} }
@ -434,7 +436,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
@Override public Object call() { @Override public Object call() {
for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) { for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
final Object value = entry.getValue(); final Object value = entry.getValue();
final Object modValue = globalChanged? wrap(value, oldGlobal) : value; final Object modValue = globalChanged? wrapLikeMe(value, oldGlobal) : value;
final String key = entry.getKey(); final String key = entry.getKey();
checkKey(key); checkKey(key);
sobj.set(key, unwrap(modValue, global), getCallSiteFlags()); sobj.set(key, unwrap(modValue, global), getCallSiteFlags());
@ -449,7 +451,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
checkKey(key); checkKey(key);
return inGlobal(new Callable<Object>() { return inGlobal(new Callable<Object>() {
@Override public Object call() { @Override public Object call() {
return translateUndefined(wrap(sobj.remove(key, strict), global)); return translateUndefined(wrapLikeMe(sobj.remove(key, strict)));
} }
}); });
} }
@ -486,7 +488,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
final Iterator<Object> iter = sobj.valueIterator(); final Iterator<Object> iter = sobj.valueIterator();
while (iter.hasNext()) { while (iter.hasNext()) {
values.add(translateUndefined(wrap(iter.next(), global))); values.add(translateUndefined(wrapLikeMe(iter.next())));
} }
return Collections.unmodifiableList(values); return Collections.unmodifiableList(values);
@ -503,7 +505,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
public Object getProto() { public Object getProto() {
return inGlobal(new Callable<Object>() { return inGlobal(new Callable<Object>() {
@Override public Object call() { @Override public Object call() {
return wrap(sobj.getProto(), global); return wrapLikeMe(sobj.getProto());
} }
}); });
} }
@ -532,7 +534,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
public Object getOwnPropertyDescriptor(final String key) { public Object getOwnPropertyDescriptor(final String key) {
return inGlobal(new Callable<Object>() { return inGlobal(new Callable<Object>() {
@Override public Object call() { @Override public Object call() {
return wrap(sobj.getOwnPropertyDescriptor(key), global); return wrapLikeMe(sobj.getOwnPropertyDescriptor(key));
} }
}); });
} }
@ -661,15 +663,75 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
* @return wrapped/converted object * @return wrapped/converted object
*/ */
public static Object wrap(final Object obj, final Object homeGlobal) { public static Object wrap(final Object obj, final Object homeGlobal) {
if(obj instanceof ScriptObject) { return wrap(obj, homeGlobal, false);
return homeGlobal instanceof Global ? new ScriptObjectMirror((ScriptObject)obj, (Global)homeGlobal) : obj;
} }
if(obj instanceof ConsString) {
/**
* Make a script object mirror on given object if needed. Also converts ConsString instances to Strings. The
* created wrapper will implement the Java {@code List} interface if {@code obj} is a JavaScript
* {@code Array} object; this is compatible with Java JSON libraries expectations. Arrays retrieved through its
* properties (transitively) will also implement the list interface.
*
* @param obj object to be wrapped/converted
* @param homeGlobal global to which this object belongs. Not used for ConsStrings.
* @return wrapped/converted object
*/
public static Object wrapAsJSONCompatible(final Object obj, final Object homeGlobal) {
return wrap(obj, homeGlobal, true);
}
/**
* Make a script object mirror on given object if needed. Also converts ConsString instances to Strings.
*
* @param obj object to be wrapped/converted
* @param homeGlobal global to which this object belongs. Not used for ConsStrings.
* @param jsonCompatible if true, the created wrapper will implement the Java {@code List} interface if
* {@code obj} is a JavaScript {@code Array} object. Arrays retrieved through its properties (transitively)
* will also implement the list interface.
* @return wrapped/converted object
*/
private static Object wrap(final Object obj, final Object homeGlobal, final boolean jsonCompatible) {
if(obj instanceof ScriptObject) {
if (!(homeGlobal instanceof Global)) {
return obj;
}
final ScriptObject sobj = (ScriptObject)obj;
final Global global = (Global)homeGlobal;
final ScriptObjectMirror mirror = new ScriptObjectMirror(sobj, global, jsonCompatible);
if (jsonCompatible && sobj.isArray()) {
return new JSONListAdapter(mirror, global);
}
return mirror;
} else if(obj instanceof ConsString) {
return obj.toString(); return obj.toString();
} else if (jsonCompatible && obj instanceof ScriptObjectMirror) {
// Since choosing JSON compatible representation is an explicit decision on user's part, if we're asked to
// wrap a mirror that was not JSON compatible, explicitly create its compatible counterpart following the
// principle of least surprise.
return ((ScriptObjectMirror)obj).asJSONCompatible();
} }
return obj; return obj;
} }
/**
* Wraps the passed object with the same jsonCompatible flag as this mirror.
* @param obj the object
* @param homeGlobal the object's home global.
* @return a wrapper for the object.
*/
private Object wrapLikeMe(final Object obj, final Object homeGlobal) {
return wrap(obj, homeGlobal, jsonCompatible);
}
/**
* Wraps the passed object with the same home global and jsonCompatible flag as this mirror.
* @param obj the object
* @return a wrapper for the object.
*/
private Object wrapLikeMe(final Object obj) {
return wrapLikeMe(obj, global);
}
/** /**
* Unwrap a script object mirror if needed. * Unwrap a script object mirror if needed.
* *
@ -681,6 +743,8 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
if (obj instanceof ScriptObjectMirror) { if (obj instanceof ScriptObjectMirror) {
final ScriptObjectMirror mirror = (ScriptObjectMirror)obj; final ScriptObjectMirror mirror = (ScriptObjectMirror)obj;
return (mirror.global == homeGlobal)? mirror.sobj : obj; return (mirror.global == homeGlobal)? mirror.sobj : obj;
} else if (obj instanceof JSONListAdapter) {
return ((JSONListAdapter)obj).unwrap(homeGlobal);
} }
return obj; return obj;
@ -694,6 +758,10 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
* @return wrapped array * @return wrapped array
*/ */
public static Object[] wrapArray(final Object[] args, final Object homeGlobal) { public static Object[] wrapArray(final Object[] args, final Object homeGlobal) {
return wrapArray(args, homeGlobal, false);
}
private static Object[] wrapArray(final Object[] args, final Object homeGlobal, final boolean jsonCompatible) {
if (args == null || args.length == 0) { if (args == null || args.length == 0) {
return args; return args;
} }
@ -701,12 +769,16 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
final Object[] newArgs = new Object[args.length]; final Object[] newArgs = new Object[args.length];
int index = 0; int index = 0;
for (final Object obj : args) { for (final Object obj : args) {
newArgs[index] = wrap(obj, homeGlobal); newArgs[index] = wrap(obj, homeGlobal, jsonCompatible);
index++; index++;
} }
return newArgs; return newArgs;
} }
private Object[] wrapArrayLikeMe(final Object[] args, final Object homeGlobal) {
return wrapArray(args, homeGlobal, jsonCompatible);
}
/** /**
* Unwrap an array of script object mirrors if needed. * Unwrap an array of script object mirrors if needed.
* *
@ -748,12 +820,17 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
// package-privates below this. // package-privates below this.
ScriptObjectMirror(final ScriptObject sobj, final Global global) { ScriptObjectMirror(final ScriptObject sobj, final Global global) {
this(sobj, global, false);
}
private ScriptObjectMirror(final ScriptObject sobj, final Global global, final boolean jsonCompatible) {
assert sobj != null : "ScriptObjectMirror on null!"; assert sobj != null : "ScriptObjectMirror on null!";
assert global != null : "home Global is null"; assert global != null : "home Global is null";
this.sobj = sobj; this.sobj = sobj;
this.global = global; this.global = global;
this.strict = global.isStrictContext(); this.strict = global.isStrictContext();
this.jsonCompatible = jsonCompatible;
} }
// accessors for script engine // accessors for script engine
@ -838,4 +915,11 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
} }
}); });
} }
private ScriptObjectMirror asJSONCompatible() {
if (this.jsonCompatible) {
return this;
}
return new ScriptObjectMirror(sobj, global, true);
}
} }

View File

@ -53,7 +53,7 @@ final class ArrayAccessTreeImpl extends ExpressionTreeImpl implements ArrayAcces
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitArrayAccess(this, data); return visitor.visitArrayAccess(this, data);
} }
} }

View File

@ -47,7 +47,7 @@ final class ArrayLiteralTreeImpl extends ExpressionTreeImpl
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitArrayLiteral(this, data); return visitor.visitArrayLiteral(this, data);
} }
} }

View File

@ -55,7 +55,7 @@ final class AssignmentTreeImpl extends ExpressionTreeImpl implements AssignmentT
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitAssignment(this, data); return visitor.visitAssignment(this, data);
} }
} }

View File

@ -55,7 +55,7 @@ class BinaryTreeImpl extends ExpressionTreeImpl implements BinaryTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitBinary(this, data); return visitor.visitBinary(this, data);
} }
} }

View File

@ -53,7 +53,7 @@ final class BlockTreeImpl extends StatementTreeImpl implements BlockTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitBlock(this, data); return visitor.visitBlock(this, data);
} }
} }

View File

@ -46,7 +46,7 @@ final class BreakTreeImpl extends StatementTreeImpl implements BreakTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitBreak(this, data); return visitor.visitBreak(this, data);
} }
} }

View File

@ -56,7 +56,7 @@ final class CaseTreeImpl extends TreeImpl implements CaseTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitCase(this, data); return visitor.visitCase(this, data);
} }
} }

View File

@ -63,7 +63,7 @@ final class CatchTreeImpl extends TreeImpl implements CatchTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitCatch(this, data); return visitor.visitCatch(this, data);
} }
} }

View File

@ -67,7 +67,7 @@ final class CompilationUnitTreeImpl extends TreeImpl
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitCompilationUnit(this, data); return visitor.visitCompilationUnit(this, data);
} }
} }

View File

@ -57,7 +57,7 @@ final class CompoundAssignmentTreeImpl extends ExpressionTreeImpl implements Com
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitCompoundAssignment(this, data); return visitor.visitCompoundAssignment(this, data);
} }
} }

View File

@ -61,7 +61,7 @@ final class ConditionalExpressionTreeImpl extends ExpressionTreeImpl implements
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitConditionalExpression(this, data); return visitor.visitConditionalExpression(this, data);
} }
} }

View File

@ -46,7 +46,7 @@ final class ContinueTreeImpl extends StatementTreeImpl implements ContinueTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitContinue(this, data); return visitor.visitContinue(this, data);
} }
} }

View File

@ -38,7 +38,7 @@ final class DebuggerTreeImpl extends StatementTreeImpl implements DebuggerTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitDebugger(this, data); return visitor.visitDebugger(this, data);
} }
} }

View File

@ -54,7 +54,7 @@ final class DoWhileLoopTreeImpl extends StatementTreeImpl implements DoWhileLoop
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitDoWhileLoop(this, data); return visitor.visitDoWhileLoop(this, data);
} }
} }

View File

@ -38,7 +38,7 @@ final class EmptyStatementTreeImpl extends StatementTreeImpl implements EmptySta
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitEmptyStatement(this, data); return visitor.visitEmptyStatement(this, data);
} }
} }

View File

@ -38,7 +38,7 @@ final class ErroneousTreeImpl extends ExpressionTreeImpl implements ErroneousTre
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitErroneous(this, data); return visitor.visitErroneous(this, data);
} }
} }

View File

@ -46,7 +46,7 @@ final class ExpressionStatementTreeImpl extends StatementTreeImpl implements Exp
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitExpressionStatement(this, data); return visitor.visitExpressionStatement(this, data);
} }
} }

View File

@ -71,7 +71,7 @@ final class ForInLoopTreeImpl extends StatementTreeImpl implements ForInLoopTree
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitForInLoop(this, data); return visitor.visitForInLoop(this, data);
} }
} }

View File

@ -72,7 +72,7 @@ final class ForLoopTreeImpl extends StatementTreeImpl implements ForLoopTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitForLoop(this, data); return visitor.visitForLoop(this, data);
} }
} }

View File

@ -55,7 +55,7 @@ class FunctionCallTreeImpl extends ExpressionTreeImpl implements FunctionCallTre
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitFunctionCall(this, data); return visitor.visitFunctionCall(this, data);
} }
} }

View File

@ -74,7 +74,7 @@ final class FunctionDeclarationTreeImpl extends StatementTreeImpl
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitFunctionDeclaration(this, data); return visitor.visitFunctionDeclaration(this, data);
} }
} }

View File

@ -79,7 +79,7 @@ final class FunctionExpressionTreeImpl extends ExpressionTreeImpl
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitFunctionExpression(this, data); return visitor.visitFunctionExpression(this, data);
} }
} }

View File

@ -47,7 +47,7 @@ final class IdentifierTreeImpl extends ExpressionTreeImpl implements IdentifierT
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitIdentifier(this, data); return visitor.visitIdentifier(this, data);
} }
} }

View File

@ -63,7 +63,7 @@ final class IfTreeImpl extends StatementTreeImpl implements IfTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitIf(this, data); return visitor.visitIf(this, data);
} }
} }

View File

@ -52,7 +52,7 @@ final class InstanceOfTreeImpl extends BinaryTreeImpl implements InstanceOfTree
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitInstanceOf(this, data); return visitor.visitInstanceOf(this, data);
} }
} }

View File

@ -54,7 +54,7 @@ final class LabeledStatementTreeImpl extends StatementTreeImpl
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitLabeledStatement(this, data); return visitor.visitLabeledStatement(this, data);
} }
} }

View File

@ -35,12 +35,12 @@ final class LineMapImpl implements LineMap {
} }
@Override @Override
public long getLineNumber(long pos) { public long getLineNumber(final long pos) {
return source.getLine((int)pos); return source.getLine((int)pos);
} }
@Override @Override
public long getColumnNumber(long pos) { public long getColumnNumber(final long pos) {
return source.getColumn((int)pos); return source.getColumn((int)pos);
} }
} }

View File

@ -61,7 +61,7 @@ final class LiteralTreeImpl extends ExpressionTreeImpl implements LiteralTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitLiteral(this, data); return visitor.visitLiteral(this, data);
} }
} }

View File

@ -53,7 +53,7 @@ final class MemberSelectTreeImpl extends ExpressionTreeImpl
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitMemberSelect(this, data); return visitor.visitMemberSelect(this, data);
} }
} }

View File

@ -47,7 +47,7 @@ final class NewTreeImpl extends ExpressionTreeImpl implements NewTree {
} }
@Override @Override
public <R, D> R accept(TreeVisitor<R, D> visitor, D data) { public <R, D> R accept(final TreeVisitor<R, D> visitor, final D data) {
return visitor.visitNew(this, data); return visitor.visitNew(this, data);
} }
} }

View File

@ -47,7 +47,7 @@ final class ObjectLiteralTreeImpl extends ExpressionTreeImpl
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitObjectLiteral(this, data); return visitor.visitObjectLiteral(this, data);
} }
} }

View File

@ -70,7 +70,7 @@ final class PropertyTreeImpl extends TreeImpl implements PropertyTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitProperty(this, data); return visitor.visitProperty(this, data);
} }
} }

View File

@ -56,7 +56,7 @@ final class RegExpLiteralTreeImpl extends ExpressionTreeImpl
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitRegExpLiteral(this, data); return visitor.visitRegExpLiteral(this, data);
} }
} }

View File

@ -46,7 +46,7 @@ final class ReturnTreeImpl extends StatementTreeImpl implements ReturnTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitReturn(this, data); return visitor.visitReturn(this, data);
} }
} }

View File

@ -48,28 +48,28 @@ package jdk.nashorn.api.tree;
*/ */
public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> { public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
@Override @Override
public R visitAssignment(AssignmentTree node, P r) { public R visitAssignment(final AssignmentTree node, final P r) {
node.getVariable().accept(this, r); node.getVariable().accept(this, r);
node.getExpression().accept(this, r); node.getExpression().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitCompoundAssignment(CompoundAssignmentTree node, P r) { public R visitCompoundAssignment(final CompoundAssignmentTree node, final P r) {
node.getVariable().accept(this, r); node.getVariable().accept(this, r);
node.getExpression().accept(this, r); node.getExpression().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitBinary(BinaryTree node, P r) { public R visitBinary(final BinaryTree node, final P r) {
node.getLeftOperand().accept(this, r); node.getLeftOperand().accept(this, r);
node.getRightOperand().accept(this, r); node.getRightOperand().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitBlock(BlockTree node, P r) { public R visitBlock(final BlockTree node, final P r) {
node.getStatements().forEach((tree) -> { node.getStatements().forEach((tree) -> {
tree.accept(this, r); tree.accept(this, r);
}); });
@ -77,12 +77,12 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitBreak(BreakTree node, P r) { public R visitBreak(final BreakTree node, final P r) {
return null; return null;
} }
@Override @Override
public R visitCase(CaseTree node, P r) { public R visitCase(final CaseTree node, final P r) {
final Tree caseVal = node.getExpression(); final Tree caseVal = node.getExpression();
if (caseVal != null) { if (caseVal != null) {
caseVal.accept(this, r); caseVal.accept(this, r);
@ -95,7 +95,7 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitCatch(CatchTree node, P r) { public R visitCatch(final CatchTree node, final P r) {
final Tree cond = node.getCondition(); final Tree cond = node.getCondition();
if (cond != null) { if (cond != null) {
cond.accept(this, r); cond.accept(this, r);
@ -106,7 +106,7 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitConditionalExpression(ConditionalExpressionTree node, P r) { public R visitConditionalExpression(final ConditionalExpressionTree node, final P r) {
node.getCondition().accept(this, r); node.getCondition().accept(this, r);
node.getTrueExpression().accept(this, r); node.getTrueExpression().accept(this, r);
node.getFalseExpression().accept(this, r); node.getFalseExpression().accept(this, r);
@ -114,35 +114,35 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitContinue(ContinueTree node, P r) { public R visitContinue(final ContinueTree node, final P r) {
return null; return null;
} }
@Override @Override
public R visitDebugger(DebuggerTree node, P r) { public R visitDebugger(final DebuggerTree node, final P r) {
return null; return null;
} }
@Override @Override
public R visitDoWhileLoop(DoWhileLoopTree node, P r) { public R visitDoWhileLoop(final DoWhileLoopTree node, final P r) {
node.getStatement().accept(this, r); node.getStatement().accept(this, r);
node.getCondition().accept(this, r); node.getCondition().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitErroneous(ErroneousTree node, P r) { public R visitErroneous(final ErroneousTree node, final P r) {
return null; return null;
} }
@Override @Override
public R visitExpressionStatement(ExpressionStatementTree node, P r) { public R visitExpressionStatement(final ExpressionStatementTree node, final P r) {
node.getExpression().accept(this, r); node.getExpression().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitForLoop(ForLoopTree node, P r) { public R visitForLoop(final ForLoopTree node, final P r) {
final Tree init = node.getInitializer(); final Tree init = node.getInitializer();
if (init != null) { if (init != null) {
init.accept(this, r); init.accept(this, r);
@ -163,7 +163,7 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitForInLoop(ForInLoopTree node, P r) { public R visitForInLoop(final ForInLoopTree node, final P r) {
node.getVariable().accept(this, r); node.getVariable().accept(this, r);
node.getExpression().accept(this, r); node.getExpression().accept(this, r);
final StatementTree stat = node.getStatement(); final StatementTree stat = node.getStatement();
@ -174,7 +174,7 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitFunctionCall(FunctionCallTree node, P r) { public R visitFunctionCall(final FunctionCallTree node, final P r) {
node.getFunctionSelect().accept(this, r); node.getFunctionSelect().accept(this, r);
node.getArguments().forEach((tree) -> { node.getArguments().forEach((tree) -> {
tree.accept(this, r); tree.accept(this, r);
@ -183,7 +183,7 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitFunctionDeclaration(FunctionDeclarationTree node, P r) { public R visitFunctionDeclaration(final FunctionDeclarationTree node, final P r) {
node.getParameters().forEach((tree) -> { node.getParameters().forEach((tree) -> {
tree.accept(this, r); tree.accept(this, r);
}); });
@ -192,7 +192,7 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitFunctionExpression(FunctionExpressionTree node, P r) { public R visitFunctionExpression(final FunctionExpressionTree node, final P r) {
node.getParameters().forEach((tree) -> { node.getParameters().forEach((tree) -> {
tree.accept(this, r); tree.accept(this, r);
}); });
@ -201,12 +201,12 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitIdentifier(IdentifierTree node, P r) { public R visitIdentifier(final IdentifierTree node, final P r) {
return null; return null;
} }
@Override @Override
public R visitIf(IfTree node, P r) { public R visitIf(final IfTree node, final P r) {
node.getCondition().accept(this, r); node.getCondition().accept(this, r);
node.getThenStatement().accept(this, r); node.getThenStatement().accept(this, r);
final Tree elseStat = node.getElseStatement(); final Tree elseStat = node.getElseStatement();
@ -217,14 +217,14 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitArrayAccess(ArrayAccessTree node, P r) { public R visitArrayAccess(final ArrayAccessTree node, final P r) {
node.getExpression().accept(this, r); node.getExpression().accept(this, r);
node.getIndex().accept(this, r); node.getIndex().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitArrayLiteral(ArrayLiteralTree node, P r) { public R visitArrayLiteral(final ArrayLiteralTree node, final P r) {
node.getElements().stream().filter((tree) -> (tree != null)).forEach((tree) -> { node.getElements().stream().filter((tree) -> (tree != null)).forEach((tree) -> {
tree.accept(this, r); tree.accept(this, r);
}); });
@ -232,24 +232,24 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitLabeledStatement(LabeledStatementTree node, P r) { public R visitLabeledStatement(final LabeledStatementTree node, final P r) {
node.getStatement().accept(this, r); node.getStatement().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitLiteral(LiteralTree node, P r) { public R visitLiteral(final LiteralTree node, final P r) {
return null; return null;
} }
@Override @Override
public R visitParenthesized(ParenthesizedTree node, P r) { public R visitParenthesized(final ParenthesizedTree node, final P r) {
node.getExpression().accept(this, r); node.getExpression().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitReturn(ReturnTree node, P r) { public R visitReturn(final ReturnTree node, final P r) {
final Tree retExpr = node.getExpression(); final Tree retExpr = node.getExpression();
if (retExpr != null) { if (retExpr != null) {
retExpr.accept(this, r); retExpr.accept(this, r);
@ -258,19 +258,19 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitMemberSelect(MemberSelectTree node, P r) { public R visitMemberSelect(final MemberSelectTree node, final P r) {
node.getExpression().accept(this, r); node.getExpression().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitNew(NewTree node, P r) { public R visitNew(final NewTree node, final P r) {
node.getConstructorExpression().accept(this, r); node.getConstructorExpression().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitObjectLiteral(ObjectLiteralTree node, P r) { public R visitObjectLiteral(final ObjectLiteralTree node, final P r) {
node.getProperties().forEach((tree) -> { node.getProperties().forEach((tree) -> {
tree.accept(this, r); tree.accept(this, r);
}); });
@ -278,7 +278,7 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitProperty(PropertyTree node, P r) { public R visitProperty(final PropertyTree node, final P r) {
FunctionExpressionTree getter = node.getGetter(); FunctionExpressionTree getter = node.getGetter();
if (getter != null) { if (getter != null) {
getter.accept(this, r); getter.accept(this, r);
@ -301,17 +301,17 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitRegExpLiteral(RegExpLiteralTree node, P r) { public R visitRegExpLiteral(final RegExpLiteralTree node, final P r) {
return null; return null;
} }
@Override @Override
public R visitEmptyStatement(EmptyStatementTree node, P r) { public R visitEmptyStatement(final EmptyStatementTree node, final P r) {
return null; return null;
} }
@Override @Override
public R visitSwitch(SwitchTree node, P r) { public R visitSwitch(final SwitchTree node, final P r) {
node.getExpression().accept(this, r); node.getExpression().accept(this, r);
node.getCases().forEach((tree) -> { node.getCases().forEach((tree) -> {
tree.accept(this, r); tree.accept(this, r);
@ -320,13 +320,13 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitThrow(ThrowTree node, P r) { public R visitThrow(final ThrowTree node, final P r) {
node.getExpression().accept(this, r); node.getExpression().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitCompilationUnit(CompilationUnitTree node, P r) { public R visitCompilationUnit(final CompilationUnitTree node, final P r) {
node.getSourceElements().forEach((tree) -> { node.getSourceElements().forEach((tree) -> {
tree.accept(this, r); tree.accept(this, r);
}); });
@ -334,7 +334,7 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitTry(TryTree node, P r) { public R visitTry(final TryTree node, final P r) {
node.getBlock().accept(this, r); node.getBlock().accept(this, r);
node.getCatches().forEach((tree) -> { node.getCatches().forEach((tree) -> {
tree.accept(this, r); tree.accept(this, r);
@ -348,20 +348,20 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitInstanceOf(InstanceOfTree node, P r) { public R visitInstanceOf(final InstanceOfTree node, final P r) {
node.getType().accept(this, r); node.getType().accept(this, r);
node.getExpression().accept(this, r); node.getExpression().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitUnary(UnaryTree node, P r) { public R visitUnary(final UnaryTree node, final P r) {
node.getExpression().accept(this, r); node.getExpression().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitVariable(VariableTree node, P r) { public R visitVariable(final VariableTree node, final P r) {
if (node.getInitializer() != null) { if (node.getInitializer() != null) {
node.getInitializer().accept(this, r); node.getInitializer().accept(this, r);
} }
@ -369,21 +369,21 @@ public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
} }
@Override @Override
public R visitWhileLoop(WhileLoopTree node, P r) { public R visitWhileLoop(final WhileLoopTree node, final P r) {
node.getCondition().accept(this, r); node.getCondition().accept(this, r);
node.getStatement().accept(this, r); node.getStatement().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitWith(WithTree node, P r) { public R visitWith(final WithTree node, final P r) {
node.getScope().accept(this, r); node.getScope().accept(this, r);
node.getStatement().accept(this, r); node.getStatement().accept(this, r);
return null; return null;
} }
@Override @Override
public R visitUnknown(Tree node, P r) { public R visitUnknown(final Tree node, final P r) {
// unknown in ECMAScript 5.1 edition // unknown in ECMAScript 5.1 edition
throw new UnknownTreeException(node, r); throw new UnknownTreeException(node, r);
} }

View File

@ -55,7 +55,7 @@ final class SwitchTreeImpl extends StatementTreeImpl implements SwitchTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitSwitch(this, data); return visitor.visitSwitch(this, data);
} }
} }

View File

@ -45,7 +45,7 @@ final class ThrowTreeImpl extends StatementTreeImpl implements ThrowTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitThrow(this, data); return visitor.visitThrow(this, data);
} }
} }

View File

@ -47,7 +47,7 @@ abstract class TreeImpl implements Tree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitUnknown(this, data); return visitor.visitUnknown(this, data);
} }

View File

@ -63,7 +63,7 @@ final class TryTreeImpl extends StatementTreeImpl implements TryTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitTry(this, data); return visitor.visitTry(this, data);
} }
} }

View File

@ -47,7 +47,7 @@ class UnaryTreeImpl extends ExpressionTreeImpl implements UnaryTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitUnary(this, data); return visitor.visitUnary(this, data);
} }
} }

View File

@ -53,7 +53,7 @@ final class VariableTreeImpl extends StatementTreeImpl implements VariableTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitVariable(this, data); return visitor.visitVariable(this, data);
} }
} }

View File

@ -54,7 +54,7 @@ final class WhileLoopTreeImpl extends StatementTreeImpl implements WhileLoopTree
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitWhileLoop(this, data); return visitor.visitWhileLoop(this, data);
} }
} }

View File

@ -53,7 +53,7 @@ final class WithTreeImpl extends StatementTreeImpl implements WithTree {
} }
@Override @Override
public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
return visitor.visitWith(this, data); return visitor.visitWith(this, data);
} }
} }

View File

@ -363,7 +363,7 @@ enum CompilationPhase {
//partial code generation //partial code generation
final FunctionNode newFunctionNode = transformFunction(fn, new ReplaceCompileUnits() { final FunctionNode newFunctionNode = transformFunction(fn, new ReplaceCompileUnits() {
@Override @Override
CompileUnit getReplacement(CompileUnit original) { CompileUnit getReplacement(final CompileUnit original) {
return map.get(original); return map.get(original);
} }

View File

@ -567,7 +567,7 @@ public final class OptimisticTypesPersistence {
final MessageDigest digest = MessageDigest.getInstance("SHA-1"); final MessageDigest digest = MessageDigest.getInstance("SHA-1");
Files.walk(nashorn).forEach(new Consumer<Path>() { Files.walk(nashorn).forEach(new Consumer<Path>() {
@Override @Override
public void accept(Path p) { public void accept(final Path p) {
// take only the .class resources. // take only the .class resources.
if (Files.isRegularFile(p) && p.toString().endsWith(".class")) { if (Files.isRegularFile(p) && p.toString().endsWith(".class")) {
try { try {

View File

@ -102,7 +102,7 @@ final class SplitIntoFunctions extends NodeVisitor<BlockLexicalContext> {
public SplitIntoFunctions(final Compiler compiler) { public SplitIntoFunctions(final Compiler compiler) {
super(new BlockLexicalContext() { super(new BlockLexicalContext() {
@Override @Override
protected Block afterSetStatements(Block block) { protected Block afterSetStatements(final Block block) {
for(Statement stmt: block.getStatements()) { for(Statement stmt: block.getStatements()) {
assert !(stmt instanceof SplitNode); assert !(stmt instanceof SplitNode);
} }
@ -305,7 +305,7 @@ final class SplitIntoFunctions extends NodeVisitor<BlockLexicalContext> {
} }
@Override @Override
public boolean enterVarNode(VarNode varNode) { public boolean enterVarNode(final VarNode varNode) {
if (!inSplitNode()) { if (!inSplitNode()) {
return super.enterVarNode(varNode); return super.enterVarNode(varNode);
} }

View File

@ -54,7 +54,7 @@ public final class SplitReturn extends Statement {
} }
@Override @Override
public void toString(StringBuilder sb, boolean printType) { public void toString(final StringBuilder sb, final boolean printType) {
sb.append(":splitreturn;"); sb.append(":splitreturn;");
} }

View File

@ -122,7 +122,7 @@ public final class TryNode extends LexicalContextStatement implements JoinPredec
* @param visitor IR navigating visitor. * @param visitor IR navigating visitor.
*/ */
@Override @Override
public Node accept(final LexicalContext lc, NodeVisitor<? extends LexicalContext> visitor) { public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterTryNode(this)) { if (visitor.enterTryNode(this)) {
// Need to do finallybody first for termination analysis. TODO still necessary? // Need to do finallybody first for termination analysis. TODO still necessary?
final Block newFinallyBody = finallyBody == null ? null : (Block)finallyBody.accept(visitor); final Block newFinallyBody = finallyBody == null ? null : (Block)finallyBody.accept(visitor);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -1109,7 +1109,7 @@ public final class NashornTextifier extends Printer {
} }
final String ex = catches.get(node); final String ex = catches.get(node);
if (ex != null) { if (ex != null) {
sb.append("*** CATCH: ").append(ex).append(" ***\n"); sb.append("*** CATCH: ").append(ex).append(" ***\\l");
} }
sb.append(c); sb.append(c);
sb.append("\"]\n"); sb.append("\"]\n");

View File

@ -928,9 +928,11 @@ public final class Global extends ScriptObject implements Scope {
private final Context context; private final Context context;
// current ScriptContext to use - can be null. // current ScriptContext to use - can be null.
private ScriptContext scontext; private ThreadLocal<ScriptContext> scontext;
// current ScriptEngine associated - can be null. // current ScriptEngine associated - can be null.
private ScriptEngine engine; private ScriptEngine engine;
// initial ScriptContext - can be null
private volatile ScriptContext initscontext;
// ES6 global lexical scope. // ES6 global lexical scope.
private final LexicalScope lexicalScope; private final LexicalScope lexicalScope;
@ -940,10 +942,25 @@ public final class Global extends ScriptObject implements Scope {
/** /**
* Set the current script context * Set the current script context
* @param scontext script context * @param ctxt script context
*/ */
public void setScriptContext(final ScriptContext scontext) { public void setScriptContext(final ScriptContext ctxt) {
this.scontext = scontext; assert scontext != null;
scontext.set(ctxt);
}
/**
* Get the current script context
* @return current script context
*/
public ScriptContext getScriptContext() {
assert scontext != null;
return scontext.get();
}
private ScriptContext currentContext() {
final ScriptContext sc = scontext != null? scontext.get() : null;
return sc == null? initscontext : sc;
} }
@Override @Override
@ -1056,14 +1073,19 @@ public final class Global extends ScriptObject implements Scope {
* of the global scope object. * of the global scope object.
* *
* @param eng ScriptEngine to initialize * @param eng ScriptEngine to initialize
* @param ctxt ScriptContext to initialize
*/ */
public void initBuiltinObjects(final ScriptEngine eng) { public void initBuiltinObjects(final ScriptEngine eng, final ScriptContext ctxt) {
if (this.builtinObject != null) { if (this.builtinObject != null) {
// already initialized, just return // already initialized, just return
return; return;
} }
this.engine = eng; this.engine = eng;
this.initscontext = ctxt;
if (this.engine != null) {
this.scontext = new ThreadLocal<>();
}
init(eng); init(eng);
} }
@ -1392,7 +1414,7 @@ public final class Global extends ScriptObject implements Scope {
*/ */
public static Object __noSuchProperty__(final Object self, final Object name) { public static Object __noSuchProperty__(final Object self, final Object name) {
final Global global = Global.instance(); final Global global = Global.instance();
final ScriptContext sctxt = global.scontext; final ScriptContext sctxt = global.currentContext();
final String nameStr = name.toString(); final String nameStr = name.toString();
if (sctxt != null) { if (sctxt != null) {
@ -2737,8 +2759,9 @@ public final class Global extends ScriptObject implements Scope {
} }
private Object printImpl(final boolean newLine, final Object... objects) { private Object printImpl(final boolean newLine, final Object... objects) {
final ScriptContext sc = currentContext();
@SuppressWarnings("resource") @SuppressWarnings("resource")
final PrintWriter out = scontext != null? new PrintWriter(scontext.getWriter()) : getContext().getEnv().getOut(); final PrintWriter out = sc != null? new PrintWriter(sc.getWriter()) : getContext().getEnv().getOut();
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
for (final Object obj : objects) { for (final Object obj : objects) {

View File

@ -33,10 +33,12 @@ import java.lang.reflect.Array;
import java.util.Collection; import java.util.Collection;
import java.util.Deque; import java.util.Deque;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Queue; import java.util.Queue;
import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.support.TypeUtilities; import jdk.internal.dynalink.support.TypeUtilities;
import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Function; import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.objects.annotations.ScriptClass;
@ -656,4 +658,20 @@ public final class NativeJava {
public static Object _super(final Object self, final Object adapter) { public static Object _super(final Object self, final Object adapter) {
return Bootstrap.createSuperAdapter(adapter); return Bootstrap.createSuperAdapter(adapter);
} }
/**
* Returns an object that is compatible with Java JSON libraries expectations; namely, that if it itself, or any
* object transitively reachable through it is a JavaScript array, then such objects will be exposed as
* {@link JSObject} that also implements the {@link List} interface for exposing the array elements. An explicit
* API is required as otherwise Nashorn exposes all objects externally as {@link JSObject}s that also implement the
* {@link Map} interface instead. By using this method, arrays will be exposed as {@link List}s and all other
* objects as {@link Map}s.
* @param self not used
* @param obj the object to be exposed in a Java JSON library compatible manner.
* @return a wrapper around the object that will enforce Java JSON library compatible exposure.
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object asJSONCompatible(final Object self, final Object obj) {
return ScriptObjectMirror.wrapAsJSONCompatible(obj, Context.getGlobal());
}
} }

View File

@ -528,8 +528,9 @@ final class CompiledFunction {
final int fnParamCountNoCallee = fnParamCount - thisThisIndex; final int fnParamCountNoCallee = fnParamCount - thisThisIndex;
final int minParams = Math.min(csParamCount - 1, fnParamCountNoCallee); // callSiteType always has callee, so subtract 1 final int minParams = Math.min(csParamCount - 1, fnParamCountNoCallee); // callSiteType always has callee, so subtract 1
// We must match all incoming parameters, except "this". Starting from 1 to skip "this". // We must match all incoming parameters, including "this". "this" will usually be Object, but there
for(int i = 1; i < minParams; ++i) { // are exceptions, e.g. when calling functions with primitive "this" in strict mode or through call/apply.
for(int i = 0; i < minParams; ++i) {
final Type fnType = Type.typeFor(type.parameterType(i + thisThisIndex)); final Type fnType = Type.typeFor(type.parameterType(i + thisThisIndex));
final Type csType = csIsVarArg ? Type.OBJECT : Type.typeFor(other.parameterType(i + 1)); final Type csType = csIsVarArg ? Type.OBJECT : Type.typeFor(other.parameterType(i + 1));
if(!fnType.isEquivalentTo(csType)) { if(!fnType.isEquivalentTo(csType)) {

View File

@ -66,6 +66,7 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.logging.Level; import java.util.logging.Level;
import javax.script.ScriptContext;
import javax.script.ScriptEngine; import javax.script.ScriptEngine;
import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
@ -1095,16 +1096,17 @@ public final class Context {
* *
* @param global the global * @param global the global
* @param engine the associated ScriptEngine instance, can be null * @param engine the associated ScriptEngine instance, can be null
* @param ctxt the initial ScriptContext, can be null
* @return the initialized global scope object. * @return the initialized global scope object.
*/ */
public Global initGlobal(final Global global, final ScriptEngine engine) { public Global initGlobal(final Global global, final ScriptEngine engine, final ScriptContext ctxt) {
// Need only minimal global object, if we are just compiling. // Need only minimal global object, if we are just compiling.
if (!env._compile_only) { if (!env._compile_only) {
final Global oldGlobal = Context.getGlobal(); final Global oldGlobal = Context.getGlobal();
try { try {
Context.setGlobal(global); Context.setGlobal(global);
// initialize global scope with builtin global objects // initialize global scope with builtin global objects
global.initBuiltinObjects(engine); global.initBuiltinObjects(engine, ctxt);
} finally { } finally {
Context.setGlobal(oldGlobal); Context.setGlobal(oldGlobal);
} }
@ -1120,7 +1122,7 @@ public final class Context {
* @return the initialized global scope object. * @return the initialized global scope object.
*/ */
public Global initGlobal(final Global global) { public Global initGlobal(final Global global) {
return initGlobal(global, null); return initGlobal(global, null, null);
} }
/** /**

View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2015, 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 java.util.Collection;
import java.util.List;
import java.util.Set;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.objects.Global;
/**
* A {@link ListAdapter} that also implements {@link JSObject}. Named {@code JSONListAdapter} as it is used as a
* {@code JSObject} implementing the {@link List} interface, which is the expected interface to be implemented by
* JSON-parsed arrays when they are handled in Java. We aren't implementing {@link JSObject} on {@link ListAdapter}
* directly since that'd have implications for other uses of list adapter (e.g. interferences of JSObject default
* value calculation vs. List's {@code toString()} etc.)
*/
public final class JSONListAdapter extends ListAdapter implements JSObject {
/**
* Creates a new JSON list adapter.
* @param obj the underlying object being exposed as a list.
* @param global the home global of the underlying object.
*/
public JSONListAdapter(final JSObject obj, final Global global) {
super(obj, global);
}
/**
* Unwraps this adapter into its underlying non-JSObject representative.
* @param homeGlobal the home global for unwrapping
* @return either the unwrapped object or this if it should not be unwrapped in the specified global.
*/
public Object unwrap(final Object homeGlobal) {
final Object unwrapped = ScriptObjectMirror.unwrap(obj, homeGlobal);
return unwrapped != obj ? unwrapped : this;
}
@Override
public Object call(final Object thiz, final Object... args) {
return obj.call(thiz, args);
}
@Override
public Object newObject(final Object... args) {
return obj.newObject(args);
}
@Override
public Object eval(final String s) {
return obj.eval(s);
}
@Override
public Object getMember(final String name) {
return obj.getMember(name);
}
@Override
public Object getSlot(final int index) {
return obj.getSlot(index);
}
@Override
public boolean hasMember(final String name) {
return obj.hasMember(name);
}
@Override
public boolean hasSlot(final int slot) {
return obj.hasSlot(slot);
}
@Override
public void removeMember(final String name) {
obj.removeMember(name);
}
@Override
public void setMember(final String name, final Object value) {
obj.setMember(name, value);
}
@Override
public void setSlot(final int index, final Object value) {
obj.setSlot(index, value);
}
@Override
public Set<String> keySet() {
return obj.keySet();
}
@Override
public Collection<Object> values() {
return obj.values();
}
@Override
public boolean isInstance(final Object instance) {
return obj.isInstance(instance);
}
@Override
public boolean isInstanceOf(final Object clazz) {
return obj.isInstanceOf(clazz);
}
@Override
public String getClassName() {
return obj.getClassName();
}
@Override
public boolean isFunction() {
return obj.isFunction();
}
@Override
public boolean isStrictFunction() {
return obj.isStrictFunction();
}
@Override
public boolean isArray() {
return obj.isArray();
}
@Override @Deprecated
public double toNumber() {
return obj.toNumber();
}
@Override
public Object getDefaultValue(Class<?> hint) throws UnsupportedOperationException {
return obj.getDefaultValue(hint);
}
}

View File

@ -52,7 +52,7 @@ import jdk.nashorn.internal.runtime.linker.Bootstrap;
* operations respectively, while {@link #addLast(Object)} and {@link #removeLast()} will translate to {@code push} and * operations respectively, while {@link #addLast(Object)} and {@link #removeLast()} will translate to {@code push} and
* {@code pop}. * {@code pop}.
*/ */
public final class ListAdapter extends AbstractList<Object> implements RandomAccess, Deque<Object> { public class ListAdapter extends AbstractList<Object> implements RandomAccess, Deque<Object> {
// Invoker creator for methods that add to the start or end of the list: PUSH and UNSHIFT. Takes fn, this, and value, returns void. // Invoker creator for methods that add to the start or end of the list: PUSH and UNSHIFT. Takes fn, this, and value, returns void.
private static final Callable<MethodHandle> ADD_INVOKER_CREATOR = invokerCreator(void.class, Object.class, JSObject.class, Object.class); private static final Callable<MethodHandle> ADD_INVOKER_CREATOR = invokerCreator(void.class, Object.class, JSObject.class, Object.class);
@ -78,21 +78,17 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
private static final Callable<MethodHandle> SPLICE_REMOVE_INVOKER_CREATOR = invokerCreator(void.class, Object.class, JSObject.class, int.class, int.class); private static final Callable<MethodHandle> SPLICE_REMOVE_INVOKER_CREATOR = invokerCreator(void.class, Object.class, JSObject.class, int.class, int.class);
/** wrapped object */ /** wrapped object */
private final JSObject obj; final JSObject obj;
private final Global global; private final Global global;
// allow subclasses only in this package // allow subclasses only in this package
ListAdapter(final JSObject obj) { ListAdapter(final JSObject obj, final Global global) {
this.obj = obj; if (global == null) {
this.global = getGlobalNonNull(); throw new IllegalStateException(ECMAErrors.getMessage("list.adapter.null.global"));
} }
private static Global getGlobalNonNull() { this.obj = obj;
final Global global = Context.getGlobal(); this.global = global;
if (global != null) {
return global;
}
throw new IllegalStateException(ECMAErrors.getMessage("list.adapter.null.global"));
} }
/** /**
@ -102,12 +98,13 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
* @return A ListAdapter wrapper object * @return A ListAdapter wrapper object
*/ */
public static ListAdapter create(final Object obj) { public static ListAdapter create(final Object obj) {
return new ListAdapter(getJSObject(obj)); final Global global = Context.getGlobal();
return new ListAdapter(getJSObject(obj, global), global);
} }
private static JSObject getJSObject(final Object obj) { private static JSObject getJSObject(final Object obj, final Global global) {
if (obj instanceof ScriptObject) { if (obj instanceof ScriptObject) {
return (JSObject)ScriptObjectMirror.wrap(obj, Context.getGlobal()); return (JSObject)ScriptObjectMirror.wrap(obj, global);
} else if (obj instanceof JSObject) { } else if (obj instanceof JSObject) {
return (JSObject)obj; return (JSObject)obj;
} }

View File

@ -137,7 +137,7 @@ public final class ScriptingFunctions {
final ScriptObject global = Context.getGlobal(); final ScriptObject global = Context.getGlobal();
// Set up initial process. // Set up initial process.
final ProcessBuilder processBuilder = new ProcessBuilder(tokenizeCommandLine(JSType.toString(string))); final ProcessBuilder processBuilder = new ProcessBuilder(tokenizeString(JSType.toString(string)));
// Current ENV property state. // Current ENV property state.
final Object env = global.get(ENV_NAME); final Object env = global.get(ENV_NAME);
@ -237,23 +237,22 @@ public final class ScriptingFunctions {
} }
/** /**
* Break an exec string into tokens, honoring quoted arguments and escaped * Break a string into tokens, honoring quoted arguments and escaped spaces.
* spaces.
* *
* @param execString a {@link String} with the command line to execute. * @param str a {@link String} to tokenize.
* @return a {@link List} of {@link String}s representing the tokens that * @return a {@link List} of {@link String}s representing the tokens that
* constitute the command line. * constitute the string.
* @throws IOException in case {@link StreamTokenizer#nextToken()} raises it. * @throws IOException in case {@link StreamTokenizer#nextToken()} raises it.
*/ */
public static List<String> tokenizeCommandLine(final String execString) throws IOException { public static List<String> tokenizeString(final String str) throws IOException {
final StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(execString)); final StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(str));
tokenizer.resetSyntax(); tokenizer.resetSyntax();
tokenizer.wordChars(0, 255); tokenizer.wordChars(0, 255);
tokenizer.whitespaceChars(0, ' '); tokenizer.whitespaceChars(0, ' ');
tokenizer.commentChar('#'); tokenizer.commentChar('#');
tokenizer.quoteChar('"'); tokenizer.quoteChar('"');
tokenizer.quoteChar('\''); tokenizer.quoteChar('\'');
final List<String> cmdList = new ArrayList<>(); final List<String> tokenList = new ArrayList<>();
final StringBuilder toAppend = new StringBuilder(); final StringBuilder toAppend = new StringBuilder();
while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) { while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) {
final String s = tokenizer.sval; final String s = tokenizer.sval;
@ -265,13 +264,13 @@ public final class ScriptingFunctions {
// omit trailing \, append space instead // omit trailing \, append space instead
toAppend.append(s.substring(0, s.length() - 1)).append(' '); toAppend.append(s.substring(0, s.length() - 1)).append(' ');
} else { } else {
cmdList.add(toAppend.append(s).toString()); tokenList.add(toAppend.append(s).toString());
toAppend.setLength(0); toAppend.setLength(0);
} }
} }
if (toAppend.length() != 0) { if (toAppend.length() != 0) {
cmdList.add(toAppend.toString()); tokenList.add(toAppend.toString());
} }
return cmdList; return tokenList;
} }
} }

View File

@ -934,14 +934,16 @@ public final class Source implements Loggable {
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) {
if (bytes.length > 3 && bytes[2] == 0 && bytes[3] == 0) {
start = 4;
cs = Charset.forName("UTF-32LE");
} else {
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) {
start = 4;
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");

View File

@ -246,7 +246,7 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
} }
@Override @Override
public MethodHandle filterInternalObjects(MethodHandle target) { public MethodHandle filterInternalObjects(final MethodHandle target) {
return linkerServices.filterInternalObjects(target); return linkerServices.filterInternalObjects(target);
} }
} }

View File

@ -0,0 +1,26 @@
###########################################################################
#
# Copyright (c) 2015, 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.
#
# 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.
#
###########################################################################
# No nashorn tests are on the problem list.

View File

@ -1,6 +1,11 @@
# This file identifies the root of the test-suite hierarchy. # This file identifies the root of the test-suite hierarchy.
# It also contains test-suite configuration information. # It also contains test-suite configuration information.
# DO NOT EDIT without first contacting jdk-regtest@sun.com.
# The list of keywords supported in the entire test suite # The list of keywords supported in the entire test suite
keys=2d dnd i18n keys=intermittent randomness
# Group definitions
groups=TEST.groups
# Minimum jtreg version
requiredVersion=4.1 b11

29
nashorn/test/TEST.groups Normal file
View File

@ -0,0 +1,29 @@
# Copyright (c) 2015, 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.
#
# 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.
#
# Tiered testing definitions
# No nashorn tests are tier 1.
tier1 =
# All nashorn tests are tier 2.
tier2 = src

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2015, 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.
*
* 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.
*/
/**
* JDK-8066220: Fuzzing bug: MethodHandle bug (Object,Object) != (boolean)Object
*
* @test
* @run
*/
function f() {}
// Call f with primitive this first, then as constructor
f.call(1);
new f();
// Same as above in strict mode
eval('"use strict"; function e() { print(typeof this); } e.call(1); new e();');

View File

@ -0,0 +1,2 @@
number
object

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2015, 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.api.scripting;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import org.testng.Assert;
import org.testng.annotations.Test;
public class JSONCompatibleTest {
/**
* Wrap a top-level array as a list.
*/
@Test
public void testWrapArray() throws ScriptException {
final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
final Object val = engine.eval("Java.asJSONCompatible([1, 2, 3])");
assertEquals(asList(val), Arrays.asList(1, 2, 3));
}
/**
* Wrap an embedded array as a list.
*/
@Test
public void testWrapObjectWithArray() throws ScriptException {
final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
final Object val = engine.eval("Java.asJSONCompatible({x: [1, 2, 3]})");
assertEquals(asList(asMap(val).get("x")), Arrays.asList(1, 2, 3));
}
/**
* Check it all works transitively several more levels down.
*/
@Test
public void testDeepWrapping() throws ScriptException {
final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
final Object val = engine.eval("Java.asJSONCompatible({x: [1, {y: [2, {z: [3]}]}, [4, 5]]})");
final Map<String, Object> root = asMap(val);
final List<Object> x = asList(root.get("x"));
assertEquals(x.get(0), 1);
final Map<String, Object> x1 = asMap(x.get(1));
final List<Object> y = asList(x1.get("y"));
assertEquals(y.get(0), 2);
final Map<String, Object> y1 = asMap(y.get(1));
assertEquals(asList(y1.get("z")), Arrays.asList(3));
assertEquals(asList(x.get(2)), Arrays.asList(4, 5));
}
/**
* Ensure that the old behaviour (every object is a Map) is unchanged.
*/
@Test
public void testNonWrapping() throws ScriptException {
final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
final Object val = engine.eval("({x: [1, {y: [2, {z: [3]}]}, [4, 5]]})");
final Map<String, Object> root = asMap(val);
final Map<String, Object> x = asMap(root.get("x"));
assertEquals(x.get("0"), 1);
final Map<String, Object> x1 = asMap(x.get("1"));
final Map<String, Object> y = asMap(x1.get("y"));
assertEquals(y.get("0"), 2);
final Map<String, Object> y1 = asMap(y.get("1"));
final Map<String, Object> z = asMap(y1.get("z"));
assertEquals(z.get("0"), 3);
final Map<String, Object> x2 = asMap(x.get("2"));
assertEquals(x2.get("0"), 4);
assertEquals(x2.get("1"), 5);
}
private static List<Object> asList(final Object obj) {
assertJSObject(obj);
Assert.assertTrue(obj instanceof List);
return (List)obj;
}
private static Map<String, Object> asMap(final Object obj) {
assertJSObject(obj);
Assert.assertTrue(obj instanceof Map);
return (Map)obj;
}
private static void assertJSObject(final Object obj) {
assertTrue(obj instanceof JSObject);
}
}

View File

@ -31,10 +31,12 @@ import static org.testng.Assert.fail;
import javax.script.Bindings; import javax.script.Bindings;
import javax.script.ScriptContext; import javax.script.ScriptContext;
import javax.script.ScriptEngine; import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager; import javax.script.ScriptEngineManager;
import javax.script.ScriptException; import javax.script.ScriptException;
import javax.script.SimpleBindings; import javax.script.SimpleBindings;
import javax.script.SimpleScriptContext; import javax.script.SimpleScriptContext;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.api.scripting.URLReader; import jdk.nashorn.api.scripting.URLReader;
import org.testng.Assert; import org.testng.Assert;
@ -778,4 +780,44 @@ public class ScopeTest {
throw new AssertionError("should have thrown NPE"); throw new AssertionError("should have thrown NPE");
} catch (NullPointerException npe5) {} } catch (NullPointerException npe5) {}
} }
public static class RecursiveEval {
private final ScriptEngineFactory factory = new NashornScriptEngineFactory();
private final ScriptEngine engine = factory.getScriptEngine();
private final Bindings engineBindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
public void program() throws ScriptException {
ScriptContext sc = new SimpleScriptContext();
Bindings global = new SimpleBindings();
sc.setBindings(global, ScriptContext.GLOBAL_SCOPE);
sc.setBindings(engineBindings, ScriptContext.ENGINE_SCOPE);
global.put("text", "programText");
String value = engine.eval("text", sc).toString();
Assert.assertEquals(value, "programText");
engine.put("program", this);
engine.eval("program.method()");
// eval again from here!
value = engine.eval("text", sc).toString();
Assert.assertEquals(value, "programText");
}
public void method() throws ScriptException {
// a context with a new global bindings, same engine bindings
final ScriptContext sc = new SimpleScriptContext();
final Bindings global = new SimpleBindings();
sc.setBindings(global, ScriptContext.GLOBAL_SCOPE);
sc.setBindings(engineBindings, ScriptContext.ENGINE_SCOPE);
global.put("text", "methodText");
String value = engine.eval("text", sc).toString();
Assert.assertEquals(value, "methodText");
}
}
// @bug 8081609: engine.eval call from a java method which
// was called from a previous engine.eval results in wrong
// ScriptContext being used.
@Test
public void recursiveEvalCallScriptContextTest() throws ScriptException {
new RecursiveEval().program();
}
} }

View File

@ -225,7 +225,7 @@ public final class TestFinder {
boolean explicitOptimistic = false; boolean explicitOptimistic = false;
String allContent = new String(Files.readAllBytes(testFile)); String allContent = new String(Files.readAllBytes(testFile));
Iterator<String> scanner = ScriptingFunctions.tokenizeCommandLine(allContent).iterator(); Iterator<String> scanner = ScriptingFunctions.tokenizeString(allContent).iterator();
while (scanner.hasNext()) { while (scanner.hasNext()) {
// TODO: Scan for /ref=file qualifiers, etc, to determine run // TODO: Scan for /ref=file qualifiers, etc, to determine run
// behavior // behavior