Fri, 21 Mar 2014 20:24:01 +0530
8037562: Nashorn: JSON.parse comes up with nonexistent entries if there are gaps between the keys
Reviewed-by: jlaskey, hannesw
1.1 --- a/src/jdk/nashorn/internal/objects/NativeArray.java Mon Mar 17 18:02:00 2014 +0530 1.2 +++ b/src/jdk/nashorn/internal/objects/NativeArray.java Fri Mar 21 20:24:01 2014 +0530 1.3 @@ -31,6 +31,7 @@ 1.4 import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE; 1.5 import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator; 1.6 import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator; 1.7 +import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; 1.8 1.9 import java.lang.invoke.MethodHandle; 1.10 import java.util.ArrayList; 1.11 @@ -350,6 +351,27 @@ 1.12 } 1.13 1.14 /** 1.15 + * Spec. mentions use of [[DefineOwnProperty]] for indexed properties in 1.16 + * certain places (eg. Array.prototype.map, filter). We can not use ScriptObject.set 1.17 + * method in such cases. This is because set method uses inherited setters (if any) 1.18 + * from any object in proto chain such as Array.prototype, Object.prototype. 1.19 + * This method directly sets a particular element value in the current object. 1.20 + * 1.21 + * @param index key for property 1.22 + * @param value value to define 1.23 + */ 1.24 + @Override 1.25 + public final void defineOwnProperty(final int index, final Object value) { 1.26 + assert isValidArrayIndex(index) : "invalid array index"; 1.27 + final long longIndex = ArrayIndex.toLongIndex(index); 1.28 + if (longIndex >= getArray().length()) { 1.29 + // make array big enough to hold.. 1.30 + setArray(getArray().ensure(longIndex)); 1.31 + } 1.32 + setArray(getArray().set(index, value, false)); 1.33 + } 1.34 + 1.35 + /** 1.36 * Return the array contents upcasted as an ObjectArray, regardless of 1.37 * representation 1.38 *
2.1 --- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java Mon Mar 17 18:02:00 2014 +0530 2.2 +++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java Fri Mar 21 20:24:01 2014 +0530 2.3 @@ -101,7 +101,6 @@ 2.4 // apply 'reviver' function if available 2.5 private static Object applyReviver(final Global global, final Object unfiltered, final Object reviver) { 2.6 if (reviver instanceof ScriptFunction) { 2.7 - assert global instanceof Global; 2.8 final ScriptObject root = global.newObject(); 2.9 root.addOwnProperty("", Property.WRITABLE_ENUMERABLE_CONFIGURABLE, unfiltered); 2.10 return walk(root, "", (ScriptFunction)reviver);
3.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Mon Mar 17 18:02:00 2014 +0530 3.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Fri Mar 21 20:24:01 2014 +0530 3.3 @@ -593,23 +593,16 @@ 3.4 } 3.5 3.6 /** 3.7 - * Spec. mentions use of [[DefineOwnProperty]] for indexed properties in 3.8 - * certain places (eg. Array.prototype.map, filter). We can not use ScriptObject.set 3.9 - * method in such cases. This is because set method uses inherited setters (if any) 3.10 - * from any object in proto chain such as Array.prototype, Object.prototype. 3.11 - * This method directly sets a particular element value in the current object. 3.12 + * Almost like defineOwnProperty(int,Object) for arrays this one does 3.13 + * not add 'gap' elements (like the array one does). 3.14 * 3.15 * @param index key for property 3.16 * @param value value to define 3.17 */ 3.18 - public final void defineOwnProperty(final int index, final Object value) { 3.19 + public void defineOwnProperty(final int index, final Object value) { 3.20 assert isValidArrayIndex(index) : "invalid array index"; 3.21 final long longIndex = ArrayIndex.toLongIndex(index); 3.22 - if (longIndex >= getArray().length()) { 3.23 - // make array big enough to hold.. 3.24 - setArray(getArray().ensure(longIndex)); 3.25 - } 3.26 - setArray(getArray().set(index, value, false)); 3.27 + setValueAtArrayIndex(longIndex, index, value, false); 3.28 } 3.29 3.30 private void checkIntegerKey(final String key) { 3.31 @@ -2747,9 +2740,7 @@ 3.32 * @param strict are we in strict mode 3.33 */ 3.34 private void doesNotHave(final int index, final Object value, final boolean strict) { 3.35 - final long oldLength = getArray().length(); 3.36 final long longIndex = ArrayIndex.toLongIndex(index); 3.37 - 3.38 if (getMap().containsArrayKeys()) { 3.39 final String key = JSType.toString(longIndex); 3.40 final FindProperty find = findProperty(key, true); 3.41 @@ -2760,6 +2751,18 @@ 3.42 } 3.43 } 3.44 3.45 + setValueAtArrayIndex(longIndex, index, value, strict); 3.46 + } 3.47 + 3.48 + /** 3.49 + * Handle when an array doesn't have a slot - possibly grow and/or convert array. 3.50 + * 3.51 + * @param index key as index 3.52 + * @param value element value 3.53 + * @param strict are we in strict mode 3.54 + */ 3.55 + private void setValueAtArrayIndex(final long longIndex, final int index, final Object value, final boolean strict) { 3.56 + final long oldLength = getArray().length(); 3.57 if (longIndex >= oldLength) { 3.58 if (!isExtensible()) { 3.59 if (strict) {
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/test/script/basic/JDK-8037562.js Fri Mar 21 20:24:01 2014 +0530 4.3 @@ -0,0 +1,41 @@ 4.4 +/* 4.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.7 + * 4.8 + * This code is free software; you can redistribute it and/or modify it 4.9 + * under the terms of the GNU General Public License version 2 only, as 4.10 + * published by the Free Software Foundation. 4.11 + * 4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 4.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 4.15 + * version 2 for more details (a copy is included in the LICENSE file that 4.16 + * accompanied this code). 4.17 + * 4.18 + * You should have received a copy of the GNU General Public License version 4.19 + * 2 along with this work; if not, write to the Free Software Foundation, 4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 4.21 + * 4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 4.23 + * or visit www.oracle.com if you need additional information or have any 4.24 + * questions. 4.25 + */ 4.26 + 4.27 + 4.28 +/** 4.29 + * JDK-8037562: Nashorn: JSON.parse comes up with nonexistent entries if there are gaps between the keys 4.30 + * 4.31 + * @test 4.32 + * @run 4.33 + */ 4.34 + 4.35 +var strs = [ 4.36 + '{ "0":0, "2":2 }', 4.37 + '{ "0":"", "2":"" }', 4.38 + '{ "0":0, "5":"hello" }', 4.39 + '{ "0":"", "15":3234 }', 4.40 +] 4.41 + 4.42 +for (var i in strs) { 4.43 + print(JSON.stringify(JSON.parse(strs[i]))); 4.44 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/test/script/basic/JDK-8037562.js.EXPECTED Fri Mar 21 20:24:01 2014 +0530 5.3 @@ -0,0 +1,4 @@ 5.4 +{"0":0,"2":2} 5.5 +{"0":"","2":""} 5.6 +{"0":0,"5":"hello"} 5.7 +{"0":"","15":3234}