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 static jdk.nashorn.internal.lookup.Lookup.MH; |
|
30 |
|
31 import java.lang.invoke.MethodHandle; |
|
32 import java.lang.invoke.MethodHandles; |
|
33 import java.util.Arrays; |
|
34 import jdk.nashorn.internal.runtime.JSType; |
|
35 import jdk.nashorn.internal.runtime.ScriptRuntime; |
|
36 |
|
37 /** |
|
38 * Implementation of {@link ArrayData} as soon as a long has been |
|
39 * written to the array |
|
40 */ |
|
41 final class LongArrayData extends ContinuousArrayData implements IntOrLongElements { |
|
42 /** |
|
43 * The wrapped array |
|
44 */ |
|
45 private long[] array; |
|
46 |
|
47 /** |
|
48 * Constructor |
|
49 * @param array an int array |
|
50 * @param length a length, not necessarily array.length |
|
51 */ |
|
52 LongArrayData(final long array[], final int length) { |
|
53 super(length); |
|
54 assert array.length >= length; |
|
55 this.array = array; |
|
56 } |
|
57 |
|
58 @Override |
|
59 public final Class<?> getElementType() { |
|
60 return long.class; |
|
61 } |
|
62 |
|
63 @Override |
|
64 public final Class<?> getBoxedElementType() { |
|
65 return Long.class; |
|
66 } |
|
67 |
|
68 @Override |
|
69 public final ContinuousArrayData widest(final ContinuousArrayData otherData) { |
|
70 return otherData instanceof IntElements ? this : otherData; |
|
71 } |
|
72 |
|
73 @Override |
|
74 public final int getElementWeight() { |
|
75 return 2; |
|
76 } |
|
77 |
|
78 @Override |
|
79 public LongArrayData copy() { |
|
80 return new LongArrayData(array.clone(), (int)length()); |
|
81 } |
|
82 |
|
83 @Override |
|
84 public Object[] asObjectArray() { |
|
85 return toObjectArray(true); |
|
86 } |
|
87 |
|
88 private Object[] toObjectArray(final boolean trim) { |
|
89 assert length() <= array.length : "length exceeds internal array size"; |
|
90 final int len = (int)length(); |
|
91 final Object[] oarray = new Object[trim ? len : array.length]; |
|
92 |
|
93 for (int index = 0; index < len; index++) { |
|
94 oarray[index] = array[index]; |
|
95 } |
|
96 |
|
97 return oarray; |
|
98 } |
|
99 |
|
100 @Override |
|
101 public Object asArrayOfType(final Class<?> componentType) { |
|
102 if (componentType == long.class) { |
|
103 final int len = (int)length(); |
|
104 return array.length == len ? array.clone() : Arrays.copyOf(array, len); |
|
105 } |
|
106 return super.asArrayOfType(componentType); |
|
107 } |
|
108 |
|
109 private double[] toDoubleArray() { |
|
110 assert length() <= array.length : "length exceeds internal array size"; |
|
111 final int len = (int)length(); |
|
112 final double[] darray = new double[array.length]; |
|
113 |
|
114 for (int index = 0; index < len; index++) { |
|
115 darray[index] = array[index]; |
|
116 } |
|
117 |
|
118 return darray; |
|
119 } |
|
120 |
|
121 @Override |
|
122 public ContinuousArrayData convert(final Class<?> type) { |
|
123 if (type == Integer.class || type == Long.class || type == Byte.class || type == Short.class) { |
|
124 return this; |
|
125 } |
|
126 final int len = (int)length(); |
|
127 if (type == Double.class || type == Float.class) { |
|
128 return new NumberArrayData(toDoubleArray(), len); |
|
129 } |
|
130 return new ObjectArrayData(toObjectArray(false), len); |
|
131 } |
|
132 |
|
133 @Override |
|
134 public void shiftLeft(final int by) { |
|
135 System.arraycopy(array, by, array, 0, array.length - by); |
|
136 } |
|
137 |
|
138 @Override |
|
139 public ArrayData shiftRight(final int by) { |
|
140 final ArrayData newData = ensure(by + length() - 1); |
|
141 if (newData != this) { |
|
142 newData.shiftRight(by); |
|
143 return newData; |
|
144 } |
|
145 System.arraycopy(array, 0, array, by, array.length - by); |
|
146 |
|
147 return this; |
|
148 } |
|
149 |
|
150 @Override |
|
151 public ArrayData ensure(final long safeIndex) { |
|
152 if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { |
|
153 return new SparseArrayData(this, safeIndex + 1); |
|
154 } |
|
155 final int alen = array.length; |
|
156 if (safeIndex >= alen) { |
|
157 final int newLength = ArrayData.nextSize((int)safeIndex); |
|
158 array = Arrays.copyOf(array, newLength); |
|
159 } |
|
160 if (safeIndex >= length()) { |
|
161 setLength(safeIndex + 1); |
|
162 } |
|
163 return this; |
|
164 } |
|
165 |
|
166 @Override |
|
167 public ArrayData shrink(final long newLength) { |
|
168 Arrays.fill(array, (int)newLength, array.length, 0L); |
|
169 return this; |
|
170 } |
|
171 |
|
172 @Override |
|
173 public ArrayData set(final int index, final Object value, final boolean strict) { |
|
174 if (value instanceof Long || value instanceof Integer || |
|
175 value instanceof Byte || value instanceof Short) { |
|
176 return set(index, ((Number)value).longValue(), strict); |
|
177 } else if (value == ScriptRuntime.UNDEFINED) { |
|
178 return new UndefinedArrayFilter(this).set(index, value, strict); |
|
179 } |
|
180 |
|
181 final ArrayData newData = convert(value == null ? Object.class : value.getClass()); |
|
182 return newData.set(index, value, strict); |
|
183 } |
|
184 |
|
185 @Override |
|
186 public ArrayData set(final int index, final int value, final boolean strict) { |
|
187 array[index] = value; |
|
188 setLength(Math.max(index + 1, length())); |
|
189 return this; |
|
190 } |
|
191 |
|
192 @Override |
|
193 public ArrayData set(final int index, final long value, final boolean strict) { |
|
194 array[index] = value; |
|
195 setLength(Math.max(index + 1, length())); |
|
196 return this; |
|
197 } |
|
198 |
|
199 @Override |
|
200 public ArrayData set(final int index, final double value, final boolean strict) { |
|
201 if (JSType.isRepresentableAsLong(value)) { |
|
202 array[index] = (long)value; |
|
203 setLength(Math.max(index + 1, length())); |
|
204 return this; |
|
205 } |
|
206 return convert(Double.class).set(index, value, strict); |
|
207 } |
|
208 |
|
209 private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, "getElem", long.class, int.class).methodHandle(); |
|
210 private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, "setElem", void.class, int.class, long.class).methodHandle(); |
|
211 |
|
212 @SuppressWarnings("unused") |
|
213 private long getElem(final int index) { |
|
214 if (has(index)) { |
|
215 return array[index]; |
|
216 } |
|
217 throw new ClassCastException(); |
|
218 } |
|
219 |
|
220 @SuppressWarnings("unused") |
|
221 private void setElem(final int index, final long elem) { |
|
222 if (hasRoomFor(index)) { |
|
223 array[index] = elem; |
|
224 return; |
|
225 } |
|
226 throw new ClassCastException(); |
|
227 } |
|
228 |
|
229 @Override |
|
230 public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { |
|
231 if (returnType == int.class) { |
|
232 return null; |
|
233 } |
|
234 return getContinuousElementGetter(HAS_GET_ELEM, returnType, programPoint); |
|
235 } |
|
236 |
|
237 @Override |
|
238 public MethodHandle getElementSetter(final Class<?> elementType) { |
|
239 return elementType == int.class || elementType == long.class ? getContinuousElementSetter(MH.asType(SET_ELEM, SET_ELEM.type().changeParameterType(2, elementType)), elementType) : null; |
|
240 } |
|
241 |
|
242 @Override |
|
243 public int getInt(final int index) { |
|
244 return JSType.toInt32(array[index]); |
|
245 } |
|
246 |
|
247 @Override |
|
248 public long getLong(final int index) { |
|
249 return array[index]; |
|
250 } |
|
251 |
|
252 @Override |
|
253 public long getLongOptimistic(final int index, final int programPoint) { |
|
254 return array[index]; |
|
255 } |
|
256 |
|
257 @Override |
|
258 public double getDouble(final int index) { |
|
259 return array[index]; |
|
260 } |
|
261 |
|
262 @Override |
|
263 public double getDoubleOptimistic(final int index, final int programPoint) { |
|
264 return array[index]; |
|
265 } |
|
266 |
|
267 @Override |
|
268 public Object getObject(final int index) { |
|
269 return array[index]; |
|
270 } |
|
271 |
|
272 @Override |
|
273 public boolean has(final int index) { |
|
274 return 0 <= index && index < length(); |
|
275 } |
|
276 |
|
277 @Override |
|
278 public ArrayData delete(final int index) { |
|
279 return new DeletedRangeArrayFilter(this, index, index); |
|
280 } |
|
281 |
|
282 @Override |
|
283 public ArrayData delete(final long fromIndex, final long toIndex) { |
|
284 return new DeletedRangeArrayFilter(this, fromIndex, toIndex); |
|
285 } |
|
286 |
|
287 @Override |
|
288 public Object pop() { |
|
289 final int len = (int)length(); |
|
290 if (len == 0) { |
|
291 return ScriptRuntime.UNDEFINED; |
|
292 } |
|
293 |
|
294 final int newLength = len - 1; |
|
295 final long elem = array[newLength]; |
|
296 array[newLength] = 0; |
|
297 setLength(newLength); |
|
298 |
|
299 return elem; |
|
300 } |
|
301 |
|
302 @Override |
|
303 public ArrayData slice(final long from, final long to) { |
|
304 final long start = from < 0 ? from + length() : from; |
|
305 final long newLength = to - start; |
|
306 return new LongArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength); |
|
307 } |
|
308 |
|
309 @Override |
|
310 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { |
|
311 final long oldLength = length(); |
|
312 final long newLength = oldLength - removed + added; |
|
313 if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) { |
|
314 throw new UnsupportedOperationException(); |
|
315 } |
|
316 final ArrayData returnValue = removed == 0 ? |
|
317 EMPTY_ARRAY : new LongArrayData(Arrays.copyOfRange(array, start, start + removed), removed); |
|
318 |
|
319 if (newLength != oldLength) { |
|
320 final long[] newArray; |
|
321 |
|
322 if (newLength > array.length) { |
|
323 newArray = new long[ArrayData.nextSize((int)newLength)]; |
|
324 System.arraycopy(array, 0, newArray, 0, start); |
|
325 } else { |
|
326 newArray = array; |
|
327 } |
|
328 |
|
329 System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed)); |
|
330 array = newArray; |
|
331 setLength(newLength); |
|
332 } |
|
333 |
|
334 return returnValue; |
|
335 } |
|
336 |
|
337 @Override |
|
338 public long fastPush(final int arg) { |
|
339 return fastPush((long)arg); |
|
340 } |
|
341 |
|
342 @Override |
|
343 public long fastPush(final long arg) { |
|
344 final int len = (int)length(); |
|
345 if (len == array.length) { |
|
346 array = Arrays.copyOf(array, nextSize(len)); |
|
347 } |
|
348 array[len] = arg; |
|
349 return increaseLength(); |
|
350 } |
|
351 |
|
352 @Override |
|
353 public long fastPopLong() { |
|
354 if (length() == 0) { |
|
355 throw new ClassCastException(); //undefined result |
|
356 } |
|
357 final int newLength = (int)decreaseLength(); |
|
358 final long elem = array[newLength]; |
|
359 array[newLength] = 0; |
|
360 return elem; |
|
361 } |
|
362 |
|
363 @Override |
|
364 public double fastPopDouble() { |
|
365 return fastPopLong(); |
|
366 } |
|
367 |
|
368 @Override |
|
369 public Object fastPopObject() { |
|
370 return fastPopLong(); |
|
371 } |
|
372 |
|
373 @Override |
|
374 public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { |
|
375 final int otherLength = (int)otherData.length(); |
|
376 final int thisLength = (int)length(); |
|
377 assert otherLength > 0 && thisLength > 0; |
|
378 |
|
379 final long[] otherArray = ((LongArrayData)otherData).array; |
|
380 final int newLength = otherLength + thisLength; |
|
381 final long[] newArray = new long[ArrayData.alignUp(newLength)]; |
|
382 |
|
383 System.arraycopy(array, 0, newArray, 0, thisLength); |
|
384 System.arraycopy(otherArray, 0, newArray, thisLength, otherLength); |
|
385 |
|
386 return new LongArrayData(newArray, newLength); |
|
387 } |
|
388 |
|
389 @Override |
|
390 public String toString() { |
|
391 assert length() <= array.length : length() + " > " + array.length; |
|
392 |
|
393 final StringBuilder sb = new StringBuilder(getClass().getSimpleName()). |
|
394 append(": ["); |
|
395 final int len = (int)length(); |
|
396 for (int i = 0; i < len; i++) { |
|
397 sb.append(array[i]).append('L'); //make sure L suffix is on elements, to discriminate this from IntArrayData.toString() |
|
398 if (i + 1 < len) { |
|
399 sb.append(", "); |
|
400 } |
|
401 } |
|
402 sb.append(']'); |
|
403 |
|
404 return sb.toString(); |
|
405 } |
|
406 } |
|