Skip to content

Commit

Permalink
x: NULL initialize dataAddr field for 0 size arrays
Browse files Browse the repository at this point in the history
Update array inline allocation sequence to initialize dataAddr field
only for non-zero size arrays. Field should be left blank for zero
size arrays.

Signed-off-by: Shubham Verma <[email protected]>
  • Loading branch information
VermaSh committed Jan 4, 2025
1 parent 9cf1f59 commit 5c97785
Showing 1 changed file with 77 additions and 75 deletions.
152 changes: 77 additions & 75 deletions runtime/compiler/x/codegen/J9TreeEvaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1499,7 +1499,6 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node,
TR::LabelSymbol *nonZeroFirstDimLabel = generateLabelSymbol(cg);
#if defined(J9VM_GC_SPARSE_HEAP_ALLOCATION)
bool isOffHeapAllocationEnabled = TR::Compiler->om.isOffHeapAllocationEnabled();
TR::LabelSymbol *populateFirstDimDataAddrSlot = isOffHeapAllocationEnabled? generateLabelSymbol(cg) : NULL;
#endif /* defined(J9VM_GC_SPARSE_HEAP_ALLOCATION) */

startLabel->setStartInternalControlFlow();
Expand Down Expand Up @@ -1554,37 +1553,18 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node,
// Init size and mustBeZero ('0') fields to 0
generateMemImmInstruction(TR::InstOpCode::S4MemImm4, node, generateX86MemoryReference(targetReg, fej9->getOffsetOfContiguousArraySizeField(), cg), 0, cg);
generateMemImmInstruction(TR::InstOpCode::S4MemImm4, node, generateX86MemoryReference(targetReg, fej9->getOffsetOfDiscontiguousArraySizeField(), cg), 0, cg);
if (TR::Compiler->om.compressObjectReferences())
{ // Clear padding in contiguous array header layout. +4 because size field is 4 bytes wide.
generateMemImmInstruction(TR::InstOpCode::S4MemImm4, node, generateX86MemoryReference(targetReg, fej9->getOffsetOfDiscontiguousArraySizeField() + 4, cg), 0, cg);
}

#if defined(J9VM_GC_SPARSE_HEAP_ALLOCATION)
if (isOffHeapAllocationEnabled)
{
// Load dataAddr slot offset difference since 0 size arrays are treated as discontiguous.
TR_ASSERT_FATAL_WITH_NODE(node,
IS_32BIT_SIGNED(fej9->getOffsetOfDiscontiguousDataAddrField() - fej9->getOffsetOfContiguousDataAddrField()),
"dataAddrFieldOffset is too big for the instruction.");

TR_ASSERT_FATAL_WITH_NODE(node,
(TR::Compiler->om.compressObjectReferences()
&& (fej9->getOffsetOfDiscontiguousDataAddrField() - fej9->getOffsetOfContiguousDataAddrField()) == 8)
|| (!TR::Compiler->om.compressObjectReferences()
&& fej9->getOffsetOfDiscontiguousDataAddrField() == fej9->getOffsetOfContiguousDataAddrField()),
"Offset of dataAddr field in discontiguous array is expected to be 8 bytes more than contiguous array if using compressed refs, "
"or same if using full refs. But was %d bytes for discontiguous and %d bytes for contiguous array.\n",
fej9->getOffsetOfDiscontiguousDataAddrField(), fej9->getOffsetOfContiguousDataAddrField());

generateRegImmInstruction(TR::InstOpCode::MOV8RegImm4,
node,
temp3Reg,
static_cast<int32_t>(fej9->getOffsetOfDiscontiguousDataAddrField() - fej9->getOffsetOfContiguousDataAddrField()),
cg);

generateLabelInstruction(TR::InstOpCode::JMP4, node, populateFirstDimDataAddrSlot, cg);
{ // Init 1st dim dataAddr slot to 0
generateMemRegInstruction(TR::InstOpCode::S8MemImm4, node, generateX86MemoryReference(targetReg, fej9->getOffsetOfDiscontiguousDataAddrField(), cg), 0, cg);
}
else
#endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */
{
generateLabelInstruction(TR::InstOpCode::JMP4, node, doneLabel, cg);
}
generateLabelInstruction(TR::InstOpCode::JMP4, node, doneLabel, cg);

//First dim length not 0
generateLabelInstruction(TR::InstOpCode::label, node, nonZeroFirstDimLabel, cg);
Expand Down Expand Up @@ -1633,6 +1613,28 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node,
generateMemRegInstruction(TR::InstOpCode::SMemReg(use64BitClasses), node, generateX86MemoryReference(targetReg, TR::Compiler->om.offsetOfObjectVftField(), cg), classReg, cg);
// Init 1st dim array size field
generateMemRegInstruction(TR::InstOpCode::S4MemReg, node, generateX86MemoryReference(targetReg, fej9->getOffsetOfContiguousArraySizeField(), cg), firstDimLenReg, cg);
if (!TR::Compiler->om.compressObjectReferences())
{ // Clear padding in contiguous array header layout. +4 because size field is 4 bytes wide.
generateMemImmInstruction(TR::InstOpCode::S4MemImm4, node, generateX86MemoryReference(targetReg, fej9->getOffsetOfContiguousArraySizeField() + 4, cg), 0, cg);
}
#if defined(J9VM_GC_SPARSE_HEAP_ALLOCATION)
if (isOffHeapAllocationEnabled)
{
/* Populate dataAddr slot of 1st dimension array. Arrays of non-zero size
* use contiguous header layout while zero size arrays use discontiguous header layout.
*/
generateRegMemInstruction(TR::InstOpCode::LEARegMem(),
node,
temp3Reg,
generateX86MemoryReference(targetReg, fej9->contiguousArrayHeaderSizeInBytes(), cg),
cg);
generateMemRegInstruction(TR::InstOpCode::SMemReg(),
node,
generateX86MemoryReference(targetReg, fej9->getOffsetOfContiguousDataAddrField(), cg),
temp3Reg,
cg);
}
#endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */

// temp2 point to end of 1st dim array i.e. start of 2nd dim
generateRegRegInstruction(TR::InstOpCode::MOVRegReg(), node, temp2Reg, targetReg, cg);
Expand All @@ -1647,21 +1649,16 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node,
// Init 2nd dim element's size and mustBeZero ('0') fields to 0
generateMemImmInstruction(TR::InstOpCode::S4MemImm4, node, generateX86MemoryReference(temp2Reg, fej9->getOffsetOfContiguousArraySizeField(), cg), 0, cg);
generateMemImmInstruction(TR::InstOpCode::S4MemImm4, node, generateX86MemoryReference(temp2Reg, fej9->getOffsetOfDiscontiguousArraySizeField(), cg), 0, cg);
if (TR::Compiler->om.compressObjectReferences())
{ // Clear padding in contiguous array header layout. +4 because size field is 4 bytes wide.
generateMemImmInstruction(TR::InstOpCode::S4MemImm4, node, generateX86MemoryReference(temp2Reg, fej9->getOffsetOfDiscontiguousArraySizeField() + 4, cg), 0, cg);
}

#if defined(J9VM_GC_SPARSE_HEAP_ALLOCATION)
if (isOffHeapAllocationEnabled)
{
// Populate dataAddr slot for 2nd dimension zero size array.
generateRegMemInstruction(TR::InstOpCode::LEARegMem(),
node,
temp3Reg,
generateX86MemoryReference(temp2Reg, TR::Compiler->om.discontiguousArrayHeaderSizeInBytes(), cg),
cg);
generateMemRegInstruction(TR::InstOpCode::SMemReg(),
node,
generateX86MemoryReference(temp2Reg, fej9->getOffsetOfDiscontiguousDataAddrField(), cg),
temp3Reg,
cg);
generateMemRegInstruction(TR::InstOpCode::S8MemImm4, node, generateX86MemoryReference(temp2Reg, fej9->getOffsetOfDiscontiguousDataAddrField(), cg), 0, cg);
}
#endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */

Expand All @@ -1688,18 +1685,7 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node,
generateRegInstruction(TR::InstOpCode::DEC4Reg, node, firstDimLenReg, cg);
generateLabelInstruction(TR::InstOpCode::JA4, node, loopLabel, cg);

#if defined(J9VM_GC_SPARSE_HEAP_ALLOCATION)
if (isOffHeapAllocationEnabled)
{
// No offset is needed since 1st dimension array is contiguous.
generateRegRegInstruction(TR::InstOpCode::XOR4RegReg, node, temp3Reg, temp3Reg, cg);
generateLabelInstruction(TR::InstOpCode::JMP4, node, populateFirstDimDataAddrSlot, cg);
}
else
#endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */
{
generateLabelInstruction(TR::InstOpCode::JMP4, node, doneLabel, cg);
}
generateLabelInstruction(TR::InstOpCode::JMP4, node, doneLabel, cg);

TR::RegisterDependencyConditions *deps = generateRegisterDependencyConditions((uint8_t)0, 13, cg);

Expand Down Expand Up @@ -1746,26 +1732,6 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node,
generateLabelInstruction(TR::InstOpCode::label, node, oolJumpPoint, cg);
generateLabelInstruction(TR::InstOpCode::JMP4, node, oolFailLabel, cg);

#if defined(J9VM_GC_SPARSE_HEAP_ALLOCATION)
if (isOffHeapAllocationEnabled)
{
/* Populate dataAddr slot of 1st dimension array. Arrays of non-zero size
* use contiguous header layout while zero size arrays use discontiguous header layout.
*/
generateLabelInstruction(TR::InstOpCode::label, node, populateFirstDimDataAddrSlot, cg);
generateRegMemInstruction(TR::InstOpCode::LEARegMem(),
node,
temp2Reg,
generateX86MemoryReference(targetReg, temp3Reg, 0, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg),
cg);
generateMemRegInstruction(TR::InstOpCode::SMemReg(),
node,
generateX86MemoryReference(targetReg, temp3Reg, 0, fej9->getOffsetOfContiguousDataAddrField(), cg),
temp2Reg,
cg);
}
#endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */

generateLabelInstruction(TR::InstOpCode::label, node, doneLabel, deps, cg);

// Copy the newly allocated object into a collected reference register now that it is a valid object.
Expand Down Expand Up @@ -6827,6 +6793,24 @@ static void genInitArrayHeader(
}
}

// Clear padding after size field in array header
if (TR::Compiler->om.compressObjectReferences())
{ // Clear padding after size field in discontiguous header layout (for 0 length arrays)
generateMemImmInstruction(TR::InstOpCode::SMemImm4(),
node,
generateX86MemoryReference(objectReg, fej9->getOffsetOfDiscontiguousArraySizeField() + 4, cg),
0,
cg);
}
else
{ // Clear padding after size field in contiguous header layout
generateMemImmInstruction(TR::InstOpCode::SMemImm4(),
node,
generateX86MemoryReference(objectReg, fej9->getOffsetOfDiscontiguousArraySizeField(), cg),
0,
cg);
}

bool generateArraylets = comp->generateArraylets();

if (generateArraylets)
Expand Down Expand Up @@ -7481,7 +7465,8 @@ static void handleOffHeapDataForArrays(
* runtime size checks are needed to determine whether to use contiguous or discontiguous header layout.
*
* In both scenarios, arrays of non-zero size use contiguous header layout while zero size arrays use
* discontiguous header layout.
* discontiguous header layout. DataAddr field of zero size arrays is intialized to NULL because they
* don't have any data elements.
*/
TR::MemoryReference *dataAddrSlotMR = NULL;
TR::MemoryReference *dataAddrMR = NULL;
Expand All @@ -7504,16 +7489,26 @@ static void handleOffHeapDataForArrays(
generateRegRegInstruction(TR::InstOpCode::XOR4RegReg, node, discontiguousDataAddrOffsetReg, discontiguousDataAddrOffsetReg, cg);
generateRegImmInstruction(TR::InstOpCode::CMPRegImm4(), node, sizeReg, 1, cg);
generateRegImmInstruction(TR::InstOpCode::ADCRegImm4(), node, discontiguousDataAddrOffsetReg, 0, cg);

dataAddrMR = generateX86MemoryReference(targetReg, discontiguousDataAddrOffsetReg, 3, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg);
dataAddrSlotMR = generateX86MemoryReference(targetReg, discontiguousDataAddrOffsetReg, 3, fej9->getOffsetOfContiguousDataAddrField(), cg);
// Load first data element address
generateRegMemInstruction(TR::InstOpCode::LEARegMem(), node, tempReg, dataAddrMR, cg);

// Clear out tempReg if dealing with 0 length array
generateRegImmInstruction(TR::InstOpCode::CMPRegImm4(), node, sizeReg, 0, cg);
generateRegMemInstruction(TR::InstOpCode::CMOVE8RegMem, node, tempReg, generateX86MemoryReference(cg->findOrCreate8ByteConstant(node, 0), cg()), cg());

// Write first data element address to dataAddr slot
generateMemRegInstruction(TR::InstOpCode::SMemReg(), node, dataAddrSlotMR, tempReg, cg);
}
else if (NULL == sizeReg && node->getFirstChild()->getOpCode().isLoadConst() && node->getFirstChild()->getInt() == 0)
{
if (comp->getOption(TR_TraceCG))
traceMsg(comp, "Node (%p): Dealing with full/compressed refs fixed length zero size array.\n", node);

dataAddrMR = generateX86MemoryReference(targetReg, TR::Compiler->om.discontiguousArrayHeaderSizeInBytes(), cg);
dataAddrSlotMR = generateX86MemoryReference(targetReg, fej9->getOffsetOfDiscontiguousDataAddrField(), cg);
generateMemRegInstruction(TR::InstOpCode::S8MemImm4, node, dataAddrSlotMR, 0, cg);
}
else
{
Expand All @@ -7535,11 +7530,18 @@ static void handleOffHeapDataForArrays(

dataAddrMR = generateX86MemoryReference(targetReg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg);
dataAddrSlotMR = generateX86MemoryReference(targetReg, fej9->getOffsetOfContiguousDataAddrField(), cg);
}
// Load first data element address
generateRegMemInstruction(TR::InstOpCode::LEARegMem(), node, tempReg, dataAddrMR, cg);

// write first data element address to dataAddr slot
generateRegMemInstruction(TR::InstOpCode::LEARegMem(), node, tempReg, dataAddrMR, cg);
generateMemRegInstruction(TR::InstOpCode::SMemReg(), node, dataAddrSlotMR, tempReg, cg);
if (!TR::Compiler->om.compressObjectReferences() && NULL != sizeReg)
{
// Clear out tempReg if dealing with 0 length array
generateRegImmInstruction(TR::InstOpCode::CMPRegImm4(), node, sizeReg, 0, cg);
generateRegMemInstruction(TR::InstOpCode::CMOVE8RegMem, node, tempReg, generateX86MemoryReference(cg->findOrCreate8ByteConstant(node, 0), cg()), cg());
}
// Write first data element address to dataAddr slot
generateMemRegInstruction(TR::InstOpCode::SMemReg(), node, dataAddrSlotMR, tempReg, cg);
}
}
#endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */

Expand Down

0 comments on commit 5c97785

Please sign in to comment.