use of org.jikesrvm.classloader.RVMArray in project JikesRVM by JikesRVM.
the class MultianewarrayHelper method newArrayArray.
/**
* Allocate something like {@code new Foo[cnt0][cnt1]...[cntN-1]},
* or {@code new int[cnt0][cnt1]...[cntN-1]}.
* @param methodId method id of caller
* @param numDimensions number of array dimensions
* @param typeId type id of type reference for array
* @param argOffset position of word *above* `cnt0' argument within
* caller's frame This is used to access the number of elements to
* be allocated for each dimension.
*
* See also: bytecode 0xc5 ("multianewarray") in BaselineCompilerImpl
*
* @return newly allocated multidimensional array
*/
@Entrypoint
static Object newArrayArray(int methodId, int numDimensions, int typeId, int argOffset) throws NoClassDefFoundError, NegativeArraySizeException, OutOfMemoryError {
if (numDimensions == 2) {
int dim0, dim1;
// fetch number of elements to be allocated for each array dimension
VM.disableGC();
Address argp = Magic.getFramePointer().plus(argOffset);
argp = argp.minus(BYTES_IN_WORD);
dim0 = argp.loadInt();
argp = argp.minus(BYTES_IN_WORD);
dim1 = argp.loadInt();
VM.enableGC();
// validate arguments
if ((dim0 < 0) || (dim1 < 0))
throw new NegativeArraySizeException();
// create array
TypeReference tRef = TypeReference.getTypeRef(typeId);
RVMArray array = tRef.resolve().asArray();
return RuntimeEntrypoints.buildTwoDimensionalArray(methodId, dim0, dim1, array);
} else {
// fetch number of elements to be allocated for each array dimension
int[] numElements = new int[numDimensions];
VM.disableGC();
Address argp = Magic.getFramePointer().plus(argOffset);
for (int i = 0; i < numDimensions; ++i) {
argp = argp.minus(BYTES_IN_WORD);
numElements[i] = argp.loadInt();
}
VM.enableGC();
// validate arguments
for (int elements : numElements) {
if (elements < 0)
throw new NegativeArraySizeException();
}
// create array
TypeReference tRef = TypeReference.getTypeRef(typeId);
RVMArray array = tRef.resolve().asArray();
return RuntimeEntrypoints.buildMultiDimensionalArray(methodId, numElements, array);
}
}
use of org.jikesrvm.classloader.RVMArray in project JikesRVM by JikesRVM.
the class VMCommonLibrarySupport method createArray.
/* ---- Array Methods ---- */
/**
* Dynamically create an array of objects.
*
* @param cls guaranteed to be a valid object type
* @param length the length of the array
* @return the new array
* @throws NegativeArraySizeException if dim is negative
* @throws OutOfMemoryError if memory allocation fails
*/
static Object createArray(Class<?> cls, int length) throws OutOfMemoryError, NegativeArraySizeException {
if (cls == Void.TYPE)
throwNewIllegalArgumentException("Cannot create new array instance for the specified arguments");
// will raise NPE
RVMArray arrayType = java.lang.JikesRVMSupport.getTypeForClass(cls).getArrayTypeForElementType();
if (!arrayType.isInitialized()) {
arrayType.resolve();
arrayType.instantiate();
arrayType.initialize();
}
// will check -ve array size
return RuntimeEntrypoints.resolvedNewArray(length, arrayType);
}
use of org.jikesrvm.classloader.RVMArray in project JikesRVM by JikesRVM.
the class MemoryManagerTest method allocateArrayTestPositive.
@Test
public void allocateArrayTestPositive() {
int size = 20;
RVMArray arrayType = RVMArray.IntArray;
int headerSize = ObjectModel.computeArrayHeaderSize(arrayType);
int align = ObjectModel.getAlignment(arrayType);
int offset = ObjectModel.getOffsetForAlignment(arrayType, false);
int width = arrayType.getLogElementSize();
TIB arrayTib = arrayType.getTypeInformationBlock();
int[] test = (int[]) MemoryManager.allocateArray(size, width, headerSize, arrayTib, ALLOC_NON_MOVING, align, offset, DEFAULT_SITE);
assertEquals(test.length, 20);
}
use of org.jikesrvm.classloader.RVMArray in project JikesRVM by JikesRVM.
the class MemoryManagerTest method allocateArrayTestOverflowToPositive.
@Test(expected = OutOfMemoryError.class)
public void allocateArrayTestOverflowToPositive() {
int size = 1 << 30;
RVMArray arrayType = RVMArray.IntArray;
int headerSize = ObjectModel.computeArrayHeaderSize(arrayType);
int align = ObjectModel.getAlignment(arrayType);
int offset = ObjectModel.getOffsetForAlignment(arrayType, false);
int width = arrayType.getLogElementSize();
TIB arrayTib = arrayType.getTypeInformationBlock();
int[] test = (int[]) MemoryManager.allocateArray(size, width, headerSize, arrayTib, ALLOC_NON_MOVING, align, offset, DEFAULT_SITE);
fail("FAIL! Created array with length " + test.length);
}
use of org.jikesrvm.classloader.RVMArray in project JikesRVM by JikesRVM.
the class DynamicTypeCheckExpansion method generateBranchingTypeCheck.
/**
* Generate a branching dynamic type check.
* This routine assumes that the CFG and code order are already
* correctly established.
* This routine must either remove s or mutate it.
*
* @param s The Instruction that is to be replaced by a
* branching type check
* @param ir The IR containing the instruction to be expanded.
* @param RHSobj The RegisterOperand containing the rhs object.
* @param LHStype The TypeReference to be tested against.
* @param RHStib The Operand containing the TIB of the rhs.
* @param trueBlock The BasicBlock to continue at if the typecheck
* evaluates to true
* @param falseBlock The BasicBlock to continue at if the typecheck
* evaluates to false.
* @param oldGuard A suitable guard operand (not necessarily related
* the instruction that is to be replaced).
* @param falseProb The probability that typecheck will branch to the falseBlock
* @return the opt instruction immediately before the instruction to
* continue expansion.
*/
private static Instruction generateBranchingTypeCheck(Instruction s, IR ir, Operand RHSobj, TypeReference LHStype, Operand RHStib, BasicBlock trueBlock, BasicBlock falseBlock, RegisterOperand oldGuard, BranchProfileOperand falseProb) {
Instruction continueAt = Goto.create(GOTO, trueBlock.makeJumpTarget());
continueAt.copyPosition(s);
s.insertBefore(continueAt);
s.remove();
if (LHStype.isClassType()) {
RVMClass LHSclass = (RVMClass) LHStype.peekType();
if (LHSclass != null && LHSclass.isResolved()) {
// class or interface
if (LHSclass.isInterface()) {
// A resolved interface (case 4)
int interfaceIndex = LHSclass.getDoesImplementIndex();
int interfaceMask = LHSclass.getDoesImplementBitMask();
RegisterOperand doesImpl = InsertUnary(continueAt, ir, GET_DOES_IMPLEMENT_FROM_TIB, TypeReference.IntArray, RHStib);
if (DynamicTypeCheck.MIN_DOES_IMPLEMENT_SIZE <= interfaceIndex) {
RegisterOperand doesImplLength = InsertGuardedUnary(continueAt, ir, ARRAYLENGTH, TypeReference.Int, doesImpl.copyD2U(), TG());
Instruction lengthCheck = IfCmp.create(INT_IFCMP, oldGuard, doesImplLength, IC(interfaceIndex), ConditionOperand.LESS_EQUAL(), falseBlock.makeJumpTarget(), BranchProfileOperand.unlikely());
if (oldGuard != null) {
oldGuard = oldGuard.copyD2D();
}
continueAt.insertBefore(lengthCheck);
BasicBlock oldBlock = continueAt.getBasicBlock();
oldBlock.splitNodeWithLinksAt(lengthCheck, ir);
// required due to splitNode!
oldBlock.insertOut(falseBlock);
}
RegisterOperand entry = InsertLoadOffset(continueAt, ir, INT_LOAD, TypeReference.Int, doesImpl, Offset.fromIntZeroExtend(interfaceIndex << 2), new LocationOperand(TypeReference.Int), TG());
RegisterOperand bit = insertBinary(continueAt, ir, INT_AND, TypeReference.Int, entry, IC(interfaceMask));
continueAt.insertBefore(IfCmp.create(INT_IFCMP, oldGuard, bit, IC(0), ConditionOperand.EQUAL(), falseBlock.makeJumpTarget(), falseProb));
return continueAt;
} else {
// A resolved class (cases 5 and 6 in DynamicTypeCheck)
if (LHSclass.isFinal()) {
// For a final class, we can do a PTR compare of
// rhsTIB and the TIB of the class
Operand classTIB = getTIB(continueAt, ir, LHSclass);
continueAt.insertBefore(IfCmp.create(REF_IFCMP, oldGuard, RHStib, classTIB, ConditionOperand.NOT_EQUAL(), falseBlock.makeJumpTarget(), falseProb));
return continueAt;
} else {
// Do the full blown case 5 or 6 typecheck.
int LHSDepth = LHSclass.getTypeDepth();
int LHSId = LHSclass.getId();
RegisterOperand superclassIds = InsertUnary(continueAt, ir, GET_SUPERCLASS_IDS_FROM_TIB, TypeReference.ShortArray, RHStib);
if (DynamicTypeCheck.MIN_SUPERCLASS_IDS_SIZE <= LHSDepth) {
RegisterOperand superclassIdsLength = InsertGuardedUnary(continueAt, ir, ARRAYLENGTH, TypeReference.Int, superclassIds.copyD2U(), TG());
Instruction lengthCheck = IfCmp.create(INT_IFCMP, oldGuard, superclassIdsLength, IC(LHSDepth), ConditionOperand.LESS(), falseBlock.makeJumpTarget(), BranchProfileOperand.unlikely());
if (oldGuard != null) {
oldGuard = oldGuard.copyD2D();
}
continueAt.insertBefore(lengthCheck);
BasicBlock oldBlock = continueAt.getBasicBlock();
oldBlock.splitNodeWithLinksAt(lengthCheck, ir);
// required due to splitNode!
oldBlock.insertOut(falseBlock);
}
RegisterOperand refCandidate = InsertLoadOffset(continueAt, ir, USHORT_LOAD, TypeReference.Short, superclassIds, Offset.fromIntZeroExtend(LHSDepth << 1), new LocationOperand(TypeReference.Short), TG());
continueAt.insertBefore(IfCmp.create(INT_IFCMP, oldGuard, refCandidate, IC(LHSId), ConditionOperand.NOT_EQUAL(), falseBlock.makeJumpTarget(), falseProb));
return continueAt;
}
}
} else {
// A non-resolved class or interface. Case 3 of DynamicTypeCheck
// Branch on the result of a call to
// RuntimeEntrypoints.instance
RegisterOperand result = ir.regpool.makeTempInt();
RVMMethod target = Entrypoints.instanceOfMethod;
Instruction call = Call.create2(CALL, result, AC(target.getOffset()), MethodOperand.STATIC(target), RHSobj, IC(LHStype.getId()));
call.copyPosition(continueAt);
continueAt.insertBefore(call);
call = callHelper(call, ir);
continueAt.insertBefore(IfCmp.create(INT_IFCMP, oldGuard, result.copyD2U(), IC(0), ConditionOperand.EQUAL(), falseBlock.makeJumpTarget(), falseProb));
return continueAt;
}
}
if (LHStype.isArrayType()) {
// Case 2 of DynamicTypeCheck: LHS is an array.
RVMArray LHSArray = (RVMArray) LHStype.peekType();
if (LHSArray != null) {
Operand classTIB = getTIB(continueAt, ir, LHSArray);
RVMType innermostElementType = LHSArray.getInnermostElementType();
if (innermostElementType.isPrimitiveType() || innermostElementType.isUnboxedType() || (innermostElementType.asClass().isResolved() && innermostElementType.asClass().isFinal())) {
// [^k of primitive or [^k of final class. Just like final classes,
// a PTR compare of rhsTIB and the TIB of the class gives the answer.
continueAt.insertBefore(IfCmp.create(REF_IFCMP, oldGuard, RHStib, classTIB, ConditionOperand.NOT_EQUAL(), falseBlock.makeJumpTarget(), falseProb));
return continueAt;
}
// TODO: branch probability calculation is somewhat bogus for this case.
Instruction shortcircuit = IfCmp.create(REF_IFCMP, oldGuard, RHStib, classTIB, ConditionOperand.EQUAL(), trueBlock.makeJumpTarget(), new BranchProfileOperand());
if (oldGuard != null) {
oldGuard = oldGuard.copyD2D();
}
continueAt.insertBefore(shortcircuit);
BasicBlock myBlock = shortcircuit.getBasicBlock();
BasicBlock mainBlock = myBlock.splitNodeWithLinksAt(shortcircuit, ir);
// must come after the splitNodeAt
myBlock.insertOut(trueBlock);
RegisterOperand rhsType = InsertUnary(continueAt, ir, GET_TYPE_FROM_TIB, TypeReference.Type, RHStib.copy());
if (innermostElementType.isJavaLangObjectType()) {
IntConstantOperand lhsDimension = IC(LHStype.getDimensionality());
RegisterOperand rhsDimension = getField(continueAt, ir, rhsType, Entrypoints.dimensionField);
Instruction dimTest = IfCmp2.create(INT_IFCMP2, oldGuard, rhsDimension, lhsDimension, ConditionOperand.GREATER(), trueBlock.makeJumpTarget(), ((BranchProfileOperand) falseProb.copy()).flip(), ConditionOperand.LESS(), falseBlock.makeJumpTarget(), (BranchProfileOperand) falseProb.copy());
if (oldGuard != null) {
oldGuard = oldGuard.copyD2D();
}
continueAt.insertBefore(dimTest);
// BasicBlock testBlock =
mainBlock.splitNodeWithLinksAt(dimTest, ir);
mainBlock.insertOut(trueBlock);
mainBlock.insertOut(falseBlock);
RegisterOperand rhsInnermostElementTypeDimension = getField(continueAt, ir, rhsType.copyU2U(), Entrypoints.innermostElementTypeDimensionField);
continueAt.insertBefore(IfCmp.create(INT_IFCMP, oldGuard, rhsInnermostElementTypeDimension, IC(0), ConditionOperand.NOT_EQUAL(), falseBlock.makeJumpTarget(), falseProb));
return continueAt;
}
}
// Not a case we want to handle inline
RVMMethod target = Entrypoints.instanceOfMethod;
RegisterOperand callResult = ir.regpool.makeTempInt();
Instruction call = Call.create2(CALL, callResult, AC(target.getOffset()), MethodOperand.STATIC(target), RHSobj, IC(LHStype.getId()));
call.copyPosition(continueAt);
continueAt.insertBefore(call);
call = callHelper(call, ir);
continueAt.insertBefore(IfCmp.create(INT_IFCMP, oldGuard, callResult.copyD2U(), IC(0), ConditionOperand.EQUAL(), falseBlock.makeJumpTarget(), falseProb));
return continueAt;
}
OptimizingCompilerException.UNREACHABLE();
return null;
}
Aggregations