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