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