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    import org.jikesrvm.ArchitectureSpecific;
017    import org.jikesrvm.VM;
018    import org.jikesrvm.Constants;
019    import org.jikesrvm.mm.mminterface.Barriers;
020    import org.jikesrvm.mm.mminterface.MemoryManager;
021    import org.jikesrvm.objectmodel.ObjectModel;
022    import org.jikesrvm.objectmodel.TIB;
023    import org.jikesrvm.runtime.Magic;
024    import org.jikesrvm.runtime.Memory;
025    import org.jikesrvm.runtime.RuntimeEntrypoints;
026    import org.jikesrvm.runtime.Statics;
027    import org.vmmagic.pragma.Entrypoint;
028    import org.vmmagic.pragma.Inline;
029    import org.vmmagic.pragma.NoInline;
030    import org.vmmagic.pragma.NonMoving;
031    import org.vmmagic.pragma.Pure;
032    import org.vmmagic.pragma.Uninterruptible;
033    import org.vmmagic.unboxed.Offset;
034    
035    /**
036     * Description of a java "array" type. <p>
037     *
038     * This description is not read from a ".class" file, but rather
039     * is manufactured by the vm as execution proceeds.
040     *
041     * @see RVMType
042     * @see RVMClass
043     * @see Primitive
044     * @see UnboxedType
045     */
046    @NonMoving
047    public final class RVMArray extends RVMType implements Constants, ClassLoaderConstants {
048    
049      /*
050       * We hold on to a number of commonly used arrays for easy access.
051       */
052      public static final RVMArray BooleanArray;
053      public static final RVMArray ByteArray;
054      public static final RVMArray CharArray;
055      public static final RVMArray ShortArray;
056      public static final RVMArray IntArray;
057      public static final RVMArray LongArray;
058      public static final RVMArray FloatArray;
059      public static final RVMArray DoubleArray;
060      public static final RVMArray JavaLangObjectArray;
061    
062      static {
063        BooleanArray = (RVMArray) TypeReference.BooleanArray.resolve();
064        CharArray = (RVMArray) TypeReference.CharArray.resolve();
065        FloatArray = (RVMArray) TypeReference.FloatArray.resolve();
066        DoubleArray = (RVMArray) TypeReference.DoubleArray.resolve();
067        ByteArray = (RVMArray) TypeReference.ByteArray.resolve();
068        ShortArray = (RVMArray) TypeReference.ShortArray.resolve();
069        IntArray = (RVMArray) TypeReference.IntArray.resolve();
070        LongArray = (RVMArray) TypeReference.LongArray.resolve();
071        JavaLangObjectArray = (RVMArray) TypeReference.JavaLangObjectArray.resolve();
072      }
073    
074      /**
075       * The RVMType object for elements of this array type.
076       */
077      private final RVMType elementType;
078    
079      /**
080       * The log of the element size for this array type.
081       */
082      private final int logElementSize;
083    
084      /**
085       * The RVMType object for the innermost element of this array type.
086       */
087      private final RVMType innermostElementType;
088    
089      /**
090       * The dimension of the innermost element of this array type.
091       */
092      @Entrypoint
093      @SuppressWarnings({"unused"})
094      private final int innermostElementTypeDimension;
095    
096      /**
097       * The desired alignment for instances of this type.
098       * Cached rather than computed because this is a frequently
099       * asked question
100       */
101      private final int alignment;
102    
103      /**
104       * Reference Count GC: is this type acyclic?
105       */
106      private final boolean acyclic;
107    
108      /**
109       * The TIB for this type, created when the array is resolved.
110       */
111      private TIB typeInformationBlock;
112    
113      /**
114       * current class-loading stage (loaded, resolved or initialized)
115       */
116      private byte state;
117    
118      /**
119       * Is this array type in the bootimage?
120       */
121      private boolean inBootImage;
122    
123      /**
124       * Name - something like "[I" or "[Ljava.lang.String;"
125       */
126      @Override
127      @Pure
128      public String toString() {
129        return getDescriptor().toString().replace('/', '.');
130      }
131    
132      /**
133       * @return java Expression stack space requirement.
134       */
135      @Override
136      @Pure
137      @Uninterruptible
138      public int getStackWords() {
139        return 1;
140      }
141    
142      /**
143       * Space required in memory in bytes.
144       */
145      @Override
146      @Pure
147      @Uninterruptible
148      public int getMemoryBytes() {
149        return BYTES_IN_ADDRESS;
150      }
151    
152      /**
153       * @return element type.
154       */
155      @Uninterruptible
156      public RVMType getElementType() {
157        return elementType;
158      }
159    
160      /**
161       * @return innermost element type
162       */
163      @Uninterruptible
164      public RVMType getInnermostElementType() {
165        return innermostElementType;
166      }
167    
168      /**
169       * @return alignment for instances of this array type
170       */
171      @Uninterruptible
172      public int getAlignment() {
173        return alignment;
174      }
175    
176      /**
177       * Size, in bytes, of an array element, log base 2.
178       * @return log base 2 of array element size
179       */
180      @Uninterruptible
181      public int getLogElementSize() {
182        return logElementSize;
183      }
184    
185      /**
186       * Calculate the size, in bytes, of an array element, log base 2.
187       * @return log base 2 of array element size
188       */
189      private int computeLogElementSize() {
190        if (elementType.getTypeRef().equals(TypeReference.Code)) {
191          return ArchitectureSpecific.ArchConstants.LG_INSTRUCTION_WIDTH;
192        }
193        switch (getDescriptor().parseForArrayElementTypeCode()) {
194          case ClassTypeCode:
195            return LOG_BYTES_IN_ADDRESS;
196          case ArrayTypeCode:
197            return LOG_BYTES_IN_ADDRESS;
198          case BooleanTypeCode:
199            return LOG_BYTES_IN_BOOLEAN;
200          case ByteTypeCode:
201            return 0;
202          case ShortTypeCode:
203            return LOG_BYTES_IN_SHORT;
204          case IntTypeCode:
205            return LOG_BYTES_IN_INT;
206          case LongTypeCode:
207            return LOG_BYTES_IN_LONG;
208          case FloatTypeCode:
209            return LOG_BYTES_IN_FLOAT;
210          case DoubleTypeCode:
211            return LOG_BYTES_IN_DOUBLE;
212          case CharTypeCode:
213            return LOG_BYTES_IN_CHAR;
214        }
215        if (VM.VerifyAssertions) VM._assert(NOT_REACHED);
216        return -1;
217      }
218    
219      /**
220       * Total size, in bytes, of an instance of this array type (including object header).
221       * @param numelts number of array elements in the instance
222       * @return size in bytes
223       */
224      @Inline
225      @Pure
226      @Uninterruptible
227      public int getInstanceSize(int numelts) {
228        return ObjectModel.computeArrayHeaderSize(this) + (numelts << getLogElementSize());
229      }
230    
231      /**
232       * Does this class override java.lang.Object.finalize()?
233       */
234      @Override
235      @Pure
236      @Uninterruptible
237      public boolean hasFinalizer() {
238        return false;
239      }
240    
241      /**
242       * Static fields of this array type.
243       */
244      @Override
245      @Pure
246      public RVMField[] getStaticFields() {
247        return RVMType.JavaLangObjectType.getStaticFields();
248      }
249    
250      /**
251       * Non-static fields of this array type.
252       */
253      @Override
254      @Pure
255      public RVMField[] getInstanceFields() {
256        return RVMType.JavaLangObjectType.getInstanceFields();
257      }
258    
259      /**
260       * Statically dispatched methods of this array type.
261       */
262      @Override
263      @Pure
264      public RVMMethod[] getStaticMethods() {
265        return RVMType.JavaLangObjectType.getStaticMethods();
266      }
267    
268      /**
269       * Virtually dispatched methods of this array type.
270       */
271      @Override
272      @Pure
273      public RVMMethod[] getVirtualMethods() {
274        return RVMType.JavaLangObjectType.getVirtualMethods();
275      }
276    
277      /**
278       * Runtime type information for this array type.
279       */
280      @Override
281      @Pure
282      @Uninterruptible
283      public TIB getTypeInformationBlock() {
284        if (VM.VerifyAssertions) VM._assert(isResolved());
285        return typeInformationBlock;
286      }
287    
288      /**
289       * get number of superclasses to Object
290       * @return 1
291       */
292      @Override
293      @Pure
294      @Uninterruptible
295      public int getTypeDepth() {
296        return 1;
297      }
298    
299      /**
300       * Reference Count GC: Is a reference of this type contained in
301       * another object inherently acyclic (without cycles) ?
302       * @return true
303       */
304      @Override
305      @Pure
306      @Uninterruptible
307      public boolean isAcyclicReference() {
308        return acyclic;
309      }
310    
311      /**
312       * Number of [ in descriptor for arrays; -1 for primitives; 0 for
313       * classes
314       */
315      @Override
316      @Pure
317      @Uninterruptible
318      public int getDimensionality() {
319        return dimension;
320      }
321    
322      /**
323       * Resolution status.
324       */
325      @Override
326      @Uninterruptible
327      public boolean isResolved() {
328        return state >= CLASS_RESOLVED;
329      }
330    
331      /**
332       * Instantiation status.
333       */
334      @Override
335      @Uninterruptible
336      public boolean isInstantiated() {
337        return state >= CLASS_INSTANTIATED;
338      }
339    
340      /**
341       * Initialization status.
342       */
343      @Override
344      @Uninterruptible
345      public boolean isInitialized() {
346        return state == CLASS_INITIALIZED;
347      }
348    
349      /**
350       * Only intended to be used by the BootImageWriter
351       */
352      @Override
353      public void markAsBootImageClass() {
354        inBootImage = true;
355      }
356    
357      /**
358       * Is this class part of the virtual machine's boot image?
359       */
360      @Override
361      @Uninterruptible
362      public boolean isInBootImage() {
363        return inBootImage;
364      }
365    
366      /**
367       * Get the offset in instances of this type assigned to the thin lock word.
368       * Offset.max() if instances of this type do not have thin lock words.
369       */
370      @Override
371      @Uninterruptible
372      public Offset getThinLockOffset() {
373        return ObjectModel.defaultThinLockOffset();
374      }
375    
376      /**
377       * Whether or not this is an instance of RVMClass?
378       * @return false
379       */
380      @Override
381      @Pure
382      @Uninterruptible
383      public boolean isClassType() {
384        return false;
385      }
386    
387      /**
388       * Whether or not this is an instance of RVMArray?
389       * @return true
390       */
391      @Override
392      @Pure
393      @Uninterruptible
394      public boolean isArrayType() {
395        return true;
396      }
397    
398      /**
399       * Whether or not this is a primitive type
400       * @return false
401       */
402      @Override
403      @Pure
404      @Uninterruptible
405      public boolean isPrimitiveType() {
406        return false;
407      }
408    
409      /**
410       * @return whether or not this is a reference (ie non-primitive) type.
411       */
412      @Override
413      @Pure
414      @Uninterruptible
415      public boolean isReferenceType() {
416        return true;
417      }
418    
419      /**
420       * @return whether or not this is an unboxed type
421       */
422      @Override
423      @Pure
424      @Uninterruptible
425      public boolean isUnboxedType() {
426        return false;
427      }
428    
429      /**
430       * Constructor
431       * @param typeRef
432       * @param elementType
433       */
434      RVMArray(TypeReference typeRef, RVMType elementType) {
435        super(typeRef, typeRef.getDimensionality(), null);
436        this.elementType = elementType;
437        this.logElementSize = computeLogElementSize();
438        depth = 1;
439    
440        if (elementType.isArrayType()) {
441          innermostElementType = elementType.asArray().getInnermostElementType();
442        } else {
443          innermostElementType = elementType;
444        }
445        innermostElementTypeDimension = innermostElementType.dimension;
446        if (VM.BuildForIA32 && typeRef == TypeReference.CodeArray) {
447          this.alignment = 16;
448        } else if (BYTES_IN_DOUBLE != BYTES_IN_ADDRESS) {
449          // Desired alignment on 32bit architectures
450          if (elementType.isDoubleType() || elementType.isLongType()) {
451            this.alignment = BYTES_IN_DOUBLE;
452          } else {
453            this.alignment = BYTES_IN_ADDRESS;
454          }
455        } else {
456          this.alignment = BYTES_IN_DOUBLE;
457        }
458    
459        // RCGC: Array is acyclic if its references are acyclic
460        acyclic = elementType.isAcyclicReference();
461    
462        state = CLASS_LOADED;
463    
464        if (VM.verboseClassLoading) VM.sysWrite("[Loaded " + this.getDescriptor() + "]\n");
465        if (VM.verboseClassLoading) VM.sysWrite("[Loaded superclasses of " + this.getDescriptor() + "]\n");
466      }
467    
468      /**
469       * Resolve an array.
470       * Also forces the resolution of the element type.
471       */
472      @Override
473      public synchronized void resolve() {
474        if (isResolved()) return;
475    
476        if (VM.VerifyAssertions) VM._assert(state == CLASS_LOADED);
477    
478        elementType.resolve();
479    
480        // Using the type information block for java.lang.Object as a template,
481        // build a type information block for this new array type by copying the
482        // virtual method fields and substituting an appropriate type field.
483        //
484        TIB javaLangObjectTIB = RVMType.JavaLangObjectType.getTypeInformationBlock();
485        TIB allocatedTib = MemoryManager.newTIB(javaLangObjectTIB.numVirtualMethods());
486        superclassIds = DynamicTypeCheck.buildSuperclassIds(this);
487        doesImplement = DynamicTypeCheck.buildDoesImplement(this);
488        publishResolved(allocatedTib, superclassIds, doesImplement);
489    
490        MemoryManager.notifyClassResolved(this);
491      }
492    
493      /**
494       * Atomically initialize the important parts of the TIB and let the world know this type is
495       * resolved.
496       *
497       * @param allocatedTib The TIB that has been allocated for this type
498       * @param superclassIds The calculated superclass ids array
499       * @param doesImplement The calculated does implement array
500       */
501      @Uninterruptible
502      private void publishResolved(TIB allocatedTib, short[] superclassIds, int[] doesImplement) {
503        Statics.setSlotContents(getTibOffset(), allocatedTib);
504        allocatedTib.setType(this);
505        allocatedTib.setSuperclassIds(superclassIds);
506        allocatedTib.setDoesImplement(doesImplement);
507        if (!(elementType.isPrimitiveType()||elementType.isUnboxedType())) {
508          allocatedTib.setArrayElementTib(elementType.getTypeInformationBlock());
509        }
510        typeInformationBlock = allocatedTib;
511        state = CLASS_RESOLVED;
512      }
513    
514      @Override
515      public void allBootImageTypesResolved() {
516        // nothing to do
517      }
518    
519      /**
520       * Instantiate an array.
521       * Main result is to copy the virtual methods from JavaLangObject's tib.
522       */
523      @Override
524      public synchronized void instantiate() {
525        if (isInstantiated()) return;
526    
527        if (VM.VerifyAssertions) VM._assert(state == CLASS_RESOLVED);
528        if (VM.TraceClassLoading && VM.runningVM) {
529          VM.sysWrite("RVMArray: instantiate " + this + "\n");
530        }
531    
532        // Initialize TIB slots for virtual methods (copy from superclass == Object)
533        RVMType objectType = RVMType.JavaLangObjectType;
534        int retries=0;
535        while(!objectType.isInstantiated()) {
536          try {
537            Thread.sleep(1);
538          } catch (InterruptedException e) {}
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 <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_BOOLEAN_ASTORE_BARRIER || NEEDS_BOOLEAN_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 srcIdx The starting source index
1158       * @param dst The destination array
1159       * @param dstIdx The starting destination index
1160       * @param len The number of array elements to be copied
1161       */
1162      private static void arraycopyPiecemealNoCheckcast(Object[] src, Object[] dst, int len,
1163          Offset srcOffset, Offset dstOffset, int bytes) {
1164    
1165        // set up things according to the direction of the copy
1166        int increment;
1167        if (srcOffset.sGT(dstOffset)) { // direction of copy
1168          increment = BYTES_IN_ADDRESS;
1169        } else {
1170          srcOffset = srcOffset.plus(bytes - BYTES_IN_ADDRESS);
1171          dstOffset = dstOffset.plus(bytes - BYTES_IN_ADDRESS);
1172          increment = -BYTES_IN_ADDRESS;
1173        }
1174    
1175        // perform the copy
1176        while (len-- != 0) {
1177          Object value;
1178          if (NEEDS_OBJECT_ALOAD_BARRIER) {
1179            value = Barriers.objectArrayRead(src, srcOffset.toInt() >> LOG_BYTES_IN_ADDRESS);
1180          } else {
1181            value = Magic.getObjectAtOffset(src, srcOffset);
1182          }
1183          if (NEEDS_OBJECT_ASTORE_BARRIER) {
1184            Barriers.objectArrayWrite(dst, dstOffset.toInt() >> LOG_BYTES_IN_ADDRESS, value);
1185          } else {
1186            Magic.setObjectAtOffset(dst, dstOffset, value);
1187          }
1188          srcOffset = srcOffset.plus(increment);
1189          dstOffset = dstOffset.plus(increment);
1190        }
1191      }
1192    
1193      /**
1194       * Perform an array copy for arrays of objects where the possibility
1195       * of an ArrayStoreException being thrown exists.  This must be done
1196       * with element by element assignments in the correct order.
1197       * <i>Since write barriers are implicitly performed on explicit
1198       * array stores, there is no need to explicitly invoke a write
1199       * barrier in this code.</i>
1200       *
1201       * @param src The source array
1202       * @param srcIdx The starting source index
1203       * @param dst The destination array
1204       * @param dstIdx The starting destination index
1205       * @param len The number of array elements to be copied
1206       */
1207      private static void arraycopyPiecemeal(Object[] src, int srcIdx, Object[] dst, int dstIdx, int len) {
1208        if ((src != dst) || srcIdx >= dstIdx) {
1209          while (len-- != 0) {
1210            dst[dstIdx++] = src[srcIdx++];
1211          }
1212        } else {
1213          srcIdx += len;
1214          dstIdx += len;
1215          while (len-- != 0) {
1216            dst[--dstIdx] = src[--srcIdx];
1217          }
1218        }
1219      }
1220    
1221      @NoInline
1222      private static void failWithIndexOutOfBoundsException() {
1223        throw new ArrayIndexOutOfBoundsException();
1224      }
1225    }