ArrayData.java revision 1073:06c06c8443fd
1234353Sdim/* 2218885Sdim * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3218885Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4218885Sdim * 5218885Sdim * This code is free software; you can redistribute it and/or modify it 6218885Sdim * under the terms of the GNU General Public License version 2 only, as 7218885Sdim * published by the Free Software Foundation. Oracle designates this 8218885Sdim * particular file as subject to the "Classpath" exception as provided 9218885Sdim * by Oracle in the LICENSE file that accompanied this code. 10218885Sdim * 11218885Sdim * This code is distributed in the hope that it will be useful, but WITHOUT 12218885Sdim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13218885Sdim * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14218885Sdim * version 2 for more details (a copy is included in the LICENSE file that 15218885Sdim * accompanied this code). 16218885Sdim * 17218885Sdim * You should have received a copy of the GNU General Public License version 18218885Sdim * 2 along with this work; if not, write to the Free Software Foundation, 19218885Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20218885Sdim * 21218885Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22249423Sdim * or visit www.oracle.com if you need additional information or have any 23249423Sdim * questions. 24249423Sdim */ 25218885Sdim 26218885Sdimpackage jdk.nashorn.internal.runtime.arrays; 27218885Sdim 28218885Sdimimport static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; 29218885Sdimimport java.lang.invoke.MethodHandle; 30218885Sdimimport java.lang.invoke.MethodHandles; 31218885Sdimimport java.lang.reflect.Array; 32234353Sdimimport java.nio.ByteBuffer; 33218885Sdimimport jdk.internal.dynalink.CallSiteDescriptor; 34218885Sdimimport jdk.internal.dynalink.linker.GuardedInvocation; 35218885Sdimimport jdk.internal.dynalink.linker.LinkRequest; 36218885Sdimimport jdk.nashorn.internal.codegen.CompilerConstants; 37218885Sdimimport jdk.nashorn.internal.codegen.types.Type; 38218885Sdimimport jdk.nashorn.internal.objects.Global; 39218885Sdimimport jdk.nashorn.internal.runtime.JSType; 40218885Sdimimport jdk.nashorn.internal.runtime.PropertyDescriptor; 41218885Sdimimport jdk.nashorn.internal.runtime.ScriptRuntime; 42218885Sdimimport jdk.nashorn.internal.runtime.UnwarrantedOptimismException; 43218885Sdim 44218885Sdim/** 45218885Sdim * ArrayData - abstraction for wrapping array elements 46218885Sdim */ 47218885Sdimpublic abstract class ArrayData { 48218885Sdim /** Minimum chunk size for underlying arrays */ 49218885Sdim protected static final int CHUNK_SIZE = 32; 50218885Sdim 51218885Sdim /** Mask for getting a chunk */ 52218885Sdim protected static final int CHUNK_MASK = CHUNK_SIZE - 1; 53218885Sdim 54218885Sdim /** Untouched data - still link callsites as IntArrayData, but expands to 55218885Sdim * a proper ArrayData when we try to write to it */ 56218885Sdim public static final ArrayData EMPTY_ARRAY = new UntouchedArrayData(); 57218885Sdim 58218885Sdim /** 59218885Sdim * Immutable empty array to get ScriptObjects started. 60218885Sdim * Use the same array and convert it to mutable as soon as it is modified 61218885Sdim */ 62218885Sdim private static class UntouchedArrayData extends ContinuousArrayData { 63218885Sdim private UntouchedArrayData() { 64218885Sdim this(0); 65218885Sdim } 66218885Sdim 67218885Sdim private UntouchedArrayData(final int length) { 68218885Sdim super(length); 69218885Sdim } 70218885Sdim 71218885Sdim private ArrayData toRealArrayData() { 72218885Sdim return toRealArrayData(0); 73218885Sdim } 74218885Sdim 75218885Sdim private ArrayData toRealArrayData(final int index) { 76218885Sdim final IntArrayData newData = new IntArrayData(index + 1); 77218885Sdim if (index == 0) { 78218885Sdim return newData; 79218885Sdim } 80218885Sdim return new DeletedRangeArrayFilter(newData, 0, index); 81218885Sdim } 82218885Sdim 83218885Sdim @Override 84218885Sdim public ContinuousArrayData copy() { 85218885Sdim return new UntouchedArrayData((int)length); 86218885Sdim } 87218885Sdim 88218885Sdim @Override 89218885Sdim public Object asArrayOfType(final Class<?> componentType) { 90218885Sdim return Array.newInstance(componentType, 0); 91218885Sdim } 92218885Sdim 93218885Sdim @Override 94218885Sdim public Object[] asObjectArray() { 95218885Sdim return ScriptRuntime.EMPTY_ARRAY; 96218885Sdim } 97218885Sdim 98218885Sdim @Override 99218885Sdim public ArrayData ensure(final long safeIndex) { 100218885Sdim if (safeIndex > 0L) { 101218885Sdim return toRealArrayData((int)safeIndex).ensure(safeIndex); 102218885Sdim } 103218885Sdim return this; 104218885Sdim } 105218885Sdim 106218885Sdim @Override 107218885Sdim public ArrayData convert(final Class<?> type) { 108218885Sdim return toRealArrayData(0).convert(type); 109218885Sdim } 110218885Sdim 111218885Sdim @Override 112218885Sdim public void shiftLeft(final int by) { 113218885Sdim //nop, always empty or we wouldn't be of this class 114218885Sdim } 115218885Sdim 116218885Sdim @Override 117218885Sdim public ArrayData shiftRight(final int by) { 118218885Sdim return this; //always empty or we wouldn't be of this class 119218885Sdim } 120218885Sdim 121218885Sdim @Override 122218885Sdim public ArrayData shrink(final long newLength) { 123218885Sdim return this; 124218885Sdim } 125218885Sdim 126218885Sdim @Override 127218885Sdim public ArrayData set(final int index, final Object value, final boolean strict) { 128218885Sdim return toRealArrayData(index).set(index, value, strict); 129218885Sdim } 130218885Sdim 131218885Sdim @Override 132218885Sdim public ArrayData set(final int index, final int value, final boolean strict) { 133218885Sdim return toRealArrayData(index).set(index, value, strict); 134218885Sdim } 135218885Sdim 136218885Sdim @Override 137218885Sdim public ArrayData set(final int index, final long value, final boolean strict) { 138218885Sdim return toRealArrayData(index).set(index, value, strict); 139218885Sdim } 140218885Sdim 141218885Sdim @Override 142218885Sdim public ArrayData set(final int index, final double value, final boolean strict) { 143234353Sdim return toRealArrayData(index).set(index, value, strict); 144218885Sdim } 145218885Sdim 146218885Sdim @Override 147218885Sdim public int getInt(final int index) { 148218885Sdim throw new ArrayIndexOutOfBoundsException(index); //empty 149218885Sdim } 150218885Sdim 151218885Sdim @Override 152218885Sdim public long getLong(final int index) { 153218885Sdim throw new ArrayIndexOutOfBoundsException(index); //empty 154218885Sdim } 155218885Sdim 156218885Sdim @Override 157218885Sdim public double getDouble(final int index) { 158218885Sdim throw new ArrayIndexOutOfBoundsException(index); //empty 159218885Sdim } 160218885Sdim 161218885Sdim @Override 162218885Sdim public Object getObject(final int index) { 163218885Sdim throw new ArrayIndexOutOfBoundsException(index); //empty 164218885Sdim } 165218885Sdim 166218885Sdim @Override 167218885Sdim public boolean has(final int index) { 168218885Sdim return false; //empty 169218885Sdim } 170218885Sdim 171218885Sdim @Override 172218885Sdim public ArrayData delete(final int index) { 173218885Sdim return new DeletedRangeArrayFilter(this, index, index); 174218885Sdim } 175218885Sdim 176218885Sdim @Override 177218885Sdim public ArrayData delete(final long fromIndex, final long toIndex) { 178218885Sdim return new DeletedRangeArrayFilter(this, fromIndex, toIndex); 179218885Sdim } 180218885Sdim 181218885Sdim @Override 182218885Sdim public Object pop() { 183218885Sdim return ScriptRuntime.UNDEFINED; 184218885Sdim } 185218885Sdim 186218885Sdim @Override 187218885Sdim public ArrayData push(final boolean strict, final Object item) { 188218885Sdim return toRealArrayData().push(strict, item); 189218885Sdim } 190218885Sdim 191218885Sdim @Override 192218885Sdim public ArrayData slice(final long from, final long to) { 193218885Sdim return this; //empty 194218885Sdim } 195218885Sdim 196218885Sdim @Override 197218885Sdim public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) { 198218885Sdim return otherData.copy(); 199218885Sdim } 200218885Sdim 201218885Sdim //no need to override fastPopInt, as the default behavior is to throw classcast exception so we 202218885Sdim //can relink and return an undefined, this is the IntArrayData default behavior 203218885Sdim @Override 204218885Sdim public String toString() { 205218885Sdim return getClass().getSimpleName(); 206218885Sdim } 207218885Sdim 208218885Sdim @Override 209218885Sdim public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) { 210218885Sdim return null; 211218885Sdim } 212218885Sdim 213218885Sdim @Override 214218885Sdim public MethodHandle getElementSetter(final Class<?> elementType) { 215218885Sdim return null; 216218885Sdim } 217218885Sdim 218218885Sdim @Override 219218885Sdim public Class<?> getElementType() { 220218885Sdim return int.class; 221218885Sdim } 222218885Sdim 223218885Sdim @Override 224243830Sdim public Class<?> getBoxedElementType() { 225249423Sdim return Integer.class; 226249423Sdim } 227249423Sdim }; 228249423Sdim 229249423Sdim /** 230249423Sdim * Length of the array data. Not necessarily length of the wrapped array. 231249423Sdim */ 232249423Sdim protected long length; 233249423Sdim 234249423Sdim /** 235249423Sdim * Method handle to throw an {@link UnwarrantedOptimismException} when getting an element 236249423Sdim * of the wrong type 237249423Sdim */ 238249423Sdim protected static final CompilerConstants.Call THROW_UNWARRANTED = staticCall(MethodHandles.lookup(), ArrayData.class, "throwUnwarranted", void.class, ArrayData.class, int.class, int.class); 239249423Sdim 240249423Sdim /** 241249423Sdim * Constructor 242249423Sdim * @param length Virtual length of the array. 243249423Sdim */ 244249423Sdim protected ArrayData(final long length) { 245249423Sdim this.length = length; 246249423Sdim } 247249423Sdim 248249423Sdim /** 249249423Sdim * Factory method for unspecified array - start as int 250249423Sdim * @return ArrayData 251249423Sdim */ 252249423Sdim public final static ArrayData initialArray() { 253249423Sdim return new IntArrayData(); 254249423Sdim } 255249423Sdim 256249423Sdim /** 257249423Sdim * Unwarranted thrower 258249423Sdim * 259249423Sdim * @param data array data 260249423Sdim * @param programPoint program point 261249423Sdim * @param index array index 262249423Sdim */ 263249423Sdim protected static void throwUnwarranted(final ArrayData data, final int programPoint, final int index) { 264249423Sdim throw new UnwarrantedOptimismException(data.getObject(index), programPoint); 265249423Sdim } 266249423Sdim 267249423Sdim /** 268249423Sdim * Align an array size up to the nearest array chunk size 269249423Sdim * @param size size required 270249423Sdim * @return size given, always >= size 271249423Sdim */ 272249423Sdim protected final static int alignUp(final int size) { 273249423Sdim return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1); 274249423Sdim } 275249423Sdim 276249423Sdim /** 277249423Sdim * Factory method for unspecified array with given length - start as int array data 278249423Sdim * 279249423Sdim * @param length the initial length 280249423Sdim * @return ArrayData 281249423Sdim */ 282249423Sdim public static final ArrayData allocate(final int length) { 283249423Sdim if (length == 0) { 284249423Sdim return new IntArrayData(); 285249423Sdim } else if (length >= SparseArrayData.MAX_DENSE_LENGTH) { 286249423Sdim return new SparseArrayData(EMPTY_ARRAY, length); 287243830Sdim } else { 288249423Sdim return new DeletedRangeArrayFilter(new IntArrayData(length), 0, length - 1); 289249423Sdim } 290243830Sdim } 291249423Sdim 292243830Sdim /** 293243830Sdim * Factory method for unspecified given an array object 294243830Sdim * 295243830Sdim * @param array the array 296243830Sdim * @return ArrayData wrapping this array 297243830Sdim */ 298 public static final ArrayData allocate(final Object array) { 299 final Class<?> clazz = array.getClass(); 300 301 if (clazz == int[].class) { 302 return new IntArrayData((int[])array, ((int[])array).length); 303 } else if (clazz == long[].class) { 304 return new LongArrayData((long[])array, ((long[])array).length); 305 } else if (clazz == double[].class) { 306 return new NumberArrayData((double[])array, ((double[])array).length); 307 } else { 308 return new ObjectArrayData((Object[])array, ((Object[])array).length); 309 } 310 } 311 312 /** 313 * Allocate an ArrayData wrapping a given array 314 * 315 * @param array the array to use for initial elements 316 * @return the ArrayData 317 */ 318 public static final ArrayData allocate(final int[] array) { 319 return new IntArrayData(array, array.length); 320 } 321 322 /** 323 * Allocate an ArrayData wrapping a given array 324 * 325 * @param array the array to use for initial elements 326 * @return the ArrayData 327 */ 328 public static final ArrayData allocate(final long[] array) { 329 return new LongArrayData(array, array.length); 330 } 331 332 /** 333 * Allocate an ArrayData wrapping a given array 334 * 335 * @param array the array to use for initial elements 336 * @return the ArrayData 337 */ 338 public static final ArrayData allocate(final double[] array) { 339 return new NumberArrayData(array, array.length); 340 } 341 342 /** 343 * Allocate an ArrayData wrapping a given array 344 * 345 * @param array the array to use for initial elements 346 * @return the ArrayData 347 */ 348 public static final ArrayData allocate(final Object[] array) { 349 return new ObjectArrayData(array, array.length); 350 } 351 352 /** 353 * Allocate an ArrayData wrapping a given nio ByteBuffer 354 * 355 * @param buf the nio ByteBuffer to wrap 356 * @return the ArrayData 357 */ 358 public static final ArrayData allocate(final ByteBuffer buf) { 359 return new ByteBufferArrayData(buf); 360 } 361 362 /** 363 * Apply a freeze filter to an ArrayData. 364 * 365 * @param underlying the underlying ArrayData to wrap in the freeze filter 366 * @return the frozen ArrayData 367 */ 368 public static final ArrayData freeze(final ArrayData underlying) { 369 return new FrozenArrayFilter(underlying); 370 } 371 372 /** 373 * Apply a seal filter to an ArrayData. 374 * 375 * @param underlying the underlying ArrayData to wrap in the seal filter 376 * @return the sealed ArrayData 377 */ 378 public static final ArrayData seal(final ArrayData underlying) { 379 return new SealedArrayFilter(underlying); 380 } 381 382 /** 383 * Prevent this array from being extended 384 * 385 * @param underlying the underlying ArrayData to wrap in the non extensible filter 386 * @return new array data, filtered 387 */ 388 public static final ArrayData preventExtension(final ArrayData underlying) { 389 return new NonExtensibleArrayFilter(underlying); 390 } 391 392 /** 393 * Return the length of the array data. This may differ from the actual 394 * length of the array this wraps as length may be set or gotten as any 395 * other JavaScript Property 396 * 397 * Even though a JavaScript array length may be a long, we only store 398 * int parts for the optimized array access. For long lengths there 399 * are special cases anyway. 400 * 401 * TODO: represent arrays with "long" lengths as a special ArrayData 402 * that basically maps to the ScriptObject directly for better abstraction 403 * 404 * @return the length of the data 405 */ 406 public final long length() { 407 return length; 408 } 409 410 /** 411 * Return a copy of the array that can be modified without affecting this instance. 412 * It is safe to return themselves for immutable subclasses. 413 * 414 * @return a new array 415 */ 416 public abstract ArrayData copy(); 417 418 /** 419 * Return a copy of the array data as an Object array. 420 * 421 * @return an Object array 422 */ 423 public abstract Object[] asObjectArray(); 424 425 /** 426 * Return a copy of the array data as an array of the specified type. 427 * 428 * @param componentType the type of elements in the array 429 * @return and array of the given type 430 */ 431 public Object asArrayOfType(final Class<?> componentType) { 432 return JSType.convertArray(asObjectArray(), componentType); 433 } 434 435 /** 436 * Set the length of the data array 437 * 438 * @param length the new length for the data array 439 */ 440 public void setLength(final long length) { 441 this.length = length; 442 } 443 444 /** 445 * Shift the array data left 446 * 447 * TODO: explore start at an index and not at zero, to make these operations 448 * even faster. Offset everything from the index. Costs memory but is probably 449 * worth it 450 * 451 * @param by offset to shift 452 */ 453 public abstract void shiftLeft(int by); 454 455 /** 456 * Shift the array right 457 * 458 * @param by offset to shift 459 460 * @return New arraydata (or same) 461 */ 462 public abstract ArrayData shiftRight(int by); 463 464 /** 465 * Ensure that the given index exists and won't fail subsequent 466 * 467 * @param safeIndex the index to ensure wont go out of bounds 468 * @return new array data (or same) 469 */ 470 public abstract ArrayData ensure(long safeIndex); 471 472 /** 473 * Shrink the array to a new length, may or may not retain the 474 * inner array 475 * 476 * @param newLength new max length 477 * 478 * @return new array data (or same) 479 */ 480 public abstract ArrayData shrink(long newLength); 481 482 /** 483 * Set an object value at a given index 484 * 485 * @param index the index 486 * @param value the value 487 * @param strict are we in strict mode 488 * @return new array data (or same) 489 */ 490 public abstract ArrayData set(int index, Object value, boolean strict); 491 492 /** 493 * Set an int value at a given index 494 * 495 * @param index the index 496 * @param value the value 497 * @param strict are we in strict mode 498 * @return new array data (or same) 499 */ 500 public abstract ArrayData set(int index, int value, boolean strict); 501 502 /** 503 * Set a long value at a given index 504 * 505 * @param index the index 506 * @param value the value 507 * @param strict are we in strict mode 508 * @return new array data (or same) 509 */ 510 public abstract ArrayData set(int index, long value, boolean strict); 511 512 /** 513 * Set an double value at a given index 514 * 515 * @param index the index 516 * @param value the value 517 * @param strict are we in strict mode 518 * @return new array data (or same) 519 */ 520 public abstract ArrayData set(int index, double value, boolean strict); 521 522 /** 523 * Set an empty value at a given index. Should only affect Object array. 524 * 525 * @param index the index 526 * @return new array data (or same) 527 */ 528 public ArrayData setEmpty(final int index) { 529 // Do nothing. 530 return this; 531 } 532 533 /** 534 * Set an empty value for a given range. Should only affect Object array. 535 * 536 * @param lo range low end 537 * @param hi range high end 538 * @return new array data (or same) 539 */ 540 public ArrayData setEmpty(final long lo, final long hi) { 541 // Do nothing. 542 return this; 543 } 544 545 /** 546 * Get an int value from a given index 547 * 548 * @param index the index 549 * @return the value 550 */ 551 public abstract int getInt(int index); 552 553 /** 554 * Returns the optimistic type of this array data. Basically, when an array data object needs to throw an 555 * {@link UnwarrantedOptimismException}, this type is used as the actual type of the return value. 556 * @return the optimistic type of this array data. 557 */ 558 public Type getOptimisticType() { 559 return Type.OBJECT; 560 } 561 562 /** 563 * Get optimistic int - default is that it's impossible. Overridden 564 * by arrays that actually represents ints 565 * 566 * @param index the index 567 * @param programPoint program point 568 * @return the value 569 */ 570 public int getIntOptimistic(final int index, final int programPoint) { 571 throw new UnwarrantedOptimismException(getObject(index), programPoint, getOptimisticType()); 572 } 573 574 /** 575 * Get a long value from a given index 576 * 577 * @param index the index 578 * @return the value 579 */ 580 public abstract long getLong(int index); 581 582 /** 583 * Get optimistic long - default is that it's impossible. Overridden 584 * by arrays that actually represents longs or narrower 585 * 586 * @param index the index 587 * @param programPoint program point 588 * @return the value 589 */ 590 public long getLongOptimistic(final int index, final int programPoint) { 591 throw new UnwarrantedOptimismException(getObject(index), programPoint, getOptimisticType()); 592 } 593 594 /** 595 * Get a double value from a given index 596 * 597 * @param index the index 598 * @return the value 599 */ 600 public abstract double getDouble(int index); 601 602 /** 603 * Get optimistic double - default is that it's impossible. Overridden 604 * by arrays that actually represents doubles or narrower 605 * 606 * @param index the index 607 * @param programPoint program point 608 * @return the value 609 */ 610 public double getDoubleOptimistic(final int index, final int programPoint) { 611 throw new UnwarrantedOptimismException(getObject(index), programPoint, getOptimisticType()); 612 } 613 614 /** 615 * Get an Object value from a given index 616 * 617 * @param index the index 618 * @return the value 619 */ 620 public abstract Object getObject(int index); 621 622 /** 623 * Tests to see if an entry exists (avoids boxing.) 624 * @param index the index 625 * @return true if entry exists 626 */ 627 public abstract boolean has(int index); 628 629 /** 630 * Returns if element at specific index can be deleted or not. 631 * 632 * @param index the index of the element 633 * @param strict are we in strict mode 634 * 635 * @return true if element can be deleted 636 */ 637 public boolean canDelete(final int index, final boolean strict) { 638 return true; 639 } 640 641 /** 642 * Returns if element at specific index range can be deleted or not. 643 * 644 * @param fromIndex the start index 645 * @param toIndex the end index 646 * @param strict are we in strict mode 647 * 648 * @return true if range can be deleted 649 */ 650 public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) { 651 return true; 652 } 653 654 /** 655 * Returns property descriptor for element at a given index 656 * 657 * @param global the global object 658 * @param index the index 659 * 660 * @return property descriptor for element 661 */ 662 public PropertyDescriptor getDescriptor(final Global global, final int index) { 663 return global.newDataDescriptor(getObject(index), true, true, true); 664 } 665 666 /** 667 * Delete an array value at the given index, substituting 668 * for an undefined 669 * 670 * @param index the index 671 * @return new array data (or same) 672 */ 673 public abstract ArrayData delete(int index); 674 675 /** 676 * Delete a given range from this array; 677 * 678 * @param fromIndex from index (inclusive) 679 * @param toIndex to index (inclusive) 680 * 681 * @return new ArrayData after deletion 682 */ 683 public abstract ArrayData delete(long fromIndex, long toIndex); 684 685 /** 686 * Convert the ArrayData to one with a different element type 687 * Currently Arrays are not collapsed to narrower types, just to 688 * wider ones. Attempting to narrow an array will assert 689 * 690 * @param type new element type 691 * @return new array data 692 */ 693 public abstract ArrayData convert(Class<?> type); 694 695 /** 696 * Push an array of items to the end of the array 697 * 698 * @param strict are we in strict mode 699 * @param items the items 700 * @return new array data (or same) 701 */ 702 public ArrayData push(final boolean strict, final Object... items) { 703 if (items.length == 0) { 704 return this; 705 } 706 707 final Class<?> widest = widestType(items); 708 709 ArrayData newData = convert(widest); 710 long pos = newData.length; 711 for (final Object item : items) { 712 newData = newData.ensure(pos); //avoid sparse array 713 newData.set((int)pos++, item, strict); 714 } 715 return newData; 716 } 717 718 /** 719 * Push an array of items to the end of the array 720 * 721 * @param strict are we in strict mode 722 * @param item the item 723 * @return new array data (or same) 724 */ 725 public ArrayData push(final boolean strict, final Object item) { 726 return push(strict, new Object[] { item }); 727 } 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 item the item 734 * @return new array data (or same) 735 */ 736 public ArrayData push(final boolean strict, final double item) { 737 return push(strict, item); 738 } 739 740 /** 741 * Push an array of items to the end of the array 742 * 743 * @param strict are we in strict mode 744 * @param item the item 745 * @return new array data (or same) 746 */ 747 public ArrayData push(final boolean strict, final long item) { 748 return push(strict, item); 749 } 750 751 /** 752 * Push an array of items to the end of the array 753 * 754 * @param strict are we in strict mode 755 * @param item the item 756 * @return new array data (or same) 757 */ 758 public ArrayData push(final boolean strict, final int item) { 759 return push(strict, item); 760 } 761 762 /** 763 * Pop an element from the end of the array 764 * 765 * @return the popped element 766 */ 767 public abstract Object pop(); 768 769 /** 770 * Slice out a section of the array and return that 771 * subsection as a new array data: [from, to) 772 * 773 * @param from start index 774 * @param to end index + 1 775 * @return new array data 776 */ 777 public abstract ArrayData slice(long from, long to); 778 779 /** 780 * Fast splice operation. This just modifies the array according to the number of 781 * elements added and deleted but does not insert the added elements. Throws 782 * {@code UnsupportedOperationException} if fast splice operation is not supported 783 * for this class or arguments. 784 * 785 * @param start start index of splice operation 786 * @param removed number of removed elements 787 * @param added number of added elements 788 * @throws UnsupportedOperationException if fast splice is not supported for the class or arguments. 789 * @return new arraydata, but this never happens because we always throw an exception 790 */ 791 public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException { 792 throw new UnsupportedOperationException(); 793 } 794 795 static Class<?> widestType(final Object... items) { 796 assert items.length > 0; 797 798 Class<?> widest = Integer.class; 799 800 for (final Object item : items) { 801 if (item == null) { 802 return Object.class; 803 } 804 final Class<?> itemClass = item.getClass(); 805 if (itemClass == Long.class) { 806 if (widest == Integer.class) { 807 widest = Long.class; 808 } 809 } else if (itemClass == Double.class || itemClass == Float.class) { 810 if (widest == Integer.class || widest == Long.class) { 811 widest = Double.class; 812 } 813 } else if (itemClass != Integer.class && itemClass != Short.class && itemClass != Byte.class) { 814 return Object.class; 815 } 816 } 817 818 return widest; 819 } 820 821 /** 822 * Exponential growth function for array size when in 823 * need of resizing. 824 * 825 * @param size current size 826 * @return next size to allocate for internal array 827 */ 828 public static int nextSize(final int size) { 829 return alignUp(size + 1) * 2; 830 } 831 832 /** 833 * Return the next valid index from a given one. Subclassed for various 834 * array representation 835 * 836 * @param index the current index 837 * 838 * @return the next index 839 */ 840 public long nextIndex(final long index) { 841 return index + 1; 842 } 843 844 static Object invoke(final MethodHandle mh, final Object arg) { 845 try { 846 return mh.invoke(arg); 847 } catch (final RuntimeException | Error e) { 848 throw e; 849 } catch (final Throwable t) { 850 throw new RuntimeException(t); 851 } 852 } 853 854 /** 855 * Find a fast call if one exists 856 * 857 * @param clazz array data class 858 * @param desc callsite descriptor 859 * @param request link request 860 * @return fast property getter if one is found 861 */ 862 public GuardedInvocation findFastCallMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { 863 return null; 864 } 865 866 /** 867 * Find a fast property getter if one exists 868 * 869 * @param clazz array data class 870 * @param desc callsite descriptor 871 * @param request link request 872 * @param operator operator 873 * @return fast property getter if one is found 874 */ 875 public GuardedInvocation findFastGetMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request, final String operator) { 876 return null; 877 } 878 879 /** 880 * Find a fast element getter 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 findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value 888 return null; 889 } 890 891 /** 892 * Find a fast element setter if one exists 893 * 894 * @param clazz array data class 895 * @param desc callsite descriptor 896 * @param request link request 897 * @return fast index getter if one is found 898 */ 899 public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value 900 return null; 901 } 902} 903