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