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
26 package jdk.nashorn.internal.runtime.arrays;
27
28 import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
29 import java.lang.invoke.MethodHandle;
30 import java.lang.invoke.MethodHandles;
31 import java.util.Arrays;
32 import jdk.nashorn.internal.runtime.JSType;
33 import jdk.nashorn.internal.runtime.ScriptRuntime;
34
35 /**
36 * Implementation of {@link ArrayData} as soon as an Object has been
37 * written to the array
38 */
39 final 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 if (safeIndex >= length()) {
127 setLength(safeIndex + 1);
128 }
129 return this;
130 }
131
132 @Override
133 public ArrayData shrink(final long newLength) {
134 Arrays.fill(array, (int) newLength, array.length, ScriptRuntime.UNDEFINED);
135 return this;
136 }
137
138 @Override
139 public ArrayData set(final int index, final Object value, final boolean strict) {
140 array[index] = value;
141 setLength(Math.max(index + 1, length()));
142 return this;
143 }
144
145 @Override
146 public ArrayData set(final int index, final int value, final boolean strict) {
147 array[index] = value;
148 setLength(Math.max(index + 1, length()));
149 return this;
150 }
151
152 @Override
153 public ArrayData set(final int index, final double value, final boolean strict) {
154 array[index] = value;
155 setLength(Math.max(index + 1, length()));
156 return this;
157 }
158
159 @Override
160 public ArrayData setEmpty(final int index) {
161 array[index] = ScriptRuntime.EMPTY;
162 return this;
163 }
164
165 @Override
166 public ArrayData setEmpty(final long lo, final long hi) {
167 // hi parameter is inclusive, but Arrays.fill toIndex parameter is exclusive
168 Arrays.fill(array, (int)Math.max(lo, 0L), (int)Math.min(hi + 1, Integer.MAX_VALUE), ScriptRuntime.EMPTY);
169 return this;
170 }
171
172 private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "getElem", Object.class, int.class).methodHandle();
173 private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, "setElem", void.class, int.class, Object.class).methodHandle();
174
175 @SuppressWarnings("unused")
176 private Object getElem(final int index) {
177 if (has(index)) {
178 return array[index];
179 }
180 throw new ClassCastException();
181 }
182
183 @SuppressWarnings("unused")
184 private void setElem(final int index, final Object elem) {
185 if (hasRoomFor(index)) {
186 array[index] = elem;
187 return;
188 }
189 throw new ClassCastException();
190 }
191
192 @Override
193 public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
194 if (returnType.isPrimitive()) {
195 return null;
196 }
197 return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint);
198 }
199
200 @Override
201 public MethodHandle getElementSetter(final Class<?> elementType) {
202 return getContinuousElementSetter(SET_ELEM, Object.class);
203 }
204
205
206 @Override
207 public int getInt(final int index) {
208 return JSType.toInt32(array[index]);
209 }
210
211 @Override
212 public double getDouble(final int index) {
213 return JSType.toNumber(array[index]);
214 }
215
216 @Override
217 public Object getObject(final int index) {
218 return array[index];
219 }
220
221 @Override
222 public boolean has(final int index) {
223 return 0 <= index && index < length();
224 }
225
226 @Override
227 public ArrayData delete(final int index) {
228 setEmpty(index);
229 return new DeletedRangeArrayFilter(this, index, index);
230 }
231
232 @Override
233 public ArrayData delete(final long fromIndex, final long toIndex) {
234 setEmpty(fromIndex, toIndex);
235 return new DeletedRangeArrayFilter(this, fromIndex, toIndex);
236 }
237
238 @Override
239 public double fastPush(final int arg) {
240 return fastPush((Object)arg);
241 }
242
243 @Override
244 public double fastPush(final long arg) {
245 return fastPush((Object)arg);
246 }
247
248 @Override
249 public double fastPush(final double arg) {
250 return fastPush((Object)arg);
251 }
252
253 @Override
254 public double fastPush(final Object arg) {
255 final int len = (int)length();
256 if (len == array.length) {
257 array = Arrays.copyOf(array, nextSize(len));
258 }
259 array[len] = arg;
260 return increaseLength();
261 }
262
263 @Override
264 public Object fastPopObject() {
265 if (length() == 0) {
266 return ScriptRuntime.UNDEFINED;
267 }
268 final int newLength = (int)decreaseLength();
269 final Object elem = array[newLength];
270 array[newLength] = ScriptRuntime.EMPTY;
271 return elem;
272 }
273
274 @Override
275 public Object pop() {
276 if (length() == 0) {
277 return ScriptRuntime.UNDEFINED;
278 }
279
280 final int newLength = (int)length() - 1;
281 final Object elem = array[newLength];
282 setEmpty(newLength);
283 setLength(newLength);
284 return elem;
285 }
286
287 @Override
288 public ArrayData slice(final long from, final long to) {
289 final long start = from < 0 ? from + length() : from;
290 final long newLength = to - start;
291 return new ObjectArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
292 }
293
294 @Override
295 public ArrayData push(final boolean strict, final Object item) {
296 final long len = length();
297 final ArrayData newData = ensure(len);
298 if (newData == this) {
299 array[(int)len] = item;
300 return this;
301 }
302 return newData.set((int)len, item, strict);
303 }
304
305 @Override
306 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
307 final long oldLength = length();
308 final long newLength = oldLength - removed + added;
309 if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
310 throw new UnsupportedOperationException();
311 }
312 final ArrayData returnValue = removed == 0 ?
313 EMPTY_ARRAY : new ObjectArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
314
315 if (newLength != oldLength) {
316 final Object[] newArray;
317
318 if (newLength > array.length) {
319 newArray = new Object[ArrayData.nextSize((int)newLength)];
320 System.arraycopy(array, 0, newArray, 0, start);
321 } else {
322 newArray = array;
323 }
324
325 System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed));
326 array = newArray;
327 setLength(newLength);
328 }
329
330 return returnValue;
331 }
332
333 @Override
334 public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
335 final int otherLength = (int)otherData.length();
336 final int thisLength = (int)length();
337 assert otherLength > 0 && thisLength > 0;
338
339 final Object[] otherArray = ((ObjectArrayData)otherData).array;
340 final int newLength = otherLength + thisLength;
341 final Object[] newArray = new Object[ArrayData.alignUp(newLength)];
342
343 System.arraycopy(array, 0, newArray, 0, thisLength);
344 System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
345
346 return new ObjectArrayData(newArray, newLength);
347 }
348
349 @Override
350 public String toString() {
351 assert length() <= array.length : length() + " > " + array.length;
352 return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length()));
353 }
354 }
--- EOF ---