diff options
47 files changed, 1454 insertions, 199 deletions
@@ -266,6 +266,20 @@ f0b7b8b5e29a3a4e481fbeb9b346552c9819675e jdk8u5-b08 bc23b19e08eb1575663044902b6442ceaafa924f jdk8u5-b11 18b007062905dac9304605955a4b84eaf2a08553 jdk8u5-b12 e4fb85d69d6b33c9561b932ec5515f44c53c1017 jdk8u5-b13 +53cc5fda790e0f90dca53fb459c70517d76680bc jdk8u5-b31 +53cc5fda790e0f90dca53fb459c70517d76680bc jdk8u11-b01 +4dda2b1e51aa7977f53c261f983230fe505bbc3e jdk8u11-b02 +161f144c4e84037f655a2f6ebb0ba3057e8b18fa jdk8u11-b03 +2842beaa5db81731abe9d895181fbfceef720cf3 jdk8u11-b04 +7001e9f95b443a75e432205a29974c05b88e0fdc jdk8u11-b05 +daa414a4d8b712584d0818fab3fd31996e4cb645 jdk8u11-b06 +d9d482948b7c89161887b47e68e3367663d51b76 jdk8u11-b07 +a392513941025e2750acdcc45f9df2ec9080bde9 jdk8u11-b08 +dec6999877f39d3c17f7a092d8e2e17b676bb34b jdk8u11-b09 +d522ff5f53730cabd02c1863bb9d437c13bcc5e0 jdk8u11-b10 +3175dcbdd76ee9272276fa756247203dffb20596 jdk8u11-b11 +eea7f92c5fcc95310a6d946300ea47ac3e302cfe jdk8u11-b12 +b2c8eadc494bd32ed47d15d02cf942a8bd92c57f jdk8u11-b31 43a1183d2ab0ee3dbffd8bc47606e88dbe0c6116 jdk8u20-b02 9d69311869d513deecfebe767cc5f01502c9c01e jdk8u20-b03 e70dd55986e085185d976f2a78843a7d7eb87afd jdk8u20-b04 @@ -284,3 +298,12 @@ c720454d2435be052fd941a789ece9468d1e8f74 jdk8u20-b12 2f6add5fefb37cfeeb9a7745e7144f0b6d96bbea jdk8u20-b14 bb2d116675479fb2c9deaeeab6d4c41d41060693 jdk8u20-b15 c89a4945404ce80e26cb94c90fc13adad6b114bf jdk8u20-b16 +046bf6509a1f3fcf8c9c8b5d09beec0400f704d1 jdk8u20-b17 +847387339a561e50353c0805a54ec14eca256d2a jdk8u20-b18 +b047df215de40cb8a87ff1e2bac0b57bb9e2e121 jdk8u20-b19 +ed3439dca4a73a2dd4a284f3457f0af216a3eb55 jdk8u20-b20 +f2925491b61b22ac42f8c30ee9c6723ffa401a4c jdk8u20-b21 +5332595fe7ba2a1fc5564cc2689f378b04a56eb4 jdk8u20-b22 +ad36f9454ce38d78be39fc819902e1223765ee5e jdk8u20-b23 +f2925491b61b22ac42f8c30ee9c6723ffa401a4c jdk8u40-b00 +62468d841b842769d875bd97d10370585c296eb7 jdk8u40-b01 diff --git a/THIRD_PARTY_README b/THIRD_PARTY_README index ce018105..6d1c60f2 100644 --- a/THIRD_PARTY_README +++ b/THIRD_PARTY_README @@ -2,7 +2,7 @@ DO NOT TRANSLATE OR LOCALIZE. ----------------------------- %% This notice is provided with respect to ASM Bytecode Manipulation -Framework v5.0, which may be included with JRE 8, and JDK 8, and +Framework v5.0.3, which may be included with JRE 8, and JDK 8, and OpenJDK 8. --- begin of LICENSE --- @@ -1471,7 +1471,7 @@ source code repository. It is licensed under Mozilla Public License (MPL), version 2.0. The NSS libraries are supplied in executable form, built from unmodified -NSS source code labeled with the "NSS_3.13.1_RTM" release tag. +NSS source code labeled with the "NSS_3_16_RTM" HG tag. The NSS source code is available in the OpenJDK source code repository at: jdk/test/sun/security/pkcs11/nss/src @@ -3349,14 +3349,14 @@ info@urwpp.de or design@bigelowandholmes.com ------------------------------------------------------------------------------- -%% This notice is provided with respect to zlib v1.2.5, which may be included +%% This notice is provided with respect to zlib v1.2.8, which may be included with JRE 8, JDK 8, and OpenJDK 8. --- begin of LICENSE --- - version 1.2.5, July 18th, 2005 + version 1.2.8, April 28th, 2013 - Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -3382,11 +3382,11 @@ with JRE 8, JDK 8, and OpenJDK 8. ------------------------------------------------------------------------------- %% This notice is provided with respect to the following which may be -included with JRE 8, JDK 8, and OpenJDK 8, except where noted: +included with JRE 8, JDK 8, and OpenJDK 8. - Apache Commons Math 2.2 - Apache Derby 10.10.1.2 [included with JDK 8] - Apache Jakarta BCEL 5.2 + Apache Commons Math 3.2 + Apache Derby 10.10.1.3 + Apache Jakarta BCEL 5.1 Apache Jakarta Regexp 1.4 Apache Santuario XML Security for Java 1.5.4 Apache Xalan-Java 2.7.1 diff --git a/make/build.xml b/make/build.xml index 4d23f228..3b30a089 100644 --- a/make/build.xml +++ b/make/build.xml @@ -193,14 +193,16 @@ </jar> </target> - <target name="javadoc" depends="prepare"> - <javadoc destdir="${dist.javadoc.dir}" use="yes" overview="src/overview.html" windowtitle="${nashorn.product.name} ${nashorn.version}" additionalparam="-quiet" failonerror="true"> + <target name="javadoc" depends="jar"> + <javadoc destdir="${dist.javadoc.dir}" use="yes" overview="src/overview.html" + extdirs="${nashorn.ext.path}" windowtitle="${nashorn.product.name} ${nashorn.version}" + additionalparam="-quiet" failonerror="true"> <classpath> <pathelement location="${build.classes.dir}"/> </classpath> <fileset dir="${src.dir}" includes="**/*.java"/> <fileset dir="${jdk.asm.src.dir}" includes="**/*.java"/> - <link href="http://docs.oracle.com/javase/7/docs/api/"/> + <link href="http://docs.oracle.com/javase/8/docs/api/"/> <!-- The following tags are used only in ASM sources - just ignore these --> <tag name="label" description="label tag in ASM sources" enabled="false"/> <tag name="linked" description="linked tag in ASM sources" enabled="false"/> @@ -208,6 +210,19 @@ </javadoc> </target> + <!-- generate javadoc only for nashorn extension api classes --> + <target name="javadocapi" depends="jar"> + <javadoc destdir="${dist.javadoc.dir}" use="yes" extdirs="${nashorn.ext.path}" + windowtitle="${nashorn.product.name}" additionalparam="-quiet" failonerror="true"> + <classpath> + <pathelement location="${build.classes.dir}"/> + </classpath> + <fileset dir="${src.dir}" includes="jdk/nashorn/api/**/*.java"/> + <link href="http://docs.oracle.com/javase/8/docs/api/"/> + </javadoc> + </target> + + <!-- generate shell.html for shell tool documentation --> <target name="shelldoc" depends="jar"> <java classname="${nashorn.shell.tool}" dir="${basedir}" output="${dist.dir}/shell.html" failonerror="true" fork="true"> @@ -336,22 +351,58 @@ grant codeBase "file:/${basedir}/test/script/basic/classloader.js" { <echo message="WARNING: TestNG not available, will not run tests. Please copy testng.jar under test/lib directory."/> </target> - <target name="test" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available"> - <fileset id="test.classes" dir="${build.test.classes.dir}"> - <include name="**/api/javaaccess/*Test.class"/> - <include name="**/api/scripting/*Test.class"/> - <include name="**/codegen/*Test.class"/> - <include name="**/parser/*Test.class"/> - <include name="**/runtime/*Test.class"/> - <include name="**/runtime/regexp/*Test.class"/> - <include name="**/runtime/regexp/joni/*Test.class"/> - <include name="**/framework/*Test.class"/> + <!-- only to be invoked as dependency of "test" target --> + <target name="-test-classes-all" depends="jar" unless="test.class"> + <fileset id="test.classes" dir="${build.test.classes.dir}"> + <include name="**/api/javaaccess/*Test.class"/> + <include name="**/api/scripting/*Test.class"/> + <include name="**/codegen/*Test.class"/> + <include name="**/parser/*Test.class"/> + <include name="**/runtime/*Test.class"/> + <include name="**/runtime/regexp/*Test.class"/> + <include name="**/runtime/regexp/joni/*Test.class"/> + <include name="**/framework/*Test.class"/> + </fileset> + </target> + + <!-- only to be invoked as dependency of "test" target --> + <target name="-test-classes-single" depends="jar" if="test.class"> + <fileset id="test.classes" dir="${build.test.classes.dir}"> + <include name="${test.class}*"/> + </fileset> + </target> + + <!-- only to be invoked as dependency of "test" target --> + <target name="-test-nosecurity" unless="test.class"> + <fileset id="test.nosecurity.classes" dir="${build.test.classes.dir}"> + <include name="**/framework/ScriptTest.class"/> </fileset> + <testng outputdir="${build.nosecurity.test.results.dir}" classfilesetref="test.nosecurity.classes" + verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}"> + <jvmarg line="${ext.class.path}"/> + <jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx}"/> + <propertyset> + <propertyref prefix="nashorn."/> + </propertyset> + <propertyset> + <propertyref prefix="test-sys-prop-no-security."/> + <mapper from="test-sys-prop-no-security.*" to="*" type="glob"/> + </propertyset> + <classpath> + <pathelement path="${run.test.classpath}"/> + </classpath> + </testng> + </target> + <!-- only to be invoked as dependency of "test" target --> + <target name="-test-security"> + <delete dir="${build.dir}/nashorn_code_cache"/> + <property name="debug.test.jvmargs" value=""/> <testng outputdir="${build.test.results.dir}" classfilesetref="test.classes" verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}"> <jvmarg line="${ext.class.path}"/> <jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs}"/> + <jvmarg line="${debug.test.jvmargs}"/> <propertyset> <propertyref prefix="test-sys-prop."/> <mapper from="test-sys-prop.*" to="*" type="glob"/> @@ -363,6 +414,8 @@ grant codeBase "file:/${basedir}/test/script/basic/classloader.js" { </testng> </target> + <target name="test" depends="jar, -test-classes-all,-test-classes-single, check-testng, check-external-tests, compile-test, generate-policy-file, -test-security, -test-nosecurity" if="testng.available"/> + <target name="test-basicparallel" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file"> <!-- use just build.test.classes.dir to avoid referring to TestNG --> <java classname="${parallel.test.runner}" dir="${basedir}" classpath="${build.test.classes.dir}" failonerror="true" fork="true"> diff --git a/make/nbproject/ide-file-targets.xml b/make/nbproject/ide-file-targets.xml index cb017bb2..00a06351 100644 --- a/make/nbproject/ide-file-targets.xml +++ b/make/nbproject/ide-file-targets.xml @@ -22,38 +22,14 @@ questions. --> <project basedir=".." name="nashorn-IDE"> - <property file="nbproject/nbjdk.properties"/> - <property location="${netbeans.user}/build.properties" name="user.properties.file"/> - <property file="${user.properties.file}"/> - <import file="jdk.xml"/> - <import file="${basedir}/build-init.xml"/> - <!-- TODO: edit the following target according to your needs --> - <!-- (more info: http://www.netbeans.org/kb/articles/freeform-config.html#runsingle) --> - <target depends="-jdk-init, init" name="debug-selected-file-in-src"> - <fail unless="debug.class">Must set property 'debug.class'</fail> - <ant antfile="build.xml" inheritall="false" target="jar"/> + <target name="debug-selected-file-in-src"> + <fail unless="test.class">Must set property 'debug.class'</fail> <nbjpdastart addressproperty="jpda.address" name="nashorn" transport="dt_socket"> <classpath path="${run.test.classpath}"/> </nbjpdastart> - <java classname="${debug.class}" fork="false"> - <classpath path="${run.test.classpath}"/> - <jvmarg line="${boot.class.path}"/> - <jvmarg value="-Xdebug"/> - <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/> - <jvmarg line="${run.test.jvmargs}"/> - <arg value="${debug.class}"/> - </java> - </target> - <!-- TODO: edit the following target according to your needs --> - <!-- (more info: http://www.netbeans.org/kb/articles/freeform-config.html#runsingle) --> - <target depends="-jdk-init, init" name="run-selected-file-in-src"> - <fail unless="run.class">Must set property 'run.class'</fail> - <ant antfile="build.xml" inheritall="false" target="jar"/> - <java classname="${run.class}" failonerror="true" fork="false"> - <classpath path="${run.test.classpath}"/> - <jvmarg line="${boot.class.path}"/> - <jvmarg line="${run.test.jvmargs}"/> - <arg value="${run.class}"/> - </java> + <ant antfile="build.xml" inheritall="false" target="test"> + <property name="test.class" value="${test.class}"/> + <property name="debug.test.jvmargs" value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/> + </ant> </target> </project> diff --git a/make/nbproject/project.xml b/make/nbproject/project.xml index 828dc29d..2fcc6442 100644 --- a/make/nbproject/project.xml +++ b/make/nbproject/project.xml @@ -98,27 +98,27 @@ <script>nbproject/nbjdk.xml</script> <target>debug-nb</target> </action> - <action name="debug.single"> - <script>nbproject/ide-file-targets.xml</script> - <target>debug-selected-file-in-src</target> + <action name="run.single"> + <script>build.xml</script> + <target>test</target> <context> - <property>debug.class</property> - <folder>test/src</folder> + <property>test.class</property> + <folder>../test/src</folder> <pattern>\.java$</pattern> - <format>java-name</format> + <format>relative-path-noext</format> <arity> <one-file-only/> </arity> </context> </action> - <action name="run.single"> + <action name="debug.single"> <script>nbproject/ide-file-targets.xml</script> - <target>run-selected-file-in-src</target> + <target>debug-selected-file-in-src</target> <context> - <property>run.class</property> - <folder>test/src</folder> + <property>test.class</property> + <folder>../test/src</folder> <pattern>\.java$</pattern> - <format>java-name</format> + <format>relative-path-noext</format> <arity> <one-file-only/> </arity> diff --git a/make/project.properties b/make/project.properties index 8c5dd4f4..2abccdeb 100644 --- a/make/project.properties +++ b/make/project.properties @@ -59,6 +59,7 @@ nashorn.api.tests.jar=${build.dir}/nashorn-api-tests.jar # test results directory build.test.results.dir=${build.dir}/test/reports +build.nosecurity.test.results.dir=${build.dir}/test/nosecurity/reports # This directory is removed when the project is cleaned: dist.dir=dist @@ -110,6 +111,7 @@ run.classpath=\ # test scripts to run test.dir=test +test.nosecurity.dir=test/script/nosecurity test.script.dir=test/script test.basic.dir=test/script/basic test.maptests.dir=test/script/maptests @@ -127,8 +129,12 @@ test-sys-prop.test262.suite.dir=${test262.suite.dir} test-sys-prop.es5conform.testcases.dir=${test.external.dir}/ES5Conform/TestCases test-sys-prop.test.basic.dir=${test.basic.dir} +test-sys-prop-no-security.test.dir=${test.dir} +test-sys-prop-no-security.test.js.roots=${test.nosecurity.dir} + # framework root for our script tests test-sys-prop.test.js.framework=${test.script.dir}/assert.js +test-sys-prop-no-security.test.js.framework=${test.script.dir}/assert.js # Control the verbosity of ParserTest test-sys-prop.parsertest.verbose=false @@ -245,7 +251,7 @@ src.dir=src test.src.dir=test/src # -Xmx is used for all tests, -Xms only for octane benchmark -run.test.xmx=3G +run.test.xmx=2G run.test.xms=2G run.test.user.language=tr diff --git a/samples/filebrowser.js b/samples/filebrowser.js new file mode 100644 index 00000000..da00553a --- /dev/null +++ b/samples/filebrowser.js @@ -0,0 +1,100 @@ +#// Usage: jjs -fx filebrowser.js -- <start_dir> + +/* + * Copyright (c) 2014, 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. + */ + +// Uses -fx and javafx TreeView to visualize directories +if (!$OPTIONS._fx) { + print("Usage: jjs -fx filebrowser.js -- <start_dir>"); + exit(1); +} + +// Java classes used +var File = Java.type("java.io.File"); +var Files = Java.type("java.nio.file.Files"); + +// check directory argument, if passed +var dir = arguments.length > 0? new File(arguments[0]) : new File("."); +if (! dir.isDirectory()) { + print(dir + " is not a directory!"); + exit(2); +} + +// JavaFX classes used +var FXCollections = Java.type("javafx.collections.FXCollections"); +var Scene = Java.type("javafx.scene.Scene"); +var TreeItem = Java.type("javafx.scene.control.TreeItem"); +var TreeView = Java.type("javafx.scene.control.TreeView"); + +// create a subclass of JavaFX TreeItem class +var LazyTreeItem = Java.extend(TreeItem); + +// lazily filling children of a directory LazyTreeItem +function buildChildren(dir) { + var children = FXCollections.observableArrayList(); + var stream = Files.list(dir.toPath()); + stream.forEach(function(path) { + var file = path.toFile(); + var item = file.isDirectory()? + makeLazyTreeItem(file) : new TreeItem(file.name); + children.add(item); + }); + stream.close(); + return children; +} + +// create an instance LazyTreeItem with override methods +function makeLazyTreeItem(dir) { + var item = new LazyTreeItem(dir.name) { + expanded: false, + isLeaf: function() false, + getChildren: function() { + if (! this.expanded) { + // call super class (TreeItem) method + Java.super(item).getChildren().setAll(buildChildren(dir)); + this.expanded = true; + } + // call super class (TreeItem) method + return Java.super(item).getChildren(); + } + } + return item; +} + +// JavaFX start method +function start(stage) { + stage.title = dir.absolutePath; + var rootItem = makeLazyTreeItem(dir); + rootItem.expanded = true; + var tree = new TreeView(rootItem); + stage.scene = new Scene(tree, 300, 450); + stage.show(); +} diff --git a/samples/word_histogram.js b/samples/word_histogram.js new file mode 100644 index 00000000..9c739ea0 --- /dev/null +++ b/samples/word_histogram.js @@ -0,0 +1,53 @@ +#nashorn word histogram of a file + +/* + * Copyright (c) 2014, 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. + */ + +/* + * This example demonstrates how to print word histogram + * of a given text file using regex, array and JSON + * functions. + */ + +if (arguments.length < 1) { + print("Usage: jjs -scripting word_histogram.js -- <file>"); + exit(1); +} + +var obj = {}; + +readFully(arguments[0]). + split(/[^\w+]/). + forEach(function(x) + (x in obj? obj[x]++ : obj[x] = 1)); + +print(JSON.stringify(obj)); + diff --git a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java index b1255336..b8035d2e 100644 --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -496,7 +496,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin public void setProto(final Object proto) { inGlobal(new Callable<Void>() { @Override public Void call() { - sobj.setProtoCheck(unwrap(proto, global)); + sobj.setPrototypeOf(unwrap(proto, global)); return null; } }); @@ -621,6 +621,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin /** * Utilitity to convert this script object to the given type. * + * @param <T> destination type to convert to * @param type destination type to convert to * @return converted object */ diff --git a/src/jdk/nashorn/api/scripting/package-info.java b/src/jdk/nashorn/api/scripting/package-info.java index 6876151e..f017ba9e 100644 --- a/src/jdk/nashorn/api/scripting/package-info.java +++ b/src/jdk/nashorn/api/scripting/package-info.java @@ -32,7 +32,8 @@ * ScriptEngine nashornEngine = new ScriptEngineManager().getEngineByName("Nashorn"); * </pre> * <p>Nashorn script engines implement the optional {@link javax.script.Invocable} and {@link javax.script.Compilable} - * interfaces, allowing for efficient pre-compilation and repeated execution of scripts. See + * interfaces, allowing for efficient pre-compilation and repeated execution of scripts. In addition, + * this package provides nashorn specific extension classes, interfaces and methods. See * {@link jdk.nashorn.api.scripting.NashornScriptEngineFactory} for further details. */ package jdk.nashorn.api.scripting; diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 882846c6..52bdc7cb 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -1500,7 +1500,9 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex method.dup(); if (protoNode != null) { load(protoNode); - method.invoke(ScriptObject.SET_PROTO_CHECK); + // take care of { __proto__: 34 } or some such! + method.convert(Type.OBJECT); + method.invoke(ScriptObject.SET_PROTO_FROM_LITERAL); } else { globalObjectPrototype(); method.invoke(ScriptObject.SET_PROTO); diff --git a/src/jdk/nashorn/internal/ir/annotations/Reference.java b/src/jdk/nashorn/internal/ir/annotations/Reference.java index 20c8ffca..27f6a697 100644 --- a/src/jdk/nashorn/internal/ir/annotations/Reference.java +++ b/src/jdk/nashorn/internal/ir/annotations/Reference.java @@ -32,9 +32,7 @@ import java.lang.annotation.RetentionPolicy; * Reference node in AST, i.e. anything not a copy. Important for * AST traversal and cloning. Cloning currently as a rule uses * existingOrSame for references and otherwise existingOrCopy - * <p> */ - @Retention(value=RetentionPolicy.RUNTIME) public @interface Reference { // EMPTY diff --git a/src/jdk/nashorn/internal/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java index 00019382..0614c4b4 100644 --- a/src/jdk/nashorn/internal/objects/Global.java +++ b/src/jdk/nashorn/internal/objects/Global.java @@ -1908,8 +1908,8 @@ public final class Global extends ScriptObject implements Scope { // ES6 draft compliant __proto__ property of Object.prototype // accessors on Object.prototype for "__proto__" - final ScriptFunction getProto = ScriptFunctionImpl.makeFunction("getProto", ScriptObject.GETPROTO); - final ScriptFunction setProto = ScriptFunctionImpl.makeFunction("setProto", ScriptObject.SETPROTOCHECK); + final ScriptFunction getProto = ScriptFunctionImpl.makeFunction("getProto", NativeObject.GET__PROTO__); + final ScriptFunction setProto = ScriptFunctionImpl.makeFunction("setProto", NativeObject.SET__PROTO__); ObjectPrototype.addOwnProperty("__proto__", Attribute.NOT_ENUMERABLE, getProto, setProto); diff --git a/src/jdk/nashorn/internal/objects/NativeError.java b/src/jdk/nashorn/internal/objects/NativeError.java index 1b6b8094..18aa11e5 100644 --- a/src/jdk/nashorn/internal/objects/NativeError.java +++ b/src/jdk/nashorn/internal/objects/NativeError.java @@ -327,7 +327,12 @@ public final class NativeError extends ScriptObject { final Object exception = ECMAException.getException(sobj); if (exception instanceof Throwable) { Object value = getScriptStackString(sobj, (Throwable)exception); - sobj.put(STACK, value, false); + if (sobj.hasOwnProperty(STACK)) { + sobj.put(STACK, value, false); + } else { + sobj.addOwnProperty(STACK, Attribute.NOT_ENUMERABLE, value); + } + return value; } @@ -346,7 +351,12 @@ public final class NativeError extends ScriptObject { public static Object setStack(final Object self, final Object value) { Global.checkObject(self); final ScriptObject sobj = (ScriptObject)self; - sobj.set(STACK, value, false); + if (sobj.hasOwnProperty(STACK)) { + sobj.put(STACK, value, false); + } else { + sobj.addOwnProperty(STACK, Attribute.NOT_ENUMERABLE, value); + } + return value; } diff --git a/src/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk/nashorn/internal/objects/NativeObject.java index 9cde4faf..4fd8aeb5 100644 --- a/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/src/jdk/nashorn/internal/objects/NativeObject.java @@ -25,6 +25,7 @@ package jdk.nashorn.internal.objects; +import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; @@ -74,6 +75,9 @@ import jdk.nashorn.internal.runtime.linker.NashornBeansLinker; */ @ScriptClass("Object") public final class NativeObject { + public static final MethodHandle GET__PROTO__ = findOwnMH("get__proto__", ScriptObject.class, Object.class); + public static final MethodHandle SET__PROTO__ = findOwnMH("set__proto__", Object.class, Object.class, Object.class); + private static final Object TO_STRING = new Object(); private static InvokeByName getTO_STRING() { @@ -86,6 +90,35 @@ public final class NativeObject { }); } + @SuppressWarnings("unused") + private static ScriptObject get__proto__(final Object self) { + // See ES6 draft spec: B.2.2.1.1 get Object.prototype.__proto__ + // Step 1 Let O be the result of calling ToObject passing the this. + final Object obj = Global.toObject(self); + Global.checkObject(obj); + final ScriptObject sobj = (ScriptObject)obj; + return sobj.getProto(); + } + + @SuppressWarnings("unused") + private static Object set__proto__(final Object self, final Object proto) { + // See ES6 draft spec: B.2.2.1.2 set Object.prototype.__proto__ + // Step 1 + Global.checkObjectCoercible(self); + // Step 4 + if (! (self instanceof ScriptObject)) { + return UNDEFINED; + } + + final ScriptObject sobj = (ScriptObject)self; + // __proto__ assignment ignores non-nulls and non-objects + // step 3: If Type(proto) is neither Object nor Null, then return undefined. + if (proto == null || proto instanceof ScriptObject) { + sobj.setPrototypeOf(proto); + } + return UNDEFINED; + } + private static final MethodType MIRROR_GETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class); private static final MethodType MIRROR_SETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class, Object.class); @@ -160,7 +193,7 @@ public final class NativeObject { @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static Object setPrototypeOf(final Object self, final Object obj, final Object proto) { if (obj instanceof ScriptObject) { - ((ScriptObject)obj).setProtoCheck(proto); + ((ScriptObject)obj).setPrototypeOf(proto); return obj; } else if (obj instanceof ScriptObjectMirror) { ((ScriptObjectMirror)obj).setProto(proto); @@ -777,4 +810,8 @@ public final class NativeObject { return new LinkRequestImpl(CallSiteDescriptorFactory.create(MethodHandles.publicLookup(), operation, methodType), false, source); } + + private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { + return MH.findStatic(MethodHandles.lookup(), NativeObject.class, name, MH.type(rtype, types)); + } } diff --git a/src/jdk/nashorn/internal/objects/NativeRegExp.java b/src/jdk/nashorn/internal/objects/NativeRegExp.java index 89a9a828..34657d25 100644 --- a/src/jdk/nashorn/internal/objects/NativeRegExp.java +++ b/src/jdk/nashorn/internal/objects/NativeRegExp.java @@ -731,6 +731,12 @@ public final class NativeRegExp extends ScriptObject { if (nextChar == '$') { // Skip past $ cursor++; + if (cursor == replacement.length()) { + // nothing after "$" + sb.append('$'); + break; + } + nextChar = replacement.charAt(cursor); final int firstDigit = nextChar - '0'; diff --git a/src/jdk/nashorn/internal/runtime/CodeStore.java b/src/jdk/nashorn/internal/runtime/CodeStore.java index 8f595999..85a74ccb 100644 --- a/src/jdk/nashorn/internal/runtime/CodeStore.java +++ b/src/jdk/nashorn/internal/runtime/CodeStore.java @@ -37,7 +37,6 @@ import java.io.Serializable; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; -import java.util.Base64; import java.util.Map; /** @@ -48,9 +47,6 @@ final class CodeStore { private final File dir; private final int minSize; - // Message digest to file name encoder - private final static Base64.Encoder BASE64 = Base64.getUrlEncoder().withoutPadding(); - // Default minimum size for storing a compiled script class private final static int DEFAULT_MIN_SIZE = 1000; @@ -108,8 +104,7 @@ final class CodeStore { return null; } - final String digest = BASE64.encodeToString(source.getDigest()); - final File file = new File(dir, digest); + final File file = new File(dir, source.getDigest()); try { return AccessController.doPrivileged(new PrivilegedExceptionAction<CompiledScript>() { @@ -157,8 +152,7 @@ final class CodeStore { } } - final String digest = BASE64.encodeToString(source.getDigest()); - final File file = new File(dir, digest); + final File file = new File(dir, source.getDigest()); final CompiledScript script = new CompiledScript(source, mainClassName, classBytes, constants); try { diff --git a/src/jdk/nashorn/internal/runtime/DebuggerSupport.java b/src/jdk/nashorn/internal/runtime/DebuggerSupport.java index 261bc020..38e5d858 100644 --- a/src/jdk/nashorn/internal/runtime/DebuggerSupport.java +++ b/src/jdk/nashorn/internal/runtime/DebuggerSupport.java @@ -25,12 +25,20 @@ package jdk.nashorn.internal.runtime; +import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.net.URL; import java.util.HashSet; import java.util.Set; +import jdk.nashorn.internal.scripts.JS; /** * This class provides support for external debuggers. Its primary purpose is * is to simplify the debugger tasks and provide better performance. + * Even though the methods are not public, there are still part of the + * external debugger interface. */ final class DebuggerSupport { /** @@ -46,6 +54,11 @@ final class DebuggerSupport { */ @SuppressWarnings("unused") DebuggerValueDesc forceLoad = new DebuggerValueDesc(null, false, null, null); + + // Hook to force the loading of the SourceInfo class + @SuppressWarnings("unused") + final + SourceInfo srcInfo = new SourceInfo(null, 0, null, null); } /** This class is used to send a bulk description of a value. */ @@ -70,6 +83,54 @@ final class DebuggerSupport { } } + static class SourceInfo { + final String name; + final URL url; + final int hash; + final char[] content; + + SourceInfo(final String name, final int hash, final URL url, final char[] content) { + this.name = name; + this.hash = hash; + this.url = url; + this.content = content; + } + } + + /** + * Hook that is called just before invoking method handle + * from ScriptFunctionData via invoke, constructor method calls. + * + * @param mh script class method about to be invoked. + */ + static void notifyInvoke(final MethodHandle mh) { + // Do nothing here. This is placeholder method on which a + // debugger can place a breakpoint so that it can access the + // (script class) method handle that is about to be invoked. + // See ScriptFunctionData.invoke and ScriptFunctionData.construct. + } + + /** + * Return the script source info for the given script class. + * + * @param clazz compiled script class + * @return SourceInfo + */ + static SourceInfo getSourceInfo(final Class<?> clazz) { + if (JS.class.isAssignableFrom(clazz)) { + try { + final Field sourceField = clazz.getDeclaredField(SOURCE.symbolName()); + sourceField.setAccessible(true); + final Source src = (Source) sourceField.get(null); + return src.getSourceInfo(); + } catch (final IllegalAccessException | NoSuchFieldException ignored) { + return null; + } + } + + return null; + } + /** * Return the current context global. * @return context global. @@ -84,7 +145,7 @@ final class DebuggerSupport { * @param self Receiver to use. * @param string String to evaluate. * @param returnException true if exceptions are to be returned. - * @return Result of eval as string, or, an exception or null depending on returnException. + * @return Result of eval, or, an exception or null depending on returnException. */ static Object eval(final ScriptObject scope, final Object self, final String string, final boolean returnException) { final ScriptObject global = Context.getGlobal(); @@ -235,7 +296,7 @@ final class DebuggerSupport { * @param value Arbitrary value to be displayed by the debugger. * @return A string representation of the value or an array of DebuggerValueDesc. */ - private static String valueAsString(final Object value) { + static String valueAsString(final Object value) { final JSType type = JSType.of(value); switch (type) { diff --git a/src/jdk/nashorn/internal/runtime/GlobalFunctions.java b/src/jdk/nashorn/internal/runtime/GlobalFunctions.java index c750d80e..10747a1b 100644 --- a/src/jdk/nashorn/internal/runtime/GlobalFunctions.java +++ b/src/jdk/nashorn/internal/runtime/GlobalFunctions.java @@ -459,5 +459,4 @@ loop: private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { return MH.findStatic(MethodHandles.lookup(), GlobalFunctions.class, name, MH.type(rtype, types)); } - } diff --git a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java index ad40d622..001996b7 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java +++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java @@ -519,6 +519,8 @@ public abstract class ScriptFunctionData implements Serializable { final Object selfObj = convertThisObject(self); final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; + DebuggerSupport.notifyInvoke(mh); + if (isVarArg(mh)) { if (needsCallee(mh)) { return mh.invokeExact(fn, selfObj, args); @@ -572,6 +574,8 @@ public abstract class ScriptFunctionData implements Serializable { final MethodHandle mh = getGenericConstructor(); final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; + DebuggerSupport.notifyInvoke(mh); + if (isVarArg(mh)) { if (needsCallee(mh)) { return mh.invokeExact(fn, args); diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index d4556d89..deae803e 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -132,9 +132,7 @@ public abstract class ScriptObject implements PropertyAccess { /** Method handle to retrive prototype of this object */ public static final MethodHandle GETPROTO = findOwnMH("getProto", ScriptObject.class); - /** Method handle to set prototype of this object */ - public static final MethodHandle SETPROTOCHECK = findOwnMH("setProtoCheck", void.class, Object.class); - static final MethodHandle MEGAMORPHIC_GET = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class, boolean.class); + static final MethodHandle MEGAMORPHIC_GET = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class); static final MethodHandle GLOBALFILTER = findOwnMH("globalFilter", Object.class, Object.class); static final MethodHandle SETFIELD = findOwnMH("setField", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class); @@ -160,7 +158,7 @@ public abstract class ScriptObject implements PropertyAccess { public static final Call SET_PROTO = virtualCallNoLookup(ScriptObject.class, "setInitialProto", void.class, ScriptObject.class); /** Method handle for setting the proto of a ScriptObject after checking argument */ - public static final Call SET_PROTO_CHECK = virtualCallNoLookup(ScriptObject.class, "setProtoCheck", void.class, Object.class); + public static final Call SET_PROTO_FROM_LITERAL = virtualCallNoLookup(ScriptObject.class, "setProtoFromLiteral", void.class, Object.class); /** Method handle for setting the user accessors of a ScriptObject */ public static final Call SET_USER_ACCESSORS = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class); @@ -1127,14 +1125,21 @@ public abstract class ScriptObject implements PropertyAccess { /** * Set the __proto__ of an object with checks. + * This is the built-in operation [[SetPrototypeOf]] + * See ES6 draft spec: 9.1.2 [[SetPrototypeOf]] (V) + * * @param newProto Prototype to set. */ - public final void setProtoCheck(final Object newProto) { - if (!isExtensible()) { - throw typeError("__proto__.set.non.extensible", ScriptRuntime.safeToString(this)); - } - + public final void setPrototypeOf(final Object newProto) { if (newProto == null || newProto instanceof ScriptObject) { + if (!isExtensible()) { + // okay to set same proto again - even if non-extensible + if (newProto == getProto()) { + return; + } + throw typeError("__proto__.set.non.extensible", ScriptRuntime.safeToString(this)); + } + // check for circularity ScriptObject p = (ScriptObject)newProto; while (p != null) { @@ -1145,14 +1150,27 @@ public abstract class ScriptObject implements PropertyAccess { } setProto((ScriptObject)newProto); } else { - final Global global = Context.getGlobal(); - final Object newProtoObject = JSType.toScriptObject(global, newProto); + throw typeError("cant.set.proto.to.non.object", ScriptRuntime.safeToString(this), ScriptRuntime.safeToString(newProto)); + } + } - if (newProtoObject instanceof ScriptObject) { - setProto((ScriptObject)newProtoObject); - } else { - throw typeError(global, "cant.set.proto.to.non.object", ScriptRuntime.safeToString(this), ScriptRuntime.safeToString(newProto)); - } + /** + * Set the __proto__ of an object from an object literal. + * See ES6 draft spec: B.3.1 __proto__ Property Names in + * Object Initializers. Step 6 handling of "__proto__". + * + * @param newProto Prototype to set. + */ + public final void setProtoFromLiteral(final Object newProto) { + if (newProto == null || newProto instanceof ScriptObject) { + setPrototypeOf(newProto); + } else { + // Some non-object, non-null. Then, we need to set + // Object.prototype as the new __proto__ + // + // var obj = { __proto__ : 34 }; + // print(obj.__proto__ === Object.prototype); // => true + setPrototypeOf(Global.objectPrototype()); } } @@ -1727,7 +1745,7 @@ public abstract class ScriptObject implements PropertyAccess { protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) { final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); if (request.isCallSiteUnstable() || hasWithScope()) { - return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator), isScope() && NashornCallSiteDescriptor.isScope(desc)); + return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator)); } final FindProperty find = findProperty(name, true); @@ -1770,22 +1788,19 @@ public abstract class ScriptObject implements PropertyAccess { } private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, - final boolean isMethod, final boolean isScope) { - final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod, isScope); + final boolean isMethod) { + final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod); final MethodHandle guard = getScriptObjectGuard(desc.getMethodType()); return new GuardedInvocation(invoker, guard); } @SuppressWarnings("unused") - private Object megamorphicGet(final String key, final boolean isMethod, final boolean isScope) { + private Object megamorphicGet(final String key, final boolean isMethod) { final FindProperty find = findProperty(key, true); if (find != null) { return find.getObjectValue(); } - if (isScope) { - throw referenceError("not.defined", key); - } return isMethod ? getNoSuchMethod(key) : invokeNoSuchProperty(key); } diff --git a/src/jdk/nashorn/internal/runtime/Source.java b/src/jdk/nashorn/internal/runtime/Source.java index f7e890ff..4f9c16e6 100644 --- a/src/jdk/nashorn/internal/runtime/Source.java +++ b/src/jdk/nashorn/internal/runtime/Source.java @@ -45,6 +45,7 @@ import java.nio.file.Paths; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.Base64; import java.util.Objects; import java.util.WeakHashMap; import jdk.nashorn.api.scripting.URLReader; @@ -59,6 +60,9 @@ public final class Source { private static final int BUF_SIZE = 8 * 1024; private static final Cache CACHE = new Cache(); + // Message digest to file name encoder + private final static Base64.Encoder BASE64 = Base64.getUrlEncoder().withoutPadding(); + /** * Descriptive name of the source as supplied by the user. Used for error * reporting to the user. For example, SyntaxError will use this to print message. @@ -79,8 +83,8 @@ public final class Source { /** Cached hash code */ private int hash; - /** Message digest */ - private byte[] digest; + /** Base64-encoded SHA1 digest of this source object */ + private volatile byte[] digest; // Do *not* make this public, ever! Trusts the URL and content. private Source(final String name, final String base, final Data data) { @@ -124,6 +128,11 @@ public final class Source { } } + /* package-private */ + DebuggerSupport.SourceInfo getSourceInfo() { + return new DebuggerSupport.SourceInfo(getName(), data.hashCode(), data.url(), data.array()); + } + // Wrapper to manage lazy loading private static interface Data { @@ -706,12 +715,17 @@ public final class Source { } /** - * Get a message digest for this source. + * Get a Base64-encoded SHA1 digest for this source. * - * @return a message digest for this source + * @return a Base64-encoded SHA1 digest for this source */ - public synchronized byte[] getDigest() { - if (digest == null) { + public String getDigest() { + return new String(getDigestBytes(), StandardCharsets.US_ASCII); + } + + private byte[] getDigestBytes() { + byte[] ldigest = digest; + if (ldigest == null) { final char[] content = data(); final byte[] bytes = new byte[content.length * 2]; @@ -731,12 +745,12 @@ public final class Source { if (getURL() != null) { md.update(getURL().toString().getBytes(StandardCharsets.UTF_8)); } - digest = md.digest(bytes); - } catch (NoSuchAlgorithmException e) { + digest = ldigest = BASE64.encode(md.digest(bytes)); + } catch (final NoSuchAlgorithmException e) { throw new RuntimeException(e); } } - return digest; + return ldigest; } /** diff --git a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java index c8f39fcf..48821036 100644 --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java @@ -61,9 +61,17 @@ public final class Bootstrap { private static final DynamicLinker dynamicLinker; static { final DynamicLinkerFactory factory = new DynamicLinkerFactory(); - factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(), - new BoundDynamicMethodLinker(), new JavaSuperAdapterLinker(), new JSObjectLinker(), new ReflectionCheckLinker()); - factory.setFallbackLinkers(new NashornBeansLinker(), new NashornBottomLinker()); + final NashornBeansLinker nashornBeansLinker = new NashornBeansLinker(); + final JSObjectLinker jsObjectLinker = new JSObjectLinker(nashornBeansLinker); + factory.setPrioritizedLinkers( + new NashornLinker(), + new NashornPrimitiveLinker(), + new NashornStaticClassLinker(), + new BoundDynamicMethodLinker(), + new JavaSuperAdapterLinker(), + jsObjectLinker, + new ReflectionCheckLinker()); + factory.setFallbackLinkers(nashornBeansLinker, new NashornBottomLinker()); factory.setSyncOnRelink(true); final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1); if (relinkThreshold > -1) { diff --git a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java index f3c8284b..52fb46bc 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java @@ -30,6 +30,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.HashMap; import java.util.Map; +import javax.script.Bindings; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.GuardedTypeConversion; @@ -48,14 +49,23 @@ import jdk.nashorn.internal.runtime.JSType; * as ScriptObjects from other Nashorn contexts. */ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory { + private final NashornBeansLinker nashornBeansLinker; + + JSObjectLinker(final NashornBeansLinker nashornBeansLinker) { + this.nashornBeansLinker = nashornBeansLinker; + } + @Override public boolean canLinkType(final Class<?> type) { return canLinkTypeStatic(type); } static boolean canLinkTypeStatic(final Class<?> type) { - // can link JSObject - return JSObject.class.isAssignableFrom(type); + // can link JSObject also handles Map, Bindings to make + // sure those are not JSObjects. + return Map.class.isAssignableFrom(type) || + Bindings.class.isAssignableFrom(type) || + JSObject.class.isAssignableFrom(type); } @Override @@ -72,6 +82,11 @@ final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTy final GuardedInvocation inv; if (self instanceof JSObject) { inv = lookup(desc); + } else if (self instanceof Map || self instanceof Bindings) { + // guard to make sure the Map or Bindings does not turn into JSObject later! + final GuardedInvocation beanInv = nashornBeansLinker.getGuardedInvocation(request, linkerServices); + inv = new GuardedInvocation(beanInv.getInvocation(), + NashornGuards.combineGuards(beanInv.getGuard(), NashornGuards.getNotJSObjectGuard())); } else { throw new AssertionError(); // Should never reach here. } diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java b/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java index ca3e10c4..77c5e93c 100644 --- a/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java +++ b/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java @@ -31,6 +31,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.ref.WeakReference; import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.internal.codegen.ObjectClassGenerator; import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.Property; @@ -43,6 +44,7 @@ import jdk.nashorn.internal.runtime.ScriptObject; */ public final class NashornGuards { private static final MethodHandle IS_SCRIPTOBJECT = findOwnMH("isScriptObject", boolean.class, Object.class); + private static final MethodHandle IS_NOT_JSOBJECT = findOwnMH("isNotJSObject", boolean.class, Object.class); private static final MethodHandle IS_SCRIPTFUNCTION = findOwnMH("isScriptFunction", boolean.class, Object.class); private static final MethodHandle IS_MAP = findOwnMH("isMap", boolean.class, Object.class, PropertyMap.class); private static final MethodHandle SAME_OBJECT = findOwnMH("sameObject", boolean.class, Object.class, WeakReference.class); @@ -61,6 +63,14 @@ public final class NashornGuards { } /** + * Get the guard that checks if an item is not a {@code JSObject} + * @return method handle for guard + */ + public static MethodHandle getNotJSObjectGuard() { + return IS_NOT_JSOBJECT; + } + + /** * Get the guard that checks if an item is a {@code ScriptFunction} * @return method handle for guard */ @@ -157,6 +167,11 @@ public final class NashornGuards { } @SuppressWarnings("unused") + private static boolean isNotJSObject(final Object self) { + return !(self instanceof JSObject); + } + + @SuppressWarnings("unused") private static boolean isScriptFunction(final Object self) { return self instanceof ScriptFunction; } diff --git a/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java b/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java index 272b4ec0..f8ea9916 100644 --- a/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java @@ -25,6 +25,7 @@ package jdk.nashorn.internal.runtime.linker; +import java.lang.reflect.Modifier; import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.beans.BeansLinker; import jdk.internal.dynalink.beans.StaticClass; @@ -65,10 +66,15 @@ final class NashornStaticClassLinker implements TypeBasedGuardingDynamicLinker { return null; } final Class<?> receiverClass = ((StaticClass) self).getRepresentedClass(); + Bootstrap.checkReflectionAccess(receiverClass, true); final CallSiteDescriptor desc = request.getCallSiteDescriptor(); // We intercept "new" on StaticClass instances to provide additional capabilities if ("new".equals(desc.getNameToken(CallSiteDescriptor.OPERATOR))) { + if (! Modifier.isPublic(receiverClass.getModifiers())) { + throw ECMAErrors.typeError("new.on.nonpublic.javatype", receiverClass.getName()); + } + // make sure new is on accessible Class Context.checkPackageAccess(receiverClass); diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java b/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java index a75e84ca..eb612cd3 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/Analyser.java @@ -771,7 +771,7 @@ final class Analyser extends Parser { while (value < end) { int ovalue = value; - buf = Character.toLowerCase(chars[value++]); + buf = EncodingHelper.toLowerCase(chars[value++]); if (chars[ovalue] != buf) { @@ -779,7 +779,7 @@ final class Analyser extends Parser { System.arraycopy(chars, sn.p, sbuf, 0, ovalue - sn.p); value = ovalue; while (value < end) { - buf = Character.toLowerCase(chars[value++]); + buf = EncodingHelper.toLowerCase(chars[value++]); if (sp >= sbuf.length) { char[]tmp = new char[sbuf.length << 1]; System.arraycopy(sbuf, 0, tmp, 0, sbuf.length); diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ApplyCaseFold.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ApplyCaseFold.java index 397b05ce..dda5b733 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ApplyCaseFold.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ApplyCaseFold.java @@ -20,70 +20,42 @@ package jdk.nashorn.internal.runtime.regexp.joni; import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.ConsAltNode; -import jdk.nashorn.internal.runtime.regexp.joni.ast.StringNode; final class ApplyCaseFold { // i_apply_case_fold - public void apply(int from, int[]to, int length, Object o) { + public void apply(int from, int to, Object o) { ApplyCaseFoldArg arg = (ApplyCaseFoldArg)o; ScanEnvironment env = arg.env; CClassNode cc = arg.cc; BitSet bs = cc.bs; - if (length == 1) { - boolean inCC = cc.isCodeInCC(from); + boolean inCC = cc.isCodeInCC(from); - if (Config.CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS) { - if ((inCC && !cc.isNot()) || (!inCC && cc.isNot())) { - if (to[0] >= BitSet.SINGLE_BYTE_SIZE) { - cc.addCodeRange(env, to[0], to[0]); - } else { - /* /(?i:[^A-C])/.match("a") ==> fail. */ - bs.set(to[0]); - } - } - } else { - if (inCC) { - if (to[0] >= BitSet.SINGLE_BYTE_SIZE) { - if (cc.isNot()) cc.clearNotFlag(); - cc.addCodeRange(env, to[0], to[0]); - } else { - if (cc.isNot()) { - bs.clear(to[0]); - } else { - bs.set(to[0]); - } - } + if (Config.CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS) { + if ((inCC && !cc.isNot()) || (!inCC && cc.isNot())) { + if (to >= BitSet.SINGLE_BYTE_SIZE) { + cc.addCodeRange(env, to, to); + } else { + /* /(?i:[^A-C])/.match("a") ==> fail. */ + bs.set(to); } - } // CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS - + } } else { - if (cc.isCodeInCC(from) && (!Config.CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS || !cc.isNot())) { - StringNode node = null; - for (int i=0; i<length; i++) { - if (i == 0) { - node = new StringNode(); - /* char-class expanded multi-char only - compare with string folded at match time. */ - node.setAmbig(); - } - node.catCode(to[i]); - } - - ConsAltNode alt = ConsAltNode.newAltNode(node, null); - - if (arg.tail == null) { - arg.altRoot = alt; + if (inCC) { + if (to >= BitSet.SINGLE_BYTE_SIZE) { + if (cc.isNot()) cc.clearNotFlag(); + cc.addCodeRange(env, to, to); } else { - arg.tail.setCdr(alt); + if (cc.isNot()) { + bs.clear(to); + } else { + bs.set(to); + } } - arg.tail = alt; } - - } + } // CASE_FOLD_IS_APPLIED_INSIDE_NEGATIVE_CCLASS } diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java index df4b125b..b897a8cb 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/ByteCodeMachine.java @@ -58,8 +58,8 @@ class ByteCodeMachine extends StackMachine { int end1 = s1 + mbLen; while (s1 < end1) { - char c1 = Character.toLowerCase(chars[s1++]); - char c2 = Character.toLowerCase(chars[s2++]); + char c1 = EncodingHelper.toLowerCase(chars[s1++]); + char c2 = EncodingHelper.toLowerCase(chars[s2++]); if (c1 != c2) { return false; @@ -367,7 +367,7 @@ class ByteCodeMachine extends StackMachine { } private void opExact1IC() { - if (s >= range || code[ip] != Character.toLowerCase(chars[s++])) {opFail(); return;} + if (s >= range || code[ip] != EncodingHelper.toLowerCase(chars[s++])) {opFail(); return;} ip++; sprev = sbegin; // break; } @@ -380,10 +380,10 @@ class ByteCodeMachine extends StackMachine { char[] bs = regex.templates[code[ip++]]; int ps = code[ip++]; - while (tlen-- > 0) if (bs[ps++] != Character.toLowerCase(chars[s++])) {opFail(); return;} + while (tlen-- > 0) if (bs[ps++] != EncodingHelper.toLowerCase(chars[s++])) {opFail(); return;} } else { - while (tlen-- > 0) if (code[ip++] != Character.toLowerCase(chars[s++])) {opFail(); return;} + while (tlen-- > 0) if (code[ip++] != EncodingHelper.toLowerCase(chars[s++])) {opFail(); return;} } sprev = s - 1; } diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java b/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java index afbb1b20..0c9c8ab4 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/EncodingHelper.java @@ -93,43 +93,80 @@ public final class EncodingHelper { return s; } - public static int mbcToCode(byte[] bytes, int p, int end) { - int code = 0; - for (int i = p; i < end; i++) { - code = (code << 8) | (bytes[i] & 0xff); - } - return code; - } - public static int mbcodeStartPosition() { return 0x80; } public static char[] caseFoldCodesByString(int flag, char c) { - if (Character.isUpperCase(c)) { - return new char[] {Character.toLowerCase(c)}; - } else if (Character.isLowerCase(c)) { - return new char[] {Character.toUpperCase(c)}; - } else { - return EMPTYCHARS; + char[] codes = EMPTYCHARS; + final char upper = toUpperCase(c); + + if (upper != toLowerCase(upper)) { + int count = 0; + char ch = 0; + + do { + final char u = toUpperCase(ch); + if (u == upper && ch != c) { + // Almost all characters will return array of length 1, very few 2 or 3, so growing by one is fine. + codes = count == 0 ? new char[1] : Arrays.copyOf(codes, count + 1); + codes[count++] = ch; + } + } while (ch++ < 0xffff); } + return codes; } public static void applyAllCaseFold(int flag, ApplyCaseFold fun, Object arg) { - int[] code = new int[1]; - for (int c = 0; c < 0xffff; c++) { - if (Character.getType(c) == Character.LOWERCASE_LETTER) { + if (Character.isLowerCase(c)) { + final int upper = toUpperCase(c); - int upper = code[0] = Character.toUpperCase(c); - fun.apply(c, code, 1, arg); + if (upper != c) { + fun.apply(c, upper, arg); + } + } + } - code[0] = c; - fun.apply(upper, code, 1, arg); + // Some characters have multiple lower case variants, hence we need to do a second run + for (int c = 0; c < 0xffff; c++) { + if (Character.isLowerCase(c)) { + final int upper = toUpperCase(c); + + if (upper != c) { + fun.apply(upper, c, arg); + } } } } + public static char toLowerCase(char c) { + return (char)toLowerCase((int)c); + } + + public static int toLowerCase(int c) { + if (c < 128) { + return ('A' <= c && c <= 'Z') ? (c + ('a' - 'A')) : c; + } + // Do not convert non-ASCII upper case character to ASCII lower case. + int lower = Character.toLowerCase(c); + return (lower < 128) ? c : lower; + + } + + public static char toUpperCase(char c) { + return (char)toUpperCase((int)c); + } + + public static int toUpperCase(int c) { + if (c < 128) { + return ('a' <= c && c <= 'z') ? c + ('A' - 'a') : c; + } + // Do not convert non-ASCII lower case character to ASCII upper case. + int upper = Character.toUpperCase(c); + return (upper < 128) ? c : upper; + } + public static int[] ctypeCodeRange(int ctype, IntHolder sbOut) { sbOut.value = 0x100; // use bitset for codes smaller than 256 int[] range = null; diff --git a/src/jdk/nashorn/internal/runtime/regexp/joni/SearchAlgorithm.java b/src/jdk/nashorn/internal/runtime/regexp/joni/SearchAlgorithm.java index 758679a2..5b2eac97 100644 --- a/src/jdk/nashorn/internal/runtime/regexp/joni/SearchAlgorithm.java +++ b/src/jdk/nashorn/internal/runtime/regexp/joni/SearchAlgorithm.java @@ -168,7 +168,7 @@ public abstract class SearchAlgorithm { char[] chars, int p, int end) { while (tP < tEnd) { - if (t[tP++] != Character.toLowerCase(chars[p++])) return false; + if (t[tP++] != EncodingHelper.toLowerCase(chars[p++])) return false; } return true; } diff --git a/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/src/jdk/nashorn/internal/runtime/resources/Messages.properties index 47248fce..c98c1c7c 100644 --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -138,6 +138,7 @@ type.error.no.method.matches.args=Can not invoke method {0} with the passed argu type.error.method.not.constructor=Java method {0} can't be used as a constructor. type.error.env.not.object=$ENV must be an Object. type.error.unsupported.java.to.type=Unsupported Java.to target type {0}. +type.error.new.on.nonpublic.javatype=new cannot be used with non-public java type {0}. range.error.dataview.constructor.offset=Wrong offset or length in DataView constructor range.error.dataview.offset=Offset is outside the bounds of the DataView diff --git a/test/script/basic/JDK-8030202.js b/test/script/basic/JDK-8030202.js new file mode 100644 index 00000000..6cf56475 --- /dev/null +++ b/test/script/basic/JDK-8030202.js @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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-8030202: Nashorn: Multiple RegExp#ignoreCase issues + * + * @test + * @run + */ + +print(/\u2160/i.test("\u2170")); +print(/[\u2160]/i.test("\u2170")); +print(/\u2170/i.test("\u2160")); +print(/[\u2170]/i.test("\u2160")); + +print(/\u0130/i.test("\u0069")); +print(/[\u0130]/i.test("\u0069")); +print(/\u0069/i.test("\u0130")); +print(/[\u0069]/i.test("\u0130")); + +print(/\u1e9e/i.test("\u00df")); +print(/[\u1e9e]/i.test("\u00df")); +print(/\u00df/i.test("\u1e9e")); +print(/[\u00df]/i.test("\u1e9e")); + +print(/[^\u1e9e]/i.test("\u00df")); +print(/[^\u00df]/i.test("\u1e9e")); + +print(/\u0345{4}/i.test("\u0345\u0399\u03b9\u1fbe")); +print(/\u0399{4}/i.test("\u0345\u0399\u03b9\u1fbe")); +print(/\u03b9{4}/i.test("\u0345\u0399\u03b9\u1fbe")); +print(/\u1fbe{4}/i.test("\u0345\u0399\u03b9\u1fbe")); + +print(/[\u0345]{4}/i.test("\u0345\u0399\u03b9\u1fbe")); +print(/[\u0399]{4}/i.test("\u0345\u0399\u03b9\u1fbe")); +print(/[\u03b9]{4}/i.test("\u0345\u0399\u03b9\u1fbe")); +print(/[\u1fbe]{4}/i.test("\u0345\u0399\u03b9\u1fbe")); diff --git a/test/script/basic/JDK-8030202.js.EXPECTED b/test/script/basic/JDK-8030202.js.EXPECTED new file mode 100644 index 00000000..7c73d8c0 --- /dev/null +++ b/test/script/basic/JDK-8030202.js.EXPECTED @@ -0,0 +1,22 @@ +true +true +true +true +false +false +false +false +false +false +false +false +true +true +true +true +true +true +true +true +true +true diff --git a/test/script/basic/JDK-8043930.js b/test/script/basic/JDK-8043930.js new file mode 100644 index 00000000..a89b3541 --- /dev/null +++ b/test/script/basic/JDK-8043930.js @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2010, 2013, 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-8043930: TypeError when attemping to create an instance of non-public class could be better + * + * @test + * @run + */ + +var NonPublicClass = Java.type("jdk.nashorn.test.models.NonPublicClass"); +try { + var obj = new NonPublicClass(); + fail("Expected TypeError to be thrown!"); +} catch (e) { + print(e); +} diff --git a/test/script/basic/JDK-8043930.js.EXPECTED b/test/script/basic/JDK-8043930.js.EXPECTED new file mode 100644 index 00000000..ee5cf9dc --- /dev/null +++ b/test/script/basic/JDK-8043930.js.EXPECTED @@ -0,0 +1 @@ +TypeError: new cannot be used with non-public java type jdk.nashorn.test.models.NonPublicClass. diff --git a/test/script/basic/JDK-8044520.js b/test/script/basic/JDK-8044520.js new file mode 100644 index 00000000..edcaa116 --- /dev/null +++ b/test/script/basic/JDK-8044520.js @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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-8044520: Nashorn cannot execute node.js's express module + * + * @test + * @run + */ + +function checkNullProto() { + var obj = {}; + obj.__proto__ = null; + var proto = Object.getPrototypeOf(obj); + if (typeof proto != 'object' || proto !== null) { + fail("__proto__ can't be set to null!"); + } +} + +checkNullProto(); + +function checkSetProto(proto) { + var obj = {}; + obj.__proto__ = proto; + if (Object.getPrototypeOf(obj) !== Object.prototype) { + fail("obj.__proto__ set not ignored for " + proto); + } +} + +checkSetProto(undefined); +checkSetProto(42); +checkSetProto(false); +checkSetProto("hello"); + +function checkLiteralSetProto(proto) { + var obj = { __proto__: proto }; + if (obj.__proto__ !== Object.prototype) { + fail("object literal _proto__ set not ignored for " + proto); + } +} + +checkLiteralSetProto(undefined); +checkLiteralSetProto(34); +checkLiteralSetProto(true); +checkLiteralSetProto("world"); + +function checkNullProtoFromLiteral() { + var obj = { __proto__: null }; + var proto = Object.getPrototypeOf(obj); + if (typeof proto != 'object' || proto !== null) { + fail("__proto__ can't be set to null!"); + } +} + +checkNullProtoFromLiteral(); + +function checkSetPrototypeOf(proto) { + try { + Object.setPrototypeOf({}, proto); + fail("should have thrown error for " + proto); + } catch (e) { + if (! (e instanceof TypeError)) { + fail("should have thrown TypeError, got " + e); + } + } +} + +checkSetPrototypeOf(undefined); +checkSetPrototypeOf(43); +checkSetPrototypeOf(false); +checkSetPrototypeOf("nashorn"); + +function checkNullSetPrototypeOf() { + var obj = { }; + Object.setPrototypeOf(obj, null); + var proto = Object.getPrototypeOf(obj); + if (typeof proto != 'object' || proto !== null) { + fail("__proto__ can't be set to null!"); + } +} + +checkNullSetPrototypeOf(); + +var desc = Object.getOwnPropertyDescriptor(Object.prototype, "__proto__"); + +function checkProtoGetterOnPrimitive(value) { + // call __proto__ getter on primitive - check ToObject + // is called on 'this' value as per draft spec + if (desc.get.call(value) !== Object(value).__proto__) { + fail("can't call __proto__ getter on " + value); + } +} + +checkProtoGetterOnPrimitive(32); +checkProtoGetterOnPrimitive(false); +checkProtoGetterOnPrimitive("great!"); + +function checkProtoSetterOnNonObjectThis(self) { + try { + desc.set.call(self); + fail("should have thrown TypeError"); + } catch (e) { + if (! (e instanceof TypeError)) { + fail("should throw TypeError on non-object self, got " +e); + } + } +} + +checkProtoSetterOnNonObjectThis(undefined); +checkProtoSetterOnNonObjectThis(null); + +function checkProtoSetterReturnValue(obj, p) { + if (typeof desc.set.call(obj, p) != "undefined") { + fail("__proto__ setter does not return undefined: " + obj + " " + p); + } +} + +// try non-object 'this'. setter is expected to return undefined. +checkProtoSetterReturnValue(23); +checkProtoSetterReturnValue(false); +checkProtoSetterReturnValue("foo"); + +// set proper __proto__. Still return value is undefined. +checkProtoSetterReturnValue({}, {}); +checkProtoSetterReturnValue({}, null); diff --git a/test/script/basic/JDK-8044612.js b/test/script/basic/JDK-8044612.js new file mode 100644 index 00000000..6980cd1b --- /dev/null +++ b/test/script/basic/JDK-8044612.js @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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-8044612: StringIndexOutOfBoundException in NativeRegExp.appendReplacement + * + * @test + * @run + */ + +if ("hello".replace("h", "$") != "$ello") { + fail("String.prototype.replace failed to handle '$' as replacement"); +} + +if ("hello".replace("o", "$x") != "hell$x") { + fail("String.prototype.replace failed to handle '$x' as replacement"); +} diff --git a/test/script/basic/JDK-8044695.js b/test/script/basic/JDK-8044695.js new file mode 100644 index 00000000..2e7b7742 --- /dev/null +++ b/test/script/basic/JDK-8044695.js @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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-8044695: __stack__ becomes visible in Error properties + * + * @test + * @run + */ + +var e = new Error(); +// access stack to force __stack__ +e.stack; +var jsonStr = JSON.stringify(e); +if (jsonStr != "{}") { + fail("JSON string is not {}, it is " + jsonStr); +} diff --git a/test/script/basic/JDK-8044750.js b/test/script/basic/JDK-8044750.js new file mode 100644 index 00000000..ee6fa4d5 --- /dev/null +++ b/test/script/basic/JDK-8044750.js @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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-8044750: megamorphic getter for scope objects does not call __noSuchProperty__ hook + * + * @test + * @run + */ + +__noSuchProperty__ = function(name) { + return 1; +} + +function func(obj) { + with(obj) { + // this "foo" getter site becomes megamorphic + // due to different 'with' scope objects. + foo; + } +} + +for (var i = 0; i < 20; i++) { + var obj = {}; + obj.foo = i; + obj[i] = i; + func(obj); +} + +// pass a 'with' scope object that does not have 'foo'. +// callsite inside func should see __noSuchProperty__ +// hook on global scope object. +func({}); diff --git a/test/script/nosecurity/JDK-8044798.js b/test/script/nosecurity/JDK-8044798.js new file mode 100644 index 00000000..dc1a7478 --- /dev/null +++ b/test/script/nosecurity/JDK-8044798.js @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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-8044798: API for debugging Nashorn + * + * @test + * @run + */ + +// basic API exercise checks + +var Arrays = Java.type("java.util.Arrays"); +var CharArray = Java.type("char[]"); +var DebuggerSupport = Java.type("jdk.nashorn.internal.runtime.DebuggerSupport"); +var DebuggerValueDesc = Java.type("jdk.nashorn.internal.runtime.DebuggerSupport.DebuggerValueDesc"); + +var valueDescFields = DebuggerValueDesc.class.declaredFields; +Arrays.sort(valueDescFields, function(f1, f2) f1.name.compareTo(f2.name)); +var keyField; +for each (var f in valueDescFields) { + if (f.name == "key") { + keyField = f; + } + f.accessible = true; +} + +var debuggerSupportMethods = DebuggerSupport.class.declaredMethods; + +// methods of DebuggerSupport that we use +var evalMethod, valueInfoMethod, valueInfosMethod; +var getSourceInfoMethod, valueAsStringMethod; + +for each (var m in debuggerSupportMethods) { + m.accessible = true; + switch (m.name) { + case "eval": + evalMethod = m; + break; + case "valueInfo": + if (m.parameterCount == 3) { + valueInfoMethod = m; + } + break; + case "valueInfos": + valueInfosMethod = m; + break; + case "valueAsString": + valueAsStringMethod = m; + break; + case "getSourceInfo": + getSourceInfoMethod = m; + break; + } +} + +// eval +var value = evalMethod.invoke(null, null, null, "33 + 55", false); +print(value); + +// valueInfo +var info = valueInfoMethod.invoke(null, "apply", Function, true); +for each (var f in valueDescFields) { + print(f.name, "=", f.get(info)); +} + +// valueInfo - user defined object +var info = valueInfoMethod.invoke(null, "foo", { foo: 343 }, true); +for each (var f in valueDescFields) { + print(f.name, "=", f.get(info)); +} + +// valueInfos +var infos = valueInfosMethod.invoke(null, Object, true); +Arrays.sort(infos, function (i1, i2) keyField.get(i1).compareTo(keyField.get(i2))); + +for each (var info in infos) { + for each (var f in valueDescFields) { + print(f.name, "=", f.get(info)); + } +} + +// valueInfos - user defined object +var infos = valueInfosMethod.invoke(null, { foo: 34, bar: "hello" }, true); +Arrays.sort(infos, function (i1, i2) keyField.get(i1).compareTo(keyField.get(i2))); + +for each (var info in infos) { + for each (var f in valueDescFields) { + print(f.name, "=", f.get(info)); + } +} + +// valueAsString +function printValue(value) { + print(valueAsStringMethod.invoke(null, value)); +} + +printValue(undefined); +printValue(null); +printValue("hello"); +printValue(Math.PI); +printValue(this); + +// The below are not part of DebuggerSupport. But we need these to +// test DebuggerSupport.getSourceInfo etc. which need compiled script class + +var Source = Java.type("jdk.nashorn.internal.runtime.Source"); +var Context = Java.type("jdk.nashorn.internal.runtime.Context"); +var sourceCls = Source.class; +var errorMgrCls = Java.type("jdk.nashorn.internal.runtime.ErrorManager").class; +var booleanCls = Java.type("java.lang.Boolean").TYPE; + +// private compile method of Context class +var compileMethod = Context.class.getDeclaredMethod("compile", + sourceCls, errorMgrCls, booleanCls); +compileMethod.accessible = true; + +var scriptCls = compileMethod.invoke(Context.context, + Source.sourceFor("test", "print('hello')"), + new Context.ThrowErrorManager(), false); + +var SCRIPT_CLASS_NAME_PREFIX = "jdk.nashorn.internal.scripts.Script$"; +print("script class name pattern satisfied? " + + scriptCls.name.startsWith(SCRIPT_CLASS_NAME_PREFIX)); + +var srcInfo = getSourceInfoMethod.invoke(null, scriptCls); +var srcInfoFields = srcInfo.class.declaredFields; +Arrays.sort(srcInfoFields, function(f1, f2) f1.name.compareTo(f2.name)); + +print("Source info"); +for each (var f in srcInfoFields) { + f.accessible = true; + var fieldValue = f.get(srcInfo); + if (fieldValue instanceof CharArray) { + fieldValue = new java.lang.String(fieldValue); + } + + print(f.name, "=", fieldValue); +} diff --git a/test/script/nosecurity/JDK-8044798.js.EXPECTED b/test/script/nosecurity/JDK-8044798.js.EXPECTED new file mode 100644 index 00000000..2a21328c --- /dev/null +++ b/test/script/nosecurity/JDK-8044798.js.EXPECTED @@ -0,0 +1,104 @@ +88 +expandable = false +key = apply +valueAsObject = function Function() { [native code] } +valueAsString = function Function() { [native code] } +expandable = true +key = foo +valueAsObject = [object Object] +valueAsString = {foo: 343} +expandable = false +key = bindProperties +valueAsObject = function bindProperties() { [native code] } +valueAsString = function bindProperties() { [native code] } +expandable = false +key = create +valueAsObject = function create() { [native code] } +valueAsString = function create() { [native code] } +expandable = false +key = defineProperties +valueAsObject = function defineProperties() { [native code] } +valueAsString = function defineProperties() { [native code] } +expandable = false +key = defineProperty +valueAsObject = function defineProperty() { [native code] } +valueAsString = function defineProperty() { [native code] } +expandable = false +key = freeze +valueAsObject = function freeze() { [native code] } +valueAsString = function freeze() { [native code] } +expandable = false +key = getOwnPropertyDescriptor +valueAsObject = function getOwnPropertyDescriptor() { [native code] } +valueAsString = function getOwnPropertyDescriptor() { [native code] } +expandable = false +key = getOwnPropertyNames +valueAsObject = function getOwnPropertyNames() { [native code] } +valueAsString = function getOwnPropertyNames() { [native code] } +expandable = false +key = getPrototypeOf +valueAsObject = function getPrototypeOf() { [native code] } +valueAsString = function getPrototypeOf() { [native code] } +expandable = false +key = isExtensible +valueAsObject = function isExtensible() { [native code] } +valueAsString = function isExtensible() { [native code] } +expandable = false +key = isFrozen +valueAsObject = function isFrozen() { [native code] } +valueAsString = function isFrozen() { [native code] } +expandable = false +key = isSealed +valueAsObject = function isSealed() { [native code] } +valueAsString = function isSealed() { [native code] } +expandable = false +key = keys +valueAsObject = function keys() { [native code] } +valueAsString = function keys() { [native code] } +expandable = false +key = length +valueAsObject = 1 +valueAsString = 1 +expandable = false +key = name +valueAsObject = Object +valueAsString = "Object" +expandable = false +key = preventExtensions +valueAsObject = function preventExtensions() { [native code] } +valueAsString = function preventExtensions() { [native code] } +expandable = false +key = prototype +valueAsObject = [object Object] +valueAsString = {toString: function toString() { [native code] }, toLocaleString: function toLocaleString() { [native code] }, valueOf: function valueOf() { [native code] }, hasOwnProperty: function hasOwnProperty() { [native code] }, isPrototypeOf: function isPrototypeOf() { [native code] }, propertyIsEnumerable: function propertyIsEnumerable() { [native code] }, constructor: function Object() { [native code] }, __proto__: null} +expandable = false +key = seal +valueAsObject = function seal() { [native code] } +valueAsString = function seal() { [native code] } +expandable = false +key = setIndexedPropertiesToExternalArrayData +valueAsObject = function setIndexedPropertiesToExternalArrayData() { [native code] } +valueAsString = function setIndexedPropertiesToExternalArrayData() { [native code] } +expandable = false +key = setPrototypeOf +valueAsObject = function setPrototypeOf() { [native code] } +valueAsString = function setPrototypeOf() { [native code] } +expandable = false +key = bar +valueAsObject = hello +valueAsString = "hello" +expandable = false +key = foo +valueAsObject = 34 +valueAsString = 34 +undefined +null +"hello" +3.141592653589793 +[object global] +script class name pattern satisfied? true +Source info +content = print('hello') +hash = 1655359881 +name = test +url = null diff --git a/test/script/nosecurity/debuggersupportapi.js b/test/script/nosecurity/debuggersupportapi.js new file mode 100644 index 00000000..f2fa1014 --- /dev/null +++ b/test/script/nosecurity/debuggersupportapi.js @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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-8044798: API for debugging Nashorn + * + * @test + * @run + */ + +// Basic API class, method, field existence checks. + +// The following classes and the associated methods and fields are used as +// private debugger interface. Though private/implementation defined, nashorn +// code should not be changed to remove these classes, fields and methods. +// The test takes signatures of debugger interface and stores in .EXPECTED file. +// If any incompatible change is made to nashorn to break any of these, this +// test will fail. + +var Arrays = Java.type("java.util.Arrays"); +var DebuggerSupport = Java.type("jdk.nashorn.internal.runtime.DebuggerSupport"); + +print(DebuggerSupport.class); +print(); +var methods = DebuggerSupport.class.declaredMethods; +Arrays.sort(methods, function(m1, m2) m1.name.compareTo(m2.name)); +for each (var mth in methods) { + switch (mth.name) { + case "eval": + case "notifyInvoke": + case "getSourceInfo": + case "valueAsString": + case "valueInfos": + print(mth); + break; + case "valueInfo": + if (mth.parameterCount == 3) { + print(mth); + } + break; + } +} +print(); + +var DebuggerValueDesc = Java.type("jdk.nashorn.internal.runtime.DebuggerSupport.DebuggerValueDesc"); +print(DebuggerValueDesc.class); +print(); +var fields = DebuggerValueDesc.class.declaredFields; +Arrays.sort(fields, function(f1, f2) f1.name.compareTo(f2.name)); +for each (var fld in fields) { + switch (fld.name) { + case "key": + case "expandable": + case "valueAsObject": + case "valueAsString": + print(fld); + } +} +print(); + +var SourceInfo = Java.type("jdk.nashorn.internal.runtime.DebuggerSupport.SourceInfo"); +print(SourceInfo.class); +print(); +var fields = SourceInfo.class.declaredFields; +Arrays.sort(fields, function(f1, f2) f1.name.compareTo(f2.name)); +for each (var fld in fields) { + switch (fld.name) { + case "name": + case "hash": + case "url": + case "content": + print(fld); + } +} diff --git a/test/script/nosecurity/debuggersupportapi.js.EXPECTED b/test/script/nosecurity/debuggersupportapi.js.EXPECTED new file mode 100644 index 00000000..0db8b30c --- /dev/null +++ b/test/script/nosecurity/debuggersupportapi.js.EXPECTED @@ -0,0 +1,22 @@ +class jdk.nashorn.internal.runtime.DebuggerSupport + +static java.lang.Object jdk.nashorn.internal.runtime.DebuggerSupport.eval(jdk.nashorn.internal.runtime.ScriptObject,java.lang.Object,java.lang.String,boolean) +static jdk.nashorn.internal.runtime.DebuggerSupport$SourceInfo jdk.nashorn.internal.runtime.DebuggerSupport.getSourceInfo(java.lang.Class) +static void jdk.nashorn.internal.runtime.DebuggerSupport.notifyInvoke(java.lang.invoke.MethodHandle) +static java.lang.String jdk.nashorn.internal.runtime.DebuggerSupport.valueAsString(java.lang.Object) +static jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc jdk.nashorn.internal.runtime.DebuggerSupport.valueInfo(java.lang.String,java.lang.Object,boolean) +static jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc[] jdk.nashorn.internal.runtime.DebuggerSupport.valueInfos(java.lang.Object,boolean) + +class jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc + +final boolean jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc.expandable +final java.lang.String jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc.key +final java.lang.Object jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc.valueAsObject +final java.lang.String jdk.nashorn.internal.runtime.DebuggerSupport$DebuggerValueDesc.valueAsString + +class jdk.nashorn.internal.runtime.DebuggerSupport$SourceInfo + +final char[] jdk.nashorn.internal.runtime.DebuggerSupport$SourceInfo.content +final int jdk.nashorn.internal.runtime.DebuggerSupport$SourceInfo.hash +final java.lang.String jdk.nashorn.internal.runtime.DebuggerSupport$SourceInfo.name +final java.net.URL jdk.nashorn.internal.runtime.DebuggerSupport$SourceInfo.url diff --git a/test/script/nosecurity/nosecurity.js b/test/script/nosecurity/nosecurity.js new file mode 100644 index 00000000..688af8cf --- /dev/null +++ b/test/script/nosecurity/nosecurity.js @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/** + * 8043443: Test framework changes to run script tests without security manager + * @test + * @run + */ + +var System = Java.type("java.lang.System"); + +if (System.securityManager != null) { + fail("SecurityManager is set!"); +} diff --git a/test/src/jdk/nashorn/api/scripting/ScopeTest.java b/test/src/jdk/nashorn/api/scripting/ScopeTest.java index dc27d826..e2aec242 100644 --- a/test/src/jdk/nashorn/api/scripting/ScopeTest.java +++ b/test/src/jdk/nashorn/api/scripting/ScopeTest.java @@ -510,6 +510,23 @@ public class ScopeTest { assertEquals(e.eval("x", newCtxt), 2); } + // @bug 8044750: megamorphic getter for scope objects does not call __noSuchProperty__ hook + @Test + public static void testMegamorphicGetInGlobal() throws Exception { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine engine = m.getEngineByName("nashorn"); + final String script = "foo"; + // "foo" is megamorphic because of different global scopes. + // Make sure ScriptContext variable search works even after + // it becomes megamorphic. + for (int index = 0; index < 25; index++) { + final Bindings bindings = new SimpleBindings(); + bindings.put("foo", index); + final Number value = (Number)engine.eval(script, bindings); + assertEquals(index, value.intValue()); + } + } + /** * Test "slow" scopes involving {@code with} and {@code eval} statements for shared script classes with multiple globals. */ diff --git a/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java index 241f22c3..30eaefca 100644 --- a/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java +++ b/test/src/jdk/nashorn/api/scripting/ScriptObjectMirrorTest.java @@ -29,6 +29,8 @@ import java.nio.ByteBuffer; import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.script.Bindings; +import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; @@ -276,4 +278,31 @@ public class ScriptObjectMirrorTest { "({ toString: function() { return 'foo' } })"); assertEquals("foo", obj.to(String.class)); } + + // @bug 8044000: Access to undefined property yields "null" instead of "undefined" + @Test + public void mapScriptObjectMirrorCallsiteTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine engine = m.getEngineByName("nashorn"); + final String TEST_SCRIPT = "typeof obj.foo"; + + final Bindings global = engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE); + engine.eval("var obj = java.util.Collections.emptyMap()"); + // this will drive callsite "obj.foo" of TEST_SCRIPT + // to use "obj instanceof Map" as it's guard + engine.eval(TEST_SCRIPT, global); + // redefine 'obj' to be a script object + engine.eval("obj = {}"); + + final Bindings newGlobal = engine.createBindings(); + // transfer 'obj' from default global to new global + // new global will get a ScriptObjectMirror wrapping 'obj' + newGlobal.put("obj", global.get("obj")); + + // Every ScriptObjectMirror is a Map! If callsite "obj.foo" + // does not see the new 'obj' is a ScriptObjectMirror, it'll + // continue to use Map's get("obj.foo") instead of ScriptObjectMirror's + // getMember("obj.foo") - thereby getting null instead of undefined + assertEquals("undefined", engine.eval(TEST_SCRIPT, newGlobal)); + } } |