/* * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /** * JDK-8035312 push to frozen array must not increase length property * * @test * @run * @fork * @option -Dnashorn.debug=true */ function printArrayDataClass(x) { if (typeof Debug !== 'undefined') { print(Debug.getArrayDataClass(x)); } } function gpush(x, elem) { try { print("Pushing " + elem + " to " + x); x.push(elem); } catch (e) { print("caught error" + e); } print("\tarray is now [" + x + "] length is = " + x.length); print(); printArrayDataClass(x); } function gpop(x) { try { print("Popping from " + x); x.pop(); } catch (e) { if (!(e instanceof TypeError)) { print("e of wrong type " + e); } } print("\tarray is now [" + x + "] length is = " + x.length); print(); printArrayDataClass(x); } function checkArray(x) { print(); print(">>> Push test"); var olen = x.length; gpush(x, 0); print("x.length === " + x.length + " (should be " + olen + ")"); print("x[3] === " + x[3] + " (should be 0)"); print("x[4] === " + x[4] + " (should be undefined)"); print(); print(">>> Pop test"); gpop(x); gpop(x); print("x.length === " + x.length + " (should be " + olen + ")"); print("x === " + x); for (var i = 0 ; i < 5; i++) { gpop(x); } print("x.length === " + x.length + " (should be " + olen + ")"); print("x === " + x); } print("*** Freezing"); var frozen = [1,2,3]; Object.freeze(frozen); checkArray(frozen); printArrayDataClass(frozen); //so far so good print(); print("*** Other length not writable issues"); var lengthNotWritable = [1,2,3]; Object.defineProperty(lengthNotWritable, "length", { writable: false }); checkArray(lengthNotWritable); printArrayDataClass(lengthNotWritable); function set(array, from, to, stride) { //add three elements for (var i = from; i < to; i+=stride) { try { print("Writing " + i); array[i] = i; printArrayDataClass(array); } catch (e) { print(e instanceof TypeError); } } } //define empty array with non writable length var arr = [1]; Object.defineProperty(arr, "length", { writable: false }); var olen2 = arr.length; set(arr, 0, 3, 1); if (arr.length != olen2) { throw new ("error: " + arr.length + " != " + olen2); } print(); print("array writing 0-3, with 1 stride, array = " + arr); print("length = " + arr.length + ", but elements are: " + arr[0] + " " + arr[1] + " " + arr[2]); print(); //do the same but sparse/deleted range var arr2 = [1]; Object.defineProperty(arr2, "length", { writable: false }); print("initial length = " + arr2.length); var olen3 = arr2.length; set(arr2, 0, 30, 3); if (arr2.length != olen3) { throw new ("error: " + arr2.length + " != " + olen3); } print(); var larger = 20; print("array writing 0-" + larger + ", with 3 stride, array = " + arr2); print("length = " + arr2.length + ", but elements are: " + arr2[0] + " " + arr2[1] + " " + arr2[2]); for (var i = 0; i < larger; i++) { if (arr2[i] === undefined) { continue; } print(arr2[i] + " has length " + arr2.length); } print(); var elem = 0x7fffffff - 10; printArrayDataClass(arr2); print("adding a new element high up in the array"); print("length before element was added " + arr2.length); print("putting sparse at " + elem); arr2[elem] = "sparse"; print("length after element was added " + arr2.length + " should be the same"); printArrayDataClass(arr2); print(); print("Printing arr2 - this will fail if length is > 28 and it is " + arr2.length); print("arr2 = [" + arr2 + "]"); print("new length that should not be writable = " + arr2.length); print(arr2[elem] === "sparse"); print(arr2[elem]); for (var i = 0; i < larger; i++) { print(arr2[i]); } for (var key in arr2) { print(key + ":" + arr2[key]); } //issues reported by sundar - generic setter doesn't go through push/pop bulkable function sundarExample2(arr, _writable) { print("Checking if push works for bulkable non bulkable arrays - Setting length property not allowed"); arr[0] = "bar"; print(arr.length + " should be 1"); // should be 1 print(arr[0] + " should be bar"); print("["+ arr + "] should be [bar]"); // Object.defineProperty(arr, "length", { configurable: _writable }); Object.defineProperty(arr, "length", { writable: _writable }); arr[1] = "baz"; if (_writable) { print(arr.length + " should be 2"); print(arr[0] + " should be bar"); print(arr[1] + " should be baz"); print("["+ arr + "] should be [bar,baz]"); } else { print(arr.length + " should STILL be 1"); print(arr[0] + " should be bar"); print(arr[1] + " should be baz"); print("["+ arr + "] should be [bar]"); } } var newArr1 = []; sundarExample2(newArr1, false); print(); try { sundarExample2(newArr1, true); print("should not get here"); } catch (e) { if (!(e instanceof TypeError)) { print("Wrong exception"); } print("got TypeError when redefining length, as expected") } print(); sundarExample2([], true); print("Done");