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 }