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.staticCall; 29 30 import java.lang.invoke.MethodHandle; 31 import java.lang.invoke.MethodHandles; 32 import java.lang.reflect.Array; 33 import java.nio.ByteBuffer; 34 import java.util.ArrayList; 35 import java.util.Iterator; 36 import java.util.List; 37 import jdk.internal.dynalink.CallSiteDescriptor; 38 import jdk.internal.dynalink.linker.GuardedInvocation; 39 import jdk.internal.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 /** 75 * Immutable empty array to get ScriptObjects started. 76 * Use the same array and convert it to mutable as soon as it is modified 77 */ 78 private static class UntouchedArrayData extends ContinuousArrayData { 79 private UntouchedArrayData() { 80 super(0); 81 } 82 83 private ArrayData toRealArrayData() { 84 return toRealArrayData(0); 85 } 86 87 private ArrayData toRealArrayData(final int index) { 88 final IntArrayData newData = new IntArrayData(index + 1); 89 if (index == 0) { 90 return newData; 91 } 92 return new DeletedRangeArrayFilter(newData, 0, index); 93 } 94 95 @Override 96 public ContinuousArrayData copy() { 97 assert length() == 0; 98 return this; 99 } 100 101 @Override 102 public Object asArrayOfType(final Class<?> componentType) { 103 return Array.newInstance(componentType, 0); 104 } 105 106 @Override 107 public Object[] asObjectArray() { 108 return ScriptRuntime.EMPTY_ARRAY; 109 } 110 111 @Override 112 public ArrayData ensure(final long safeIndex) { 113 if (safeIndex > 0L) { 114 if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) { 115 return new SparseArrayData(this, safeIndex + 1); 116 } 117 //known to fit in int 118 return toRealArrayData((int)safeIndex); 119 } 120 return this; 121 } 122 123 @Override 124 public ArrayData convert(final Class<?> type) { 125 return toRealArrayData(0).convert(type); 126 } 127 128 @Override 129 public ArrayData delete(final int index) { 130 return new DeletedRangeArrayFilter(this, index, index); 131 } 132 133 @Override 134 public ArrayData delete(final long fromIndex, final long toIndex) { 135 return new DeletedRangeArrayFilter(this, fromIndex, toIndex); 136 } 137 138 @Override 139 public void shiftLeft(final int by) { 140 //nop, always empty or we wouldn't be of this class 141 } 142 143 @Override 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 194 public ArrayData push(final boolean strict, final Object item) { 195 return toRealArrayData().push(strict, item); 196 } 197 198 @Override 199 public ArrayData slice(final long from, final long to) { 200 return this; //empty 201 } 202 203 @Override 204 public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { 205 return otherData.copy(); 206 } 207 208 //no need to override fastPopInt, as the default behavior is to throw classcast exception so we 209 //can relink and return an undefined, this is the IntArrayData default behavior 210 @Override 211 public String toString() { 212 return getClass().getSimpleName(); 213 } 214 215 @Override 216 public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { 217 return null; 218 } 219 220 @Override 221 public MethodHandle getElementSetter(final Class<?> elementType) { 222 return null; 223 } 224 225 @Override 226 public Class<?> getElementType() { 227 return int.class; 228 } 229 230 @Override 231 public Class<?> getBoxedElementType() { 232 return Integer.class; 233 } 234 } 235 236 /** 237 * Constructor 238 * @param length Virtual length of the array. 239 */ 240 protected ArrayData(final long length) { 241 this.length = length; 242 } 243 244 /** 245 * Factory method for unspecified array - start as int 246 * @return ArrayData 247 */ 248 public static ArrayData initialArray() { 249 return new IntArrayData(); 250 } 251 252 /** 253 * Unwarranted thrower 254 * 255 * @param data array data 256 * @param programPoint program point 257 * @param index array index 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 */ 342 public static ArrayData allocate(final ByteBuffer buf) { 343 return new ByteBufferArrayData(buf); 344 } 345 346 /** 347 * Apply a freeze filter to an ArrayData. 348 * 349 * @param underlying the underlying ArrayData to wrap in the freeze filter 350 * @return the frozen ArrayData 351 */ 352 public static ArrayData freeze(final ArrayData underlying) { 353 return new FrozenArrayFilter(underlying); 354 } 355 356 /** 357 * Apply a seal filter to an ArrayData. 358 * 359 * @param underlying the underlying ArrayData to wrap in the seal filter 360 * @return the sealed ArrayData 361 */ 362 public static ArrayData seal(final ArrayData underlying) { 363 return new SealedArrayFilter(underlying); 364 } 365 366 /** 367 * Prevent this array from being extended 368 * 369 * @param underlying the underlying ArrayData to wrap in the non extensible filter 370 * @return new array data, filtered 371 */ 372 public static ArrayData preventExtension(final ArrayData underlying) { 373 return new NonExtensibleArrayFilter(underlying); 374 } 375 376 /** 377 * Prevent this array from having its length reset 378 * 379 * @param underlying the underlying ArrayDAta to wrap in the non extensible filter 380 * @return new array data, filtered 381 */ 382 public static ArrayData setIsLengthNotWritable(final ArrayData underlying) { 383 return new LengthNotWritableFilter(underlying); 384 } 385 386 /** 387 * Return the length of the array data. This may differ from the actual 388 * length of the array this wraps as length may be set or gotten as any 389 * other JavaScript Property 390 * 391 * Even though a JavaScript array length may be a long, we only store 392 * int parts for the optimized array access. For long lengths there 393 * are special cases anyway. 394 * 395 * TODO: represent arrays with "long" lengths as a special ArrayData 396 * that basically maps to the ScriptObject directly for better abstraction 397 * 398 * @return the length of the data 399 */ 400 public final long length() { 401 return length; 402 } 403 404 /** 405 * Return a copy of the array that can be modified without affecting this instance. 406 * It is safe to return themselves for immutable subclasses. 407 * 408 * @return a new array 409 */ 410 public abstract ArrayData copy(); 411 412 /** 413 * Return a copy of the array data as an Object array. 414 * 415 * @return an Object array 416 */ 417 public abstract Object[] asObjectArray(); 418 419 /** 420 * Return a copy of the array data as an array of the specified type. 421 * 422 * @param componentType the type of elements in the array 423 * @return and array of the given type 424 */ 425 public Object asArrayOfType(final Class<?> componentType) { 426 return JSType.convertArray(asObjectArray(), componentType); 427 } 428 429 /** 430 * Set the length of the data array 431 * 432 * @param length the new length for the data array 433 */ 434 public void setLength(final long length) { 435 this.length = length; 436 } 437 438 /** 439 * Increase length by 1 440 * @return the new length, not the old one (i.e. pre-increment) 441 */ 442 protected final long increaseLength() { 443 return ++this.length; 444 } 445 446 /** 447 * Decrease length by 1. 448 * @return the new length, not the old one (i.e. pre-decrement) 449 */ 450 protected final long decreaseLength() { 451 return --this.length; 452 } 453 454 /** 455 * Shift the array data left 456 * 457 * TODO: explore start at an index and not at zero, to make these operations 458 * even faster. Offset everything from the index. Costs memory but is probably 459 * worth it 460 * 461 * @param by offset to shift 462 */ 463 public abstract void shiftLeft(final int by); 464 465 /** 466 * Shift the array right 467 * 468 * @param by offset to shift 469 470 * @return New arraydata (or same) 471 */ 472 public abstract ArrayData shiftRight(final int by); 473 474 /** 475 * Ensure that the given index exists and won't fail in a subsequent access. 476 * If {@code safeIndex} is equal or greater than the current length the length is 477 * updated to {@code safeIndex + 1}. 478 * 479 * @param safeIndex the index to ensure wont go out of bounds 480 * @return new array data (or same) 481 */ 482 public abstract ArrayData ensure(final long safeIndex); 483 484 /** 485 * Shrink the array to a new length, may or may not retain the 486 * inner array 487 * 488 * @param newLength new max length 489 * 490 * @return new array data (or same) 491 */ 492 public abstract ArrayData shrink(final long newLength); 493 494 /** 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 535 /** 536 * Set an empty value for a given range. Should only affect Object array. 537 * 538 * @param lo range low end 539 * @param hi range high end 540 * @return new array data (or same) 541 */ 542 public ArrayData setEmpty(final long lo, final long hi) { 543 // Do nothing. 544 return this; 545 } 546 547 /** 548 * Get an int value from a given index 549 * 550 * @param index the index 551 * @return the value 552 */ 553 public abstract int getInt(final int index); 554 555 /** 556 * Returns the optimistic type of this array data. Basically, when an array data object needs to throw an 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 /** 597 * Get an Object value from a given index 598 * 599 * @param index the index 600 * @return the value 601 */ 602 public abstract Object getObject(final int index); 603 604 /** 605 * Tests to see if an entry exists (avoids boxing.) 606 * @param index the index 607 * @return true if entry exists 608 */ 609 public abstract boolean has(final int index); 610 611 /** 612 * Returns if element at specific index can be deleted or not. 613 * 614 * @param index the index of the element 615 * @param strict are we in strict mode 616 * 617 * @return true if element can be deleted 618 */ 619 public boolean canDelete(final int index, final boolean strict) { 620 return true; 621 } 622 623 /** 624 * Returns if element at specific index can be deleted or not. 625 * 626 * @param longIndex the index 627 * @param strict are we in strict mode 628 * 629 * @return true if range can be deleted 630 */ 631 public boolean canDelete(final long longIndex, final boolean strict) { 632 return true; 633 } 634 635 /** 636 * Delete a range from the array if {@code fromIndex} is less than or equal to {@code toIndex} 637 * and the array supports deletion. 638 * 639 * @param fromIndex the start index (inclusive) 640 * @param toIndex the end index (inclusive) 641 * @param strict are we in strict mode 642 * @return an array with the range deleted, or this array if no deletion took place 643 */ 644 public final ArrayData safeDelete(final long fromIndex, final long toIndex, final boolean strict) { 645 if (fromIndex <= toIndex && canDelete(fromIndex, strict)) { 646 return delete(fromIndex, toIndex); 647 } 648 return this; 649 } 650 651 /** 652 * Returns property descriptor for element at a given index 653 * 654 * @param global the global object 655 * @param index the index 656 * 657 * @return property descriptor for element 658 */ 659 public PropertyDescriptor getDescriptor(final Global global, final int index) { 660 return global.newDataDescriptor(getObject(index), true, true, true); 661 } 662 663 /** 664 * Delete an array value at the given index, substituting 665 * for an undefined 666 * 667 * @param index the index 668 * @return new array data (or same) 669 */ 670 public abstract ArrayData delete(final int index); 671 672 /** 673 * Delete a given range from this array; 674 * 675 * @param fromIndex from index (inclusive) 676 * @param toIndex to index (inclusive) 677 * 678 * @return new ArrayData after deletion 679 */ 680 public abstract ArrayData delete(final long fromIndex, final long toIndex); 681 682 /** 683 * Convert the ArrayData to one with a different element type 684 * Currently Arrays are not collapsed to narrower types, just to 685 * wider ones. Attempting to narrow an array will assert 686 * 687 * @param type new element type 688 * @return new array data 689 */ 690 public abstract ArrayData convert(final Class<?> type); 691 692 /** 693 * Push an array of items to the end of the array 694 * 695 * @param strict are we in strict mode 696 * @param items the items 697 * @return new array data (or same) 698 */ 699 public ArrayData push(final boolean strict, final Object... items) { 700 if (items.length == 0) { 701 return this; 702 } 703 704 final Class<?> widest = widestType(items); 705 706 ArrayData newData = convert(widest); 707 long pos = newData.length; 708 for (final Object item : items) { 709 newData = newData.ensure(pos); //avoid sparse array 710 newData.set((int)pos++, item, strict); 711 } 712 return newData; 713 } 714 715 /** 716 * Push an array of items to the end of the array 717 * 718 * @param strict are we in strict mode 719 * @param item the item 720 * @return new array data (or same) 721 */ 722 public ArrayData push(final boolean strict, final Object item) { 723 return push(strict, new Object[] { item }); 724 } 725 726 /** 727 * Pop an element from the end of the array 728 * 729 * @return the popped element 730 */ 731 public abstract Object pop(); 732 733 /** 734 * Slice out a section of the array and return that 735 * subsection as a new array data: [from, to) 736 * 737 * @param from start index 738 * @param to end index + 1 739 * @return new array data 740 */ 741 public abstract ArrayData slice(final long from, final long to); 742 743 /** 744 * Fast splice operation. This just modifies the array according to the number of 745 * elements added and deleted but does not insert the added elements. Throws 746 * {@code UnsupportedOperationException} if fast splice operation is not supported 747 * for this class or arguments. 748 * 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)) { 791 keys.add(i); 792 } 793 } 794 795 return keys; 796 } 797 798 /** 799 * Return an iterator that goes through all indexes of elements 800 * in this array. This includes those after array.length if 801 * they exist 802 * 803 * @return iterator 804 */ 805 public Iterator<Long> indexIterator() { 806 return computeIteratorKeys().iterator(); 807 } 808 809 /** 810 * Exponential growth function for array size when in 811 * need of resizing. 812 * 813 * @param size current size 814 * @return next size to allocate for internal array 815 */ 816 public static int nextSize(final int size) { 817 return alignUp(size + 1) * 2; 818 } 819 820 /** 821 * Return the next valid index from a given one. Subclassed for various 822 * array representation 823 * 824 * @param index the current index 825 * 826 * @return the next index 827 */ 828 long nextIndex(final long index) { 829 return index + 1; 830 } 831 832 static Object invoke(final MethodHandle mh, final Object arg) { 833 try { 834 return mh.invoke(arg); 835 } catch (final RuntimeException | Error e) { 836 throw e; 837 } catch (final Throwable t) { 838 throw new RuntimeException(t); 839 } 840 } 841 842 /** 843 * Find a fast call if one exists 844 * 845 * @param clazz array data class 846 * @param desc callsite descriptor 847 * @param request link request 848 * @return fast property getter if one is found 849 */ 850 public GuardedInvocation findFastCallMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { 851 return null; 852 } 853 854 /** 855 * Find a fast property getter if one exists 856 * 857 * @param clazz array data class 858 * @param desc callsite descriptor 859 * @param request link request 860 * @param operator operator 861 * @return fast property getter if one is found 862 */ 863 public GuardedInvocation findFastGetMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request, final String operator) { 864 return null; 865 } 866 867 /** 868 * Find a fast element getter if one exists 869 * 870 * @param clazz array data class 871 * @param desc callsite descriptor 872 * @param request link request 873 * @return fast index getter if one is found 874 */ 875 public GuardedInvocation findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value 876 return null; 877 } 878 879 /** 880 * Find a fast element setter if one exists 881 * 882 * @param clazz array data class 883 * @param desc callsite descriptor 884 * @param request link request 885 * @return fast index getter if one is found 886 */ 887 public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value 888 return null; 889 } 890 }