001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 package org.jikesrvm.classloader; 014 015 import static org.jikesrvm.mm.mminterface.Barriers.*; 016 017 import org.jikesrvm.ArchitectureSpecific; 018 import org.jikesrvm.VM; 019 import org.jikesrvm.Constants; 020 import org.jikesrvm.mm.mminterface.HandInlinedScanning; 021 import org.jikesrvm.mm.mminterface.Barriers; 022 import org.jikesrvm.mm.mminterface.MemoryManager; 023 import org.jikesrvm.objectmodel.ObjectModel; 024 import org.jikesrvm.objectmodel.TIB; 025 import org.jikesrvm.runtime.Magic; 026 import org.jikesrvm.runtime.Memory; 027 import org.jikesrvm.runtime.RuntimeEntrypoints; 028 import org.jikesrvm.runtime.Statics; 029 import org.vmmagic.pragma.Entrypoint; 030 import org.vmmagic.pragma.Inline; 031 import org.vmmagic.pragma.NoInline; 032 import org.vmmagic.pragma.NonMoving; 033 import org.vmmagic.pragma.Pure; 034 import org.vmmagic.pragma.Uninterruptible; 035 import org.vmmagic.unboxed.Offset; 036 037 /** 038 * Description of a java "array" type. <p> 039 * 040 * This description is not read from a ".class" file, but rather 041 * is manufactured by the VM as execution proceeds. 042 * 043 * @see RVMType 044 * @see RVMClass 045 * @see Primitive 046 * @see UnboxedType 047 */ 048 @NonMoving 049 public final class RVMArray extends RVMType implements Constants, ClassLoaderConstants { 050 051 /* 052 * We hold on to a number of commonly used arrays for easy access. 053 */ 054 public static final RVMArray BooleanArray; 055 public static final RVMArray ByteArray; 056 public static final RVMArray CharArray; 057 public static final RVMArray ShortArray; 058 public static final RVMArray IntArray; 059 public static final RVMArray LongArray; 060 public static final RVMArray FloatArray; 061 public static final RVMArray DoubleArray; 062 public static final RVMArray JavaLangObjectArray; 063 064 static { 065 BooleanArray = (RVMArray) TypeReference.BooleanArray.resolve(); 066 CharArray = (RVMArray) TypeReference.CharArray.resolve(); 067 FloatArray = (RVMArray) TypeReference.FloatArray.resolve(); 068 DoubleArray = (RVMArray) TypeReference.DoubleArray.resolve(); 069 ByteArray = (RVMArray) TypeReference.ByteArray.resolve(); 070 ShortArray = (RVMArray) TypeReference.ShortArray.resolve(); 071 IntArray = (RVMArray) TypeReference.IntArray.resolve(); 072 LongArray = (RVMArray) TypeReference.LongArray.resolve(); 073 JavaLangObjectArray = (RVMArray) TypeReference.JavaLangObjectArray.resolve(); 074 } 075 076 /** 077 * The RVMType object for elements of this array type. 078 */ 079 private final RVMType elementType; 080 081 /** 082 * The log of the element size for this array type. 083 */ 084 private final int logElementSize; 085 086 /** 087 * The RVMType object for the innermost element of this array type. 088 */ 089 private final RVMType innermostElementType; 090 091 /** 092 * The dimension of the innermost element of this array type. 093 */ 094 @Entrypoint 095 @SuppressWarnings({"unused"}) 096 private final int innermostElementTypeDimension; 097 098 /** 099 * The desired alignment for instances of this type. 100 * Cached rather than computed because this is a frequently 101 * asked question 102 */ 103 private final int alignment; 104 105 /** 106 * Reference Count GC: is this type acyclic? 107 */ 108 private final boolean acyclic; 109 110 /** 111 * The TIB for this type, created when the array is resolved. 112 */ 113 private TIB typeInformationBlock; 114 115 /** 116 * current class-loading stage (loaded, resolved or initialized) 117 */ 118 private byte state; 119 120 /** 121 * Is this array type in the bootimage? 122 */ 123 private boolean inBootImage; 124 125 /** 126 * Name - something like "[I" or "[Ljava.lang.String;" 127 */ 128 @Override 129 @Pure 130 public String toString() { 131 return getDescriptor().toString().replace('/', '.'); 132 } 133 134 /** 135 * @return 1 136 */ 137 @Override 138 @Pure 139 @Uninterruptible 140 public int getStackWords() { 141 return 1; 142 } 143 144 @Override 145 @Pure 146 @Uninterruptible 147 public int getMemoryBytes() { 148 return BYTES_IN_ADDRESS; 149 } 150 151 /** 152 * @return element type. 153 */ 154 @Uninterruptible 155 public RVMType getElementType() { 156 return elementType; 157 } 158 159 /** 160 * @return innermost element type 161 */ 162 @Uninterruptible 163 public RVMType getInnermostElementType() { 164 return innermostElementType; 165 } 166 167 /** 168 * @return alignment for instances of this array type 169 */ 170 @Uninterruptible 171 public int getAlignment() { 172 return alignment; 173 } 174 175 /** 176 * Size, in bytes, of an array element, log base 2. 177 * @return log base 2 of array element size 178 */ 179 @Uninterruptible 180 public int getLogElementSize() { 181 return logElementSize; 182 } 183 184 /** 185 * Calculate the size, in bytes, of an array element, log base 2. 186 * @return log base 2 of array element size 187 */ 188 private int computeLogElementSize() { 189 if (elementType.getTypeRef().equals(TypeReference.Code)) { 190 return ArchitectureSpecific.ArchConstants.LG_INSTRUCTION_WIDTH; 191 } 192 switch (getDescriptor().parseForArrayElementTypeCode()) { 193 case ClassTypeCode: 194 return LOG_BYTES_IN_ADDRESS; 195 case ArrayTypeCode: 196 return LOG_BYTES_IN_ADDRESS; 197 case BooleanTypeCode: 198 return LOG_BYTES_IN_BOOLEAN; 199 case ByteTypeCode: 200 return 0; 201 case ShortTypeCode: 202 return LOG_BYTES_IN_SHORT; 203 case IntTypeCode: 204 return LOG_BYTES_IN_INT; 205 case LongTypeCode: 206 return LOG_BYTES_IN_LONG; 207 case FloatTypeCode: 208 return LOG_BYTES_IN_FLOAT; 209 case DoubleTypeCode: 210 return LOG_BYTES_IN_DOUBLE; 211 case CharTypeCode: 212 return LOG_BYTES_IN_CHAR; 213 } 214 if (VM.VerifyAssertions) VM._assert(NOT_REACHED); 215 return -1; 216 } 217 218 /** 219 * Total size, in bytes, of an instance of this array type (including object header). 220 * @param numelts number of array elements in the instance 221 * @return size in bytes 222 */ 223 @Inline 224 @Pure 225 @Uninterruptible 226 public int getInstanceSize(int numelts) { 227 return ObjectModel.computeArrayHeaderSize(this) + (numelts << getLogElementSize()); 228 } 229 230 /** 231 * @return false 232 */ 233 @Override 234 @Pure 235 @Uninterruptible 236 public boolean hasFinalizer() { 237 return false; 238 } 239 240 /** 241 * Static fields of this array type. 242 */ 243 @Override 244 @Pure 245 public RVMField[] getStaticFields() { 246 return RVMType.JavaLangObjectType.getStaticFields(); 247 } 248 249 /** 250 * Non-static fields of this array type. 251 */ 252 @Override 253 @Pure 254 public RVMField[] getInstanceFields() { 255 return RVMType.JavaLangObjectType.getInstanceFields(); 256 } 257 258 /** 259 * Statically dispatched methods of this array type. 260 */ 261 @Override 262 @Pure 263 public RVMMethod[] getStaticMethods() { 264 return RVMType.JavaLangObjectType.getStaticMethods(); 265 } 266 267 /** 268 * Virtually dispatched methods of this array type. 269 */ 270 @Override 271 @Pure 272 public RVMMethod[] getVirtualMethods() { 273 return RVMType.JavaLangObjectType.getVirtualMethods(); 274 } 275 276 /** 277 * Runtime type information for this array type. 278 */ 279 @Override 280 @Pure 281 @Uninterruptible 282 public TIB getTypeInformationBlock() { 283 if (VM.VerifyAssertions) VM._assert(isResolved()); 284 return typeInformationBlock; 285 } 286 287 /** 288 * @return 1 289 */ 290 @Override 291 @Pure 292 @Uninterruptible 293 public int getTypeDepth() { 294 return 1; 295 } 296 297 @Override 298 @Pure 299 @Uninterruptible 300 public boolean isAcyclicReference() { 301 return acyclic; 302 } 303 304 /** 305 * Number of [ in descriptor for arrays 306 */ 307 @Override 308 @Pure 309 @Uninterruptible 310 public int getDimensionality() { 311 return dimension; 312 } 313 314 @Override 315 @Uninterruptible 316 public boolean isResolved() { 317 return state >= CLASS_RESOLVED; 318 } 319 320 @Override 321 @Uninterruptible 322 public boolean isInstantiated() { 323 return state >= CLASS_INSTANTIATED; 324 } 325 326 @Override 327 @Uninterruptible 328 public boolean isInitialized() { 329 return state == CLASS_INITIALIZED; 330 } 331 332 @Override 333 public void markAsBootImageClass() { 334 inBootImage = true; 335 } 336 337 @Override 338 @Uninterruptible 339 public boolean isInBootImage() { 340 return inBootImage; 341 } 342 343 /** 344 * Get the offset in instances of this type assigned to the thin lock word. 345 */ 346 @Override 347 @Uninterruptible 348 public Offset getThinLockOffset() { 349 return ObjectModel.defaultThinLockOffset(); 350 } 351 352 /** 353 * @return <code>false</code> 354 */ 355 @Override 356 @Pure 357 @Uninterruptible 358 public boolean isClassType() { 359 return false; 360 } 361 362 /** 363 * @return <code>true</code> 364 */ 365 @Override 366 @Pure 367 @Uninterruptible 368 public boolean isArrayType() { 369 return true; 370 } 371 372 /** 373 * @return <code>false</code> 374 */ 375 @Override 376 @Pure 377 @Uninterruptible 378 public boolean isPrimitiveType() { 379 return false; 380 } 381 382 /** 383 * @return <code>true</code> 384 */ 385 @Override 386 @Pure 387 @Uninterruptible 388 public boolean isReferenceType() { 389 return true; 390 } 391 392 /** 393 * @return <code>false</code> 394 */ 395 @Override 396 @Pure 397 @Uninterruptible 398 public boolean isUnboxedType() { 399 return false; 400 } 401 402 /** 403 * Constructor 404 * @param typeRef 405 * @param elementType 406 */ 407 RVMArray(TypeReference typeRef, RVMType elementType) { 408 super(typeRef, typeRef.getDimensionality(), null); 409 this.elementType = elementType; 410 this.logElementSize = computeLogElementSize(); 411 depth = 1; 412 413 if (elementType.isArrayType()) { 414 innermostElementType = elementType.asArray().getInnermostElementType(); 415 } else { 416 innermostElementType = elementType; 417 } 418 innermostElementTypeDimension = innermostElementType.dimension; 419 if (VM.BuildForIA32 && typeRef == TypeReference.CodeArray) { 420 this.alignment = 16; 421 } else if (BYTES_IN_DOUBLE != BYTES_IN_ADDRESS) { 422 // Desired alignment on 32bit architectures 423 if (elementType.isDoubleType() || elementType.isLongType()) { 424 this.alignment = BYTES_IN_DOUBLE; 425 } else { 426 this.alignment = BYTES_IN_ADDRESS; 427 } 428 } else { 429 this.alignment = BYTES_IN_DOUBLE; 430 } 431 432 // RCGC: Array is acyclic if its references are acyclic 433 acyclic = elementType.isAcyclicReference(); 434 435 /* Set GC metadata for this type */ 436 boolean isRefArray = elementType.isReferenceType(); 437 referenceOffsets = isRefArray ? REFARRAY_OFFSET_ARRAY : NOREFS_OFFSET_ARRAY; 438 439 state = CLASS_LOADED; 440 441 if (VM.verboseClassLoading) VM.sysWrite("[Loaded " + this.getDescriptor() + "]\n"); 442 if (VM.verboseClassLoading) VM.sysWrite("[Loaded superclasses of " + this.getDescriptor() + "]\n"); 443 } 444 445 /** 446 * Resolve an array. 447 * Also forces the resolution of the element type. 448 */ 449 @Override 450 public synchronized void resolve() { 451 if (isResolved()) return; 452 453 if (VM.VerifyAssertions) VM._assert(state == CLASS_LOADED); 454 455 elementType.resolve(); 456 457 // Using the type information block for java.lang.Object as a template, 458 // build a type information block for this new array type by copying the 459 // virtual method fields and substituting an appropriate type field. 460 // 461 TIB javaLangObjectTIB = RVMType.JavaLangObjectType.getTypeInformationBlock(); 462 463 int alignCode = elementType.isReferenceType() ? HandInlinedScanning.referenceArray() : HandInlinedScanning.primitiveArray(); 464 TIB allocatedTib = MemoryManager.newTIB(javaLangObjectTIB.numVirtualMethods(), alignCode); 465 superclassIds = DynamicTypeCheck.buildSuperclassIds(this); 466 doesImplement = DynamicTypeCheck.buildDoesImplement(this); 467 publishResolved(allocatedTib, superclassIds, doesImplement); 468 469 MemoryManager.notifyClassResolved(this); 470 } 471 472 /** 473 * Atomically initialize the important parts of the TIB and let the world know this type is 474 * resolved. 475 * 476 * @param allocatedTib The TIB that has been allocated for this type 477 * @param superclassIds The calculated superclass ids array 478 * @param doesImplement The calculated does implement array 479 */ 480 @Uninterruptible 481 private void publishResolved(TIB allocatedTib, short[] superclassIds, int[] doesImplement) { 482 Statics.setSlotContents(getTibOffset(), allocatedTib); 483 allocatedTib.setType(this); 484 allocatedTib.setSuperclassIds(superclassIds); 485 allocatedTib.setDoesImplement(doesImplement); 486 if (!(elementType.isPrimitiveType()||elementType.isUnboxedType())) { 487 allocatedTib.setArrayElementTib(elementType.getTypeInformationBlock()); 488 } 489 typeInformationBlock = allocatedTib; 490 state = CLASS_RESOLVED; 491 } 492 493 @Override 494 public void allBootImageTypesResolved() { 495 // nothing to do 496 } 497 498 /** 499 * Instantiate an array. 500 * Main result is to copy the virtual methods from JavaLangObject's TIB. 501 */ 502 @Override 503 public synchronized void instantiate() { 504 if (isInstantiated()) return; 505 506 if (VM.VerifyAssertions) VM._assert(state == CLASS_RESOLVED); 507 if (VM.TraceClassLoading && VM.runningVM) { 508 VM.sysWrite("RVMArray: instantiate " + this + "\n"); 509 } 510 511 // Initialize TIB slots for virtual methods (copy from superclass == Object) 512 RVMType objectType = RVMType.JavaLangObjectType; 513 int retries=0; 514 while(!objectType.isInstantiated()) { 515 try { 516 Thread.sleep(1); 517 } catch (InterruptedException e) {} 518 retries++; 519 if (retries > 10) { 520 throw new Error("Failed waiting for java.lang.Object to be instantiated during instantiation of "+toString()); 521 } 522 } 523 if (VM.VerifyAssertions) VM._assert(objectType.isInstantiated()); 524 TIB javaLangObjectTIB = objectType.getTypeInformationBlock(); 525 526 for(int i=0; i < javaLangObjectTIB.numVirtualMethods(); i++) { 527 typeInformationBlock.setVirtualMethod(i, javaLangObjectTIB.getVirtualMethod(i)); 528 } 529 530 SpecializedMethodManager.notifyTypeInstantiated(this); 531 532 state = CLASS_INITIALIZED; // arrays have no "initialize" phase 533 } 534 535 /** 536 * Initialization is a no-op (arrays have no <clinit> method). 537 */ 538 @Override 539 public void initialize() { } 540 541 //-------------------------------------------------------------------------------------------------// 542 // Misc static methods. // 543 //-------------------------------------------------------------------------------------------------// 544 545 /** 546 * Get description of specified primitive array. 547 * @param atype array type number (see "newarray" bytecode description in Java VM Specification) 548 * @return array description 549 */ 550 @Pure 551 public static RVMArray getPrimitiveArrayType(int atype) { 552 switch (atype) { 553 case 4: 554 return BooleanArray; 555 case 5: 556 return CharArray; 557 case 6: 558 return FloatArray; 559 case 7: 560 return DoubleArray; 561 case 8: 562 return ByteArray; 563 case 9: 564 return ShortArray; 565 case 10: 566 return IntArray; 567 case 11: 568 return LongArray; 569 } 570 if (VM.VerifyAssertions) VM._assert(NOT_REACHED); 571 return null; 572 } 573 574 //--------------------------------------------------------------------------------------------------// 575 // Support for array copy // 576 //--------------------------------------------------------------------------------------------------// 577 578 /** 579 * Perform an array copy for arrays of bytes. 580 * 581 * @param src The source array 582 * @param srcIdx The starting source index 583 * @param dst The destination array 584 * @param dstIdx The starting destination index 585 * @param len The number of array elements to be copied 586 */ 587 @Inline(value=Inline.When.ArgumentsAreConstant, arguments={1,3,4}) 588 public static void arraycopy(byte[] src, int srcIdx, byte[] dst, int dstIdx, int len) { 589 // Don't do any of the assignments if the offsets and lengths 590 // are in error 591 if (srcIdx >= 0 && 592 dstIdx >= 0 && 593 len >= 0 && 594 (srcIdx + len) >= 0 && 595 (srcIdx + len) <= src.length && 596 (dstIdx + len) >= 0 && 597 (dstIdx + len) <= dst.length) { 598 if ((src != dst || srcIdx >= (dstIdx + BYTES_IN_ADDRESS)) && BYTE_BULK_COPY_SUPPORTED) { 599 if (NEEDS_BYTE_ASTORE_BARRIER || NEEDS_BYTE_ALOAD_BARRIER) { 600 Offset srcOffset = Offset.fromIntZeroExtend(srcIdx); 601 Offset dstOffset = Offset.fromIntZeroExtend(dstIdx); 602 Barriers.byteBulkCopy(src, srcOffset, dst, dstOffset, len); 603 } else { 604 Memory.arraycopy8Bit(src, srcIdx, dst, dstIdx, len); 605 } 606 } else { 607 arraycopyPiecemeal(src, srcIdx, dst, dstIdx, len); 608 } 609 } else { 610 failWithIndexOutOfBoundsException(); 611 } 612 } 613 614 /** 615 * Perform element-by-element arraycopy for array of bytes. Used 616 * when bulk copy is not possible. 617 * 618 * @param src The source array 619 * @param srcIdx The starting source index 620 * @param dst The destination array 621 * @param dstIdx The starting destination index 622 * @param len The number of array elements to be copied 623 */ 624 @NoInline // unlikely case, so reduce code space costs 625 private static void arraycopyPiecemeal(byte[] src, int srcIdx, byte[] dst, int dstIdx, int len) { 626 if (srcIdx < dstIdx) { 627 srcIdx += len; 628 dstIdx += len; 629 while (len-- != 0) { 630 dst[--dstIdx] = src[--srcIdx]; 631 } 632 } else { 633 while (len-- != 0) { 634 dst[dstIdx++] = src[srcIdx++]; 635 } 636 } 637 } 638 639 /** 640 * Perform an array copy for arrays of booleans. 641 * 642 * @param src The source array 643 * @param srcIdx The starting source index 644 * @param dst The destination array 645 * @param dstIdx The starting destination index 646 * @param len The number of array elements to be copied 647 */ 648 @Inline(value=Inline.When.ArgumentsAreConstant, arguments={1,3,4}) 649 public static void arraycopy(boolean[] src, int srcIdx, boolean[] dst, int dstIdx, int len) { 650 // Don't do any of the assignments if the offsets and lengths 651 // are in error 652 if (srcIdx >= 0 && 653 dstIdx >= 0 && 654 len >= 0 && 655 (srcIdx + len) >= 0 && 656 (srcIdx + len) <= src.length && 657 (dstIdx + len) >= 0 && 658 (dstIdx + len) <= dst.length) { 659 if ((src != dst || srcIdx >= (dstIdx + BYTES_IN_ADDRESS / BYTES_IN_BOOLEAN)) && BOOLEAN_BULK_COPY_SUPPORTED) { 660 if (NEEDS_BOOLEAN_ASTORE_BARRIER || NEEDS_BOOLEAN_ALOAD_BARRIER) { 661 Offset srcOffset = Offset.fromIntZeroExtend(srcIdx<<LOG_BYTES_IN_BOOLEAN); 662 Offset dstOffset = Offset.fromIntZeroExtend(dstIdx<<LOG_BYTES_IN_BOOLEAN); 663 Barriers.booleanBulkCopy(src, srcOffset, dst, dstOffset, len); 664 } else { 665 Memory.arraycopy8Bit(src, srcIdx, dst, dstIdx, len); 666 } 667 } else { 668 arraycopyPiecemeal(src, srcIdx, dst, dstIdx, len); 669 } 670 } else { 671 failWithIndexOutOfBoundsException(); 672 } 673 } 674 675 /** 676 * Perform element-by-element arraycopy for array of booleans. Used 677 * when bulk copy is not possible. 678 * 679 * @param src The source array 680 * @param srcIdx The starting source index 681 * @param dst The destination array 682 * @param dstIdx The starting destination index 683 * @param len The number of array elements to be copied 684 */ 685 @NoInline // unlikely case, so reduce code space costs 686 private static void arraycopyPiecemeal(boolean[] src, int srcIdx, boolean[] dst, int dstIdx, int len) { 687 if (srcIdx < dstIdx) { 688 srcIdx += len; 689 dstIdx += len; 690 while (len-- != 0) { 691 dst[--dstIdx] = src[--srcIdx]; 692 } 693 } else { 694 while (len-- != 0) { 695 dst[dstIdx++] = src[srcIdx++]; 696 } 697 } 698 } 699 700 /** 701 * Perform an array copy for arrays of shorts. 702 * 703 * @param src The source array 704 * @param srcIdx The starting source index 705 * @param dst The destination array 706 * @param dstIdx The starting destination index 707 * @param len The number of array elements to be copied 708 */ 709 @Inline(value=Inline.When.ArgumentsAreConstant, arguments={1,3,4}) 710 public static void arraycopy(short[] src, int srcIdx, short[] dst, int dstIdx, int len) { 711 // Don't do any of the assignments if the offsets and lengths 712 // are in error 713 if (srcIdx >= 0 && 714 dstIdx >= 0 && 715 len >= 0 && 716 (srcIdx + len) >= 0 && 717 (srcIdx + len) <= src.length && 718 (dstIdx + len) >= 0 && 719 (dstIdx + len) <= dst.length) { 720 if ((src != dst || srcIdx >= (dstIdx + BYTES_IN_ADDRESS / BYTES_IN_SHORT)) && SHORT_BULK_COPY_SUPPORTED) { 721 if (NEEDS_SHORT_ASTORE_BARRIER || NEEDS_SHORT_ALOAD_BARRIER) { 722 Offset srcOffset = Offset.fromIntZeroExtend(srcIdx<<LOG_BYTES_IN_SHORT); 723 Offset dstOffset = Offset.fromIntZeroExtend(dstIdx<<LOG_BYTES_IN_SHORT); 724 Barriers.shortBulkCopy(src, srcOffset, dst, dstOffset, len << LOG_BYTES_IN_SHORT); 725 } else { 726 Memory.arraycopy16Bit(src, srcIdx, dst, dstIdx, len); 727 } 728 } else { 729 arraycopyPiecemeal(src, srcIdx, dst, dstIdx, len); 730 } 731 } else { 732 failWithIndexOutOfBoundsException(); 733 } 734 } 735 736 /** 737 * Perform element-by-element arraycopy for array of shorts. Used 738 * when bulk copy is not possible. 739 * 740 * @param src The source array 741 * @param srcIdx The starting source index 742 * @param dst The destination array 743 * @param dstIdx The starting destination index 744 * @param len The number of array elements to be copied 745 */ 746 @NoInline // unlikely case, so reduce code space costs 747 private static void arraycopyPiecemeal(short[] src, int srcIdx, short[] dst, int dstIdx, int len) { 748 if (srcIdx < dstIdx) { 749 srcIdx += len; 750 dstIdx += len; 751 while (len-- != 0) { 752 dst[--dstIdx] = src[--srcIdx]; 753 } 754 } else { 755 while (len-- != 0) { 756 dst[dstIdx++] = src[srcIdx++]; 757 } 758 } 759 } 760 761 /** 762 * Perform an array copy for arrays of chars. 763 * 764 * @param src The source array 765 * @param srcIdx The starting source index 766 * @param dst The destination array 767 * @param dstIdx The starting destination index 768 * @param len The number of array elements to be copied 769 */ 770 @Inline(value=Inline.When.ArgumentsAreConstant, arguments={1,3,4}) 771 public static void arraycopy(char[] src, int srcIdx, char[] dst, int dstIdx, int len) { 772 // Don't do any of the assignments if the offsets and lengths 773 // are in error 774 if (srcIdx >= 0 && 775 dstIdx >= 0 && 776 len >= 0 && 777 (srcIdx + len) >= 0 && 778 (srcIdx + len) <= src.length && 779 (dstIdx + len) >= 0 && 780 (dstIdx + len) <= dst.length) { 781 if ((src != dst || srcIdx >= (dstIdx + BYTES_IN_ADDRESS / BYTES_IN_CHAR)) && CHAR_BULK_COPY_SUPPORTED) { 782 if (NEEDS_CHAR_ASTORE_BARRIER || NEEDS_CHAR_ALOAD_BARRIER) { 783 Offset srcOffset = Offset.fromIntZeroExtend(srcIdx<<LOG_BYTES_IN_CHAR); 784 Offset dstOffset = Offset.fromIntZeroExtend(dstIdx<<LOG_BYTES_IN_CHAR); 785 Barriers.charBulkCopy(src, srcOffset, dst, dstOffset, len << LOG_BYTES_IN_CHAR); 786 } else { 787 Memory.arraycopy16Bit(src, srcIdx, dst, dstIdx, len); 788 } 789 } else { 790 arraycopyPiecemeal(src, srcIdx, dst, dstIdx, len); 791 } 792 } else { 793 failWithIndexOutOfBoundsException(); 794 } 795 } 796 797 /** 798 * Perform element-by-element arraycopy for array of chars. Used 799 * when bulk copy is not possible. 800 * 801 * @param src The source array 802 * @param srcIdx The starting source index 803 * @param dst The destination array 804 * @param dstIdx The starting destination index 805 * @param len The number of array elements to be copied 806 */ 807 @NoInline // unlikely case, so reduce code space costs 808 private static void arraycopyPiecemeal(char[] src, int srcIdx, char[] dst, int dstIdx, int len) { 809 if (srcIdx < dstIdx) { 810 srcIdx += len; 811 dstIdx += len; 812 while (len-- != 0) { 813 dst[--dstIdx] = src[--srcIdx]; 814 } 815 } else { 816 while (len-- != 0) { 817 dst[dstIdx++] = src[srcIdx++]; 818 } 819 } 820 } 821 822 /** 823 * Perform an array copy for arrays of ints. 824 * 825 * @param src The source array 826 * @param srcIdx The starting source index 827 * @param dst The destination array 828 * @param dstIdx The starting destination index 829 * @param len The number of array elements to be copied 830 */ 831 @Inline(value=Inline.When.ArgumentsAreConstant, arguments={1,3,4}) 832 public static void arraycopy(int[] src, int srcIdx, int[] dst, int dstIdx, int len) { 833 // Don't do any of the assignments if the offsets and lengths 834 // are in error 835 if (srcIdx >= 0 && 836 dstIdx >= 0 && 837 len >= 0 && 838 (srcIdx + len) >= 0 && 839 (srcIdx + len) <= src.length && 840 (dstIdx + len) >= 0 && 841 (dstIdx + len) <= dst.length) { 842 if ((src != dst || srcIdx >= dstIdx) && INT_BULK_COPY_SUPPORTED) { 843 if (NEEDS_INT_ASTORE_BARRIER || NEEDS_INT_ALOAD_BARRIER) { 844 Offset srcOffset = Offset.fromIntZeroExtend(srcIdx<<LOG_BYTES_IN_INT); 845 Offset dstOffset = Offset.fromIntZeroExtend(dstIdx<<LOG_BYTES_IN_INT); 846 Barriers.intBulkCopy(src, srcOffset, dst, dstOffset, len << LOG_BYTES_IN_INT); 847 } else { 848 Memory.arraycopy32Bit(src, srcIdx, dst, dstIdx, len); 849 } 850 } else { 851 arraycopyPiecemeal(src, srcIdx, dst, dstIdx, len); 852 } 853 } else { 854 failWithIndexOutOfBoundsException(); 855 } 856 } 857 858 /** 859 * Perform element-by-element arraycopy for array of ints. Used 860 * when bulk copy is not possible. 861 * 862 * @param src The source array 863 * @param srcIdx The starting source index 864 * @param dst The destination array 865 * @param dstIdx The starting destination index 866 * @param len The number of array elements to be copied 867 */ 868 @NoInline // unlikely case, so reduce code space costs 869 private static void arraycopyPiecemeal(int[] src, int srcIdx, int[] dst, int dstIdx, int len) { 870 if (srcIdx < dstIdx) { 871 srcIdx += len; 872 dstIdx += len; 873 while (len-- != 0) { 874 dst[--dstIdx] = src[--srcIdx]; 875 } 876 } else { 877 while (len-- != 0) { 878 dst[dstIdx++] = src[srcIdx++]; 879 } 880 } 881 } 882 883 /** 884 * Perform an array copy for arrays of floats. 885 * 886 * @param src The source array 887 * @param srcIdx The starting source index 888 * @param dst The destination array 889 * @param dstIdx The starting destination index 890 * @param len The number of array elements to be copied 891 */ 892 @Inline(value=Inline.When.ArgumentsAreConstant, arguments={1,3,4}) 893 public static void arraycopy(float[] src, int srcIdx, float[] dst, int dstIdx, int len) { 894 // Don't do any of the assignments if the offsets and lengths 895 // are in error 896 if (srcIdx >= 0 && 897 dstIdx >= 0 && 898 len >= 0 && 899 (srcIdx + len) >= 0 && 900 (srcIdx + len) <= src.length && 901 (dstIdx + len) >= 0 && 902 (dstIdx + len) <= dst.length) { 903 if ((src != dst || srcIdx > dstIdx) && FLOAT_BULK_COPY_SUPPORTED) { 904 if (NEEDS_FLOAT_ASTORE_BARRIER || NEEDS_FLOAT_ALOAD_BARRIER) { 905 Offset srcOffset = Offset.fromIntZeroExtend(srcIdx<<LOG_BYTES_IN_FLOAT); 906 Offset dstOffset = Offset.fromIntZeroExtend(dstIdx<<LOG_BYTES_IN_FLOAT); 907 Barriers.floatBulkCopy(src, srcOffset, dst, dstOffset, len << LOG_BYTES_IN_FLOAT); 908 } else { 909 Memory.arraycopy32Bit(src, srcIdx, dst, dstIdx, len); 910 } 911 } else { 912 arraycopyPiecemeal(src, srcIdx, dst, dstIdx, len); 913 } 914 } else { 915 failWithIndexOutOfBoundsException(); 916 } 917 } 918 919 /** 920 * Perform element-by-element arraycopy for array of floats. Used 921 * when bulk copy is not possible. 922 * 923 * @param src The source array 924 * @param srcIdx The starting source index 925 * @param dst The destination array 926 * @param dstIdx The starting destination index 927 * @param len The number of array elements to be copied 928 */ 929 @NoInline // unlikely case, so reduce code space costs 930 private static void arraycopyPiecemeal(float[] src, int srcIdx, float[] dst, int dstIdx, int len) { 931 if (srcIdx < dstIdx) { 932 srcIdx += len; 933 dstIdx += len; 934 while (len-- != 0) { 935 dst[--dstIdx] = src[--srcIdx]; 936 } 937 } else { 938 while (len-- != 0) { 939 dst[dstIdx++] = src[srcIdx++]; 940 } 941 } 942 } 943 944 /** 945 * Perform an array copy for arrays of longs. 946 * 947 * @param src The source array 948 * @param srcIdx The starting source index 949 * @param dst The destination array 950 * @param dstIdx The starting destination index 951 * @param len The number of array elements to be copied 952 */ 953 @Inline(value=Inline.When.ArgumentsAreConstant, arguments={1,3,4}) 954 public static void arraycopy(long[] src, int srcIdx, long[] dst, int dstIdx, int len) { 955 // Don't do any of the assignments if the offsets and lengths 956 // are in error 957 if (srcIdx >= 0 && 958 dstIdx >= 0 && 959 len >= 0 && 960 (srcIdx + len) >= 0 && 961 (srcIdx + len) <= src.length && 962 (dstIdx + len) >= 0 && 963 (dstIdx + len) <= dst.length) { 964 if ((src != dst || srcIdx > dstIdx) && LONG_BULK_COPY_SUPPORTED) { 965 if (NEEDS_LONG_ASTORE_BARRIER || NEEDS_LONG_ALOAD_BARRIER) { 966 Offset srcOffset = Offset.fromIntZeroExtend(srcIdx<<LOG_BYTES_IN_LONG); 967 Offset dstOffset = Offset.fromIntZeroExtend(dstIdx<<LOG_BYTES_IN_LONG); 968 Barriers.longBulkCopy(src, srcOffset, dst, dstOffset, len << LOG_BYTES_IN_LONG); 969 } else { 970 Memory.arraycopy64Bit(src, srcIdx, dst, dstIdx, len); 971 } 972 } else { 973 arraycopyPiecemeal(src, srcIdx, dst, dstIdx, len); 974 } 975 } else { 976 failWithIndexOutOfBoundsException(); 977 } 978 } 979 980 /** 981 * Perform element-by-element arraycopy for array of longs. Used 982 * when bulk copy is not possible. 983 * 984 * @param src The source array 985 * @param srcIdx The starting source index 986 * @param dst The destination array 987 * @param dstIdx The starting destination index 988 * @param len The number of array elements to be copied 989 */ 990 @NoInline // unlikely case, so reduce code space costs 991 private static void arraycopyPiecemeal(long[] src, int srcIdx, long[] dst, int dstIdx, int len) { 992 if (srcIdx < dstIdx) { 993 srcIdx += len; 994 dstIdx += len; 995 while (len-- != 0) { 996 dst[--dstIdx] = src[--srcIdx]; 997 } 998 } else { 999 while (len-- != 0) { 1000 dst[dstIdx++] = src[srcIdx++]; 1001 } 1002 } 1003 } 1004 1005 /** 1006 * Perform an array copy for arrays of doubles. 1007 * 1008 * @param src The source array 1009 * @param srcIdx The starting source index 1010 * @param dst The destination array 1011 * @param dstIdx The starting destination index 1012 * @param len The number of array elements to be copied 1013 */ 1014 @Inline(value=Inline.When.ArgumentsAreConstant, arguments={1,3,4}) 1015 public static void arraycopy(double[] src, int srcIdx, double[] dst, int dstIdx, int len) { 1016 // Don't do any of the assignments if the offsets and lengths 1017 // are in error 1018 if (srcIdx >= 0 && 1019 dstIdx >= 0 && 1020 len >= 0 && 1021 (srcIdx + len) >= 0 && 1022 (srcIdx + len) <= src.length && 1023 (dstIdx + len) >= 0 && 1024 (dstIdx + len) <= dst.length) { 1025 if ((src != dst || srcIdx > dstIdx) && DOUBLE_BULK_COPY_SUPPORTED) { 1026 if (NEEDS_DOUBLE_ASTORE_BARRIER || NEEDS_DOUBLE_ALOAD_BARRIER) { 1027 Offset srcOffset = Offset.fromIntZeroExtend(srcIdx<<LOG_BYTES_IN_DOUBLE); 1028 Offset dstOffset = Offset.fromIntZeroExtend(dstIdx<<LOG_BYTES_IN_DOUBLE); 1029 Barriers.doubleBulkCopy(src, srcOffset, dst, dstOffset, len << LOG_BYTES_IN_DOUBLE); 1030 } else { 1031 Memory.arraycopy64Bit(src, srcIdx, dst, dstIdx, len); 1032 } 1033 } else { 1034 arraycopyPiecemeal(src, srcIdx, dst, dstIdx, len); 1035 } 1036 } else { 1037 failWithIndexOutOfBoundsException(); 1038 } 1039 } 1040 1041 /** 1042 * Perform element-by-element arraycopy for array of doubles. Used 1043 * when bulk copy is not possible. 1044 * 1045 * @param src The source array 1046 * @param srcIdx The starting source index 1047 * @param dst The destination array 1048 * @param dstIdx The starting destination index 1049 * @param len The number of array elements to be copied 1050 */ 1051 @NoInline // unlikely case, so reduce code space costs 1052 private static void arraycopyPiecemeal(double[] src, int srcIdx, double[] dst, int dstIdx, int len) { 1053 if (srcIdx < dstIdx) { 1054 srcIdx += len; 1055 dstIdx += len; 1056 while (len-- != 0) { 1057 dst[--dstIdx] = src[--srcIdx]; 1058 } 1059 } else { 1060 while (len-- != 0) { 1061 dst[dstIdx++] = src[srcIdx++]; 1062 } 1063 } 1064 } 1065 1066 /** 1067 * Perform an array copy for arrays of objects. This code must 1068 * ensure that write barriers are invoked as if the copy were 1069 * performed element-by-element. 1070 * 1071 * @param src The source array 1072 * @param srcIdx The starting source index 1073 * @param dst The destination array 1074 * @param dstIdx The starting destination index 1075 * @param len The number of array elements to be copied 1076 */ 1077 public static void arraycopy(Object[] src, int srcIdx, Object[] dst, int dstIdx, int len) { 1078 // Check offsets and lengths before doing anything 1079 if (srcIdx >= 0 && 1080 dstIdx >= 0 && 1081 len >= 0 && 1082 (srcIdx + len) >= 0 && 1083 (srcIdx + len) <= src.length && 1084 (dstIdx + len) >= 0 && 1085 (dstIdx + len) <= dst.length) { 1086 RVMType lhs = Magic.getObjectType(dst).asArray().getElementType(); 1087 RVMType rhs = Magic.getObjectType(src).asArray().getElementType(); 1088 1089 if ((lhs == rhs) || (lhs == RVMType.JavaLangObjectType) || RuntimeEntrypoints.isAssignableWith(lhs, rhs)) { 1090 arraycopyNoCheckcast(src, srcIdx, dst, dstIdx, len); 1091 } else { 1092 arraycopyPiecemeal(src, srcIdx, dst, dstIdx, len); 1093 } 1094 } else { 1095 failWithIndexOutOfBoundsException(); 1096 } 1097 } 1098 1099 /** 1100 * Perform an array copy for arrays of objects where the possibility 1101 * of an ArrayStoreException being thrown <i>does not</i> exist. 1102 * This may be done using direct byte copies, <i>however</i>, write 1103 * barriers must be explicitly invoked (if required by the GC) since 1104 * the write barrier associated with an explicit array store 1105 * (aastore) will be bypassed. 1106 * 1107 * @param src The source array 1108 * @param srcIdx The starting source index 1109 * @param dst The destination array 1110 * @param dstIdx The starting source index 1111 * @param len The number of array elements to be copied 1112 */ 1113 private static void arraycopyNoCheckcast(Object[] src, int srcIdx, Object[] dst, int dstIdx, int len) { 1114 Offset srcOffset = Offset.fromIntZeroExtend(srcIdx << LOG_BYTES_IN_ADDRESS); 1115 Offset dstOffset = Offset.fromIntZeroExtend(dstIdx << LOG_BYTES_IN_ADDRESS); 1116 int bytes = len << LOG_BYTES_IN_ADDRESS; 1117 1118 if (((src != dst) || (srcIdx > dstIdx)) && OBJECT_BULK_COPY_SUPPORTED) { 1119 if (NEEDS_OBJECT_ASTORE_BARRIER || NEEDS_OBJECT_ALOAD_BARRIER) { 1120 Barriers.objectBulkCopy(src, srcOffset, dst, dstOffset, bytes); 1121 } else { 1122 Memory.alignedWordCopy(Magic.objectAsAddress(dst).plus(dstOffset), Magic.objectAsAddress(src).plus(srcOffset), bytes); 1123 } 1124 } else { 1125 arraycopyPiecemealNoCheckcast(src, dst, len, srcOffset, dstOffset, bytes); 1126 } 1127 } 1128 1129 /** 1130 * Perform element-by-element arraycopy for array of objects without 1131 * performing checkcast. Used when bulk copy is not possible, but 1132 * checkcast is still not necessary. If barriers are required they 1133 * must be explicitly invoked. 1134 * 1135 * @param src The source array 1136 * @param dst The destination array 1137 * @param len The number of array elements to be copied 1138 * @param srcOffset The starting offset in the source array 1139 * @param dstOffset The starting offset in the destination array. 1140 * @param bytes the number of bytes to copy 1141 */ 1142 private static void arraycopyPiecemealNoCheckcast(Object[] src, Object[] dst, int len, 1143 Offset srcOffset, Offset dstOffset, int bytes) { 1144 1145 // set up things according to the direction of the copy 1146 int increment; 1147 if (srcOffset.sGT(dstOffset)) { // direction of copy 1148 increment = BYTES_IN_ADDRESS; 1149 } else { 1150 srcOffset = srcOffset.plus(bytes - BYTES_IN_ADDRESS); 1151 dstOffset = dstOffset.plus(bytes - BYTES_IN_ADDRESS); 1152 increment = -BYTES_IN_ADDRESS; 1153 } 1154 1155 // perform the copy 1156 while (len-- != 0) { 1157 Object value; 1158 if (NEEDS_OBJECT_ALOAD_BARRIER) { 1159 value = Barriers.objectArrayRead(src, srcOffset.toInt() >> LOG_BYTES_IN_ADDRESS); 1160 } else { 1161 value = Magic.getObjectAtOffset(src, srcOffset); 1162 } 1163 if (NEEDS_OBJECT_ASTORE_BARRIER) { 1164 Barriers.objectArrayWrite(dst, dstOffset.toInt() >> LOG_BYTES_IN_ADDRESS, value); 1165 } else { 1166 Magic.setObjectAtOffset(dst, dstOffset, value); 1167 } 1168 srcOffset = srcOffset.plus(increment); 1169 dstOffset = dstOffset.plus(increment); 1170 } 1171 } 1172 1173 /** 1174 * Perform an array copy for arrays of objects where the possibility 1175 * of an ArrayStoreException being thrown exists. This must be done 1176 * with element by element assignments in the correct order. 1177 * <i>Since write barriers are implicitly performed on explicit 1178 * array stores, there is no need to explicitly invoke a write 1179 * barrier in this code.</i> 1180 * 1181 * @param src The source array 1182 * @param srcIdx The starting source index 1183 * @param dst The destination array 1184 * @param dstIdx The starting destination index 1185 * @param len The number of array elements to be copied 1186 */ 1187 private static void arraycopyPiecemeal(Object[] src, int srcIdx, Object[] dst, int dstIdx, int len) { 1188 if ((src != dst) || srcIdx >= dstIdx) { 1189 while (len-- != 0) { 1190 dst[dstIdx++] = src[srcIdx++]; 1191 } 1192 } else { 1193 srcIdx += len; 1194 dstIdx += len; 1195 while (len-- != 0) { 1196 dst[--dstIdx] = src[--srcIdx]; 1197 } 1198 } 1199 } 1200 1201 @NoInline 1202 private static void failWithIndexOutOfBoundsException() { 1203 throw new ArrayIndexOutOfBoundsException(); 1204 } 1205 }