IntArrayData.java revision 1062:f9ed1ca59030
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 26package jdk.nashorn.internal.runtime.arrays; 27 28import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall; 29 30import java.lang.invoke.MethodHandle; 31import java.lang.invoke.MethodHandles; 32import java.util.Arrays; 33import jdk.nashorn.internal.runtime.JSType; 34import 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 */ 40final 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.length >= length; 63 this.array = array; 64 } 65 66 @Override 67 public Class<?> getElementType() { 68 return int.class; 69 } 70 71 private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle(); 72 private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle(); 73 74 @Override 75 public Object[] asObjectArray() { 76 return toObjectArray(true); 77 } 78 79 @SuppressWarnings("unused") 80 private int getElem(final int index) { 81 if (has(index)) { 82 return array[index]; 83 } 84 throw new ClassCastException(); 85 } 86 87 @SuppressWarnings("unused") 88 private void setElem(final int index, final int elem) { 89 if (hasRoomFor(index)) { 90 array[index] = elem; 91 return; 92 } 93 throw new ClassCastException(); 94 } 95 96 @Override 97 public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { 98 return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint); 99 } 100 101 @Override 102 public MethodHandle getElementSetter(final Class<?> elementType) { 103 return elementType == int.class ? getContinuousElementSetter(SET_ELEM, elementType) : null; 104 } 105 106 @Override 107 public ArrayData copy() { 108 return new IntArrayData(array.clone(), (int)length); 109 } 110 111 @Override 112 public Object asArrayOfType(final Class<?> componentType) { 113 if (componentType == int.class) { 114 return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length); 115 } 116 return super.asArrayOfType(componentType); 117 } 118 119 private Object[] toObjectArray(final boolean trim) { 120 assert length <= array.length : "length exceeds internal array size"; 121 final Object[] oarray = new Object[trim ? (int)length : array.length]; 122 123 for (int index = 0; index < length; index++) { 124 oarray[index] = Integer.valueOf(array[index]); 125 } 126 127 return oarray; 128 } 129 130 private double[] toDoubleArray() { 131 assert length <= array.length : "length exceeds internal array size"; 132 final double[] darray = new double[array.length]; 133 134 for (int index = 0; index < length; index++) { 135 darray[index] = array[index]; 136 } 137 138 return darray; 139 } 140 141 private long[] toLongArray() { 142 assert length <= array.length : "length exceeds internal array size"; 143 final long[] larray = new long[array.length]; 144 145 for (int index = 0; index < length; index++) { 146 larray[index] = array[index]; 147 } 148 149 return larray; 150 } 151 152 private LongArrayData convertToLong() { 153 return new LongArrayData(toLongArray(), (int)length); 154 } 155 156 private NumberArrayData convertToDouble() { 157 return new NumberArrayData(toDoubleArray(), (int)length); 158 } 159 160 private ObjectArrayData convertToObject() { 161 return new ObjectArrayData(toObjectArray(false), (int)length); 162 } 163 164 @Override 165 public ArrayData convert(final Class<?> type) { 166 if (type == Integer.class) { 167 return this; 168 } 169 if (type == Long.class) { 170 return convertToLong(); 171 } else if (type == Double.class) { 172 return convertToDouble(); 173 } else { 174 assert type == null || (!Number.class.isAssignableFrom(type) && !type.isPrimitive()); 175 return convertToObject(); 176 } 177 } 178 179 @Override 180 public void shiftLeft(final int by) { 181 System.arraycopy(array, by, array, 0, array.length - by); 182 } 183 184 @Override 185 public ArrayData shiftRight(final int by) { 186 final ArrayData newData = ensure(by + length - 1); 187 if (newData != this) { 188 newData.shiftRight(by); 189 return newData; 190 } 191 System.arraycopy(array, 0, array, by, array.length - by); 192 193 return this; 194 } 195 196 @Override 197 public ArrayData ensure(final long safeIndex) { 198 if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { 199 return new SparseArrayData(this, safeIndex + 1); 200 } 201 final int alen = array.length; 202 if (safeIndex >= alen) { 203 final int newLength = ArrayData.nextSize((int)safeIndex); 204 array = Arrays.copyOf(array, newLength); 205 } 206 setLength(safeIndex + 1); 207 return this; 208 } 209 210 @Override 211 public ArrayData shrink(final long newLength) { 212 Arrays.fill(array, (int) newLength, array.length, 0); 213 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 long value, final boolean strict) { 239 if (JSType.isRepresentableAsInt(value)) { 240 array[index] = JSType.toInt32(value); 241 setLength(Math.max(index + 1, length)); 242 return this; 243 } 244 245 return convert(Long.class).set(index, value, strict); 246 } 247 248 @Override 249 public ArrayData set(final int index, final double value, final boolean strict) { 250 if (JSType.isRepresentableAsInt(value)) { 251 array[index] = (int)(long)value; 252 setLength(Math.max(index + 1, length)); 253 return this; 254 } 255 256 return convert(Double.class).set(index, value, strict); 257 } 258 259 @Override 260 public int getInt(final int index) { 261 return array[index]; 262 } 263 264 @Override 265 public int getIntOptimistic(final int index, final int programPoint) { 266 return array[index]; 267 } 268 269 @Override 270 public long getLong(final int index) { 271 return array[index]; 272 } 273 274 @Override 275 public long getLongOptimistic(final int index, final int programPoint) { 276 return array[index]; 277 } 278 279 @Override 280 public double getDouble(final int index) { 281 return array[index]; 282 } 283 284 @Override 285 public double getDoubleOptimistic(final int index, final int programPoint) { 286 return array[index]; 287 } 288 289 @Override 290 public Object getObject(final int index) { 291 return array[index]; 292 } 293 294 @Override 295 public boolean has(final int index) { 296 return 0 <= index && index < length; 297 } 298 299 @Override 300 public ArrayData delete(final int index) { 301 return new DeletedRangeArrayFilter(this, index, index); 302 } 303 304 @Override 305 public ArrayData delete(final long fromIndex, final long toIndex) { 306 return new DeletedRangeArrayFilter(this, fromIndex, toIndex); 307 } 308 309 @Override 310 public Object pop() { 311 if (length == 0) { 312 return ScriptRuntime.UNDEFINED; 313 } 314 315 final int newLength = (int)length - 1; 316 final int elem = array[newLength]; 317 array[newLength] = 0; 318 setLength(newLength); 319 320 return elem; 321 } 322 323 @Override 324 public ArrayData slice(final long from, final long to) { 325 final long start = from < 0 ? from + length : from; 326 final long newLength = to - start; 327 328 return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); 329 } 330 331 @Override 332 public final ArrayData push(final boolean strict, final int item) { 333 final long len = length; 334 final ArrayData newData = ensure(len); 335 if (newData == this) { 336 array[(int)len] = item; 337 return this; 338 } 339 return newData.set((int)len, item, strict); 340 } 341 342 @Override 343 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { 344 final long oldLength = length; 345 final long newLength = oldLength - removed + added; 346 if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { 347 throw new UnsupportedOperationException(); 348 } 349 final ArrayData returnValue = removed == 0 ? 350 EMPTY_ARRAY : new IntArrayData(Arrays.copyOfRange(array, start, start + removed), removed); 351 352 if (newLength != oldLength) { 353 final int[] newArray; 354 355 if (newLength > array.length) { 356 newArray = new int[ArrayData.nextSize((int)newLength)]; 357 System.arraycopy(array, 0, newArray, 0, start); 358 } else { 359 newArray = array; 360 } 361 362 System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); 363 array = newArray; 364 setLength(newLength); 365 } 366 367 return returnValue; 368 } 369 370 @Override 371 public long fastPush(final int arg) { 372 final int len = (int)length; 373 if (len == array.length) { 374 array = Arrays.copyOf(array, nextSize(len)); 375 } 376 array[len] = arg; 377 return ++length; 378 } 379 380 //length must not be zero 381 @Override 382 public int fastPopInt() { 383 if (length == 0) { 384 throw new ClassCastException(); //relink 385 } 386 final int newLength = (int)--length; 387 final int elem = array[newLength]; 388 array[newLength] = 0; 389 return elem; 390 } 391 392 @Override 393 public long fastPopLong() { 394 return fastPopInt(); 395 } 396 397 @Override 398 public double fastPopDouble() { 399 return fastPopInt(); 400 } 401 402 @Override 403 public Object fastPopObject() { 404 return fastPopInt(); 405 } 406} 407