IntArrayData.java revision 1179:2b9af466a49d
1234949Sbapt/* 2234949Sbapt * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3234949Sbapt * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4234949Sbapt * 5234949Sbapt * This code is free software; you can redistribute it and/or modify it 6234949Sbapt * under the terms of the GNU General Public License version 2 only, as 7234949Sbapt * published by the Free Software Foundation. Oracle designates this 8234949Sbapt * particular file as subject to the "Classpath" exception as provided 9234949Sbapt * by Oracle in the LICENSE file that accompanied this code. 10234949Sbapt * 11234949Sbapt * This code is distributed in the hope that it will be useful, but WITHOUT 12234949Sbapt * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13234949Sbapt * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14234949Sbapt * version 2 for more details (a copy is included in the LICENSE file that 15234949Sbapt * accompanied this code). 16234949Sbapt * 17234949Sbapt * You should have received a copy of the GNU General Public License version 18234949Sbapt * 2 along with this work; if not, write to the Free Software Foundation, 19234949Sbapt * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20234949Sbapt * 21234949Sbapt * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22234949Sbapt * or visit www.oracle.com if you need additional information or have any 23234949Sbapt * questions. 24234949Sbapt */ 25234949Sbapt 26234949Sbaptpackage jdk.nashorn.internal.runtime.arrays; 27234949Sbapt 28234949Sbaptimport static jdk.nashorn.internal.codegen.CompilerConstants.specialCall; 29234949Sbapt 30234949Sbaptimport java.lang.invoke.MethodHandle; 31234949Sbaptimport java.lang.invoke.MethodHandles; 32234949Sbaptimport java.util.Arrays; 33234949Sbaptimport jdk.nashorn.internal.runtime.JSType; 34234949Sbaptimport jdk.nashorn.internal.runtime.ScriptRuntime; 35234949Sbapt 36234949Sbapt/** 37234949Sbapt * Implementation of {@link ArrayData} as soon as an int has been 38234949Sbapt * written to the array. This is the default data for new arrays 39234949Sbapt */ 40234949Sbaptfinal class IntArrayData extends ContinuousArrayData implements IntElements { 41234949Sbapt /** 42234949Sbapt * The wrapped array 43234949Sbapt */ 44234949Sbapt private int[] array; 45234949Sbapt 46234949Sbapt IntArrayData() { 47234949Sbapt this(new int[ArrayData.CHUNK_SIZE], 0); 48234949Sbapt } 49234949Sbapt 50234949Sbapt IntArrayData(final int length) { 51234949Sbapt super(length); 52234949Sbapt this.array = new int[ArrayData.nextSize(length)]; 53234949Sbapt } 54234949Sbapt 55234949Sbapt /** 56234949Sbapt * Constructor 57234949Sbapt * @param array an int array 58234949Sbapt * @param length a length, not necessarily array.length 59234949Sbapt */ 60234949Sbapt IntArrayData(final int[] array, final int length) { 61234949Sbapt super(length); 62234949Sbapt assert array == null || array.length >= length; 63234949Sbapt this.array = array; 64234949Sbapt } 65234949Sbapt 66234949Sbapt @Override 67234949Sbapt public final Class<?> getElementType() { 68234949Sbapt return int.class; 69234949Sbapt } 70234949Sbapt 71234949Sbapt @Override 72234949Sbapt public final Class<?> getBoxedElementType() { 73234949Sbapt return Integer.class; 74234949Sbapt } 75234949Sbapt 76234949Sbapt @Override 77234949Sbapt public final int getElementWeight() { 78234949Sbapt return 1; 79234949Sbapt } 80234949Sbapt 81234949Sbapt @Override 82234949Sbapt public final ContinuousArrayData widest(final ContinuousArrayData otherData) { 83234949Sbapt return otherData; 84234949Sbapt } 85234949Sbapt 86234949Sbapt private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle(); 87234949Sbapt private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle(); 88234949Sbapt 89234949Sbapt @Override 90234949Sbapt public Object[] asObjectArray() { 91234949Sbapt return toObjectArray(true); 92234949Sbapt } 93234949Sbapt 94264803Sbapt @SuppressWarnings("unused") 95264803Sbapt private int getElem(final int index) { 96234949Sbapt if (has(index)) { 97234949Sbapt return array[index]; 98234949Sbapt } 99264803Sbapt throw new ClassCastException(); 100264803Sbapt } 101234949Sbapt 102234949Sbapt @SuppressWarnings("unused") 103234949Sbapt private void setElem(final int index, final int elem) { 104234949Sbapt if (hasRoomFor(index)) { 105234949Sbapt array[index] = elem; 106234949Sbapt return; 107234949Sbapt } 108234949Sbapt throw new ClassCastException(); 109234949Sbapt } 110234949Sbapt 111234949Sbapt @Override 112234949Sbapt public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { 113234949Sbapt return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint); 114234949Sbapt } 115234949Sbapt 116234949Sbapt @Override 117234949Sbapt public MethodHandle getElementSetter(final Class<?> elementType) { 118234949Sbapt return elementType == int.class ? getContinuousElementSetter(SET_ELEM, elementType) : null; 119234949Sbapt } 120234949Sbapt 121234949Sbapt @Override 122234949Sbapt public IntArrayData copy() { 123234949Sbapt return new IntArrayData(array.clone(), (int)length()); 124234949Sbapt } 125234949Sbapt 126234949Sbapt @Override 127234949Sbapt 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 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) { 186 return this; 187 } else if (type == Long.class) { 188 return convertToLong(); 189 } else if (type == Double.class) { 190 return convertToDouble(); 191 } else { 192 assert type == null || (!Number.class.isAssignableFrom(type) && !type.isPrimitive()); 193 return convertToObject(); 194 } 195 } 196 197 @Override 198 public void shiftLeft(final int by) { 199 System.arraycopy(array, by, array, 0, array.length - by); 200 } 201 202 @Override 203 public ArrayData shiftRight(final int by) { 204 final ArrayData newData = ensure(by + length() - 1); 205 if (newData != this) { 206 newData.shiftRight(by); 207 return newData; 208 } 209 System.arraycopy(array, 0, array, by, array.length - by); 210 211 return this; 212 } 213 214 @Override 215 public ArrayData ensure(final long safeIndex) { 216 if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { 217 return new SparseArrayData(this, safeIndex + 1); 218 } 219 final int alen = array.length; 220 if (safeIndex >= alen) { 221 final int newLength = ArrayData.nextSize((int)safeIndex); 222 array = Arrays.copyOf(array, newLength); 223 } 224 if (safeIndex >= length()) { 225 setLength(safeIndex + 1); 226 } 227 return this; 228 } 229 230 @Override 231 public ArrayData shrink(final long newLength) { 232 Arrays.fill(array, (int)newLength, array.length, 0); 233 return this; 234 } 235 236 @Override 237 public ArrayData set(final int index, final Object value, final boolean strict) { 238 if (JSType.isRepresentableAsInt(value)) { 239 return set(index, JSType.toInt32(value), strict); 240 } else if (value == ScriptRuntime.UNDEFINED) { 241 return new UndefinedArrayFilter(this).set(index, value, strict); 242 } 243 244 final ArrayData newData = convert(value == null ? Object.class : value.getClass()); 245 return newData.set(index, value, strict); 246 } 247 248 @Override 249 public ArrayData set(final int index, final int value, final boolean strict) { 250 array[index] = value; 251 setLength(Math.max(index + 1, length())); 252 253 return this; 254 } 255 256 @Override 257 public ArrayData set(final int index, final long value, final boolean strict) { 258 if (JSType.isRepresentableAsInt(value)) { 259 array[index] = JSType.toInt32(value); 260 setLength(Math.max(index + 1, length())); 261 return this; 262 } 263 264 return convert(Long.class).set(index, value, strict); 265 } 266 267 @Override 268 public ArrayData set(final int index, final double value, final boolean strict) { 269 if (JSType.isRepresentableAsInt(value)) { 270 array[index] = (int)(long)value; 271 setLength(Math.max(index + 1, length())); 272 return this; 273 } 274 275 return convert(Double.class).set(index, value, strict); 276 } 277 278 @Override 279 public int getInt(final int index) { 280 return array[index]; 281 } 282 283 @Override 284 public int getIntOptimistic(final int index, final int programPoint) { 285 return array[index]; 286 } 287 288 @Override 289 public long getLong(final int index) { 290 return array[index]; 291 } 292 293 @Override 294 public long getLongOptimistic(final int index, final int programPoint) { 295 return array[index]; 296 } 297 298 @Override 299 public double getDouble(final int index) { 300 return array[index]; 301 } 302 303 @Override 304 public double getDoubleOptimistic(final int index, final int programPoint) { 305 return array[index]; 306 } 307 308 @Override 309 public Object getObject(final int index) { 310 return array[index]; 311 } 312 313 @Override 314 public boolean has(final int index) { 315 return 0 <= index && index < length(); 316 } 317 318 @Override 319 public ArrayData delete(final int index) { 320 return new DeletedRangeArrayFilter(this, index, index); 321 } 322 323 @Override 324 public ArrayData delete(final long fromIndex, final long toIndex) { 325 return new DeletedRangeArrayFilter(this, fromIndex, toIndex); 326 } 327 328 @Override 329 public Object pop() { 330 final int len = (int)length(); 331 if (len == 0) { 332 return ScriptRuntime.UNDEFINED; 333 } 334 335 final int newLength = len - 1; 336 final int elem = array[newLength]; 337 array[newLength] = 0; 338 setLength(newLength); 339 340 return elem; 341 } 342 343 @Override 344 public ArrayData slice(final long from, final long to) { 345 return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length() : from))); 346 } 347 348 @Override 349 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { 350 final long oldLength = length(); 351 final long newLength = oldLength - removed + added; 352 if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { 353 throw new UnsupportedOperationException(); 354 } 355 final ArrayData returnValue = removed == 0 ? 356 EMPTY_ARRAY : 357 new IntArrayData( 358 Arrays.copyOfRange( 359 array, 360 start, 361 start + removed), 362 removed); 363 364 if (newLength != oldLength) { 365 final int[] newArray; 366 367 if (newLength > array.length) { 368 newArray = new int[ArrayData.nextSize((int)newLength)]; 369 System.arraycopy(array, 0, newArray, 0, start); 370 } else { 371 newArray = array; 372 } 373 374 System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); 375 array = newArray; 376 setLength(newLength); 377 } 378 379 return returnValue; 380 } 381 382 @Override 383 public long fastPush(final int arg) { 384 final int len = (int)length(); 385 if (len == array.length) { 386 array = Arrays.copyOf(array, nextSize(len)); 387 } 388 array[len] = arg; 389 return increaseLength(); 390 } 391 392 //length must not be zero 393 @Override 394 public int fastPopInt() { 395 if (length() == 0) { 396 throw new ClassCastException(); //relink 397 } 398 final int newLength = (int)decreaseLength(); 399 final int elem = array[newLength]; 400 array[newLength] = 0; 401 return elem; 402 } 403 404 @Override 405 public long fastPopLong() { 406 return fastPopInt(); 407 } 408 409 @Override 410 public double fastPopDouble() { 411 return fastPopInt(); 412 } 413 414 @Override 415 public Object fastPopObject() { 416 return fastPopInt(); 417 } 418 419 @Override 420 public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { 421 final int otherLength = (int)otherData.length(); 422 final int thisLength = (int)length(); 423 assert otherLength > 0 && thisLength > 0; 424 425 final int[] otherArray = ((IntArrayData)otherData).array; 426 final int newLength = otherLength + thisLength; 427 final int[] newArray = new int[ArrayData.alignUp(newLength)]; 428 429 System.arraycopy(array, 0, newArray, 0, thisLength); 430 System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); 431 432 return new IntArrayData(newArray, newLength); 433 } 434 435 @Override 436 public String toString() { 437 assert length() <= array.length : length() + " > " + array.length; 438 return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length())); 439 } 440} 441