/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.classloader;
import org.jikesrvm.ArchitectureSpecific;
import org.jikesrvm.VM;
import org.jikesrvm.VM_Constants;
import org.jikesrvm.memorymanagers.mminterface.MM_Constants;
import org.jikesrvm.memorymanagers.mminterface.MM_Interface;
import org.jikesrvm.objectmodel.VM_JavaHeaderConstants;
import org.jikesrvm.objectmodel.VM_ObjectModel;
import org.jikesrvm.objectmodel.VM_TIBLayoutConstants;
import org.jikesrvm.runtime.VM_Magic;
import org.jikesrvm.runtime.VM_Memory;
import org.jikesrvm.runtime.VM_Runtime;
import org.jikesrvm.runtime.VM_Statics;
import org.jikesrvm.runtime.VM_SubArchStatics;
import org.vmmagic.pragma.Entrypoint;
import org.vmmagic.pragma.Inline;
import org.vmmagic.pragma.NoInline;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Offset;
/**
* Description of a java "array" type. <p>
*
* This description is not read from a ".class" file, but rather
* is manufactured by the vm as execution proceeds.
*
* @see VM_Type
* @see VM_Class
* @see VM_Primitive
*/
public final class VM_Array extends VM_Type implements VM_Constants, VM_ClassLoaderConstants {
/*
* We hold on to a number of commonly used arrays for easy access.
*/
public static final VM_Array BooleanArray;
public static final VM_Array ByteArray;
public static final VM_Array CharArray;
public static final VM_Array ShortArray;
public static final VM_Array IntArray;
public static final VM_Array LongArray;
public static final VM_Array FloatArray;
public static final VM_Array DoubleArray;
public static final VM_Array JavaLangObjectArray;
static {
BooleanArray = (VM_Array) VM_TypeReference.BooleanArray.resolve(false);
CharArray = (VM_Array) VM_TypeReference.CharArray.resolve(false);
FloatArray = (VM_Array) VM_TypeReference.FloatArray.resolve(false);
DoubleArray = (VM_Array) VM_TypeReference.DoubleArray.resolve(false);
ByteArray = (VM_Array) VM_TypeReference.ByteArray.resolve(false);
ShortArray = (VM_Array) VM_TypeReference.ShortArray.resolve(false);
IntArray = (VM_Array) VM_TypeReference.IntArray.resolve(false);
LongArray = (VM_Array) VM_TypeReference.LongArray.resolve(false);
JavaLangObjectArray = (VM_Array) VM_TypeReference.JavaLangObjectArray.resolve(false);
}
/**
* The VM_Type object for elements of this array type.
*/
private final VM_Type elementType;
/**
* The log of the element size for this array type.
*/
private final int logElementSize;
/**
* The VM_Type object for the innermost element of this array type.
*/
@Entrypoint
private final VM_Type innermostElementType;
/**
* The desired alignment for instances of this type.
* Cached rather than computed because this is a frequently
* asked question
*/
private final int alignment;
/**
* Reference Count GC: is this type acyclic?
*/
private final boolean acyclic;
/**
* The TIB for this type, created when the array is resolved.
*/
private Object[] typeInformationBlock;
/**
* current class-loading stage (loaded, resolved or initialized)
*/
private int state;
/**
* current class-loading stage for subarch (loaded, resolved or initialized)
*/
private int subArchState;
/**
* Is this array type in the bootimage?
*/
private boolean inBootImage;
/**
* Name - something like "[I" or "[Ljava.lang.String;"
*/
public String toString() {
return getDescriptor().toString().replace('/', '.');
}
/**
* @return java Expression stack space requirement.
*/
@Uninterruptible
public int getStackWords() {
return 1;
}
/**
* Space required in memory in bytes.
*/
@Uninterruptible
public int getMemoryBytes() {
return BYTES_IN_ADDRESS;
}
/**
* @return element type.
*/
@Uninterruptible
public VM_Type getElementType() {
return elementType;
}
/**
* @return innermost element type
*/
@Uninterruptible
public VM_Type getInnermostElementType() {
return innermostElementType;
}
/**
* @return alignment for instances of this array type
*/
@Uninterruptible
public int getAlignment() {
return alignment;
}
/**
* Size, in bytes, of an array element, log base 2.
* @return log base 2 of array element size
*/
@Uninterruptible
public int getLogElementSize() {
return logElementSize;
}
/**
* Calculate the size, in bytes, of an array element, log base 2.
* @return log base 2 of array element size
*/
private int computeLogElementSize() {
if (elementType.getTypeRef().equals(VM_TypeReference.Code)) {
return ArchitectureSpecific.VM_ArchConstants.LG_INSTRUCTION_WIDTH;
}
switch (getDescriptor().parseForArrayElementTypeCode()) {
case VM_Atom.ClassTypeCode:
return LOG_BYTES_IN_ADDRESS;
case VM_Atom.ArrayTypeCode:
return LOG_BYTES_IN_ADDRESS;
case VM_Atom.BooleanTypeCode:
return LOG_BYTES_IN_BOOLEAN;
case VM_Atom.ByteTypeCode:
return 0;
case VM_Atom.ShortTypeCode:
return LOG_BYTES_IN_SHORT;
case VM_Atom.IntTypeCode:
return LOG_BYTES_IN_INT;
case VM_Atom.LongTypeCode:
return LOG_BYTES_IN_LONG;
case VM_Atom.FloatTypeCode:
return LOG_BYTES_IN_FLOAT;
case VM_Atom.DoubleTypeCode:
return LOG_BYTES_IN_DOUBLE;
case VM_Atom.CharTypeCode:
return LOG_BYTES_IN_CHAR;
}
if (VM.VerifyAssertions) VM._assert(NOT_REACHED);
return -1;
}
/**
* Total size, in bytes, of an instance of this array type (including object header).
* @param numelts number of array elements in the instance
* @return size in bytes
*/
@Inline
@Uninterruptible
public int getInstanceSize(int numelts) {
return VM_ObjectModel.computeArrayHeaderSize(this) + (numelts << getLogElementSize());
}
/**
* Does this class override java.lang.Object.finalize()?
*/
@Uninterruptible
public boolean hasFinalizer() {
return false;
}
/**
* Static fields of this array type.
*/
public VM_Field[] getStaticFields() {
return VM_Type.JavaLangObjectType.getStaticFields();
}
/**
* Non-static fields of this array type.
*/
public VM_Field[] getInstanceFields() {
return VM_Type.JavaLangObjectType.getInstanceFields();
}
/**
* Statically dispatched methods of this array type.
*/
public VM_Method[] getStaticMethods() {
return VM_Type.JavaLangObjectType.getStaticMethods();
}
/**
* Virtually dispatched methods of this array type.
*/
public VM_Method[] getVirtualMethods() {
return VM_Type.JavaLangObjectType.getVirtualMethods();
}
/**
* Runtime type information for this array type.
*/
@Uninterruptible
public Object[] getTypeInformationBlock() {
if (VM.VerifyAssertions) VM._assert(isResolved(false));
return typeInformationBlock;
}
/**
* Does this slot in the TIB hold a TIB entry?
* @param slot the TIB slot
* @return true if this the array element TIB
*/
public boolean isTIBSlotTIB(int slot) {
if (VM.VerifyAssertions) checkTIBSlotIsAccessible(slot);
return slot == TIB_ARRAY_ELEMENT_TIB_INDEX;
}
/**
* Does this slot in the TIB hold code?
* @param slot the TIB slot
* @return true if slot is one that holds a code array reference
*/
public boolean isTIBSlotCode(int slot) {
if (VM.VerifyAssertions) checkTIBSlotIsAccessible(slot);
return slot >= TIB_FIRST_VIRTUAL_METHOD_INDEX;
}
/**
* get number of superclasses to Object
* @return 1
*/
@Uninterruptible
public int getTypeDepth() {
return 1;
}
/**
* Reference Count GC: Is a reference of this type contained in
* another object inherently acyclic (without cycles) ?
* @return true
*/
@Uninterruptible
public boolean isAcyclicReference() {
return acyclic;
}
/**
* Number of [ in descriptor for arrays; -1 for primitives; 0 for
* classes
*/
@Uninterruptible
public int getDimensionality() {
return dimension;
}
/**
* Loaded status.
*/
@Uninterruptible
public boolean isLoaded(boolean forSubArch) {
if (forSubArch) {
return subArchState >= CLASS_LOADED;
} else {
return state >= CLASS_LOADED;
}
}
/**
* Resolution status.
*/
@Uninterruptible
public boolean isResolved(boolean forSubArch) {
if (forSubArch) {
return subArchState >= CLASS_RESOLVED;
} else {
return state >= CLASS_RESOLVED;
}
}
/**
* Instantiation status.
*/
@Uninterruptible
public boolean isInstantiated(boolean forSubArch) {
if (forSubArch) {
return subArchState >= CLASS_INSTANTIATED;
} else {
return state >= CLASS_INSTANTIATED;
}
}
/**
* Initialization status.
*/
@Uninterruptible
public boolean isInitialized(boolean forSubArch) {
if (forSubArch) {
return subArchState >= CLASS_INITIALIZED;
} else {
return state >= CLASS_INITIALIZED;
}
}
/**
* Only intended to be used by the BootImageWriter
*/
public void markAsBootImageClass() {
inBootImage = true;
}
/**
* Is this class part of the virtual machine's boot image?
*/
@Uninterruptible
public boolean isInBootImage() {
return inBootImage;
}
/**
* Get the offset in instances of this type assigned to the thin lock word.
* Offset.max() if instances of this type do not have thin lock words.
*/
@Uninterruptible
public Offset getThinLockOffset() {
return VM_ObjectModel.defaultThinLockOffset();
}
/**
* Whether or not this is an instance of VM_Class?
* @return false
*/
@Uninterruptible
public boolean isClassType() {
return false;
}
/**
* Whether or not this is an instance of VM_Array?
* @return true
*/
@Uninterruptible
public boolean isArrayType() {
return true;
}
/**
* Whether or not this is a primitive type
* @return false
*/
@Uninterruptible
public boolean isPrimitiveType() {
return false;
}
/**
* @return whether or not this is a reference (ie non-primitive) type.
*/
@Uninterruptible
public boolean isReferenceType() {
return true;
}
/**
* Constructor
* @param typeRef
* @param elementType
*/
VM_Array(VM_TypeReference typeRef, VM_Type elementType) {
super(typeRef, typeRef.getDimensionality(), null, elementType.annoModifiers);
this.elementType = elementType;
this.logElementSize = computeLogElementSize();
depth = 1;
if (elementType.isArrayType()) {
innermostElementType = elementType.asArray().getInnermostElementType();
} else {
innermostElementType = elementType;
}
if (this.toString().equals("[Lorg.jikesrvm.ia32.VM_Code;")) {
this.alignment = 16;
} else if (this.toString().equals("[Lorg.jikesrvm.cellspu.VM_Code;")) {
this.alignment = 16;
} else if (VM.SubArchCellSpu) {
this.alignment = 16;
} else if (BYTES_IN_DOUBLE != BYTES_IN_ADDRESS) {
// Desired alignment on 32bit architectures
if (elementType.isDoubleType() || elementType.isLongType()) {
this.alignment = BYTES_IN_DOUBLE;
} else {
this.alignment = BYTES_IN_ADDRESS;
}
} else {
this.alignment = BYTES_IN_DOUBLE;
}
// RCGC: Array is acyclic if its references are acyclic
acyclic = elementType.isAcyclicReference();
state = CLASS_LOADED;
if (VM.verboseClassLoading) VM.sysWrite("[Loaded " + this.getDescriptor() + "]\n");
if (VM.verboseClassLoading) VM.sysWrite("[Loaded superclasses of " + this.getDescriptor() + "]\n");
}
/**
* Load an array.
* Implicit for arrays
*/
public synchronized void load(boolean forSubArch) {
if (forSubArch) {
subArchState = CLASS_LOADED;
return;
} else {
return;
}
}
/**
* Resolve an array.
* Also forces the resolution of the element type.
*/
public synchronized void resolve(boolean forSubArch) {
if (forSubArch) {
resolveForSubArch();
} else {
resolveForMainArch();
}
}
/**
* Resolve an array.
* Also forces the resolution of the element type.
*/
private void resolveForMainArch() {
if (isResolved(false)) return;
if (VM.VerifyAssertions) VM._assert(state == CLASS_LOADED);
elementType.resolve(false);
// Using the type information block for java.lang.Object as a template,
// build a type information block for this new array type by copying the
// virtual method fields and substituting an appropriate type field.
//
Object[] javaLangObjectTIB = VM_Type.JavaLangObjectType.getTypeInformationBlock();
typeInformationBlock = MM_Interface.newTIB(javaLangObjectTIB.length);
VM_Statics.setSlotContents(getTibOffset(), typeInformationBlock);
// Initialize dynamic type checking data structures
typeInformationBlock[TIB_TYPE_INDEX] = this;
typeInformationBlock[TIB_SUPERCLASS_IDS_INDEX] = VM_DynamicTypeCheck.buildSuperclassIds(this);
typeInformationBlock[TIB_DOES_IMPLEMENT_INDEX] = VM_DynamicTypeCheck.buildDoesImplement(this);
if (!elementType.isPrimitiveType()) {
typeInformationBlock[TIB_ARRAY_ELEMENT_TIB_INDEX] = elementType.getTypeInformationBlock();
}
if (VM_JavaHeaderConstants.SUBARCH_CLASS_IDX_IN_HEADER) {
subArchTocIdx = Offset.fromIntZeroExtend(VM_TIBLayoutConstants.NOT_RESOLVED_FOR_SUBARCH);
if (VM.runningVM) {
typeInformationBlock[TIB_SUBARCH_CLASS_IDX] = VM_Magic.addressAsObject(Address.fromIntZeroExtend(VM_TIBLayoutConstants.NOT_RESOLVED_FOR_SUBARCH));
} else {
typeInformationBlock[TIB_SUBARCH_CLASS_IDX] = null;
//VM_Magic.bootWriterFixup(typeInformationBlock, TIB_SUBARCH_CLASS_IDX << LOG_BYTES_IN_ADDRESS, VM_TIBLayoutConstants.NOT_RESOLVED_FOR_SUBARCH);
}
}
state = CLASS_RESOLVED;
MM_Interface.notifyClassResolved(this);
}
/**
* Resolve an array for the subarch.
* Also forces the resolution of the element type.
*/
private void resolveForSubArch() {
if (isResolved(true)) return;
if (!isLoaded(true)) load(true);
if (!isResolved(false)) resolve(false);
if (VM.VerifyAssertions) VM._assert(subArchState == CLASS_LOADED);
elementType.resolve(true);
Object[] javaLangObjectTIB = VM_Type.JavaLangObjectType.subArchTIB;
subArchTIB = MM_Interface.newTIB(javaLangObjectTIB.length);
// Initialize dynamic type checking data structures
subArchTIB[TIB_TYPE_INDEX] = this;
subArchTIB[TIB_SUPERCLASS_IDS_INDEX] = VM_DynamicTypeCheck.buildSuperclassIds(this);
subArchTIB[TIB_DOES_IMPLEMENT_INDEX] = VM_DynamicTypeCheck.buildDoesImplement(this);
if (!elementType.isPrimitiveType()) {
subArchTIB[TIB_ARRAY_ELEMENT_TIB_INDEX] = elementType.getTypeInformationBlock();
}
subArchTocIdx = VM_SubArchStatics.addNewType(Address.zero(), 0, Address.zero(), 0,
VM_Magic.objectAsAddress(subArchTIB), subArchTIB.length << LOG_BYTES_IN_ADDRESS);
if (VM_JavaHeaderConstants.SUBARCH_CLASS_IDX_IN_HEADER) {
if (VM.runningVM) {
typeInformationBlock[TIB_SUBARCH_CLASS_IDX] = VM_Magic.addressAsObject(Address.fromIntZeroExtend(subArchTocIdx.toInt() >> LOG_BYTES_IN_ADDRESS));
} else {
typeInformationBlock[TIB_SUBARCH_CLASS_IDX] = null;
//VM_Magic.bootWriterFixup(typeInformationBlock, TIB_SUBARCH_CLASS_IDX << LOG_BYTES_IN_ADDRESS, subArchTocIdx.toInt() >> LOG_BYTES_IN_ADDRESS);
}
}
subArchState = CLASS_RESOLVED;
}
public void allBootImageTypesResolved() {
// nothing to do
}
/**
* Instantiate an array.
* Main result is to copy the virtual methods from JavaLangObject's tib.
*/
public synchronized void instantiate(boolean forSubArch) {
if (forSubArch) {
instantiateForSubArch();
} else {
instantiateForMainArch();
}
}
/**
* Instantiate an array.
* Main result is to copy the virtual methods from JavaLangObject's tib.
*/
private void instantiateForMainArch() {
if (isInstantiated(false)) return;
if (VM.VerifyAssertions) VM._assert(state == CLASS_RESOLVED);
if (VM.TraceClassLoading && VM.runningVM) {
VM.sysWrite("VM_Array: instantiate " + this + "\n");
}
// Initialize TIB slots for virtual methods (copy from superclass == Object)
VM_Type objectType = VM_Type.JavaLangObjectType;
while(!objectType.isInstantiated(false)) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
}
if (VM.VerifyAssertions) VM._assert(objectType.isInstantiated(false));
Object[] javaLangObjectTIB = objectType.getTypeInformationBlock();
for (int i = TIB_FIRST_VIRTUAL_METHOD_INDEX; i < javaLangObjectTIB.length; i++) {
typeInformationBlock[i] = javaLangObjectTIB[i];
}
VM_SpecializedMethodManager.notifyTypeInstantiated(this);
state = CLASS_INITIALIZED; // arrays have no "initialize" phase
}
/**
* Instantiate an array for SubArch.
* Main result is to copy the virtual methods from JavaLangObject's tib.
*/
private void instantiateForSubArch() {
if (isInstantiated(false)) return;
if (VM.VerifyAssertions) VM._assert(subArchState == CLASS_RESOLVED);
// Initialize TIB slots for virtual methods (copy from superclass == Object)
VM_Type objectType = VM_Type.JavaLangObjectType;
while(!objectType.isInstantiated(true)) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
}
if (VM.VerifyAssertions) VM._assert(objectType.isInstantiated(true));
Object[] javaLangObjectTIB = objectType.subArchTIB;
for (int i = TIB_FIRST_SUBARCH_METHOD_INDEX; i < javaLangObjectTIB.length; i++) {
subArchTIB[i] = javaLangObjectTIB[i];
}
subArchState = CLASS_INITIALIZED; // arrays have no "initialize" phase
}
/**
* Initialization is a no-op (arrays have no <clinit> method).
*/
public void initialize(boolean forSubArch) { }
//-------------------------------------------------------------------------------------------------//
// Misc static methods. //
//-------------------------------------------------------------------------------------------------//
/**
* Get description of specified primitive array.
* @param atype array type number (see "newarray" bytecode description in Java VM Specification)
* @return array description
*/
public static VM_Array getPrimitiveArrayType(int atype) {
switch (atype) {
case 4:
return BooleanArray;
case 5:
return CharArray;
case 6:
return FloatArray;
case 7:
return DoubleArray;
case 8:
return ByteArray;
case 9:
return ShortArray;
case 10:
return IntArray;
case 11:
return LongArray;
}
if (VM.VerifyAssertions) VM._assert(NOT_REACHED);
return null;
}
//--------------------------------------------------------------------------------------------------//
// Support for array copy //
//--------------------------------------------------------------------------------------------------//
/**
* Perform an array copy for arrays of bytes.
*
* @param src The source array
* @param srcIdx The starting source index
* @param dst The destination array
* @param dstIdx The starting destination index
* @param len The number of array elements to be copied
*/
public static void arraycopy(byte[] src, int srcIdx, byte[] dst, int dstIdx, int len) {
// Don't do any of the assignments if the offsets and lengths
// are in error
if (srcIdx >= 0 &&
dstIdx >= 0 &&
len >= 0 &&
(srcIdx + len) >= 0 &&
(srcIdx + len) <= src.length &&
(dstIdx + len) >= 0 &&
(dstIdx + len) <= dst.length) {
if (src != dst || srcIdx >= (dstIdx + BYTES_IN_ADDRESS)) {
VM_Memory.arraycopy8Bit(src, srcIdx, dst, dstIdx, len);
} else {
arraycopyOverlap(src, srcIdx, dst, dstIdx, len);
}
} else {
failWithIndexOutOfBoundsException();
}
}
// Outlined unlikely case of potentially overlapping subarrays
// Motivation is to reduce code space costs of inlined array copy.
@NoInline
private static void arraycopyOverlap(byte[] src, int srcIdx, byte[] dst, int dstIdx, int len) {
if (srcIdx < dstIdx) {
srcIdx += len;
dstIdx += len;
while (len-- != 0) {
dst[--dstIdx] = src[--srcIdx];
}
} else {
while (len-- != 0) {
dst[dstIdx++] = src[srcIdx++];
}
}
}
/**
* Perform an array copy for arrays of booleans.
*
* @param src The source array
* @param srcIdx The starting source index
* @param dst The destination array
* @param dstIdx The starting destination index
* @param len The number of array elements to be copied
*/
public static void arraycopy(boolean[] src, int srcIdx, boolean[] dst, int dstIdx, int len) {
// Don't do any of the assignments if the offsets and lengths
// are in error
if (srcIdx >= 0 &&
dstIdx >= 0 &&
len >= 0 &&
(srcIdx + len) >= 0 &&
(srcIdx + len) <= src.length &&
(dstIdx + len) >= 0 &&
(dstIdx + len) <= dst.length) {
if (src != dst || srcIdx >= (dstIdx + BYTES_IN_ADDRESS / BYTES_IN_BOOLEAN)) {
VM_Memory.arraycopy8Bit(src, srcIdx, dst, dstIdx, len);
} else {
arraycopyOverlap(src, srcIdx, dst, dstIdx, len);
}
} else {
failWithIndexOutOfBoundsException();
}
}
// Outlined unlikely case of potentially overlapping subarrays
// Motivation is to reduce code space costs of inlined array copy.
@NoInline
private static void arraycopyOverlap(boolean[] src, int srcIdx, boolean[] dst, int dstIdx, int len) {
if (srcIdx < dstIdx) {
srcIdx += len;
dstIdx += len;
while (len-- != 0) {
dst[--dstIdx] = src[--srcIdx];
}
} else {
while (len-- != 0) {
dst[dstIdx++] = src[srcIdx++];
}
}
}
/**
* Perform an array copy for arrays of shorts.
*
* @param src The source array
* @param srcIdx The starting source index
* @param dst The destination array
* @param dstIdx The starting destination index
* @param len The number of array elements to be copied
*/
public static void arraycopy(short[] src, int srcIdx, short[] dst, int dstIdx, int len) {
// Don't do any of the assignments if the offsets and lengths
// are in error
if (srcIdx >= 0 &&
dstIdx >= 0 &&
len >= 0 &&
(srcIdx + len) >= 0 &&
(srcIdx + len) <= src.length &&
(dstIdx + len) >= 0 &&
(dstIdx + len) <= dst.length) {
if (src != dst || srcIdx >= (dstIdx + BYTES_IN_ADDRESS / BYTES_IN_SHORT)) {
VM_Memory.arraycopy16Bit(src, srcIdx, dst, dstIdx, len);
} else {
arraycopyOverlap(src, srcIdx, dst, dstIdx, len);
}
} else {
failWithIndexOutOfBoundsException();
}
}
// Outlined unlikely case of potentially overlapping subarrays
// Motivation is to reduce code space costs of inlined array copy.
@NoInline
private static void arraycopyOverlap(short[] src, int srcIdx, short[] dst, int dstIdx, int len) {
if (srcIdx < dstIdx) {
srcIdx += len;
dstIdx += len;
while (len-- != 0) {
dst[--dstIdx] = src[--srcIdx];
}
} else {
while (len-- != 0) {
dst[dstIdx++] = src[srcIdx++];
}
}
}
/**
* Perform an array copy for arrays of chars.
*
* @param src The source array
* @param srcIdx The starting source index
* @param dst The destination array
* @param dstIdx The starting destination index
* @param len The number of array elements to be copied
*/
public static void arraycopy(char[] src, int srcIdx, char[] dst, int dstIdx, int len) {
// Don't do any of the assignments if the offsets and lengths
// are in error
if (srcIdx >= 0 &&
dstIdx >= 0 &&
len >= 0 &&
(srcIdx + len) >= 0 &&
(srcIdx + len) <= src.length &&
(dstIdx + len) >= 0 &&
(dstIdx + len) <= dst.length) {
if (src != dst || srcIdx >= (dstIdx + BYTES_IN_ADDRESS / BYTES_IN_CHAR)) {
VM_Memory.arraycopy16Bit(src, srcIdx, dst, dstIdx, len);
} else {
arraycopyOverlap(src, srcIdx, dst, dstIdx, len);
}
} else {
failWithIndexOutOfBoundsException();
}
}
// Outlined unlikely case of potentially overlapping subarrays
// Motivation is to reduce code space costs of inlined array copy.
@NoInline
private static void arraycopyOverlap(char[] src, int srcIdx, char[] dst, int dstIdx, int len) {
if (srcIdx < dstIdx) {
srcIdx += len;
dstIdx += len;
while (len-- != 0) {
dst[--dstIdx] = src[--srcIdx];
}
} else {
while (len-- != 0) {
dst[dstIdx++] = src[srcIdx++];
}
}
}
/**
* Perform an array copy for arrays of ints.
*
* @param src The source array
* @param srcIdx The starting source index
* @param dst The destination array
* @param dstIdx The starting destination index
* @param len The number of array elements to be copied
*/
public static void arraycopy(int[] src, int srcIdx, int[] dst, int dstIdx, int len) {
// Don't do any of the assignments if the offsets and lengths
// are in error
if (srcIdx >= 0 &&
dstIdx >= 0 &&
len >= 0 &&
(srcIdx + len) >= 0 &&
(srcIdx + len) <= src.length &&
(dstIdx + len) >= 0 &&
(dstIdx + len) <= dst.length) {
if (src != dst || srcIdx >= dstIdx) {
VM_Memory.arraycopy32Bit(src, srcIdx, dst, dstIdx, len);
} else {
arraycopyOverlap(src, srcIdx, dst, dstIdx, len);
}
} else {
failWithIndexOutOfBoundsException();
}
}
// Outlined unlikely case of potentially overlapping subarrays
// Motivation is to reduce code space costs of inlined array copy.
@NoInline
private static void arraycopyOverlap(int[] src, int srcIdx, int[] dst, int dstIdx, int len) {
if (srcIdx < dstIdx) {
srcIdx += len;
dstIdx += len;
while (len-- != 0) {
dst[--dstIdx] = src[--srcIdx];
}
} else {
while (len-- != 0) {
dst[dstIdx++] = src[srcIdx++];
}
}
}
/**
* Perform an array copy for arrays of floats.
*
* @param src The source array
* @param srcIdx The starting source index
* @param dst The destination array
* @param dstIdx The starting destination index
* @param len The number of array elements to be copied
*/
public static void arraycopy(float[] src, int srcIdx, float[] dst, int dstIdx, int len) {
// Don't do any of the assignments if the offsets and lengths
// are in error
if (srcIdx >= 0 &&
dstIdx >= 0 &&
len >= 0 &&
(srcIdx + len) >= 0 &&
(srcIdx + len) <= src.length &&
(dstIdx + len) >= 0 &&
(dstIdx + len) <= dst.length) {
if (src != dst || srcIdx > dstIdx) {
VM_Memory.arraycopy32Bit(src, srcIdx, dst, dstIdx, len);
} else {
arraycopyOverlap(src, srcIdx, dst, dstIdx, len);
}
} else {
failWithIndexOutOfBoundsException();
}
}
// Outlined unlikely case of potentially overlapping subarrays
// Motivation is to reduce code space costs of inlined array copy.
@NoInline
private static void arraycopyOverlap(float[] src, int srcIdx, float[] dst, int dstIdx, int len) {
if (srcIdx < dstIdx) {
srcIdx += len;
dstIdx += len;
while (len-- != 0) {
dst[--dstIdx] = src[--srcIdx];
}
} else {
while (len-- != 0) {
dst[dstIdx++] = src[srcIdx++];
}
}
}
/**
* Perform an array copy for arrays of longs.
*
* @param src The source array
* @param srcIdx The starting source index
* @param dst The destination array
* @param dstIdx The starting destination index
* @param len The number of array elements to be copied
*/
public static void arraycopy(long[] src, int srcIdx, long[] dst, int dstIdx, int len) {
// Don't do any of the assignments if the offsets and lengths
// are in error
if (srcIdx >= 0 &&
dstIdx >= 0 &&
len >= 0 &&
(srcIdx + len) >= 0 &&
(srcIdx + len) <= src.length &&
(dstIdx + len) >= 0 &&
(dstIdx + len) <= dst.length) {
if (src != dst || srcIdx > dstIdx) {
VM_Memory.arraycopy64Bit(src, srcIdx, dst, dstIdx, len);
} else {
arraycopyOverlap(src, srcIdx, dst, dstIdx, len);
}
} else {
failWithIndexOutOfBoundsException();
}
}
// Outlined unlikely case of potentially overlapping subarrays
// Motivation is to reduce code space costs of inlined array copy.
@NoInline
private static void arraycopyOverlap(long[] src, int srcIdx, long[] dst, int dstIdx, int len) {
if (srcIdx < dstIdx) {
srcIdx += len;
dstIdx += len;
while (len-- != 0) {
dst[--dstIdx] = src[--srcIdx];
}
} else {
while (len-- != 0) {
dst[dstIdx++] = src[srcIdx++];
}
}
}
/**
* Perform an array copy for arrays of doubles.
*
* @param src The source array
* @param srcIdx The starting source index
* @param dst The destination array
* @param dstIdx The starting destination index
* @param len The number of array elements to be copied
*/
public static void arraycopy(double[] src, int srcIdx, double[] dst, int dstIdx, int len) {
// Don't do any of the assignments if the offsets and lengths
// are in error
if (srcIdx >= 0 &&
dstIdx >= 0 &&
len >= 0 &&
(srcIdx + len) >= 0 &&
(srcIdx + len) <= src.length &&
(dstIdx + len) >= 0 &&
(dstIdx + len) <= dst.length) {
if (src != dst || srcIdx > dstIdx) {
VM_Memory.arraycopy64Bit(src, srcIdx, dst, dstIdx, len);
} else {
arraycopyOverlap(src, srcIdx, dst, dstIdx, len);
}
} else {
failWithIndexOutOfBoundsException();
}
}
// Outlined unlikely case of potentially overlapping subarrays
// Motivation is to reduce code space costs of inlined array copy.
@NoInline
private static void arraycopyOverlap(double[] src, int srcIdx, double[] dst, int dstIdx, int len) {
if (srcIdx < dstIdx) {
srcIdx += len;
dstIdx += len;
while (len-- != 0) {
dst[--dstIdx] = src[--srcIdx];
}
} else {
while (len-- != 0) {
dst[dstIdx++] = src[srcIdx++];
}
}
}
/**
* Perform an array copy for arrays of objects. This code must
* ensure that write barriers are invoked as if the copy were
* performed element-by-element.
*
* @param src The source array
* @param srcIdx The starting source index
* @param dst The destination array
* @param dstIdx The starting destination index
* @param len The number of array elements to be copied
*/
public static void arraycopy(Object[] src, int srcIdx, Object[] dst, int dstIdx, int len) {
// Check offsets and lengths before doing anything
if (srcIdx >= 0 &&
dstIdx >= 0 &&
len >= 0 &&
(srcIdx + len) >= 0 &&
(srcIdx + len) <= src.length &&
(dstIdx + len) >= 0 &&
(dstIdx + len) <= dst.length) {
VM_Type lhs = VM_Magic.getObjectType(dst).asArray().getElementType();
VM_Type rhs = VM_Magic.getObjectType(src).asArray().getElementType();
if ((lhs == rhs) || (lhs == VM_Type.JavaLangObjectType) || VM_Runtime.isAssignableWith(lhs, rhs)) {
fastArrayCopy(src, srcIdx, dst, dstIdx, len);
} else {
slowArrayCopy(src, srcIdx, dst, dstIdx, len);
}
} else {
failWithIndexOutOfBoundsException();
}
}
/**
* Perform an array copy for arrays of objects where the possibility
* of an ArrayStoreException being thrown <i>does not</i> exist.
* This may be done using direct byte copies, <i>however</i>, write
* barriers must be explicitly invoked (if required by the GC) since
* the write barrier associated with an explicit array store
* (aastore) will be bypassed.
*
* @param src The source array
* @param srcIdx The starting source index
* @param dst The destination array
* @param dstIdx The starting destination index
* @param len The number of array elements to be copied
*/
private static void fastArrayCopy(Object[] src, int srcIdx, Object[] dst, int dstIdx, int len) {
boolean loToHi = (srcIdx > dstIdx); // direction of copy
Offset srcOffset = Offset.fromIntZeroExtend(srcIdx << LOG_BYTES_IN_ADDRESS);
Offset dstOffset = Offset.fromIntZeroExtend(dstIdx << LOG_BYTES_IN_ADDRESS);
int bytes = len << LOG_BYTES_IN_ADDRESS;
if ((src != dst) || loToHi) {
if (!MM_Constants.NEEDS_WRITE_BARRIER ||
!MM_Interface.arrayCopyWriteBarrier(src, srcOffset, dst, dstOffset, bytes)) {
VM_Memory.alignedWordCopy(VM_Magic.objectAsAddress(dst).plus(dstOffset),
VM_Magic.objectAsAddress(src).plus(srcOffset),
bytes);
}
} else {
// set up things according to the direction of the copy
int increment;
if (loToHi) {
increment = BYTES_IN_ADDRESS;
} else {
srcOffset = srcOffset.plus(bytes - BYTES_IN_ADDRESS);
dstOffset = dstOffset.plus(bytes - BYTES_IN_ADDRESS);
increment = -BYTES_IN_ADDRESS;
}
// perform the copy
while (len-- != 0) {
Object value = VM_Magic.getObjectAtOffset(src, srcOffset);
if (MM_Constants.NEEDS_WRITE_BARRIER) {
MM_Interface.arrayStoreWriteBarrier(dst, dstOffset.toInt() >> LOG_BYTES_IN_ADDRESS, value);
} else {
VM_Magic.setObjectAtOffset(dst, dstOffset, value);
}
srcOffset = srcOffset.plus(increment);
dstOffset = dstOffset.plus(increment);
}
}
}
/**
* Perform an array copy for arrays of objects where the possibility
* of an ArrayStoreException being thrown exists. This must be done
* with element by element assignments in the correct order.
* <i>Since write barriers are implicitly performed on explicit
* array stores, there is no need to explicitly invoke a write
* barrier in this code.</i>
*
* @param src The source array
* @param srcIdx The starting source index
* @param dst The destination array
* @param dstIdx The starting destination index
* @param len The number of array elements to be copied
*/
private static void slowArrayCopy(Object[] src, int srcIdx, Object[] dst, int dstIdx, int len) {
// must perform copy in correct order
if ((src != dst) || srcIdx > dstIdx) {
// non-overlapping case: straightforward
while (len-- != 0) {
dst[dstIdx++] = src[srcIdx++];
}
} else {
// the arrays overlap: must use temp array
VM_Array ary = VM_Magic.getObjectType(src).asArray();
Object[] temp = (Object[]) VM_Runtime.resolvedNewArray(len, ary);
int cnt = len;
int tempIdx = 0;
while (cnt-- != 0) {
temp[tempIdx++] = src[srcIdx++];
}
tempIdx = 0;
while (len-- != 0) {
dst[dstIdx++] = temp[tempIdx++];
}
}
}
@NoInline
private static void failWithIndexOutOfBoundsException() {
throw new ArrayIndexOutOfBoundsException();
}
}