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

Merge

......@@ -72,14 +72,11 @@ after which you can view the generated documentation at dist/javadoc/index.html.
- Running tests
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
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:
Once TestNG is properly installed, you can run the tests using:
cd make
ant clean test
......
<?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.
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" {
</target>
<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>
<!-- only to be invoked as dependency of "test" target -->
......@@ -460,7 +460,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</testng>
</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">
<echo message="Running test suite in OPTIMISTIC mode..."/>
......@@ -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."/>
</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}">
<include name="**/framework/*Test.class"/>
</fileset>
......@@ -518,7 +518,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</testng>
</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}">
<include name="**/framework/*Test.class"/>
</fileset>
......@@ -537,7 +537,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</testng>
</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}">
<include name="**/framework/*Test.class"/>
</fileset>
......@@ -561,7 +561,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<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 -->
<java classname="${parallel.test.runner}" dir="${basedir}" fork="true">
<jvmarg line="${ext.class.path}"/>
......@@ -580,7 +580,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<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 -->
<java classname="${parallel.test.runner}" dir="${basedir}"
failonerror="true"
......@@ -685,7 +685,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
</target>
<!-- 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 -->
<mkdir dir="${test.external.dir}"/>
......@@ -710,8 +710,8 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<!-- 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.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/showdown.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>
......@@ -721,12 +721,20 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
<!-- run all perf tests -->
<target name="perf" depends="externals, update-externals, sunspider, octane"/>
<!-- run all tests -->
<target name="exit-if-no-testng" depends="init, check-testng" unless="${testng.available}">
<fail message="Exiting.."/>
<!-- download and install testng.jar -->
<target name="get-testng" depends="prepare" unless="testng.available">
<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 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"/>
......
#
# 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.
#
# This code is free software; you can redistribute it and/or modify it
......@@ -77,8 +77,11 @@ fxshell.jar = ${dist.dir}/nashornfx.jar
# configuration for java flight recorder
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
file.reference.testng.jar=test/lib/testng.jar
file.reference.testng.jar=${test.lib}${file.separator}testng.jar
# Set testng verbose level
# 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=\
-fx \
${test.script.dir}${file.separator}jfx.js
file.reference.jemmyfx.jar=test${file.separator}lib${file.separator}JemmyFX.jar
file.reference.jemmycore.jar=test${file.separator}lib${file.separator}JemmyCore.jar
file.reference.jemmyawtinput.jar=test${file.separator}lib${file.separator}JemmyAWTInput.jar
file.reference.jemmyfx.jar=${test.lib}${file.separator}JemmyFX.jar
file.reference.jemmycore.jar=${test.lib}${file.separator}JemmyCore.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
testjfx.run.test.classpath=\
${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;
import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl;
/**
* The linker for {@link RelinkableCallSite} objects. Users of it (scripting frameworks and language runtimes) have to
* create a linker using the {@link DynamicLinkerFactory} and invoke its link method from the invokedynamic 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:
* The linker for {@link RelinkableCallSite} objects. Users of it (scripting
* frameworks and language runtimes) have to create a linker using the
* {@link DynamicLinkerFactory} and invoke its link method from the invokedynamic
* 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>
* class MyLanguageRuntime {
......@@ -123,19 +125,27 @@ import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl;
*
* Note how there are three components you will need to provide here:
* <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
* dynamic linker; you would simply not invoke the {@code setPrioritizedLinker} method on the factory, or even better,
* simply use {@link DefaultBootstrapper}.</li>
* <li>The performance of the programs can depend on your choice of the class to represent call sites. The above
* example used {@link MonomorphicCallSite}, but you might want to use {@link ChainedCallSite} instead. You'll need to
* 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>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
*
* <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 dynamic
* linker; you would simply not invoke the {@code setPrioritizedLinker} method
* on the factory, or even better, simply use {@link DefaultBootstrapper}.</li>
*
* <li>The performance of the programs can depend on your choice of the class to
* represent call sites. The above example used {@link MonomorphicCallSite}, but
* you might want to use {@link ChainedCallSite} instead. You'll need to
* 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>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>
*
* </ul>
*
* @author Attila Szegedi
......@@ -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
* mechanism of this linker. Next time the call site is invoked, it will be linked for the actual arguments it was
* invoked with.
* Links an invokedynamic call site. It will install a method handle into
* the call site that invokes the relinking mechanism of this linker. Next
* 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.
*
* @return the callSite, for easy call chaining.
*/
public <T extends RelinkableCallSite> T link(final T callSite) {
......@@ -189,10 +203,13 @@ public class DynamicLinker {
}
/**
* Returns the object representing the lower level linker services of this class that are normally exposed to
* individual language-specific linkers. While as a user of this class you normally only care about the
* {@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.
* Returns the object representing the lower level linker services of this
* class that are normally exposed to individual language-specific linkers.
* While as a user of this class you normally only care about the
* {@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.
*/
public LinkerServices getLinkerServices() {
......@@ -218,7 +235,9 @@ public class DynamicLinker {
*
* @param callSite the call site itself
* @param arguments arguments to the invocation
*
* @return return the method handle for the invocation
*
* @throws Exception rethrows any exception thrown by the linkers
*/
@SuppressWarnings("unused")
......@@ -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
* thread. The operation internally creates a Throwable object and inspects its stack trace, so it's potentially
* expensive. The recommended usage for it is in writing 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.
* Returns a stack trace element describing the location of the call site
* currently being linked on the current thread. The operation internally
* creates a Throwable object and inspects its stack trace, so it's
* potentially expensive. The recommended usage for it is in writing
* 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() {
final StackTraceElement[] trace = new Throwable().getStackTrace();
......@@ -290,8 +313,10 @@ public class DynamicLinker {
}
/**
* Deprecated because of not precise name.
* Deprecated because of imprecise name.
*
* @deprecated Use {@link #getLinkedCallSiteLocation()} instead.
*
* @return see non-deprecated method
*/
@Deprecated
......@@ -300,20 +325,26 @@ public class DynamicLinker {
}
/**
* Returns true if the frame represents {@code MethodHandleNatives.linkCallSite()}, the frame immediately on top of
* the call site frame when the call site is being linked for the first time.
* Returns {@code true} if the frame represents {@code MethodHandleNatives.linkCallSite()},
* 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
* @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) {
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
* site frame when the call site is being relinked (linked for second and subsequent times).
* Returns {@code true} if the frame represents {@code DynamicLinker.relink()},
* 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
* @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) {
return testFrame(frame, RELINK_METHOD_NAME, CLASS_NAME);
......
......@@ -28,6 +28,7 @@ package jdk.nashorn.api.scripting;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import jdk.nashorn.internal.runtime.JSONListAdapter;
import jdk.nashorn.internal.runtime.JSType;
/**
......@@ -282,6 +283,8 @@ public abstract class AbstractJSObject implements JSObject {
public static Object getDefaultValue(final JSObject jsobj, final Class<?> hint) {
if (jsobj instanceof AbstractJSObject) {
return ((AbstractJSObject)jsobj).getDefaultValue(hint);
} else if (jsobj instanceof JSONListAdapter) {
return ((JSONListAdapter)jsobj).getDefaultValue(hint);
}
return DefaultValueImpl.getDefaultValue(jsobj, hint);
}
......
......@@ -354,8 +354,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
}, CREATE_GLOBAL_ACC_CTXT);
nashornContext.initGlobal(newGlobal, this);
newGlobal.setScriptContext(ctxt);
nashornContext.initGlobal(newGlobal, this, ctxt);
return newGlobal;
}
......@@ -404,7 +403,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
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 boolean globalChanged = (oldGlobal != ctxtGlobal);
try {
......@@ -413,8 +412,13 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
final ScriptFunction script = mgcs.getFunction(ctxtGlobal);
final ScriptContext oldCtxt = ctxtGlobal.getScriptContext();
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) {
throwAsScriptException(e, ctxtGlobal);
throw new AssertionError("should not reach here");
......@@ -425,7 +429,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
}
private static Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
if (script == null) {
return null;
}
......@@ -436,8 +440,13 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
Context.setGlobal(ctxtGlobal);
}
final ScriptContext oldCtxt = ctxtGlobal.getScriptContext();
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) {
throwAsScriptException(e, ctxtGlobal);
throw new AssertionError("should not reach here");
......
......@@ -178,8 +178,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* denies {@code RuntimePermission("nashorn.setConfig")}
*/
public ScriptEngine getScriptEngine(final ClassFilter classFilter) {
Objects.requireNonNull(classFilter);
return newEngine(DEFAULT_OPTIONS, getAppClassLoader(), classFilter);
return newEngine(DEFAULT_OPTIONS, getAppClassLoader(), Objects.requireNonNull(classFilter));
}
/**
......@@ -193,8 +192,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* denies {@code RuntimePermission("nashorn.setConfig")}
*/
public ScriptEngine getScriptEngine(final String... args) {
Objects.requireNonNull(args);
return newEngine(args, getAppClassLoader(), null);
return newEngine(Objects.requireNonNull(args), getAppClassLoader(), null);
}
/**
......@@ -209,8 +207,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* denies {@code RuntimePermission("nashorn.setConfig")}
*/
public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader) {
Objects.requireNonNull(args);
return newEngine(args, appLoader, null);
return newEngine(Objects.requireNonNull(args), appLoader, null);
}
/**
......@@ -226,9 +223,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory {
* denies {@code RuntimePermission("nashorn.setConfig")}
*/
public ScriptEngine getScriptEngine(final String[] args, final ClassLoader appLoader, final ClassFilter classFilter) {
Objects.requireNonNull(args);
Objects.requireNonNull(classFilter);
return newEngine(args, appLoader, classFilter);
return newEngine(Objects.requireNonNull(args), appLoader, Objects.requireNonNull(classFilter));
}
private ScriptEngine newEngine(final String[] args, final ClassLoader appLoader, final ClassFilter classFilter) {
......
......@@ -47,6 +47,7 @@ import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.JSONListAdapter;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
......@@ -72,6 +73,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
private final ScriptObject sobj;
private final Global global;
private final boolean strict;
private final boolean jsonCompatible;
@Override
public boolean equals(final Object other) {
......@@ -110,9 +112,9 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
}
if (sobj instanceof ScriptFunction) {
final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
final Object self = globalChanged? wrap(thiz, oldGlobal) : thiz;
return wrap(ScriptRuntime.apply((ScriptFunction)sobj, unwrap(self, global), unwrapArray(modArgs, global)), global);
final Object[] modArgs = globalChanged? wrapArrayLikeMe(args, oldGlobal) : args;
final Object self = globalChanged? wrapLikeMe(thiz, oldGlobal) : thiz;
return wrapLikeMe(ScriptRuntime.apply((ScriptFunction)sobj, unwrap(self, global), unwrapArray(modArgs, global)));
}
throw new RuntimeException("not a function: " + toString());
......@@ -140,8 +142,8 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
}
if (sobj instanceof ScriptFunction) {
final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
return wrap(ScriptRuntime.construct((ScriptFunction)sobj, unwrapArray(modArgs, global)), global);
final Object[] modArgs = globalChanged? wrapArrayLikeMe(args, oldGlobal) : args;
return wrapLikeMe(ScriptRuntime.construct((ScriptFunction)sobj, unwrapArray(modArgs, global)));
}
throw new RuntimeException("not a constructor: " + toString());
......@@ -170,7 +172,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
return Context.getContext();
}
}, 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
final Object val = sobj.get(functionName);
if (val instanceof ScriptFunction) {
final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
return wrap(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
final Object[] modArgs = globalChanged? wrapArrayLikeMe(args, oldGlobal) : args;
return wrapLikeMe(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)));
} else if (val instanceof JSObject && ((JSObject)val).isFunction()) {
return ((JSObject)val).call(sobj, args);
}
......@@ -218,7 +220,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
Objects.requireNonNull(name);
return inGlobal(new Callable<Object>() {
@Override public Object call() {
return wrap(sobj.get(name), global);
return wrapLikeMe(sobj.get(name));
}
});
}
......@@ -227,7 +229,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
public Object getSlot(final int index) {
return inGlobal(new Callable<Object>() {
@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
@Override
public void removeMember(final String name) {
Objects.requireNonNull(name);
remove(name);
remove(Objects.requireNonNull(name));
}
@Override
public void setMember(final String name, final Object value) {
Objects.requireNonNull(name);
put(name, value);
put(Objects.requireNonNull(name), value);
}
@Override
......@@ -368,7 +368,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
while (iter.hasNext()) {
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));
}
......@@ -382,7 +382,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
checkKey(key);
return inGlobal(new Callable<Object>() {
@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
final boolean globalChanged = (oldGlobal != global);
return inGlobal(new Callable<Object>() {
@Override public Object call() {
final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global), strict), global));
final Object modValue = globalChanged? wrapLikeMe(value, oldGlobal) : value;
return translateUndefined(wrapLikeMe(sobj.put(key, unwrap(modValue, global), strict)));
}
});
}
@Override
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 boolean globalChanged = (oldGlobal != global);
inGlobal(new Callable<Object>() {
@Override public Object call() {
for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
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();
checkKey(key);
sobj.set(key, unwrap(modValue, global), getCallSiteFlags());
......@@ -449,7 +449,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
checkKey(key);
return inGlobal(new Callable<Object>() {
@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
final Iterator<Object> iter = sobj.valueIterator();
while (iter.hasNext()) {
values.add(translateUndefined(wrap(iter.next(), global)));
values.add(translateUndefined(wrapLikeMe(iter.next())));
}
return Collections.unmodifiableList(values);
......@@ -503,7 +503,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
public Object getProto() {
return inGlobal(new Callable<Object>() {
@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
public Object getOwnPropertyDescriptor(final String key) {
return inGlobal(new Callable<Object>() {
@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
* @return wrapped/converted object
*/
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) {
return homeGlobal instanceof Global ? new ScriptObjectMirror((ScriptObject)obj, (Global)homeGlobal) : obj;
}
if(obj instanceof ConsString) {
if (!(homeGlobal instanceof Global)) {
return obj;
}
final ScriptObject sobj = (ScriptObject)obj;
final Global global = (Global)homeGlobal;
final ScriptObjectMirror mirror = new ScriptObjectMirror(sobj, global, jsonCompatible);
if (jsonCompatible && sobj.isArray()) {
return new JSONListAdapter(mirror, global);
}
return mirror;
} else if(obj instanceof ConsString) {
return obj.toString();
} 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;
}
/**
* 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.
*
......@@ -681,6 +741,8 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
if (obj instanceof ScriptObjectMirror) {
final ScriptObjectMirror mirror = (ScriptObjectMirror)obj;
return (mirror.global == homeGlobal)? mirror.sobj : obj;
} else if (obj instanceof JSONListAdapter) {
return ((JSONListAdapter)obj).unwrap(homeGlobal);
}
return obj;
......@@ -694,6 +756,10 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
* @return wrapped array
*/
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) {
return args;
}
......@@ -701,12 +767,16 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
final Object[] newArgs = new Object[args.length];
int index = 0;
for (final Object obj : args) {
newArgs[index] = wrap(obj, homeGlobal);
newArgs[index] = wrap(obj, homeGlobal, jsonCompatible);
index++;
}
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.
*
......@@ -748,12 +818,17 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
// package-privates below this.
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 global != null : "home Global is null";
this.sobj = sobj;
this.global = global;
this.strict = global.isStrictContext();
this.jsonCompatible = jsonCompatible;
}
// accessors for script engine
......@@ -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 {
* @throws NullPointerException if url is null
*/
public URLReader(final URL url, final Charset cs) {
Objects.requireNonNull(url);
this.url = url;
this.url = Objects.requireNonNull(url);
this.cs = cs;
}
......
......@@ -100,7 +100,6 @@ import jdk.nashorn.internal.runtime.Source;
* There is also a very nice debug interface that can emit formatted
* bytecodes that have been written. This is enabled by setting the
* environment "nashorn.codegen.debug" to true, or --log=codegen:{@literal <level>}
* <p>
*
* @see Compiler
*/
......@@ -144,7 +143,7 @@ public class ClassEmitter {
/**
* 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 cw ASM classwriter
......@@ -157,7 +156,8 @@ public class ClassEmitter {
}
/**
* Return the method names encountered
* Return the method names encountered.
*
* @return method names
*/
public Set<String> getMethodNames() {
......@@ -165,12 +165,13 @@ public class ClassEmitter {
}
/**
* Constructor
* Constructor.
*
* @param env script environment
* @param className name of class to weave
* @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) {
this(context, new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS));
......@@ -178,7 +179,7 @@ public class ClassEmitter {
}
/**
* Constructor from the compiler
* Constructor from the compiler.
*
* @param env Script environment
* @param sourceName Source name
......@@ -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.
*/
String getUnitClassName() {
......@@ -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
*/
public int getMethodCount() {
......@@ -233,7 +234,8 @@ public class ClassEmitter {
}
/**
* Get the clinit count
* Get the clinit count.
*
* @return clinit count
*/
public int getClinitCount() {
......@@ -241,7 +243,8 @@ public class ClassEmitter {
}
/**
* Get the init count
* Get the init count.
*
* @return init count
*/
public int getInitCount() {
......@@ -249,7 +252,8 @@ public class ClassEmitter {
}
/**
* Get the field count
* Get the field count.
*
* @return field count
*/
public int getFieldCount() {
......@@ -260,6 +264,7 @@ public class ClassEmitter {
* Convert a binary name to a package/class name.
*
* @param name Binary name.
*
* @return Package/class name.
*/
private static String pathName(final String name) {
......@@ -268,6 +273,7 @@ public class ClassEmitter {
/**
* Define the static fields common in all scripts.
*
* @param strictMode Should we generate this method in strict mode
*/
private void defineCommonStatics(final boolean strictMode) {
......@@ -284,8 +290,8 @@ public class ClassEmitter {
}
/**
* Define static utilities common needed in scripts. These are per compile unit
* and therefore have to be defined here and not in code gen.
* Define static utilities common needed in scripts. These are per compile
* unit and therefore have to be defined here and not in code gen.
*/
private void defineCommonUtilities() {
assert unitClassName != null;
......@@ -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.
*/
private void defineGetArrayMethod(final Class<?> clazz) {
......@@ -356,7 +364,9 @@ public class ClassEmitter {
/**
* Generate the name of a get array from constant pool method.
*
* @param clazz Name of array class.
*
* @return Method name.
*/
static String getArrayMethodName(final Class<?> clazz) {
......@@ -366,6 +376,7 @@ public class ClassEmitter {
/**
* Ensure a get constant method is issued for the class.
*
* @param clazz Class of constant.
*/
void needGetConstantMethod(final Class<?> clazz) {
......@@ -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 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) {
if (type.startsWith(scriptPrefix)) {
......@@ -393,14 +404,14 @@ public class ClassEmitter {
}
/**
* Call at beginning of class emission
* Call at beginning of class emission.
*/
public void begin() {
classStarted = true;
}
/**
* Call at end of class emission
* Call at end of class emission.
*/
public void end() {
assert classStarted : "class not started for " + unitClassName;
......@@ -424,7 +435,9 @@ public class ClassEmitter {
/**
* Disassemble an array of byte code.
*
* @param bytecode byte array representing bytecode
*
* @return disassembly as human readable string
*/
static String disassemble(final byte[] bytecode) {
......@@ -446,7 +459,7 @@ public class ClassEmitter {
}
/**
* Call back from MethodEmitter for method start
* Call back from MethodEmitter for method start.
*
* @see MethodEmitter
*
......@@ -458,7 +471,7 @@ public class ClassEmitter {
}
/**
* Call back from MethodEmitter for method end
* Call back from MethodEmitter for method end.
*
* @see MethodEmitter
*
......@@ -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 rtype return type of the method
......@@ -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 methodName name of method
......@@ -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 descriptor descriptor of method
......@@ -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 methodName name of method
......@@ -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
*
* @return method emitter to use for weaving this method
*/
MethodEmitter method(final FunctionNode functionNode) {
......@@ -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
*
* @return method emitter to use for weaving this method
*/
MethodEmitter restOfMethod(final FunctionNode functionNode) {
......@@ -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>
*/
......@@ -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
*/
......@@ -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
* @return method emitter to use for weaving <init>()V
......@@ -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 ptypes parameter types for the constructor
......@@ -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 fieldName name of field
......@@ -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 fieldName name of field
......@@ -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 fieldType type of field
......@@ -651,7 +667,8 @@ public class ClassEmitter {
* Return a bytecode array from this ClassEmitter. The ClassEmitter must
* 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() {
assert classEnded;
......@@ -663,13 +680,9 @@ public class ClassEmitter {
}
/**
* Abstraction for flags used in class emission
*
* We provide abstraction separating these from the underlying bytecode
* emitter.
*
* Flags are provided for method handles, protection levels, static/virtual
* fields/methods.
* Abstraction for flags used in class emission. We provide abstraction
* separating these from the underlying bytecode emitter. Flags are provided
* for method handles, protection levels, static/virtual fields/methods.
*/
static enum Flag {
/** method handle with static access */
......@@ -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
* @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) {
int v = 0;
......
......@@ -363,7 +363,7 @@ enum CompilationPhase {
//partial code generation
final FunctionNode newFunctionNode = transformFunction(fn, new ReplaceCompileUnits() {
@Override
CompileUnit getReplacement(CompileUnit original) {
CompileUnit getReplacement(final CompileUnit original) {
return map.get(original);
}
......
......@@ -122,8 +122,7 @@ public final class CompileUnit implements Comparable<CompileUnit>, Serializable
* @param clazz class with code for this compile unit
*/
void setCode(final Class<?> clazz) {
Objects.requireNonNull(clazz);
this.clazz = clazz;
this.clazz = Objects.requireNonNull(clazz);
// Revisit this - refactor to avoid null-ed out non-final fields
// null out emitter
this.classEmitter = null;
......
......@@ -101,7 +101,7 @@ final class SplitIntoFunctions extends NodeVisitor<BlockLexicalContext> {
public SplitIntoFunctions(final Compiler compiler) {
super(new BlockLexicalContext() {
@Override
protected Block afterSetStatements(Block block) {
protected Block afterSetStatements(final Block block) {
for(Statement stmt: block.getStatements()) {
assert !(stmt instanceof SplitNode);
}
......@@ -301,7 +301,7 @@ final class SplitIntoFunctions extends NodeVisitor<BlockLexicalContext> {
}
@Override
public boolean enterVarNode(VarNode varNode) {
public boolean enterVarNode(final VarNode varNode) {
if (!inSplitNode()) {
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -31,11 +31,13 @@ import jdk.nashorn.internal.runtime.Debug;
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
* methods to retrieve useful subsets of the context.
* A class that tracks the current lexical context of node visitation as a stack
* 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
* performance wise. None of the collection classes were optimal
* This is implemented with a primitive array and a stack pointer, because it
* really makes a difference performance-wise. None of the collection classes
* were optimal.
*/
public class LexicalContext {
private LexicalContextNode[] stack;
......@@ -79,6 +81,7 @@ public class LexicalContext {
* {@link Block#NEEDS_SCOPE} because it atomically also sets the
* {@link FunctionNode#HAS_SCOPE_BLOCK} flag on the block's containing
* function.
*
* @param block the block that needs to be marked as creating a scope.
*/
public void setBlockNeedsScope(final Block block) {
......@@ -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
*
* @return the flags for the node
*/
public int getFlags(final LexicalContextNode node) {
......@@ -112,8 +117,10 @@ public class LexicalContext {
/**
* 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
*
* @return body of function node
*/
public Block getFunctionBody(final FunctionNode functionNode) {
......@@ -126,15 +133,16 @@ public class LexicalContext {
}
/**
* Return all nodes in the LexicalContext
* @return all nodes
* @return all nodes in the LexicalContext.
*/
public Iterator<LexicalContextNode> getAllNodes() {
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.
*/
public FunctionNode getOutermostFunction() {
......@@ -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
*
* @return the node that was pushed
*/
public <T extends LexicalContextNode> T push(final T node) {
......@@ -168,25 +180,28 @@ public class LexicalContext {
/**
* Is the context empty?
* @return true if empty
*
* @return {@code true} if empty
*/
public boolean isEmpty() {
return sp == 0;
}
/**
* The depth of the lexical context
* @return depth
* @return the depth of the lexical context.
*/
public int size() {
return sp;
}
/**
* Pops the innermost block off the context and all nodes that has been contributed
* since it was put there
* Pops the innermost block off the context and all nodes that has been
* 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
*/
@SuppressWarnings("unchecked")
......@@ -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
* {@code NodeVisitor.leaveXxx()} method and only on the node being exited at the time. It is not mandatory to use,
* as {@link #pop(Node)} will apply the flags automatically, but this method can be used to apply them
* during the {@code leaveXxx()} method in case its logic depends on the value of the flags.
* @param node the node to apply the flags to. Must be the topmost node on the stack.
* Explicitly apply flags to the topmost element on the stack. This is only
* valid to use from a {@code NodeVisitor.leaveXxx()} method and only on the
* node being exited at the time. It is not mandatory to use, as
* {@link #pop(Node)} will apply the flags automatically, but this method
* 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)
*/
public <T extends LexicalContextNode & Flags<T>> T applyTopFlags(final T node) {
......@@ -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
*/
public LexicalContextNode peek() {
......@@ -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
* @return true if in the context
*
* @return {@code true} if in the context
*/
public boolean contains(final LexicalContextNode node) {
for (int i = 0; i < sp; i++) {
......@@ -242,6 +266,7 @@ public class LexicalContext {
*
* @param oldNode old node
* @param newNode new node
*
* @return the new node
*/
public LexicalContextNode replace(final LexicalContextNode oldNode, final LexicalContextNode newNode) {
......@@ -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.
*/
public Iterator<Block> getBlocks() {
......@@ -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.
*/
public Iterator<FunctionNode> getFunctions() {
......@@ -273,6 +302,7 @@ public class LexicalContext {
/**
* Get the parent block for the current lexical context block
*
* @return parent block
*/
public Block getParentBlock() {
......@@ -283,7 +313,9 @@ public class LexicalContext {
/**
* 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() {
assert stack[sp - 1] instanceof Block;
......@@ -294,21 +326,12 @@ public class LexicalContext {
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
*
* @return an iterator over all ancestors block of the given block.
*/
public Iterator<Block> getAncestorBlocks(final Block block) {
......@@ -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.
*
* @return an iterator over a block and all its ancestors.
*/
public Iterator<Block> getBlocks(final Block block) {
......@@ -352,7 +378,9 @@ public class LexicalContext {
/**
* Get the function for this block.
*
* @param block block for which to get function
*
* @return function for block
*/
public FunctionNode getFunction(final Block block) {
......@@ -373,7 +401,6 @@ public class LexicalContext {
}
/**
* Returns the innermost block in the context.
* @return the innermost block in the context.
*/
public Block getCurrentBlock() {
......@@ -381,7 +408,6 @@ public class LexicalContext {
}
/**
* Returns the innermost function in the context.
* @return the innermost function in the context.
*/
public FunctionNode getCurrentFunction() {
......@@ -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
* @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) {
final String name = symbol.getName();
......@@ -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
* @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) {
final String name = symbol.getName();
......@@ -433,7 +465,8 @@ public class LexicalContext {
/**
* Is the topmost lexical context element a function body?
* @return true if function body
*
* @return {@code true} if function body.
*/
public boolean isFunctionBody() {
return getParentBlock() == null;
......@@ -441,16 +474,20 @@ public class LexicalContext {
/**
* 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() {
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
* @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) {
final Iterator<FunctionNode> iter = new NodeIterator<>(FunctionNode.class);
......@@ -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
* scopes that need to be explicitly popped in order to perform a break or continue jump within the current bytecode
* method. For this reason, the method returns 0 if it encounters a {@code SplitNode} between the current location
* and the break/continue target.
* @param until node to stop counting at. Must be within the current function
* @return number of with scopes encountered in the context
* Count the number of scopes until a given node. Note that this method is
* solely used to figure out the number of scopes that need to be explicitly
* popped in order to perform a break or continue jump within the current
* bytecode method. For this reason, the method returns 0 if it encounters a
* {@code SplitNode} between the current location and the break/continue
* 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) {
assert until != null;
......@@ -500,16 +541,17 @@ public class LexicalContext {
}
/**
* Check whether the lexical context is currently inside a loop
* @return true if inside a loop
* Check whether the lexical context is currently inside a loop.
*
* @return {@code true} if inside a loop
*/
public boolean inLoop() {
return getCurrentLoop() != null;
}
/**
* Returns the loop header of the current loop, or null if not inside a loop
* @return loop header
* @return the loop header of the current loop, or {@code null} if not
* inside a loop.
*/
public LoopNode getCurrentLoop() {
final Iterator<LoopNode> iter = new NodeIterator<>(LoopNode.class, getCurrentFunction());
......@@ -518,9 +560,12 @@ public class LexicalContext {
/**
* 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
* @return closest breakable node
*
* @param labelName name of the label to search for. If {@code null}, the
* 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) {
if (labelName != null) {
......@@ -544,9 +589,12 @@ public class LexicalContext {
/**
* 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
* @return closest continue target node
*
* @param labelName label name to search for. If {@code null} the closest
* 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) {
if (labelName != null) {
......@@ -566,8 +614,10 @@ public class LexicalContext {
/**
* 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) {
for (final NodeIterator<TryNode> iter = new NodeIterator<>(TryNode.class); iter.hasNext(); ) {
......@@ -581,7 +631,9 @@ public class LexicalContext {
/**
* 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.
*/
public TryNode getTryNodeForInlinedFinally(final String labelName) {
......@@ -595,9 +647,11 @@ public class LexicalContext {
}
/**
* Check the lexical context for a given label node by name
* @param name name of the label
* @return LabelNode if found, null otherwise
* Check the lexical context for a given label node by name.
*
* @param name name of the label.
*
* @return LabelNode if found, {@code null} otherwise.
*/
public LabelNode findLabel(final String name) {
for (final Iterator<LabelNode> iter = new NodeIterator<>(LabelNode.class, getCurrentFunction()); iter.hasNext(); ) {
......@@ -610,10 +664,13 @@ public class LexicalContext {
}
/**
* Checks whether a given target is a jump destination that lies outside a given split node
* @param splitNode the split node
* @param target the target node
* @return true if target resides outside the split node
* Checks whether a given target is a jump destination that lies outside a
* given 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) {
for (int i = sp; i-- > 0;) {
......@@ -634,8 +691,10 @@ public class LexicalContext {
}
/**
* Checks whether the current context is inside a switch statement without explicit blocks (curly braces).
* @return true if in unprotected switch statement
* Checks whether the current context is inside a switch statement without
* explicit blocks (curly braces).
*
* @return {@code true} if in unprotected switch statement.
*/
public boolean inUnprotectedSwitchContext() {
for (int i = sp; i > 0; i--) {
......
......@@ -54,7 +54,7 @@ public final class SplitReturn extends Statement {
}
@Override
public void toString(StringBuilder sb, boolean printType) {
public void toString(final StringBuilder sb, final boolean printType) {
sb.append(":splitreturn;");
}
......
......@@ -122,7 +122,7 @@ public final class TryNode extends LexicalContextStatement implements JoinPredec
* @param visitor IR navigating visitor.
*/
@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)) {
// Need to do finallybody first for termination analysis. TODO still necessary?
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -1109,7 +1109,7 @@ public final class NashornTextifier extends Printer {
}
final String ex = catches.get(node);
if (ex != null) {
sb.append("*** CATCH: ").append(ex).append(" ***\n");
sb.append("*** CATCH: ").append(ex).append(" ***\\l");
}
sb.append(c);
sb.append("\"]\n");
......
......@@ -928,9 +928,11 @@ public final class Global extends ScriptObject implements Scope {
private final Context context;
// current ScriptContext to use - can be null.
private ScriptContext scontext;
private ThreadLocal<ScriptContext> scontext;
// current ScriptEngine associated - can be null.
private ScriptEngine engine;
// initial ScriptContext - can be null
private volatile ScriptContext initscontext;
// ES6 global lexical scope.
private final LexicalScope lexicalScope;
......@@ -940,10 +942,25 @@ public final class Global extends ScriptObject implements Scope {
/**
* Set the current script context
* @param scontext script context
* @param ctxt script context
*/
public void setScriptContext(final ScriptContext scontext) {
this.scontext = scontext;
public void setScriptContext(final ScriptContext ctxt) {
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
......@@ -988,9 +1005,7 @@ public final class Global extends ScriptObject implements Scope {
* @return the global singleton
*/
public static Global instance() {
final Global global = Context.getGlobal();
Objects.requireNonNull(global);
return global;
return Objects.requireNonNull(Context.getGlobal());
}
private static Global instanceFrom(final Object self) {
......@@ -1055,17 +1070,21 @@ public final class Global extends ScriptObject implements Scope {
* as well as our extension builtin objects like "Java", "JSAdapter" as properties
* 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 engine) {
public void initBuiltinObjects(final ScriptEngine eng, final ScriptContext ctxt) {
if (this.builtinObject != null) {
// already initialized, just return
return;
}
this.engine = engine;
init(engine);
this.engine = eng;
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 {
*/
public static Object __noSuchProperty__(final Object self, final Object name) {
final Global global = Global.instance();
final ScriptContext sctxt = global.scontext;
final ScriptContext sctxt = global.currentContext();
final String nameStr = name.toString();
if (sctxt != null) {
......@@ -1432,7 +1451,7 @@ public final class Global extends ScriptObject implements Scope {
* @return the result of eval
*/
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 {
* @param str Evaluated code
* @param callThis "this" to be passed to the evaluated code
* @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
*
......@@ -2485,7 +2504,7 @@ public final class Global extends ScriptObject implements Scope {
}
@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";
final ScriptEnvironment env = getContext().getEnv();
......@@ -2601,7 +2620,7 @@ public final class Global extends ScriptObject implements Scope {
addOwnProperty("$ARG", Attribute.NOT_ENUMERABLE, arguments);
}
if (engine != null) {
if (eng != null) {
// default file name
addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null);
// __noSuchProperty__ hook for ScriptContext search of missing variables
......@@ -2692,6 +2711,14 @@ public final class Global extends ScriptObject implements Scope {
// Retrieve current state of ENV variables.
final ScriptObject env = newObject();
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);
} else {
addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, UNDEFINED);
......@@ -2739,8 +2766,9 @@ public final class Global extends ScriptObject implements Scope {
}
private Object printImpl(final boolean newLine, final Object... objects) {
final ScriptContext sc = currentContext();
@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();
for (final Object obj : objects) {
......
......@@ -279,8 +279,8 @@ public final class NativeFunction {
sb.append("})");
final Global global = Global.instance();
return (ScriptFunction)Global.directEval(global, sb.toString(), global, "<function>", global.isStrictContext());
final Context context = global.getContext();
return (ScriptFunction)context.eval(global, sb.toString(), global, "<function>");
}
private static void checkFunctionParameters(final String params) {
......
......@@ -33,10 +33,12 @@ import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.support.TypeUtilities;
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.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
......@@ -656,4 +658,20 @@ public final class NativeJava {
public static Object _super(final Object self, final Object adapter) {
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -37,13 +37,15 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD)
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 "";
/**
* The arity of the function. By default computed from the method signature.
* Note that -1 means varargs. So, -2 is used as invalid arity.
* @return the arity of the function. By default computed from the method
* signature. Note that -1 means varargs. So, -2 is used as invalid
* arity.
*/
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -41,22 +41,23 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD)
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 "";
/**
* Attribute flags for this function.
* @return the attribute flags for this function.
*/
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;
/**
* where this function lives
* @return where this function lives.
*/
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -39,17 +39,17 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD)
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 "";
/**
* Attribute flags for this setter.
* @return the attribute flags for this setter.
*/
public int attributes() default DEFAULT_ATTRIBUTES;
/**
* Where this getter lives?
* @return where this getter lives.
*/
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -37,8 +37,8 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE)
public @interface ScriptClass {
/**
* Name of the script class. By default, the name is derived from
* the Java class name.
* @return the name of the script class. By default, the name is derived
* from the Java class name.
*/
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -39,17 +39,17 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD)
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 "";
/**
* Attribute flags for this setter.
* @return the attribute flags for this setter.
*/
public int attributes() default DEFAULT_ATTRIBUTES;
/**
* Where this setter lives?
* @return where this setter lives.
*/
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -33,10 +33,11 @@ import java.lang.invoke.MethodHandle;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
/**
* 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)
@Target(ElementType.METHOD)
......@@ -45,23 +46,23 @@ public @interface SpecializedFunction {
/**
* Functionality for testing if we are allowed to link a specialized
* 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
* 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.
*/
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"
*/
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 {
@Override
public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
......@@ -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
*/
public static Class<? extends LinkLogic> getEmptyLinkLogicClass() {
......@@ -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() {
return null;
}
/**
* Is this link logic class empty - i.e. no special linking logic
* supplied
* Is this link logic class empty - i.e., no special linking logic
* supplied?
*
* @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) {
return clazz == Empty.class;
}
/**
* Is this link logic instance empty - i.e. no special linking logic
* supplied
* Is this link logic instance empty - i.e., no special linking logic
* supplied?
*
* @return true if this link logic instance is empty
* @return {@code true} if this link logic instance is empty
*/
public boolean isEmpty() {
return false;
......@@ -121,7 +123,7 @@ public @interface SpecializedFunction {
* @param desc callsite descriptor
* @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);
......@@ -131,7 +133,7 @@ public @interface SpecializedFunction {
*
* @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) {
return true;
......@@ -139,13 +141,13 @@ public @interface SpecializedFunction {
/**
* Given a callsite, and optional arguments, do we need an extra guard
* for specialization to go through - this guard can be a function of
* the arguments too
* for specialization to go through? This guard can be a function of
* the arguments too.
*
* @param self receiver
* @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) {
return true;
......@@ -169,9 +171,9 @@ public @interface SpecializedFunction {
* @param self receiver
* @param desc callsite descriptor
* @param request link request
* @return true if we can link, false otherwise - that means we have to
* pick a non specialized target
*
* @return {@code true} if we can link, {@code false} otherwise - that
* means we have to pick a non specialized target
*/
public boolean checkLinkable(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
// check the link guard, if it says we can link, go ahead
......@@ -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,
* 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
* 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.
* "push"
......@@ -199,16 +201,18 @@ public @interface SpecializedFunction {
Class<?> linkLogic() default LinkLogic.Empty.class;
/**
* Is this a specialized constructor?
* @return whether this is a specialized constructor.
*/
boolean isConstructor() default false;
/**
* Can this function throw UnwarrantedOptimismExceptions? This works just
* like the normal functions, but we need the function to be
* Can this function throw {@link UnwarrantedOptimismException}s? This works
* just like the normal functions, but we need the function to be
* 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
* property
* property.
*
* @return whether this function can throw {@link UnwarrantedOptimismException}.
*/
boolean isOptimistic() default false;
}
......@@ -47,7 +47,8 @@ import jdk.nashorn.internal.scripts.JO;
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
*/
......@@ -70,9 +71,11 @@ public class JSONParser {
private static final int STATE_COMMA_PARSED = 2;
/**
* Constructor
* @param source the source
* @param global the global object
* Constructor.
*
* @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) {
this.source = source;
......@@ -82,8 +85,9 @@ public class JSONParser {
}
/**
* Implementation of the Quote(value) operation as defined in the ECMA script spec
* It wraps a String value in double quotes and escapes characters within in
* Implementation of the Quote(value) operation as defined in the ECMAscript
* spec. It wraps a String value in double quotes and escapes characters
* within.
*
* @param value string to quote
*
......
......@@ -2635,8 +2635,12 @@ loop:
name = getIdent();
verifyStrictIdent(name, "function name");
} else if (isStatement) {
// Nashorn extension: anonymous function statements
if (env._no_syntax_extensions) {
// Nashorn extension: anonymous function statements.
// 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);
}
}
......
/*
* 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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -222,9 +222,11 @@ public enum TokenType {
/**
* Determines if the token has greater precedence than other.
*
* @param other Compare token.
* @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) {
return other.precedence != 0 &&
......@@ -234,16 +236,16 @@ public enum TokenType {
/**
* 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) {
return kind == BINARY && (!noIn || this != IN) && precedence != 0;
}
/**
* Accessors.
*/
public int getLength() {
assert name != null : "Token name not set";
return name.length();
......
......@@ -528,8 +528,9 @@ final class CompiledFunction {
final int fnParamCountNoCallee = fnParamCount - thisThisIndex;
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".
for(int i = 1; i < minParams; ++i) {
// We must match all incoming parameters, including "this". "this" will usually be Object, but there
// 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 csType = csIsVarArg ? Type.OBJECT : Type.typeFor(other.parameterType(i + 1));
if(!fnType.isEquivalentTo(csType)) {
......
......@@ -66,6 +66,7 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Level;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
......@@ -667,12 +668,11 @@ public final class Context {
* @param string Evaluated code as a String
* @param callThis "this" to be passed to the evaluated code
* @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}
*/
public Object eval(final ScriptObject initialScope, final String string,
final Object callThis, final Object location, final boolean strict) {
return eval(initialScope, string, callThis, location, strict, false);
final Object callThis, final Object location) {
return eval(initialScope, string, callThis, location, false, false);
}
/**
......@@ -691,14 +691,16 @@ public final class Context {
final Object callThis, final Object location, final boolean strict, final boolean evalCall) {
final String file = location == UNDEFINED || location == null ? "<eval>" : location.toString();
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();
ScriptObject scope = initialScope;
// 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
// 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;
try {
......@@ -739,7 +741,8 @@ public final class Context {
if (directEval) {
evalThis = (callThis != UNDEFINED && callThis != null) || strictFlag ? callThis : global;
} else {
evalThis = global;
// either indirect evalCall or non-eval (Function, engine.eval, ScriptObjectMirror.eval..)
evalThis = callThis;
}
return ScriptRuntime.apply(func, evalThis);
......@@ -1095,16 +1098,17 @@ public final class Context {
*
* @param global the global
* @param engine the associated ScriptEngine instance, can be null
* @param ctxt the initial ScriptContext, can be null
* @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.
if (!env._compile_only) {
final Global oldGlobal = Context.getGlobal();
try {
Context.setGlobal(global);
// initialize global scope with builtin global objects
global.initBuiltinObjects(engine);
global.initBuiltinObjects(engine, ctxt);
} finally {
Context.setGlobal(oldGlobal);
}
......@@ -1120,7 +1124,7 @@ public final class Context {
* @return the initialized global scope object.
*/
public Global initGlobal(final Global global) {
return initGlobal(global, null);
return initGlobal(global, null, null);
}
/**
......
......@@ -156,7 +156,7 @@ final class DebuggerSupport {
final Context context = global.getContext();
try {
return context.eval(initialScope, string, callThis, ScriptRuntime.UNDEFINED, false);
return context.eval(initialScope, string, callThis, ScriptRuntime.UNDEFINED);
} catch (final Throwable ex) {
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;
import java.util.concurrent.Callable;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.objects.Global;
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
* {@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.
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 MethodHandle getPushInvoker() {
return getDynamicInvoker(PUSH, ADD_INVOKER_CREATOR);
}
// UNSHIFT adds to the start of the list
// UNSHIFT adds to the end of the list
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.
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 MethodHandle getPopInvoker() {
return getDynamicInvoker(POP, REMOVE_INVOKER_CREATOR);
}
// SHIFT removes from the to the start of the list
// SHIFT removes from the end of the list
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.
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 MethodHandle getSpliceAddInvoker() {
return getDynamicInvoker(SPLICE_ADD, SPLICE_ADD_INVOKER_CREATOR);
}
// 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 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 */
protected final JSObject obj;
final JSObject obj;
private final Global global;
// 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.global = global;
}
/**
......@@ -111,12 +98,13 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
* @return A ListAdapter wrapper object
*/
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) {
return (JSObject)ScriptObjectMirror.wrap(obj, Context.getGlobal());
return (JSObject)ScriptObjectMirror.wrap(obj, global);
} else if (obj instanceof JSObject) {
return (JSObject)obj;
}
......@@ -166,7 +154,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
@Override
public final void addFirst(final Object e) {
try {
getUnshiftInvoker().invokeExact(getFunction("unshift"), obj, e);
getDynamicInvoker(UNSHIFT, ADD_INVOKER_CREATOR).invokeExact(getFunction("unshift"), obj, e);
} catch(RuntimeException | Error ex) {
throw ex;
} catch(final Throwable t) {
......@@ -177,7 +165,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
@Override
public final void addLast(final Object e) {
try {
getPushInvoker().invokeExact(getFunction("push"), obj, e);
getDynamicInvoker(PUSH, ADD_INVOKER_CREATOR).invokeExact(getFunction("push"), obj, e);
} catch(RuntimeException | Error ex) {
throw ex;
} catch(final Throwable t) {
......@@ -195,7 +183,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
} else {
final int size = 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) {
addLast(e);
} else {
......@@ -287,7 +275,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
private Object invokeShift() {
try {
return getShiftInvoker().invokeExact(getFunction("shift"), obj);
return getDynamicInvoker(SHIFT, REMOVE_INVOKER_CREATOR).invokeExact(getFunction("shift"), obj);
} catch(RuntimeException | Error ex) {
throw ex;
} catch(final Throwable t) {
......@@ -297,7 +285,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
private Object invokePop() {
try {
return getPopInvoker().invokeExact(getFunction("pop"), obj);
return getDynamicInvoker(POP, REMOVE_INVOKER_CREATOR).invokeExact(getFunction("pop"), obj);
} catch(RuntimeException | Error ex) {
throw ex;
} catch(final Throwable t) {
......@@ -312,7 +300,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
private void invokeSpliceRemove(final int fromIndex, final int count) {
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) {
throw ex;
} catch(final Throwable t) {
......@@ -417,7 +405,7 @@ public final class ListAdapter extends AbstractList<Object> implements RandomAcc
};
}
private static MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) {
return Context.getGlobal().getDynamicInvoker(key, creator);
private MethodHandle getDynamicInvoker(final Object key, final Callable<MethodHandle> creator) {
return global.getDynamicInvoker(key, creator);
}
}
......@@ -342,6 +342,9 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
if (functionNode.isVarArg()) {
flags |= IS_VARIABLE_ARITY;
}
if (functionNode.getKind() == FunctionNode.Kind.GETTER || functionNode.getKind() == FunctionNode.Kind.SETTER) {
flags |= IS_PROPERTY_ACCESSOR;
}
return flags;
}
......@@ -382,7 +385,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
parser.setReparsedFunction(this);
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
// recompiling a single function, extract it from the program.
return (isProgram() ? program : extractFunctionFromScript(program)).setName(null, functionName);
......
......@@ -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);
/** 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? */
public static final int IS_BUILTIN = 1 << 1;
public static final int IS_BUILTIN = 1 << 1;
/** 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? */
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? */
public static final int USES_THIS = 1 << 4;
public static final int USES_THIS = 1 << 4;
/** 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 */
public static final int IS_STRICT_OR_BUILTIN = IS_STRICT | IS_BUILTIN;
/** Flag for built-in constructors */
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;
......@@ -122,6 +122,10 @@ public abstract class ScriptFunctionData implements Serializable {
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
* @param arity new arity
......
......@@ -70,7 +70,6 @@ final class ScriptLoader extends NashornLoader {
* @return Installed class.
*/
synchronized Class<?> installClass(final String name, final byte[] data, final CodeSource cs) {
Objects.requireNonNull(cs);
return defineClass(name, data, 0, data.length, cs);
return defineClass(name, data, 0, data.length, Objects.requireNonNull(cs));
}
}
......@@ -2582,7 +2582,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
final int callCount = callType.parameterCount();
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();
if (isCalleeVarArg) {
......
......@@ -39,8 +39,10 @@ import java.io.StringReader;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import jdk.nashorn.internal.objects.NativeArray;
/**
* Global functions supported only in scripting mode.
......@@ -54,7 +56,7 @@ public final class ScriptingFunctions {
public static final MethodHandle READFULLY = findOwnMH("readFully", Object.class, Object.class, Object.class);
/** 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. */
public static final String EXEC_NAME = "$EXEC";
......@@ -71,7 +73,8 @@ public final class ScriptingFunctions {
/** Names of special properties used by $ENV API. */
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() {
}
......@@ -125,19 +128,32 @@ public final class ScriptingFunctions {
* Nashorn extension: exec a string in a separate process.
*
* @param self self reference
* @param string string to execute
* @param input input
* @param args string to execute, input and additional arguments, to be appended to {@code string}. Additional arguments can be passed as
* 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
*
* @throws IOException if any stream access fails
* @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.
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.
final ProcessBuilder processBuilder = new ProcessBuilder(tokenizeCommandLine(JSType.toString(string)));
final ProcessBuilder processBuilder = new ProcessBuilder(cmdLine);
// Current ENV property state.
final Object env = global.get(ENV_NAME);
......@@ -237,23 +253,22 @@ public final class ScriptingFunctions {
}
/**
* Break an exec string into tokens, honoring quoted arguments and escaped
* spaces.
* Break a string into tokens, honoring quoted arguments and escaped 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
* constitute the command line.
* constitute the string.
* @throws IOException in case {@link StreamTokenizer#nextToken()} raises it.
*/
public static List<String> tokenizeCommandLine(final String execString) throws IOException {
final StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(execString));
public static List<String> tokenizeString(final String str) throws IOException {
final StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(str));
tokenizer.resetSyntax();
tokenizer.wordChars(0, 255);
tokenizer.whitespaceChars(0, ' ');
tokenizer.commentChar('#');
tokenizer.quoteChar('"');
tokenizer.quoteChar('\'');
final List<String> cmdList = new ArrayList<>();
final List<String> tokenList = new ArrayList<>();
final StringBuilder toAppend = new StringBuilder();
while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) {
final String s = tokenizer.sval;
......@@ -265,13 +280,13 @@ public final class ScriptingFunctions {
// omit trailing \, append space instead
toAppend.append(s.substring(0, s.length() - 1)).append(' ');
} else {
cmdList.add(toAppend.append(s).toString());
tokenList.add(toAppend.append(s).toString());
toAppend.setLength(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 {
start = 2;
cs = StandardCharsets.UTF_16BE;
} else if (bytes.length > 1 && bytes[0] == (byte) 0xFF && bytes[1] == (byte) 0xFE) {
start = 2;
cs = StandardCharsets.UTF_16LE;
if (bytes.length > 3 && bytes[2] == 0 && bytes[3] == 0) {
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) {
start = 3;
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) {
start = 4;
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.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -54,23 +54,28 @@ import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
/**
* <p>A factory class that generates adapter classes. Adapter classes allow implementation of Java interfaces and
* extending of Java classes from JavaScript. For every combination of a superclass to extend and interfaces to
* implement (collectively: "original types"), exactly one adapter class is generated that extends the specified
* superclass and implements the specified interfaces. (But see the discussion of class-based overrides for exceptions.)
* </p><p>
* The adapter class is generated in a new secure class loader that inherits Nashorn's protection domain, and has either
* one of the original types' class loader or the Nashorn's class loader as its parent - the parent class loader
* is chosen so that all the original types and the Nashorn core classes are visible from it (as the adapter will have
* constant pool references to ScriptObject and ScriptFunction classes). In case none of the candidate class loaders has
* visibility of all the required types, an error is thrown. The class uses {@link JavaAdapterBytecodeGenerator} to
* generate the adapter class 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.
* </p>
* A factory class that generates adapter classes. Adapter classes allow
* implementation of Java interfaces and extending of Java classes from
* JavaScript. For every combination of a superclass to extend and interfaces to
* implement (collectively: "original types"), exactly one adapter class is
* generated that extends the specified superclass and implements the specified
* interfaces. (But see the discussion of class-based overrides for exceptions.)
* <p>
* The adapter class is generated in a new secure class loader that inherits
* Nashorn's protection domain, and has either one of the original types' class
* loader or the Nashorn's class loader as its parent - the parent class loader
* is chosen so that all the original types and the Nashorn core classes are
* visible from it (as the adapter will have constant pool references to
* ScriptObject and ScriptFunction classes). In case none of the candidate class
* loaders has visibility of all the required types, an error is thrown. The
* class uses {@link JavaAdapterBytecodeGenerator} to generate the adapter class
* itself; see its documentation for details about the generated class.
* <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")
......@@ -93,25 +98,39 @@ public final class JavaAdapterFactory {
};
/**
* Returns an adapter class for the specified original types. The adapter 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
* specified, at most one can be a class and the rest have to be interfaces. The class can be in any position in the
* array. Invoking the method twice with exactly the same types in the same order will return the same adapter
* class, any reordering of types or even addition or removal of redundant types (i.e. interfaces that other types
* in the list already implement/extend, or {@code java.lang.Object} in a list of types consisting purely of
* interfaces) will result in a different adapter class, even though those adapter classes are functionally
* identical; we deliberately don't want to incur the additional processing cost of canonicalizing type lists.
* @param classOverrides a JavaScript object with functions serving as the 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.
* Returns an adapter class for the specified original types. The adapter
* 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 specified, at most one can be a class and the
* rest have to be interfaces. The class can be in any position in
* the array. Invoking the method twice with exactly the same types
* in the same order will return the same adapter class, any
* reordering of types or even addition or removal of redundant types
* (i.e., interfaces that other types in the list already
* implement/extend, or {@code java.lang.Object} in a list of types
* consisting purely of interfaces) will result in a different
* adapter class, even though those adapter classes are functionally
* identical; we deliberately don't want to incur the additional
* processing cost of canonicalizing type lists.
* @param classOverrides a JavaScript object with functions serving as the
* 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) {
return getAdapterClassFor(types, classOverrides, getProtectionDomain(lookup));
......@@ -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,
* really, should be one of {@link ScriptObject}, {@link ScriptFunction}, or {@link Object}, and returns an instance
* of the adapter for the target type. Used to implement the function autoconverters as well as the Nashorn's
* JSR-223 script engine's {@code getInterface()} method.
* @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.
* Returns a method handle representing a constructor that takes a single
* argument of the source type (which, really, should be one of {@link ScriptObject},
* {@link ScriptFunction}, or {@link Object}, and returns an instance of the
* adapter for the target type. Used to implement the function autoconverters
* as well as the Nashorn JSR-223 script engine's {@code getInterface()}
* method.
*
* @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 lookup method handle lookup to use
*
* @return the constructor method handle.
*
* @throws Exception if anything goes wrong
*/
public static MethodHandle getConstructor(final Class<?> sourceType, final Class<?> targetType, final MethodHandles.Lookup lookup) throws Exception {
......@@ -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
* iff: the adapter for the class/interface can be created, it is abstract (this includes interfaces), it has at
* least one abstract method, all the abstract 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.
* Returns whether an instance of the specified class/interface can be
* generated from a ScriptFunction. Returns {@code true} iff: the adapter
* for the class/interface can be created, it is abstract (this includes
* interfaces), it has at least one abstract method, all the abstract
* 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
* @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) {
return getAdapterInfo(new Class<?>[] { clazz }).autoConvertibleFromFunction;
......@@ -198,7 +230,9 @@ public final class JavaAdapterFactory {
/**
* For a given class, create its adapter class and associated info.
*
* @param type the class for which the adapter is created
*
* @return the adapter info for the class.
*/
private static AdapterInfo createAdapterInfo(final Class<?>[] types, final ClassAndLoader definingClassAndLoader) {
......@@ -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
* 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.
* Choose between the passed class loader and the class loader that defines the
* 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.
*
* @return the class loader that sees both the specified class and Nashorn classes.
*
* @throws IllegalStateException if no such class loader is found.
*/
private static ClassLoader findCommonLoader(final ClassAndLoader classAndLoader) throws AdaptationException {
......
......@@ -36,8 +36,7 @@ class JavaSuperAdapter {
private final Object adapter;
JavaSuperAdapter(final Object adapter) {
Objects.requireNonNull(adapter);
this.adapter = adapter;
this.adapter = Objects.requireNonNull(adapter);
}
public Object getAdapter() {
......
......@@ -246,7 +246,7 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
}
@Override
public MethodHandle filterInternalObjects(MethodHandle target) {
public MethodHandle filterInternalObjects(final MethodHandle target) {
return linkerServices.filterInternalObjects(target);
}
}
......
......@@ -136,6 +136,12 @@ public final class Options {
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
......@@ -144,11 +150,7 @@ public final class Options {
* @return true if set to true, default value if unset or set to false
*/
public static boolean getBooleanProperty(final String name, final Boolean defValue) {
Objects.requireNonNull(name);
if (!name.startsWith("nashorn.")) {
throw new IllegalArgumentException(name);
}
checkPropertyName(name);
return AccessController.doPrivileged(
new PrivilegedAction<Boolean>() {
@Override
......@@ -185,11 +187,7 @@ public final class Options {
* @return string property if set or default value
*/
public static String getStringProperty(final String name, final String defValue) {
Objects.requireNonNull(name);
if (! name.startsWith("nashorn.")) {
throw new IllegalArgumentException(name);
}
checkPropertyName(name);
return AccessController.doPrivileged(
new PrivilegedAction<String>() {
@Override
......@@ -212,11 +210,7 @@ public final class Options {
* @return integer property if set or default value
*/
public static int getIntProperty(final String name, final int defValue) {
Objects.requireNonNull(name);
if (! name.startsWith("nashorn.")) {
throw new IllegalArgumentException(name);
}
checkPropertyName(name);
return AccessController.doPrivileged(
new PrivilegedAction<Integer>() {
@Override
......
......@@ -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>
*
* @param code code
* @param ctype ctype
*
* @return isCodeCType
*/
public static boolean isCodeCType(final int code, final int ctype) {
int type;
......
......@@ -57,10 +57,10 @@ public final class Syntax implements SyntaxProperties {
}
}
/**
* OP
*
*/
//
// OP
//
protected boolean isOp(final int opm) {
return (op & opm) != 0;
}
......@@ -189,11 +189,10 @@ public final class Syntax implements SyntaxProperties {
return isOp(OP_ESC_X_BRACE_HEX8);
}
//
// OP2
//
/**
* OP
*
*/
protected boolean isOp2(final int opm) {
return (op2 & opm) != 0;
}
......@@ -278,10 +277,10 @@ public final class Syntax implements SyntaxProperties {
return isOp2(OP2_INEFFECTIVE_ESCAPE);
}
/**
* BEHAVIOR
*
*/
//
// BEHAVIOR
//
protected boolean isBehavior(final int bvm) {
return (behavior & bvm) != 0;
}
......
......@@ -174,4 +174,4 @@ io.error.cant.write=cannot write "{0}"
config.error.no.dest=no destination directory supplied
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 {
}
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) {
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;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import javax.script.SimpleScriptContext;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.api.scripting.URLReader;
import org.testng.Assert;
......@@ -778,4 +780,44 @@ public class ScopeTest {
throw new AssertionError("should have thrown NPE");
} 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 {
boolean explicitOptimistic = false;
String allContent = new String(Files.readAllBytes(testFile));
Iterator<String> scanner = ScriptingFunctions.tokenizeCommandLine(allContent).iterator();
Iterator<String> scanner = ScriptingFunctions.tokenizeString(allContent).iterator();
while (scanner.hasNext()) {
// TODO: Scan for /ref=file qualifiers, etc, to determine run
// behavior
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册