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    }