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