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] = Integer.valueOf(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 NumberArrayData convertToDouble() { 160 return new NumberArrayData(toDoubleArray(), (int)length()); 161 } 162 163 private ObjectArrayData convertToObject() { 164 return new ObjectArrayData(toObjectArray(false), (int)length()); 165 } 166 167 @Override 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 179 public void shiftLeft(final int by) { 180 System.arraycopy(array, by, array, 0, array.length - by); 181 } 182 183 @Override 184 public ArrayData shiftRight(final int by) { 185 final ArrayData newData = ensure(by + length() - 1); 186 if (newData != this) { 187 newData.shiftRight(by); 188 return newData; 189 } 190 System.arraycopy(array, 0, array, by, array.length - by); 191 192 return this; 193 } 194 195 @Override 196 public ArrayData ensure(final long safeIndex) { 197 if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { 198 return new SparseArrayData(this, safeIndex + 1); 199 } 200 final int alen = array.length; 201 if (safeIndex >= alen) { 202 final int newLength = ArrayData.nextSize((int)safeIndex); 203 array = Arrays.copyOf(array, newLength); 204 } 205 if (safeIndex >= length()) { 206 setLength(safeIndex + 1); 207 } 208 return this; 209 } 210 211 @Override 212 public ArrayData shrink(final long newLength) { 213 Arrays.fill(array, (int)newLength, array.length, 0); 214 return this; 215 } 216 217 @Override 218 public ArrayData set(final int index, final Object value, final boolean strict) { 219 if (JSType.isRepresentableAsInt(value)) { 220 return set(index, JSType.toInt32(value), strict); 221 } else if (value == ScriptRuntime.UNDEFINED) { 222 return new UndefinedArrayFilter(this).set(index, value, strict); 223 } 224 225 final ArrayData newData = convert(value == null ? Object.class : value.getClass()); 226 return newData.set(index, value, strict); 227 } 228 229 @Override 230 public ArrayData set(final int index, final int value, final boolean strict) { 231 array[index] = value; 232 setLength(Math.max(index + 1, length())); 233 234 return this; 235 } 236 237 @Override 238 public ArrayData set(final int index, final double value, final boolean strict) { 239 if (JSType.isRepresentableAsInt(value)) { 240 array[index] = (int)(long)value; 241 setLength(Math.max(index + 1, length())); 242 return this; 243 } 244 245 return convert(Double.class).set(index, value, strict); 246 } 247 248 @Override 249 public int getInt(final int index) { 250 return array[index]; 251 } 252 253 @Override 254 public int getIntOptimistic(final int index, final int programPoint) { 255 return array[index]; 256 } 257 258 @Override 259 public double getDouble(final int index) { 260 return array[index]; 261 } 262 263 @Override 264 public double getDoubleOptimistic(final int index, final int programPoint) { 265 return array[index]; 266 } 267 268 @Override 269 public Object getObject(final int index) { 270 return array[index]; 271 } 272 273 @Override 274 public boolean has(final int index) { 275 return 0 <= index && index < length(); 276 } 277 278 @Override 279 public ArrayData delete(final int index) { 280 return new DeletedRangeArrayFilter(this, index, index); 281 } 282 283 @Override 284 public ArrayData delete(final long fromIndex, final long toIndex) { 285 return new DeletedRangeArrayFilter(this, fromIndex, toIndex); 286 } 287 288 @Override 289 public Object pop() { 290 final int len = (int)length(); 291 if (len == 0) { 292 return ScriptRuntime.UNDEFINED; 293 } 294 295 final int newLength = len - 1; 296 final int elem = array[newLength]; 297 array[newLength] = 0; 298 setLength(newLength); 299 300 return elem; 301 } 302 303 @Override 304 public ArrayData slice(final long from, final long to) { 305 return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length() : from))); 306 } 307 308 @Override 309 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { 310 final long oldLength = length(); 311 final long newLength = oldLength - removed + added; 312 if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { 313 throw new UnsupportedOperationException(); 314 } 315 final ArrayData returnValue = removed == 0 ? 316 EMPTY_ARRAY : 317 new IntArrayData( 318 Arrays.copyOfRange( 319 array, 320 start, 321 start + removed), 322 removed); 323 324 if (newLength != oldLength) { 325 final int[] newArray; 326 327 if (newLength > array.length) { 328 newArray = new int[ArrayData.nextSize((int)newLength)]; 329 System.arraycopy(array, 0, newArray, 0, start); 330 } else { 331 newArray = array; 332 } 333 334 System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); 335 array = newArray; 336 setLength(newLength); 337 } 338 339 return returnValue; 340 } 341 342 @Override 343 public double fastPush(final int arg) { 344 final int len = (int)length(); 345 if (len == array.length) { 346 array = Arrays.copyOf(array, nextSize(len)); 347 } 348 array[len] = arg; 349 return increaseLength(); 350 } 351 352 //length must not be zero 353 @Override 354 public int fastPopInt() { 355 if (length() == 0) { 356 throw new ClassCastException(); //relink 357 } 358 final int newLength = (int)decreaseLength(); 359 final int elem = array[newLength]; 360 array[newLength] = 0; 361 return elem; 362 } 363 364 @Override 365 public double fastPopDouble() { 366 return fastPopInt(); 367 } 368 369 @Override 370 public Object fastPopObject() { 371 return fastPopInt(); 372 } 373 374 @Override 375 public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { 376 final int otherLength = (int)otherData.length(); 377 final int thisLength = (int)length(); 378 assert otherLength > 0 && thisLength > 0; 379 380 final int[] otherArray = ((IntArrayData)otherData).array; 381 final int newLength = otherLength + thisLength; 382 final int[] newArray = new int[ArrayData.alignUp(newLength)]; 383 384 System.arraycopy(array, 0, newArray, 0, thisLength); 385 System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); 386 387 return new IntArrayData(newArray, newLength); 388 } 389 390 @Override 391 public String toString() { 392 assert length() <= array.length : length() + " > " + array.length; 393 return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length())); 394 } 395 }