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 import static jdk.nashorn.internal.lookup.Lookup.MH; 30 31 import java.lang.invoke.MethodHandle; 32 import java.lang.invoke.MethodHandles; 33 import java.util.Arrays; 34 import jdk.nashorn.internal.runtime.JSType; 35 import jdk.nashorn.internal.runtime.ScriptRuntime; 36 37 /** 38 * Implementation of {@link ArrayData} as soon as a long has been 39 * written to the array 40 */ 41 final class LongArrayData extends ContinuousArrayData implements IntOrLongElements { 42 /** 43 * The wrapped array 44 */ 45 private long[] array; 46 47 /** 48 * Constructor 49 * @param array an int array 50 * @param length a length, not necessarily array.length 51 */ 52 LongArrayData(final long array[], final int length) { 53 super(length); 54 assert array.length >= length; 55 this.array = array; 56 } 57 58 @Override 59 public final Class<?> getElementType() { 60 return long.class; 61 } 62 63 @Override 64 public final Class<?> getBoxedElementType() { 65 return Long.class; 66 } 67 68 @Override 69 public final ContinuousArrayData widest(final ContinuousArrayData otherData) { 70 return otherData instanceof IntElements ? this : otherData; 71 } 72 73 @Override 74 public final int getElementWeight() { 75 return 2; 76 } 77 78 @Override 79 public LongArrayData copy() { 80 return new LongArrayData(array.clone(), (int)length()); 81 } 82 83 @Override 84 public Object[] asObjectArray() { 85 return toObjectArray(true); 86 } 87 88 private Object[] toObjectArray(final boolean trim) { 89 assert length() <= array.length : "length exceeds internal array size"; 90 final int len = (int)length(); 91 final Object[] oarray = new Object[trim ? len : array.length]; 92 93 for (int index = 0; index < len; index++) { 94 oarray[index] = Long.valueOf(array[index]); 95 } 96 97 return oarray; 98 } 99 100 @Override 101 public Object asArrayOfType(final Class<?> componentType) { 102 if (componentType == long.class) { 103 final int len = (int)length(); 104 return array.length == len ? array.clone() : Arrays.copyOf(array, len); 105 } 106 return super.asArrayOfType(componentType); 107 } 108 109 private double[] toDoubleArray() { 110 assert length() <= array.length : "length exceeds internal array size"; 111 final int len = (int)length(); 112 final double[] darray = new double[array.length]; 113 114 for (int index = 0; index < len; index++) { 115 darray[index] = array[index]; 116 } 117 118 return darray; 119 } 120 121 @Override 122 public ContinuousArrayData convert(final Class<?> type) { 123 if (type == Integer.class || type == Long.class || type == Byte.class || type == Short.class) { 124 return this; 125 } 126 final int len = (int)length(); 127 if (type == Double.class || type == Float.class) { 128 return new NumberArrayData(toDoubleArray(), len); 129 } 130 return new ObjectArrayData(toObjectArray(false), len); 131 } 132 133 @Override 134 public void shiftLeft(final int by) { 135 System.arraycopy(array, by, array, 0, array.length - by); 136 } 137 138 @Override 139 public ArrayData shiftRight(final int by) { 140 final ArrayData newData = ensure(by + length() - 1); 141 if (newData != this) { 142 newData.shiftRight(by); 143 return newData; 144 } 145 System.arraycopy(array, 0, array, by, array.length - by); 146 147 return this; 148 } 149 150 @Override 151 public ArrayData ensure(final long safeIndex) { 152 if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { 153 return new SparseArrayData(this, safeIndex + 1); 154 } 155 final int alen = array.length; 156 if (safeIndex >= alen) { 157 final int newLength = ArrayData.nextSize((int)safeIndex); 158 array = Arrays.copyOf(array, newLength); 159 } 160 if (safeIndex >= length()) { 161 setLength(safeIndex + 1); 162 } 163 return this; 164 } 165 166 @Override 167 public ArrayData shrink(final long newLength) { 168 Arrays.fill(array, (int)newLength, array.length, 0L); 169 return this; 170 } 171 172 @Override 173 public ArrayData set(final int index, final Object value, final boolean strict) { 174 if (value instanceof Long || value instanceof Integer || 175 value instanceof Byte || value instanceof Short) { 176 return set(index, ((Number)value).longValue(), strict); 177 } else if (value == ScriptRuntime.UNDEFINED) { 178 return new UndefinedArrayFilter(this).set(index, value, strict); 179 } 180 181 final ArrayData newData = convert(value == null ? Object.class : value.getClass()); 182 return newData.set(index, value, strict); 183 } 184 185 @Override 186 public ArrayData set(final int index, final int value, final boolean strict) { 187 array[index] = value; 188 setLength(Math.max(index + 1, length())); 189 return this; 190 } 191 192 @Override 193 public ArrayData set(final int index, final long value, final boolean strict) { 194 array[index] = value; 195 setLength(Math.max(index + 1, length())); 196 return this; 197 } 198 199 @Override 200 public ArrayData set(final int index, final double value, final boolean strict) { 201 if (JSType.isRepresentableAsLong(value)) { 202 array[index] = (long)value; 203 setLength(Math.max(index + 1, length())); 204 return this; 205 } 206 return convert(Double.class).set(index, value, strict); 207 } 208 209 private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, "getElem", long.class, int.class).methodHandle(); 210 private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, "setElem", void.class, int.class, long.class).methodHandle(); 211 212 @SuppressWarnings("unused") 213 private long getElem(final int index) { 214 if (has(index)) { 215 return array[index]; 216 } 217 throw new ClassCastException(); 218 } 219 220 @SuppressWarnings("unused") 221 private void setElem(final int index, final long elem) { 222 if (hasRoomFor(index)) { 223 array[index] = elem; 224 return; 225 } 226 throw new ClassCastException(); 227 } 228 229 @Override 230 public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { 231 if (returnType == int.class) { 232 return null; 233 } 234 return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint); 235 } 236 237 @Override 238 public MethodHandle getElementSetter(final Class<?> elementType) { 239 return elementType == int.class || elementType == long.class ? getContinuousElementSetter(MH.asType(SET_ELEM, SET_ELEM.type().changeParameterType(2, elementType)), elementType) : null; 240 } 241 242 @Override 243 public int getInt(final int index) { 244 return (int)array[index]; 245 } 246 247 @Override 248 public long getLong(final int index) { 249 return array[index]; 250 } 251 252 @Override 253 public long getLongOptimistic(final int index, final int programPoint) { 254 return array[index]; 255 } 256 257 @Override 258 public double getDouble(final int index) { 259 return array[index]; 260 } 261 262 @Override 263 public double getDoubleOptimistic(final int index, final int programPoint) { 264 return array[index]; 265 } 266 267 @Override 268 public Object getObject(final int index) { 269 return array[index]; 270 } 271 272 @Override 273 public boolean has(final int index) { 274 return 0 <= index && index < length(); 275 } 276 277 @Override 278 public ArrayData delete(final int index) { 279 return new DeletedRangeArrayFilter(this, index, index); 280 } 281 282 @Override 283 public ArrayData delete(final long fromIndex, final long toIndex) { 284 return new DeletedRangeArrayFilter(this, fromIndex, toIndex); 285 } 286 287 @Override 288 public Object pop() { 289 final int len = (int)length(); 290 if (len == 0) { 291 return ScriptRuntime.UNDEFINED; 292 } 293 294 final int newLength = len - 1; 295 final long elem = array[newLength]; 296 array[newLength] = 0; 297 setLength(newLength); 298 299 return elem; 300 } 301 302 @Override 303 public ArrayData slice(final long from, final long to) { 304 final long start = from < 0 ? from + length() : from; 305 final long newLength = to - start; 306 return new LongArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); 307 } 308 309 @Override 310 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { 311 final long oldLength = length(); 312 final long newLength = oldLength - removed + added; 313 if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { 314 throw new UnsupportedOperationException(); 315 } 316 final ArrayData returnValue = removed == 0 ? 317 EMPTY_ARRAY : new LongArrayData(Arrays.copyOfRange(array, start, start + removed), removed); 318 319 if (newLength != oldLength) { 320 final long[] newArray; 321 322 if (newLength > array.length) { 323 newArray = new long[ArrayData.nextSize((int)newLength)]; 324 System.arraycopy(array, 0, newArray, 0, start); 325 } else { 326 newArray = array; 327 } 328 329 System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); 330 array = newArray; 331 setLength(newLength); 332 } 333 334 return returnValue; 335 } 336 337 @Override 338 public long fastPush(final int arg) { 339 return fastPush((long)arg); 340 } 341 342 @Override 343 public long fastPush(final long 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 @Override 353 public long fastPopLong() { 354 if (length() == 0) { 355 throw new ClassCastException(); //undefined result 356 } 357 final int newLength = (int)decreaseLength(); 358 final long elem = array[newLength]; 359 array[newLength] = 0; 360 return elem; 361 } 362 363 @Override 364 public double fastPopDouble() { 365 return fastPopLong(); 366 } 367 368 @Override 369 public Object fastPopObject() { 370 return fastPopLong(); 371 } 372 373 @Override 374 public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { 375 final int otherLength = (int)otherData.length(); 376 final int thisLength = (int)length(); 377 assert otherLength > 0 && thisLength > 0; 378 379 final long[] otherArray = ((LongArrayData)otherData).array; 380 final int newLength = otherLength + thisLength; 381 final long[] newArray = new long[ArrayData.alignUp(newLength)]; 382 383 System.arraycopy(array, 0, newArray, 0, thisLength); 384 System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); 385 386 return new LongArrayData(newArray, newLength); 387 } 388 389 @Override 390 public String toString() { 391 assert length() <= array.length : length() + " > " + array.length; 392 393 final StringBuilder sb = new StringBuilder(getClass().getSimpleName()). 394 append(": ["); 395 final int len = (int)length(); 396 for (int i = 0; i < len; i++) { 397 sb.append(array[i]).append('L'); //make sure L suffix is on elements, to discriminate this from IntArrayData.toString() 398 if (i + 1 < len) { 399 sb.append(", "); 400 } 401 } 402 sb.append(']'); 403 404 return sb.toString(); 405 } 406 }