35 import java.util.Iterator;
36 import java.util.List;
37 import jdk.dynalink.CallSiteDescriptor;
38 import jdk.dynalink.linker.GuardedInvocation;
39 import jdk.dynalink.linker.LinkRequest;
40 import jdk.nashorn.internal.codegen.CompilerConstants;
41 import jdk.nashorn.internal.codegen.types.Type;
42 import jdk.nashorn.internal.objects.Global;
43 import jdk.nashorn.internal.runtime.JSType;
44 import jdk.nashorn.internal.runtime.PropertyDescriptor;
45 import jdk.nashorn.internal.runtime.ScriptRuntime;
46 import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
47
48 /**
49 * ArrayData - abstraction for wrapping array elements
50 */
51 public abstract class ArrayData {
52 /** Minimum chunk size for underlying arrays */
53 protected static final int CHUNK_SIZE = 32;
54
55 /** Mask for getting a chunk */
56 protected static final int CHUNK_MASK = CHUNK_SIZE - 1;
57
58 /** Untouched data - still link callsites as IntArrayData, but expands to
59 * a proper ArrayData when we try to write to it */
60 public static final ArrayData EMPTY_ARRAY = new UntouchedArrayData();
61
62 /**
63 * Length of the array data. Not necessarily length of the wrapped array.
64 * This is private to ensure that no one in a subclass is able to touch the length
65 * without going through {@link #setLength}. This is used to implement
66 * {@link LengthNotWritableFilter}s, ensuring that there are no ways past
67 * a {@link #setLength} function replaced by a nop
68 */
69 private long length;
70
71 /**
72 * Method handle to throw an {@link UnwarrantedOptimismException} when getting an element
73 * of the wrong type
74 */
75 protected static final CompilerConstants.Call THROW_UNWARRANTED = staticCall(MethodHandles.lookup(), ArrayData.class, "throwUnwarranted", void.class, ArrayData.class, int.class, int.class);
76
77 /**
147 public ArrayData shiftRight(final int by) {
148 return this; //always empty or we wouldn't be of this class
149 }
150
151 @Override
152 public ArrayData shrink(final long newLength) {
153 return this;
154 }
155
156 @Override
157 public ArrayData set(final int index, final Object value, final boolean strict) {
158 return toRealArrayData(index).set(index, value, strict);
159 }
160
161 @Override
162 public ArrayData set(final int index, final int value, final boolean strict) {
163 return toRealArrayData(index).set(index, value, strict);
164 }
165
166 @Override
167 public ArrayData set(final int index, final long value, final boolean strict) {
168 return toRealArrayData(index).set(index, value, strict);
169 }
170
171 @Override
172 public ArrayData set(final int index, final double value, final boolean strict) {
173 return toRealArrayData(index).set(index, value, strict);
174 }
175
176 @Override
177 public int getInt(final int index) {
178 throw new ArrayIndexOutOfBoundsException(index); //empty
179 }
180
181 @Override
182 public long getLong(final int index) {
183 throw new ArrayIndexOutOfBoundsException(index); //empty
184 }
185
186 @Override
187 public double getDouble(final int index) {
188 throw new ArrayIndexOutOfBoundsException(index); //empty
189 }
190
191 @Override
192 public Object getObject(final int index) {
193 throw new ArrayIndexOutOfBoundsException(index); //empty
194 }
195
196 @Override
197 public boolean has(final int index) {
198 return false; //empty
199 }
200
201 @Override
202 public Object pop() {
203 return ScriptRuntime.UNDEFINED;
204 }
205
206 @Override
271 */
272 protected static void throwUnwarranted(final ArrayData data, final int programPoint, final int index) {
273 throw new UnwarrantedOptimismException(data.getObject(index), programPoint);
274 }
275
276 /**
277 * Align an array size up to the nearest array chunk size
278 * @param size size required
279 * @return size given, always >= size
280 */
281 protected static int alignUp(final int size) {
282 return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1);
283 }
284
285 /**
286 * Factory method for unspecified array with given length - start as int array data
287 *
288 * @param length the initial length
289 * @return ArrayData
290 */
291 public static ArrayData allocate(final int length) {
292 if (length == 0) {
293 return new IntArrayData();
294 } else if (length >= SparseArrayData.MAX_DENSE_LENGTH) {
295 return new SparseArrayData(EMPTY_ARRAY, length);
296 } else {
297 return new DeletedRangeArrayFilter(new IntArrayData(length), 0, length - 1);
298 }
299 }
300
301 /**
302 * Factory method for unspecified given an array object
303 *
304 * @param array the array
305 * @return ArrayData wrapping this array
306 */
307 public static ArrayData allocate(final Object array) {
308 final Class<?> clazz = array.getClass();
309
310 if (clazz == int[].class) {
311 return new IntArrayData((int[])array, ((int[])array).length);
312 } else if (clazz == long[].class) {
313 return new LongArrayData((long[])array, ((long[])array).length);
314 } else if (clazz == double[].class) {
315 return new NumberArrayData((double[])array, ((double[])array).length);
316 } else {
317 return new ObjectArrayData((Object[])array, ((Object[])array).length);
318 }
319 }
320
321 /**
322 * Allocate an ArrayData wrapping a given array
323 *
324 * @param array the array to use for initial elements
325 * @return the ArrayData
326 */
327 public static ArrayData allocate(final int[] array) {
328 return new IntArrayData(array, array.length);
329 }
330
331 /**
332 * Allocate an ArrayData wrapping a given array
333 *
334 * @param array the array to use for initial elements
335 * @return the ArrayData
336 */
337 public static ArrayData allocate(final long[] array) {
338 return new LongArrayData(array, array.length);
339 }
340
341 /**
342 * Allocate an ArrayData wrapping a given array
343 *
344 * @param array the array to use for initial elements
345 * @return the ArrayData
346 */
347 public static ArrayData allocate(final double[] array) {
348 return new NumberArrayData(array, array.length);
349 }
350
351 /**
352 * Allocate an ArrayData wrapping a given array
353 *
354 * @param array the array to use for initial elements
355 * @return the ArrayData
356 */
357 public static ArrayData allocate(final Object[] array) {
358 return new ObjectArrayData(array, array.length);
359 }
360
361 /**
362 * Allocate an ArrayData wrapping a given nio ByteBuffer
363 *
364 * @param buf the nio ByteBuffer to wrap
365 * @return the ArrayData
366 */
520 * Set an object value at a given index
521 *
522 * @param index the index
523 * @param value the value
524 * @param strict are we in strict mode
525 * @return new array data (or same)
526 */
527 public abstract ArrayData set(final int index, final Object value, final boolean strict);
528
529 /**
530 * Set an int value at a given index
531 *
532 * @param index the index
533 * @param value the value
534 * @param strict are we in strict mode
535 * @return new array data (or same)
536 */
537 public abstract ArrayData set(final int index, final int value, final boolean strict);
538
539 /**
540 * Set a long value at a given index
541 *
542 * @param index the index
543 * @param value the value
544 * @param strict are we in strict mode
545 * @return new array data (or same)
546 */
547 public abstract ArrayData set(final int index, final long value, final boolean strict);
548
549 /**
550 * Set an double value at a given index
551 *
552 * @param index the index
553 * @param value the value
554 * @param strict are we in strict mode
555 * @return new array data (or same)
556 */
557 public abstract ArrayData set(final int index, final double value, final boolean strict);
558
559 /**
560 * Set an empty value at a given index. Should only affect Object array.
561 *
562 * @param index the index
563 * @return new array data (or same)
564 */
565 public ArrayData setEmpty(final int index) {
566 // Do nothing.
567 return this;
568 }
569
592 * {@link UnwarrantedOptimismException}, this type is used as the actual type of the return value.
593 * @return the optimistic type of this array data.
594 */
595 public Type getOptimisticType() {
596 return Type.OBJECT;
597 }
598
599 /**
600 * Get optimistic int - default is that it's impossible. Overridden
601 * by arrays that actually represents ints
602 *
603 * @param index the index
604 * @param programPoint program point
605 * @return the value
606 */
607 public int getIntOptimistic(final int index, final int programPoint) {
608 throw new UnwarrantedOptimismException(getObject(index), programPoint, getOptimisticType());
609 }
610
611 /**
612 * Get a long value from a given index
613 *
614 * @param index the index
615 * @return the value
616 */
617 public abstract long getLong(final int index);
618
619 /**
620 * Get optimistic long - default is that it's impossible. Overridden
621 * by arrays that actually represents longs or narrower
622 *
623 * @param index the index
624 * @param programPoint program point
625 * @return the value
626 */
627 public long getLongOptimistic(final int index, final int programPoint) {
628 throw new UnwarrantedOptimismException(getObject(index), programPoint, getOptimisticType());
629 }
630
631 /**
632 * Get a double value from a given index
633 *
634 * @param index the index
635 * @return the value
636 */
637 public abstract double getDouble(final int index);
638
639 /**
640 * Get optimistic double - default is that it's impossible. Overridden
641 * by arrays that actually represents doubles or narrower
642 *
643 * @param index the index
644 * @param programPoint program point
645 * @return the value
646 */
647 public double getDoubleOptimistic(final int index, final int programPoint) {
648 throw new UnwarrantedOptimismException(getObject(index), programPoint, getOptimisticType());
649 }
650
651 /**
804 * @param start start index of splice operation
805 * @param removed number of removed elements
806 * @param added number of added elements
807 * @throws UnsupportedOperationException if fast splice is not supported for the class or arguments.
808 * @return new arraydata, but this never happens because we always throw an exception
809 */
810 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
811 throw new UnsupportedOperationException();
812 }
813
814 static Class<?> widestType(final Object... items) {
815 assert items.length > 0;
816
817 Class<?> widest = Integer.class;
818
819 for (final Object item : items) {
820 if (item == null) {
821 return Object.class;
822 }
823 final Class<?> itemClass = item.getClass();
824 if (itemClass == Long.class) {
825 if (widest == Integer.class) {
826 widest = Long.class;
827 }
828 } else if (itemClass == Double.class || itemClass == Float.class) {
829 if (widest == Integer.class || widest == Long.class) {
830 widest = Double.class;
831 }
832 } else if (itemClass != Integer.class && itemClass != Short.class && itemClass != Byte.class) {
833 return Object.class;
834 }
835 }
836
837 return widest;
838 }
839
840 /**
841 * Return a list of keys in the array for the iterators
842 * @return iterator key list
843 */
844 protected List<Long> computeIteratorKeys() {
845 final List<Long> keys = new ArrayList<>();
846
847 final long len = length();
848 for (long i = 0L; i < len; i = nextIndex(i)) {
849 if (has((int)i)) {
|
35 import java.util.Iterator;
36 import java.util.List;
37 import jdk.dynalink.CallSiteDescriptor;
38 import jdk.dynalink.linker.GuardedInvocation;
39 import jdk.dynalink.linker.LinkRequest;
40 import jdk.nashorn.internal.codegen.CompilerConstants;
41 import jdk.nashorn.internal.codegen.types.Type;
42 import jdk.nashorn.internal.objects.Global;
43 import jdk.nashorn.internal.runtime.JSType;
44 import jdk.nashorn.internal.runtime.PropertyDescriptor;
45 import jdk.nashorn.internal.runtime.ScriptRuntime;
46 import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
47
48 /**
49 * ArrayData - abstraction for wrapping array elements
50 */
51 public abstract class ArrayData {
52 /** Minimum chunk size for underlying arrays */
53 protected static final int CHUNK_SIZE = 32;
54
55 /** Untouched data - still link callsites as IntArrayData, but expands to
56 * a proper ArrayData when we try to write to it */
57 public static final ArrayData EMPTY_ARRAY = new UntouchedArrayData();
58
59 /**
60 * Length of the array data. Not necessarily length of the wrapped array.
61 * This is private to ensure that no one in a subclass is able to touch the length
62 * without going through {@link #setLength}. This is used to implement
63 * {@link LengthNotWritableFilter}s, ensuring that there are no ways past
64 * a {@link #setLength} function replaced by a nop
65 */
66 private long length;
67
68 /**
69 * Method handle to throw an {@link UnwarrantedOptimismException} when getting an element
70 * of the wrong type
71 */
72 protected static final CompilerConstants.Call THROW_UNWARRANTED = staticCall(MethodHandles.lookup(), ArrayData.class, "throwUnwarranted", void.class, ArrayData.class, int.class, int.class);
73
74 /**
144 public ArrayData shiftRight(final int by) {
145 return this; //always empty or we wouldn't be of this class
146 }
147
148 @Override
149 public ArrayData shrink(final long newLength) {
150 return this;
151 }
152
153 @Override
154 public ArrayData set(final int index, final Object value, final boolean strict) {
155 return toRealArrayData(index).set(index, value, strict);
156 }
157
158 @Override
159 public ArrayData set(final int index, final int value, final boolean strict) {
160 return toRealArrayData(index).set(index, value, strict);
161 }
162
163 @Override
164 public ArrayData set(final int index, final double value, final boolean strict) {
165 return toRealArrayData(index).set(index, value, strict);
166 }
167
168 @Override
169 public int getInt(final int index) {
170 throw new ArrayIndexOutOfBoundsException(index); //empty
171 }
172
173 @Override
174 public double getDouble(final int index) {
175 throw new ArrayIndexOutOfBoundsException(index); //empty
176 }
177
178 @Override
179 public Object getObject(final int index) {
180 throw new ArrayIndexOutOfBoundsException(index); //empty
181 }
182
183 @Override
184 public boolean has(final int index) {
185 return false; //empty
186 }
187
188 @Override
189 public Object pop() {
190 return ScriptRuntime.UNDEFINED;
191 }
192
193 @Override
258 */
259 protected static void throwUnwarranted(final ArrayData data, final int programPoint, final int index) {
260 throw new UnwarrantedOptimismException(data.getObject(index), programPoint);
261 }
262
263 /**
264 * Align an array size up to the nearest array chunk size
265 * @param size size required
266 * @return size given, always >= size
267 */
268 protected static int alignUp(final int size) {
269 return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1);
270 }
271
272 /**
273 * Factory method for unspecified array with given length - start as int array data
274 *
275 * @param length the initial length
276 * @return ArrayData
277 */
278 public static ArrayData allocate(final long length) {
279 if (length == 0L) {
280 return new IntArrayData();
281 } else if (length >= SparseArrayData.MAX_DENSE_LENGTH) {
282 return new SparseArrayData(EMPTY_ARRAY, length);
283 } else {
284 return new DeletedRangeArrayFilter(new IntArrayData((int) length), 0, length - 1);
285 }
286 }
287
288 /**
289 * Factory method for unspecified given an array object
290 *
291 * @param array the array
292 * @return ArrayData wrapping this array
293 */
294 public static ArrayData allocate(final Object array) {
295 final Class<?> clazz = array.getClass();
296
297 if (clazz == int[].class) {
298 return new IntArrayData((int[])array, ((int[])array).length);
299 } else if (clazz == double[].class) {
300 return new NumberArrayData((double[])array, ((double[])array).length);
301 } else {
302 return new ObjectArrayData((Object[])array, ((Object[])array).length);
303 }
304 }
305
306 /**
307 * Allocate an ArrayData wrapping a given array
308 *
309 * @param array the array to use for initial elements
310 * @return the ArrayData
311 */
312 public static ArrayData allocate(final int[] array) {
313 return new IntArrayData(array, array.length);
314 }
315
316 /**
317 * Allocate an ArrayData wrapping a given array
318 *
319 * @param array the array to use for initial elements
320 * @return the ArrayData
321 */
322 public static ArrayData allocate(final double[] array) {
323 return new NumberArrayData(array, array.length);
324 }
325
326 /**
327 * Allocate an ArrayData wrapping a given array
328 *
329 * @param array the array to use for initial elements
330 * @return the ArrayData
331 */
332 public static ArrayData allocate(final Object[] array) {
333 return new ObjectArrayData(array, array.length);
334 }
335
336 /**
337 * Allocate an ArrayData wrapping a given nio ByteBuffer
338 *
339 * @param buf the nio ByteBuffer to wrap
340 * @return the ArrayData
341 */
495 * Set an object value at a given index
496 *
497 * @param index the index
498 * @param value the value
499 * @param strict are we in strict mode
500 * @return new array data (or same)
501 */
502 public abstract ArrayData set(final int index, final Object value, final boolean strict);
503
504 /**
505 * Set an int value at a given index
506 *
507 * @param index the index
508 * @param value the value
509 * @param strict are we in strict mode
510 * @return new array data (or same)
511 */
512 public abstract ArrayData set(final int index, final int value, final boolean strict);
513
514 /**
515 * Set an double value at a given index
516 *
517 * @param index the index
518 * @param value the value
519 * @param strict are we in strict mode
520 * @return new array data (or same)
521 */
522 public abstract ArrayData set(final int index, final double value, final boolean strict);
523
524 /**
525 * Set an empty value at a given index. Should only affect Object array.
526 *
527 * @param index the index
528 * @return new array data (or same)
529 */
530 public ArrayData setEmpty(final int index) {
531 // Do nothing.
532 return this;
533 }
534
557 * {@link UnwarrantedOptimismException}, this type is used as the actual type of the return value.
558 * @return the optimistic type of this array data.
559 */
560 public Type getOptimisticType() {
561 return Type.OBJECT;
562 }
563
564 /**
565 * Get optimistic int - default is that it's impossible. Overridden
566 * by arrays that actually represents ints
567 *
568 * @param index the index
569 * @param programPoint program point
570 * @return the value
571 */
572 public int getIntOptimistic(final int index, final int programPoint) {
573 throw new UnwarrantedOptimismException(getObject(index), programPoint, getOptimisticType());
574 }
575
576 /**
577 * Get a double value from a given index
578 *
579 * @param index the index
580 * @return the value
581 */
582 public abstract double getDouble(final int index);
583
584 /**
585 * Get optimistic double - default is that it's impossible. Overridden
586 * by arrays that actually represents doubles or narrower
587 *
588 * @param index the index
589 * @param programPoint program point
590 * @return the value
591 */
592 public double getDoubleOptimistic(final int index, final int programPoint) {
593 throw new UnwarrantedOptimismException(getObject(index), programPoint, getOptimisticType());
594 }
595
596 /**
749 * @param start start index of splice operation
750 * @param removed number of removed elements
751 * @param added number of added elements
752 * @throws UnsupportedOperationException if fast splice is not supported for the class or arguments.
753 * @return new arraydata, but this never happens because we always throw an exception
754 */
755 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
756 throw new UnsupportedOperationException();
757 }
758
759 static Class<?> widestType(final Object... items) {
760 assert items.length > 0;
761
762 Class<?> widest = Integer.class;
763
764 for (final Object item : items) {
765 if (item == null) {
766 return Object.class;
767 }
768 final Class<?> itemClass = item.getClass();
769 if (itemClass == Double.class || itemClass == Float.class || itemClass == Long.class) {
770 if (widest == Integer.class) {
771 widest = Double.class;
772 }
773 } else if (itemClass != Integer.class && itemClass != Short.class && itemClass != Byte.class) {
774 return Object.class;
775 }
776 }
777
778 return widest;
779 }
780
781 /**
782 * Return a list of keys in the array for the iterators
783 * @return iterator key list
784 */
785 protected List<Long> computeIteratorKeys() {
786 final List<Long> keys = new ArrayList<>();
787
788 final long len = length();
789 for (long i = 0L; i < len; i = nextIndex(i)) {
790 if (has((int)i)) {
|