Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement X86 codegen support for dynamic array clone #4179

Merged
merged 1 commit into from
Jan 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion runtime/compiler/compile/J9Compilation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -648,8 +648,15 @@ J9::Compilation::canAllocateInline(TR::Node* node, TR_OpaqueClassBlock* &classIn
else if (node->getOpCodeValue() == TR::anewarray)
{
classRef = node->getSecondChild();
classSymRef = classRef->getSymbolReference();

// In the case of dynamic array allocation, return 0 indicating variable dynamic array allocation
if (classRef->getOpCodeValue() != TR::loadaddr)
{
classInfo = NULL;
return 0;
}

classSymRef = classRef->getSymbolReference();
// Can't skip the allocation if the class is unresolved
//
clazz = self()->fej9vm()->getClassForAllocationInlining(self(), classSymRef);
Expand Down
92 changes: 57 additions & 35 deletions runtime/compiler/x/codegen/J9TreeEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6558,6 +6558,7 @@ static void genInitObjectHeader(TR::Node *node,
TR::Register *objectReg,
TR::Register *tempReg,
bool isZeroInitialized,
bool isDynamicAllocation,
TR::CodeGenerator *cg)
{
TR::Compilation *comp = cg->comp();
Expand All @@ -6567,12 +6568,7 @@ static void genInitObjectHeader(TR::Node *node,
(!TR::Compiler->om.generateCompressedObjectHeaders() ||
(cg->comp()->compileRelocatableCode() && cg->comp()->getOption(TR_UseSymbolValidationManager)));

// This code was moved to this point so that the romClass can be used by the AOT
// portion without calling the method again.
//
J9ROMClass *romClass = 0;
TR_ASSERT(clazz, "Cannot have a null OpaqueClassBlock\n");
romClass = TR::Compiler->cls.romClassOf(clazz);
TR_ASSERT((isDynamicAllocation || clazz), "Cannot have a null clazz while not doing dynamic array allocation\n");

// --------------------------------------------------------------------------------
//
Expand All @@ -6584,8 +6580,16 @@ static void genInitObjectHeader(TR::Node *node,

TR::Register * clzReg = classReg;

// For dynamic array allocation, load the array class from the component class and store into clzReg
if (isDynamicAllocation)
{
TR_ASSERT((node->getOpCodeValue() == TR::anewarray), "Dynamic allocation currently only supports reference arrays");
TR_ASSERT(classReg, "must have a classReg for dynamic allocation");
clzReg = tempReg;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we assert here that node->getOpCodeValue() == TR::anewarray? Just because if (isDynamicAllocation) sounds more generic, but only anewarray is handled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

generateRegMemInstruction(LRegMem(), node, clzReg, generateX86MemoryReference(classReg, offsetof(J9Class, arrayClass), cg), cg);
}
// TODO: should be able to use a TR_ClassPointer relocation without this stuff (along with class validation)
if (cg->needClassAndMethodPointerRelocations() && !comp->getOption(TR_UseSymbolValidationManager))
else if (cg->needClassAndMethodPointerRelocations() && !comp->getOption(TR_UseSymbolValidationManager))
{
TR::Register *vmThreadReg = cg->getVMThreadRegister();
if (node->getOpCodeValue() == TR::newarray)
Expand All @@ -6601,13 +6605,6 @@ static void genInitObjectHeader(TR::Node *node,
tempReg, cg);
clzReg = tempReg;
}
else if (node->getOpCodeValue() == TR::anewarray)
{
TR_ASSERT(classReg, "must have a classReg for TR::anewarray in AOT mode");
generateRegMemInstruction(LRegMem(), node, tempReg,
generateX86MemoryReference(classReg, offsetof(J9Class, arrayClass), cg), cg);
clzReg = tempReg;
}
else
{
TR_ASSERT((node->getOpCodeValue() == TR::New)
Expand Down Expand Up @@ -6661,6 +6658,7 @@ static void genInitObjectHeader(TR::Node *node,

#ifndef J9VM_INTERP_FLAGS_IN_CLASS_SLOT
// Enable macro once GC-Helper is fixed
J9ROMClass *romClass = TR::Compiler->cls.romClassOf(clazz);
if (romClass)
{
orFlags |= romClass->instanceShape;
Expand All @@ -6682,23 +6680,39 @@ static void genInitObjectHeader(TR::Node *node,
//
// --------------------------------------------------------------------------------
//
J9Class *j9class = TR::Compiler->cls.convertClassOffsetToClassPtr(clazz);
bool initReservable = J9CLASS_EXTENDED_FLAGS(j9class) & J9ClassReservableLockWordInit;
if (!isZeroInitialized || initReservable)
// For dynamic array allocation, in case (very unlikely) the object array has a lock word, we just initialized it to 0 conservatively.
// In this case, if the original array is reserved, initializating the cloned object's lock word to 0 will force the
// locking to go to the slow locking path.
if (isDynamicAllocation)
{
TR::LabelSymbol *doneLabel = generateLabelSymbol(cg);
generateRegMemInstruction(LRegMem(), node, tempReg, generateX86MemoryReference(clzReg, offsetof(J9ArrayClass, lockOffset), cg), cg);
generateRegImmInstruction(CMPRegImm4(), node, tempReg, (int32_t)-1, cg);
generateLabelInstruction (JE4, node, doneLabel, cg);
generateMemImmInstruction(SMemImm4(TR::Compiler->target.is64Bit() && !fej9->generateCompressedLockWord()),
node, generateX86MemoryReference(objectReg, tempReg, 0, cg), 0, cg);
generateLabelInstruction(LABEL, node, doneLabel, cg);
}
else
{
bool initLw = (node->getOpCodeValue() != TR::New) || initReservable;
int lwOffset = fej9->getByteOffsetToLockword(clazz);
if (lwOffset == -1)
initLw = false;

if (initLw)
J9Class *j9class = TR::Compiler->cls.convertClassOffsetToClassPtr(clazz);
bool initReservable = J9CLASS_EXTENDED_FLAGS(j9class) & J9ClassReservableLockWordInit;
if (!isZeroInitialized || initReservable)
{
int32_t initialLwValue = 0;
if (initReservable)
initialLwValue = OBJECT_HEADER_LOCK_RESERVED;
bool initLw = (node->getOpCodeValue() != TR::New) || initReservable;
int lwOffset = fej9->getByteOffsetToLockword(clazz);
if (lwOffset == -1)
initLw = false;

TR_X86OpCodes op = (TR::Compiler->target.is64Bit() && fej9->generateCompressedLockWord()) ? S4MemImm4 : SMemImm4();
generateMemImmInstruction(op, node, generateX86MemoryReference(objectReg, lwOffset, cg), initialLwValue, cg);
if (initLw)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some comments about lock word handling are warranted along with a description of the interaction with lock reservation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added more comments to address lock reservation case.

{
int32_t initialLwValue = 0;
if (initReservable)
initialLwValue = OBJECT_HEADER_LOCK_RESERVED;

generateMemImmInstruction(SMemImm4(TR::Compiler->target.is64Bit() && !fej9->generateCompressedLockWord()),
node, generateX86MemoryReference(objectReg, lwOffset, cg), initialLwValue, cg);
}
}
}
}
Expand All @@ -6716,13 +6730,14 @@ static void genInitArrayHeader(
int32_t arrayletDataOffset,
TR::Register *tempReg,
bool isZeroInitialized,
bool isDynamicAllocation,
TR::CodeGenerator *cg)
{
TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->fe());

// Initialize the object header
//
genInitObjectHeader(node, clazz, classReg, objectReg, tempReg, isZeroInitialized, cg);
genInitObjectHeader(node, clazz, classReg, objectReg, tempReg, isZeroInitialized, isDynamicAllocation, cg);

int32_t arraySizeOffset = fej9->getOffsetOfContiguousArraySizeField();

Expand Down Expand Up @@ -7293,7 +7308,6 @@ J9::X86::TreeEvaluator::VMnewEvaluator(
TR_OpaqueClassBlock *clazz = NULL;
TR::Register *classReg = NULL;
bool isArrayNew = false;

int32_t allocationSize = 0;
int32_t objectSize = 0;
int32_t elementSize = 0;
Expand Down Expand Up @@ -7347,7 +7361,11 @@ J9::X86::TreeEvaluator::VMnewEvaluator(
objectSize = comp->canAllocateInline(node, clazz);
if (objectSize < 0)
return NULL;

// Currently dynamic allocation is only supported on reference array.
// We are performing dynamic array allocation if both object size and
// class block cannot be statically determined.
bool dynamicArrayAllocation = (node->getOpCodeValue() == TR::anewarray)
&& (objectSize == 0) && (clazz == NULL);
allocationSize = objectSize;

static long count = 0;
Expand Down Expand Up @@ -7392,6 +7410,9 @@ J9::X86::TreeEvaluator::VMnewEvaluator(
elementSize = (int32_t)TR::Compiler->om.sizeofReferenceAddress();

classReg = node->getSecondChild()->getRegister();
// For dynamic array allocation, need to evaluate second child
if (!classReg && dynamicArrayAllocation)
classReg = cg->evaluate(node->getSecondChild());
}

isArrayNew = true;
Expand Down Expand Up @@ -7683,9 +7704,8 @@ J9::X86::TreeEvaluator::VMnewEvaluator(
// --------------------------------------------------------------------------------
// Initialize the header
// --------------------------------------------------------------------------------
if (fej9->inlinedAllocationsMustBeVerified()
&& !comp->getOption(TR_UseSymbolValidationManager)
&& node->getOpCodeValue() == TR::anewarray)
// If dynamic array allocation, must pass in classReg to initialize the array header
if ((fej9->inlinedAllocationsMustBeVerified() && !comp->getOption(TR_UseSymbolValidationManager) && node->getOpCodeValue() == TR::anewarray) || dynamicArrayAllocation)
{
genInitArrayHeader(
node,
Expand All @@ -7697,6 +7717,7 @@ J9::X86::TreeEvaluator::VMnewEvaluator(
dataOffset,
tempReg,
monitorSlotIsInitialized,
true,
cg);
}
else if (isArrayNew)
Expand All @@ -7711,11 +7732,12 @@ J9::X86::TreeEvaluator::VMnewEvaluator(
dataOffset,
tempReg,
monitorSlotIsInitialized,
false,
cg);
}
else
{
genInitObjectHeader(node, clazz, classReg, targetReg, tempReg, monitorSlotIsInitialized, cg);
genInitObjectHeader(node, clazz, classReg, targetReg, tempReg, monitorSlotIsInitialized, false, cg);
}

if (fej9->inlinedAllocationsMustBeVerified() && (node->getOpCodeValue() == TR::New ||
Expand Down