From 0c6c3fa370d97964decd95f232d6cae700998268 Mon Sep 17 00:00:00 2001 From: lagergren Date: Mon, 17 Nov 2014 14:36:15 +0100 Subject: 8049407: Endianness problem with TypedArrays Reviewed-by: hannesw, sundar --- test/script/basic/JDK-8049407-big-endian.js | 33 +++ .../basic/JDK-8049407-big-endian.js.EXPECTED | 1 + test/script/basic/JDK-8049407-payload.js | 37 ++++ test/script/basic/JDK-8049407.js | 33 +++ test/script/basic/JDK-8049407.js.EXPECTED | 1 + test/script/basic/NASHORN-377-big-endian.js | 33 +++ .../basic/NASHORN-377-big-endian.js.EXPECTED | 34 ++++ test/script/basic/NASHORN-377-payload.js | 226 +++++++++++++++++++++ test/script/basic/NASHORN-377.js | 199 +----------------- .../internal/test/framework/TestFinder.java | 7 + 10 files changed, 408 insertions(+), 196 deletions(-) create mode 100644 test/script/basic/JDK-8049407-big-endian.js create mode 100644 test/script/basic/JDK-8049407-big-endian.js.EXPECTED create mode 100644 test/script/basic/JDK-8049407-payload.js create mode 100644 test/script/basic/JDK-8049407.js create mode 100644 test/script/basic/JDK-8049407.js.EXPECTED create mode 100644 test/script/basic/NASHORN-377-big-endian.js create mode 100644 test/script/basic/NASHORN-377-big-endian.js.EXPECTED create mode 100644 test/script/basic/NASHORN-377-payload.js diff --git a/test/script/basic/JDK-8049407-big-endian.js b/test/script/basic/JDK-8049407-big-endian.js new file mode 100644 index 00000000..323c4540 --- /dev/null +++ b/test/script/basic/JDK-8049407-big-endian.js @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/** + * Verify DataView behavior with little/big endian + * + * @test + * @run + * @bigendian + */ + +var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__; +load(dir + "JDK-8049407-payload.js"); diff --git a/test/script/basic/JDK-8049407-big-endian.js.EXPECTED b/test/script/basic/JDK-8049407-big-endian.js.EXPECTED new file mode 100644 index 00000000..c508d536 --- /dev/null +++ b/test/script/basic/JDK-8049407-big-endian.js.EXPECTED @@ -0,0 +1 @@ +false diff --git a/test/script/basic/JDK-8049407-payload.js b/test/script/basic/JDK-8049407-payload.js new file mode 100644 index 00000000..467d4bb7 --- /dev/null +++ b/test/script/basic/JDK-8049407-payload.js @@ -0,0 +1,37 @@ +/* + * 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. + */ + +/** + * Verify DataView behavior with little/big endian + * + * @subtest + * @run + */ + +var littleEndian = (function() { + var buffer = new ArrayBuffer(2); + new DataView(buffer).setInt16(0, 256, true); + return new Int16Array(buffer)[0] === 256; + })(); + +print(littleEndian); diff --git a/test/script/basic/JDK-8049407.js b/test/script/basic/JDK-8049407.js new file mode 100644 index 00000000..4bfcd26c --- /dev/null +++ b/test/script/basic/JDK-8049407.js @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/** + * Verify DataView behavior with little/big endian + * + * @test + * @run + * @littleendian + */ + +var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__; +load(dir + "JDK-8049407-payload.js"); diff --git a/test/script/basic/JDK-8049407.js.EXPECTED b/test/script/basic/JDK-8049407.js.EXPECTED new file mode 100644 index 00000000..27ba77dd --- /dev/null +++ b/test/script/basic/JDK-8049407.js.EXPECTED @@ -0,0 +1 @@ +true diff --git a/test/script/basic/NASHORN-377-big-endian.js b/test/script/basic/NASHORN-377-big-endian.js new file mode 100644 index 00000000..30f0cc3e --- /dev/null +++ b/test/script/basic/NASHORN-377-big-endian.js @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/* + * NASHORN-377: Typed arrays. + * + * @test + * @run + * @bigendian + */ + +var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__; +load(dir + "NASHORN-377-payload.js"); diff --git a/test/script/basic/NASHORN-377-big-endian.js.EXPECTED b/test/script/basic/NASHORN-377-big-endian.js.EXPECTED new file mode 100644 index 00000000..ed3f19ab --- /dev/null +++ b/test/script/basic/NASHORN-377-big-endian.js.EXPECTED @@ -0,0 +1,34 @@ +8 8 true undefined +[object ArrayBuffer] [object ArrayBuffer] [object Int8Array] +0 8 8 1 +0 8 8 1 +0 8 8 1 +0 8 4 2 +0 8 4 2 +0 8 2 4 +0 8 2 4 +0 8 2 4 +0 8 1 8 +7071727374-807677 7071727374807677 +727374-807677 2 6 +72737480 2 4 +71727374 1 4 +717273748076 +7071727374807677 1886483059 1954575991 +70717273-1020305 1886483059 -16909061 +70717273fefdfcfb 1886483059 4278058235 +40490fdafefdfcfb 2 +400921fb4d12d84a 1 +400921fb4d12d84a 1074340347 1293080650 +00000000400921fb4d12d84a +400921fb4d12-27b6 400921fb4d12d84a +00-100804d12-27b6 ffff00804d12d84a +0 1 2 3 4 5 6 7 +0102030405060708 +subarray(2,4)=0304 subarray(-6,-4)=0304 +010203040506 +03040506 0405 +0102030405060708090a0b0c0d0e0f10 +slice(4,8)=05060708 slice(-8,-4)=090a0b0c +0102030405060708090a0b0c +060708090a0b diff --git a/test/script/basic/NASHORN-377-payload.js b/test/script/basic/NASHORN-377-payload.js new file mode 100644 index 00000000..b47fb7cf --- /dev/null +++ b/test/script/basic/NASHORN-377-payload.js @@ -0,0 +1,226 @@ +/* + * 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. + */ + +/* + * NASHORN-377: Typed arrays. Payload for litte and big endian platforms. + * + * @subtest + * @run + */ + +var types = [Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array]; + +//--------------------------------------------------------------------------- +// utility functions +//--------------------------------------------------------------------------- +function tohex(d, w) { + var hex = Number(d).toString(16); + var pad = (w ? w : 8) - hex.length; + hex = "00000000".substr(0, pad) + hex; + return hex; +} + +function arrstr(a, n, w) { + var s = ""; + if (typeof n == "undefined") n = a.length; + if (typeof w == "undefined") w = a.constructor.BYTES_PER_ELEMENT * 2; + for (var i = 0; i < n; i++) { + s += tohex(a[i], w); + } + return s; +} +function bufstr(b) { + if (b.buffer !== undefined) { + b = b.buffer; + } + return arrstr(new Uint8Array(b)); +} + +function assertFail(f) { + try { + f(); + } catch (e) { + //print(e); + return; + } + throw "assertion failed: expected exception"; +} + +function assertTrue(f) { + if (f() !== true) throw "assertion failed: " + f; +} + +function isUndefined(x) { + return typeof x === "undefined"; +} + +function fillArray(a, start) { + if (typeof start == "undefined") start = 1; + for (var i = 0; i < a.length; i++) { + a[i] = i + start; + } + return a; +} + +//--------------------------------------------------------------------------- +// tests +//--------------------------------------------------------------------------- +(function() { + var b = new ArrayBuffer(8); + var i8 = new Int8Array(b); + print(i8.buffer.byteLength, b.byteLength, i8.buffer === b, b.length); + print(b, i8.buffer, i8); +})(); + +(function test_attributes() { + var b = new ArrayBuffer(8); + for (var i in types) { + var x = new types[i](b); + print(x.byteOffset, x.byteLength, x.length, x.constructor.BYTES_PER_ELEMENT); + assertTrue(function(){ return x.constructor === types[i] }); + } +})(); + +(function() { + var b = new ArrayBuffer(8); + var i8 = new Int8Array(b); + fillArray(i8, 0x70); + + var i8_2 = new Int8Array(b, 2); + var i8_2_4 = new Uint8Array(b, 2, 4); + + i8_2_4[3] = 0x80; + + print(arrstr(i8, 8, 2) + " " + bufstr(i8)); + print(arrstr(i8_2, 6) + " " + i8_2.byteOffset + " " + i8_2.byteLength); + print(arrstr(i8_2_4, 4) + " " + i8_2_4.byteOffset + " " + i8_2_4.byteLength); + + var i8_1_5 = i8.subarray(1, 5); + i8_2_4.subarray(1, 5); + print(arrstr(i8_1_5, 4) + " " + i8_1_5.byteOffset + " " + i8_1_5.byteLength); + + print(bufstr(b.slice(1,7))); +})(); + +(function() { + var b = new ArrayBuffer(8); + fillArray(new Int8Array(b), 0x70); + new Int8Array(b)[5] = 0x80; + + var i32 = new Int32Array(b); + var u32 = new Uint32Array(b); + print(arrstr(i32), i32[0], i32[1]); + i32[1] = 0xfefdfcfb; + print(arrstr(i32), i32[0], i32[1]); + print(arrstr(u32), u32[0], u32[1]); + + var pi = 3.1415926; + var f32 = new Float32Array(b); + var f64 = new Float64Array(b); + f32[0] = pi; + print(bufstr(b), f32.length); + f64[0] = pi; + print(bufstr(b), f64.length); + print(arrstr(u32), u32[0], u32[1]); + + var d = new Int32Array(3); + d.set(i32,1); + print(bufstr(d)); + + var s = new Int16Array(b); + var t = new Uint16Array(b); + print(arrstr(s), arrstr(t)); + s[0] = -1; s[1] = 0x80; + print(arrstr(s), arrstr(t)); +})(); + +(function enumerate_properties() { + var i8 = new Int8Array(new ArrayBuffer(8)); + var s = ""; for (var i in i8) { s += i + " "; } print(s.trim()); +})(); + +// check that ScriptObject fallback is still working +// DISABLED because correct behavior is unclear +(function() { + // NB: firefox will never set any out-of-bounds or non-array values although it does get both from prototype. + var z = new Uint8Array(4); + z["asdf"] = "asdf"; print(z["asdf"]); + z[0x100000000] = "asdf"; print(z[0x100000000]); + z[-1] = "asdf"; print(z[-1]); + + // v8 and nashorn disagree on out-of-bounds uint32 indices: v8 won't go to the prototype. + z[0xf0000000] = "asdf"; print(z[0xf0000000]); + z[0xffffffff] = "asdf"; print(z[0xffffffff]); + z[0x70000000] = "asdf"; print(z[0x70000000]); + + // this will work in firefox and nashorn (not in v8). + Uint8Array.prototype[4] = "asdf"; print(z[4]); +}); + +(function test_exceptions() { + assertFail(function() { new Int32Array(new ArrayBuffer(7)); }); + assertFail(function() { new Int32Array(new ArrayBuffer(8), 0, 4); }); + assertFail(function() { new Int32Array(new ArrayBuffer(8),-1, 2); }); + assertFail(function() { new Int32Array(new ArrayBuffer(8), 0,-1); }); +})(); + +(function test_subarray() { + var x = fillArray(new Int8Array(8)); + print(arrstr(x)); + print("subarray(2,4)=" + arrstr(x.subarray(2, 4)), "subarray(-6,-4)=" + arrstr(x.subarray(-6, -4))); // negative index refers from the end of the array + print(arrstr(x.subarray(-10, -2))); // negative index clamped to 0 + assertTrue(function(){ return arrstr(x.subarray(6, 4)) === ""; }); // negative length clamped to 0 + print(arrstr(x.subarray(1,-1).subarray(1,-1)), arrstr(x.subarray(1,-1).subarray(1,-1).subarray(1,-1))); // subarray of subarray +})(); + +(function test_slice() { + var b = new ArrayBuffer(16); + fillArray(new Int8Array(b)); + print(bufstr(b)); + print("slice(4,8)=" + bufstr(b.slice(4, 8)), "slice(-8,-4)=" + bufstr(b.slice(-8, -4))); // negative index refers from the end of the array + print(bufstr(b.slice(-20, -4))); // negative index clamped to 0 + assertTrue(function(){ return bufstr(b.slice(8, 4)) === ""; }); // negative length clamped to 0 + print(arrstr(new Int16Array(b.slice(1,-1).slice(2,-1).slice(1,-2).slice(1,-1)))); // slice of slice +})(); + +(function test_clamped() { + var a = new Uint8ClampedArray(10); + a[0] = -17; // clamped to 0 + a[1] = 4711; // clamped to 255 + a[2] = 17.5; // clamped to 18 + a[3] = 16.5; // clamped to 16 + a[4] = 255.9; // clamped to 255 + a[5] = Infinity; // clamped to 255 + a[6] = -Infinity; // clamped to 0 + a[7] = NaN; // 0 + assertTrue(function(){ return a[0] === 0 && a[1] === 255 && a[2] === 18 && a[3] === 16 && a[4] === 255 && a[5] === 255 && a[6] === 0 && a[7] === 0; }); +})(); + +(function test_out_of_bounds() { + var a = new Int32Array(10); + a[10] = 10; + a[100] = 100; + a[1000] = 1000; + assertTrue(function(){ return isUndefined(a[10]) && isUndefined(a[11]) && isUndefined(a[100]) && isUndefined(a[123]) && isUndefined(a[1000]); }); +})(); + diff --git a/test/script/basic/NASHORN-377.js b/test/script/basic/NASHORN-377.js index 968e46e8..3484223f 100644 --- a/test/script/basic/NASHORN-377.js +++ b/test/script/basic/NASHORN-377.js @@ -26,201 +26,8 @@ * * @test * @run + * @littleendian */ -var types = [Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array]; - -//--------------------------------------------------------------------------- -// utility functions -//--------------------------------------------------------------------------- -function tohex(d, w) { - var hex = Number(d).toString(16); - var pad = (w ? w : 8) - hex.length; - hex = "00000000".substr(0, pad) + hex; - return hex; -} - -function arrstr(a, n, w) { - var s = ""; - if (typeof n == "undefined") n = a.length; - if (typeof w == "undefined") w = a.constructor.BYTES_PER_ELEMENT * 2; - for (var i = 0; i < n; i++) { - s += tohex(a[i], w); - } - return s; -} -function bufstr(b) { - if (b.buffer !== undefined) { - b = b.buffer; - } - return arrstr(new Uint8Array(b)); -} - -function assertFail(f) { - try { - f(); - } catch (e) { - //print(e); - return; - } - throw "assertion failed: expected exception"; -} - -function assertTrue(f) { - if (f() !== true) throw "assertion failed: " + f; -} - -function isUndefined(x) { - return typeof x === "undefined"; -} - -function fillArray(a, start) { - if (typeof start == "undefined") start = 1; - for (var i = 0; i < a.length; i++) { - a[i] = i + start; - } - return a; -} - -//--------------------------------------------------------------------------- -// tests -//--------------------------------------------------------------------------- -(function() { - var b = new ArrayBuffer(8); - var i8 = new Int8Array(b); - print(i8.buffer.byteLength, b.byteLength, i8.buffer === b, b.length); - print(b, i8.buffer, i8); -})(); - -(function test_attributes() { - var b = new ArrayBuffer(8); - for (var i in types) { - var x = new types[i](b); - print(x.byteOffset, x.byteLength, x.length, x.constructor.BYTES_PER_ELEMENT); - assertTrue(function(){ return x.constructor === types[i] }); - } -})(); - -(function() { - var b = new ArrayBuffer(8); - var i8 = new Int8Array(b); - fillArray(i8, 0x70); - - var i8_2 = new Int8Array(b, 2); - var i8_2_4 = new Uint8Array(b, 2, 4); - - i8_2_4[3] = 0x80; - - print(arrstr(i8, 8, 2) + " " + bufstr(i8)); - print(arrstr(i8_2, 6) + " " + i8_2.byteOffset + " " + i8_2.byteLength); - print(arrstr(i8_2_4, 4) + " " + i8_2_4.byteOffset + " " + i8_2_4.byteLength); - - var i8_1_5 = i8.subarray(1, 5); - i8_2_4.subarray(1, 5); - print(arrstr(i8_1_5, 4) + " " + i8_1_5.byteOffset + " " + i8_1_5.byteLength); - - print(bufstr(b.slice(1,7))); -})(); - -(function() { - var b = new ArrayBuffer(8); - fillArray(new Int8Array(b), 0x70); - new Int8Array(b)[5] = 0x80; - - var i32 = new Int32Array(b); - var u32 = new Uint32Array(b); - print(arrstr(i32), i32[0], i32[1]); - i32[1] = 0xfefdfcfb; - print(arrstr(i32), i32[0], i32[1]); - print(arrstr(u32), u32[0], u32[1]); - - var pi = 3.1415926; - var f32 = new Float32Array(b); - var f64 = new Float64Array(b); - f32[0] = pi; - print(bufstr(b), f32.length); - f64[0] = pi; - print(bufstr(b), f64.length); - print(arrstr(u32), u32[0], u32[1]); - - var d = new Int32Array(3); - d.set(i32,1); - print(bufstr(d)); - - var s = new Int16Array(b); - var t = new Uint16Array(b); - print(arrstr(s), arrstr(t)); - s[0] = -1; s[1] = 0x80; - print(arrstr(s), arrstr(t)); -})(); - -(function enumerate_properties() { - var i8 = new Int8Array(new ArrayBuffer(8)); - var s = ""; for (var i in i8) { s += i + " "; } print(s.trim()); -})(); - -// check that ScriptObject fallback is still working -// DISABLED because correct behavior is unclear -(function() { - // NB: firefox will never set any out-of-bounds or non-array values although it does get both from prototype. - var z = new Uint8Array(4); - z["asdf"] = "asdf"; print(z["asdf"]); - z[0x100000000] = "asdf"; print(z[0x100000000]); - z[-1] = "asdf"; print(z[-1]); - - // v8 and nashorn disagree on out-of-bounds uint32 indices: v8 won't go to the prototype. - z[0xf0000000] = "asdf"; print(z[0xf0000000]); - z[0xffffffff] = "asdf"; print(z[0xffffffff]); - z[0x70000000] = "asdf"; print(z[0x70000000]); - - // this will work in firefox and nashorn (not in v8). - Uint8Array.prototype[4] = "asdf"; print(z[4]); -}); - -(function test_exceptions() { - assertFail(function() { new Int32Array(new ArrayBuffer(7)); }); - assertFail(function() { new Int32Array(new ArrayBuffer(8), 0, 4); }); - assertFail(function() { new Int32Array(new ArrayBuffer(8),-1, 2); }); - assertFail(function() { new Int32Array(new ArrayBuffer(8), 0,-1); }); -})(); - -(function test_subarray() { - var x = fillArray(new Int8Array(8)); - print(arrstr(x)); - print("subarray(2,4)=" + arrstr(x.subarray(2, 4)), "subarray(-6,-4)=" + arrstr(x.subarray(-6, -4))); // negative index refers from the end of the array - print(arrstr(x.subarray(-10, -2))); // negative index clamped to 0 - assertTrue(function(){ return arrstr(x.subarray(6, 4)) === ""; }); // negative length clamped to 0 - print(arrstr(x.subarray(1,-1).subarray(1,-1)), arrstr(x.subarray(1,-1).subarray(1,-1).subarray(1,-1))); // subarray of subarray -})(); - -(function test_slice() { - var b = new ArrayBuffer(16); - fillArray(new Int8Array(b)); - print(bufstr(b)); - print("slice(4,8)=" + bufstr(b.slice(4, 8)), "slice(-8,-4)=" + bufstr(b.slice(-8, -4))); // negative index refers from the end of the array - print(bufstr(b.slice(-20, -4))); // negative index clamped to 0 - assertTrue(function(){ return bufstr(b.slice(8, 4)) === ""; }); // negative length clamped to 0 - print(arrstr(new Int16Array(b.slice(1,-1).slice(2,-1).slice(1,-2).slice(1,-1)))); // slice of slice -})(); - -(function test_clamped() { - var a = new Uint8ClampedArray(10); - a[0] = -17; // clamped to 0 - a[1] = 4711; // clamped to 255 - a[2] = 17.5; // clamped to 18 - a[3] = 16.5; // clamped to 16 - a[4] = 255.9; // clamped to 255 - a[5] = Infinity; // clamped to 255 - a[6] = -Infinity; // clamped to 0 - a[7] = NaN; // 0 - assertTrue(function(){ return a[0] === 0 && a[1] === 255 && a[2] === 18 && a[3] === 16 && a[4] === 255 && a[5] === 255 && a[6] === 0 && a[7] === 0; }); -})(); - -(function test_out_of_bounds() { - var a = new Int32Array(10); - a[10] = 10; - a[100] = 100; - a[1000] = 1000; - assertTrue(function(){ return isUndefined(a[10]) && isUndefined(a[11]) && isUndefined(a[100]) && isUndefined(a[123]) && isUndefined(a[1000]); }); -})(); - +var dir = typeof(__DIR__) == 'undefined' ? "test/script/basic/" : __DIR__; +load(dir + "NASHORN-377-payload.js"); diff --git a/test/src/jdk/nashorn/internal/test/framework/TestFinder.java b/test/src/jdk/nashorn/internal/test/framework/TestFinder.java index ab472d70..32b1cbd5 100644 --- a/test/src/jdk/nashorn/internal/test/framework/TestFinder.java +++ b/test/src/jdk/nashorn/internal/test/framework/TestFinder.java @@ -46,6 +46,7 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.nio.ByteOrder; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.FileVisitOption; @@ -264,6 +265,12 @@ public final class TestFinder { isTest = false; isNotTest = true; break; + case "@bigendian": + shouldRun = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN; + break; + case "@littleendian": + shouldRun = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN; + break; case "@runif": { final String prop = scanner.next(); if (System.getProperty(prop) != null) { -- cgit v1.2.3 From 422aa12f3ece2332330f86c1666ae223a3ab8bba Mon Sep 17 00:00:00 2001 From: hannesw Date: Fri, 21 Nov 2014 20:17:02 +0100 Subject: 8064789: Nashorn should just warn on code store instantiation error Reviewed-by: attila, lagergren --- src/jdk/nashorn/internal/runtime/CodeStore.java | 16 ++++++++++------ src/jdk/nashorn/internal/runtime/Context.java | 8 ++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/jdk/nashorn/internal/runtime/CodeStore.java b/src/jdk/nashorn/internal/runtime/CodeStore.java index 0e85beeb..4e745ff4 100644 --- a/src/jdk/nashorn/internal/runtime/CodeStore.java +++ b/src/jdk/nashorn/internal/runtime/CodeStore.java @@ -82,10 +82,9 @@ public abstract class CodeStore implements Loggable { * Returns a new code store instance. * * @param context the current context - * @return The instance - * @throws IOException If an error occurs + * @return The instance, or null if code store could not be created */ - public static CodeStore newCodeStore(final Context context) throws IOException { + public static CodeStore newCodeStore(final Context context) { final Class baseClass = CodeStore.class; try { // security check first @@ -103,9 +102,14 @@ public abstract class CodeStore implements Loggable { } catch (final AccessControlException e) { context.getLogger(CodeStore.class).warning("failed to load code store provider ", e); } - final CodeStore store = new DirectoryCodeStore(context); - store.initLogger(context); - return store; + try { + final CodeStore store = new DirectoryCodeStore(context); + store.initLogger(context); + return store; + } catch (final IOException e) { + context.getLogger(CodeStore.class).warning("failed to create cache directory ", e); + return null; + } } diff --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java index 86369ab7..9e851998 100644 --- a/src/jdk/nashorn/internal/runtime/Context.java +++ b/src/jdk/nashorn/internal/runtime/Context.java @@ -509,11 +509,7 @@ public final class Context { } if (env._persistent_cache) { - try { - codeStore = newCodeStore(this); - } catch (final IOException e) { - throw new RuntimeException("Error initializing code cache", e); - } + codeStore = newCodeStore(this); } // print version info if asked. @@ -1200,7 +1196,7 @@ public final class Context { FunctionNode functionNode = null; // We only use the code store here if optimistic types are disabled. With optimistic types, initial compilation // just creates a thin wrapper, and actual code is stored per function in RecompilableScriptFunctionData. - final boolean useCodeStore = env._persistent_cache && !env._parse_only && !env._optimistic_types; + final boolean useCodeStore = codeStore != null && !env._parse_only && !env._optimistic_types; final String cacheKey = useCodeStore ? CodeStore.getCacheKey(0, null) : null; if (useCodeStore) { -- cgit v1.2.3 From 9e84bddace10ff39aabfa7dbcdcc16cb0c9e656c Mon Sep 17 00:00:00 2001 From: hannesw Date: Mon, 24 Nov 2014 12:03:15 +0100 Subject: 8057691: Nashorn: let & const declarations are not shared between scripts Reviewed-by: lagergren, attila --- .../nashorn/internal/codegen/AssignSymbols.java | 6 +- src/jdk/nashorn/internal/codegen/MapCreator.java | 4 + src/jdk/nashorn/internal/objects/Global.java | 188 +++++++++++++++++- src/jdk/nashorn/internal/parser/Parser.java | 15 +- src/jdk/nashorn/internal/runtime/Property.java | 17 +- src/jdk/nashorn/internal/runtime/ScriptObject.java | 59 ++++-- .../basic/es6/const-redeclare-extra.js.EXPECTED | 12 +- test/script/basic/es6/let-load.js | 3 +- test/script/basic/es6/let-load.js.EXPECTED | 4 +- .../basic/es6/let-redeclare-extra.js.EXPECTED | 10 +- test/script/basic/es6/lexical-toplevel-def.js | 34 ++++ test/script/basic/es6/lexical-toplevel-print.js | 51 +++++ .../es6/lexical-toplevel-redeclare-func-on-let.js | 31 +++ .../lexical-toplevel-redeclare-let-on-builtin.js | 30 +++ .../es6/lexical-toplevel-redeclare-let-on-func.js | 31 +++ .../lexical-toplevel-redeclare-let-on-global.js | 30 +++ .../es6/lexical-toplevel-redeclare-let-on-var.js | 31 +++ .../es6/lexical-toplevel-redeclare-var-on-let.js | 31 +++ .../script/basic/es6/lexical-toplevel-redeclare.js | 78 ++++++++ .../es6/lexical-toplevel-redeclare.js.EXPECTED | 100 ++++++++++ test/script/basic/es6/lexical-toplevel.js | 35 ++++ test/script/basic/es6/lexical-toplevel.js.EXPECTED | 30 +++ .../internal/runtime/LexicalBindingTest.java | 212 +++++++++++++++++++++ 23 files changed, 983 insertions(+), 59 deletions(-) create mode 100644 test/script/basic/es6/lexical-toplevel-def.js create mode 100644 test/script/basic/es6/lexical-toplevel-print.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare-func-on-let.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare-let-on-builtin.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare-let-on-func.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare-let-on-global.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare-let-on-var.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare-var-on-let.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare.js create mode 100644 test/script/basic/es6/lexical-toplevel-redeclare.js.EXPECTED create mode 100644 test/script/basic/es6/lexical-toplevel.js create mode 100644 test/script/basic/es6/lexical-toplevel.js.EXPECTED create mode 100644 test/src/jdk/nashorn/internal/runtime/LexicalBindingTest.java diff --git a/src/jdk/nashorn/internal/codegen/AssignSymbols.java b/src/jdk/nashorn/internal/codegen/AssignSymbols.java index 88fd89bb..ad0f13c7 100644 --- a/src/jdk/nashorn/internal/codegen/AssignSymbols.java +++ b/src/jdk/nashorn/internal/codegen/AssignSymbols.java @@ -356,6 +356,10 @@ final class AssignSymbols extends NodeVisitor implements Loggabl throwParserException(ECMAErrors.getMessage("syntax.error.redeclare.variable", name), origin); } else { symbol.setHasBeenDeclared(); + // Set scope flag on top-level block scoped symbols + if (function.isProgram() && function.getBody() == block) { + symbol.setIsScope(); + } } } else if ((flags & IS_INTERNAL) != 0) { // Always create a new definition. @@ -540,7 +544,7 @@ final class AssignSymbols extends NodeVisitor implements Loggabl final int flags; if (varNode.isAnonymousFunctionDeclaration()) { flags = IS_INTERNAL; - } else if (lc.getCurrentFunction().isProgram()) { + } else if (!varNode.isBlockScoped() && lc.getCurrentFunction().isProgram()) { flags = IS_SCOPE; } else { flags = 0; diff --git a/src/jdk/nashorn/internal/codegen/MapCreator.java b/src/jdk/nashorn/internal/codegen/MapCreator.java index 3ba3f630..1bec86fc 100644 --- a/src/jdk/nashorn/internal/codegen/MapCreator.java +++ b/src/jdk/nashorn/internal/codegen/MapCreator.java @@ -152,6 +152,10 @@ public class MapCreator { flags |= Property.NOT_WRITABLE; } + if (symbol.isBlockScoped()) { + flags |= Property.IS_LEXICAL_BINDING; + } + // Mark symbol as needing declaration. Access before declaration will throw a ReferenceError. if (symbol.isBlockScoped() && symbol.isScope()) { flags |= Property.NEEDS_DECLARATION; diff --git a/src/jdk/nashorn/internal/objects/Global.java b/src/jdk/nashorn/internal/objects/Global.java index 6a978627..bb3e13d2 100644 --- a/src/jdk/nashorn/internal/objects/Global.java +++ b/src/jdk/nashorn/internal/objects/Global.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.invoke.SwitchPoint; import java.lang.reflect.Field; import java.util.ArrayList; @@ -44,6 +45,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import javax.script.ScriptContext; import javax.script.ScriptEngine; +import jdk.internal.dynalink.CallSiteDescriptor; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.api.scripting.ClassFilter; @@ -54,6 +56,8 @@ import jdk.nashorn.internal.objects.annotations.Property; import jdk.nashorn.internal.objects.annotations.ScriptClass; import jdk.nashorn.internal.runtime.ConsString; import jdk.nashorn.internal.runtime.Context; +import jdk.nashorn.internal.runtime.ECMAErrors; +import jdk.nashorn.internal.runtime.GlobalConstants; import jdk.nashorn.internal.runtime.GlobalFunctions; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.NativeJavaPackage; @@ -69,6 +73,7 @@ import jdk.nashorn.internal.runtime.Specialization; import jdk.nashorn.internal.runtime.arrays.ArrayData; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.InvokeByName; +import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; import jdk.nashorn.internal.runtime.regexp.RegExpResult; import jdk.nashorn.internal.scripts.JO; @@ -410,13 +415,14 @@ public final class Global extends ScriptObject implements Scope { // Used to store the last RegExp result to support deprecated RegExp constructor properties private RegExpResult lastRegExpResult; - private static final MethodHandle EVAL = findOwnMH_S("eval", Object.class, Object.class, Object.class); - private static final MethodHandle NO_SUCH_PROPERTY = findOwnMH_S(NO_SUCH_PROPERTY_NAME, Object.class, Object.class, Object.class); - private static final MethodHandle PRINT = findOwnMH_S("print", Object.class, Object.class, Object[].class); - private static final MethodHandle PRINTLN = findOwnMH_S("println", Object.class, Object.class, Object[].class); - private static final MethodHandle LOAD = findOwnMH_S("load", Object.class, Object.class, Object.class); - private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class); - private static final MethodHandle EXIT = findOwnMH_S("exit", Object.class, Object.class, Object.class); + private static final MethodHandle EVAL = findOwnMH_S("eval", Object.class, Object.class, Object.class); + private static final MethodHandle NO_SUCH_PROPERTY = findOwnMH_S(NO_SUCH_PROPERTY_NAME, Object.class, Object.class, Object.class); + private static final MethodHandle PRINT = findOwnMH_S("print", Object.class, Object.class, Object[].class); + private static final MethodHandle PRINTLN = findOwnMH_S("println", Object.class, Object.class, Object[].class); + private static final MethodHandle LOAD = findOwnMH_S("load", Object.class, Object.class, Object.class); + private static final MethodHandle LOAD_WITH_NEW_GLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class); + private static final MethodHandle EXIT = findOwnMH_S("exit", Object.class, Object.class, Object.class); + private static final MethodHandle LEXICAL_SCOPE_FILTER = findOwnMH_S("lexicalScopeFilter", Object.class, Object.class); // initialized by nasgen private static PropertyMap $nasgenmap$; @@ -429,6 +435,12 @@ public final class Global extends ScriptObject implements Scope { // current ScriptEngine associated - can be null. private ScriptEngine engine; + // ES6 global lexical scope. + private final LexicalScope lexicalScope; + + // Switchpoint for non-constant global callsites in the presence of ES6 lexical scope. + private SwitchPoint lexicalScopeSwitchPoint; + /** * Set the current script context * @param scontext script context @@ -466,6 +478,7 @@ public final class Global extends ScriptObject implements Scope { super(checkAndGetMap(context)); this.context = context; this.setIsScope(); + this.lexicalScope = context.getEnv()._es6 ? new LexicalScope(this) : null; } /** @@ -1694,6 +1707,133 @@ public final class Global extends ScriptObject implements Scope { splitState = state; } + /** + * Return the ES6 global scope for lexically declared bindings. + * @return the ES6 lexical global scope. + */ + public final ScriptObject getLexicalScope() { + assert context.getEnv()._es6; + return lexicalScope; + } + + @Override + public void addBoundProperties(final ScriptObject source, final jdk.nashorn.internal.runtime.Property[] properties) { + PropertyMap ownMap = getMap(); + LexicalScope lexicalScope = null; + PropertyMap lexicalMap = null; + boolean hasLexicalDefinitions = false; + + if (context.getEnv()._es6) { + lexicalScope = (LexicalScope) getLexicalScope(); + lexicalMap = lexicalScope.getMap(); + + for (final jdk.nashorn.internal.runtime.Property property : properties) { + if (property.isLexicalBinding()) { + hasLexicalDefinitions = true; + } + // ES6 15.1.8 steps 6. and 7. + final jdk.nashorn.internal.runtime.Property globalProperty = ownMap.findProperty(property.getKey()); + if (globalProperty != null && !globalProperty.isConfigurable() && property.isLexicalBinding()) { + throw ECMAErrors.syntaxError("redeclare.variable", property.getKey()); + } + final jdk.nashorn.internal.runtime.Property lexicalProperty = lexicalMap.findProperty(property.getKey()); + if (lexicalProperty != null && !property.isConfigurable()) { + throw ECMAErrors.syntaxError("redeclare.variable", property.getKey()); + } + } + } + + for (final jdk.nashorn.internal.runtime.Property property : properties) { + if (property.isLexicalBinding()) { + assert lexicalScope != null; + lexicalMap = lexicalScope.addBoundProperty(lexicalMap, source, property); + + if (ownMap.findProperty(property.getKey()) != null) { + // If property exists in the global object invalidate any global constant call sites. + invalidateGlobalConstant(property.getKey()); + } + } else { + ownMap = addBoundProperty(ownMap, source, property); + } + } + + setMap(ownMap); + + if (hasLexicalDefinitions) { + lexicalScope.setMap(lexicalMap); + invalidateLexicalSwitchPoint(); + } + } + + @Override + public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) { + final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); + final boolean isScope = NashornCallSiteDescriptor.isScope(desc); + + if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) { + if (lexicalScope.hasOwnProperty(name)) { + return lexicalScope.findGetMethod(desc, request, operator); + } + } + + final GuardedInvocation invocation = super.findGetMethod(desc, request, operator); + + // We want to avoid adding our generic lexical scope switchpoint to global constant invocations, + // because those are invalidated per-key in the addBoundProperties method above. + // We therefor check if the invocation does already have a switchpoint and the property is non-inherited, + // assuming this only applies to global constants. If other non-inherited properties will + // start using switchpoints some time in the future we'll have to revisit this. + if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) { + return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); + } + + return invocation; + } + + @Override + public GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { + final boolean isScope = NashornCallSiteDescriptor.isScope(desc); + + if (lexicalScope != null && isScope) { + final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); + if (lexicalScope.hasOwnProperty(name)) { + return lexicalScope.findSetMethod(desc, request); + } + } + + final GuardedInvocation invocation = super.findSetMethod(desc, request); + + if (isScope && context.getEnv()._es6) { + return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); + } + + return invocation; + } + + private synchronized SwitchPoint getLexicalScopeSwitchPoint() { + SwitchPoint switchPoint = lexicalScopeSwitchPoint; + if (switchPoint == null || switchPoint.hasBeenInvalidated()) { + switchPoint = lexicalScopeSwitchPoint = new SwitchPoint(); + } + return switchPoint; + } + + private synchronized void invalidateLexicalSwitchPoint() { + if (lexicalScopeSwitchPoint != null) { + context.getLogger(GlobalConstants.class).info("Invalidating non-constant globals on lexical scope update"); + SwitchPoint.invalidateAll(new SwitchPoint[]{ lexicalScopeSwitchPoint }); + } + } + + + @SuppressWarnings("unused") + private static Object lexicalScopeFilter(final Object self) { + if (self instanceof Global) { + return ((Global) self).getLexicalScope(); + } + return self; + } + private T initConstructorAndSwitchPoint(final String name, final Class clazz) { final T func = initConstructor(name, clazz); tagBuiltinProperties(name, func); @@ -1739,7 +1879,7 @@ public final class Global extends ScriptObject implements Scope { this.unescape = ScriptFunctionImpl.makeFunction("unescape", GlobalFunctions.UNESCAPE); this.print = ScriptFunctionImpl.makeFunction("print", env._print_no_newline ? PRINT : PRINTLN); this.load = ScriptFunctionImpl.makeFunction("load", LOAD); - this.loadWithNewGlobal = ScriptFunctionImpl.makeFunction("loadWithNewGlobal", LOADWITHNEWGLOBAL); + this.loadWithNewGlobal = ScriptFunctionImpl.makeFunction("loadWithNewGlobal", LOAD_WITH_NEW_GLOBAL); this.exit = ScriptFunctionImpl.makeFunction("exit", EXIT); this.quit = ScriptFunctionImpl.makeFunction("quit", EXIT); @@ -2205,4 +2345,36 @@ public final class Global extends ScriptObject implements Scope { protected boolean isGlobal() { return true; } + + /** + * A class representing the ES6 global lexical scope. + */ + private static class LexicalScope extends ScriptObject { + + LexicalScope(final ScriptObject proto) { + super(proto, PropertyMap.newMap()); + } + + @Override + protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) { + return filterInvocation(super.findGetMethod(desc, request, operator)); + } + + @Override + protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { + return filterInvocation(super.findSetMethod(desc, request)); + } + + @Override + protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final jdk.nashorn.internal.runtime.Property property) { + // We override this method just to make it callable by Global + return super.addBoundProperty(propMap, source, property); + } + + private static GuardedInvocation filterInvocation(final GuardedInvocation invocation) { + final MethodType type = invocation.getInvocation().type(); + return invocation.asType(type.changeParameterType(0, Object.class)).filterArguments(0, LEXICAL_SCOPE_FILTER); + } + } + } diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java index 3162e184..ed11a18b 100644 --- a/src/jdk/nashorn/internal/parser/Parser.java +++ b/src/jdk/nashorn/internal/parser/Parser.java @@ -707,20 +707,9 @@ loop: FunctionNode.Kind.SCRIPT, functionLine); - // If ES6 block scope is enabled add a per-script block for top-level LET and CONST declarations. - final int startLine = start; - Block outer = useBlockScope() ? newBlock() : null; functionDeclarations = new ArrayList<>(); - - try { - sourceElements(allowPropertyFunction); - addFunctionDeclarations(script); - } finally { - if (outer != null) { - outer = restoreBlock(outer); - appendStatement(new BlockStatement(startLine, outer)); - } - } + sourceElements(allowPropertyFunction); + addFunctionDeclarations(script); functionDeclarations = null; expect(EOF); diff --git a/src/jdk/nashorn/internal/runtime/Property.java b/src/jdk/nashorn/internal/runtime/Property.java index 41baa642..4225c251 100644 --- a/src/jdk/nashorn/internal/runtime/Property.java +++ b/src/jdk/nashorn/internal/runtime/Property.java @@ -84,14 +84,17 @@ public abstract class Property implements Serializable { public static final int IS_NASGEN_PRIMITIVE = 1 << 6; /** Is this a builtin property, e.g. Function.prototype.apply */ - public static final int IS_BUILTIN = 1 << 7; + public static final int IS_BUILTIN = 1 << 7; /** Is this property bound to a receiver? This means get/set operations will be delegated to * a statically defined object instead of the object passed as callsite parameter. */ - public static final int IS_BOUND = 1 << 7; + public static final int IS_BOUND = 1 << 8; /** Is this a lexically scoped LET or CONST variable that is dead until it is declared. */ - public static final int NEEDS_DECLARATION = 1 << 8; + public static final int NEEDS_DECLARATION = 1 << 9; + + /** Is this property an ES6 lexical binding? */ + public static final int IS_LEXICAL_BINDING = 1 << 10; /** Property key. */ private final String key; @@ -714,4 +717,12 @@ public abstract class Property implements Serializable { public boolean isFunctionDeclaration() { return (flags & IS_FUNCTION_DECLARATION) == IS_FUNCTION_DECLARATION; } + + /** + * Is this a property defined by ES6 let or const? + * @return true if this property represents a lexical binding. + */ + public boolean isLexicalBinding() { + return (flags & IS_LEXICAL_BINDING) == IS_LEXICAL_BINDING; + } } diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index 89246241..f87af8ee 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -304,29 +304,44 @@ public abstract class ScriptObject implements PropertyAccess { PropertyMap newMap = this.getMap(); for (final Property property : properties) { - final String key = property.getKey(); - final Property oldProp = newMap.findProperty(key); - if (oldProp == null) { - if (property instanceof UserAccessorProperty) { - // Note: we copy accessor functions to this object which is semantically different from binding. - final UserAccessorProperty prop = this.newUserAccessors(key, property.getFlags(), property.getGetterFunction(source), property.getSetterFunction(source)); - newMap = newMap.addPropertyNoHistory(prop); - } else { - newMap = newMap.addPropertyBind((AccessorProperty)property, source); - } + newMap = addBoundProperty(newMap, source, property); + } + + this.setMap(newMap); + } + + /** + * Add a bound property from {@code source}, using the interim property map {@code propMap}, and return the + * new interim property map. + * + * @param propMap the property map + * @param source the source object + * @param property the property to be added + * @return the new property map + */ + protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final Property property) { + PropertyMap newMap = propMap; + final String key = property.getKey(); + final Property oldProp = newMap.findProperty(key); + if (oldProp == null) { + if (property instanceof UserAccessorProperty) { + // Note: we copy accessor functions to this object which is semantically different from binding. + final UserAccessorProperty prop = this.newUserAccessors(key, property.getFlags(), property.getGetterFunction(source), property.getSetterFunction(source)); + newMap = newMap.addPropertyNoHistory(prop); } else { - // See ECMA section 10.5 Declaration Binding Instantiation - // step 5 processing each function declaration. - if (property.isFunctionDeclaration() && !oldProp.isConfigurable()) { - if (oldProp instanceof UserAccessorProperty || - !(oldProp.isWritable() && oldProp.isEnumerable())) { - throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this)); - } + newMap = newMap.addPropertyBind((AccessorProperty)property, source); + } + } else { + // See ECMA section 10.5 Declaration Binding Instantiation + // step 5 processing each function declaration. + if (property.isFunctionDeclaration() && !oldProp.isConfigurable()) { + if (oldProp instanceof UserAccessorProperty || + !(oldProp.isWritable() && oldProp.isEnumerable())) { + throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this)); } } } - - this.setMap(newMap); + return newMap; } /** @@ -510,7 +525,11 @@ public abstract class ScriptObject implements PropertyAccess { } } - private void invalidateGlobalConstant(final String key) { + /** + * Invalidate any existing global constant method handles that may exist for {@code key}. + * @param key the property name + */ + protected void invalidateGlobalConstant(final String key) { final GlobalConstants globalConstants = getGlobalConstants(); if (globalConstants != null) { globalConstants.delete(key); diff --git a/test/script/basic/es6/const-redeclare-extra.js.EXPECTED b/test/script/basic/es6/const-redeclare-extra.js.EXPECTED index 754a75c6..06af782e 100644 --- a/test/script/basic/es6/const-redeclare-extra.js.EXPECTED +++ b/test/script/basic/es6/const-redeclare-extra.js.EXPECTED @@ -1,9 +1,9 @@ SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8:3:8 Variable "x" has already been declared var x = {}; ^ -SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8:2:8 Variable "x" has already been declared - var x = 2; - ^ -SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8:2:13 Variable "x" has already been declared - function x () {} - ^ +SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8:3:10 Variable "x" has already been declared + const x = {}; + ^ +SyntaxError: test/script/basic/es6/const-redeclare-extra.js#36:8:3:10 Variable "x" has already been declared + const x = 5; + ^ diff --git a/test/script/basic/es6/let-load.js b/test/script/basic/es6/let-load.js index b4c29465..57667543 100644 --- a/test/script/basic/es6/let-load.js +++ b/test/script/basic/es6/let-load.js @@ -26,7 +26,8 @@ * * @test * @run - * @option --language=es6 */ + * @option --language=es6 + */ "use strict"; diff --git a/test/script/basic/es6/let-load.js.EXPECTED b/test/script/basic/es6/let-load.js.EXPECTED index 510da6e6..f92f84c1 100644 --- a/test/script/basic/es6/let-load.js.EXPECTED +++ b/test/script/basic/es6/let-load.js.EXPECTED @@ -2,7 +2,7 @@ top level function block function print local defs: 20 30 imported var: 1 -ReferenceError: "b" is not defined -ReferenceError: "c" is not defined +imported let: 2 +imported const: 3 top level function ReferenceError: "block" is not defined diff --git a/test/script/basic/es6/let-redeclare-extra.js.EXPECTED b/test/script/basic/es6/let-redeclare-extra.js.EXPECTED index 5e43b694..e0e1afec 100644 --- a/test/script/basic/es6/let-redeclare-extra.js.EXPECTED +++ b/test/script/basic/es6/let-redeclare-extra.js.EXPECTED @@ -4,12 +4,12 @@ SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:2:8 Variabl SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:3:8 Variable "x" has already been declared var x = 2; ^ -SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:2:8 Variable "x" has already been declared - var x = 2; +SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:3:8 Variable "x" has already been declared + let x = undefined; ^ SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:2:10 Variable "x" has already been declared const x = function (){}; ^ -SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:3:13 Variable "a" has already been declared - function a () {}; - ^ +SyntaxError: test/script/basic/es6/let-redeclare-extra.js#35:8:2:8 Variable "a" has already been declared + let a = 2; + ^ diff --git a/test/script/basic/es6/lexical-toplevel-def.js b/test/script/basic/es6/lexical-toplevel-def.js new file mode 100644 index 00000000..c9a44f70 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-def.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. + */ + +/** + * JDK-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +var VAR = "VAR"; +let LET = "LET"; +const CONST = "CONST"; +function FUNC() {} +this.GLOBAL = "GLOBAL"; diff --git a/test/script/basic/es6/lexical-toplevel-print.js b/test/script/basic/es6/lexical-toplevel-print.js new file mode 100644 index 00000000..eef030ac --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-print.js @@ -0,0 +1,51 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +print(VAR); +print(LET); +print(CONST); +print(FUNC); +print(GLOBAL); +print(this.VAR); +print(this.LET); // undefined +print(this.CONST); // undefined +print(this.FUNC); +print(this.GLOBAL); +print("VAR" in this); +print("LET" in this); // false +print("CONST" in this); // false +print("FUNC" in this); +print("GLOBAL" in this); + +try { + LET = LET + "LET"; + CONST = CONST + "CONST"; +} catch (e) { + print(String(e).replace(/\\/g, "/")); +} diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-func-on-let.js b/test/script/basic/es6/lexical-toplevel-redeclare-func-on-let.js new file mode 100644 index 00000000..bfe7af35 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare-func-on-let.js @@ -0,0 +1,31 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +function LET() {} +var SHOULD_NOT_EXIST = 10; diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-let-on-builtin.js b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-builtin.js new file mode 100644 index 00000000..64360142 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-builtin.js @@ -0,0 +1,30 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +let Object = "LEXICAL BUILTIN"; diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-let-on-func.js b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-func.js new file mode 100644 index 00000000..44c83964 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-func.js @@ -0,0 +1,31 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +let FUNC = 10; +var SHOULD_NOT_EXIST = 10; diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-let-on-global.js b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-global.js new file mode 100644 index 00000000..a742fad3 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-global.js @@ -0,0 +1,30 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +let GLOBAL = "LEXICAL GLOBAL"; diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-let-on-var.js b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-var.js new file mode 100644 index 00000000..630741f0 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare-let-on-var.js @@ -0,0 +1,31 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +let VAR = 10; +var SHOULD_NOT_EXIST = 10; diff --git a/test/script/basic/es6/lexical-toplevel-redeclare-var-on-let.js b/test/script/basic/es6/lexical-toplevel-redeclare-var-on-let.js new file mode 100644 index 00000000..cb4b3822 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare-var-on-let.js @@ -0,0 +1,31 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @subtest + */ + +var LET = 10; +var SHOULD_NOT_EXIST = 10; diff --git a/test/script/basic/es6/lexical-toplevel-redeclare.js b/test/script/basic/es6/lexical-toplevel-redeclare.js new file mode 100644 index 00000000..6a76622f --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare.js @@ -0,0 +1,78 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @test + * @run + * @option -scripting + * @option --language=es6 + */ + +load(__DIR__ + "lexical-toplevel-def.js"); + +var global = this; + +function tryIt (code) { + try { + eval(code) + } catch (e) { + print(String(e).replace(/\\/g, "/")) + } +} + +function loadScript(script) { + print(script); + try { + load(__DIR__ + script); + } catch (e) { + print(String(e).replace(/\\/g, "/")); + } + print(VAR); + print(LET); + print(CONST); + print(FUNC); + print(GLOBAL); + print(global.VAR); + print(global.LET); + print(global.CONST); + print(global.FUNC); + print(global.GLOBAL); + try { + print(SHOULD_NOT_EXIST); + } catch (e) { + print(String(e).replace(/\\/g, "/")); + } + print(global.SHOULD_NOT_EXIST); + print(Object); + print(global.Object); + print(); +} + +loadScript("lexical-toplevel-redeclare-var-on-let.js"); +loadScript("lexical-toplevel-redeclare-func-on-let.js"); +loadScript("lexical-toplevel-redeclare-let-on-var.js"); +loadScript("lexical-toplevel-redeclare-let-on-func.js"); +loadScript("lexical-toplevel-redeclare-let-on-builtin.js"); +loadScript("lexical-toplevel-redeclare-let-on-global.js"); diff --git a/test/script/basic/es6/lexical-toplevel-redeclare.js.EXPECTED b/test/script/basic/es6/lexical-toplevel-redeclare.js.EXPECTED new file mode 100644 index 00000000..d1471c80 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel-redeclare.js.EXPECTED @@ -0,0 +1,100 @@ +lexical-toplevel-redeclare-var-on-let.js +SyntaxError: Variable "LET" has already been declared +VAR +LET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +ReferenceError: "SHOULD_NOT_EXIST" is not defined +undefined +function Object() { [native code] } +function Object() { [native code] } + +lexical-toplevel-redeclare-func-on-let.js +SyntaxError: Variable "LET" has already been declared +VAR +LET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +ReferenceError: "SHOULD_NOT_EXIST" is not defined +undefined +function Object() { [native code] } +function Object() { [native code] } + +lexical-toplevel-redeclare-let-on-var.js +SyntaxError: Variable "VAR" has already been declared +VAR +LET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +ReferenceError: "SHOULD_NOT_EXIST" is not defined +undefined +function Object() { [native code] } +function Object() { [native code] } + +lexical-toplevel-redeclare-let-on-func.js +SyntaxError: Variable "FUNC" has already been declared +VAR +LET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +ReferenceError: "SHOULD_NOT_EXIST" is not defined +undefined +function Object() { [native code] } +function Object() { [native code] } + +lexical-toplevel-redeclare-let-on-builtin.js +VAR +LET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +ReferenceError: "SHOULD_NOT_EXIST" is not defined +undefined +LEXICAL BUILTIN +function Object() { [native code] } + +lexical-toplevel-redeclare-let-on-global.js +VAR +LET +CONST +function FUNC() {} +LEXICAL GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +ReferenceError: "SHOULD_NOT_EXIST" is not defined +undefined +LEXICAL BUILTIN +function Object() { [native code] } + diff --git a/test/script/basic/es6/lexical-toplevel.js b/test/script/basic/es6/lexical-toplevel.js new file mode 100644 index 00000000..fc272a8a --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel.js @@ -0,0 +1,35 @@ +/* + * 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-8057691: Nashorn: let & const declarations are not shared between scripts + * + * @test + * @run + * @option --language=es6 + */ + +load(__DIR__ + "lexical-toplevel-def.js"); + +load(__DIR__ + "lexical-toplevel-print.js"); +load(__DIR__ + "lexical-toplevel-print.js"); diff --git a/test/script/basic/es6/lexical-toplevel.js.EXPECTED b/test/script/basic/es6/lexical-toplevel.js.EXPECTED new file mode 100644 index 00000000..804e7506 --- /dev/null +++ b/test/script/basic/es6/lexical-toplevel.js.EXPECTED @@ -0,0 +1,30 @@ +VAR +LET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +true +false +false +true +true +VAR +LETLET +CONST +function FUNC() {} +GLOBAL +VAR +undefined +undefined +function FUNC() {} +GLOBAL +true +false +false +true +true diff --git a/test/src/jdk/nashorn/internal/runtime/LexicalBindingTest.java b/test/src/jdk/nashorn/internal/runtime/LexicalBindingTest.java new file mode 100644 index 00000000..2cd0bf01 --- /dev/null +++ b/test/src/jdk/nashorn/internal/runtime/LexicalBindingTest.java @@ -0,0 +1,212 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.internal.runtime; + +import jdk.nashorn.api.scripting.NashornScriptEngineFactory; +import org.testng.annotations.Test; + +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptException; +import javax.script.SimpleScriptContext; + +import static org.testng.Assert.assertEquals; + +/** + * Top-level lexical binding tests. + * + * @test + * @run testng jdk.nashorn.internal.runtime.LexicalBindingTest + */ +@SuppressWarnings("javadoc") +public class LexicalBindingTest { + + final static String LANGUAGE_ES6 = "--language=es6"; + final static int NUMBER_OF_CONTEXTS = 20; + final static int MEGAMORPHIC_LOOP_COUNT = 20; + + /** + * Test access to global var-declared variables for shared script classes with multiple globals. + */ + @Test + public static void megamorphicVarTest() throws ScriptException, InterruptedException { + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + final ScriptEngine e = factory.getScriptEngine(); + final ScriptContext[] contexts = new ScriptContext[NUMBER_OF_CONTEXTS]; + final String sharedScript = "foo"; + + + for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) { + final ScriptContext context = contexts[i] = new SimpleScriptContext(); + final Bindings b = e.createBindings(); + context.setBindings(b, ScriptContext.ENGINE_SCOPE); + assertEquals(e.eval("var foo = '" + i + "';", context), null); + } + + for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) { + final ScriptContext context = contexts[i]; + assertEquals(e.eval(sharedScript, context), String.valueOf(i)); + } + } + + /** + * Test access to global lexically declared variables for shared script classes with multiple globals. + */ + @Test + public static void megamorphicMultiGlobalLetTest() throws ScriptException, InterruptedException { + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6); + final ScriptContext[] contexts = new ScriptContext[NUMBER_OF_CONTEXTS]; + final String sharedScript = "foo"; + + + for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) { + final ScriptContext context = contexts[i] = new SimpleScriptContext(); + final Bindings b = e.createBindings(); + context.setBindings(b, ScriptContext.ENGINE_SCOPE); + assertEquals(e.eval("let foo = '" + i + "';", context), null); + } + + for (int i = 0; i < NUMBER_OF_CONTEXTS; i++) { + final ScriptContext context = contexts[i]; + assertEquals(e.eval(sharedScript, context), String.valueOf(i)); + } + } + + + /** + * Test access to global lexically declared variables for shared script classes with single global. + */ + @Test + public static void megamorphicSingleGlobalLetTest() throws ScriptException, InterruptedException { + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6); + final String sharedGetterScript = "foo"; + final String sharedSetterScript = "foo = 1"; + + for (int i = 0; i < MEGAMORPHIC_LOOP_COUNT; i++) { + assertEquals(e.eval(sharedSetterScript), 1); + assertEquals(e.eval(sharedGetterScript), 1); + assertEquals(e.eval("delete foo; a" + i + " = 1; foo = " + i + ";"), i); + assertEquals(e.eval(sharedGetterScript), i); + } + + assertEquals(e.eval("let foo = 'foo';"), null); + assertEquals(e.eval(sharedGetterScript), "foo"); + assertEquals(e.eval(sharedSetterScript), 1); + assertEquals(e.eval(sharedGetterScript), 1); + assertEquals(e.eval("this.foo"), MEGAMORPHIC_LOOP_COUNT - 1); + } + + /** + * Test access to global lexically declared variables for shared script classes with single global. + */ + @Test + public static void megamorphicInheritedGlobalLetTest() throws ScriptException, InterruptedException { + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6); + final String sharedGetterScript = "foo"; + final String sharedSetterScript = "foo = 1"; + + for (int i = 0; i < MEGAMORPHIC_LOOP_COUNT; i++) { + assertEquals(e.eval(sharedSetterScript), 1); + assertEquals(e.eval(sharedGetterScript), 1); + assertEquals(e.eval("delete foo; a" + i + " = 1; Object.prototype.foo = " + i + ";"), i); + assertEquals(e.eval(sharedGetterScript), i); + } + + assertEquals(e.eval("let foo = 'foo';"), null); + assertEquals(e.eval(sharedGetterScript), "foo"); + assertEquals(e.eval(sharedSetterScript), 1); + assertEquals(e.eval(sharedGetterScript), 1); + assertEquals(e.eval("this.foo"), MEGAMORPHIC_LOOP_COUNT - 1); + } + + /** + * Test multi-threaded access to global lexically declared variables for shared script classes with multiple globals. + */ + @Test + public static void multiThreadedLetTest() throws ScriptException, InterruptedException { + final NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + final ScriptEngine e = factory.getScriptEngine(LANGUAGE_ES6); + final Bindings b = e.createBindings(); + final ScriptContext origContext = e.getContext(); + final ScriptContext newCtxt = new SimpleScriptContext(); + newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE); + final String sharedScript = "foo"; + + assertEquals(e.eval("let foo = 'original context';", origContext), null); + assertEquals(e.eval("let foo = 'new context';", newCtxt), null); + + final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); + final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000)); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + + assertEquals(e.eval("foo = 'newer context';", newCtxt), "newer context"); + final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000)); + final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000)); + + t3.start(); + t4.start(); + t3.join(); + t4.join(); + + assertEquals(e.eval(sharedScript), "original context"); + assertEquals(e.eval(sharedScript, newCtxt), "newer context"); + } + + private static class ScriptRunner implements Runnable { + + final ScriptEngine engine; + final ScriptContext context; + final String source; + final Object expected; + final int iterations; + + ScriptRunner(final ScriptEngine engine, final ScriptContext context, final String source, final Object expected, final int iterations) { + this.engine = engine; + this.context = context; + this.source = source; + this.expected = expected; + this.iterations = iterations; + } + + @Override + public void run() { + try { + for (int i = 0; i < iterations; i++) { + assertEquals(engine.eval(source, context), expected); + } + } catch (final ScriptException se) { + throw new RuntimeException(se); + } + } + } +} -- cgit v1.2.3 From 32204ed3e66f63ae6b696b5dea90d1db780abbc5 Mon Sep 17 00:00:00 2001 From: slugovoy Date: Tue, 25 Nov 2014 14:57:01 +0300 Subject: 8062638: RuntimeException when run command from js with -scripting on Cygwin 8054343: Nashorn: Some tests fails on windows with AccessControlException Reviewed-by: coffeys --- test/script/basic/compile-octane-normal.js | 4 ++-- test/script/basic/compile-octane-splitter.js | 4 ++-- test/script/basic/compile-octane.js | 2 +- test/script/nosecurity/JDK-8050964.js | 1 + test/script/nosecurity/JDK-8055034.js | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/test/script/basic/compile-octane-normal.js b/test/script/basic/compile-octane-normal.js index 769f00b5..c671d572 100644 --- a/test/script/basic/compile-octane-normal.js +++ b/test/script/basic/compile-octane-normal.js @@ -38,5 +38,5 @@ */ var fn = __DIR__ + 'compile-octane.js'; -var url = "file://" + fn; -loadWithNewGlobal(new java.net.URL(url)); +var url = new java.io.File(fn).toURL(); +loadWithNewGlobal(url); diff --git a/test/script/basic/compile-octane-splitter.js b/test/script/basic/compile-octane-splitter.js index 5b4f0e15..58c5966a 100644 --- a/test/script/basic/compile-octane-splitter.js +++ b/test/script/basic/compile-octane-splitter.js @@ -40,5 +40,5 @@ */ var fn = __DIR__ + 'compile-octane.js'; -var url = "file://" + fn; -loadWithNewGlobal(new java.net.URL(url)); +var url = new java.io.File(fn).toURL(); +loadWithNewGlobal(url); diff --git a/test/script/basic/compile-octane.js b/test/script/basic/compile-octane.js index aee105a0..b37038f9 100644 --- a/test/script/basic/compile-octane.js +++ b/test/script/basic/compile-octane.js @@ -132,7 +132,7 @@ for (var j in tests) { str2 += " processing file: " + file + "..."; print_if_verbose(str2); } - newGlobal.load("file://" + path + file); + newGlobal.load(new java.io.File(path + file).toURL()); } } print("Done."); diff --git a/test/script/nosecurity/JDK-8050964.js b/test/script/nosecurity/JDK-8050964.js index 486948aa..eda3d1b6 100644 --- a/test/script/nosecurity/JDK-8050964.js +++ b/test/script/nosecurity/JDK-8050964.js @@ -50,6 +50,7 @@ var javahome = System.getProperty("java.home"); var jdepsPath = javahome + "/../bin/jdeps".replaceAll(/\//g, File.separater); // run jdep on nashorn.jar - only summary but print profile info +$ENV.PWD=System.getProperty("user.dir") // to avoid RE on Cygwin `${jdepsPath} -s -P ${nashornJar.absolutePath}` // check for "(compact1)" in output from jdep tool diff --git a/test/script/nosecurity/JDK-8055034.js b/test/script/nosecurity/JDK-8055034.js index 76f24be7..a0e5057e 100644 --- a/test/script/nosecurity/JDK-8055034.js +++ b/test/script/nosecurity/JDK-8055034.js @@ -49,7 +49,7 @@ var nashornJarDir = nashornJar.parentFile.absolutePath; var jjsCmd = javahome + "/../bin/jjs"; jjsCmd += " -J-Djava.ext.dirs=" + nashornJarDir; jjsCmd = jjsCmd.toString().replaceAll(/\//g, File.separater); - +$ENV.PWD=System.getProperty("user.dir") // to avoid RE on Cygwin $EXEC(jjsCmd, "var x = Object.create(null);\nx;\nprint('PASSED');\nexit(0)"); // $ERR has all interactions including prompts! Just check for error substring. -- cgit v1.2.3 From f3e4fff787c43bba0e454663a770e028df9e3fae Mon Sep 17 00:00:00 2001 From: vlivanov Date: Thu, 27 Nov 2014 17:14:01 +0400 Subject: 8065985: Inlining failure of Number.doubleValue() in JSType.toNumeric() causes 15% peak perf regresion on Box2D Reviewed-by: lagergren, hannesw --- src/jdk/nashorn/internal/runtime/JSType.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jdk/nashorn/internal/runtime/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java index 75395ea4..7e54b1e2 100644 --- a/src/jdk/nashorn/internal/runtime/JSType.java +++ b/src/jdk/nashorn/internal/runtime/JSType.java @@ -714,6 +714,9 @@ public enum JSType { * @return a number */ public static double toNumber(final Object obj) { + if (obj instanceof Double) { + return (Double)obj; + } if (obj instanceof Number) { return ((Number)obj).doubleValue(); } -- cgit v1.2.3 From df1ab7ee4dd024358de71e9877155c7d8f542c32 Mon Sep 17 00:00:00 2001 From: hannesw Date: Thu, 27 Nov 2014 18:02:28 +0100 Subject: 8057980: let & const: remaining issues with lexical scoping Reviewed-by: lagergren, attila --- .../nashorn/internal/codegen/AssignSymbols.java | 30 +++++--- .../nashorn/internal/codegen/CodeGenerator.java | 7 ++ src/jdk/nashorn/internal/codegen/Lower.java | 2 +- src/jdk/nashorn/internal/ir/ForNode.java | 24 +++++-- src/jdk/nashorn/internal/ir/LexicalContext.java | 14 ++++ src/jdk/nashorn/internal/ir/LoopNode.java | 6 ++ src/jdk/nashorn/internal/ir/VarNode.java | 19 ++--- src/jdk/nashorn/internal/ir/WhileNode.java | 5 ++ src/jdk/nashorn/internal/parser/Parser.java | 43 ++++++----- src/jdk/nashorn/internal/runtime/ScriptObject.java | 83 +++++++++++++++------- .../nashorn/internal/runtime/arrays/ArrayData.java | 15 ++-- .../internal/runtime/resources/Messages.properties | 2 + test/script/basic/es6/for-let.js | 37 ++++++++++ test/script/basic/es6/for-let.js.EXPECTED | 22 ++++++ .../basic/es6/let-const-statement-context.js | 49 +++++++++++++ .../es6/let-const-statement-context.js.EXPECTED | 30 ++++++++ test/script/basic/es6/let-const-switch.js | 45 ++++++++++++ test/script/basic/es6/let-const-switch.js.EXPECTED | 12 ++++ test/script/basic/es6/let-load.js | 15 ++-- test/script/basic/es6/let-load.js.EXPECTED | 1 + .../script/basic/es6/let_const_closure.js.EXPECTED | 6 +- test/script/basic/es6/lexical-toplevel.js.EXPECTED | 2 + 22 files changed, 372 insertions(+), 97 deletions(-) create mode 100644 test/script/basic/es6/let-const-statement-context.js create mode 100644 test/script/basic/es6/let-const-statement-context.js.EXPECTED create mode 100644 test/script/basic/es6/let-const-switch.js create mode 100644 test/script/basic/es6/let-const-switch.js.EXPECTED diff --git a/src/jdk/nashorn/internal/codegen/AssignSymbols.java b/src/jdk/nashorn/internal/codegen/AssignSymbols.java index ad0f13c7..6eb89a16 100644 --- a/src/jdk/nashorn/internal/codegen/AssignSymbols.java +++ b/src/jdk/nashorn/internal/codegen/AssignSymbols.java @@ -189,7 +189,7 @@ final class AssignSymbols extends NodeVisitor implements Loggabl * @param body the body of the FunctionNode we are entering */ private void acceptDeclarations(final FunctionNode functionNode, final Block body) { - // This visitor will assign symbol to all declared variables, except "var" declarations in for loop initializers. + // This visitor will assign symbol to all declared variables. body.accept(new NodeVisitor(new LexicalContext()) { @Override protected boolean enterDefault(final Node node) { @@ -200,16 +200,17 @@ final class AssignSymbols extends NodeVisitor implements Loggabl @Override public Node leaveVarNode(final VarNode varNode) { - if (varNode.isStatement()) { - final IdentNode ident = varNode.getName(); - final Block block = varNode.isBlockScoped() ? getLexicalContext().getCurrentBlock() : body; - final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags()); - if (varNode.isFunctionDeclaration()) { - symbol.setIsFunctionDeclaration(); - } - return varNode.setName(ident.setSymbol(symbol)); + final IdentNode ident = varNode.getName(); + final boolean blockScoped = varNode.isBlockScoped(); + if (blockScoped && lc.inUnprotectedSwitchContext()) { + throwUnprotectedSwitchError(varNode); + } + final Block block = blockScoped ? lc.getCurrentBlock() : body; + final Symbol symbol = defineSymbol(block, ident.getName(), ident, varNode.getSymbolFlags()); + if (varNode.isFunctionDeclaration()) { + symbol.setIsFunctionDeclaration(); } - return varNode; + return varNode.setName(ident.setSymbol(symbol)); } }); } @@ -1048,6 +1049,15 @@ final class AssignSymbols extends NodeVisitor implements Loggabl return !(units == null || units.isEmpty()); } + private void throwUnprotectedSwitchError(final VarNode varNode) { + // Block scoped declarations in switch statements without explicit blocks should be declared + // in a common block that contains all the case clauses. We cannot support this without a + // fundamental rewrite of how switch statements are handled (case nodes contain blocks and are + // directly contained by switch node). As a temporary solution we throw a reference error here. + final String msg = ECMAErrors.getMessage("syntax.error.unprotected.switch.declaration", varNode.isLet() ? "let" : "const"); + throwParserException(msg, varNode); + } + private void throwParserException(final String message, final Node origin) { if (origin == null) { throw new ParserException(message); diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java index 6e84dd89..1bf3b382 100644 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java @@ -3264,6 +3264,13 @@ final class CodeGenerator extends NodeOperatorVisitor implements Lo if (isAlwaysTrue(test)) { //turn it into a for node without a test. - final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), body, ForNode.IS_FOR).accept(this); + final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), body, 0).accept(this); lc.replace(whileNode, forNode); return forNode; } diff --git a/src/jdk/nashorn/internal/ir/ForNode.java b/src/jdk/nashorn/internal/ir/ForNode.java index 2847947c..ef6f11db 100644 --- a/src/jdk/nashorn/internal/ir/ForNode.java +++ b/src/jdk/nashorn/internal/ir/ForNode.java @@ -45,14 +45,14 @@ public final class ForNode extends LoopNode { /** Iterator symbol. */ private Symbol iterator; - /** Is this a normal for loop? */ - public static final int IS_FOR = 1 << 0; - /** Is this a normal for in loop? */ - public static final int IS_FOR_IN = 1 << 1; + public static final int IS_FOR_IN = 1 << 0; /** Is this a normal for each in loop? */ - public static final int IS_FOR_EACH = 1 << 2; + public static final int IS_FOR_EACH = 1 << 1; + + /** Does this loop need a per-iteration scope because its init contain a LET declaration? */ + public static final int PER_ITERATION_SCOPE = 1 << 2; private final int flags; @@ -273,4 +273,18 @@ public final class ForNode extends LoopNode { JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) { return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion)); } + + @Override + public boolean hasPerIterationScope() { + return (flags & PER_ITERATION_SCOPE) != 0; + } + + /** + * Set the per-iteration-scope flag on this node. + * @param lc lexical context + * @return the node with flag set + */ + public ForNode setPerIterationScope(final LexicalContext lc) { + return setFlags(lc, flags | PER_ITERATION_SCOPE); + } } diff --git a/src/jdk/nashorn/internal/ir/LexicalContext.java b/src/jdk/nashorn/internal/ir/LexicalContext.java index 2b59a07c..487d6aeb 100644 --- a/src/jdk/nashorn/internal/ir/LexicalContext.java +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java @@ -597,6 +597,20 @@ public class LexicalContext { throw new AssertionError(target + " was expected in lexical context " + LexicalContext.this + " but wasn't"); } + /** + * Checks whether the current context is inside a switch statement without explicit blocks (curly braces). + * @return true if in unprotected switch statement + */ + public boolean inUnprotectedSwitchContext() { + for (int i = sp; i > 0; i--) { + final LexicalContextNode next = stack[i]; + if (next instanceof Block) { + return stack[i - 1] instanceof SwitchNode; + } + } + return false; + } + @Override public String toString() { final StringBuffer sb = new StringBuffer(); diff --git a/src/jdk/nashorn/internal/ir/LoopNode.java b/src/jdk/nashorn/internal/ir/LoopNode.java index e6436ad9..5991a32a 100644 --- a/src/jdk/nashorn/internal/ir/LoopNode.java +++ b/src/jdk/nashorn/internal/ir/LoopNode.java @@ -176,4 +176,10 @@ public abstract class LoopNode extends BreakableStatement { * @return new loop node if changed otherwise the same */ public abstract LoopNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes); + + /** + * Does this loop have a LET declaration and hence require a per-iteration scope? + * @return true if a per-iteration scope is required. + */ + public abstract boolean hasPerIterationScope(); } diff --git a/src/jdk/nashorn/internal/ir/VarNode.java b/src/jdk/nashorn/internal/ir/VarNode.java index 44d7d4c7..1cee8cb5 100644 --- a/src/jdk/nashorn/internal/ir/VarNode.java +++ b/src/jdk/nashorn/internal/ir/VarNode.java @@ -45,19 +45,16 @@ public final class VarNode extends Statement implements Assignment { /** Is this a var statement (as opposed to a "var" in a for loop statement) */ private final int flags; - /** Flag that determines if this function node is a statement */ - public static final int IS_STATEMENT = 1 << 0; - /** Flag for ES6 LET declaration */ - public static final int IS_LET = 1 << 1; + public static final int IS_LET = 1 << 0; /** Flag for ES6 CONST declaration */ - public static final int IS_CONST = 1 << 2; + public static final int IS_CONST = 1 << 1; /** Flag that determines if this is the last function declaration in a function * This is used to micro optimize the placement of return value assignments for * a program node */ - public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 3; + public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 2; /** * Constructor @@ -69,7 +66,7 @@ public final class VarNode extends Statement implements Assignment { * @param init init node or null if just a declaration */ public VarNode(final int lineNumber, final long token, final int finish, final IdentNode name, final Expression init) { - this(lineNumber, token, finish, name, init, IS_STATEMENT); + this(lineNumber, token, finish, name, init, 0); } private VarNode(final VarNode varNode, final IdentNode name, final Expression init, final int flags) { @@ -259,14 +256,6 @@ public final class VarNode extends Statement implements Assignment { return setFlags(flags | flag); } - /** - * Returns true if this is a var statement (as opposed to a var initializer in a for loop). - * @return true if this is a var statement (as opposed to a var initializer in a for loop). - */ - public boolean isStatement() { - return (flags & IS_STATEMENT) != 0; - } - /** * Returns true if this is a function declaration. * @return true if this is a function declaration. diff --git a/src/jdk/nashorn/internal/ir/WhileNode.java b/src/jdk/nashorn/internal/ir/WhileNode.java index 9a0981fb..7e60fee0 100644 --- a/src/jdk/nashorn/internal/ir/WhileNode.java +++ b/src/jdk/nashorn/internal/ir/WhileNode.java @@ -148,4 +148,9 @@ public final class WhileNode extends LoopNode { } return test == null; } + + @Override + public boolean hasPerIterationScope() { + return false; + } } diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java index ed11a18b..9c6f974d 100644 --- a/src/jdk/nashorn/internal/parser/Parser.java +++ b/src/jdk/nashorn/internal/parser/Parser.java @@ -559,7 +559,7 @@ loop: // Set up new block. Captures first token. Block newBlock = newBlock(); try { - statement(); + statement(false, false, true); } finally { newBlock = restoreBlock(newBlock); } @@ -772,7 +772,7 @@ loop: try { // Get the next element. - statement(true, allowPropertyFunction); + statement(true, allowPropertyFunction, false); allowPropertyFunction = false; // check for directive prologues @@ -862,13 +862,15 @@ loop: * Parse any of the basic statement types. */ private void statement() { - statement(false, false); + statement(false, false, false); } /** * @param topLevel does this statement occur at the "top level" of a script or a function? + * @param allowPropertyFunction allow property "get" and "set" functions? + * @param singleStatement are we in a single statement context? */ - private void statement(final boolean topLevel, final boolean allowPropertyFunction) { + private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement) { if (type == FUNCTION) { // As per spec (ECMA section 12), function declarations as arbitrary statement // is not "portable". Implementation can issue a warning or disallow the same. @@ -932,6 +934,9 @@ loop: break; default: if (useBlockScope() && (type == LET || type == CONST)) { + if (singleStatement) { + throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token); + } variableStatement(type, true); break; } @@ -1057,7 +1062,7 @@ loop: next(); final List vars = new ArrayList<>(); - int varFlags = VarNode.IS_STATEMENT; + int varFlags = 0; if (varType == LET) { varFlags |= VarNode.IS_LET; } else if (varType == CONST) { @@ -1210,7 +1215,7 @@ loop: Block outer = useBlockScope() ? newBlock() : null; // Create FOR node, capturing FOR token. - ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, ForNode.IS_FOR); + ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, 0); lc.push(forNode); try { @@ -1230,19 +1235,22 @@ loop: switch (type) { case VAR: - // Var statements captured in for outer block. + // Var declaration captured in for outer block. vars = variableStatement(type, false); break; case SEMICOLON: break; default: if (useBlockScope() && (type == LET || type == CONST)) { - // LET/CONST captured in container block created above. + if (type == LET) { + forNode = forNode.setPerIterationScope(lc); + } + // LET/CONST declaration captured in container block created above. vars = variableStatement(type, false); break; } if (env._const_as_var && type == CONST) { - // Var statements captured in for outer block. + // Var declaration captured in for outer block. vars = variableStatement(TokenType.VAR, false); break; } @@ -1323,11 +1331,12 @@ loop: appendStatement(forNode); } finally { lc.pop(forNode); - if (outer != null) { - outer.setFinish(forNode.getFinish()); - outer = restoreBlock(outer); - appendStatement(new BlockStatement(startLine, outer)); - } + } + + if (outer != null) { + outer.setFinish(forNode.getFinish()); + outer = restoreBlock(outer); + appendStatement(new BlockStatement(startLine, outer)); } } @@ -2699,11 +2708,7 @@ loop: } if (isStatement) { - int varFlags = VarNode.IS_STATEMENT; - if (!topLevel && useBlockScope()) { - // mark ES6 block functions as lexically scoped - varFlags |= VarNode.IS_LET; - } + final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET; final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, varFlags); if (topLevel) { functionDeclarations.add(varNode); diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java index f87af8ee..3f605910 100644 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -46,6 +46,8 @@ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid; import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex; import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isScopeFlag; +import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.isStrictFlag; import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck; import java.lang.invoke.MethodHandle; @@ -98,7 +100,7 @@ import jdk.nashorn.internal.runtime.linker.NashornGuards; * */ -public abstract class ScriptObject implements PropertyAccess { +public abstract class ScriptObject implements PropertyAccess, Cloneable { /** __proto__ special property name inside object literals. ES6 draft. */ public static final String PROTO_PROPERTY_NAME = "__proto__"; @@ -2202,6 +2204,9 @@ public abstract class ScriptObject implements PropertyAccess { if (find != null) { if (!find.getProperty().isWritable() && !NashornCallSiteDescriptor.isDeclaration(desc)) { + if (NashornCallSiteDescriptor.isScope(desc) && find.getProperty().isLexicalBinding()) { + throw typeError("assign.constant", name); // Overwriting ES6 const should throw also in non-strict mode. + } // Existing, non-writable property return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true); } @@ -3103,7 +3108,7 @@ public abstract class ScriptObject implements PropertyAccess { private boolean doesNotHaveEnsureLength(final long longIndex, final long oldLength, final int callSiteFlags) { if (longIndex >= oldLength) { if (!isExtensible()) { - if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) { + if (isStrictFlag(callSiteFlags)) { throw typeError("object.non.extensible", JSType.toString(longIndex), ScriptRuntime.safeToString(this)); } return true; @@ -3127,7 +3132,7 @@ public abstract class ScriptObject implements PropertyAccess { final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { - final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags); + final boolean strict = isStrictFlag(callSiteFlags); setArray(getArray().set(index, value, strict)); doesNotHaveEnsureDelete(longIndex, oldLength, strict); } @@ -3137,7 +3142,7 @@ public abstract class ScriptObject implements PropertyAccess { final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { - final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags); + final boolean strict = isStrictFlag(callSiteFlags); setArray(getArray().set(index, value, strict)); doesNotHaveEnsureDelete(longIndex, oldLength, strict); } @@ -3147,7 +3152,7 @@ public abstract class ScriptObject implements PropertyAccess { final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { - final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags); + final boolean strict = isStrictFlag(callSiteFlags); setArray(getArray().set(index, value, strict)); doesNotHaveEnsureDelete(longIndex, oldLength, strict); } @@ -3157,7 +3162,7 @@ public abstract class ScriptObject implements PropertyAccess { final long oldLength = getArray().length(); final long longIndex = ArrayIndex.toLongIndex(index); if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { - final boolean strict = NashornCallSiteDescriptor.isStrictFlag(callSiteFlags); + final boolean strict = isStrictFlag(callSiteFlags); setArray(getArray().set(index, value, strict)); doesNotHaveEnsureDelete(longIndex, oldLength, strict); } @@ -3178,7 +3183,7 @@ public abstract class ScriptObject implements PropertyAccess { invalidateGlobalConstant(key); if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) { - final boolean isScope = NashornCallSiteDescriptor.isScopeFlag(callSiteFlags); + final boolean isScope = isScopeFlag(callSiteFlags); // If the start object of the find is not this object it means the property was found inside a // 'with' statement expression (see WithObject.findProperty()). In this case we forward the 'set' // to the 'with' object. @@ -3199,16 +3204,19 @@ public abstract class ScriptObject implements PropertyAccess { if (f != null) { if (!f.getProperty().isWritable()) { - if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) { + if (isScopeFlag(callSiteFlags) && f.getProperty().isLexicalBinding()) { + throw typeError("assign.constant", key); // Overwriting ES6 const should throw also in non-strict mode. + } + if (isStrictFlag(callSiteFlags)) { throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this)); } return; } - f.setValue(value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)); + f.setValue(value, isStrictFlag(callSiteFlags)); } else if (!isExtensible()) { - if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) { + if (isStrictFlag(callSiteFlags)) { throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this)); } } else { @@ -3235,7 +3243,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3255,7 +3263,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3275,7 +3283,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3295,7 +3303,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3314,7 +3322,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3333,7 +3341,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3352,7 +3360,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3371,7 +3379,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3390,7 +3398,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3409,7 +3417,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3428,7 +3436,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3447,7 +3455,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3465,7 +3473,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { if (getArray().has(index)) { final ArrayData data = getArray(); - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3483,7 +3491,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3502,7 +3510,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3521,7 +3529,7 @@ public abstract class ScriptObject implements PropertyAccess { if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { - setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags))); + setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } @@ -3685,6 +3693,29 @@ public abstract class ScriptObject implements PropertyAccess { return true; } + /** + * Return a shallow copy of this ScriptObject. + * @return a shallow copy. + */ + public final ScriptObject copy() { + try { + return clone(); + } catch (final CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + @Override + protected ScriptObject clone() throws CloneNotSupportedException { + final ScriptObject clone = (ScriptObject) super.clone(); + if (objectSpill != null) { + clone.objectSpill = objectSpill.clone(); + clone.primitiveSpill = primitiveSpill.clone(); + } + clone.arrayData = arrayData.copy(); + return clone; + } + /** * Make a new UserAccessorProperty property. getter and setter functions are stored in * this ScriptObject and slot values are used in property object. diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java index b018596f..f0a8c7a2 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java @@ -61,9 +61,9 @@ public abstract class ArrayData { /** * Length of the array data. Not necessarily length of the wrapped array. * This is private to ensure that no one in a subclass is able to touch the length - * without going through {@link setLength}. This is used to implement + * without going through {@link #setLength}. This is used to implement * {@link LengthNotWritableFilter}s, ensuring that there are no ways past - * a {@link setLength} function replaced by a nop + * a {@link #setLength} function replaced by a nop */ private long length; @@ -79,11 +79,7 @@ public abstract class ArrayData { */ private static class UntouchedArrayData extends ContinuousArrayData { private UntouchedArrayData() { - this(0); - } - - private UntouchedArrayData(final int length) { - super(length); + super(0); } private ArrayData toRealArrayData() { @@ -100,7 +96,8 @@ public abstract class ArrayData { @Override public ContinuousArrayData copy() { - return new UntouchedArrayData((int)length()); + assert length() == 0; + return this; } @Override @@ -246,7 +243,7 @@ public abstract class ArrayData { public Class getBoxedElementType() { return Integer.class; } - }; + } /** * Constructor diff --git a/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/src/jdk/nashorn/internal/runtime/resources/Messages.properties index 3a161c8d..71c11743 100644 --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -116,6 +116,7 @@ type.error.instanceof.on.non.object=instanceof must be called with a javascript type.error.cannot.convert.to.interface=object {0} cannot be converted to {1} due to "{2}" type.error.array.reduce.invalid.init=invalid initialValue for Array.prototype.reduce type.error.array.reduceright.invalid.init=invalid initialValue for Array.prototype.reduceRight +type.error.assign.constant=Assignment to constant "{0}" type.error.cannot.get.default.string=Cannot get default string value type.error.cannot.get.default.number=Cannot get default number value type.error.cant.apply.with.to.null=Cannot apply "with" to null @@ -166,6 +167,7 @@ syntax.error.invalid.json=Invalid JSON: {0} syntax.error.strict.cant.delete=cannot delete "{0}" in strict mode syntax.error.redeclare.variable=Variable "{0}" has already been declared syntax.error.assign.constant=Assignment to constant "{0}" +syntax.error.unprotected.switch.declaration=Unsupported {0} declaration in unprotected switch statement io.error.cant.write=cannot write "{0}" config.error.no.dest=no destination directory supplied diff --git a/test/script/basic/es6/for-let.js b/test/script/basic/es6/for-let.js index 949b348c..848dc3ce 100644 --- a/test/script/basic/es6/for-let.js +++ b/test/script/basic/es6/for-let.js @@ -39,3 +39,40 @@ try { } catch (e) { print(e); } + +let a = []; + +for (let i = 0; i < 10; i++) { + a.push(function() { print(i); }); +} + +a.forEach(function(f) { f(); }); + +a = []; + +for (let i = 0; i < 10; i++) { + if (i == 5) { + i = "foo"; + } + a.push(function() { print(i); }); +} + +a.forEach(function(f) { f(); }); + +try { + print(i); +} catch (e) { + print(e); +} + +a = []; + +for (let i = 0; i < 20; i++) { + if (i % 2 == 1) { + i += 2; + continue; + } + a.push(function() { print(i); }); +} + +a.forEach(function(f) { f(); }); diff --git a/test/script/basic/es6/for-let.js.EXPECTED b/test/script/basic/es6/for-let.js.EXPECTED index 4c1ebad8..21787adb 100644 --- a/test/script/basic/es6/for-let.js.EXPECTED +++ b/test/script/basic/es6/for-let.js.EXPECTED @@ -9,3 +9,25 @@ 8 9 ReferenceError: "i" is not defined +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +0 +1 +2 +3 +4 +foo +ReferenceError: "i" is not defined +0 +4 +8 +12 +16 diff --git a/test/script/basic/es6/let-const-statement-context.js b/test/script/basic/es6/let-const-statement-context.js new file mode 100644 index 00000000..3e662378 --- /dev/null +++ b/test/script/basic/es6/let-const-statement-context.js @@ -0,0 +1,49 @@ +/* + * 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-8057980: let & const: remaining issues with lexical scoping + * + * @test + * @run + * @option --language=es6 + */ + +function tryEval(s) { + try { + eval(s); + } catch (e) { + print(String(e).replace(/\\/g, "/")); + } +} + +tryEval('if (true) let x = 1;'); +tryEval('if (true) const x = 1;'); +tryEval('while (true) let x = 1;'); +tryEval('while (true) const x = 1;'); +tryEval('for (;;) let x = 1;'); +tryEval('for (;;) const x = 1;'); +tryEval('do let x = 1; while (true);'); +tryEval('do const x = 1; while (true);'); +tryEval('with (y) const x = 1;'); +tryEval('with (y) let x = 1;'); diff --git a/test/script/basic/es6/let-const-statement-context.js.EXPECTED b/test/script/basic/es6/let-const-statement-context.js.EXPECTED new file mode 100644 index 00000000..1b73e4c7 --- /dev/null +++ b/test/script/basic/es6/let-const-statement-context.js.EXPECTED @@ -0,0 +1,30 @@ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:10 Expected statement but found let declaration +if (true) let x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:10 Expected statement but found const declaration +if (true) const x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:13 Expected statement but found let declaration +while (true) let x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:13 Expected statement but found const declaration +while (true) const x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:9 Expected statement but found let declaration +for (;;) let x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:9 Expected statement but found const declaration +for (;;) const x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:3 Expected statement but found let declaration +do let x = 1; while (true); + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:3 Expected statement but found const declaration +do const x = 1; while (true); + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:9 Expected statement but found const declaration +with (y) const x = 1; + ^ +SyntaxError: test/script/basic/es6/let-const-statement-context.js#34:8:1:9 Expected statement but found let declaration +with (y) let x = 1; + ^ diff --git a/test/script/basic/es6/let-const-switch.js b/test/script/basic/es6/let-const-switch.js new file mode 100644 index 00000000..8a538b80 --- /dev/null +++ b/test/script/basic/es6/let-const-switch.js @@ -0,0 +1,45 @@ +/* + * 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-8057980: let & const: remaining issues with lexical scoping + * + * @test + * @run + * @option --language=es6 + */ + +function tryEval(s) { + try { + eval(s); + } catch (e) { + print(String(e).replace(/\\/g, "/")); + } +} + +tryEval('var x = 0; switch (x) { case 0: { let x = 1; print(x); } case 1: { let x = 2; print(x); }} print(x);'); +tryEval('var x = 0; switch (x) { case 0: { const x = 1; print(x); } case 1: { const x = 2; print(x); }} print(x);'); + +// TODO: the following should not throw +tryEval('switch (x) { case 0: let x = 1; }'); +tryEval('switch (x) { case 0: const x = 1; }'); diff --git a/test/script/basic/es6/let-const-switch.js.EXPECTED b/test/script/basic/es6/let-const-switch.js.EXPECTED new file mode 100644 index 00000000..90309bfe --- /dev/null +++ b/test/script/basic/es6/let-const-switch.js.EXPECTED @@ -0,0 +1,12 @@ +1 +2 +0 +1 +2 +0 +SyntaxError: test/script/basic/es6/let-const-switch.js#34:8:1:25 Unsupported let declaration in unprotected switch statement +switch (x) { case 0: let x = 1; } + ^ +SyntaxError: test/script/basic/es6/let-const-switch.js#34:8:1:27 Unsupported const declaration in unprotected switch statement +switch (x) { case 0: const x = 1; } + ^ diff --git a/test/script/basic/es6/let-load.js b/test/script/basic/es6/let-load.js index 57667543..ff8f4e1c 100644 --- a/test/script/basic/es6/let-load.js +++ b/test/script/basic/es6/let-load.js @@ -40,22 +40,19 @@ load(__DIR__ + "let-load-lib.js"); } print("imported var: " + a); -try { - print("imported let: " + b); -} catch (e) { - print(e); -} +print("imported let: " + b); +print("imported const: " + c); + +top(); try { - print("imported const: " + c); + block(); } catch (e) { print(e); } -top(); - try { - block(); + c = "foo"; } catch (e) { print(e); } diff --git a/test/script/basic/es6/let-load.js.EXPECTED b/test/script/basic/es6/let-load.js.EXPECTED index f92f84c1..a0b2e094 100644 --- a/test/script/basic/es6/let-load.js.EXPECTED +++ b/test/script/basic/es6/let-load.js.EXPECTED @@ -6,3 +6,4 @@ imported let: 2 imported const: 3 top level function ReferenceError: "block" is not defined +TypeError: Assignment to constant "c" diff --git a/test/script/basic/es6/let_const_closure.js.EXPECTED b/test/script/basic/es6/let_const_closure.js.EXPECTED index 5a720d86..f49ca4b9 100644 --- a/test/script/basic/es6/let_const_closure.js.EXPECTED +++ b/test/script/basic/es6/let_const_closure.js.EXPECTED @@ -5,9 +5,9 @@ test test test -3 -3 -3 +0 +1 +2 0 1 2 diff --git a/test/script/basic/es6/lexical-toplevel.js.EXPECTED b/test/script/basic/es6/lexical-toplevel.js.EXPECTED index 804e7506..7580af4f 100644 --- a/test/script/basic/es6/lexical-toplevel.js.EXPECTED +++ b/test/script/basic/es6/lexical-toplevel.js.EXPECTED @@ -13,6 +13,7 @@ false false true true +TypeError: Assignment to constant "CONST" VAR LETLET CONST @@ -28,3 +29,4 @@ false false true true +TypeError: Assignment to constant "CONST" -- cgit v1.2.3 From 9f9274bab0cc84d81a06c4ff8926eafa45c302dd Mon Sep 17 00:00:00 2001 From: attila Date: Thu, 27 Nov 2014 13:04:46 +0100 Subject: 8051778: support bind on all Nashorn callables Reviewed-by: hannesw, lagergren --HG-- rename : src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java => src/jdk/nashorn/internal/runtime/linker/BoundCallable.java rename : src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java => src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java --- .../nashorn/internal/objects/NativeFunction.java | 9 +- src/jdk/nashorn/internal/objects/NativeObject.java | 3 +- .../internal/objects/ScriptFunctionImpl.java | 5 +- .../internal/runtime/arrays/IteratorAction.java | 16 +-- .../nashorn/internal/runtime/linker/Bootstrap.java | 59 +++++++-- .../internal/runtime/linker/BoundCallable.java | 96 +++++++++++++++ .../runtime/linker/BoundCallableLinker.java | 132 +++++++++++++++++++++ .../runtime/linker/BoundDynamicMethod.java | 57 --------- .../runtime/linker/BoundDynamicMethodLinker.java | 91 -------------- .../runtime/linker/JavaSuperAdapterLinker.java | 2 +- test/script/basic/JDK-8051778.js | 83 +++++++++++++ test/script/basic/JDK-8051778.js.EXPECTED | 10 ++ 12 files changed, 379 insertions(+), 184 deletions(-) create mode 100644 src/jdk/nashorn/internal/runtime/linker/BoundCallable.java create mode 100644 src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java delete mode 100644 src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java delete mode 100644 src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java create mode 100644 test/script/basic/JDK-8051778.js create mode 100644 test/script/basic/JDK-8051778.js.EXPECTED diff --git a/src/jdk/nashorn/internal/objects/NativeFunction.java b/src/jdk/nashorn/internal/objects/NativeFunction.java index c4a79a56..bd2f2dd9 100644 --- a/src/jdk/nashorn/internal/objects/NativeFunction.java +++ b/src/jdk/nashorn/internal/objects/NativeFunction.java @@ -48,6 +48,7 @@ import jdk.nashorn.internal.runtime.ScriptEnvironment; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; +import jdk.nashorn.internal.runtime.linker.Bootstrap; /** * ECMA 15.3 Function Objects @@ -204,11 +205,7 @@ public final class NativeFunction { * @return function with bound arguments */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static ScriptFunction bind(final Object self, final Object... args) { - if (!(self instanceof ScriptFunction)) { - throw typeError("not.a.function", ScriptRuntime.safeToString(self)); - } - + public static Object bind(final Object self, final Object... args) { final Object thiz = (args.length == 0) ? UNDEFINED : args[0]; Object[] arguments; @@ -219,7 +216,7 @@ public final class NativeFunction { arguments = ScriptRuntime.EMPTY_ARRAY; } - return ((ScriptFunctionImpl)self).makeBoundFunction(thiz, arguments); + return Bootstrap.bindCallable(self, thiz, arguments); } /** diff --git a/src/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk/nashorn/internal/objects/NativeObject.java index 7a1375d3..c086442d 100644 --- a/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/src/jdk/nashorn/internal/objects/NativeObject.java @@ -28,6 +28,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; + import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -804,7 +805,7 @@ public final class NativeObject { // name and object linked with BeansLinker. (Actually, an even stronger assumption is true: return value is // constant for any given method name and object's class.) return MethodHandles.dropArguments(MethodHandles.constant(Object.class, - Bootstrap.bindDynamicMethod(methodGetter.invoke(source), source)), 0, Object.class); + Bootstrap.bindCallable(methodGetter.invoke(source), source, null)), 0, Object.class); } catch(RuntimeException|Error e) { throw e; } catch(final Throwable t) { diff --git a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java index 36e7716b..f147234b 100644 --- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java +++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java @@ -30,7 +30,6 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import java.lang.invoke.MethodHandle; import java.util.ArrayList; - import jdk.nashorn.internal.runtime.AccessorProperty; import jdk.nashorn.internal.runtime.GlobalFunctions; import jdk.nashorn.internal.runtime.Property; @@ -237,13 +236,13 @@ public class ScriptFunctionImpl extends ScriptFunction { /** * Same as {@link ScriptFunction#makeBoundFunction(Object, Object[])}. The only reason we override it is so that we - * can expose it to methods in this package. + * can expose it. * @param self the self to bind to this function. Can be null (in which case, null is bound as this). * @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments. * @return a function with the specified self and parameters bound. */ @Override - protected ScriptFunction makeBoundFunction(final Object self, final Object[] args) { + public ScriptFunction makeBoundFunction(final Object self, final Object[] args) { return super.makeBoundFunction(self, args); } diff --git a/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java b/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java index 244739b3..ff4c13e2 100644 --- a/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java +++ b/src/jdk/nashorn/internal/runtime/arrays/IteratorAction.java @@ -25,11 +25,7 @@ package jdk.nashorn.internal.runtime.arrays; -import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; - -import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.internal.runtime.Context; -import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.linker.Bootstrap; @@ -98,17 +94,7 @@ public abstract class IteratorAction { * @return result of apply */ public final T apply() { - final boolean strict; - if (callbackfn instanceof ScriptFunction) { - strict = ((ScriptFunction)callbackfn).isStrict(); - } else if (callbackfn instanceof JSObject && - ((JSObject)callbackfn).isFunction()) { - strict = ((JSObject)callbackfn).isStrictFunction(); - } else if (Bootstrap.isDynamicMethod(callbackfn) || Bootstrap.isFunctionalInterfaceObject(callbackfn)) { - strict = false; - } else { - throw typeError("not.a.function", ScriptRuntime.safeToString(callbackfn)); - } + final boolean strict = Bootstrap.isStrictCallable(callbackfn); // for non-strict callback, need to translate undefined thisArg to be global object thisArg = (thisArg == ScriptRuntime.UNDEFINED && !strict)? Context.getGlobal() : thisArg; diff --git a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java index 8c270fb8..749c4728 100644 --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java @@ -26,6 +26,7 @@ package jdk.nashorn.internal.runtime.linker; import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; +import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import java.lang.invoke.CallSite; import java.lang.invoke.ConstantCallSite; @@ -50,6 +51,8 @@ import jdk.nashorn.internal.codegen.ObjectClassGenerator; import jdk.nashorn.internal.codegen.RuntimeCallSite; import jdk.nashorn.internal.lookup.MethodHandleFactory; import jdk.nashorn.internal.lookup.MethodHandleFunctionality; +import jdk.nashorn.internal.objects.ScriptFunctionImpl; +import jdk.nashorn.internal.runtime.ECMAException; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.OptimisticReturnFilters; import jdk.nashorn.internal.runtime.ScriptFunction; @@ -94,7 +97,7 @@ public final class Bootstrap { new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(), - new BoundDynamicMethodLinker(), + new BoundCallableLinker(), new JavaSuperAdapterLinker(), new JSObjectLinker(nashornBeansLinker), new BrowserJSObjectLinker(nashornBeansLinker), @@ -136,19 +139,47 @@ public final class Bootstrap { } return obj instanceof ScriptFunction || - ((obj instanceof JSObject) && ((JSObject)obj).isFunction()) || - isDynamicMethod(obj) || + isJSObjectFunction(obj) || + BeansLinker.isDynamicMethod(obj) || + obj instanceof BoundCallable || isFunctionalInterfaceObject(obj) || obj instanceof StaticClass; } + /** + * Returns true if the given object is a strict callable + * @param callable the callable object to be checked for strictness + * @return true if the obj is a strict callable, false if it is a non-strict callable. + * @throws ECMAException with {@code TypeError} if the object is not a callable. + */ + public static boolean isStrictCallable(final Object callable) { + if (callable instanceof ScriptFunction) { + return ((ScriptFunction)callable).isStrict(); + } else if (isJSObjectFunction(callable)) { + return ((JSObject)callable).isStrictFunction(); + } else if (callable instanceof BoundCallable) { + return isStrictCallable(((BoundCallable)callable).getCallable()); + } else if (BeansLinker.isDynamicMethod(callable) || callable instanceof StaticClass) { + return false; + } + throw notFunction(callable); + } + + private static ECMAException notFunction(final Object obj) { + return typeError("not.a.function", ScriptRuntime.safeToString(obj)); + } + + private static boolean isJSObjectFunction(final Object obj) { + return obj instanceof JSObject && ((JSObject)obj).isFunction(); + } + /** * Returns if the given object is a dynalink Dynamic method * @param obj object to be checked * @return true if the obj is a dynamic method */ public static boolean isDynamicMethod(final Object obj) { - return obj instanceof BoundDynamicMethod || BeansLinker.isDynamicMethod(obj); + return BeansLinker.isDynamicMethod(obj instanceof BoundCallable ? ((BoundCallable)obj).getCallable() : obj); } /** @@ -370,14 +401,22 @@ public final class Bootstrap { } /** - * Binds a bean dynamic method (returned by invoking {@code dyn:getMethod} on an object linked with - * {@code BeansLinker} to a receiver. - * @param dynamicMethod the dynamic method to bind + * Binds any object Nashorn can use as a [[Callable]] to a receiver and optionally arguments. + * @param callable the callable to bind * @param boundThis the bound "this" value. - * @return a bound dynamic method. + * @param boundArgs the bound arguments. Can be either null or empty array to signify no arguments are bound. + * @return a bound callable. + * @throws ECMAException with {@code TypeError} if the object is not a callable. */ - public static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) { - return new BoundDynamicMethod(dynamicMethod, boundThis); + public static Object bindCallable(final Object callable, final Object boundThis, final Object[] boundArgs) { + if (callable instanceof ScriptFunctionImpl) { + return ((ScriptFunctionImpl)callable).makeBoundFunction(boundThis, boundArgs); + } else if (callable instanceof BoundCallable) { + return ((BoundCallable)callable).bind(boundArgs); + } else if (isCallable(callable)) { + return new BoundCallable(callable, boundThis, boundArgs); + } + throw notFunction(callable); } /** diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundCallable.java b/src/jdk/nashorn/internal/runtime/linker/BoundCallable.java new file mode 100644 index 00000000..a0eee0de --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/linker/BoundCallable.java @@ -0,0 +1,96 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.internal.runtime.linker; + +import java.util.Arrays; +import jdk.nashorn.internal.runtime.ScriptRuntime; + +/** + * Represents a Nashorn callable bound to a receiver and optionally arguments. Note that objects of this class + * are just the tuples of a callable and a bound this and arguments, without any behavior. All the behavior is + * defined in the {@code BoundCallableLinker}. + */ +public final class BoundCallable { + private final Object callable; + private final Object boundThis; + private final Object[] boundArgs; + + BoundCallable(final Object callable, final Object boundThis, final Object[] boundArgs) { + this.callable = callable; + this.boundThis = boundThis; + this.boundArgs = isEmptyArray(boundArgs) ? ScriptRuntime.EMPTY_ARRAY : boundArgs.clone(); + } + + private BoundCallable(final BoundCallable original, final Object[] extraBoundArgs) { + this.callable = original.callable; + this.boundThis = original.boundThis; + this.boundArgs = original.concatenateBoundArgs(extraBoundArgs); + } + + Object getCallable() { + return callable; + } + + Object getBoundThis() { + return boundThis; + } + + Object[] getBoundArgs() { + return boundArgs; + } + + BoundCallable bind(final Object[] extraBoundArgs) { + if (isEmptyArray(extraBoundArgs)) { + return this; + } + return new BoundCallable(this, extraBoundArgs); + } + + private Object[] concatenateBoundArgs(final Object[] extraBoundArgs) { + if (boundArgs.length == 0) { + return extraBoundArgs.clone(); + } + final int origBoundArgsLen = boundArgs.length; + final int extraBoundArgsLen = extraBoundArgs.length; + final Object[] newBoundArgs = new Object[origBoundArgsLen + extraBoundArgsLen]; + System.arraycopy(boundArgs, 0, newBoundArgs, 0, origBoundArgsLen); + System.arraycopy(extraBoundArgs, 0, newBoundArgs, origBoundArgsLen, extraBoundArgsLen); + return newBoundArgs; + } + + private static boolean isEmptyArray(final Object[] a) { + return a == null || a.length == 0; + } + + @Override + public String toString() { + final StringBuilder b = new StringBuilder(callable.toString()).append(" on ").append(boundThis); + if (boundArgs.length != 0) { + b.append(" with ").append(Arrays.toString(boundArgs)); + } + return b.toString(); + } +} diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java b/src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java new file mode 100644 index 00000000..d52063bf --- /dev/null +++ b/src/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java @@ -0,0 +1,132 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nashorn.internal.runtime.linker; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Arrays; +import jdk.internal.dynalink.CallSiteDescriptor; +import jdk.internal.dynalink.linker.GuardedInvocation; +import jdk.internal.dynalink.linker.LinkRequest; +import jdk.internal.dynalink.linker.LinkerServices; +import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; +import jdk.internal.dynalink.support.Guards; + +/** + * Links {@link BoundCallable} objects. Passes through to linker services for linking a callable (for either + * "dyn:call" or "dyn:new"), and modifies the returned invocation to deal with the receiver and argument binding. + */ +final class BoundCallableLinker implements TypeBasedGuardingDynamicLinker { + @Override + public boolean canLinkType(final Class type) { + return type == BoundCallable.class; + } + + @Override + public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { + final Object objBoundCallable = linkRequest.getReceiver(); + if(!(objBoundCallable instanceof BoundCallable)) { + return null; + } + + final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor(); + if (descriptor.getNameTokenCount() < 2 || !"dyn".equals(descriptor.getNameToken(CallSiteDescriptor.SCHEME))) { + return null; + } + final String operation = descriptor.getNameToken(CallSiteDescriptor.OPERATOR); + // We need to distinguish "dyn:new" from "dyn:call" because "dyn:call" sites have parameter list of the form + // "callee, this, args", while "dyn:call" sites have "callee, args" -- they lack the "this" parameter. + final boolean isCall; + if ("new".equals(operation)) { + isCall = false; + } else if ("call".equals(operation)) { + isCall = true; + } else { + // Only dyn:call and dyn:new are supported. + return null; + } + final BoundCallable boundCallable = (BoundCallable)objBoundCallable; + final Object callable = boundCallable.getCallable(); + final Object boundThis = boundCallable.getBoundThis(); + + // We need to ask the linker services for a delegate invocation on the target callable. + + // Replace arguments (boundCallable[, this], args) => (callable[, boundThis], boundArgs, args) when delegating + final Object[] args = linkRequest.getArguments(); + final Object[] boundArgs = boundCallable.getBoundArgs(); + final int argsLen = args.length; + final int boundArgsLen = boundArgs.length; + final Object[] newArgs = new Object[argsLen + boundArgsLen]; + newArgs[0] = callable; + final int firstArgIndex; + if (isCall) { + newArgs[1] = boundThis; + firstArgIndex = 2; + } else { + firstArgIndex = 1; + } + System.arraycopy(boundArgs, 0, newArgs, firstArgIndex, boundArgsLen); + System.arraycopy(args, firstArgIndex, newArgs, firstArgIndex + boundArgsLen, argsLen - firstArgIndex); + + // Use R(T0, T1, T2, ...) => R(callable.class, boundThis.class, boundArg0.class, ..., boundArgn.class, T2, ...) + // call site type when delegating to underlying linker (for dyn:new, there's no this). + final MethodType type = descriptor.getMethodType(); + // Use R(T0, ...) => R(callable.class, ...) + MethodType newMethodType = descriptor.getMethodType().changeParameterType(0, callable.getClass()); + if (isCall) { + // R(callable.class, T1, ...) => R(callable.class, boundThis.class, ...) + newMethodType = newMethodType.changeParameterType(1, boundThis.getClass()); + } + // R(callable.class[, boundThis.class], T2, ...) => R(callable.class[, boundThis.class], boundArg0.class, ..., boundArgn.class, T2, ...) + for(int i = boundArgs.length; i-- > 0;) { + newMethodType = newMethodType.insertParameterTypes(firstArgIndex, boundArgs[i] == null ? Object.class : boundArgs[i].getClass()); + } + final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(newMethodType); + + // Delegate to target's linker + final GuardedInvocation inv = linkerServices.getGuardedInvocation(linkRequest.replaceArguments(newDescriptor, newArgs)); + if(inv == null) { + return null; + } + + // Bind (callable[, boundThis], boundArgs) to the delegate handle + final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0, + Arrays.copyOf(newArgs, firstArgIndex + boundArgs.length)); + final Class p0Type = type.parameterType(0); + final MethodHandle droppingHandle; + if (isCall) { + // Ignore incoming boundCallable and this + droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1)); + } else { + // Ignore incoming boundCallable + droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type); + } + // Identity guard on boundCallable object + final MethodHandle newGuard = Guards.getIdentityGuard(boundCallable); + return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type))); + } +} diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java deleted file mode 100644 index 9008547f..00000000 --- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.nashorn.internal.runtime.linker; - -import java.util.Objects; -import jdk.internal.dynalink.beans.BeansLinker; - -/** - * Represents a Dynalink dynamic method bound to a receiver. Note that objects of this class are just the tuples of - * a method and a bound this, without any behavior. All the behavior is defined in the {@code BoundDynamicMethodLinker}. - */ -final class BoundDynamicMethod { - private final Object dynamicMethod; - private final Object boundThis; - - BoundDynamicMethod(final Object dynamicMethod, final Object boundThis) { - assert BeansLinker.isDynamicMethod(dynamicMethod); - this.dynamicMethod = dynamicMethod; - this.boundThis = boundThis; - } - - Object getDynamicMethod() { - return dynamicMethod; - } - - Object getBoundThis() { - return boundThis; - } - - @Override - public String toString() { - return dynamicMethod.toString() + " on " + Objects.toString(boundThis); - } -} diff --git a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java b/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java deleted file mode 100644 index 67e29835..00000000 --- a/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.nashorn.internal.runtime.linker; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import jdk.internal.dynalink.CallSiteDescriptor; -import jdk.internal.dynalink.beans.BeansLinker; -import jdk.internal.dynalink.linker.GuardedInvocation; -import jdk.internal.dynalink.linker.LinkRequest; -import jdk.internal.dynalink.linker.LinkerServices; -import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; -import jdk.internal.dynalink.support.Guards; - -/** - * Links {@code BoundDynamicMethod} objects. Passes through to Dynalink's BeansLinker for linking a dynamic method - * (they only respond to "dyn:call"), and modifies the returned invocation to deal with the receiver binding. - */ -final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker { - @Override - public boolean canLinkType(final Class type) { - return type == BoundDynamicMethod.class; - } - - @Override - public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { - final Object objBoundDynamicMethod = linkRequest.getReceiver(); - if(!(objBoundDynamicMethod instanceof BoundDynamicMethod)) { - return null; - } - - final BoundDynamicMethod boundDynamicMethod = (BoundDynamicMethod)objBoundDynamicMethod; - final Object dynamicMethod = boundDynamicMethod.getDynamicMethod(); - final Object boundThis = boundDynamicMethod.getBoundThis(); - - // Replace arguments (boundDynamicMethod, this, ...) => (dynamicMethod, boundThis, ...) when delegating to - // BeansLinker - final Object[] args = linkRequest.getArguments(); - args[0] = dynamicMethod; - args[1] = boundThis; - - // Use R(T0, T1, ...) => R(dynamicMethod.class, boundThis.class, ...) call site type when delegating to - // BeansLinker. - final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor(); - final MethodType type = descriptor.getMethodType(); - final Class dynamicMethodClass = dynamicMethod.getClass(); - final CallSiteDescriptor newDescriptor = descriptor.changeMethodType( - type.changeParameterType(0, dynamicMethodClass).changeParameterType(1, boundThis.getClass())); - - // Delegate to BeansLinker - final GuardedInvocation inv = NashornBeansLinker.getGuardedInvocation(BeansLinker.getLinkerForClass(dynamicMethodClass), - linkRequest.replaceArguments(newDescriptor, args), linkerServices); - if(inv == null) { - return null; - } - - // Bind (dynamicMethod, boundThis) to the handle - final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0, dynamicMethod, boundThis); - final Class p0Type = type.parameterType(0); - // Ignore incoming (boundDynamicMethod, this) - final MethodHandle droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1)); - // Identity guard on boundDynamicMethod object - final MethodHandle newGuard = Guards.getIdentityGuard(boundDynamicMethod); - - return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type))); - } -} diff --git a/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java b/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java index 5fc93cb4..9aeefd72 100644 --- a/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java +++ b/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java @@ -165,7 +165,7 @@ final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker { */ @SuppressWarnings("unused") private static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) { - return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindDynamicMethod(dynamicMethod, boundThis); + return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindCallable(dynamicMethod, boundThis, null); } /** diff --git a/test/script/basic/JDK-8051778.js b/test/script/basic/JDK-8051778.js new file mode 100644 index 00000000..2d8d788a --- /dev/null +++ b/test/script/basic/JDK-8051778.js @@ -0,0 +1,83 @@ +/* + * 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-8051778: support bind on all Nashorn callables + * + * @test + * @run + */ + +var bind = Function.prototype.bind; + +// Bind a POJO method +var l = new java.util.ArrayList(); +var l_add_foo = bind.call(l.add, l, "foo"); +l_add_foo(); +print("l=" + l); + +// Bind a BoundCallable +var l_add = bind.call(l.add, l); +var l_add_foo2 = bind.call(l_add, null, "foo2"); +l_add_foo2(); +print("l=" + l); + +// Bind a POJO method retrieved from one instance to a different but +// compatible instance. +var l2 = new java.util.ArrayList(); +var l2_size = bind.call(l.size, l2); +print("l2_size()=" + l2_size()); + +// Bind a Java type object (used as a constructor). +var construct_two = bind.call(java.lang.Integer, null, 2); +print("Bound Integer(2) constructor: " + new construct_two()) + +// Bind a @FunctionalInterface proxying to an object literal. NOTE: the +// expected value of this.a is always "original" and never "bound". This +// might seem counterintuitive, but we are not binding the apply() +// function of the object literal that defines the BiFunction behaviour, +// we are binding the SAM proxy object instead, and it is always +// forwarding to the apply() function with "this" set to the object +// literal. Basically, binding "this" for SAM proxies is useless; only +// binding arguments makes sense. +var f1 = new java.util.function.BiFunction() { + apply: function(x, y) { + return "BiFunction with literal: " + this.a + ", " + x + ", " + y; + }, + a: "unbound" +}; +print((bind.call(f1, {a: "bound"}))(1, 2)) +print((bind.call(f1, {a: "bound"}, 3))(4)) +print((bind.call(f1, {a: "bound"}, 5, 6))()) + +// Bind a @FunctionalInterface proxying to a function. With the same +// reasoning as above (binding the proxy vs. binding the JS function), +// the value of this.a will always be undefined, and never "bound". +var f2 = new java.util.function.BiFunction( + function(x, y) { + return "BiFunction with function: " + this.a + ", " + x + ", " + y; + } +); +print((bind.call(f2, {a: "bound"}))(7, 8)) +print((bind.call(f2, {a: "bound"}, 9))(10)) +print((bind.call(f2, {a: "bound"}, 11, 12))()) diff --git a/test/script/basic/JDK-8051778.js.EXPECTED b/test/script/basic/JDK-8051778.js.EXPECTED new file mode 100644 index 00000000..4ba3e287 --- /dev/null +++ b/test/script/basic/JDK-8051778.js.EXPECTED @@ -0,0 +1,10 @@ +l=[foo] +l=[foo, foo2] +l2_size()=0 +Bound Integer(2) constructor: 2 +BiFunction with literal: unbound, 1, 2 +BiFunction with literal: unbound, 3, 4 +BiFunction with literal: unbound, 5, 6 +BiFunction with function: undefined, 7, 8 +BiFunction with function: undefined, 9, 10 +BiFunction with function: undefined, 11, 12 -- cgit v1.2.3 From db7258d41f6866d2b6746d54aa758aa17ddbbde7 Mon Sep 17 00:00:00 2001 From: lagergren Date: Fri, 28 Nov 2014 11:02:54 +0100 Subject: 8066119: Invalid resource tag used for looking up error message in NativeDataView Reviewed-by: hannesw, sundar --- src/jdk/nashorn/internal/objects/NativeDataView.java | 20 ++++++++++---------- .../internal/runtime/resources/Messages.properties | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/jdk/nashorn/internal/objects/NativeDataView.java b/src/jdk/nashorn/internal/objects/NativeDataView.java index fb502771..14c11f69 100644 --- a/src/jdk/nashorn/internal/objects/NativeDataView.java +++ b/src/jdk/nashorn/internal/objects/NativeDataView.java @@ -105,10 +105,10 @@ public class NativeDataView extends ScriptObject { private NativeDataView(final NativeArrayBuffer arrBuf, final ByteBuffer buf, final int offset, final int length) { super(Global.instance().getDataViewPrototype(), $nasgenmap$); - this.buffer = arrBuf; + this.buffer = arrBuf; this.byteOffset = offset; this.byteLength = length; - this.buf = buf; + this.buf = buf; } /** @@ -135,14 +135,14 @@ public class NativeDataView extends ScriptObject { throw typeError("not.an.arraybuffer.in.dataview"); } - final NativeArrayBuffer arrBuf = (NativeArrayBuffer) args[0]; + final NativeArrayBuffer arrBuf = (NativeArrayBuffer)args[0]; switch (args.length) { - case 1: - return new NativeDataView(arrBuf); - case 2: - return new NativeDataView(arrBuf, JSType.toInt32(args[1])); - default: - return new NativeDataView(arrBuf, JSType.toInt32(args[1]), JSType.toInt32(args[2])); + case 1: + return new NativeDataView(arrBuf); + case 2: + return new NativeDataView(arrBuf, JSType.toInt32(args[1])); + default: + return new NativeDataView(arrBuf, JSType.toInt32(args[1]), JSType.toInt32(args[2])); } } @@ -995,7 +995,7 @@ public class NativeDataView extends ScriptObject { private static NativeDataView checkSelf(final Object self) { if (!(self instanceof NativeDataView)) { - throw typeError("not.an.arraybuffer", ScriptRuntime.safeToString(self)); + throw typeError("not.an.arraybuffer.in.dataview", ScriptRuntime.safeToString(self)); } return (NativeDataView)self; } diff --git a/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/src/jdk/nashorn/internal/runtime/resources/Messages.properties index 71c11743..119277df 100644 --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -82,7 +82,7 @@ type.error.not.a.constructor={0} is not a constructor function type.error.not.a.file={0} is not a File type.error.not.a.numeric.array={0} is not a numeric array type.error.not.a.bytebuffer={0} is not a java.nio.ByteBuffer -type.error.not.an.arraybuffer.in.dataview=First arg to DataView constructor must be an ArrayBuffer +type.error.not.an.arraybuffer.in.dataview=First argument to DataView constructor must be an ArrayBuffer type.error.no.reflection.with.classfilter=Java reflection not supported when class filter is present # operations not permitted on undefined -- cgit v1.2.3 From 09b6bf8d7aa88ba3f09434e6576eba1b45cee5e5 Mon Sep 17 00:00:00 2001 From: slugovoy Date: Fri, 28 Nov 2014 18:23:04 +0300 Subject: 8057779: Tests failed on Windows when in output contains path to script Reviewed-by: coffeys --- test/script/basic/es6/const-empty.js | 2 +- test/script/basic/es6/const-redeclare-extra.js | 2 +- test/script/basic/es6/const-redeclare.js | 2 +- test/script/basic/es6/let-redeclare-extra.js | 2 +- test/script/basic/es6/let-redeclare.js | 2 +- test/script/basic/es6/let_const_reuse.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/script/basic/es6/const-empty.js b/test/script/basic/es6/const-empty.js index 0687aa2e..c34d1d51 100644 --- a/test/script/basic/es6/const-empty.js +++ b/test/script/basic/es6/const-empty.js @@ -33,5 +33,5 @@ try { eval('"use strict";\n' + 'const x;\n'); } catch (e) { - print(e); + print(String(e).replace(/\\/g, "/")); } diff --git a/test/script/basic/es6/const-redeclare-extra.js b/test/script/basic/es6/const-redeclare-extra.js index 6d77e18e..94fc53b2 100644 --- a/test/script/basic/es6/const-redeclare-extra.js +++ b/test/script/basic/es6/const-redeclare-extra.js @@ -35,7 +35,7 @@ function tryIt (code) { try { eval(code) } catch (e) { - print(e) + print(String(e).replace(/\\/g, "/")) } } diff --git a/test/script/basic/es6/const-redeclare.js b/test/script/basic/es6/const-redeclare.js index 8e4aa7e4..efe34ac2 100644 --- a/test/script/basic/es6/const-redeclare.js +++ b/test/script/basic/es6/const-redeclare.js @@ -34,5 +34,5 @@ try { 'const x = 2;\n' + 'const x = 2;\n'); } catch (e) { - print(e); + print(String(e).replace(/\\/g, "/")); } diff --git a/test/script/basic/es6/let-redeclare-extra.js b/test/script/basic/es6/let-redeclare-extra.js index 630513f4..ddb205e4 100644 --- a/test/script/basic/es6/let-redeclare-extra.js +++ b/test/script/basic/es6/let-redeclare-extra.js @@ -34,7 +34,7 @@ function tryIt (code) { try { eval(code) } catch (e) { - print(e) + print(String(e).replace(/\\/g, "/")) } } diff --git a/test/script/basic/es6/let-redeclare.js b/test/script/basic/es6/let-redeclare.js index b6ad0f0a..adc05196 100644 --- a/test/script/basic/es6/let-redeclare.js +++ b/test/script/basic/es6/let-redeclare.js @@ -34,5 +34,5 @@ try { 'let x = 2;\n' + 'let x = 2;\n'); } catch (e) { - print(e); + print(String(e).replace(/\\/g, "/")); } diff --git a/test/script/basic/es6/let_const_reuse.js b/test/script/basic/es6/let_const_reuse.js index 556c23dc..bc9e8f84 100644 --- a/test/script/basic/es6/let_const_reuse.js +++ b/test/script/basic/es6/let_const_reuse.js @@ -34,7 +34,7 @@ function tryIt (code) { try { eval(code) } catch (e) { - print(e) + print(String(e).replace(/\\/g, "/")) } } -- cgit v1.2.3 From 719866d0cb4929f4c80e7c0b9fc1f6ec1b3c10b2 Mon Sep 17 00:00:00 2001 From: katleman Date: Wed, 3 Dec 2014 11:12:46 -0800 Subject: Added tag jdk8u40-b17 for changeset 88e22262fdb2 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 2941d00d..93cd9b56 100644 --- a/.hgtags +++ b/.hgtags @@ -336,3 +336,4 @@ d60fbb5343c186abbf92b0259e67efb3b71377b4 jdk8u40-b13 7e34104c55cafa0b579be3a480dda383c616a378 jdk8u40-b14 fc37699ddc0ed41d4ab5da821211a6d2648c8883 jdk8u40-b15 e079f3f6d536510b1ab3589b1038d893d78302ac jdk8u40-b16 +88e22262fdb26e3154a1034c2413415e97b9a86a jdk8u40-b17 -- cgit v1.2.3 From 14acd70e6f6b96c5b4ab23d382aa2f9e378354ce Mon Sep 17 00:00:00 2001 From: katleman Date: Wed, 10 Dec 2014 14:36:00 -0800 Subject: Added tag jdk8u40-b18 for changeset 653739706172 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 93cd9b56..357e2b9a 100644 --- a/.hgtags +++ b/.hgtags @@ -337,3 +337,4 @@ d60fbb5343c186abbf92b0259e67efb3b71377b4 jdk8u40-b13 fc37699ddc0ed41d4ab5da821211a6d2648c8883 jdk8u40-b15 e079f3f6d536510b1ab3589b1038d893d78302ac jdk8u40-b16 88e22262fdb26e3154a1034c2413415e97b9a86a jdk8u40-b17 +653739706172ae94e999731a3a9f10f8ce11ffca jdk8u40-b18 -- cgit v1.2.3