ArrayData.java revision 1118:e26843ca558b
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.staticCall; 29import java.lang.invoke.MethodHandle; 30import java.lang.invoke.MethodHandles; 31import java.lang.reflect.Array; 32import java.nio.ByteBuffer; 33import java.util.ArrayList; 34import java.util.Iterator; 35import java.util.List; 36import jdk.internal.dynalink.CallSiteDescriptor; 37import jdk.internal.dynalink.linker.GuardedInvocation; 38import jdk.internal.dynalink.linker.LinkRequest; 39import jdk.nashorn.internal.codegen.CompilerConstants; 40import jdk.nashorn.internal.codegen.types.Type; 41import jdk.nashorn.internal.objects.Global; 42import jdk.nashorn.internal.runtime.JSType; 43import jdk.nashorn.internal.runtime.PropertyDescriptor; 44import jdk.nashorn.internal.runtime.ScriptRuntime; 45import jdk.nashorn.internal.runtime.UnwarrantedOptimismException; 46 47/** 48 * ArrayData - abstraction for wrapping array elements 49 */ 50public abstract class ArrayData { 51 /** Minimum chunk size for underlying arrays */ 52 protected static final int CHUNK_SIZE = 32; 53 54 /** Mask for getting a chunk */ 55 protected static final int CHUNK_MASK = CHUNK_SIZE - 1; 56 57 /** Untouched data - still link callsites as IntArrayData, but expands to 58 * a proper ArrayData when we try to write to it */ 59 public static final ArrayData EMPTY_ARRAY = new UntouchedArrayData(); 60 61 /** 62 * Length of the array data. Not necessarily length of the wrapped array. 63 * This is private to ensure that no one in a subclass is able to touch the length 64 * without going through {@link #setLength}. This is used to implement 65 * {@link LengthNotWritableFilter}s, ensuring that there are no ways past 66 * a {@link #setLength} function replaced by a nop 67 */ 68 private long length; 69 70 /** 71 * Method handle to throw an {@link UnwarrantedOptimismException} when getting an element 72 * of the wrong type 73 */ 74 protected static final CompilerConstants.Call THROW_UNWARRANTED = staticCall(MethodHandles.lookup(), ArrayData.class, "throwUnwarranted", void.class, ArrayData.class, int.class, int.class); 75 76 /** 77 * Immutable empty array to get ScriptObjects started. 78 * Use the same array and convert it to mutable as soon as it is modified 79 */ 80 private static class UntouchedArrayData extends ContinuousArrayData { 81 private UntouchedArrayData() { 82 super(0); 83 } 84 85 private ArrayData toRealArrayData() { 86 return toRealArrayData(0); 87 } 88 89 private ArrayData toRealArrayData(final int index) { 90 final IntArrayData newData = new IntArrayData(index + 1); 91 if (index == 0) { 92 return newData; 93 } 94 return new DeletedRangeArrayFilter(newData, 0, index); 95 } 96 97 @Override 98 public ContinuousArrayData copy() { 99 assert length() == 0; 100 return this; 101 } 102 103 @Override 104 public Object asArrayOfType(final Class<?> componentType) { 105 return Array.newInstance(componentType, 0); 106 } 107 108 @Override 109 public Object[] asObjectArray() { 110 return ScriptRuntime.EMPTY_ARRAY; 111 } 112 113 @Override 114 public ArrayData ensure(final long safeIndex) { 115 if (safeIndex > 0L) { 116 if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { 117 return new SparseArrayData(this, safeIndex + 1); 118 } 119 //known to fit in int 120 return toRealArrayData((int)safeIndex).ensure(safeIndex); 121 } 122 return this; 123 } 124 125 @Override 126 public ArrayData convert(final Class<?> type) { 127 return toRealArrayData(0).convert(type); 128 } 129 130 @Override 131 public ArrayData delete(final int index) { 132 return new DeletedRangeArrayFilter(this, index, index); 133 } 134 135 @Override 136 public ArrayData delete(final long fromIndex, final long toIndex) { 137 return new DeletedRangeArrayFilter(this, fromIndex, toIndex); 138 } 139 140 @Override 141 public void shiftLeft(final int by) { 142 //nop, always empty or we wouldn't be of this class 143 } 144 145 @Override 146 public ArrayData shiftRight(final int by) { 147 return this; //always empty or we wouldn't be of this class 148 } 149 150 @Override 151 public ArrayData shrink(final long newLength) { 152 return this; 153 } 154 155 @Override 156 public ArrayData set(final int index, final Object value, final boolean strict) { 157 return toRealArrayData(index).set(index, value, strict); 158 } 159 160 @Override 161 public ArrayData set(final int index, final int value, final boolean strict) { 162 return toRealArrayData(index).set(index, value, strict); 163 } 164 165 @Override 166 public ArrayData set(final int index, final long value, final boolean strict) { 167 return toRealArrayData(index).set(index, value, strict); 168 } 169 170 @Override 171 public ArrayData set(final int index, final double value, final boolean strict) { 172 return toRealArrayData(index).set(index, value, strict); 173 } 174 175 @Override 176 public int getInt(final int index) { 177 throw new ArrayIndexOutOfBoundsException(index); //empty 178 } 179 180 @Override 181 public long getLong(final int index) { 182 throw new ArrayIndexOutOfBoundsException(index); //empty 183 } 184 185 @Override 186 public double getDouble(final int index) { 187 throw new ArrayIndexOutOfBoundsException(index); //empty 188 } 189 190 @Override 191 public Object getObject(final int index) { 192 throw new ArrayIndexOutOfBoundsException(index); //empty 193 } 194 195 @Override 196 public boolean has(final int index) { 197 return false; //empty 198 } 199 200 @Override 201 public Object pop() { 202 return ScriptRuntime.UNDEFINED; 203 } 204 205 @Override 206 public ArrayData push(final boolean strict, final Object item) { 207 return toRealArrayData().push(strict, item); 208 } 209 210 @Override 211 public ArrayData slice(final long from, final long to) { 212 return this; //empty 213 } 214 215 @Override 216 public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { 217 return otherData.copy(); 218 } 219 220 //no need to override fastPopInt, as the default behavior is to throw classcast exception so we 221 //can relink and return an undefined, this is the IntArrayData default behavior 222 @Override 223 public String toString() { 224 return getClass().getSimpleName(); 225 } 226 227 @Override 228 public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { 229 return null; 230 } 231 232 @Override 233 public MethodHandle getElementSetter(final Class<?> elementType) { 234 return null; 235 } 236 237 @Override 238 public Class<?> getElementType() { 239 return int.class; 240 } 241 242 @Override 243 public Class<?> getBoxedElementType() { 244 return Integer.class; 245 } 246 } 247 248 /** 249 * Constructor 250 * @param length Virtual length of the array. 251 */ 252 protected ArrayData(final long length) { 253 this.length = length; 254 } 255 256 /** 257 * Factory method for unspecified array - start as int 258 * @return ArrayData 259 */ 260 public final static ArrayData initialArray() { 261 return new IntArrayData(); 262 } 263 264 /** 265 * Unwarranted thrower 266 * 267 * @param data array data 268 * @param programPoint program point 269 * @param index array index 270 */ 271 protected static void throwUnwarranted(final ArrayData data, final int programPoint, final int index) { 272 throw new UnwarrantedOptimismException(data.getObject(index), programPoint); 273 } 274 275 /** 276 * Align an array size up to the nearest array chunk size 277 * @param size size required 278 * @return size given, always >= size 279 */ 280 protected final static int alignUp(final int size) { 281 return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1); 282 } 283 284 /** 285 * Factory method for unspecified array with given length - start as int array data 286 * 287 * @param length the initial length 288 * @return ArrayData 289 */ 290 public static final ArrayData allocate(final int length) { 291 if (length == 0) { 292 return new IntArrayData(); 293 } else if (length >= SparseArrayData.MAX_DENSE_LENGTH) { 294 return new SparseArrayData(EMPTY_ARRAY, length); 295 } else { 296 return new DeletedRangeArrayFilter(new IntArrayData(length), 0, length - 1); 297 } 298 } 299 300 /** 301 * Factory method for unspecified given an array object 302 * 303 * @param array the array 304 * @return ArrayData wrapping this array 305 */ 306 public static final ArrayData allocate(final Object array) { 307 final Class<?> clazz = array.getClass(); 308 309 if (clazz == int[].class) { 310 return new IntArrayData((int[])array, ((int[])array).length); 311 } else if (clazz == long[].class) { 312 return new LongArrayData((long[])array, ((long[])array).length); 313 } else if (clazz == double[].class) { 314 return new NumberArrayData((double[])array, ((double[])array).length); 315 } else { 316 return new ObjectArrayData((Object[])array, ((Object[])array).length); 317 } 318 } 319 320 /** 321 * Allocate an ArrayData wrapping a given array 322 * 323 * @param array the array to use for initial elements 324 * @return the ArrayData 325 */ 326 public static final ArrayData allocate(final int[] array) { 327 return new IntArrayData(array, array.length); 328 } 329 330 /** 331 * Allocate an ArrayData wrapping a given array 332 * 333 * @param array the array to use for initial elements 334 * @return the ArrayData 335 */ 336 public static final ArrayData allocate(final long[] array) { 337 return new LongArrayData(array, array.length); 338 } 339 340 /** 341 * Allocate an ArrayData wrapping a given array 342 * 343 * @param array the array to use for initial elements 344 * @return the ArrayData 345 */ 346 public static final ArrayData allocate(final double[] array) { 347 return new NumberArrayData(array, array.length); 348 } 349 350 /** 351 * Allocate an ArrayData wrapping a given array 352 * 353 * @param array the array to use for initial elements 354 * @return the ArrayData 355 */ 356 public static final ArrayData allocate(final Object[] array) { 357 return new ObjectArrayData(array, array.length); 358 } 359 360 /** 361 * Allocate an ArrayData wrapping a given nio ByteBuffer 362 * 363 * @param buf the nio ByteBuffer to wrap 364 * @return the ArrayData 365 */ 366 public static final ArrayData allocate(final ByteBuffer buf) { 367 return new ByteBufferArrayData(buf); 368 } 369 370 /** 371 * Apply a freeze filter to an ArrayData. 372 * 373 * @param underlying the underlying ArrayData to wrap in the freeze filter 374 * @return the frozen ArrayData 375 */ 376 public static final ArrayData freeze(final ArrayData underlying) { 377 return new FrozenArrayFilter(underlying); 378 } 379 380 /** 381 * Apply a seal filter to an ArrayData. 382 * 383 * @param underlying the underlying ArrayData to wrap in the seal filter 384 * @return the sealed ArrayData 385 */ 386 public static final ArrayData seal(final ArrayData underlying) { 387 return new SealedArrayFilter(underlying); 388 } 389 390 /** 391 * Prevent this array from being extended 392 * 393 * @param underlying the underlying ArrayData to wrap in the non extensible filter 394 * @return new array data, filtered 395 */ 396 public static final ArrayData preventExtension(final ArrayData underlying) { 397 return new NonExtensibleArrayFilter(underlying); 398 } 399 400 /** 401 * Prevent this array from having its length reset 402 * 403 * @param underlying the underlying ArrayDAta to wrap in the non extensible filter 404 * @return new array data, filtered 405 */ 406 public static final ArrayData setIsLengthNotWritable(final ArrayData underlying) { 407 return new LengthNotWritableFilter(underlying); 408 } 409 410 /** 411 * Return the length of the array data. This may differ from the actual 412 * length of the array this wraps as length may be set or gotten as any 413 * other JavaScript Property 414 * 415 * Even though a JavaScript array length may be a long, we only store 416 * int parts for the optimized array access. For long lengths there 417 * are special cases anyway. 418 * 419 * TODO: represent arrays with "long" lengths as a special ArrayData 420 * that basically maps to the ScriptObject directly for better abstraction 421 * 422 * @return the length of the data 423 */ 424 public final long length() { 425 return length; 426 } 427 428 /** 429 * Return a copy of the array that can be modified without affecting this instance. 430 * It is safe to return themselves for immutable subclasses. 431 * 432 * @return a new array 433 */ 434 public abstract ArrayData copy(); 435 436 /** 437 * Return a copy of the array data as an Object array. 438 * 439 * @return an Object array 440 */ 441 public abstract Object[] asObjectArray(); 442 443 /** 444 * Return a copy of the array data as an array of the specified type. 445 * 446 * @param componentType the type of elements in the array 447 * @return and array of the given type 448 */ 449 public Object asArrayOfType(final Class<?> componentType) { 450 return JSType.convertArray(asObjectArray(), componentType); 451 } 452 453 /** 454 * Set the length of the data array 455 * 456 * @param length the new length for the data array 457 */ 458 public void setLength(final long length) { 459 this.length = length; 460 } 461 462 /** 463 * Increase length by 1 464 * @return the new length, not the old one (i.e. pre-increment) 465 */ 466 protected final long increaseLength() { 467 return ++this.length; 468 } 469 470 /** 471 * Decrease length by 1. 472 * @return the new length, not the old one (i.e. pre-decrement) 473 */ 474 protected final long decreaseLength() { 475 return --this.length; 476 } 477 478 /** 479 * Shift the array data left 480 * 481 * TODO: explore start at an index and not at zero, to make these operations 482 * even faster. Offset everything from the index. Costs memory but is probably 483 * worth it 484 * 485 * @param by offset to shift 486 */ 487 public abstract void shiftLeft(final int by); 488 489 /** 490 * Shift the array right 491 * 492 * @param by offset to shift 493 494 * @return New arraydata (or same) 495 */ 496 public abstract ArrayData shiftRight(final int by); 497 498 /** 499 * Ensure that the given index exists and won't fail subsequent 500 * 501 * @param safeIndex the index to ensure wont go out of bounds 502 * @return new array data (or same) 503 */ 504 public abstract ArrayData ensure(final long safeIndex); 505 506 /** 507 * Shrink the array to a new length, may or may not retain the 508 * inner array 509 * 510 * @param newLength new max length 511 * 512 * @return new array data (or same) 513 */ 514 public abstract ArrayData shrink(final long newLength); 515 516 /** 517 * Set an object value at a given index 518 * 519 * @param index the index 520 * @param value the value 521 * @param strict are we in strict mode 522 * @return new array data (or same) 523 */ 524 public abstract ArrayData set(final int index, final Object value, final boolean strict); 525 526 /** 527 * Set an int value at a given index 528 * 529 * @param index the index 530 * @param value the value 531 * @param strict are we in strict mode 532 * @return new array data (or same) 533 */ 534 public abstract ArrayData set(final int index, final int value, final boolean strict); 535 536 /** 537 * Set a long value at a given index 538 * 539 * @param index the index 540 * @param value the value 541 * @param strict are we in strict mode 542 * @return new array data (or same) 543 */ 544 public abstract ArrayData set(final int index, final long value, final boolean strict); 545 546 /** 547 * Set an double value at a given index 548 * 549 * @param index the index 550 * @param value the value 551 * @param strict are we in strict mode 552 * @return new array data (or same) 553 */ 554 public abstract ArrayData set(final int index, final double value, final boolean strict); 555 556 /** 557 * Set an empty value at a given index. Should only affect Object array. 558 * 559 * @param index the index 560 * @return new array data (or same) 561 */ 562 public ArrayData setEmpty(final int index) { 563 // Do nothing. 564 return this; 565 } 566 567 /** 568 * Set an empty value for a given range. Should only affect Object array. 569 * 570 * @param lo range low end 571 * @param hi range high end 572 * @return new array data (or same) 573 */ 574 public ArrayData setEmpty(final long lo, final long hi) { 575 // Do nothing. 576 return this; 577 } 578 579 /** 580 * Get an int value from a given index 581 * 582 * @param index the index 583 * @return the value 584 */ 585 public abstract int getInt(final int index); 586 587 /** 588 * Returns the optimistic type of this array data. Basically, when an array data object needs to throw an 589 * {@link UnwarrantedOptimismException}, this type is used as the actual type of the return value. 590 * @return the optimistic type of this array data. 591 */ 592 public Type getOptimisticType() { 593 return Type.OBJECT; 594 } 595 596 /** 597 * Get optimistic int - default is that it's impossible. Overridden 598 * by arrays that actually represents ints 599 * 600 * @param index the index 601 * @param programPoint program point 602 * @return the value 603 */ 604 public int getIntOptimistic(final int index, final int programPoint) { 605 throw new UnwarrantedOptimismException(getObject(index), programPoint, getOptimisticType()); 606 } 607 608 /** 609 * Get a long value from a given index 610 * 611 * @param index the index 612 * @return the value 613 */ 614 public abstract long getLong(final int index); 615 616 /** 617 * Get optimistic long - default is that it's impossible. Overridden 618 * by arrays that actually represents longs or narrower 619 * 620 * @param index the index 621 * @param programPoint program point 622 * @return the value 623 */ 624 public long getLongOptimistic(final int index, final int programPoint) { 625 throw new UnwarrantedOptimismException(getObject(index), programPoint, getOptimisticType()); 626 } 627 628 /** 629 * Get a double value from a given index 630 * 631 * @param index the index 632 * @return the value 633 */ 634 public abstract double getDouble(final int index); 635 636 /** 637 * Get optimistic double - default is that it's impossible. Overridden 638 * by arrays that actually represents doubles or narrower 639 * 640 * @param index the index 641 * @param programPoint program point 642 * @return the value 643 */ 644 public double getDoubleOptimistic(final int index, final int programPoint) { 645 throw new UnwarrantedOptimismException(getObject(index), programPoint, getOptimisticType()); 646 } 647 648 /** 649 * Get an Object value from a given index 650 * 651 * @param index the index 652 * @return the value 653 */ 654 public abstract Object getObject(final int index); 655 656 /** 657 * Tests to see if an entry exists (avoids boxing.) 658 * @param index the index 659 * @return true if entry exists 660 */ 661 public abstract boolean has(final int index); 662 663 /** 664 * Returns if element at specific index can be deleted or not. 665 * 666 * @param index the index of the element 667 * @param strict are we in strict mode 668 * 669 * @return true if element can be deleted 670 */ 671 public boolean canDelete(final int index, final boolean strict) { 672 return true; 673 } 674 675 /** 676 * Returns if element at specific index range can be deleted or not. 677 * 678 * @param fromIndex the start index 679 * @param toIndex the end index 680 * @param strict are we in strict mode 681 * 682 * @return true if range can be deleted 683 */ 684 public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) { 685 return true; 686 } 687 688 /** 689 * Returns property descriptor for element at a given index 690 * 691 * @param global the global object 692 * @param index the index 693 * 694 * @return property descriptor for element 695 */ 696 public PropertyDescriptor getDescriptor(final Global global, final int index) { 697 return global.newDataDescriptor(getObject(index), true, true, true); 698 } 699 700 /** 701 * Delete an array value at the given index, substituting 702 * for an undefined 703 * 704 * @param index the index 705 * @return new array data (or same) 706 */ 707 public abstract ArrayData delete(final int index); 708 709 /** 710 * Delete a given range from this array; 711 * 712 * @param fromIndex from index (inclusive) 713 * @param toIndex to index (inclusive) 714 * 715 * @return new ArrayData after deletion 716 */ 717 public abstract ArrayData delete(final long fromIndex, final long toIndex); 718 719 /** 720 * Convert the ArrayData to one with a different element type 721 * Currently Arrays are not collapsed to narrower types, just to 722 * wider ones. Attempting to narrow an array will assert 723 * 724 * @param type new element type 725 * @return new array data 726 */ 727 public abstract ArrayData convert(final Class<?> type); 728 729 /** 730 * Push an array of items to the end of the array 731 * 732 * @param strict are we in strict mode 733 * @param items the items 734 * @return new array data (or same) 735 */ 736 public ArrayData push(final boolean strict, final Object... items) { 737 if (items.length == 0) { 738 return this; 739 } 740 741 final Class<?> widest = widestType(items); 742 743 ArrayData newData = convert(widest); 744 long pos = newData.length; 745 for (final Object item : items) { 746 newData = newData.ensure(pos); //avoid sparse array 747 newData.set((int)pos++, item, strict); 748 } 749 return newData; 750 } 751 752 /** 753 * Push an array of items to the end of the array 754 * 755 * @param strict are we in strict mode 756 * @param item the item 757 * @return new array data (or same) 758 */ 759 public ArrayData push(final boolean strict, final Object item) { 760 return push(strict, new Object[] { item }); 761 } 762 763 /** 764 * Push an array of items to the end of the array 765 * 766 * @param strict are we in strict mode 767 * @param item the item 768 * @return new array data (or same) 769 */ 770 public ArrayData push(final boolean strict, final double item) { 771 return push(strict, item); 772 } 773 774 /** 775 * Push an array of items to the end of the array 776 * 777 * @param strict are we in strict mode 778 * @param item the item 779 * @return new array data (or same) 780 */ 781 public ArrayData push(final boolean strict, final long item) { 782 return push(strict, item); 783 } 784 785 /** 786 * Push an array of items to the end of the array 787 * 788 * @param strict are we in strict mode 789 * @param item the item 790 * @return new array data (or same) 791 */ 792 public ArrayData push(final boolean strict, final int item) { 793 return push(strict, item); 794 } 795 796 /** 797 * Pop an element from the end of the array 798 * 799 * @return the popped element 800 */ 801 public abstract Object pop(); 802 803 /** 804 * Slice out a section of the array and return that 805 * subsection as a new array data: [from, to) 806 * 807 * @param from start index 808 * @param to end index + 1 809 * @return new array data 810 */ 811 public abstract ArrayData slice(final long from, final long to); 812 813 /** 814 * Fast splice operation. This just modifies the array according to the number of 815 * elements added and deleted but does not insert the added elements. Throws 816 * {@code UnsupportedOperationException} if fast splice operation is not supported 817 * for this class or arguments. 818 * 819 * @param start start index of splice operation 820 * @param removed number of removed elements 821 * @param added number of added elements 822 * @throws UnsupportedOperationException if fast splice is not supported for the class or arguments. 823 * @return new arraydata, but this never happens because we always throw an exception 824 */ 825 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { 826 throw new UnsupportedOperationException(); 827 } 828 829 static Class<?> widestType(final Object... items) { 830 assert items.length > 0; 831 832 Class<?> widest = Integer.class; 833 834 for (final Object item : items) { 835 if (item == null) { 836 return Object.class; 837 } 838 final Class<?> itemClass = item.getClass(); 839 if (itemClass == Long.class) { 840 if (widest == Integer.class) { 841 widest = Long.class; 842 } 843 } else if (itemClass == Double.class || itemClass == Float.class) { 844 if (widest == Integer.class || widest == Long.class) { 845 widest = Double.class; 846 } 847 } else if (itemClass != Integer.class && itemClass != Short.class && itemClass != Byte.class) { 848 return Object.class; 849 } 850 } 851 852 return widest; 853 } 854 855 /** 856 * Return a list of keys in the array for the iterators 857 * @return iterator key list 858 */ 859 protected List<Long> computeIteratorKeys() { 860 final List<Long> keys = new ArrayList<>(); 861 862 final long len = length(); 863 for (long i = 0L; i < len; i = nextIndex(i)) { 864 if (has((int)i)) { 865 keys.add(i); 866 } 867 } 868 869 return keys; 870 } 871 872 /** 873 * Return an iterator that goes through all indexes of elements 874 * in this array. This includes those after array.length if 875 * they exist 876 * 877 * @return iterator 878 */ 879 public Iterator<Long> indexIterator() { 880 return computeIteratorKeys().iterator(); 881 } 882 883 /** 884 * Exponential growth function for array size when in 885 * need of resizing. 886 * 887 * @param size current size 888 * @return next size to allocate for internal array 889 */ 890 public static int nextSize(final int size) { 891 return alignUp(size + 1) * 2; 892 } 893 894 /** 895 * Return the next valid index from a given one. Subclassed for various 896 * array representation 897 * 898 * @param index the current index 899 * 900 * @return the next index 901 */ 902 long nextIndex(final long index) { 903 return index + 1; 904 } 905 906 static Object invoke(final MethodHandle mh, final Object arg) { 907 try { 908 return mh.invoke(arg); 909 } catch (final RuntimeException | Error e) { 910 throw e; 911 } catch (final Throwable t) { 912 throw new RuntimeException(t); 913 } 914 } 915 916 /** 917 * Find a fast call if one exists 918 * 919 * @param clazz array data class 920 * @param desc callsite descriptor 921 * @param request link request 922 * @return fast property getter if one is found 923 */ 924 public GuardedInvocation findFastCallMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { 925 return null; 926 } 927 928 /** 929 * Find a fast property getter if one exists 930 * 931 * @param clazz array data class 932 * @param desc callsite descriptor 933 * @param request link request 934 * @param operator operator 935 * @return fast property getter if one is found 936 */ 937 public GuardedInvocation findFastGetMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request, final String operator) { 938 return null; 939 } 940 941 /** 942 * Find a fast element getter if one exists 943 * 944 * @param clazz array data class 945 * @param desc callsite descriptor 946 * @param request link request 947 * @return fast index getter if one is found 948 */ 949 public GuardedInvocation findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value 950 return null; 951 } 952 953 /** 954 * Find a fast element setter if one exists 955 * 956 * @param clazz array data class 957 * @param desc callsite descriptor 958 * @param request link request 959 * @return fast index getter if one is found 960 */ 961 public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value 962 return null; 963 } 964} 965