NumberArrayData.java revision 1477:dd36e980905b
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; 35import jdk.internal.dynalink.linker.support.TypeUtilities; 36 37/** 38 * Implementation of {@link ArrayData} as soon as a double has been 39 * written to the array 40 */ 41final class NumberArrayData extends ContinuousArrayData implements NumericElements { 42 /** 43 * The wrapped array 44 */ 45 private double[] array; 46 47 /** 48 * Constructor 49 * @param array an int array 50 * @param length a length, not necessarily array.length 51 */ 52 NumberArrayData(final double[] 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 double.class; 61 } 62 63 @Override 64 public final Class<?> getBoxedElementType() { 65 return Double.class; 66 } 67 68 @Override 69 public final int getElementWeight() { 70 return 3; 71 } 72 73 @Override 74 public final ContinuousArrayData widest(final ContinuousArrayData otherData) { 75 return otherData instanceof IntOrLongElements ? this : otherData; 76 } 77 78 @Override 79 public NumberArrayData copy() { 80 return new NumberArrayData(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] = array[index]; 95 } 96 return oarray; 97 } 98 99 @Override 100 public Object asArrayOfType(final Class<?> componentType) { 101 if (componentType == double.class) { 102 final int len = (int)length(); 103 return array.length == len ? array.clone() : Arrays.copyOf(array, len); 104 } 105 return super.asArrayOfType(componentType); 106 } 107 108 private static boolean canWiden(final Class<?> type) { 109 return TypeUtilities.isWrapperType(type) && 110 type != Boolean.class && type != Character.class; 111 } 112 113 @Override 114 public ContinuousArrayData convert(final Class<?> type) { 115 if (! canWiden(type)) { 116 final int len = (int)length(); 117 return new ObjectArrayData(toObjectArray(false), len); 118 } 119 return this; 120 } 121 122 @Override 123 public void shiftLeft(final int by) { 124 System.arraycopy(array, by, array, 0, array.length - by); 125 } 126 127 @Override 128 public ArrayData shiftRight(final int by) { 129 final ArrayData newData = ensure(by + length() - 1); 130 if (newData != this) { 131 newData.shiftRight(by); 132 return newData; 133 } 134 System.arraycopy(array, 0, array, by, array.length - by); 135 return this; 136 } 137 138 @Override 139 public ArrayData ensure(final long safeIndex) { 140 if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { 141 return new SparseArrayData(this, safeIndex + 1); 142 } 143 final int alen = array.length; 144 if (safeIndex >= alen) { 145 final int newLength = ArrayData.nextSize((int)safeIndex); 146 array = Arrays.copyOf(array, newLength); //todo fill with nan or never accessed? 147 } 148 if (safeIndex >= length()) { 149 setLength(safeIndex + 1); 150 } 151 return this; 152 153 } 154 155 @Override 156 public ArrayData shrink(final long newLength) { 157 Arrays.fill(array, (int)newLength, array.length, 0.0); 158 return this; 159 } 160 161 @Override 162 public ArrayData set(final int index, final Object value, final boolean strict) { 163 if (value instanceof Double || (value != null && canWiden(value.getClass()))) { 164 return set(index, ((Number)value).doubleValue(), strict); 165 } else if (value == UNDEFINED) { 166 return new UndefinedArrayFilter(this).set(index, value, strict); 167 } 168 169 final ArrayData newData = convert(value == null ? Object.class : value.getClass()); 170 return newData.set(index, value, strict); 171 } 172 173 @Override 174 public ArrayData set(final int index, final int value, final boolean strict) { 175 array[index] = value; 176 setLength(Math.max(index + 1, length())); 177 return this; 178 } 179 180 @Override 181 public ArrayData set(final int index, final long value, final boolean strict) { 182 array[index] = value; 183 setLength(Math.max(index + 1, length())); 184 return this; 185 } 186 187 @Override 188 public ArrayData set(final int index, final double value, final boolean strict) { 189 array[index] = value; 190 setLength(Math.max(index + 1, length())); 191 return this; 192 } 193 194 private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), NumberArrayData.class, "getElem", double.class, int.class).methodHandle(); 195 private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), NumberArrayData.class, "setElem", void.class, int.class, double.class).methodHandle(); 196 197 @SuppressWarnings("unused") 198 private double getElem(final int index) { 199 if (has(index)) { 200 return array[index]; 201 } 202 throw new ClassCastException(); 203 } 204 205 @SuppressWarnings("unused") 206 private void setElem(final int index, final double elem) { 207 if (hasRoomFor(index)) { 208 array[index] = elem; 209 return; 210 } 211 throw new ClassCastException(); 212 } 213 214 @Override 215 public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { 216 if (returnType == int.class || returnType == long.class) { 217 return null; 218 } 219 return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint); 220 } 221 222 @Override 223 public MethodHandle getElementSetter(final Class<?> elementType) { 224 return elementType.isPrimitive() ? getContinuousElementSetter(MH.asType(SET_ELEM, SET_ELEM.type().changeParameterType(2, elementType)), elementType) : null; 225 } 226 227 @Override 228 public int getInt(final int index) { 229 return (int)array[index]; 230 } 231 232 @Override 233 public long getLong(final int index) { 234 return (long)array[index]; 235 } 236 237 @Override 238 public double getDouble(final int index) { 239 return array[index]; 240 } 241 242 @Override 243 public double getDoubleOptimistic(final int index, final int programPoint) { 244 return array[index]; 245 } 246 247 @Override 248 public Object getObject(final int index) { 249 return array[index]; 250 } 251 252 @Override 253 public boolean has(final int index) { 254 return 0 <= index && index < length(); 255 } 256 257 @Override 258 public ArrayData delete(final int index) { 259 return new DeletedRangeArrayFilter(this, index, index); 260 } 261 262 @Override 263 public ArrayData delete(final long fromIndex, final long toIndex) { 264 return new DeletedRangeArrayFilter(this, fromIndex, toIndex); 265 } 266 267 @Override 268 public Object pop() { 269 final int len = (int)length(); 270 if (len == 0) { 271 return UNDEFINED; 272 } 273 274 final int newLength = len - 1; 275 final double elem = array[newLength]; 276 array[newLength] = 0; 277 setLength(newLength); 278 return elem; 279 } 280 281 @Override 282 public ArrayData slice(final long from, final long to) { 283 final long start = from < 0 ? from + length() : from; 284 final long newLength = to - start; 285 return new NumberArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); 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 increaseLength(); 335 } 336 337 @Override 338 public double fastPopDouble() { 339 if (length() == 0) { 340 throw new ClassCastException(); 341 } 342 final int newLength = (int)decreaseLength(); 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