ObjectArrayData.java revision 1101:be3f5ca1edbf
150397Sobrien/* 250397Sobrien * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3169689Skan * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 450397Sobrien * 5132718Skan * This code is free software; you can redistribute it and/or modify it 650397Sobrien * under the terms of the GNU General Public License version 2 only, as 7132718Skan * published by the Free Software Foundation. Oracle designates this 850397Sobrien * particular file as subject to the "Classpath" exception as provided 950397Sobrien * by Oracle in the LICENSE file that accompanied this code. 1050397Sobrien * 1150397Sobrien * This code is distributed in the hope that it will be useful, but WITHOUT 12132718Skan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1350397Sobrien * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1450397Sobrien * version 2 for more details (a copy is included in the LICENSE file that 1550397Sobrien * accompanied this code). 1650397Sobrien * 1750397Sobrien * You should have received a copy of the GNU General Public License version 18132718Skan * 2 along with this work; if not, write to the Free Software Foundation, 19169689Skan * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20169689Skan * 2150397Sobrien * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2290075Sobrien * or visit www.oracle.com if you need additional information or have any 2390075Sobrien * questions. 2490075Sobrien */ 2550397Sobrien 26117395Skanpackage jdk.nashorn.internal.runtime.arrays; 2750397Sobrien 2850397Sobrienimport static jdk.nashorn.internal.codegen.CompilerConstants.specialCall; 2950397Sobrienimport java.lang.invoke.MethodHandle; 3050397Sobrienimport java.lang.invoke.MethodHandles; 3150397Sobrienimport java.util.Arrays; 32169689Skanimport jdk.nashorn.internal.runtime.JSType; 3350397Sobrienimport jdk.nashorn.internal.runtime.ScriptRuntime; 3450397Sobrien 3550397Sobrien/** 3650397Sobrien * Implementation of {@link ArrayData} as soon as an Object has been 3750397Sobrien * written to the array 3850397Sobrien */ 39final class ObjectArrayData extends ContinuousArrayData implements AnyElements { 40 41 /** 42 * The wrapped array 43 */ 44 private Object[] array; 45 46 /** 47 * Constructor 48 * @param array an int array 49 * @param length a length, not necessarily array.length 50 */ 51 ObjectArrayData(final Object[] 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 Object.class; 60 } 61 62 @Override 63 public final Class<?> getBoxedElementType() { 64 return getElementType(); 65 } 66 67 @Override 68 public final int getElementWeight() { 69 return 4; 70 } 71 72 @Override 73 public final ContinuousArrayData widest(final ContinuousArrayData otherData) { 74 return otherData instanceof NumericElements ? this : otherData; 75 } 76 77 @Override 78 public ObjectArrayData copy() { 79 return new ObjectArrayData(array.clone(), (int)length()); 80 } 81 82 @Override 83 public Object[] asObjectArray() { 84 return array.length == length() ? array.clone() : asObjectArrayCopy(); 85 } 86 87 private Object[] asObjectArrayCopy() { 88 final long len = length(); 89 assert len <= Integer.MAX_VALUE; 90 final Object[] copy = new Object[(int)len]; 91 System.arraycopy(array, 0, copy, 0, (int)len); 92 return copy; 93 } 94 95 @Override 96 public ObjectArrayData convert(final Class<?> type) { 97 return this; 98 } 99 100 @Override 101 public void shiftLeft(final int by) { 102 System.arraycopy(array, by, array, 0, array.length - by); 103 } 104 105 @Override 106 public ArrayData shiftRight(final int by) { 107 final ArrayData newData = ensure(by + length() - 1); 108 if (newData != this) { 109 newData.shiftRight(by); 110 return newData; 111 } 112 System.arraycopy(array, 0, array, by, array.length - by); 113 return this; 114 } 115 116 @Override 117 public ArrayData ensure(final long safeIndex) { 118 if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { 119 return new SparseArrayData(this, safeIndex + 1); 120 } 121 final int alen = array.length; 122 if (safeIndex >= alen) { 123 final int newLength = ArrayData.nextSize((int)safeIndex); 124 array = Arrays.copyOf(array, newLength); //fill with undefined or OK? TODO 125 } 126 setLength(safeIndex + 1); 127 return this; 128 } 129 130 @Override 131 public ArrayData shrink(final long newLength) { 132 Arrays.fill(array, (int) newLength, array.length, ScriptRuntime.UNDEFINED); 133 return this; 134 } 135 136 @Override 137 public ArrayData set(final int index, final Object value, final boolean strict) { 138 array[index] = value; 139 setLength(Math.max(index + 1, length())); 140 return this; 141 } 142 143 @Override 144 public ArrayData set(final int index, final int value, final boolean strict) { 145 array[index] = value; 146 setLength(Math.max(index + 1, length())); 147 return this; 148 } 149 150 @Override 151 public ArrayData set(final int index, final long value, final boolean strict) { 152 array[index] = value; 153 setLength(Math.max(index + 1, length())); 154 return this; 155 } 156 157 @Override 158 public ArrayData set(final int index, final double value, final boolean strict) { 159 array[index] = value; 160 setLength(Math.max(index + 1, length())); 161 return this; 162 } 163 164 @Override 165 public ArrayData setEmpty(final int index) { 166 array[index] = ScriptRuntime.EMPTY; 167 return this; 168 } 169 170 @Override 171 public ArrayData setEmpty(final long lo, final long hi) { 172 // hi parameter is inclusive, but Arrays.fill toIndex parameter is exclusive 173 Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi + 1, Integer.MAX_VALUE), ScriptRuntime.EMPTY); 174 return this; 175 } 176 177 private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "getElem", Object.class, int.class).methodHandle(); 178 private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "setElem", void.class, int.class, Object.class).methodHandle(); 179 180 @SuppressWarnings("unused") 181 private Object getElem(final int index) { 182 if (has(index)) { 183 return array[index]; 184 } 185 throw new ClassCastException(); 186 } 187 188 @SuppressWarnings("unused") 189 private void setElem(final int index, final Object elem) { 190 if (hasRoomFor(index)) { 191 array[index] = elem; 192 return; 193 } 194 throw new ClassCastException(); 195 } 196 197 @Override 198 public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { 199 if (returnType.isPrimitive()) { 200 return null; 201 } 202 return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint); 203 } 204 205 @Override 206 public MethodHandle getElementSetter(final Class<?> elementType) { 207 return getContinuousElementSetter(SET_ELEM, Object.class); 208 } 209 210 211 @Override 212 public int getInt(final int index) { 213 return JSType.toInt32(array[index]); 214 } 215 216 @Override 217 public long getLong(final int index) { 218 return JSType.toLong(array[index]); 219 } 220 221 @Override 222 public double getDouble(final int index) { 223 return JSType.toNumber(array[index]); 224 } 225 226 @Override 227 public Object getObject(final int index) { 228 return array[index]; 229 } 230 231 @Override 232 public boolean has(final int index) { 233 return 0 <= index && index < length(); 234 } 235 236 @Override 237 public ArrayData delete(final int index) { 238 setEmpty(index); 239 return new DeletedRangeArrayFilter(this, index, index); 240 } 241 242 @Override 243 public ArrayData delete(final long fromIndex, final long toIndex) { 244 setEmpty(fromIndex, toIndex); 245 return new DeletedRangeArrayFilter(this, fromIndex, toIndex); 246 } 247 248 @Override 249 public long fastPush(final int arg) { 250 return fastPush((Object)arg); 251 } 252 253 @Override 254 public long fastPush(final long arg) { 255 return fastPush((Object)arg); 256 } 257 258 @Override 259 public long fastPush(final double arg) { 260 return fastPush((Object)arg); 261 } 262 263 @Override 264 public long fastPush(final Object arg) { 265 final int len = (int)length(); 266 if (len == array.length) { 267 array = Arrays.copyOf(array, nextSize(len)); 268 } 269 array[len] = arg; 270 return increaseLength(); 271 } 272 273 @Override 274 public Object fastPopObject() { 275 if (length() == 0) { 276 return ScriptRuntime.UNDEFINED; 277 } 278 final int newLength = (int)decreaseLength(); 279 final Object elem = array[newLength]; 280 array[newLength] = ScriptRuntime.EMPTY; 281 return elem; 282 } 283 284 @Override 285 public Object pop() { 286 if (length() == 0) { 287 return ScriptRuntime.UNDEFINED; 288 } 289 290 final int newLength = (int)length() - 1; 291 final Object elem = array[newLength]; 292 setEmpty(newLength); 293 setLength(newLength); 294 return elem; 295 } 296 297 @Override 298 public ArrayData slice(final long from, final long to) { 299 final long start = from < 0 ? from + length() : from; 300 final long newLength = to - start; 301 return new ObjectArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); 302 } 303 304 @Override 305 public ArrayData push(final boolean strict, final Object item) { 306 final long len = length(); 307 final ArrayData newData = ensure(len); 308 if (newData == this) { 309 array[(int)len] = item; 310 return this; 311 } 312 return newData.set((int)len, item, strict); 313 } 314 315 @Override 316 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { 317 final long oldLength = length(); 318 final long newLength = oldLength - removed + added; 319 if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { 320 throw new UnsupportedOperationException(); 321 } 322 final ArrayData returnValue = removed == 0 ? 323 EMPTY_ARRAY : new ObjectArrayData(Arrays.copyOfRange(array, start, start + removed), removed); 324 325 if (newLength != oldLength) { 326 final Object[] newArray; 327 328 if (newLength > array.length) { 329 newArray = new Object[ArrayData.nextSize((int)newLength)]; 330 System.arraycopy(array, 0, newArray, 0, start); 331 } else { 332 newArray = array; 333 } 334 335 System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); 336 array = newArray; 337 setLength(newLength); 338 } 339 340 return returnValue; 341 } 342 343 @Override 344 public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { 345 final int otherLength = (int)otherData.length(); 346 final int thisLength = (int)length(); 347 assert otherLength > 0 && thisLength > 0; 348 349 final Object[] otherArray = ((ObjectArrayData)otherData).array; 350 final int newLength = otherLength + thisLength; 351 final Object[] newArray = new Object[ArrayData.alignUp(newLength)]; 352 353 System.arraycopy(array, 0, newArray, 0, thisLength); 354 System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); 355 356 return new ObjectArrayData(newArray, newLength); 357 } 358 359 @Override 360 public String toString() { 361 assert length() <= array.length : length() + " > " + array.length; 362 return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length())); 363 } 364} 365