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