IntArrayData.java revision 953:221a84ef44c0
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.codegen.types.Type; 34import jdk.nashorn.internal.runtime.JSType; 35import jdk.nashorn.internal.runtime.ScriptRuntime; 36 37/** 38 * Implementation of {@link ArrayData} as soon as an int has been 39 * written to the array. This is the default data for new arrays 40 */ 41final class IntArrayData extends ContinuousArrayData { 42 /** 43 * The wrapped array 44 */ 45 private int[] array; 46 47 IntArrayData() { 48 this(new int[ArrayData.CHUNK_SIZE], 0); 49 } 50 51 IntArrayData(final int length) { 52 super(length); 53 this.array = new int[ArrayData.nextSize(length)]; 54 } 55 56 /** 57 * Constructor 58 * @param array an int array 59 * @param length a length, not necessarily array.length 60 */ 61 IntArrayData(final int array[], final int length) { 62 super(length); 63 assert array.length >= length; 64 this.array = array; 65 } 66 67 private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle(); 68 private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle(); 69 70 @SuppressWarnings("unused") 71 private int getElem(final int index) { 72 if (has(index)) { 73 return array[index]; 74 } 75 throw new ClassCastException(); 76 } 77 78 @SuppressWarnings("unused") 79 private void setElem(final int index, final int elem) { 80 if (hasRoomFor(index)) { 81 array[index] = elem; 82 return; 83 } 84 throw new ClassCastException(); 85 } 86 87 @Override 88 public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { 89 return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint); 90 } 91 92 @Override 93 public MethodHandle getElementSetter(final Class<?> elementType) { 94 return elementType == int.class ? getContinuousElementSetter(SET_ELEM, elementType) : null; 95 } 96 97 @Override 98 public ArrayData copy() { 99 return new IntArrayData(array.clone(), (int) length()); 100 } 101 102 @Override 103 public Object[] asObjectArray() { 104 return toObjectArray(array, (int) length()); 105 } 106 107 @Override 108 public Object asArrayOfType(final Class<?> componentType) { 109 if (componentType == int.class) { 110 return array.length == length() ? array.clone() : Arrays.copyOf(array, (int) length()); 111 } 112 return super.asArrayOfType(componentType); 113 } 114 115 private static Object[] toObjectArray(final int[] array, final int length) { 116 assert length <= array.length : "length exceeds internal array size"; 117 final Object[] oarray = new Object[array.length]; 118 119 for (int index = 0; index < length; index++) { 120 oarray[index] = Integer.valueOf(array[index]); 121 } 122 123 return oarray; 124 } 125 126 private static double[] toDoubleArray(final int[] array, final int length) { 127 assert length <= array.length : "length exceeds internal array size"; 128 final double[] darray = new double[array.length]; 129 130 for (int index = 0; index < length; index++) { 131 darray[index] = array[index]; 132 } 133 134 return darray; 135 } 136 137 private static long[] toLongArray(final int[] array, final int length) { 138 assert length <= array.length : "length exceeds internal array size"; 139 final long[] larray = new long[array.length]; 140 141 for (int index = 0; index < length; index++) { 142 larray[index] = array[index]; 143 } 144 145 return larray; 146 } 147 148 @Override 149 public ArrayData convert(final Class<?> type) { 150 if (type == Integer.class) { 151 return this; 152 } 153 final int length = (int) length(); 154 if (type == Long.class) { 155 return new LongArrayData(IntArrayData.toLongArray(array, length), length); 156 } else if (type == Double.class) { 157 return new NumberArrayData(IntArrayData.toDoubleArray(array, length), length); 158 } else { 159 return new ObjectArrayData(IntArrayData.toObjectArray(array, length), length); 160 } 161 } 162 163 @Override 164 public void shiftLeft(final int by) { 165 System.arraycopy(array, by, array, 0, array.length - by); 166 } 167 168 @Override 169 public ArrayData shiftRight(final int by) { 170 final ArrayData newData = ensure(by + length() - 1); 171 if (newData != this) { 172 newData.shiftRight(by); 173 return newData; 174 } 175 System.arraycopy(array, 0, array, by, array.length - by); 176 177 return this; 178 } 179 180 @Override 181 public ArrayData ensure(final long safeIndex) { 182 if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { 183 return new SparseArrayData(this, safeIndex + 1); 184 } 185 final int alen = array.length; 186 if (safeIndex >= alen) { 187 final int newLength = ArrayData.nextSize((int)safeIndex); 188 array = Arrays.copyOf(array, newLength); 189 } 190 setLength(safeIndex + 1); 191 return this; 192 } 193 194 @Override 195 public ArrayData shrink(final long newLength) { 196 Arrays.fill(array, (int) newLength, array.length, 0); 197 198 return this; 199 } 200 201 @Override 202 public ArrayData set(final int index, final Object value, final boolean strict) { 203 if (JSType.isRepresentableAsInt(value)) { 204 return set(index, JSType.toInt32(value), strict); 205 } else if (value == ScriptRuntime.UNDEFINED) { 206 return new UndefinedArrayFilter(this).set(index, value, strict); 207 } 208 209 final ArrayData newData = convert(value == null ? Object.class : value.getClass()); 210 return newData.set(index, value, strict); 211 } 212 213 @Override 214 public ArrayData set(final int index, final int value, final boolean strict) { 215 array[index] = value; 216 setLength(Math.max(index + 1, length())); 217 218 return this; 219 } 220 221 @Override 222 public ArrayData set(final int index, final long value, final boolean strict) { 223 if (JSType.isRepresentableAsInt(value)) { 224 array[index] = JSType.toInt32(value); 225 setLength(Math.max(index + 1, length())); 226 return this; 227 } 228 229 return convert(Long.class).set(index, value, strict); 230 } 231 232 @Override 233 public ArrayData set(final int index, final double value, final boolean strict) { 234 if (JSType.isRepresentableAsInt(value)) { 235 array[index] = (int)(long)value; 236 setLength(Math.max(index + 1, length())); 237 return this; 238 } 239 240 return convert(Double.class).set(index, value, strict); 241 } 242 243 @Override 244 public Type getOptimisticType() { 245 return Type.INT; 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 long getLong(final int index) { 260 return array[index]; 261 } 262 263 @Override 264 public long getLongOptimistic(final int index, final int programPoint) { 265 return array[index]; 266 } 267 268 @Override 269 public double getDouble(final int index) { 270 return array[index]; 271 } 272 273 @Override 274 public double getDoubleOptimistic(final int index, final int programPoint) { 275 return array[index]; 276 } 277 278 @Override 279 public Object getObject(final int index) { 280 return array[index]; 281 } 282 283 @Override 284 public boolean has(final int index) { 285 return 0 <= index && index < length(); 286 } 287 288 @Override 289 public ArrayData delete(final int index) { 290 return new DeletedRangeArrayFilter(this, index, index); 291 } 292 293 @Override 294 public ArrayData delete(final long fromIndex, final long toIndex) { 295 return new DeletedRangeArrayFilter(this, fromIndex, toIndex); 296 } 297 298 @Override 299 public Object pop() { 300 if (length() == 0) { 301 return ScriptRuntime.UNDEFINED; 302 } 303 304 final int newLength = (int) length() - 1; 305 final int elem = array[newLength]; 306 array[newLength] = 0; 307 setLength(newLength); 308 309 return elem; 310 } 311 312 @Override 313 public ArrayData slice(final long from, final long to) { 314 final long start = from < 0 ? from + length() : from; 315 final long newLength = to - start; 316 317 return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); 318 } 319 320 @Override 321 public final ArrayData push(final boolean strict, final int item) { 322 final long length = length(); 323 final ArrayData newData = ensure(length); 324 if (newData == this) { 325 array[(int)length] = item; 326 return this; 327 } 328 return newData.set((int)length, item, strict); 329 } 330 331 @Override 332 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { 333 final long oldLength = length(); 334 final long newLength = oldLength - removed + added; 335 if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { 336 throw new UnsupportedOperationException(); 337 } 338 final ArrayData returnValue = removed == 0 ? 339 EMPTY_ARRAY : new IntArrayData(Arrays.copyOfRange(array, start, start + removed), removed); 340 341 if (newLength != oldLength) { 342 final int[] newArray; 343 344 if (newLength > array.length) { 345 newArray = new int[ArrayData.nextSize((int)newLength)]; 346 System.arraycopy(array, 0, newArray, 0, start); 347 } else { 348 newArray = array; 349 } 350 351 System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); 352 array = newArray; 353 setLength(newLength); 354 } 355 356 return returnValue; 357 } 358} 359