From 216efba603dbcf2466c8ec422c691f1b57f231ba Mon Sep 17 00:00:00 2001 From: Shubham Verma Date: Wed, 22 Jan 2025 10:51:06 -0500 Subject: [PATCH] x: NULL initialize dataAddr field for 0 size arrays 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 --- .../compiler/x/codegen/J9TreeEvaluator.cpp | 129 ++++++++---------- 1 file changed, 55 insertions(+), 74 deletions(-) diff --git a/runtime/compiler/x/codegen/J9TreeEvaluator.cpp b/runtime/compiler/x/codegen/J9TreeEvaluator.cpp index 5fb3e3e9499..62eef49bf63 100644 --- a/runtime/compiler/x/codegen/J9TreeEvaluator.cpp +++ b/runtime/compiler/x/codegen/J9TreeEvaluator.cpp @@ -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(); @@ -1558,33 +1557,11 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node, #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(fej9->getOffsetOfDiscontiguousDataAddrField() - fej9->getOffsetOfContiguousDataAddrField()), - cg); - - generateLabelInstruction(TR::InstOpCode::JMP4, node, populateFirstDimDataAddrSlot, cg); + // Init 1st dim dataAddr slot to 0 + generateMemImmInstruction(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); @@ -1633,6 +1610,24 @@ 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 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, TR::Compiler->om.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); @@ -1652,16 +1647,7 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node, 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); + generateMemImmInstruction(TR::InstOpCode::S8MemImm4, node, generateX86MemoryReference(temp2Reg, fej9->getOffsetOfDiscontiguousDataAddrField(), cg), 0, cg); } #endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */ @@ -1688,18 +1674,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); @@ -1746,26 +1721,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. @@ -7481,10 +7436,12 @@ 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; + TR::Register *zeroReg = NULL; if (TR::Compiler->om.compressObjectReferences() && NULL != sizeReg) { /* We need to check sizeReg at runtime to determine correct offset of dataAddr field. @@ -7504,16 +7461,30 @@ 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 + zeroReg = srm->findOrCreateScratchRegister(); + generateRegRegInstruction(TR::InstOpCode::XOR4RegReg, node, zeroReg, zeroReg, cg); + generateRegImmInstruction(TR::InstOpCode::CMPRegImm4(), node, sizeReg, 0, cg); + generateRegRegInstruction(TR::InstOpCode::CMOVERegReg(), node, tempReg, zeroReg, cg); + srm->reclaimScratchRegister(zeroReg); + + // Write first data element address to dataAddr slot + generateMemRegInstruction(TR::InstOpCode::SMemReg(), node, dataAddrSlotMR, tempReg, cg); + srm->reclaimScratchRegister(discontiguousDataAddrOffsetReg); } 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); + generateMemImmInstruction(TR::InstOpCode::SMemImm4(), node, dataAddrSlotMR, 0, cg); } else { @@ -7535,11 +7506,21 @@ 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 + zeroReg = srm->findOrCreateScratchRegister(); + generateRegRegInstruction(TR::InstOpCode::XORRegReg(), node, zeroReg, zeroReg, cg); + generateRegImmInstruction(TR::InstOpCode::CMPRegImm4(), node, sizeReg, 0, cg); + generateRegRegInstruction(TR::InstOpCode::CMOVERegReg(), node, tempReg, zeroReg, cg); + srm->reclaimScratchRegister(zeroReg); + } + // Write first data element address to dataAddr slot + generateMemRegInstruction(TR::InstOpCode::SMemReg(), node, dataAddrSlotMR, tempReg, cg); + } } #endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */