ObjectArrayData.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; 29 30import java.lang.invoke.MethodHandle; 31import java.lang.invoke.MethodHandles; 32import java.util.Arrays; 33import jdk.nashorn.internal.codegen.types.Type; 34import jdk.nashorn.internal.runtime.JSType; 35import jdk.nashorn.internal.runtime.ScriptRuntime; 36 37/** 38 * Implementation of {@link ArrayData} as soon as an Object has been 39 * written to the array 40 */ 41final class ObjectArrayData extends ContinuousArrayData { 42 43 /** 44 * The wrapped array 45 */ 46 private Object[] array; 47 48 /** 49 * Constructor 50 * @param array an int array 51 * @param length a length, not necessarily array.length 52 */ 53 ObjectArrayData(final Object array[], final int length) { 54 super(length); 55 assert array.length >= length; 56 this.array = array; 57 } 58 59 @Override 60 public ArrayData copy() { 61 return new ObjectArrayData(array.clone(), (int) length()); 62 } 63 64 @Override 65 public Object[] asObjectArray() { 66 return array.length == length() ? array.clone() : asObjectArrayCopy(); 67 } 68 69 private Object[] asObjectArrayCopy() { 70 final long l = length(); 71 assert l <= Integer.MAX_VALUE; 72 final Object[] copy = new Object[(int)l]; 73 System.arraycopy(array, 0, copy, 0, (int)l); 74 return copy; 75 } 76 77 @Override 78 public ArrayData convert(final Class<?> type) { 79 return this; 80 } 81 82 @Override 83 public void shiftLeft(final int by) { 84 System.arraycopy(array, by, array, 0, array.length - by); 85 } 86 87 @Override 88 public ArrayData shiftRight(final int by) { 89 final ArrayData newData = ensure(by + length() - 1); 90 if (newData != this) { 91 newData.shiftRight(by); 92 return newData; 93 } 94 System.arraycopy(array, 0, array, by, array.length - by); 95 return this; 96 } 97 98 @Override 99 public ArrayData ensure(final long safeIndex) { 100 if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { 101 return new SparseArrayData(this, safeIndex + 1); 102 } 103 final int alen = array.length; 104 if (safeIndex >= alen) { 105 final int newLength = ArrayData.nextSize((int)safeIndex); 106 array = Arrays.copyOf(array, newLength); //fill with undefined or OK? TODO 107 } 108 setLength(safeIndex + 1); 109 return this; 110 } 111 112 @Override 113 public ArrayData shrink(final long newLength) { 114 Arrays.fill(array, (int) newLength, array.length, ScriptRuntime.UNDEFINED); 115 return this; 116 } 117 118 @Override 119 public ArrayData set(final int index, final Object value, final boolean strict) { 120 array[index] = value; 121 setLength(Math.max(index + 1, length())); 122 return this; 123 } 124 125 @Override 126 public ArrayData set(final int index, final int value, final boolean strict) { 127 array[index] = value; 128 setLength(Math.max(index + 1, length())); 129 return this; 130 } 131 132 @Override 133 public ArrayData set(final int index, final long value, final boolean strict) { 134 array[index] = value; 135 setLength(Math.max(index + 1, length())); 136 return this; 137 } 138 139 @Override 140 public ArrayData set(final int index, final double value, final boolean strict) { 141 array[index] = value; 142 setLength(Math.max(index + 1, length())); 143 return this; 144 } 145 146 @Override 147 public ArrayData setEmpty(final int index) { 148 array[index] = ScriptRuntime.EMPTY; 149 return this; 150 } 151 152 @Override 153 public ArrayData setEmpty(final long lo, final long hi) { 154 Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi, Integer.MAX_VALUE), ScriptRuntime.EMPTY); 155 return this; 156 } 157 158 @Override 159 public Type getOptimisticType() { 160 return Type.OBJECT; 161 } 162 163 private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "getElem", Object.class, int.class).methodHandle(); 164 private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "setElem", void.class, int.class, Object.class).methodHandle(); 165 166 @SuppressWarnings("unused") 167 private Object getElem(final int index) { 168 if (has(index)) { 169 return array[index]; 170 } 171 throw new ClassCastException(); 172 } 173 174 @SuppressWarnings("unused") 175 private void setElem(final int index, final Object elem) { 176 if (hasRoomFor(index)) { 177 array[index] = elem; 178 return; 179 } 180 throw new ClassCastException(); 181 } 182 183 @Override 184 public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { 185 if (returnType.isPrimitive()) { 186 return null; 187 } 188 return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint); 189 } 190 191 @Override 192 public MethodHandle getElementSetter(final Class<?> elementType) { 193 return getContinuousElementSetter(SET_ELEM, Object.class); 194 } 195 196 197 @Override 198 public int getInt(final int index) { 199 return JSType.toInt32(array[index]); 200 } 201 202 @Override 203 public long getLong(final int index) { 204 return JSType.toLong(array[index]); 205 } 206 207 @Override 208 public double getDouble(final int index) { 209 return JSType.toNumber(array[index]); 210 } 211 212 @Override 213 public Object getObject(final int index) { 214 return array[index]; 215 } 216 217 @Override 218 public boolean has(final int index) { 219 return 0 <= index && index < length(); 220 } 221 222 @Override 223 public ArrayData delete(final int index) { 224 setEmpty(index); 225 return new DeletedRangeArrayFilter(this, index, index); 226 } 227 228 @Override 229 public ArrayData delete(final long fromIndex, final long toIndex) { 230 setEmpty(fromIndex, toIndex); 231 return new DeletedRangeArrayFilter(this, fromIndex, toIndex); 232 } 233 234 @Override 235 public Object pop() { 236 if (length() == 0) { 237 return ScriptRuntime.UNDEFINED; 238 } 239 240 final int newLength = (int) (length() - 1); 241 final Object elem = array[newLength]; 242 setEmpty(newLength); 243 setLength(newLength); 244 return elem; 245 } 246 247 @Override 248 public ArrayData slice(final long from, final long to) { 249 final long start = from < 0 ? from + length() : from; 250 final long newLength = to - start; 251 return new ObjectArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); 252 } 253 254 @Override 255 public ArrayData push(final boolean strict, final Object item) { 256 final long length = length(); 257 final ArrayData newData = ensure(length); 258 if (newData == this) { 259 array[(int)length] = item; 260 return this; 261 } 262 return newData.set((int)length, item, strict); 263 } 264 265 @Override 266 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { 267 final long oldLength = length(); 268 final long newLength = oldLength - removed + added; 269 if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { 270 throw new UnsupportedOperationException(); 271 } 272 final ArrayData returnValue = removed == 0 ? 273 EMPTY_ARRAY : new ObjectArrayData(Arrays.copyOfRange(array, start, start + removed), removed); 274 275 if (newLength != oldLength) { 276 final Object[] newArray; 277 278 if (newLength > array.length) { 279 newArray = new Object[ArrayData.nextSize((int)newLength)]; 280 System.arraycopy(array, 0, newArray, 0, start); 281 } else { 282 newArray = array; 283 } 284 285 System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); 286 array = newArray; 287 setLength(newLength); 288 } 289 290 return returnValue; 291 } 292} 293