1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.internal.runtime.arrays; 27 28 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall; 29 30 import java.lang.invoke.MethodHandle; 31 import java.lang.invoke.MethodHandles; 32 import java.util.Arrays; 33 import jdk.nashorn.internal.runtime.JSType; 34 import jdk.nashorn.internal.runtime.ScriptRuntime; 35 36 /** 37 * Implementation of {@link ArrayData} as soon as an int has been 38 * written to the array. This is the default data for new arrays 39 */ 40 final class IntArrayData extends ContinuousArrayData implements IntElements { 41 /** 42 * The wrapped array 43 */ 44 private int[] array; 45 IntArrayData()46 IntArrayData() { 47 this(new int[ArrayData.CHUNK_SIZE], 0); 48 } 49 IntArrayData(final int length)50 IntArrayData(final int length) { 51 super(length); 52 this.array = new int[ArrayData.nextSize(length)]; 53 } 54 55 /** 56 * Constructor 57 * @param array an int array 58 * @param length a length, not necessarily array.length 59 */ IntArrayData(final int[] array, final int length)60 IntArrayData(final int[] array, final int length) { 61 super(length); 62 assert array == null || array.length >= length; 63 this.array = array; 64 } 65 66 @Override getElementType()67 public final Class<?> getElementType() { 68 return int.class; 69 } 70 71 @Override getBoxedElementType()72 public final Class<?> getBoxedElementType() { 73 return Integer.class; 74 } 75 76 @Override getElementWeight()77 public final int getElementWeight() { 78 return 1; 79 } 80 81 @Override widest(final ContinuousArrayData otherData)82 public final ContinuousArrayData widest(final ContinuousArrayData otherData) { 83 return otherData; 84 } 85 86 private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle(); 87 private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle(); 88 89 @Override asObjectArray()90 public Object[] asObjectArray() { 91 return toObjectArray(true); 92 } 93 94 @SuppressWarnings("unused") getElem(final int index)95 private int getElem(final int index) { 96 if (has(index)) { 97 return array[index]; 98 } 99 throw new ClassCastException(); 100 } 101 102 @SuppressWarnings("unused") setElem(final int index, final int elem)103 private void setElem(final int index, final int elem) { 104 if (hasRoomFor(index)) { 105 array[index] = elem; 106 return; 107 } 108 throw new ClassCastException(); 109 } 110 111 @Override getElementGetter(final Class<?> returnType, final int programPoint)112 public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { 113 return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint); 114 } 115 116 @Override getElementSetter(final Class<?> elementType)117 public MethodHandle getElementSetter(final Class<?> elementType) { 118 return elementType == int.class ? getContinuousElementSetter(SET_ELEM, elementType) : null; 119 } 120 121 @Override copy()122 public IntArrayData copy() { 123 return new IntArrayData(array.clone(), (int)length()); 124 } 125 126 @Override asArrayOfType(final Class<?> componentType)127 public Object asArrayOfType(final Class<?> componentType) { 128 if (componentType == int.class) { 129 final int len = (int)length(); 130 return array.length == len ? array.clone() : Arrays.copyOf(array, len); 131 } 132 return super.asArrayOfType(componentType); 133 } 134 toObjectArray(final boolean trim)135 private Object[] toObjectArray(final boolean trim) { 136 assert length() <= array.length : "length exceeds internal array size"; 137 final int len = (int)length(); 138 final Object[] oarray = new Object[trim ? len : array.length]; 139 140 for (int index = 0; index < len; index++) { 141 oarray[index] = array[index]; 142 } 143 144 return oarray; 145 } 146 toDoubleArray()147 private double[] toDoubleArray() { 148 assert length() <= array.length : "length exceeds internal array size"; 149 final int len = (int)length(); 150 final double[] darray = new double[array.length]; 151 152 for (int index = 0; index < len; index++) { 153 darray[index] = array[index]; 154 } 155 156 return darray; 157 } 158 convertToDouble()159 private NumberArrayData convertToDouble() { 160 return new NumberArrayData(toDoubleArray(), (int)length()); 161 } 162 convertToObject()163 private ObjectArrayData convertToObject() { 164 return new ObjectArrayData(toObjectArray(false), (int)length()); 165 } 166 167 @Override convert(final Class<?> type)168 public ArrayData convert(final Class<?> type) { 169 if (type == Integer.class || type == Byte.class || type == Short.class) { 170 return this; 171 } else if (type == Double.class || type == Float.class) { 172 return convertToDouble(); 173 } else { 174 return convertToObject(); 175 } 176 } 177 178 @Override shiftLeft(final int by)179 public ArrayData shiftLeft(final int by) { 180 if (by >= length()) { 181 shrink(0); 182 } else { 183 System.arraycopy(array, by, array, 0, array.length - by); 184 } 185 setLength(Math.max(0, length() - by)); 186 187 return this; 188 } 189 190 @Override shiftRight(final int by)191 public ArrayData shiftRight(final int by) { 192 final ArrayData newData = ensure(by + length() - 1); 193 if (newData != this) { 194 newData.shiftRight(by); 195 return newData; 196 } 197 System.arraycopy(array, 0, array, by, array.length - by); 198 199 return this; 200 } 201 202 @Override ensure(final long safeIndex)203 public ArrayData ensure(final long safeIndex) { 204 if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { 205 return new SparseArrayData(this, safeIndex + 1); 206 } 207 final int alen = array.length; 208 if (safeIndex >= alen) { 209 final int newLength = ArrayData.nextSize((int)safeIndex); 210 array = Arrays.copyOf(array, newLength); 211 } 212 if (safeIndex >= length()) { 213 setLength(safeIndex + 1); 214 } 215 return this; 216 } 217 218 @Override shrink(final long newLength)219 public ArrayData shrink(final long newLength) { 220 Arrays.fill(array, (int)newLength, array.length, 0); 221 return this; 222 } 223 224 @Override set(final int index, final Object value, final boolean strict)225 public ArrayData set(final int index, final Object value, final boolean strict) { 226 if (JSType.isRepresentableAsInt(value)) { 227 return set(index, JSType.toInt32(value), strict); 228 } else if (value == ScriptRuntime.UNDEFINED) { 229 return new UndefinedArrayFilter(this).set(index, value, strict); 230 } 231 232 final ArrayData newData = convert(value == null ? Object.class : value.getClass()); 233 return newData.set(index, value, strict); 234 } 235 236 @Override set(final int index, final int value, final boolean strict)237 public ArrayData set(final int index, final int value, final boolean strict) { 238 array[index] = value; 239 setLength(Math.max(index + 1, length())); 240 241 return this; 242 } 243 244 @Override set(final int index, final double value, final boolean strict)245 public ArrayData set(final int index, final double value, final boolean strict) { 246 if (JSType.isRepresentableAsInt(value)) { 247 array[index] = (int)(long)value; 248 setLength(Math.max(index + 1, length())); 249 return this; 250 } 251 252 return convert(Double.class).set(index, value, strict); 253 } 254 255 @Override getInt(final int index)256 public int getInt(final int index) { 257 return array[index]; 258 } 259 260 @Override getIntOptimistic(final int index, final int programPoint)261 public int getIntOptimistic(final int index, final int programPoint) { 262 return array[index]; 263 } 264 265 @Override getDouble(final int index)266 public double getDouble(final int index) { 267 return array[index]; 268 } 269 270 @Override getDoubleOptimistic(final int index, final int programPoint)271 public double getDoubleOptimistic(final int index, final int programPoint) { 272 return array[index]; 273 } 274 275 @Override getObject(final int index)276 public Object getObject(final int index) { 277 return array[index]; 278 } 279 280 @Override has(final int index)281 public boolean has(final int index) { 282 return 0 <= index && index < length(); 283 } 284 285 @Override delete(final int index)286 public ArrayData delete(final int index) { 287 return new DeletedRangeArrayFilter(this, index, index); 288 } 289 290 @Override delete(final long fromIndex, final long toIndex)291 public ArrayData delete(final long fromIndex, final long toIndex) { 292 return new DeletedRangeArrayFilter(this, fromIndex, toIndex); 293 } 294 295 @Override pop()296 public Object pop() { 297 final int len = (int)length(); 298 if (len == 0) { 299 return ScriptRuntime.UNDEFINED; 300 } 301 302 final int newLength = len - 1; 303 final int elem = array[newLength]; 304 array[newLength] = 0; 305 setLength(newLength); 306 307 return elem; 308 } 309 310 @Override slice(final long from, final long to)311 public ArrayData slice(final long from, final long to) { 312 return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length() : from))); 313 } 314 315 @Override fastSplice(final int start, final int removed, final int added)316 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { 317 final long oldLength = length(); 318 final long newLength = oldLength - removed + added; 319 if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { 320 throw new UnsupportedOperationException(); 321 } 322 final ArrayData returnValue = removed == 0 ? 323 EMPTY_ARRAY : 324 new IntArrayData( 325 Arrays.copyOfRange( 326 array, 327 start, 328 start + removed), 329 removed); 330 331 if (newLength != oldLength) { 332 final int[] newArray; 333 334 if (newLength > array.length) { 335 newArray = new int[ArrayData.nextSize((int)newLength)]; 336 System.arraycopy(array, 0, newArray, 0, start); 337 } else { 338 newArray = array; 339 } 340 341 System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); 342 array = newArray; 343 setLength(newLength); 344 } 345 346 return returnValue; 347 } 348 349 @Override fastPush(final int arg)350 public double fastPush(final int arg) { 351 final int len = (int)length(); 352 if (len == array.length) { 353 array = Arrays.copyOf(array, nextSize(len)); 354 } 355 array[len] = arg; 356 return increaseLength(); 357 } 358 359 //length must not be zero 360 @Override fastPopInt()361 public int fastPopInt() { 362 if (length() == 0) { 363 throw new ClassCastException(); //relink 364 } 365 final int newLength = (int)decreaseLength(); 366 final int elem = array[newLength]; 367 array[newLength] = 0; 368 return elem; 369 } 370 371 @Override fastPopDouble()372 public double fastPopDouble() { 373 return fastPopInt(); 374 } 375 376 @Override fastPopObject()377 public Object fastPopObject() { 378 return fastPopInt(); 379 } 380 381 @Override fastConcat(final ContinuousArrayData otherData)382 public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { 383 final int otherLength = (int)otherData.length(); 384 final int thisLength = (int)length(); 385 assert otherLength > 0 && thisLength > 0; 386 387 final int[] otherArray = ((IntArrayData)otherData).array; 388 final int newLength = otherLength + thisLength; 389 final int[] newArray = new int[ArrayData.alignUp(newLength)]; 390 391 System.arraycopy(array, 0, newArray, 0, thisLength); 392 System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); 393 394 return new IntArrayData(newArray, newLength); 395 } 396 397 @Override toString()398 public String toString() { 399 assert length() <= array.length : length() + " > " + array.length; 400 return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length())); 401 } 402 } 403