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}