From edc01dfee9918172aefe04568e2898ed17ebcdfc Mon Sep 17 00:00:00 2001 From: sundar Date: Tue, 20 May 2014 08:32:09 +0530 Subject: 8043443: Test framework changes to run script tests without security manager Reviewed-by: attila --- make/build.xml | 19 +++++++++++++++++++ make/project.properties | 6 ++++++ test/script/nosecurity/nosecurity.js | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 test/script/nosecurity/nosecurity.js diff --git a/make/build.xml b/make/build.xml index 4d23f228..35877aef 100644 --- a/make/build.xml +++ b/make/build.xml @@ -348,6 +348,10 @@ grant codeBase "file:/${basedir}/test/script/basic/classloader.js" { + + + + @@ -361,6 +365,21 @@ grant codeBase "file:/${basedir}/test/script/basic/classloader.js" { + + + + + + + + + + + + + + diff --git a/make/project.properties b/make/project.properties index 8c5dd4f4..d38dd50d 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 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!"); +} -- cgit v1.2.3 From 275ceaf7c4e14832387b1da778ccc544c22a6a4e Mon Sep 17 00:00:00 2001 From: hannesw Date: Thu, 22 May 2014 17:51:56 +0200 Subject: 8030202: Nashorn: Multiple RegExp#ignoreCase issues Reviewed-by: sundar, jlaskey --- .../internal/runtime/regexp/joni/Analyser.java | 4 +- .../runtime/regexp/joni/ApplyCaseFold.java | 68 ++++++------------- .../runtime/regexp/joni/ByteCodeMachine.java | 10 +-- .../runtime/regexp/joni/EncodingHelper.java | 79 ++++++++++++++++------ .../runtime/regexp/joni/SearchAlgorithm.java | 2 +- test/script/basic/JDK-8030202.js | 57 ++++++++++++++++ test/script/basic/JDK-8030202.js.EXPECTED | 22 ++++++ 7 files changed, 165 insertions(+), 77 deletions(-) create mode 100644 test/script/basic/JDK-8030202.js create mode 100644 test/script/basic/JDK-8030202.js.EXPECTED 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= 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/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 -- cgit v1.2.3 From 6a0591d04e739d5e220432b43d1445bf1023dcf4 Mon Sep 17 00:00:00 2001 From: mnunez Date: Thu, 22 May 2014 11:12:29 +0200 Subject: 8028615: jdk.nashorn.x3::some.serious.failure needs more memory to run Reviewed-by: attila, sundar Contributed-by: sergey.lugovoy@oracle.com --- make/project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/project.properties b/make/project.properties index d38dd50d..2abccdeb 100644 --- a/make/project.properties +++ b/make/project.properties @@ -251,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 -- cgit v1.2.3 From 42fbdf6d39a1d894351322a72fcd175d578214fc Mon Sep 17 00:00:00 2001 From: sundar Date: Mon, 26 May 2014 15:48:25 +0530 Subject: 8043930: TypeError when attemping to create an instance of non-public class could be better Reviewed-by: attila, lagergren --- .../runtime/linker/NashornStaticClassLinker.java | 6 ++++ .../internal/runtime/resources/Messages.properties | 1 + test/script/basic/JDK-8043930.js | 37 ++++++++++++++++++++++ test/script/basic/JDK-8043930.js.EXPECTED | 1 + 4 files changed, 45 insertions(+) create mode 100644 test/script/basic/JDK-8043930.js create mode 100644 test/script/basic/JDK-8043930.js.EXPECTED 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/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-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. -- cgit v1.2.3 From 95ad38e3ec82e03e821e5d523e357fd27de78dc9 Mon Sep 17 00:00:00 2001 From: sundar Date: Tue, 27 May 2014 17:40:19 +0530 Subject: 8044000: Access to undefined property yields "null" instead of "undefined" Reviewed-by: lagergren, jlaskey --- .../nashorn/internal/runtime/linker/Bootstrap.java | 14 ++++++++--- .../internal/runtime/linker/JSObjectLinker.java | 19 ++++++++++++-- .../internal/runtime/linker/NashornGuards.java | 15 +++++++++++ .../api/scripting/ScriptObjectMirrorTest.java | 29 ++++++++++++++++++++++ 4 files changed, 72 insertions(+), 5 deletions(-) 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); @@ -60,6 +62,14 @@ public final class NashornGuards { return IS_SCRIPTOBJECT; } + /** + * 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 @@ -156,6 +166,11 @@ public final class NashornGuards { return self instanceof ScriptObject; } + @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/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)); + } } -- cgit v1.2.3