提交 55581a3b 编写于 作者: L lana

Merge

...@@ -72,14 +72,11 @@ after which you can view the generated documentation at dist/javadoc/index.html. ...@@ -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
......
<?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
...@@ -388,7 +388,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" { ...@@ -388,7 +388,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 -->
...@@ -460,7 +460,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" { ...@@ -460,7 +460,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..."/>
...@@ -490,7 +490,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" { ...@@ -490,7 +490,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>
...@@ -518,7 +518,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" { ...@@ -518,7 +518,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>
...@@ -537,7 +537,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" { ...@@ -537,7 +537,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>
...@@ -561,7 +561,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" { ...@@ -561,7 +561,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="${ext.class.path}"/> <jvmarg line="${ext.class.path}"/>
...@@ -580,7 +580,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" { ...@@ -580,7 +580,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"
...@@ -685,7 +685,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" { ...@@ -685,7 +685,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}"/>
...@@ -710,8 +710,8 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" { ...@@ -710,8 +710,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>
...@@ -721,12 +721,20 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" { ...@@ -721,12 +721,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"/>
......
# #
# 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 ...@@ -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)
...@@ -237,9 +240,9 @@ testjfx-test-sys-prop.test.js.framework=\ ...@@ -237,9 +240,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}\
......
# autoimports script requires -scripting mode
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* It is tedious to import Java classes used in a script. Sometimes it is easier
* use simple names of java classes and have a script auto import Java classes.
* You can load this script at the start of an interactive jjs session or at the
* start of your script. This script defines a __noSuchProperty__ hook to auto
* import Java classes as needed and when they are referred to for the first time
* in your script. You can also call the "autoimports" function to print script
* statements that you need to use in your script, i.e., have the function generate
* a script to import Java classes used by your script so far. After running your
* script, you can call autoimports to get the exact Java imports you need and replace
* the autoimports load with the generated import statements (to avoid costly init of
* the autoimports script).
*/
(function() {
var ArrayList = Java.type("java.util.ArrayList");
var HashMap = Java.type("java.util.HashMap");
var JarFile = Java.type("java.util.jar.JarFile");
var File = Java.type("java.io.File");
var Files = Java.type("java.nio.file.Files");
var FileSystems = Java.type("java.nio.file.FileSystems");
var System = Java.type("java.lang.System");
var URI = Java.type("java.net.URI");
// initialize a class to package map by iterating all
// classes available in the system by walking through "jrt fs"
var clsToPkg = new HashMap();
// locate rt.jar from sun.boot.class.path
function findRtJar() {
var paths = System.getProperty("sun.boot.class.path").split(File.pathSeparator);
for each (var p in paths) {
if (p.endsWith("rt.jar") && new File(p).exists()) {
return p;
}
}
}
function addToClsToPkg(c, p) {
if (clsToPkg.containsKey(c)) {
var val = clsToPkg.get(c);
if (val instanceof ArrayList) {
val.add(p);
} else {
var al = new ArrayList();
al.add(val);
al.add(p);
clsToPkg.put(c, al);
}
} else {
clsToPkg.put(c, p);
}
}
// handle collision and allow user to choose package
function getPkgOfCls(c) {
var val = clsToPkg.get(c);
if (val instanceof ArrayList) {
var count = 1;
print("Multiple matches for " + c + ", choose package:");
for each (var v in val) {
print(count + ". " + v);
count++;
}
var choice = parseInt(readLine());
if (isNaN(choice) || choice < 1 || choice > val.size()) {
print("invalid choice: " + choice);
return undefined;
}
return val.get(choice - 1);
} else {
return val;
}
}
var rtJar = findRtJar();
var stream = new JarFile(rtJar).stream();
try {
stream.forEach(
function(entry) {
var str = entry.name;
if (str.endsWith(".class")) {
if (str.startsWith("java") ||
str.startsWith("javax") ||
str.startsWith("org")) {
var lastIdx = str.lastIndexOf('/');
if (lastIdx != -1) {
var pkg = str.substring(0, lastIdx).replaceAll('/', '.');
var cls = str.substring(lastIdx + 1, str.lastIndexOf(".class"));
addToClsToPkg(cls, pkg);
}
}
}
});
} finally {
stream.close();
}
var imports = new ArrayList();
var global = this;
var oldNoSuchProp = global.__noSuchProperty__;
this.__noSuchProperty__ = function(name) {
'use strict';
if (clsToPkg.containsKey(name)) {
var pkg = getPkgOfCls(name);
if (pkg) {
var clsName = pkg + "." + name;
imports.add("var " + name + " = Java.type('" + clsName + "');");
return global[name] = Java.type(clsName);
}
} else if (typeof oldNoSuchProp == 'function') {
return oldNoSuchProp.call(this, name);
}
if (typeof this == 'undefined') {
throw new ReferenceError(name);
} else {
return undefined;
}
}
this.autoimports = function() {
for each (var im in imports) {
print(im);
}
}
})();
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Converting between #javascript Date and #java8 LocalDateTime with #nashorn
// JavaScript Date with current time
var d = new Date();
print(d);
// Java 8 java.time classes used
var Instant = java.time.Instant;
var LocalDateTime = java.time.LocalDateTime;
var ZoneId = java.time.ZoneId;
// Date.prototype.getTime
// getTime() method returns the numeric value corresponding to the time
// for the specified date according to universal time. The value returned
// by the getTime() method is the number of milliseconds since 1 January 1970 00:00:00 UTC.
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime
// Java Instant.ofEpochMilli to convert time in milliseconds to Instant object
// https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html#ofEpochMilli-long-
var instant = Instant.ofEpochMilli(d.getTime());
// Instant to LocalDateTime using LocalDateTime.ofInstant
// https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#ofInstant-java.time.Instant-java.time.ZoneId-
var ldt = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
print(ldt);
// converting a LocalDateTime to JavaScript Date
// convert LocalDateTime to Instant first
// https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#atZone-java.time.ZoneId-
var instant = ldt.atZone(ZoneId.systemDefault()).toInstant();
// instant to to epoch milliseconds
// https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html#toEpochMilli--
// and then to JavaScript Date from time in milliseconds
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date
var d1 = new Date(instant.toEpochMilli());
print(d1);
# exec script requires -scripting mode
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// The $EXEC builtin function can be used to run external commands:
$EXEC("ls")
$EXEC("ls -la")
// It can also be given a string to use as stdin:
$EXEC("cat", "Hello, world!")
// Additional arguments can be passed after the stdin argument, as an array of
// strings, or a sequence of varargs:
$EXEC("ls", "" /* no stdin */, "-l", "-a")
$EXEC("ls", "" /* no stdin */, ["-l", "-a"])
// Output of running external commands is returned from $EXEC:
print($EXEC("ls"))
// apply on $EXEC
print($EXEC.apply(this, ["ls"]));
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// script helpers to print meta info on Java instances and classes
// print instance methods info on a Java object or static methods info of a Java class
function methods(jobj) {
if (! Java.isJavaObject(jobj)) {
throw new TypeError("not a Java object");
}
var isStatic = Java.isType(jobj);
var obj = Object.bindProperties({}, jobj);
for each (var i in obj) {
if (Java.isJavaMethod(i)) {
var str = String(i);
var idx = str.indexOf(' ');
var overloaded = str.substring(0, idx).endsWith("OverloadedDynamicMethod");
var lastIdx = isStatic? str.lastIndexOf('] on') : str.lastIndexOf(']');
print(str.substring(idx + 1, lastIdx) + (overloaded? "*" : ""))
}
}
}
// print instance field names of a Java object or static field names of a Java class
function fields(jobj) {
if (! Java.isJavaObject(jobj)) {
throw new TypeError("not a Java object");
}
var obj = Object.bindProperties({}, jobj);
for (var i in obj) {
if (! Java.isJavaMethod(obj[i])) {
print(i);
}
}
}
undefined;
# usage: jjs secondssince.js
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Number of seconds elapsed since the specified Instance #nashorn #javascript #java
// Input date and time in ISO 8601 format
// Example: 2001-01-01T00:00:00Z for 1 Jan 2001, 0 GMT
var Instant = java.time.Instant;
var ChronoUnit = java.time.temporal.ChronoUnit;
print("Enter date time:");
var sec = Instant.parse(readLine()).
until(Instant.now(), ChronoUnit.SECONDS);
print(sec);
...@@ -99,10 +99,12 @@ import jdk.internal.dynalink.support.Lookup; ...@@ -99,10 +99,12 @@ import jdk.internal.dynalink.support.Lookup;
import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl; import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl;
/** /**
* The linker for {@link RelinkableCallSite} objects. Users of it (scripting frameworks and language runtimes) have to * The linker for {@link RelinkableCallSite} objects. Users of it (scripting
* create a linker using the {@link DynamicLinkerFactory} and invoke its link method from the invokedynamic bootstrap * frameworks and language runtimes) have to create a linker using the
* methods to set the target of all the call sites in the code they generate. Usual usage would be to create one class * {@link DynamicLinkerFactory} and invoke its link method from the invokedynamic
* per language runtime to contain one linker instance as: * bootstrap methods to set the target of all the call sites in the code they
* generate. Usual usage would be to create one class per language runtime to
* contain one linker instance as:
* *
* <pre> * <pre>
* class MyLanguageRuntime { * class MyLanguageRuntime {
...@@ -123,19 +125,27 @@ import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl; ...@@ -123,19 +125,27 @@ import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl;
* *
* Note how there are three components you will need to provide here: * Note how there are three components you will need to provide here:
* <ul> * <ul>
* <li>You're expected to provide a {@link GuardingDynamicLinker} for your own language. If your runtime doesn't *
* have its own language and/or object model (i.e. it's a generic scripting shell), you don't need to implement a * <li>You're expected to provide a {@link GuardingDynamicLinker} for your own
* dynamic linker; you would simply not invoke the {@code setPrioritizedLinker} method on the factory, or even better, * language. If your runtime doesn't have its own language and/or object model
* simply use {@link DefaultBootstrapper}.</li> * (i.e., it's a generic scripting shell), you don't need to implement a dynamic
* <li>The performance of the programs can depend on your choice of the class to represent call sites. The above * linker; you would simply not invoke the {@code setPrioritizedLinker} method
* example used {@link MonomorphicCallSite}, but you might want to use {@link ChainedCallSite} instead. You'll need to * on the factory, or even better, simply use {@link DefaultBootstrapper}.</li>
* experiment and decide what fits your language runtime the best. You can subclass either of these or roll your own if *
* you need to.</li> * <li>The performance of the programs can depend on your choice of the class to
* <li>You also need to provide {@link CallSiteDescriptor}s to your call sites. They are immutable objects that contain * represent call sites. The above example used {@link MonomorphicCallSite}, but
* all the information about the call site: the class performing the lookups, the name of the method being invoked, and * you might want to use {@link ChainedCallSite} instead. You'll need to
* the method signature. The library has a default {@link CallSiteDescriptorFactory} for descriptors that you can use, * experiment and decide what fits your language runtime the best. You can
* or you can create your own descriptor classes, especially if you need to add further information (values passed in * subclass either of these or roll your own if you need to.</li>
*
* <li>You also need to provide {@link CallSiteDescriptor}s to your call sites.
* They are immutable objects that contain all the information about the call
* site: the class performing the lookups, the name of the method being invoked,
* and the method signature. The library has a default {@link CallSiteDescriptorFactory}
* for descriptors that you can use, or you can create your own descriptor
* classes, especially if you need to add further information (values passed in
* additional parameters to the bootstrap method) to them.</li> * additional parameters to the bootstrap method) to them.</li>
*
* </ul> * </ul>
* *
* @author Attila Szegedi * @author Attila Szegedi
...@@ -176,11 +186,15 @@ public class DynamicLinker { ...@@ -176,11 +186,15 @@ public class DynamicLinker {
} }
/** /**
* Links an invokedynamic call site. It will install a method handle into the call site that invokes the relinking * Links an invokedynamic call site. It will install a method handle into
* mechanism of this linker. Next time the call site is invoked, it will be linked for the actual arguments it was * the call site that invokes the relinking mechanism of this linker. Next
* invoked with. * time the call site is invoked, it will be linked for the actual arguments
* it was invoked with.
* *
* @param <T> the particular subclass of {@link RelinkableCallSite} for
* which to create a link.
* @param callSite the call site to link. * @param callSite the call site to link.
*
* @return the callSite, for easy call chaining. * @return the callSite, for easy call chaining.
*/ */
public <T extends RelinkableCallSite> T link(final T callSite) { public <T extends RelinkableCallSite> T link(final T callSite) {
...@@ -189,10 +203,13 @@ public class DynamicLinker { ...@@ -189,10 +203,13 @@ public class DynamicLinker {
} }
/** /**
* Returns the object representing the lower level linker services of this class that are normally exposed to * Returns the object representing the lower level linker services of this
* individual language-specific linkers. While as a user of this class you normally only care about the * class that are normally exposed to individual language-specific linkers.
* {@link #link(RelinkableCallSite)} method, in certain circumstances you might want to use the lower level services * While as a user of this class you normally only care about the
* directly; either to lookup specific method handles, to access the type converters, and so on. * {@link #link(RelinkableCallSite)} method, in certain circumstances you
* might want to use the lower level services directly; either to lookup
* specific method handles, to access the type converters, and so on.
*
* @return the object representing the linker services of this class. * @return the object representing the linker services of this class.
*/ */
public LinkerServices getLinkerServices() { public LinkerServices getLinkerServices() {
...@@ -218,7 +235,9 @@ public class DynamicLinker { ...@@ -218,7 +235,9 @@ public class DynamicLinker {
* *
* @param callSite the call site itself * @param callSite the call site itself
* @param arguments arguments to the invocation * @param arguments arguments to the invocation
*
* @return return the method handle for the invocation * @return return the method handle for the invocation
*
* @throws Exception rethrows any exception thrown by the linkers * @throws Exception rethrows any exception thrown by the linkers
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
...@@ -272,11 +291,15 @@ public class DynamicLinker { ...@@ -272,11 +291,15 @@ public class DynamicLinker {
} }
/** /**
* Returns a stack trace element describing the location of the call site currently being linked on the current * Returns a stack trace element describing the location of the call site
* thread. The operation internally creates a Throwable object and inspects its stack trace, so it's potentially * currently being linked on the current thread. The operation internally
* expensive. The recommended usage for it is in writing diagnostics code. * creates a Throwable object and inspects its stack trace, so it's
* @return a stack trace element describing the location of the call site currently being linked, or null if it is * potentially expensive. The recommended usage for it is in writing
* not invoked while a call site is being linked. * diagnostics code.
*
* @return a stack trace element describing the location of the call site
* currently being linked, or null if it is not invoked while a call
* site is being linked.
*/ */
public static StackTraceElement getLinkedCallSiteLocation() { public static StackTraceElement getLinkedCallSiteLocation() {
final StackTraceElement[] trace = new Throwable().getStackTrace(); final StackTraceElement[] trace = new Throwable().getStackTrace();
...@@ -290,8 +313,10 @@ public class DynamicLinker { ...@@ -290,8 +313,10 @@ public class DynamicLinker {
} }
/** /**
* Deprecated because of not precise name. * Deprecated because of imprecise name.
*
* @deprecated Use {@link #getLinkedCallSiteLocation()} instead. * @deprecated Use {@link #getLinkedCallSiteLocation()} instead.
*
* @return see non-deprecated method * @return see non-deprecated method
*/ */
@Deprecated @Deprecated
...@@ -300,20 +325,26 @@ public class DynamicLinker { ...@@ -300,20 +325,26 @@ public class DynamicLinker {
} }
/** /**
* Returns true if the frame represents {@code MethodHandleNatives.linkCallSite()}, the frame immediately on top of * Returns {@code true} if the frame represents {@code MethodHandleNatives.linkCallSite()},
* the call site frame when the call site is being linked for the first time. * the frame immediately on top of the call site frame when the call site is
* being linked for the first time.
*
* @param frame the frame * @param frame the frame
* @return true if this frame represents {@code MethodHandleNatives.linkCallSite()} *
* @return {@code true} if this frame represents {@code MethodHandleNatives.linkCallSite()}.
*/ */
private static boolean isInitialLinkFrame(final StackTraceElement frame) { private static boolean isInitialLinkFrame(final StackTraceElement frame) {
return testFrame(frame, INITIAL_LINK_METHOD_NAME, INITIAL_LINK_CLASS_NAME); return testFrame(frame, INITIAL_LINK_METHOD_NAME, INITIAL_LINK_CLASS_NAME);
} }
/** /**
* Returns true if the frame represents {@code DynamicLinker.relink()}, the frame immediately on top of the call * Returns {@code true} if the frame represents {@code DynamicLinker.relink()},
* site frame when the call site is being relinked (linked for second and subsequent times). * the frame immediately on top of the call site frame when the call site is
* being relinked (linked for second and subsequent times).
*
* @param frame the frame * @param frame the frame
* @return true if this frame represents {@code DynamicLinker.relink()} *
* @return {@code true} if this frame represents {@code DynamicLinker.relink()}.
*/ */
private static boolean isRelinkFrame(final StackTraceElement frame) { private static boolean isRelinkFrame(final StackTraceElement frame) {
return testFrame(frame, RELINK_METHOD_NAME, CLASS_NAME); return testFrame(frame, RELINK_METHOD_NAME, CLASS_NAME);
......
...@@ -28,6 +28,7 @@ package jdk.nashorn.api.scripting; ...@@ -28,6 +28,7 @@ package jdk.nashorn.api.scripting;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import jdk.nashorn.internal.runtime.JSONListAdapter;
import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.JSType;
/** /**
...@@ -282,6 +283,8 @@ public abstract class AbstractJSObject implements JSObject { ...@@ -282,6 +283,8 @@ public abstract class AbstractJSObject implements JSObject {
public static Object getDefaultValue(final JSObject jsobj, final Class<?> hint) { public static Object getDefaultValue(final JSObject jsobj, final Class<?> hint) {
if (jsobj instanceof AbstractJSObject) { if (jsobj instanceof AbstractJSObject) {
return ((AbstractJSObject)jsobj).getDefaultValue(hint); return ((AbstractJSObject)jsobj).getDefaultValue(hint);
} else if (jsobj instanceof JSONListAdapter) {
return ((JSONListAdapter)jsobj).getDefaultValue(hint);
} }
return DefaultValueImpl.getDefaultValue(jsobj, hint); return DefaultValueImpl.getDefaultValue(jsobj, hint);
} }
......
...@@ -354,8 +354,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C ...@@ -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 ...@@ -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 ...@@ -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);
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal)); try {
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 ...@@ -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 ...@@ -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);
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal)); try {
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");
......
...@@ -178,8 +178,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory { ...@@ -178,8 +178,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* denies {@code RuntimePermission("nashorn.setConfig")} * denies {@code RuntimePermission("nashorn.setConfig")}
*/ */
public ScriptEngine getScriptEngine(final ClassFilter classFilter) { public ScriptEngine getScriptEngine(final ClassFilter classFilter) {
Objects.requireNonNull(classFilter); return newEngine(DEFAULT_OPTIONS, getAppClassLoader(), Objects.requireNonNull(classFilter));
return newEngine(DEFAULT_OPTIONS, getAppClassLoader(), classFilter);
} }
/** /**
...@@ -193,8 +192,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory { ...@@ -193,8 +192,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* denies {@code RuntimePermission("nashorn.setConfig")} * denies {@code RuntimePermission("nashorn.setConfig")}
*/ */
public ScriptEngine getScriptEngine(final String... args) { public ScriptEngine getScriptEngine(final String... args) {
Objects.requireNonNull(args); return newEngine(Objects.requireNonNull(args), getAppClassLoader(), null);
return newEngine(args, getAppClassLoader(), null);
} }
/** /**
...@@ -209,8 +207,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory { ...@@ -209,8 +207,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* denies {@code RuntimePermission("nashorn.setConfig")} * denies {@code RuntimePermission("nashorn.setConfig")}
*/ */
public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader) { public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader) {
Objects.requireNonNull(args); return newEngine(Objects.requireNonNull(args), appLoader, null);
return newEngine(args, appLoader, null);
} }
/** /**
...@@ -226,9 +223,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory { ...@@ -226,9 +223,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* denies {@code RuntimePermission("nashorn.setConfig")} * denies {@code RuntimePermission("nashorn.setConfig")}
*/ */
public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader, final ClassFilter classFilter) { public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader, final ClassFilter classFilter) {
Objects.requireNonNull(args); return newEngine(Objects.requireNonNull(args), appLoader, Objects.requireNonNull(classFilter));
Objects.requireNonNull(classFilter);
return newEngine(args, appLoader, classFilter);
} }
private ScriptEngine newEngine(final String[] args, final ClassLoader appLoader, final ClassFilter classFilter) { private ScriptEngine newEngine(final String[] args, final ClassLoader appLoader, final ClassFilter classFilter) {
......
...@@ -47,6 +47,7 @@ import jdk.nashorn.internal.objects.Global; ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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));
} }
}); });
} }
...@@ -193,8 +195,8 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -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 ...@@ -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 ...@@ -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));
} }
}); });
} }
...@@ -253,14 +255,12 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -253,14 +255,12 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
@Override @Override
public void removeMember(final String name) { public void removeMember(final String name) {
Objects.requireNonNull(name); remove(Objects.requireNonNull(name));
remove(name);
} }
@Override @Override
public void setMember(final String name, final Object value) { public void setMember(final String name, final Object value) {
Objects.requireNonNull(name); put(Objects.requireNonNull(name), value);
put(name, value);
} }
@Override @Override
...@@ -368,7 +368,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -368,7 +368,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 +382,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -382,7 +382,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,22 +419,22 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -419,22 +419,22 @@ 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)));
} }
}); });
} }
@Override @Override
public void putAll(final Map<? extends String, ? extends Object> map) { public void putAll(final Map<? extends String, ? extends Object> map) {
Objects.requireNonNull(map, "map is null"); Objects.requireNonNull(map);
final ScriptObject oldGlobal = Context.getGlobal(); final ScriptObject oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != global); final boolean globalChanged = (oldGlobal != global);
inGlobal(new Callable<Object>() { inGlobal(new Callable<Object>() {
@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 +449,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -449,7 +449,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 +486,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -486,7 +486,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 +503,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -503,7 +503,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 +532,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -532,7 +532,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 +661,75 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -661,15 +661,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) {
return wrap(obj, homeGlobal, false);
}
/**
* 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(obj instanceof ScriptObject) {
return homeGlobal instanceof Global ? new ScriptObjectMirror((ScriptObject)obj, (Global)homeGlobal) : obj; if (!(homeGlobal instanceof Global)) {
} return obj;
if(obj instanceof ConsString) { }
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 +741,8 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -681,6 +741,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 +756,10 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -694,6 +756,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 +767,16 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -701,12 +767,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 +818,17 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -748,12 +818,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 +913,11 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin ...@@ -838,4 +913,11 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
} }
}); });
} }
private ScriptObjectMirror asJSONCompatible() {
if (this.jsonCompatible) {
return this;
}
return new ScriptObjectMirror(sobj, global, true);
}
} }
...@@ -78,8 +78,7 @@ public final class URLReader extends Reader { ...@@ -78,8 +78,7 @@ public final class URLReader extends Reader {
* @throws NullPointerException if url is null * @throws NullPointerException if url is null
*/ */
public URLReader(final URL url, final Charset cs) { public URLReader(final URL url, final Charset cs) {
Objects.requireNonNull(url); this.url = Objects.requireNonNull(url);
this.url = url;
this.cs = cs; this.cs = cs;
} }
......
...@@ -100,7 +100,6 @@ import jdk.nashorn.internal.runtime.Source; ...@@ -100,7 +100,6 @@ import jdk.nashorn.internal.runtime.Source;
* There is also a very nice debug interface that can emit formatted * There is also a very nice debug interface that can emit formatted
* bytecodes that have been written. This is enabled by setting the * bytecodes that have been written. This is enabled by setting the
* environment "nashorn.codegen.debug" to true, or --log=codegen:{@literal <level>} * environment "nashorn.codegen.debug" to true, or --log=codegen:{@literal <level>}
* <p>
* *
* @see Compiler * @see Compiler
*/ */
...@@ -144,7 +143,7 @@ public class ClassEmitter { ...@@ -144,7 +143,7 @@ public class ClassEmitter {
/** /**
* Constructor - only used internally in this class as it breaks * Constructor - only used internally in this class as it breaks
* abstraction towards ASM or other code generator below * abstraction towards ASM or other code generator below.
* *
* @param env script environment * @param env script environment
* @param cw ASM classwriter * @param cw ASM classwriter
...@@ -157,7 +156,8 @@ public class ClassEmitter { ...@@ -157,7 +156,8 @@ public class ClassEmitter {
} }
/** /**
* Return the method names encountered * Return the method names encountered.
*
* @return method names * @return method names
*/ */
public Set<String> getMethodNames() { public Set<String> getMethodNames() {
...@@ -165,12 +165,13 @@ public class ClassEmitter { ...@@ -165,12 +165,13 @@ public class ClassEmitter {
} }
/** /**
* Constructor * Constructor.
* *
* @param env script environment * @param env script environment
* @param className name of class to weave * @param className name of class to weave
* @param superClassName super class name for class * @param superClassName super class name for class
* @param interfaceNames names of interfaces implemented by this class, or null if none * @param interfaceNames names of interfaces implemented by this class, or
* {@code null} if none
*/ */
ClassEmitter(final Context context, final String className, final String superClassName, final String... interfaceNames) { ClassEmitter(final Context context, final String className, final String superClassName, final String... interfaceNames) {
this(context, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS)); this(context, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS));
...@@ -178,7 +179,7 @@ public class ClassEmitter { ...@@ -178,7 +179,7 @@ public class ClassEmitter {
} }
/** /**
* Constructor from the compiler * Constructor from the compiler.
* *
* @param env Script environment * @param env Script environment
* @param sourceName Source name * @param sourceName Source name
...@@ -217,7 +218,6 @@ public class ClassEmitter { ...@@ -217,7 +218,6 @@ public class ClassEmitter {
} }
/** /**
* Returns the name of the compile unit class name.
* @return the name of the compile unit class name. * @return the name of the compile unit class name.
*/ */
String getUnitClassName() { String getUnitClassName() {
...@@ -225,7 +225,8 @@ public class ClassEmitter { ...@@ -225,7 +225,8 @@ public class ClassEmitter {
} }
/** /**
* Get the method count, including init and clinit methods * Get the method count, including init and clinit methods.
*
* @return method count * @return method count
*/ */
public int getMethodCount() { public int getMethodCount() {
...@@ -233,7 +234,8 @@ public class ClassEmitter { ...@@ -233,7 +234,8 @@ public class ClassEmitter {
} }
/** /**
* Get the clinit count * Get the clinit count.
*
* @return clinit count * @return clinit count
*/ */
public int getClinitCount() { public int getClinitCount() {
...@@ -241,7 +243,8 @@ public class ClassEmitter { ...@@ -241,7 +243,8 @@ public class ClassEmitter {
} }
/** /**
* Get the init count * Get the init count.
*
* @return init count * @return init count
*/ */
public int getInitCount() { public int getInitCount() {
...@@ -249,7 +252,8 @@ public class ClassEmitter { ...@@ -249,7 +252,8 @@ public class ClassEmitter {
} }
/** /**
* Get the field count * Get the field count.
*
* @return field count * @return field count
*/ */
public int getFieldCount() { public int getFieldCount() {
...@@ -260,6 +264,7 @@ public class ClassEmitter { ...@@ -260,6 +264,7 @@ public class ClassEmitter {
* Convert a binary name to a package/class name. * Convert a binary name to a package/class name.
* *
* @param name Binary name. * @param name Binary name.
*
* @return Package/class name. * @return Package/class name.
*/ */
private static String pathName(final String name) { private static String pathName(final String name) {
...@@ -268,6 +273,7 @@ public class ClassEmitter { ...@@ -268,6 +273,7 @@ public class ClassEmitter {
/** /**
* Define the static fields common in all scripts. * Define the static fields common in all scripts.
*
* @param strictMode Should we generate this method in strict mode * @param strictMode Should we generate this method in strict mode
*/ */
private void defineCommonStatics(final boolean strictMode) { private void defineCommonStatics(final boolean strictMode) {
...@@ -284,8 +290,8 @@ public class ClassEmitter { ...@@ -284,8 +290,8 @@ public class ClassEmitter {
} }
/** /**
* Define static utilities common needed in scripts. These are per compile unit * Define static utilities common needed in scripts. These are per compile
* and therefore have to be defined here and not in code gen. * unit and therefore have to be defined here and not in code gen.
*/ */
private void defineCommonUtilities() { private void defineCommonUtilities() {
assert unitClassName != null; assert unitClassName != null;
...@@ -333,7 +339,9 @@ public class ClassEmitter { ...@@ -333,7 +339,9 @@ public class ClassEmitter {
} }
/** /**
* Constructs a primitive specific method for getting the ith entry from the constants table as an array. * Constructs a primitive specific method for getting the ith entry from the
* constants table as an array.
*
* @param clazz Array class. * @param clazz Array class.
*/ */
private void defineGetArrayMethod(final Class<?> clazz) { private void defineGetArrayMethod(final Class<?> clazz) {
...@@ -356,7 +364,9 @@ public class ClassEmitter { ...@@ -356,7 +364,9 @@ public class ClassEmitter {
/** /**
* Generate the name of a get array from constant pool method. * Generate the name of a get array from constant pool method.
*
* @param clazz Name of array class. * @param clazz Name of array class.
*
* @return Method name. * @return Method name.
*/ */
static String getArrayMethodName(final Class<?> clazz) { static String getArrayMethodName(final Class<?> clazz) {
...@@ -366,6 +376,7 @@ public class ClassEmitter { ...@@ -366,6 +376,7 @@ public class ClassEmitter {
/** /**
* Ensure a get constant method is issued for the class. * Ensure a get constant method is issued for the class.
*
* @param clazz Class of constant. * @param clazz Class of constant.
*/ */
void needGetConstantMethod(final Class<?> clazz) { void needGetConstantMethod(final Class<?> clazz) {
...@@ -373,12 +384,12 @@ public class ClassEmitter { ...@@ -373,12 +384,12 @@ public class ClassEmitter {
} }
/** /**
* Inspect class name and decide whether we are generating a ScriptObject class * Inspect class name and decide whether we are generating a ScriptObject class.
* *
* @param scriptPrefix the script class prefix for the current script * @param scriptPrefix the script class prefix for the current script
* @param type the type to check * @param type the type to check
* *
* @return true if type is ScriptObject * @return {@code true} if type is ScriptObject
*/ */
private static boolean isScriptObject(final String scriptPrefix, final String type) { private static boolean isScriptObject(final String scriptPrefix, final String type) {
if (type.startsWith(scriptPrefix)) { if (type.startsWith(scriptPrefix)) {
...@@ -393,14 +404,14 @@ public class ClassEmitter { ...@@ -393,14 +404,14 @@ public class ClassEmitter {
} }
/** /**
* Call at beginning of class emission * Call at beginning of class emission.
*/ */
public void begin() { public void begin() {
classStarted = true; classStarted = true;
} }
/** /**
* Call at end of class emission * Call at end of class emission.
*/ */
public void end() { public void end() {
assert classStarted : "class not started for " + unitClassName; assert classStarted : "class not started for " + unitClassName;
...@@ -424,7 +435,9 @@ public class ClassEmitter { ...@@ -424,7 +435,9 @@ public class ClassEmitter {
/** /**
* Disassemble an array of byte code. * Disassemble an array of byte code.
*
* @param bytecode byte array representing bytecode * @param bytecode byte array representing bytecode
*
* @return disassembly as human readable string * @return disassembly as human readable string
*/ */
static String disassemble(final byte[] bytecode) { static String disassemble(final byte[] bytecode) {
...@@ -446,7 +459,7 @@ public class ClassEmitter { ...@@ -446,7 +459,7 @@ public class ClassEmitter {
} }
/** /**
* Call back from MethodEmitter for method start * Call back from MethodEmitter for method start.
* *
* @see MethodEmitter * @see MethodEmitter
* *
...@@ -458,7 +471,7 @@ public class ClassEmitter { ...@@ -458,7 +471,7 @@ public class ClassEmitter {
} }
/** /**
* Call back from MethodEmitter for method end * Call back from MethodEmitter for method end.
* *
* @see MethodEmitter * @see MethodEmitter
* *
...@@ -470,7 +483,7 @@ public class ClassEmitter { ...@@ -470,7 +483,7 @@ public class ClassEmitter {
} }
/** /**
* Add a new method to the class - defaults to public method * Add a new method to the class - defaults to public method.
* *
* @param methodName name of method * @param methodName name of method
* @param rtype return type of the method * @param rtype return type of the method
...@@ -483,7 +496,7 @@ public class ClassEmitter { ...@@ -483,7 +496,7 @@ public class ClassEmitter {
} }
/** /**
* Add a new method to the class - defaults to public method * Add a new method to the class - defaults to public method.
* *
* @param methodFlags access flags for the method * @param methodFlags access flags for the method
* @param methodName name of method * @param methodName name of method
...@@ -499,7 +512,7 @@ public class ClassEmitter { ...@@ -499,7 +512,7 @@ public class ClassEmitter {
} }
/** /**
* Add a new method to the class - defaults to public method * Add a new method to the class - defaults to public method.
* *
* @param methodName name of method * @param methodName name of method
* @param descriptor descriptor of method * @param descriptor descriptor of method
...@@ -511,7 +524,7 @@ public class ClassEmitter { ...@@ -511,7 +524,7 @@ public class ClassEmitter {
} }
/** /**
* Add a new method to the class - defaults to public method * Add a new method to the class - defaults to public method.
* *
* @param methodFlags access flags for the method * @param methodFlags access flags for the method
* @param methodName name of method * @param methodName name of method
...@@ -526,9 +539,10 @@ public class ClassEmitter { ...@@ -526,9 +539,10 @@ public class ClassEmitter {
} }
/** /**
* Add a new method to the class, representing a function node * Add a new method to the class, representing a function node.
* *
* @param functionNode the function node to generate a method for * @param functionNode the function node to generate a method for
*
* @return method emitter to use for weaving this method * @return method emitter to use for weaving this method
*/ */
MethodEmitter method(final FunctionNode functionNode) { MethodEmitter method(final FunctionNode functionNode) {
...@@ -546,9 +560,11 @@ public class ClassEmitter { ...@@ -546,9 +560,11 @@ public class ClassEmitter {
} }
/** /**
* Add a new method to the class, representing a rest-of version of the function node * Add a new method to the class, representing a rest-of version of the
* function node.
* *
* @param functionNode the function node to generate a method for * @param functionNode the function node to generate a method for
*
* @return method emitter to use for weaving this method * @return method emitter to use for weaving this method
*/ */
MethodEmitter restOfMethod(final FunctionNode functionNode) { MethodEmitter restOfMethod(final FunctionNode functionNode) {
...@@ -566,7 +582,7 @@ public class ClassEmitter { ...@@ -566,7 +582,7 @@ public class ClassEmitter {
/** /**
* Start generating the <clinit> method in the class * Start generating the <clinit> method in the class.
* *
* @return method emitter to use for weaving <clinit> * @return method emitter to use for weaving <clinit>
*/ */
...@@ -576,7 +592,7 @@ public class ClassEmitter { ...@@ -576,7 +592,7 @@ public class ClassEmitter {
} }
/** /**
* Start generating an <init>()V method in the class * Start generating an <init>()V method in the class.
* *
* @return method emitter to use for weaving <init>()V * @return method emitter to use for weaving <init>()V
*/ */
...@@ -586,7 +602,7 @@ public class ClassEmitter { ...@@ -586,7 +602,7 @@ public class ClassEmitter {
} }
/** /**
* Start generating an <init>()V method in the class * Start generating an <init>()V method in the class.
* *
* @param ptypes parameter types for constructor * @param ptypes parameter types for constructor
* @return method emitter to use for weaving <init>()V * @return method emitter to use for weaving <init>()V
...@@ -597,7 +613,7 @@ public class ClassEmitter { ...@@ -597,7 +613,7 @@ public class ClassEmitter {
} }
/** /**
* Start generating an <init>(...)V method in the class * Start generating an <init>(...)V method in the class.
* *
* @param flags access flags for the constructor * @param flags access flags for the constructor
* @param ptypes parameter types for the constructor * @param ptypes parameter types for the constructor
...@@ -610,7 +626,7 @@ public class ClassEmitter { ...@@ -610,7 +626,7 @@ public class ClassEmitter {
} }
/** /**
* Add a field to the class, initialized to a value * Add a field to the class, initialized to a value.
* *
* @param fieldFlags flags, e.g. should it be static or public etc * @param fieldFlags flags, e.g. should it be static or public etc
* @param fieldName name of field * @param fieldName name of field
...@@ -625,7 +641,7 @@ public class ClassEmitter { ...@@ -625,7 +641,7 @@ public class ClassEmitter {
} }
/** /**
* Add a field to the class * Add a field to the class.
* *
* @param fieldFlags access flags for the field * @param fieldFlags access flags for the field
* @param fieldName name of field * @param fieldName name of field
...@@ -638,7 +654,7 @@ public class ClassEmitter { ...@@ -638,7 +654,7 @@ public class ClassEmitter {
} }
/** /**
* Add a field to the class - defaults to public * Add a field to the class - defaults to public.
* *
* @param fieldName name of field * @param fieldName name of field
* @param fieldType type of field * @param fieldType type of field
...@@ -651,7 +667,8 @@ public class ClassEmitter { ...@@ -651,7 +667,8 @@ public class ClassEmitter {
* Return a bytecode array from this ClassEmitter. The ClassEmitter must * Return a bytecode array from this ClassEmitter. The ClassEmitter must
* have been ended (having its end function called) for this to work. * have been ended (having its end function called) for this to work.
* *
* @return byte code array for generated class, null if class generation hasn't been ended with {@link ClassEmitter#end()} * @return byte code array for generated class, {@code null} if class
* generation hasn't been ended with {@link ClassEmitter#end()}.
*/ */
byte[] toByteArray() { byte[] toByteArray() {
assert classEnded; assert classEnded;
...@@ -663,13 +680,9 @@ public class ClassEmitter { ...@@ -663,13 +680,9 @@ public class ClassEmitter {
} }
/** /**
* Abstraction for flags used in class emission * Abstraction for flags used in class emission. We provide abstraction
* * separating these from the underlying bytecode emitter. Flags are provided
* We provide abstraction separating these from the underlying bytecode * for method handles, protection levels, static/virtual fields/methods.
* emitter.
*
* Flags are provided for method handles, protection levels, static/virtual
* fields/methods.
*/ */
static enum Flag { static enum Flag {
/** method handle with static access */ /** method handle with static access */
...@@ -707,10 +720,12 @@ public class ClassEmitter { ...@@ -707,10 +720,12 @@ public class ClassEmitter {
} }
/** /**
* Return the corresponding ASM flag value for an enum set of flags * Return the corresponding ASM flag value for an enum set of flags.
* *
* @param flags enum set of flags * @param flags enum set of flags
* @return an integer value representing the flags intrinsic values or:ed together *
* @return an integer value representing the flags intrinsic values
* or:ed together
*/ */
static int getValue(final EnumSet<Flag> flags) { static int getValue(final EnumSet<Flag> flags) {
int v = 0; int v = 0;
......
...@@ -363,7 +363,7 @@ enum CompilationPhase { ...@@ -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);
} }
......
...@@ -122,8 +122,7 @@ public final class CompileUnit implements Comparable<CompileUnit>, Serializable ...@@ -122,8 +122,7 @@ public final class CompileUnit implements Comparable<CompileUnit>, Serializable
* @param clazz class with code for this compile unit * @param clazz class with code for this compile unit
*/ */
void setCode(final Class<?> clazz) { void setCode(final Class<?> clazz) {
Objects.requireNonNull(clazz); this.clazz = Objects.requireNonNull(clazz);
this.clazz = clazz;
// Revisit this - refactor to avoid null-ed out non-final fields // Revisit this - refactor to avoid null-ed out non-final fields
// null out emitter // null out emitter
this.classEmitter = null; this.classEmitter = null;
......
...@@ -101,7 +101,7 @@ final class SplitIntoFunctions extends NodeVisitor<BlockLexicalContext> { ...@@ -101,7 +101,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);
} }
...@@ -301,7 +301,7 @@ final class SplitIntoFunctions extends NodeVisitor<BlockLexicalContext> { ...@@ -301,7 +301,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);
} }
......
/* /*
* 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
...@@ -31,11 +31,13 @@ import jdk.nashorn.internal.runtime.Debug; ...@@ -31,11 +31,13 @@ import jdk.nashorn.internal.runtime.Debug;
import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.Source;
/** /**
* A class that tracks the current lexical context of node visitation as a stack of {@link Block} nodes. Has special * A class that tracks the current lexical context of node visitation as a stack
* methods to retrieve useful subsets of the context. * of {@link Block} nodes. Has special methods to retrieve useful subsets of the
* context.
* *
* This is implemented with a primitive array and a stack pointer, because it really makes a difference * This is implemented with a primitive array and a stack pointer, because it
* performance wise. None of the collection classes were optimal * really makes a difference performance-wise. None of the collection classes
* were optimal.
*/ */
public class LexicalContext { public class LexicalContext {
private LexicalContextNode[] stack; private LexicalContextNode[] stack;
...@@ -79,6 +81,7 @@ public class LexicalContext { ...@@ -79,6 +81,7 @@ public class LexicalContext {
* {@link Block#NEEDS_SCOPE} because it atomically also sets the * {@link Block#NEEDS_SCOPE} because it atomically also sets the
* {@link FunctionNode#HAS_SCOPE_BLOCK} flag on the block's containing * {@link FunctionNode#HAS_SCOPE_BLOCK} flag on the block's containing
* function. * function.
*
* @param block the block that needs to be marked as creating a scope. * @param block the block that needs to be marked as creating a scope.
*/ */
public void setBlockNeedsScope(final Block block) { public void setBlockNeedsScope(final Block block) {
...@@ -97,8 +100,10 @@ public class LexicalContext { ...@@ -97,8 +100,10 @@ public class LexicalContext {
} }
/** /**
* Get the flags for a lexical context node on the stack * Get the flags for a lexical context node on the stack.
*
* @param node node * @param node node
*
* @return the flags for the node * @return the flags for the node
*/ */
public int getFlags(final LexicalContextNode node) { public int getFlags(final LexicalContextNode node) {
...@@ -112,8 +117,10 @@ public class LexicalContext { ...@@ -112,8 +117,10 @@ public class LexicalContext {
/** /**
* Get the function body of a function node on the lexical context * Get the function body of a function node on the lexical context
* stack. This will trigger an assertion if node isn't present * stack. This will trigger an assertion if node isn't present.
*
* @param functionNode function node * @param functionNode function node
*
* @return body of function node * @return body of function node
*/ */
public Block getFunctionBody(final FunctionNode functionNode) { public Block getFunctionBody(final FunctionNode functionNode) {
...@@ -126,15 +133,16 @@ public class LexicalContext { ...@@ -126,15 +133,16 @@ public class LexicalContext {
} }
/** /**
* Return all nodes in the LexicalContext * @return all nodes in the LexicalContext.
* @return all nodes
*/ */
public Iterator<LexicalContextNode> getAllNodes() { public Iterator<LexicalContextNode> getAllNodes() {
return new NodeIterator<>(LexicalContextNode.class); return new NodeIterator<>(LexicalContextNode.class);
} }
/** /**
* Returns the outermost function in this context. It is either the program, or a lazily compiled function. * Returns the outermost function in this context. It is either the program,
* or a lazily compiled function.
*
* @return the outermost function in this context. * @return the outermost function in this context.
*/ */
public FunctionNode getOutermostFunction() { public FunctionNode getOutermostFunction() {
...@@ -142,8 +150,12 @@ public class LexicalContext { ...@@ -142,8 +150,12 @@ public class LexicalContext {
} }
/** /**
* Pushes a new block on top of the context, making it the innermost open block. * Pushes a new block on top of the context, making it the innermost open
* block.
*
* @param <T> the type of the new node
* @param node the new node * @param node the new node
*
* @return the node that was pushed * @return the node that was pushed
*/ */
public <T extends LexicalContextNode> T push(final T node) { public <T extends LexicalContextNode> T push(final T node) {
...@@ -168,25 +180,28 @@ public class LexicalContext { ...@@ -168,25 +180,28 @@ public class LexicalContext {
/** /**
* Is the context empty? * Is the context empty?
* @return true if empty *
* @return {@code true} if empty
*/ */
public boolean isEmpty() { public boolean isEmpty() {
return sp == 0; return sp == 0;
} }
/** /**
* The depth of the lexical context * @return the depth of the lexical context.
* @return depth
*/ */
public int size() { public int size() {
return sp; return sp;
} }
/** /**
* Pops the innermost block off the context and all nodes that has been contributed * Pops the innermost block off the context and all nodes that has been
* since it was put there * contributed since it was put there.
*
* @param <T> the type of the node to be popped
* @param node the node expected to be popped, used to detect unbalanced
* pushes/pops
* *
* @param node the node expected to be popped, used to detect unbalanced pushes/pops
* @return the node that was popped * @return the node that was popped
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
...@@ -202,11 +217,17 @@ public class LexicalContext { ...@@ -202,11 +217,17 @@ public class LexicalContext {
} }
/** /**
* Explicitly apply flags to the topmost element on the stack. This is only valid to use from a * Explicitly apply flags to the topmost element on the stack. This is only
* {@code NodeVisitor.leaveXxx()} method and only on the node being exited at the time. It is not mandatory to use, * valid to use from a {@code NodeVisitor.leaveXxx()} method and only on the
* as {@link #pop(Node)} will apply the flags automatically, but this method can be used to apply them * node being exited at the time. It is not mandatory to use, as
* during the {@code leaveXxx()} method in case its logic depends on the value of the flags. * {@link #pop(Node)} will apply the flags automatically, but this method
* @param node the node to apply the flags to. Must be the topmost node on the stack. * can be used to apply them during the {@code leaveXxx()} method in case
* its logic depends on the value of the flags.
*
* @param <T> the type of the node to apply the flags to.
* @param node the node to apply the flags to. Must be the topmost node on
* the stack.
*
* @return the passed in node, or a modified node (if any flags were modified) * @return the passed in node, or a modified node (if any flags were modified)
*/ */
public <T extends LexicalContextNode & Flags<T>> T applyTopFlags(final T node) { public <T extends LexicalContextNode & Flags<T>> T applyTopFlags(final T node) {
...@@ -215,7 +236,8 @@ public class LexicalContext { ...@@ -215,7 +236,8 @@ public class LexicalContext {
} }
/** /**
* Return the top element in the context * Return the top element in the context.
*
* @return the node that was pushed last * @return the node that was pushed last
*/ */
public LexicalContextNode peek() { public LexicalContextNode peek() {
...@@ -223,9 +245,11 @@ public class LexicalContext { ...@@ -223,9 +245,11 @@ public class LexicalContext {
} }
/** /**
* Check if a node is in the lexical context * Check if a node is in the lexical context.
*
* @param node node to check for * @param node node to check for
* @return true if in the context *
* @return {@code true} if in the context
*/ */
public boolean contains(final LexicalContextNode node) { public boolean contains(final LexicalContextNode node) {
for (int i = 0; i < sp; i++) { for (int i = 0; i < sp; i++) {
...@@ -242,6 +266,7 @@ public class LexicalContext { ...@@ -242,6 +266,7 @@ public class LexicalContext {
* *
* @param oldNode old node * @param oldNode old node
* @param newNode new node * @param newNode new node
*
* @return the new node * @return the new node
*/ */
public LexicalContextNode replace(final LexicalContextNode oldNode, final LexicalContextNode newNode) { public LexicalContextNode replace(final LexicalContextNode oldNode, final LexicalContextNode newNode) {
...@@ -256,7 +281,9 @@ public class LexicalContext { ...@@ -256,7 +281,9 @@ public class LexicalContext {
} }
/** /**
* Returns an iterator over all blocks in the context, with the top block (innermost lexical context) first. * Returns an iterator over all blocks in the context, with the top block
* (innermost lexical context) first.
*
* @return an iterator over all blocks in the context. * @return an iterator over all blocks in the context.
*/ */
public Iterator<Block> getBlocks() { public Iterator<Block> getBlocks() {
...@@ -264,7 +291,9 @@ public class LexicalContext { ...@@ -264,7 +291,9 @@ public class LexicalContext {
} }
/** /**
* Returns an iterator over all functions in the context, with the top (innermost open) function first. * Returns an iterator over all functions in the context, with the top
* (innermost open) function first.
*
* @return an iterator over all functions in the context. * @return an iterator over all functions in the context.
*/ */
public Iterator<FunctionNode> getFunctions() { public Iterator<FunctionNode> getFunctions() {
...@@ -273,6 +302,7 @@ public class LexicalContext { ...@@ -273,6 +302,7 @@ public class LexicalContext {
/** /**
* Get the parent block for the current lexical context block * Get the parent block for the current lexical context block
*
* @return parent block * @return parent block
*/ */
public Block getParentBlock() { public Block getParentBlock() {
...@@ -283,7 +313,9 @@ public class LexicalContext { ...@@ -283,7 +313,9 @@ public class LexicalContext {
/** /**
* Gets the label node of the current block. * Gets the label node of the current block.
* @return the label node of the current block, if it is labeled. Otherwise returns null. *
* @return the label node of the current block, if it is labeled. Otherwise
* returns {@code null}.
*/ */
public LabelNode getCurrentBlockLabelNode() { public LabelNode getCurrentBlockLabelNode() {
assert stack[sp - 1] instanceof Block; assert stack[sp - 1] instanceof Block;
...@@ -294,21 +326,12 @@ public class LexicalContext { ...@@ -294,21 +326,12 @@ public class LexicalContext {
return parent instanceof LabelNode ? (LabelNode)parent : null; return parent instanceof LabelNode ? (LabelNode)parent : null;
} }
/*
public FunctionNode getProgram() {
final Iterator<FunctionNode> iter = getFunctions();
FunctionNode last = null;
while (iter.hasNext()) {
last = iter.next();
}
assert last != null;
return last;
}*/
/** /**
* Returns an iterator over all ancestors block of the given block, with its parent block first. * Returns an iterator over all ancestors block of the given block, with its
* parent block first.
*
* @param block the block whose ancestors are returned * @param block the block whose ancestors are returned
*
* @return an iterator over all ancestors block of the given block. * @return an iterator over all ancestors block of the given block.
*/ */
public Iterator<Block> getAncestorBlocks(final Block block) { public Iterator<Block> getAncestorBlocks(final Block block) {
...@@ -323,8 +346,11 @@ public class LexicalContext { ...@@ -323,8 +346,11 @@ public class LexicalContext {
} }
/** /**
* Returns an iterator over a block and all its ancestors blocks, with the block first. * Returns an iterator over a block and all its ancestors blocks, with the
* block first.
*
* @param block the block that is the starting point of the iteration. * @param block the block that is the starting point of the iteration.
*
* @return an iterator over a block and all its ancestors. * @return an iterator over a block and all its ancestors.
*/ */
public Iterator<Block> getBlocks(final Block block) { public Iterator<Block> getBlocks(final Block block) {
...@@ -352,7 +378,9 @@ public class LexicalContext { ...@@ -352,7 +378,9 @@ public class LexicalContext {
/** /**
* Get the function for this block. * Get the function for this block.
*
* @param block block for which to get function * @param block block for which to get function
*
* @return function for block * @return function for block
*/ */
public FunctionNode getFunction(final Block block) { public FunctionNode getFunction(final Block block) {
...@@ -373,7 +401,6 @@ public class LexicalContext { ...@@ -373,7 +401,6 @@ public class LexicalContext {
} }
/** /**
* Returns the innermost block in the context.
* @return the innermost block in the context. * @return the innermost block in the context.
*/ */
public Block getCurrentBlock() { public Block getCurrentBlock() {
...@@ -381,7 +408,6 @@ public class LexicalContext { ...@@ -381,7 +408,6 @@ public class LexicalContext {
} }
/** /**
* Returns the innermost function in the context.
* @return the innermost function in the context. * @return the innermost function in the context.
*/ */
public FunctionNode getCurrentFunction() { public FunctionNode getCurrentFunction() {
...@@ -394,9 +420,12 @@ public class LexicalContext { ...@@ -394,9 +420,12 @@ public class LexicalContext {
} }
/** /**
* Get the block in which a symbol is defined * Get the block in which a symbol is defined.
*
* @param symbol symbol * @param symbol symbol
* @return block in which the symbol is defined, assert if no such block in context *
* @return block in which the symbol is defined, assert if no such block in
* context.
*/ */
public Block getDefiningBlock(final Symbol symbol) { public Block getDefiningBlock(final Symbol symbol) {
final String name = symbol.getName(); final String name = symbol.getName();
...@@ -410,9 +439,12 @@ public class LexicalContext { ...@@ -410,9 +439,12 @@ public class LexicalContext {
} }
/** /**
* Get the function in which a symbol is defined * Get the function in which a symbol is defined.
*
* @param symbol symbol * @param symbol symbol
* @return function node in which this symbol is defined, assert if no such symbol exists in context *
* @return function node in which this symbol is defined, assert if no such
* symbol exists in context.
*/ */
public FunctionNode getDefiningFunction(final Symbol symbol) { public FunctionNode getDefiningFunction(final Symbol symbol) {
final String name = symbol.getName(); final String name = symbol.getName();
...@@ -433,7 +465,8 @@ public class LexicalContext { ...@@ -433,7 +465,8 @@ public class LexicalContext {
/** /**
* Is the topmost lexical context element a function body? * Is the topmost lexical context element a function body?
* @return true if function body *
* @return {@code true} if function body.
*/ */
public boolean isFunctionBody() { public boolean isFunctionBody() {
return getParentBlock() == null; return getParentBlock() == null;
...@@ -441,16 +474,20 @@ public class LexicalContext { ...@@ -441,16 +474,20 @@ public class LexicalContext {
/** /**
* Is the topmost lexical context element body of a SplitNode? * Is the topmost lexical context element body of a SplitNode?
* @return true if it's the body of a split node. *
* @return {@code true} if it's the body of a split node.
*/ */
public boolean isSplitBody() { public boolean isSplitBody() {
return sp >= 2 && stack[sp - 1] instanceof Block && stack[sp - 2] instanceof SplitNode; return sp >= 2 && stack[sp - 1] instanceof Block && stack[sp - 2] instanceof SplitNode;
} }
/** /**
* Get the parent function for a function in the lexical context * Get the parent function for a function in the lexical context.
*
* @param functionNode function for which to get parent * @param functionNode function for which to get parent
* @return parent function of functionNode or null if none (e.g. if functionNode is the program) *
* @return parent function of functionNode or {@code null} if none (e.g., if
* functionNode is the program).
*/ */
public FunctionNode getParentFunction(final FunctionNode functionNode) { public FunctionNode getParentFunction(final FunctionNode functionNode) {
final Iterator<FunctionNode> iter = new NodeIterator<>(FunctionNode.class); final Iterator<FunctionNode> iter = new NodeIterator<>(FunctionNode.class);
...@@ -465,12 +502,16 @@ public class LexicalContext { ...@@ -465,12 +502,16 @@ public class LexicalContext {
} }
/** /**
* Count the number of scopes until a given node. Note that this method is solely used to figure out the number of * Count the number of scopes until a given node. Note that this method is
* scopes that need to be explicitly popped in order to perform a break or continue jump within the current bytecode * solely used to figure out the number of scopes that need to be explicitly
* method. For this reason, the method returns 0 if it encounters a {@code SplitNode} between the current location * popped in order to perform a break or continue jump within the current
* and the break/continue target. * bytecode method. For this reason, the method returns 0 if it encounters a
* @param until node to stop counting at. Must be within the current function * {@code SplitNode} between the current location and the break/continue
* @return number of with scopes encountered in the context * target.
*
* @param until node to stop counting at. Must be within the current function.
*
* @return number of with scopes encountered in the context.
*/ */
public int getScopeNestingLevelTo(final LexicalContextNode until) { public int getScopeNestingLevelTo(final LexicalContextNode until) {
assert until != null; assert until != null;
...@@ -500,16 +541,17 @@ public class LexicalContext { ...@@ -500,16 +541,17 @@ public class LexicalContext {
} }
/** /**
* Check whether the lexical context is currently inside a loop * Check whether the lexical context is currently inside a loop.
* @return true if inside a loop *
* @return {@code true} if inside a loop
*/ */
public boolean inLoop() { public boolean inLoop() {
return getCurrentLoop() != null; return getCurrentLoop() != null;
} }
/** /**
* Returns the loop header of the current loop, or null if not inside a loop * @return the loop header of the current loop, or {@code null} if not
* @return loop header * inside a loop.
*/ */
public LoopNode getCurrentLoop() { public LoopNode getCurrentLoop() {
final Iterator<LoopNode> iter = new NodeIterator<>(LoopNode.class, getCurrentFunction()); final Iterator<LoopNode> iter = new NodeIterator<>(LoopNode.class, getCurrentFunction());
...@@ -518,9 +560,12 @@ public class LexicalContext { ...@@ -518,9 +560,12 @@ public class LexicalContext {
/** /**
* Find the breakable node corresponding to this label. * Find the breakable node corresponding to this label.
* @param labelName name of the label to search for. If null, the closest breakable node will be returned *
* unconditionally, e.g. a while loop with no label * @param labelName name of the label to search for. If {@code null}, the
* @return closest breakable node * closest breakable node will be returned unconditionally, e.g., a
* while loop with no label.
*
* @return closest breakable node.
*/ */
public BreakableNode getBreakable(final String labelName) { public BreakableNode getBreakable(final String labelName) {
if (labelName != null) { if (labelName != null) {
...@@ -544,9 +589,12 @@ public class LexicalContext { ...@@ -544,9 +589,12 @@ public class LexicalContext {
/** /**
* Find the continue target node corresponding to this label. * Find the continue target node corresponding to this label.
* @param labelName label name to search for. If null the closest loop node will be returned unconditionally, e.g. a *
* while loop with no label * @param labelName label name to search for. If {@code null} the closest
* @return closest continue target node * loop node will be returned unconditionally, e.g., a while loop
* with no label.
*
* @return closest continue target node.
*/ */
public LoopNode getContinueTo(final String labelName) { public LoopNode getContinueTo(final String labelName) {
if (labelName != null) { if (labelName != null) {
...@@ -566,8 +614,10 @@ public class LexicalContext { ...@@ -566,8 +614,10 @@ public class LexicalContext {
/** /**
* Find the inlined finally block node corresponding to this label. * Find the inlined finally block node corresponding to this label.
* @param labelName label name to search for. Must not be null. *
* @return closest inlined finally block with the given label * @param labelName label name to search for. Must not be {@code null}.
*
* @return closest inlined finally block with the given label.
*/ */
public Block getInlinedFinally(final String labelName) { public Block getInlinedFinally(final String labelName) {
for (final NodeIterator<TryNode> iter = new NodeIterator<>(TryNode.class); iter.hasNext(); ) { for (final NodeIterator<TryNode> iter = new NodeIterator<>(TryNode.class); iter.hasNext(); ) {
...@@ -581,7 +631,9 @@ public class LexicalContext { ...@@ -581,7 +631,9 @@ public class LexicalContext {
/** /**
* Find the try node for an inlined finally block corresponding to this label. * Find the try node for an inlined finally block corresponding to this label.
* @param labelName label name to search for. Must not be null. *
* @param labelName label name to search for. Must not be {@code null}.
*
* @return the try node to which the labelled inlined finally block belongs. * @return the try node to which the labelled inlined finally block belongs.
*/ */
public TryNode getTryNodeForInlinedFinally(final String labelName) { public TryNode getTryNodeForInlinedFinally(final String labelName) {
...@@ -595,9 +647,11 @@ public class LexicalContext { ...@@ -595,9 +647,11 @@ public class LexicalContext {
} }
/** /**
* Check the lexical context for a given label node by name * Check the lexical context for a given label node by name.
* @param name name of the label *
* @return LabelNode if found, null otherwise * @param name name of the label.
*
* @return LabelNode if found, {@code null} otherwise.
*/ */
public LabelNode findLabel(final String name) { public LabelNode findLabel(final String name) {
for (final Iterator<LabelNode> iter = new NodeIterator<>(LabelNode.class, getCurrentFunction()); iter.hasNext(); ) { for (final Iterator<LabelNode> iter = new NodeIterator<>(LabelNode.class, getCurrentFunction()); iter.hasNext(); ) {
...@@ -610,10 +664,13 @@ public class LexicalContext { ...@@ -610,10 +664,13 @@ public class LexicalContext {
} }
/** /**
* Checks whether a given target is a jump destination that lies outside a given split node * Checks whether a given target is a jump destination that lies outside a
* @param splitNode the split node * given split node.
* @param target the target node *
* @return true if target resides outside the split node * @param splitNode the split node.
* @param target the target node.
*
* @return {@code true} if target resides outside the split node.
*/ */
public boolean isExternalTarget(final SplitNode splitNode, final BreakableNode target) { public boolean isExternalTarget(final SplitNode splitNode, final BreakableNode target) {
for (int i = sp; i-- > 0;) { for (int i = sp; i-- > 0;) {
...@@ -634,8 +691,10 @@ public class LexicalContext { ...@@ -634,8 +691,10 @@ public class LexicalContext {
} }
/** /**
* Checks whether the current context is inside a switch statement without explicit blocks (curly braces). * Checks whether the current context is inside a switch statement without
* @return true if in unprotected switch statement * explicit blocks (curly braces).
*
* @return {@code true} if in unprotected switch statement.
*/ */
public boolean inUnprotectedSwitchContext() { public boolean inUnprotectedSwitchContext() {
for (int i = sp; i > 0; i--) { for (int i = sp; i > 0; i--) {
......
...@@ -54,7 +54,7 @@ public final class SplitReturn extends Statement { ...@@ -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;");
} }
......
...@@ -122,7 +122,7 @@ public final class TryNode extends LexicalContextStatement implements JoinPredec ...@@ -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);
......
/* /*
* 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 { ...@@ -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");
......
...@@ -928,9 +928,11 @@ public final class Global extends ScriptObject implements Scope { ...@@ -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 { ...@@ -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
...@@ -988,9 +1005,7 @@ public final class Global extends ScriptObject implements Scope { ...@@ -988,9 +1005,7 @@ public final class Global extends ScriptObject implements Scope {
* @return the global singleton * @return the global singleton
*/ */
public static Global instance() { public static Global instance() {
final Global global = Context.getGlobal(); return Objects.requireNonNull(Context.getGlobal());
Objects.requireNonNull(global);
return global;
} }
private static Global instanceFrom(final Object self) { private static Global instanceFrom(final Object self) {
...@@ -1055,17 +1070,21 @@ public final class Global extends ScriptObject implements Scope { ...@@ -1055,17 +1070,21 @@ public final class Global extends ScriptObject implements Scope {
* as well as our extension builtin objects like "Java", "JSAdapter" as properties * as well as our extension builtin objects like "Java", "JSAdapter" as properties
* of the global scope object. * of the global scope object.
* *
* @param engine ScriptEngine to initialize * @param eng ScriptEngine to initialize
* @param ctxt ScriptContext to initialize
*/ */
@SuppressWarnings("hiding") public void initBuiltinObjects(final ScriptEngine eng, final ScriptContext ctxt) {
public void initBuiltinObjects(final ScriptEngine engine) {
if (this.builtinObject != null) { if (this.builtinObject != null) {
// already initialized, just return // already initialized, just return
return; return;
} }
this.engine = engine; this.engine = eng;
init(engine); this.initscontext = ctxt;
if (this.engine != null) {
this.scontext = new ThreadLocal<>();
}
init(eng);
} }
/** /**
...@@ -1393,7 +1412,7 @@ public final class Global extends ScriptObject implements Scope { ...@@ -1393,7 +1412,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) {
...@@ -1432,7 +1451,7 @@ public final class Global extends ScriptObject implements Scope { ...@@ -1432,7 +1451,7 @@ public final class Global extends ScriptObject implements Scope {
* @return the result of eval * @return the result of eval
*/ */
public static Object eval(final Object self, final Object str) { public static Object eval(final Object self, final Object str) {
return directEval(self, str, UNDEFINED, UNDEFINED, false); return directEval(self, str, Global.instanceFrom(self), UNDEFINED, false);
} }
/** /**
...@@ -1442,7 +1461,7 @@ public final class Global extends ScriptObject implements Scope { ...@@ -1442,7 +1461,7 @@ public final class Global extends ScriptObject implements Scope {
* @param str Evaluated code * @param str Evaluated code
* @param callThis "this" to be passed to the evaluated code * @param callThis "this" to be passed to the evaluated code
* @param location location of the eval call * @param location location of the eval call
* @param strict is eval called a strict mode code? * @param strict is eval called from a strict mode code?
* *
* @return the return value of the eval * @return the return value of the eval
* *
...@@ -2485,7 +2504,7 @@ public final class Global extends ScriptObject implements Scope { ...@@ -2485,7 +2504,7 @@ public final class Global extends ScriptObject implements Scope {
} }
@SuppressWarnings("hiding") @SuppressWarnings("hiding")
private void init(final ScriptEngine engine) { private void init(final ScriptEngine eng) {
assert Context.getGlobal() == this : "this global is not set as current"; assert Context.getGlobal() == this : "this global is not set as current";
final ScriptEnvironment env = getContext().getEnv(); final ScriptEnvironment env = getContext().getEnv();
...@@ -2601,7 +2620,7 @@ public final class Global extends ScriptObject implements Scope { ...@@ -2601,7 +2620,7 @@ public final class Global extends ScriptObject implements Scope {
addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments); addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments);
} }
if (engine != null) { if (eng != null) {
// default file name // default file name
addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null); addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null);
// __noSuchProperty__ hook for ScriptContext search of missing variables // __noSuchProperty__ hook for ScriptContext search of missing variables
...@@ -2692,6 +2711,14 @@ public final class Global extends ScriptObject implements Scope { ...@@ -2692,6 +2711,14 @@ public final class Global extends ScriptObject implements Scope {
// Retrieve current state of ENV variables. // Retrieve current state of ENV variables.
final ScriptObject env = newObject(); final ScriptObject env = newObject();
env.putAll(System.getenv(), scriptEnv._strict); env.putAll(System.getenv(), scriptEnv._strict);
// Some platforms, e.g., Windows, do not define the PWD environment
// variable, so that the $ENV.PWD property needs to be explicitly
// set.
if (!env.containsKey(ScriptingFunctions.PWD_NAME)) {
env.put(ScriptingFunctions.PWD_NAME, System.getProperty("user.dir"), scriptEnv._strict);
}
addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env); addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env);
} else { } else {
addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED); addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
...@@ -2739,8 +2766,9 @@ public final class Global extends ScriptObject implements Scope { ...@@ -2739,8 +2766,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) {
......
...@@ -279,8 +279,8 @@ public final class NativeFunction { ...@@ -279,8 +279,8 @@ public final class NativeFunction {
sb.append("})"); sb.append("})");
final Global global = Global.instance(); final Global global = Global.instance();
final Context context = global.getContext();
return (ScriptFunction)Global.directEval(global, sb.toString(), global, "<function>", global.isStrictContext()); return (ScriptFunction)context.eval(global, sb.toString(), global, "<function>");
} }
private static void checkFunctionParameters(final String params) { private static void checkFunctionParameters(final String params) {
......
...@@ -33,10 +33,12 @@ import java.lang.reflect.Array; ...@@ -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 { ...@@ -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());
}
} }
/* /*
* 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
...@@ -37,13 +37,15 @@ import java.lang.annotation.Target; ...@@ -37,13 +37,15 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface Constructor { public @interface Constructor {
/** /**
* Name of the constructor function. If empty, the name is inferred. * @return the name of the constructor function. If empty, the name is
* inferred.
*/ */
public String name() default ""; public String name() default "";
/** /**
* The arity of the function. By default computed from the method signature. * @return the arity of the function. By default computed from the method
* Note that -1 means varargs. So, -2 is used as invalid arity. * signature. Note that -1 means varargs. So, -2 is used as invalid
* arity.
*/ */
public int arity() default -2; public int arity() default -2;
} }
/* /*
* 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
...@@ -41,22 +41,23 @@ import java.lang.annotation.Target; ...@@ -41,22 +41,23 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface Function { public @interface Function {
/** /**
* Name of the property. If empty, the name is inferred. * @return the name of the property. If empty, the name is inferred.
*/ */
public String name() default ""; public String name() default "";
/** /**
* Attribute flags for this function. * @return the attribute flags for this function.
*/ */
public int attributes() default DEFAULT_ATTRIBUTES; public int attributes() default DEFAULT_ATTRIBUTES;
/** /**
* The arity of the function. By default computed from the method signature * @return the arity of the function. By default computed from the method
* signature.
*/ */
public int arity() default -2; public int arity() default -2;
/** /**
* where this function lives * @return where this function lives.
*/ */
public Where where() default Where.PROTOTYPE; public Where where() default Where.PROTOTYPE;
} }
/* /*
* 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
...@@ -39,17 +39,17 @@ import java.lang.annotation.Target; ...@@ -39,17 +39,17 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface Getter { public @interface Getter {
/** /**
* Name of the property. If empty, the name is inferred. * @return the name of the property. If empty, the name is inferred.
*/ */
public String name() default ""; public String name() default "";
/** /**
* Attribute flags for this setter. * @return the attribute flags for this setter.
*/ */
public int attributes() default DEFAULT_ATTRIBUTES; public int attributes() default DEFAULT_ATTRIBUTES;
/** /**
* Where this getter lives? * @return where this getter lives.
*/ */
public Where where() default Where.INSTANCE; public Where where() default Where.INSTANCE;
} }
/* /*
* 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
...@@ -37,8 +37,8 @@ import java.lang.annotation.Target; ...@@ -37,8 +37,8 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
public @interface ScriptClass { public @interface ScriptClass {
/** /**
* Name of the script class. By default, the name is derived from * @return the name of the script class. By default, the name is derived
* the Java class name. * from the Java class name.
*/ */
public String value() default ""; public String value() default "";
} }
/* /*
* 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
...@@ -39,17 +39,17 @@ import java.lang.annotation.Target; ...@@ -39,17 +39,17 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface Setter { public @interface Setter {
/** /**
* Name of the script property. If empty, the name is inferred. * @return the name of the script property. If empty, the name is inferred.
*/ */
public String name() default ""; public String name() default "";
/** /**
* Attribute flags for this setter. * @return the attribute flags for this setter.
*/ */
public int attributes() default DEFAULT_ATTRIBUTES; public int attributes() default DEFAULT_ATTRIBUTES;
/** /**
* Where this setter lives? * @return where this setter lives.
*/ */
public Where where() default Where.INSTANCE; public Where where() default Where.INSTANCE;
} }
/* /*
* 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
...@@ -33,10 +33,11 @@ import java.lang.invoke.MethodHandle; ...@@ -33,10 +33,11 @@ import java.lang.invoke.MethodHandle;
import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
/** /**
* The SpecializedFunction annotation is used to flag more type specific * The SpecializedFunction annotation is used to flag more type specific
* functions than the standard one in the native objects * functions than the standard one in the native objects.
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
...@@ -45,23 +46,23 @@ public @interface SpecializedFunction { ...@@ -45,23 +46,23 @@ public @interface SpecializedFunction {
/** /**
* Functionality for testing if we are allowed to link a specialized * Functionality for testing if we are allowed to link a specialized
* function the first time we encounter it. Then the guard will handle the * function the first time we encounter it. Then the guard will handle the
* rest of the invocations * rest of the invocations.
* *
* This is the same for all callsites in Nashorn, the first time callsite is * This is the same for all callsites in Nashorn; the first time a callsite is
* linked, we have to manually check that the linkage is OK. Even if we add * linked, we have to manually check that the linkage is OK. Even if we add
* a guard and it fails upon the first try, this is not good enough. * a guard and it fails upon the first try, this is not good enough.
* (Symmetrical to how it works everywhere else in the Nashorn runtime). * (Symmetrical to how it works everywhere else in the Nashorn runtime.)
* *
* Here we abstract out a few of the most common link guard checks. * Here we abstract out a few of the most common link guard checks.
*/ */
public static abstract class LinkLogic { public static abstract class LinkLogic {
/** /**
* Empty link logic instance - this is the default * Empty link logic instance - this is the default.
* "no special linking or runtime guard behavior" * "no special linking or runtime guard behavior"
*/ */
public static final LinkLogic EMPTY_INSTANCE = new Empty(); public static final LinkLogic EMPTY_INSTANCE = new Empty();
/** Empty link logic class - allow all linking, no guards */ /** Empty link logic class - allow all linking, no guards. */
private static final class Empty extends LinkLogic { private static final class Empty extends LinkLogic {
@Override @Override
public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
...@@ -75,7 +76,8 @@ public @interface SpecializedFunction { ...@@ -75,7 +76,8 @@ public @interface SpecializedFunction {
} }
/** /**
* Get the class representing the empty link logic * Get the class representing the empty link logic.
*
* @return class representing empty link logic * @return class representing empty link logic
*/ */
public static Class<? extends LinkLogic> getEmptyLinkLogicClass() { public static Class<? extends LinkLogic> getEmptyLinkLogicClass() {
...@@ -83,31 +85,31 @@ public @interface SpecializedFunction { ...@@ -83,31 +85,31 @@ public @interface SpecializedFunction {
} }
/** /**
* Should this callsite relink when an exception is thrown * Should this callsite relink when an exception is thrown?
* *
* @return the relink exception, or null if none * @return the relink exception, or {@code null} if none
*/ */
public Class<? extends Throwable> getRelinkException() { public Class<? extends Throwable> getRelinkException() {
return null; return null;
} }
/** /**
* Is this link logic class empty - i.e. no special linking logic * Is this link logic class empty - i.e., no special linking logic
* supplied * supplied?
* *
* @param clazz class to check * @param clazz class to check
* *
* @return true if this link logic is empty * @return {@code true} if this link logic is empty
*/ */
public static boolean isEmpty(final Class<? extends LinkLogic> clazz) { public static boolean isEmpty(final Class<? extends LinkLogic> clazz) {
return clazz == Empty.class; return clazz == Empty.class;
} }
/** /**
* Is this link logic instance empty - i.e. no special linking logic * Is this link logic instance empty - i.e., no special linking logic
* supplied * supplied?
* *
* @return true if this link logic instance is empty * @return {@code true} if this link logic instance is empty
*/ */
public boolean isEmpty() { public boolean isEmpty() {
return false; return false;
...@@ -121,7 +123,7 @@ public @interface SpecializedFunction { ...@@ -121,7 +123,7 @@ public @interface SpecializedFunction {
* @param desc callsite descriptor * @param desc callsite descriptor
* @param request link request * @param request link request
* *
* @return true if we can link this callsite at this time * @return {@code true} if we can link this callsite at this time
*/ */
public abstract boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request); public abstract boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request);
...@@ -131,7 +133,7 @@ public @interface SpecializedFunction { ...@@ -131,7 +133,7 @@ public @interface SpecializedFunction {
* *
* @param self receiver * @param self receiver
* *
* @return true if a guard is to be woven into the callsite * @return {@code true} if a guard is to be woven into the callsite
*/ */
public boolean needsGuard(final Object self) { public boolean needsGuard(final Object self) {
return true; return true;
...@@ -139,13 +141,13 @@ public @interface SpecializedFunction { ...@@ -139,13 +141,13 @@ public @interface SpecializedFunction {
/** /**
* Given a callsite, and optional arguments, do we need an extra guard * Given a callsite, and optional arguments, do we need an extra guard
* for specialization to go through - this guard can be a function of * for specialization to go through? This guard can be a function of
* the arguments too * the arguments too.
* *
* @param self receiver * @param self receiver
* @param args arguments * @param args arguments
* *
* @return true if a guard is to be woven into the callsite * @return {@code true} if a guard is to be woven into the callsite
*/ */
public boolean needsGuard(final Object self, final Object... args) { public boolean needsGuard(final Object self, final Object... args) {
return true; return true;
...@@ -169,9 +171,9 @@ public @interface SpecializedFunction { ...@@ -169,9 +171,9 @@ public @interface SpecializedFunction {
* @param self receiver * @param self receiver
* @param desc callsite descriptor * @param desc callsite descriptor
* @param request link request * @param request link request
*
* @return true if we can link, false otherwise - that means we have to * @return {@code true} if we can link, {@code false} otherwise - that
* pick a non specialized target * means we have to pick a non specialized target
*/ */
public boolean checkLinkable(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { public boolean checkLinkable(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
// check the link guard, if it says we can link, go ahead // check the link guard, if it says we can link, go ahead
...@@ -180,11 +182,11 @@ public @interface SpecializedFunction { ...@@ -180,11 +182,11 @@ public @interface SpecializedFunction {
} }
/** /**
* name override for return value polymorphism, for example we can't have * Name override for return value polymorphism, for example we can't have
* pop(V)I and pop(V)D in the same Java class, so they need to be named, * pop(V)I and pop(V)D in the same Java class, so they need to be named,
* e.g. popInt(V)I and popDouble(V)D for disambiguation, however, their * e.g., popInt(V)I and popDouble(V)D for disambiguation, however, their
* names still need to resolve to "pop" to JavaScript so we can still * names still need to resolve to "pop" to JavaScript so we can still
* specialize on return values and so that the linker can find them * specialize on return values and so that the linker can find them.
* *
* @return name, "" means no override, use the Java function name, e.g. * @return name, "" means no override, use the Java function name, e.g.
* "push" * "push"
...@@ -199,16 +201,18 @@ public @interface SpecializedFunction { ...@@ -199,16 +201,18 @@ public @interface SpecializedFunction {
Class<?> linkLogic() default LinkLogic.Empty.class; Class<?> linkLogic() default LinkLogic.Empty.class;
/** /**
* Is this a specialized constructor? * @return whether this is a specialized constructor.
*/ */
boolean isConstructor() default false; boolean isConstructor() default false;
/** /**
* Can this function throw UnwarrantedOptimismExceptions? This works just * Can this function throw {@link UnwarrantedOptimismException}s? This works
* like the normal functions, but we need the function to be * just like the normal functions, but we need the function to be
* immutable/non-state modifying, as we can't generate continuations for * immutable/non-state modifying, as we can't generate continuations for
* native code. Luckily a lot of the methods we want to specialize have this * native code. Luckily a lot of the methods we want to specialize have this
* property * property.
*
* @return whether this function can throw {@link UnwarrantedOptimismException}.
*/ */
boolean isOptimistic() default false; boolean isOptimistic() default false;
} }
...@@ -47,7 +47,8 @@ import jdk.nashorn.internal.scripts.JO; ...@@ -47,7 +47,8 @@ import jdk.nashorn.internal.scripts.JO;
import static jdk.nashorn.internal.parser.TokenType.STRING; import static jdk.nashorn.internal.parser.TokenType.STRING;
/** /**
* Parses JSON text and returns the corresponding IR node. This is derived from the objectLiteral production of the main parser. * Parses JSON text and returns the corresponding IR node. This is derived from
* the objectLiteral production of the main parser.
* *
* See: 15.12.1.2 The JSON Syntactic Grammar * See: 15.12.1.2 The JSON Syntactic Grammar
*/ */
...@@ -70,9 +71,11 @@ public class JSONParser { ...@@ -70,9 +71,11 @@ public class JSONParser {
private static final int STATE_COMMA_PARSED = 2; private static final int STATE_COMMA_PARSED = 2;
/** /**
* Constructor * Constructor.
* @param source the source *
* @param global the global object * @param source the source
* @param global the global object
* @param dualFields whether the parser should regard dual field representation
*/ */
public JSONParser(final String source, final Global global, final boolean dualFields) { public JSONParser(final String source, final Global global, final boolean dualFields) {
this.source = source; this.source = source;
...@@ -82,8 +85,9 @@ public class JSONParser { ...@@ -82,8 +85,9 @@ public class JSONParser {
} }
/** /**
* Implementation of the Quote(value) operation as defined in the ECMA script spec * Implementation of the Quote(value) operation as defined in the ECMAscript
* It wraps a String value in double quotes and escapes characters within in * spec. It wraps a String value in double quotes and escapes characters
* within.
* *
* @param value string to quote * @param value string to quote
* *
......
...@@ -2635,8 +2635,12 @@ loop: ...@@ -2635,8 +2635,12 @@ loop:
name = getIdent(); name = getIdent();
verifyStrictIdent(name, "function name"); verifyStrictIdent(name, "function name");
} else if (isStatement) { } else if (isStatement) {
// Nashorn extension: anonymous function statements // Nashorn extension: anonymous function statements.
if (env._no_syntax_extensions) { // Do not allow anonymous function statement if extensions
// are now allowed. But if we are reparsing then anon function
// statement is possible - because it was used as function
// expression in surrounding code.
if (env._no_syntax_extensions && reparsedFunction == null) {
expect(IDENT); expect(IDENT);
} }
} }
......
/* /*
* 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
...@@ -222,9 +222,11 @@ public enum TokenType { ...@@ -222,9 +222,11 @@ public enum TokenType {
/** /**
* Determines if the token has greater precedence than other. * Determines if the token has greater precedence than other.
*
* @param other Compare token. * @param other Compare token.
* @param isLeft Is to the left of the other. * @param isLeft Is to the left of the other.
* @return True if greater precedence. *
* @return {@code true} if greater precedence.
*/ */
public boolean needsParens(final TokenType other, final boolean isLeft) { public boolean needsParens(final TokenType other, final boolean isLeft) {
return other.precedence != 0 && return other.precedence != 0 &&
...@@ -234,16 +236,16 @@ public enum TokenType { ...@@ -234,16 +236,16 @@ public enum TokenType {
/** /**
* Determines if the type is a valid operator. * Determines if the type is a valid operator.
* @param noIn TRUE if IN operator should be ignored. *
* @return TRUE if valid operator. * @param noIn {@code true} if IN operator should be ignored.
*
* @return {@code true} if valid operator.
*/ */
public boolean isOperator(final boolean noIn) { public boolean isOperator(final boolean noIn) {
return kind == BINARY && (!noIn || this != IN) && precedence != 0; return kind == BINARY && (!noIn || this != IN) && precedence != 0;
} }
/**
* Accessors.
*/
public int getLength() { public int getLength() {
assert name != null : "Token name not set"; assert name != null : "Token name not set";
return name.length(); return name.length();
......
...@@ -528,8 +528,9 @@ final class CompiledFunction { ...@@ -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)) {
......
...@@ -66,6 +66,7 @@ import java.util.concurrent.atomic.AtomicReference; ...@@ -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;
...@@ -667,12 +668,11 @@ public final class Context { ...@@ -667,12 +668,11 @@ public final class Context {
* @param string Evaluated code as a String * @param string Evaluated code as a String
* @param callThis "this" to be passed to the evaluated code * @param callThis "this" to be passed to the evaluated code
* @param location location of the eval call * @param location location of the eval call
* @param strict is this {@code eval} call from a strict mode code?
* @return the return value of the {@code eval} * @return the return value of the {@code eval}
*/ */
public Object eval(final ScriptObject initialScope, final String string, public Object eval(final ScriptObject initialScope, final String string,
final Object callThis, final Object location, final boolean strict) { final Object callThis, final Object location) {
return eval(initialScope, string, callThis, location, strict, false); return eval(initialScope, string, callThis, location, false, false);
} }
/** /**
...@@ -691,14 +691,16 @@ public final class Context { ...@@ -691,14 +691,16 @@ public final class Context {
final Object callThis, final Object location, final boolean strict, final boolean evalCall) { final Object callThis, final Object location, final boolean strict, final boolean evalCall) {
final String file = location == UNDEFINED || location == null ? "<eval>" : location.toString(); final String file = location == UNDEFINED || location == null ? "<eval>" : location.toString();
final Source source = sourceFor(file, string, evalCall); final Source source = sourceFor(file, string, evalCall);
final boolean directEval = location != UNDEFINED; // is this direct 'eval' call or indirectly invoked eval? // is this direct 'eval' builtin call?
final boolean directEval = evalCall && (location != UNDEFINED);
final Global global = Context.getGlobal(); final Global global = Context.getGlobal();
ScriptObject scope = initialScope; ScriptObject scope = initialScope;
// ECMA section 10.1.1 point 2 says eval code is strict if it begins // ECMA section 10.1.1 point 2 says eval code is strict if it begins
// with "use strict" directive or eval direct call itself is made // with "use strict" directive or eval direct call itself is made
// from from strict mode code. We are passed with caller's strict mode. // from from strict mode code. We are passed with caller's strict mode.
boolean strictFlag = directEval && strict; // Nashorn extension: any 'eval' is unconditionally strict when -strict is specified.
boolean strictFlag = strict || this._strict;
Class<?> clazz = null; Class<?> clazz = null;
try { try {
...@@ -739,7 +741,8 @@ public final class Context { ...@@ -739,7 +741,8 @@ public final class Context {
if (directEval) { if (directEval) {
evalThis = (callThis != UNDEFINED && callThis != null) || strictFlag ? callThis : global; evalThis = (callThis != UNDEFINED && callThis != null) || strictFlag ? callThis : global;
} else { } else {
evalThis = global; // either indirect evalCall or non-eval (Function, engine.eval, ScriptObjectMirror.eval..)
evalThis = callThis;
} }
return ScriptRuntime.apply(func, evalThis); return ScriptRuntime.apply(func, evalThis);
...@@ -1095,16 +1098,17 @@ public final class Context { ...@@ -1095,16 +1098,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 +1124,7 @@ public final class Context { ...@@ -1120,7 +1124,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);
} }
/** /**
......
...@@ -156,7 +156,7 @@ final class DebuggerSupport { ...@@ -156,7 +156,7 @@ final class DebuggerSupport {
final Context context = global.getContext(); final Context context = global.getContext();
try { try {
return context.eval(initialScope, string, callThis, ScriptRuntime.UNDEFINED, false); return context.eval(initialScope, string, callThis, ScriptRuntime.UNDEFINED);
} catch (final Throwable ex) { } catch (final Throwable ex) {
return returnException ? ex : null; return returnException ? ex : null;
} }
......
/*
* 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.AbstractJSObject;
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();
}
/**
* Implements this object's {@code [[DefaultValue]]} method by returning its wrapped object's {@code [[DefaultValue]]}.
*
* @param hint the type hint. Should be either {@code null}, {@code Number.class} or {@code String.class}.
* @return the wrapped object's default value.
* @throws UnsupportedOperationException if the conversion can't be performed. The engine will convert this
* exception into a JavaScript {@code TypeError}.
*/
public Object getDefaultValue(final Class<?> hint) {
return AbstractJSObject.getDefaultValue(obj, hint);
}
}
...@@ -36,6 +36,7 @@ import java.util.RandomAccess; ...@@ -36,6 +36,7 @@ import java.util.RandomAccess;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.Bootstrap;
/** /**
...@@ -51,57 +52,43 @@ import jdk.nashorn.internal.runtime.linker.Bootstrap; ...@@ -51,57 +52,43 @@ 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);
// PUSH adds to the end of the list // PUSH adds to the start of the list
private static final Object PUSH = new Object(); private static final Object PUSH = new Object();
private static MethodHandle getPushInvoker() { // UNSHIFT adds to the end of the list
return getDynamicInvoker(PUSH, ADD_INVOKER_CREATOR);
}
// UNSHIFT adds to the start of the list
private static final Object UNSHIFT = new Object(); private static final Object UNSHIFT = new Object();
private static MethodHandle getUnshiftInvoker() {
return getDynamicInvoker(UNSHIFT, ADD_INVOKER_CREATOR);
}
// Invoker creator for methods that remove from the tail or head of the list: POP and SHIFT. Takes fn, this, returns Object. // Invoker creator for methods that remove from the tail or head of the list: POP and SHIFT. Takes fn, this, returns Object.
private static final Callable<MethodHandle> REMOVE_INVOKER_CREATOR = invokerCreator(Object.class, Object.class, JSObject.class); private static final Callable<MethodHandle> REMOVE_INVOKER_CREATOR = invokerCreator(Object.class, Object.class, JSObject.class);
// POP removes from the to the end of the list // POP removes from the start of the list
private static final Object POP = new Object(); private static final Object POP = new Object();
private static MethodHandle getPopInvoker() { // SHIFT removes from the end of the list
return getDynamicInvoker(POP, REMOVE_INVOKER_CREATOR);
}
// SHIFT removes from the to the start of the list
private static final Object SHIFT = new Object(); private static final Object SHIFT = new Object();
private static MethodHandle getShiftInvoker() {
return getDynamicInvoker(SHIFT, REMOVE_INVOKER_CREATOR);
}
// SPLICE can be used to add a value in the middle of the list. // SPLICE can be used to add a value in the middle of the list.
private static final Object SPLICE_ADD = new Object(); private static final Object SPLICE_ADD = new Object();
private static final Callable<MethodHandle> SPLICE_ADD_INVOKER_CREATOR = invokerCreator(void.class, Object.class, JSObject.class, int.class, int.class, Object.class); private static final Callable<MethodHandle> SPLICE_ADD_INVOKER_CREATOR = invokerCreator(void.class, Object.class, JSObject.class, int.class, int.class, Object.class);
private static MethodHandle getSpliceAddInvoker() {
return getDynamicInvoker(SPLICE_ADD, SPLICE_ADD_INVOKER_CREATOR);
}
// SPLICE can also be used to remove values from the middle of the list. // SPLICE can also be used to remove values from the middle of the list.
private static final Object SPLICE_REMOVE = new Object(); private static final Object SPLICE_REMOVE = new Object();
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);
private static MethodHandle getSpliceRemoveInvoker() {
return getDynamicInvoker(SPLICE_REMOVE, SPLICE_REMOVE_INVOKER_CREATOR);
}
/** wrapped object */ /** wrapped object */
protected final JSObject obj; final JSObject obj;
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) {
if (global == null) {
throw new IllegalStateException(ECMAErrors.getMessage("list.adapter.null.global"));
}
this.obj = obj; this.obj = obj;
this.global = global;
} }
/** /**
...@@ -111,12 +98,13 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc ...@@ -111,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;
} }
...@@ -166,7 +154,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc ...@@ -166,7 +154,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
@Override @Override
public final void addFirst(final Object e) { public final void addFirst(final Object e) {
try { try {
getUnshiftInvoker().invokeExact(getFunction("unshift"), obj, e); getDynamicInvoker(UNSHIFT, ADD_INVOKER_CREATOR).invokeExact(getFunction("unshift"), obj, e);
} catch(RuntimeException | Error ex) { } catch(RuntimeException | Error ex) {
throw ex; throw ex;
} catch(final Throwable t) { } catch(final Throwable t) {
...@@ -177,7 +165,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc ...@@ -177,7 +165,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
@Override @Override
public final void addLast(final Object e) { public final void addLast(final Object e) {
try { try {
getPushInvoker().invokeExact(getFunction("push"), obj, e); getDynamicInvoker(PUSH, ADD_INVOKER_CREATOR).invokeExact(getFunction("push"), obj, e);
} catch(RuntimeException | Error ex) { } catch(RuntimeException | Error ex) {
throw ex; throw ex;
} catch(final Throwable t) { } catch(final Throwable t) {
...@@ -195,7 +183,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc ...@@ -195,7 +183,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
} else { } else {
final int size = size(); final int size = size();
if(index < size) { if(index < size) {
getSpliceAddInvoker().invokeExact(obj.getMember("splice"), obj, index, 0, e); getDynamicInvoker(SPLICE_ADD, SPLICE_ADD_INVOKER_CREATOR).invokeExact(obj.getMember("splice"), obj, index, 0, e);
} else if(index == size) { } else if(index == size) {
addLast(e); addLast(e);
} else { } else {
...@@ -287,7 +275,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc ...@@ -287,7 +275,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
private Object invokeShift() { private Object invokeShift() {
try { try {
return getShiftInvoker().invokeExact(getFunction("shift"), obj); return getDynamicInvoker(SHIFT, REMOVE_INVOKER_CREATOR).invokeExact(getFunction("shift"), obj);
} catch(RuntimeException | Error ex) { } catch(RuntimeException | Error ex) {
throw ex; throw ex;
} catch(final Throwable t) { } catch(final Throwable t) {
...@@ -297,7 +285,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc ...@@ -297,7 +285,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
private Object invokePop() { private Object invokePop() {
try { try {
return getPopInvoker().invokeExact(getFunction("pop"), obj); return getDynamicInvoker(POP, REMOVE_INVOKER_CREATOR).invokeExact(getFunction("pop"), obj);
} catch(RuntimeException | Error ex) { } catch(RuntimeException | Error ex) {
throw ex; throw ex;
} catch(final Throwable t) { } catch(final Throwable t) {
...@@ -312,7 +300,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc ...@@ -312,7 +300,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
private void invokeSpliceRemove(final int fromIndex, final int count) { private void invokeSpliceRemove(final int fromIndex, final int count) {
try { try {
getSpliceRemoveInvoker().invokeExact(getFunction("splice"), obj, fromIndex, count); getDynamicInvoker(SPLICE_REMOVE, SPLICE_REMOVE_INVOKER_CREATOR).invokeExact(getFunction("splice"), obj, fromIndex, count);
} catch(RuntimeException | Error ex) { } catch(RuntimeException | Error ex) {
throw ex; throw ex;
} catch(final Throwable t) { } catch(final Throwable t) {
...@@ -417,7 +405,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc ...@@ -417,7 +405,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
}; };
} }
private static MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) { private MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) {
return Context.getGlobal().getDynamicInvoker(key, creator); return global.getDynamicInvoker(key, creator);
} }
} }
...@@ -342,6 +342,9 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp ...@@ -342,6 +342,9 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
if (functionNode.isVarArg()) { if (functionNode.isVarArg()) {
flags |= IS_VARIABLE_ARITY; flags |= IS_VARIABLE_ARITY;
} }
if (functionNode.getKind() == FunctionNode.Kind.GETTER || functionNode.getKind() == FunctionNode.Kind.SETTER) {
flags |= IS_PROPERTY_ACCESSOR;
}
return flags; return flags;
} }
...@@ -382,7 +385,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp ...@@ -382,7 +385,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
parser.setReparsedFunction(this); parser.setReparsedFunction(this);
final FunctionNode program = parser.parse(CompilerConstants.PROGRAM.symbolName(), descPosition, final FunctionNode program = parser.parse(CompilerConstants.PROGRAM.symbolName(), descPosition,
Token.descLength(token), true); Token.descLength(token), isPropertyAccessor());
// Parser generates a program AST even if we're recompiling a single function, so when we are only // Parser generates a program AST even if we're recompiling a single function, so when we are only
// recompiling a single function, extract it from the program. // recompiling a single function, extract it from the program.
return (isProgram() ? program : extractFunctionFromScript(program)).setName(null, functionName); return (isProgram() ? program : extractFunctionFromScript(program)).setName(null, functionName);
......
...@@ -80,24 +80,24 @@ public abstract class ScriptFunctionData implements Serializable { ...@@ -80,24 +80,24 @@ public abstract class ScriptFunctionData implements Serializable {
private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class); private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class);
/** Is this a strict mode function? */ /** Is this a strict mode function? */
public static final int IS_STRICT = 1 << 0; public static final int IS_STRICT = 1 << 0;
/** Is this a built-in function? */ /** Is this a built-in function? */
public static final int IS_BUILTIN = 1 << 1; public static final int IS_BUILTIN = 1 << 1;
/** Is this a constructor function? */ /** Is this a constructor function? */
public static final int IS_CONSTRUCTOR = 1 << 2; public static final int IS_CONSTRUCTOR = 1 << 2;
/** Does this function expect a callee argument? */ /** Does this function expect a callee argument? */
public static final int NEEDS_CALLEE = 1 << 3; public static final int NEEDS_CALLEE = 1 << 3;
/** Does this function make use of the this-object argument? */ /** Does this function make use of the this-object argument? */
public static final int USES_THIS = 1 << 4; public static final int USES_THIS = 1 << 4;
/** Is this a variable arity function? */ /** Is this a variable arity function? */
public static final int IS_VARIABLE_ARITY = 1 << 5; public static final int IS_VARIABLE_ARITY = 1 << 5;
/** Is this a object literal property getter or setter? */
public static final int IS_PROPERTY_ACCESSOR = 1 << 6;
/** Flag for strict or built-in functions */ /** Flag for strict or built-in functions */
public static final int IS_STRICT_OR_BUILTIN = IS_STRICT | IS_BUILTIN; public static final int IS_STRICT_OR_BUILTIN = IS_STRICT | IS_BUILTIN;
/** Flag for built-in constructors */ /** Flag for built-in constructors */
public static final int IS_BUILTIN_CONSTRUCTOR = IS_BUILTIN | IS_CONSTRUCTOR; public static final int IS_BUILTIN_CONSTRUCTOR = IS_BUILTIN | IS_CONSTRUCTOR;
/** Flag for strict constructors */
public static final int IS_STRICT_CONSTRUCTOR = IS_STRICT | IS_CONSTRUCTOR;
private static final long serialVersionUID = 4252901245508769114L; private static final long serialVersionUID = 4252901245508769114L;
...@@ -122,6 +122,10 @@ public abstract class ScriptFunctionData implements Serializable { ...@@ -122,6 +122,10 @@ public abstract class ScriptFunctionData implements Serializable {
return (flags & IS_VARIABLE_ARITY) != 0; return (flags & IS_VARIABLE_ARITY) != 0;
} }
final boolean isPropertyAccessor() {
return (flags & IS_PROPERTY_ACCESSOR) != 0;
}
/** /**
* Used from e.g. Native*$Constructors as an explicit call. TODO - make arity immutable and final * Used from e.g. Native*$Constructors as an explicit call. TODO - make arity immutable and final
* @param arity new arity * @param arity new arity
......
...@@ -70,7 +70,6 @@ final class ScriptLoader extends NashornLoader { ...@@ -70,7 +70,6 @@ final class ScriptLoader extends NashornLoader {
* @return Installed class. * @return Installed class.
*/ */
synchronized Class<?> installClass(final String name, final byte[] data, final CodeSource cs) { synchronized Class<?> installClass(final String name, final byte[] data, final CodeSource cs) {
Objects.requireNonNull(cs); return defineClass(name, data, 0, data.length, Objects.requireNonNull(cs));
return defineClass(name, data, 0, data.length, cs);
} }
} }
...@@ -2582,7 +2582,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable { ...@@ -2582,7 +2582,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
final int callCount = callType.parameterCount(); final int callCount = callType.parameterCount();
final boolean isCalleeVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray(); final boolean isCalleeVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray();
final boolean isCallerVarArg = callerVarArg != null ? callerVarArg.booleanValue() : callCount > 0 && final boolean isCallerVarArg = callerVarArg != null ? callerVarArg : callCount > 0 &&
callType.parameterType(callCount - 1).isArray(); callType.parameterType(callCount - 1).isArray();
if (isCalleeVarArg) { if (isCalleeVarArg) {
......
...@@ -39,8 +39,10 @@ import java.io.StringReader; ...@@ -39,8 +39,10 @@ import java.io.StringReader;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import jdk.nashorn.internal.objects.NativeArray;
/** /**
* Global functions supported only in scripting mode. * Global functions supported only in scripting mode.
...@@ -54,7 +56,7 @@ public final class ScriptingFunctions { ...@@ -54,7 +56,7 @@ public final class ScriptingFunctions {
public static final MethodHandle READFULLY = findOwnMH("readFully", Object.class, Object.class, Object.class); public static final MethodHandle READFULLY = findOwnMH("readFully", Object.class, Object.class, Object.class);
/** Handle to implementation of {@link ScriptingFunctions#exec} - Nashorn extension */ /** Handle to implementation of {@link ScriptingFunctions#exec} - Nashorn extension */
public static final MethodHandle EXEC = findOwnMH("exec", Object.class, Object.class, Object.class, Object.class); public static final MethodHandle EXEC = findOwnMH("exec", Object.class, Object.class, Object[].class);
/** EXEC name - special property used by $EXEC API. */ /** EXEC name - special property used by $EXEC API. */
public static final String EXEC_NAME = "$EXEC"; public static final String EXEC_NAME = "$EXEC";
...@@ -71,7 +73,8 @@ public final class ScriptingFunctions { ...@@ -71,7 +73,8 @@ public final class ScriptingFunctions {
/** Names of special properties used by $ENV API. */ /** Names of special properties used by $ENV API. */
public static final String ENV_NAME = "$ENV"; public static final String ENV_NAME = "$ENV";
private static final String PWD_NAME = "PWD"; /** Name of the environment variable for the current working directory. */
public static final String PWD_NAME = "PWD";
private ScriptingFunctions() { private ScriptingFunctions() {
} }
...@@ -125,19 +128,32 @@ public final class ScriptingFunctions { ...@@ -125,19 +128,32 @@ public final class ScriptingFunctions {
* Nashorn extension: exec a string in a separate process. * Nashorn extension: exec a string in a separate process.
* *
* @param self self reference * @param self self reference
* @param string string to execute * @param args string to execute, input and additional arguments, to be appended to {@code string}. Additional arguments can be passed as
* @param input input * either one JavaScript array, whose elements will be converted to strings; or as a sequence of
* varargs, each of which will be converted to a string.
* *
* @return output string from the request * @return output string from the request
*
* @throws IOException if any stream access fails * @throws IOException if any stream access fails
* @throws InterruptedException if execution is interrupted * @throws InterruptedException if execution is interrupted
*/ */
public static Object exec(final Object self, final Object string, final Object input) throws IOException, InterruptedException { public static Object exec(final Object self, final Object... args) throws IOException, InterruptedException {
// Current global is need to fetch additional inputs and for additional results. // Current global is need to fetch additional inputs and for additional results.
final ScriptObject global = Context.getGlobal(); final ScriptObject global = Context.getGlobal();
final Object string = args.length > 0? args[0] : UNDEFINED;
final Object input = args.length > 1? args[1] : UNDEFINED;
final Object[] argv = (args.length > 2)? Arrays.copyOfRange(args, 2, args.length) : ScriptRuntime.EMPTY_ARRAY;
// Assemble command line, process additional arguments.
final List<String> cmdLine = tokenizeString(JSType.toString(string));
final Object[] additionalArgs = argv.length == 1 && argv[0] instanceof NativeArray ?
((NativeArray) argv[0]).asObjectArray() :
argv;
for (Object arg : additionalArgs) {
cmdLine.add(JSType.toString(arg));
}
// Set up initial process. // Set up initial process.
final ProcessBuilder processBuilder = new ProcessBuilder(tokenizeCommandLine(JSType.toString(string))); final ProcessBuilder processBuilder = new ProcessBuilder(cmdLine);
// Current ENV property state. // Current ENV property state.
final Object env = global.get(ENV_NAME); final Object env = global.get(ENV_NAME);
...@@ -237,23 +253,22 @@ public final class ScriptingFunctions { ...@@ -237,23 +253,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 +280,13 @@ public final class ScriptingFunctions { ...@@ -265,13 +280,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;
} }
} }
...@@ -910,14 +910,16 @@ public final class Source implements Loggable { ...@@ -910,14 +910,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) {
start = 2; if (bytes.length > 3 && bytes[2] == 0 && bytes[3] == 0) {
cs = StandardCharsets.UTF_16LE; start = 4;
cs = Charset.forName("UTF-32LE");
} else {
start = 2;
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");
......
/* /*
* 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
...@@ -54,23 +54,28 @@ import jdk.nashorn.internal.runtime.ScriptFunction; ...@@ -54,23 +54,28 @@ import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptObject;
/** /**
* <p>A factory class that generates adapter classes. Adapter classes allow implementation of Java interfaces and * A factory class that generates adapter classes. Adapter classes allow
* extending of Java classes from JavaScript. For every combination of a superclass to extend and interfaces to * implementation of Java interfaces and extending of Java classes from
* implement (collectively: "original types"), exactly one adapter class is generated that extends the specified * JavaScript. For every combination of a superclass to extend and interfaces to
* superclass and implements the specified interfaces. (But see the discussion of class-based overrides for exceptions.) * implement (collectively: "original types"), exactly one adapter class is
* </p><p> * generated that extends the specified superclass and implements the specified
* The adapter class is generated in a new secure class loader that inherits Nashorn's protection domain, and has either * interfaces. (But see the discussion of class-based overrides for exceptions.)
* one of the original types' class loader or the Nashorn's class loader as its parent - the parent class loader * <p>
* is chosen so that all the original types and the Nashorn core classes are visible from it (as the adapter will have * The adapter class is generated in a new secure class loader that inherits
* constant pool references to ScriptObject and ScriptFunction classes). In case none of the candidate class loaders has * Nashorn's protection domain, and has either one of the original types' class
* visibility of all the required types, an error is thrown. The class uses {@link JavaAdapterBytecodeGenerator} to * loader or the Nashorn's class loader as its parent - the parent class loader
* generate the adapter class itself; see its documentation for details about the generated class. * is chosen so that all the original types and the Nashorn core classes are
* </p><p> * visible from it (as the adapter will have constant pool references to
* You normally don't use this class directly, but rather either create adapters from script using * ScriptObject and ScriptFunction classes). In case none of the candidate class
* {@link jdk.nashorn.internal.objects.NativeJava#extend(Object, Object...)}, using the {@code new} operator on abstract classes and interfaces (see * loaders has visibility of all the required types, an error is thrown. The
* {@link jdk.nashorn.internal.objects.NativeJava#type(Object, Object)}), or implicitly when passing script functions to Java methods expecting SAM * class uses {@link JavaAdapterBytecodeGenerator} to generate the adapter class
* types. * itself; see its documentation for details about the generated class.
* </p> * <p>
* You normally don't use this class directly, but rather either create adapters
* from script using {@link jdk.nashorn.internal.objects.NativeJava#extend(Object, Object...)},
* using the {@code new} operator on abstract classes and interfaces (see
* {@link jdk.nashorn.internal.objects.NativeJava#type(Object, Object)}), or
* implicitly when passing script functions to Java methods expecting SAM types.
*/ */
@SuppressWarnings("javadoc") @SuppressWarnings("javadoc")
...@@ -93,25 +98,39 @@ public final class JavaAdapterFactory { ...@@ -93,25 +98,39 @@ public final class JavaAdapterFactory {
}; };
/** /**
* Returns an adapter class for the specified original types. The adapter class extends/implements the original * Returns an adapter class for the specified original types. The adapter
* class/interfaces. * class extends/implements the original class/interfaces.
* @param types the original types. The caller must pass at least one Java type representing either a public *
* interface or a non-final public class with at least one public or protected constructor. If more than one type is * @param types the original types. The caller must pass at least one Java
* specified, at most one can be a class and the rest have to be interfaces. The class can be in any position in the * type representing either a public interface or a non-final public
* array. Invoking the method twice with exactly the same types in the same order will return the same adapter * class with at least one public or protected constructor. If more
* class, any reordering of types or even addition or removal of redundant types (i.e. interfaces that other types * than one type is specified, at most one can be a class and the
* in the list already implement/extend, or {@code java.lang.Object} in a list of types consisting purely of * rest have to be interfaces. The class can be in any position in
* interfaces) will result in a different adapter class, even though those adapter classes are functionally * the array. Invoking the method twice with exactly the same types
* identical; we deliberately don't want to incur the additional processing cost of canonicalizing type lists. * in the same order will return the same adapter class, any
* @param classOverrides a JavaScript object with functions serving as the class-level overrides and * reordering of types or even addition or removal of redundant types
* implementations. These overrides are defined for all instances of the class, and can be further overridden on a * (i.e., interfaces that other types in the list already
* per-instance basis by passing additional objects in the constructor. * implement/extend, or {@code java.lang.Object} in a list of types
* @param lookup the lookup object identifying the caller class. The generated adapter class will have the * consisting purely of interfaces) will result in a different
* protection domain of the caller class iff the lookup object is full-strength, otherwise it will be completely * adapter class, even though those adapter classes are functionally
* unprivileged. * identical; we deliberately don't want to incur the additional
* @return an adapter class. See this class' documentation for details on the generated adapter class. * processing cost of canonicalizing type lists.
* @throws ECMAException with a TypeError if the adapter class can not be generated because the original class is * @param classOverrides a JavaScript object with functions serving as the
* final, non-public, or has no public or protected constructors. * class-level overrides and implementations. These overrides are
* defined for all instances of the class, and can be further
* overridden on a per-instance basis by passing additional objects
* in the constructor.
* @param lookup the lookup object identifying the caller class. The
* generated adapter class will have the protection domain of the
* caller class iff the lookup object is full-strength, otherwise it
* will be completely unprivileged.
*
* @return an adapter class. See this class' documentation for details on
* the generated adapter class.
*
* @throws ECMAException with a TypeError if the adapter class can not be
* generated because the original class is final, non-public, or has
* no public or protected constructors.
*/ */
public static StaticClass getAdapterClassFor(final Class<?>[] types, final ScriptObject classOverrides, final MethodHandles.Lookup lookup) { public static StaticClass getAdapterClassFor(final Class<?>[] types, final ScriptObject classOverrides, final MethodHandles.Lookup lookup) {
return getAdapterClassFor(types, classOverrides, getProtectionDomain(lookup)); return getAdapterClassFor(types, classOverrides, getProtectionDomain(lookup));
...@@ -148,15 +167,23 @@ public final class JavaAdapterFactory { ...@@ -148,15 +167,23 @@ public final class JavaAdapterFactory {
} }
/** /**
* Returns a method handle representing a constructor that takes a single argument of the source type (which, * Returns a method handle representing a constructor that takes a single
* really, should be one of {@link ScriptObject}, {@link ScriptFunction}, or {@link Object}, and returns an instance * argument of the source type (which, really, should be one of {@link ScriptObject},
* of the adapter for the target type. Used to implement the function autoconverters as well as the Nashorn's * {@link ScriptFunction}, or {@link Object}, and returns an instance of the
* JSR-223 script engine's {@code getInterface()} method. * adapter for the target type. Used to implement the function autoconverters
* @param sourceType the source type; should be either {@link ScriptObject}, {@link ScriptFunction}, or * as well as the Nashorn JSR-223 script engine's {@code getInterface()}
* {@link Object}. In case of {@code Object}, it will return a method handle that dispatches to either the script * method.
* object or function constructor at invocation based on the actual argument. *
* @param sourceType the source type; should be either {@link ScriptObject},
* {@link ScriptFunction}, or {@link Object}. In case of {@code Object},
* it will return a method handle that dispatches to either the script
* object or function constructor at invocation based on the actual
* argument.
* @param targetType the target type, for which adapter instances will be created * @param targetType the target type, for which adapter instances will be created
* @param lookup method handle lookup to use
*
* @return the constructor method handle. * @return the constructor method handle.
*
* @throws Exception if anything goes wrong * @throws Exception if anything goes wrong
*/ */
public static MethodHandle getConstructor(final Class<?> sourceType, final Class<?> targetType, final MethodHandles.Lookup lookup) throws Exception { public static MethodHandle getConstructor(final Class<?> sourceType, final Class<?> targetType, final MethodHandles.Lookup lookup) throws Exception {
...@@ -168,13 +195,18 @@ public final class JavaAdapterFactory { ...@@ -168,13 +195,18 @@ public final class JavaAdapterFactory {
} }
/** /**
* Returns whether an instance of the specified class/interface can be generated from a ScriptFunction. Returns true * Returns whether an instance of the specified class/interface can be
* iff: the adapter for the class/interface can be created, it is abstract (this includes interfaces), it has at * generated from a ScriptFunction. Returns {@code true} iff: the adapter
* least one abstract method, all the abstract methods share the same name, and it has a public or protected default * for the class/interface can be created, it is abstract (this includes
* constructor. Note that invoking this class will most likely result in the adapter class being defined in the JVM * interfaces), it has at least one abstract method, all the abstract
* if it hasn't been already. * methods share the same name, and it has a public or protected default
* constructor. Note that invoking this class will most likely result in the
* adapter class being defined in the JVM if it hasn't been already.
*
* @param clazz the inspected class * @param clazz the inspected class
* @return true iff an instance of the specified class/interface can be generated from a ScriptFunction. *
* @return {@code true} iff an instance of the specified class/interface can
* be generated from a ScriptFunction.
*/ */
static boolean isAutoConvertibleFromFunction(final Class<?> clazz) { static boolean isAutoConvertibleFromFunction(final Class<?> clazz) {
return getAdapterInfo(new Class<?>[] { clazz }).autoConvertibleFromFunction; return getAdapterInfo(new Class<?>[] { clazz }).autoConvertibleFromFunction;
...@@ -198,7 +230,9 @@ public final class JavaAdapterFactory { ...@@ -198,7 +230,9 @@ public final class JavaAdapterFactory {
/** /**
* For a given class, create its adapter class and associated info. * For a given class, create its adapter class and associated info.
*
* @param type the class for which the adapter is created * @param type the class for which the adapter is created
*
* @return the adapter info for the class. * @return the adapter info for the class.
*/ */
private static AdapterInfo createAdapterInfo(final Class<?>[] types, final ClassAndLoader definingClassAndLoader) { private static AdapterInfo createAdapterInfo(final Class<?>[] types, final ClassAndLoader definingClassAndLoader) {
...@@ -311,11 +345,14 @@ public final class JavaAdapterFactory { ...@@ -311,11 +345,14 @@ public final class JavaAdapterFactory {
} }
/** /**
* Choose between the passed class loader and the class loader that defines the ScriptObject class, based on which * Choose between the passed class loader and the class loader that defines the
* of the two can see the classes in both. * ScriptObject class, based on which of the two can see the classes in both.
* @param classAndLoader the loader and a representative class from it that will be used to add the generated *
* adapter to its ADAPTER_INFO_MAPS. * @param classAndLoader the loader and a representative class from it that will
* be used to add the generated adapter to its ADAPTER_INFO_MAPS.
*
* @return the class loader that sees both the specified class and Nashorn classes. * @return the class loader that sees both the specified class and Nashorn classes.
*
* @throws IllegalStateException if no such class loader is found. * @throws IllegalStateException if no such class loader is found.
*/ */
private static ClassLoader findCommonLoader(final ClassAndLoader classAndLoader) throws AdaptationException { private static ClassLoader findCommonLoader(final ClassAndLoader classAndLoader) throws AdaptationException {
......
...@@ -36,8 +36,7 @@ class JavaSuperAdapter { ...@@ -36,8 +36,7 @@ class JavaSuperAdapter {
private final Object adapter; private final Object adapter;
JavaSuperAdapter(final Object adapter) { JavaSuperAdapter(final Object adapter) {
Objects.requireNonNull(adapter); this.adapter = Objects.requireNonNull(adapter);
this.adapter = adapter;
} }
public Object getAdapter() { public Object getAdapter() {
......
...@@ -246,7 +246,7 @@ public class NashornBeansLinker implements GuardingDynamicLinker { ...@@ -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);
} }
} }
......
...@@ -136,6 +136,12 @@ public final class Options { ...@@ -136,6 +136,12 @@ public final class Options {
return options.toString(); return options.toString();
} }
private static void checkPropertyName(final String name) {
if (! Objects.requireNonNull(name).startsWith("nashorn.")) {
throw new IllegalArgumentException(name);
}
}
/** /**
* Convenience function for getting system properties in a safe way * Convenience function for getting system properties in a safe way
...@@ -144,11 +150,7 @@ public final class Options { ...@@ -144,11 +150,7 @@ public final class Options {
* @return true if set to true, default value if unset or set to false * @return true if set to true, default value if unset or set to false
*/ */
public static boolean getBooleanProperty(final String name, final Boolean defValue) { public static boolean getBooleanProperty(final String name, final Boolean defValue) {
Objects.requireNonNull(name); checkPropertyName(name);
if (!name.startsWith("nashorn.")) {
throw new IllegalArgumentException(name);
}
return AccessController.doPrivileged( return AccessController.doPrivileged(
new PrivilegedAction<Boolean>() { new PrivilegedAction<Boolean>() {
@Override @Override
...@@ -185,11 +187,7 @@ public final class Options { ...@@ -185,11 +187,7 @@ public final class Options {
* @return string property if set or default value * @return string property if set or default value
*/ */
public static String getStringProperty(final String name, final String defValue) { public static String getStringProperty(final String name, final String defValue) {
Objects.requireNonNull(name); checkPropertyName(name);
if (! name.startsWith("nashorn.")) {
throw new IllegalArgumentException(name);
}
return AccessController.doPrivileged( return AccessController.doPrivileged(
new PrivilegedAction<String>() { new PrivilegedAction<String>() {
@Override @Override
...@@ -212,11 +210,7 @@ public final class Options { ...@@ -212,11 +210,7 @@ public final class Options {
* @return integer property if set or default value * @return integer property if set or default value
*/ */
public static int getIntProperty(final String name, final int defValue) { public static int getIntProperty(final String name, final int defValue) {
Objects.requireNonNull(name); checkPropertyName(name);
if (! name.startsWith("nashorn.")) {
throw new IllegalArgumentException(name);
}
return AccessController.doPrivileged( return AccessController.doPrivileged(
new PrivilegedAction<Integer>() { new PrivilegedAction<Integer>() {
@Override @Override
......
...@@ -229,6 +229,11 @@ public final class EncodingHelper { ...@@ -229,6 +229,11 @@ public final class EncodingHelper {
/** /**
* @see <a href="http://www.geocities.jp/kosako3/oniguruma/doc/RE.txt">http://www.geocities.jp/kosako3/oniguruma/doc/RE.txt</a> * @see <a href="http://www.geocities.jp/kosako3/oniguruma/doc/RE.txt">http://www.geocities.jp/kosako3/oniguruma/doc/RE.txt</a>
*
* @param code code
* @param ctype ctype
*
* @return isCodeCType
*/ */
public static boolean isCodeCType(final int code, final int ctype) { public static boolean isCodeCType(final int code, final int ctype) {
int type; int type;
......
...@@ -57,10 +57,10 @@ public final class Syntax implements SyntaxProperties { ...@@ -57,10 +57,10 @@ public final class Syntax implements SyntaxProperties {
} }
} }
/** //
* OP // OP
* //
*/
protected boolean isOp(final int opm) { protected boolean isOp(final int opm) {
return (op & opm) != 0; return (op & opm) != 0;
} }
...@@ -189,11 +189,10 @@ public final class Syntax implements SyntaxProperties { ...@@ -189,11 +189,10 @@ public final class Syntax implements SyntaxProperties {
return isOp(OP_ESC_X_BRACE_HEX8); return isOp(OP_ESC_X_BRACE_HEX8);
} }
//
// OP2
//
/**
* OP
*
*/
protected boolean isOp2(final int opm) { protected boolean isOp2(final int opm) {
return (op2 & opm) != 0; return (op2 & opm) != 0;
} }
...@@ -278,10 +277,10 @@ public final class Syntax implements SyntaxProperties { ...@@ -278,10 +277,10 @@ public final class Syntax implements SyntaxProperties {
return isOp2(OP2_INEFFECTIVE_ESCAPE); return isOp2(OP2_INEFFECTIVE_ESCAPE);
} }
/** //
* BEHAVIOR // BEHAVIOR
* //
*/
protected boolean isBehavior(final int bvm) { protected boolean isBehavior(final int bvm) {
return (behavior & bvm) != 0; return (behavior & bvm) != 0;
} }
......
...@@ -174,4 +174,4 @@ io.error.cant.write=cannot write "{0}" ...@@ -174,4 +174,4 @@ io.error.cant.write=cannot write "{0}"
config.error.no.dest=no destination directory supplied config.error.no.dest=no destination directory supplied
uri.error.bad.uri=Bad URI "{0}" near offset {1} uri.error.bad.uri=Bad URI "{0}" near offset {1}
list.adapter.null.global=Attempted to create the adapter from outside a JavaScript execution context.
...@@ -439,7 +439,7 @@ public class Shell { ...@@ -439,7 +439,7 @@ public class Shell {
} }
try { try {
final Object res = context.eval(global, source, global, "<shell>", env._strict); final Object res = context.eval(global, source, global, "<shell>");
if (res != ScriptRuntime.UNDEFINED) { if (res != ScriptRuntime.UNDEFINED) {
err.println(JSType.toString(res)); err.println(JSType.toString(res));
} }
......
/*
* 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();');
/*
* 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-8066237: Fuzzing bug: Parser error on optimistic recompilation
*
* @test
* @run
*/
try {
(function() {
eval("get, a")
})();
fail("should have thrown");
} catch (e) {
Assert.assertTrue(e.name === "ReferenceError");
}
/*
* 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-8085802: Nashorn -nse option causes parse error on anonymous function definition
*
* @test
* @run
* @option -nse
*/
// even with -nse passed, the following should run fine
// because anonymous function is used as expression here
(function (){})()
/*
* 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-8087211: Indirect evals should be strict with -strict option
*
* @test
* @run
* @option -strict
*/
var global = this;
try {
// indirect eval call.
global.eval("x = 34;");
throw new Error("should have thrown ReferenceError");
} catch (e if e instanceof ReferenceError) {
}
function teststrict() {
"use strict";
// strict caller, indirect eval.
global.eval('public = 1;');
}
try {
teststrict();
throw new Error("should have thrown SyntaxError");
} catch (e if e instanceof SyntaxError) {
}
function testnonstrict() {
// non strict caller, indirect eval.
global.eval('public = 1;');
}
try {
testnonstrict();
throw new Error("should have thrown SyntaxError");
} catch (e if e instanceof SyntaxError) {
}
/*
* 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-8087211: Indirect evals should be strict with -strict option
* Make sure without -strict option, indirect evals are not strict.
*
* @test
* @run
*/
var global = this;
// indirect eval call.
global.eval("x = 34;");
function teststrict() {
"use strict";
// strict caller, indirect eval.
global.eval('public = 1;');
}
teststrict();
function testnonstrict() {
// non strict caller, indirect eval.
global.eval('public = 1;');
}
testnonstrict();
/*
* 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.
*/
/**
* Anonymous function statement should result in error in -nse
*
* @option -nse
* @test/compile-error
*/
function() {}
test/script/error/anon_func_stat_nse.js:31:8 Expected ident but found (
function() {}
^
/*
* 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.
*/
/**
* Backquote string should result in error with -nse even with -scripting
*
* @option -nse
* @option -scripting
* @test/compile-error
*/
`ls -l`;
test/script/error/backquote_string_nse.js:32:0 Expected an operand but found error
`ls -l`;
^
/*
* 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.
*/
/**
* conditional catch should result in error with -nse
*
* @option -nse
* @test/compile-error
*/
try {
func();
} catch (e if e instanceof ReferenceError) {
}
test/script/error/conditional_catch_nse.js:33:11 Expected ) but found if
} catch (e if e instanceof ReferenceError) {
^
test/script/error/conditional_catch_nse.js:34:0 Expected eof but found }
}
^
/*
* 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.
*/
/**
* Expression closures should result in error with -nse
*
* @option -nse
* @test/compile-error
*/
function square(x) x*x;
test/script/error/expr_closure_nse.js:31:19 Expected { but found x
function square(x) x*x;
^
/*
* 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.
*/
/**
* for..each should result in error with -nse
*
* @option -nse
* @test/compile-error
*/
for each (var x in [3, 454, 4]) {
print(x);
}
test/script/error/for_each_nse.js:31:4 Expected ( but found each
for each (var x in [3, 454, 4]) {
^
test/script/error/for_each_nse.js:33:0 Expected eof but found }
}
^
/*
* 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.
*/
/**
* Hash comment should result in error with -nse even with -scripting
*
* @option -nse
* @option -scripting
* @test/compile-error
*/
# this is a comment
test/script/error/hash_comment_nse.js:32:0 Expected an operand but found error
# this is a comment
^
/*
* 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.
*/
/**
* Heredoc string should result in error with -nse even with -scripting
*
* @option -nse
* @option -scripting
* @test/compile-error
*/
var str = <<EOF
This is a multiple line string
inside a heredoc
EOF;
test/script/error/heredoc_nse.js:32:10 Expected an operand but found <<
var str = <<EOF
^
test/script/error/heredoc_nse.js:33:5 Expected ; but found is
This is a multiple line string
^
test/script/error/heredoc_nse.js:34:7 Expected ; but found a
inside a heredoc
^
/*
* 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.
*/
/**
* Object literal outside 'new' should result in error in -nse
*
* @option -nse
* @test/compile-error
*/
var r = new java.lang.Runnable() {
run: function() { print("hello"); }
}
test/script/error/object_literal_in_new_nse.js:31:33 Expected ; but found {
var r = new java.lang.Runnable() {
^
test/script/error/object_literal_in_new_nse.js:32:15 Expected ident but found (
run: function() { print("hello"); }
^
test/script/error/object_literal_in_new_nse.js:32:36 Expected eof but found }
run: function() { print("hello"); }
^
/*
* 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-8080087: Nashorn $ENV.PWD is originally undefined
*
* This is to ensure that $ENV.PWD is correctly set on Windows as well as on all
* other platforms.
*
* @test
* @option -scripting
* @run
*/
if (typeof($ENV.PWD) === 'undefined') {
fail('$ENV.PWD is undefined')
}
/*
* 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);
}
@SuppressWarnings("unchecked")
private static List<Object> asList(final Object obj) {
assertJSObject(obj);
Assert.assertTrue(obj instanceof List);
return (List)obj;
}
@SuppressWarnings("unchecked")
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);
}
}
...@@ -31,10 +31,12 @@ import static org.testng.Assert.fail; ...@@ -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 { ...@@ -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();
}
} }
/*
* 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.test;
import static org.testng.Assert.assertEquals;
import java.util.Arrays;
import java.util.Deque;
import java.util.List;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
import org.testng.annotations.Test;
/**
* @bug 8081204
* @summary adding and removing elements to a ListAdapter outside of JS context should work.
*/
@SuppressWarnings("javadoc")
public class AddAndRemoveOnListAdapterOutsideOfJavaScriptContextTest {
@SuppressWarnings("unchecked")
private static <T> T getListAdapter() throws ScriptException {
final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
return (T)engine.eval("Java.to([1, 2, 3, 4], 'java.util.List')");
}
@Test
public void testInvokePush() throws ScriptException {
final Deque<Object> l = getListAdapter();
l.addLast(5);
assertEquals(l.size(), 5);
assertEquals(l.getLast(), 5);
assertEquals(l.getFirst(), 1);
}
@Test
public void testPop() throws ScriptException {
final Deque<Object> l = getListAdapter();
assertEquals(l.removeLast(), 4);
assertEquals(l.size(), 3);
assertEquals(l.getLast(), 3);
}
@Test
public void testUnshift() throws ScriptException {
final Deque<Object> l = getListAdapter();
l.addFirst(0);
assertEquals(l.getFirst(), 0);
assertEquals(l.getLast(), 4);
assertEquals(l.size(), 5);
}
@Test
public void testShift() throws ScriptException {
final Deque<Object> l = getListAdapter();
l.removeFirst();
assertEquals(l.getFirst(), 2);
assertEquals(l.getLast(), 4);
assertEquals(l.size(), 3);
}
@Test
public void testSpliceAdd() throws ScriptException {
final List<Object> l = getListAdapter();
assertEquals(l, Arrays.asList(1, 2, 3, 4));
l.add(2, "foo");
assertEquals(l, Arrays.asList(1, 2, "foo", 3, 4));
}
@Test
public void testSpliceRemove() throws ScriptException {
final List<Object> l = getListAdapter();
assertEquals(l, Arrays.asList(1, 2, 3, 4));
l.remove(2);
assertEquals(l, Arrays.asList(1, 2, 4));
}
}
...@@ -225,7 +225,7 @@ public final class TestFinder { ...@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册