Thu, 01 Oct 2015 10:37:25 +0200
8138632: Sparse array does not handle growth of underlying dense array
Reviewed-by: attila, sundar
1.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Thu Oct 01 21:27:30 2015 +0530 1.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Thu Oct 01 10:37:25 2015 +0200 1.3 @@ -710,8 +710,7 @@ 1.4 final long longIndex = ArrayIndex.toLongIndex(index); 1.5 final long oldLength = getArray().length(); 1.6 if (longIndex >= oldLength) { 1.7 - setArray(getArray().ensure(longIndex)); 1.8 - doesNotHaveEnsureDelete(longIndex, oldLength, false); 1.9 + setArray(getArray().ensure(longIndex).safeDelete(oldLength, longIndex - 1, false)); 1.10 } 1.11 setArray(getArray().set(index, value, false)); 1.12 } 1.13 @@ -2678,11 +2677,7 @@ 1.14 } 1.15 1.16 if (newLength > arrayLength) { 1.17 - data = data.ensure(newLength - 1); 1.18 - if (data.canDelete(arrayLength, newLength - 1, false)) { 1.19 - data = data.delete(arrayLength, newLength - 1); 1.20 - } 1.21 - setArray(data); 1.22 + setArray(data.ensure(newLength - 1).safeDelete(arrayLength, newLength - 1, false)); 1.23 return; 1.24 } 1.25 1.26 @@ -3103,23 +3098,12 @@ 1.27 return false; 1.28 } 1.29 1.30 - private void doesNotHaveEnsureDelete(final long longIndex, final long oldLength, final boolean strict) { 1.31 - if (longIndex > oldLength) { 1.32 - ArrayData array = getArray(); 1.33 - if (array.canDelete(oldLength, longIndex - 1, strict)) { 1.34 - array = array.delete(oldLength, longIndex - 1); 1.35 - } 1.36 - setArray(array); 1.37 - } 1.38 - } 1.39 - 1.40 private void doesNotHave(final int index, final int value, final int callSiteFlags) { 1.41 final long oldLength = getArray().length(); 1.42 final long longIndex = ArrayIndex.toLongIndex(index); 1.43 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { 1.44 final boolean strict = isStrictFlag(callSiteFlags); 1.45 - setArray(getArray().set(index, value, strict)); 1.46 - doesNotHaveEnsureDelete(longIndex, oldLength, strict); 1.47 + setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict)); 1.48 } 1.49 } 1.50 1.51 @@ -3128,8 +3112,7 @@ 1.52 final long longIndex = ArrayIndex.toLongIndex(index); 1.53 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { 1.54 final boolean strict = isStrictFlag(callSiteFlags); 1.55 - setArray(getArray().set(index, value, strict)); 1.56 - doesNotHaveEnsureDelete(longIndex, oldLength, strict); 1.57 + setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict)); 1.58 } 1.59 } 1.60 1.61 @@ -3138,8 +3121,7 @@ 1.62 final long longIndex = ArrayIndex.toLongIndex(index); 1.63 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { 1.64 final boolean strict = isStrictFlag(callSiteFlags); 1.65 - setArray(getArray().set(index, value, strict)); 1.66 - doesNotHaveEnsureDelete(longIndex, oldLength, strict); 1.67 + setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict)); 1.68 } 1.69 } 1.70 1.71 @@ -3148,8 +3130,7 @@ 1.72 final long longIndex = ArrayIndex.toLongIndex(index); 1.73 if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) { 1.74 final boolean strict = isStrictFlag(callSiteFlags); 1.75 - setArray(getArray().set(index, value, strict)); 1.76 - doesNotHaveEnsureDelete(longIndex, oldLength, strict); 1.77 + setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict)); 1.78 } 1.79 } 1.80
2.1 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java Thu Oct 01 21:27:30 2015 +0530 2.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java Thu Oct 01 10:37:25 2015 +0200 2.3 @@ -258,7 +258,7 @@ 2.4 * Factory method for unspecified array - start as int 2.5 * @return ArrayData 2.6 */ 2.7 - public final static ArrayData initialArray() { 2.8 + public static ArrayData initialArray() { 2.9 return new IntArrayData(); 2.10 } 2.11 2.12 @@ -278,7 +278,7 @@ 2.13 * @param size size required 2.14 * @return size given, always >= size 2.15 */ 2.16 - protected final static int alignUp(final int size) { 2.17 + protected static int alignUp(final int size) { 2.18 return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1); 2.19 } 2.20 2.21 @@ -288,7 +288,7 @@ 2.22 * @param length the initial length 2.23 * @return ArrayData 2.24 */ 2.25 - public static final ArrayData allocate(final int length) { 2.26 + public static ArrayData allocate(final int length) { 2.27 if (length == 0) { 2.28 return new IntArrayData(); 2.29 } else if (length >= SparseArrayData.MAX_DENSE_LENGTH) { 2.30 @@ -304,7 +304,7 @@ 2.31 * @param array the array 2.32 * @return ArrayData wrapping this array 2.33 */ 2.34 - public static final ArrayData allocate(final Object array) { 2.35 + public static ArrayData allocate(final Object array) { 2.36 final Class<?> clazz = array.getClass(); 2.37 2.38 if (clazz == int[].class) { 2.39 @@ -324,7 +324,7 @@ 2.40 * @param array the array to use for initial elements 2.41 * @return the ArrayData 2.42 */ 2.43 - public static final ArrayData allocate(final int[] array) { 2.44 + public static ArrayData allocate(final int[] array) { 2.45 return new IntArrayData(array, array.length); 2.46 } 2.47 2.48 @@ -334,7 +334,7 @@ 2.49 * @param array the array to use for initial elements 2.50 * @return the ArrayData 2.51 */ 2.52 - public static final ArrayData allocate(final long[] array) { 2.53 + public static ArrayData allocate(final long[] array) { 2.54 return new LongArrayData(array, array.length); 2.55 } 2.56 2.57 @@ -344,7 +344,7 @@ 2.58 * @param array the array to use for initial elements 2.59 * @return the ArrayData 2.60 */ 2.61 - public static final ArrayData allocate(final double[] array) { 2.62 + public static ArrayData allocate(final double[] array) { 2.63 return new NumberArrayData(array, array.length); 2.64 } 2.65 2.66 @@ -354,7 +354,7 @@ 2.67 * @param array the array to use for initial elements 2.68 * @return the ArrayData 2.69 */ 2.70 - public static final ArrayData allocate(final Object[] array) { 2.71 + public static ArrayData allocate(final Object[] array) { 2.72 return new ObjectArrayData(array, array.length); 2.73 } 2.74 2.75 @@ -364,7 +364,7 @@ 2.76 * @param buf the nio ByteBuffer to wrap 2.77 * @return the ArrayData 2.78 */ 2.79 - public static final ArrayData allocate(final ByteBuffer buf) { 2.80 + public static ArrayData allocate(final ByteBuffer buf) { 2.81 return new ByteBufferArrayData(buf); 2.82 } 2.83 2.84 @@ -374,7 +374,7 @@ 2.85 * @param underlying the underlying ArrayData to wrap in the freeze filter 2.86 * @return the frozen ArrayData 2.87 */ 2.88 - public static final ArrayData freeze(final ArrayData underlying) { 2.89 + public static ArrayData freeze(final ArrayData underlying) { 2.90 return new FrozenArrayFilter(underlying); 2.91 } 2.92 2.93 @@ -384,7 +384,7 @@ 2.94 * @param underlying the underlying ArrayData to wrap in the seal filter 2.95 * @return the sealed ArrayData 2.96 */ 2.97 - public static final ArrayData seal(final ArrayData underlying) { 2.98 + public static ArrayData seal(final ArrayData underlying) { 2.99 return new SealedArrayFilter(underlying); 2.100 } 2.101 2.102 @@ -394,7 +394,7 @@ 2.103 * @param underlying the underlying ArrayData to wrap in the non extensible filter 2.104 * @return new array data, filtered 2.105 */ 2.106 - public static final ArrayData preventExtension(final ArrayData underlying) { 2.107 + public static ArrayData preventExtension(final ArrayData underlying) { 2.108 return new NonExtensibleArrayFilter(underlying); 2.109 } 2.110 2.111 @@ -404,7 +404,7 @@ 2.112 * @param underlying the underlying ArrayDAta to wrap in the non extensible filter 2.113 * @return new array data, filtered 2.114 */ 2.115 - public static final ArrayData setIsLengthNotWritable(final ArrayData underlying) { 2.116 + public static ArrayData setIsLengthNotWritable(final ArrayData underlying) { 2.117 return new LengthNotWritableFilter(underlying); 2.118 } 2.119 2.120 @@ -676,19 +676,34 @@ 2.121 } 2.122 2.123 /** 2.124 - * Returns if element at specific index range can be deleted or not. 2.125 + * Returns if element at specific index can be deleted or not. 2.126 * 2.127 - * @param fromIndex the start index 2.128 - * @param toIndex the end index 2.129 + * @param longIndex the index 2.130 * @param strict are we in strict mode 2.131 * 2.132 * @return true if range can be deleted 2.133 */ 2.134 - public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) { 2.135 + public boolean canDelete(final long longIndex, final boolean strict) { 2.136 return true; 2.137 } 2.138 2.139 /** 2.140 + * Delete a range from the array if {@code fromIndex} is less than or equal to {@code toIndex} 2.141 + * and the array supports deletion. 2.142 + * 2.143 + * @param fromIndex the start index (inclusive) 2.144 + * @param toIndex the end index (inclusive) 2.145 + * @param strict are we in strict mode 2.146 + * @return an array with the range deleted, or this array if no deletion took place 2.147 + */ 2.148 + public final ArrayData safeDelete(final long fromIndex, final long toIndex, final boolean strict) { 2.149 + if (fromIndex <= toIndex && canDelete(fromIndex, strict)) { 2.150 + return delete(fromIndex, toIndex); 2.151 + } 2.152 + return this; 2.153 + } 2.154 + 2.155 + /** 2.156 * Returns property descriptor for element at a given index 2.157 * 2.158 * @param global the global object
3.1 --- a/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java Thu Oct 01 21:27:30 2015 +0530 3.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java Thu Oct 01 10:37:25 2015 +0200 3.3 @@ -164,7 +164,7 @@ 3.4 } 3.5 3.6 @Override 3.7 - public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) { 3.8 + public boolean canDelete(final long longIndex, final boolean strict) { 3.9 return false; 3.10 } 3.11
4.1 --- a/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java Thu Oct 01 21:27:30 2015 +0530 4.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java Thu Oct 01 10:37:25 2015 +0200 4.3 @@ -50,15 +50,15 @@ 4.4 4.5 @Override 4.6 public boolean canDelete(final int index, final boolean strict) { 4.7 - if (strict) { 4.8 - throw typeError("cant.delete.property", Integer.toString(index), "sealed array"); 4.9 - } 4.10 - return false; 4.11 + return canDelete(ArrayIndex.toLongIndex(index), strict); 4.12 } 4.13 4.14 @Override 4.15 - public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) { 4.16 - return canDelete((int) fromIndex, strict); 4.17 + public boolean canDelete(final long longIndex, final boolean strict) { 4.18 + if (strict) { 4.19 + throw typeError("cant.delete.property", Long.toString(longIndex), "sealed array"); 4.20 + } 4.21 + return false; 4.22 } 4.23 4.24 @Override
5.1 --- a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java Thu Oct 01 21:27:30 2015 +0530 5.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java Thu Oct 01 10:37:25 2015 +0200 5.3 @@ -166,8 +166,9 @@ 5.4 @Override 5.5 public ArrayData set(final int index, final Object value, final boolean strict) { 5.6 if (index >= 0 && index < maxDenseLength) { 5.7 + final long oldLength = underlying.length(); 5.8 ensure(index); 5.9 - underlying = underlying.set(index, value, strict); 5.10 + underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict); 5.11 setLength(Math.max(underlying.length(), length())); 5.12 } else { 5.13 final Long longIndex = indexToKey(index); 5.14 @@ -181,8 +182,9 @@ 5.15 @Override 5.16 public ArrayData set(final int index, final int value, final boolean strict) { 5.17 if (index >= 0 && index < maxDenseLength) { 5.18 + final long oldLength = underlying.length(); 5.19 ensure(index); 5.20 - underlying = underlying.set(index, value, strict); 5.21 + underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict); 5.22 setLength(Math.max(underlying.length(), length())); 5.23 } else { 5.24 final Long longIndex = indexToKey(index); 5.25 @@ -195,8 +197,9 @@ 5.26 @Override 5.27 public ArrayData set(final int index, final long value, final boolean strict) { 5.28 if (index >= 0 && index < maxDenseLength) { 5.29 + final long oldLength = underlying.length(); 5.30 ensure(index); 5.31 - underlying = underlying.set(index, value, strict); 5.32 + underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict); 5.33 setLength(Math.max(underlying.length(), length())); 5.34 } else { 5.35 final Long longIndex = indexToKey(index); 5.36 @@ -209,8 +212,9 @@ 5.37 @Override 5.38 public ArrayData set(final int index, final double value, final boolean strict) { 5.39 if (index >= 0 && index < maxDenseLength) { 5.40 + final long oldLength = underlying.length(); 5.41 ensure(index); 5.42 - underlying = underlying.set(index, value, strict); 5.43 + underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict); 5.44 setLength(Math.max(underlying.length(), length())); 5.45 } else { 5.46 final Long longIndex = indexToKey(index);
6.1 --- a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java Thu Oct 01 21:27:30 2015 +0530 6.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java Thu Oct 01 10:37:25 2015 +0200 6.3 @@ -83,7 +83,7 @@ 6.4 } 6.5 6.6 @Override 6.7 - public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) { 6.8 + public boolean canDelete(final long longIndex, final boolean strict) { 6.9 return false; 6.10 } 6.11
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/test/script/basic/JDK-8138632.js Thu Oct 01 10:37:25 2015 +0200 7.3 @@ -0,0 +1,35 @@ 7.4 +/* 7.5 + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.7 + * 7.8 + * This code is free software; you can redistribute it and/or modify it 7.9 + * under the terms of the GNU General Public License version 2 only, as 7.10 + * published by the Free Software Foundation. 7.11 + * 7.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 7.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.15 + * version 2 for more details (a copy is included in the LICENSE file that 7.16 + * accompanied this code). 7.17 + * 7.18 + * You should have received a copy of the GNU General Public License version 7.19 + * 2 along with this work; if not, write to the Free Software Foundation, 7.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.21 + * 7.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.23 + * or visit www.oracle.com if you need additional information or have any 7.24 + * questions. 7.25 + */ 7.26 + 7.27 +/** 7.28 + * JDK-8138632: Sparse array does not handle growth of underlying dense array 7.29 + * 7.30 + * @test 7.31 + * @run 7.32 + */ 7.33 + 7.34 +var x = []; 7.35 +x[10000000] = 1; 7.36 +x[10] = 1; 7.37 +x[20] = 1; 7.38 +print(Object.keys(x));
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/test/script/basic/JDK-8138632.js.EXPECTED Thu Oct 01 10:37:25 2015 +0200 8.3 @@ -0,0 +1,1 @@ 8.4 +10,20,10000000