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