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