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 46 IntArrayData() { 47 this(new int[ArrayData.CHUNK_SIZE], 0); 48 } 49 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 */ 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 67 public final Class<?> getElementType() { 68 return int.class; 69 } 70 71 @Override 72 public final Class<?> getBoxedElementType() { 73 return Integer.class; 74 } 75 76 @Override 77 public final int getElementWeight() { 78 return 1; 79 } 80 81 @Override 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 90 public Object[] asObjectArray() { 91 return toObjectArray(true); 92 } 93 94 @SuppressWarnings("unused") 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") 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 112 public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { 113 return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint); 114 } 115 116 @Override 117 public MethodHandle getElementSetter(final Class<?> elementType) { 118 return elementType == int.class ? getContinuousElementSetter(SET_ELEM, elementType) : null; 119 } 120 121 @Override 122 public IntArrayData copy() { 123 return new IntArrayData(array.clone(), (int)length()); 124 } 125 126 @Override 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 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 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 159 private long[] toLongArray() { 160 assert length() <= array.length : "length exceeds internal array size"; 161 final int len = (int)length(); 162 final long[] larray = new long[array.length]; 163 164 for (int index = 0; index < len; index++) { 165 larray[index] = array[index]; 166 } 167 168 return larray; 169 } 170 171 private LongArrayData convertToLong() { 172 return new LongArrayData(toLongArray(), (int)length()); 173 } 174 175 private NumberArrayData convertToDouble() { 176 return new NumberArrayData(toDoubleArray(), (int)length()); 177 } 178 179 private ObjectArrayData convertToObject() { 180 return new ObjectArrayData(toObjectArray(false), (int)length()); 181 } 182 183 @Override 184 public ArrayData convert(final Class<?> type) { 185 if (type == Integer.class || type == Byte.class || type == Short.class) { 186 return this; 187 } else if (type == Long.class) { 188 return convertToLong(); 189 } else if (type == Double.class || type == Float.class) { 190 return convertToDouble(); 191 } else { 192 return convertToObject(); 193 } 194 } 195 196 @Override 197 public void shiftLeft(final int by) { 198 System.arraycopy(array, by, array, 0, array.length - by); 199 } 200 201 @Override 202 public ArrayData shiftRight(final int by) { 203 final ArrayData newData = ensure(by + length() - 1); 204 if (newData != this) { 205 newData.shiftRight(by); 206 return newData; 207 } 208 System.arraycopy(array, 0, array, by, array.length - by); 209 210 return this; 211 } 212 213 @Override 214 public ArrayData ensure(final long safeIndex) { 215 if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { 216 return new SparseArrayData(this, safeIndex + 1); 217 } 218 final int alen = array.length; 219 if (safeIndex >= alen) { 220 final int newLength = ArrayData.nextSize((int)safeIndex); 221 array = Arrays.copyOf(array, newLength); 222 } 223 if (safeIndex >= length()) { 224 setLength(safeIndex + 1); 225 } 226 return this; 227 } 228 229 @Override 230 public ArrayData shrink(final long newLength) { 231 Arrays.fill(array, (int)newLength, array.length, 0); 232 return this; 233 } 234 235 @Override 236 public ArrayData set(final int index, final Object value, final boolean strict) { 237 if (JSType.isRepresentableAsInt(value)) { 238 return set(index, JSType.toInt32(value), strict); 239 } else if (value == ScriptRuntime.UNDEFINED) { 240 return new UndefinedArrayFilter(this).set(index, value, strict); 241 } 242 243 final ArrayData newData = convert(value == null ? Object.class : value.getClass()); 244 return newData.set(index, value, strict); 245 } 246 247 @Override 248 public ArrayData set(final int index, final int value, final boolean strict) { 249 array[index] = value; 250 setLength(Math.max(index + 1, length())); 251 252 return this; 253 } 254 255 @Override 256 public ArrayData set(final int index, final long value, final boolean strict) { 257 if (JSType.isRepresentableAsInt(value)) { 258 array[index] = JSType.toInt32(value); 259 setLength(Math.max(index + 1, length())); 260 return this; 261 } 262 263 return convert(Long.class).set(index, value, strict); 264 } 265 266 @Override 267 public ArrayData set(final int index, final double value, final boolean strict) { 268 if (JSType.isRepresentableAsInt(value)) { 269 array[index] = (int)(long)value; 270 setLength(Math.max(index + 1, length())); 271 return this; 272 } 273 274 return convert(Double.class).set(index, value, strict); 275 } 276 277 @Override 278 public int getInt(final int index) { 279 return array[index]; 280 } 281 282 @Override 283 public int getIntOptimistic(final int index, final int programPoint) { 284 return array[index]; 285 } 286 287 @Override 288 public long getLong(final int index) { 289 return array[index]; 290 } 291 292 @Override 293 public long getLongOptimistic(final int index, final int programPoint) { 294 return array[index]; 295 } 296 297 @Override 298 public double getDouble(final int index) { 299 return array[index]; 300 } 301 302 @Override 303 public double getDoubleOptimistic(final int index, final int programPoint) { 304 return array[index]; 305 } 306 307 @Override 308 public Object getObject(final int index) { 309 return array[index]; 310 } 311 312 @Override 313 public boolean has(final int index) { 314 return 0 <= index && index < length(); 315 } 316 317 @Override 318 public ArrayData delete(final int index) { 319 return new DeletedRangeArrayFilter(this, index, index); 320 } 321 322 @Override 323 public ArrayData delete(final long fromIndex, final long toIndex) { 324 return new DeletedRangeArrayFilter(this, fromIndex, toIndex); 325 } 326 327 @Override 328 public Object pop() { 329 final int len = (int)length(); 330 if (len == 0) { 331 return ScriptRuntime.UNDEFINED; 332 } 333 334 final int newLength = len - 1; 335 final int elem = array[newLength]; 336 array[newLength] = 0; 337 setLength(newLength); 338 339 return elem; 340 } 341 342 @Override 343 public ArrayData slice(final long from, final long to) { 344 return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length() : from))); 345 } 346 347 @Override 348 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { 349 final long oldLength = length(); 350 final long newLength = oldLength - removed + added; 351 if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { 352 throw new UnsupportedOperationException(); 353 } 354 final ArrayData returnValue = removed == 0 ? 355 EMPTY_ARRAY : 356 new IntArrayData( 357 Arrays.copyOfRange( 358 array, 359 start, 360 start + removed), 361 removed); 362 363 if (newLength != oldLength) { 364 final int[] newArray; 365 366 if (newLength > array.length) { 367 newArray = new int[ArrayData.nextSize((int)newLength)]; 368 System.arraycopy(array, 0, newArray, 0, start); 369 } else { 370 newArray = array; 371 } 372 373 System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); 374 array = newArray; 375 setLength(newLength); 376 } 377 378 return returnValue; 379 } 380 381 @Override 382 public long fastPush(final int arg) { 383 final int len = (int)length(); 384 if (len == array.length) { 385 array = Arrays.copyOf(array, nextSize(len)); 386 } 387 array[len] = arg; 388 return increaseLength(); 389 } 390 391 //length must not be zero 392 @Override 393 public int fastPopInt() { 394 if (length() == 0) { 395 throw new ClassCastException(); //relink 396 } 397 final int newLength = (int)decreaseLength(); 398 final int elem = array[newLength]; 399 array[newLength] = 0; 400 return elem; 401 } 402 403 @Override 404 public long fastPopLong() { 405 return fastPopInt(); 406 } 407 408 @Override 409 public double fastPopDouble() { 410 return fastPopInt(); 411 } 412 413 @Override 414 public Object fastPopObject() { 415 return fastPopInt(); 416 } 417 418 @Override 419 public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { 420 final int otherLength = (int)otherData.length(); 421 final int thisLength = (int)length(); 422 assert otherLength > 0 && thisLength > 0; 423 424 final int[] otherArray = ((IntArrayData)otherData).array; 425 final int newLength = otherLength + thisLength; 426 final int[] newArray = new int[ArrayData.alignUp(newLength)]; 427 428 System.arraycopy(array, 0, newArray, 0, thisLength); 429 System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); 430 431 return new IntArrayData(newArray, newLength); 432 } 433 434 @Override 435 public String toString() { 436 assert length() <= array.length : length() + " > " + array.length; 437 return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length())); 438 } 439 }