diff --git a/runtime/compiler/z/codegen/J9TreeEvaluator.cpp b/runtime/compiler/z/codegen/J9TreeEvaluator.cpp index 2af9369469f..69c13901e18 100644 --- a/runtime/compiler/z/codegen/J9TreeEvaluator.cpp +++ b/runtime/compiler/z/codegen/J9TreeEvaluator.cpp @@ -4871,7 +4871,6 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node, #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) */ // oolJumpLabel is a common point that all branches will jump to. From this label, we branch to OOL code. @@ -4889,12 +4888,13 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node, TR::Register *classReg = cg->evaluate(thirdChild); // In the mainline, first load the first and second dimensions' lengths into registers. + TR::InstOpCode::Mnemonic loadDimLenOpCode = TR::InstOpCode::LGF; TR::Register *firstDimLenReg = cg->allocateRegister(); - cursor = generateRXInstruction(cg, TR::InstOpCode::LGF, node, firstDimLenReg, generateS390MemoryReference(dimsPtrReg, 4, cg)); + cursor = generateRXInstruction(cg, loadDimLenOpCode, node, firstDimLenReg, generateS390MemoryReference(dimsPtrReg, 4, cg)); iComment("Load 1st dim length."); TR::Register *secondDimLenReg = cg->allocateRegister(); - cursor = generateRXInstruction(cg, TR::InstOpCode::L, node, secondDimLenReg, generateS390MemoryReference(dimsPtrReg, 0, cg)); + cursor = generateRXInstruction(cg, loadDimLenOpCode, node, secondDimLenReg, generateS390MemoryReference(dimsPtrReg, 0, cg)); iComment("Load 2nd dim length."); // Check to see if second dimension is indeed 0. If yes, then proceed to handle the case here. Otherwise jump to OOL code. @@ -4948,33 +4948,24 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node, iComment("Init 1st dim mustBeZero field."); cursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, firstDimLenReg, generateS390MemoryReference(targetReg, fej9->getOffsetOfDiscontiguousArraySizeField(), cg)); iComment("Init 1st dim size field."); - } - #if defined(J9VM_GC_SPARSE_HEAP_ALLOCATION) - if (isOffHeapAllocationEnabled) - { - 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()); - - // Load dataAddr slot offset difference since 0 size arrays are treated as discontiguous. - generateRIInstruction(cg, - TR::InstOpCode::LGHI, - node, - temp1Reg, - static_cast(fej9->getOffsetOfDiscontiguousDataAddrField() - fej9->getOffsetOfContiguousDataAddrField())); - cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, populateFirstDimDataAddrSlot); - } - else + if (isOffHeapAllocationEnabled) + { + TR_ASSERT_FATAL_WITH_NODE(node, + TR::InstOpCode::LGF == loadDimLenOpCode, + "LGF must be used to load 1st dimension length into firstDimLenReg. " + "Array size field is 32 bits in size but dataAddr slot is 64 bits so " + "to use the same register to intialize dataAddr slot we must clean " + "out top 32 bits of firstDimLenReg. LGF sign extends 32 bit 1st dim " + "size to 64 bits enabling us to use firstDimLenReg to write NULL in " + "the dataAddr field for 0 length arrays.\n"); + cursor = generateRXInstruction(cg, TR::InstOpCode::STG, node, firstDimLenReg, generateS390MemoryReference(targetReg, fej9->getOffsetOfDiscontiguousDataAddrField(), cg)); + iComment("Clear 1st dim dataAddr field."); + } #endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */ - { - cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionDone); } + + cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionDone); iComment("Init class field and jump."); // We end up in this region of the ICF if the first dimension is non-zero and the second dimension is zero. @@ -5056,27 +5047,24 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node, iComment("Init 2st dim mustBeZero field."); cursor = generateRXInstruction(cg, TR::InstOpCode::ST, node, secondDimLenReg, generateS390MemoryReference(temp2Reg, fej9->getOffsetOfDiscontiguousArraySizeField(), cg)); iComment("Init 2st dim size field."); - } - - TR::Register *temp3Reg = cg->allocateRegister(); - #if defined(J9VM_GC_SPARSE_HEAP_ALLOCATION) - if (isOffHeapAllocationEnabled) - { - // Populate dataAddr slot for 2nd dimension zero size array. - generateRXInstruction(cg, - TR::InstOpCode::LA, - node, - temp3Reg, - generateS390MemoryReference(temp2Reg, TR::Compiler->om.discontiguousArrayHeaderSizeInBytes(), cg)); - generateRXInstruction(cg, - TR::InstOpCode::STG, - node, - temp3Reg, - generateS390MemoryReference(temp2Reg, fej9->getOffsetOfDiscontiguousDataAddrField(), cg)); - } + if (isOffHeapAllocationEnabled) + { + TR_ASSERT_FATAL_WITH_NODE(node, + TR::InstOpCode::LGF == loadDimLenOpCode, + "LGF must be used to load 2nd dimension length into secondDimLenReg. " + "Array size field is 32 bits in size but dataAddr slot is 64 bits so " + "to use the same register to intialize dataAddr slot we must clean " + "out top 32 bits of secondDimLenReg. LGF sign extends 32 bit 2nd dim " + "size to 64 bits enabling us to use secondDimLenReg to write NULL in " + "the dataAddr field for 0 length arrays.\n"); + cursor = generateRXInstruction(cg, TR::InstOpCode::STG, node, secondDimLenReg, generateS390MemoryReference(temp2Reg, fej9->getOffsetOfDiscontiguousDataAddrField(), cg)); + iComment("Clear 2nd dim dataAddr field."); + } #endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */ + } + TR::Register *temp3Reg = cg->allocateRegister(); // Store 2nd dim element into 1st dim array slot, compress temp2 if needed if (comp->target().is64Bit() && comp->useCompressedPointers()) { @@ -5103,15 +5091,24 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node, #if defined(J9VM_GC_SPARSE_HEAP_ALLOCATION) if (isOffHeapAllocationEnabled) { - // No offset is needed since 1st dimension array is contiguous. - generateRRInstruction(cg, TR::InstOpCode::getXORRegOpCode(), node, temp1Reg, temp1Reg); - generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, populateFirstDimDataAddrSlot); + /* Populate dataAddr slot of 1st dimension array. We don't need to worry + * about zero length array since it has already been taken care of. + */ + generateRXInstruction(cg, + TR::InstOpCode::LA, + node, + temp3Reg, + generateS390MemoryReference(targetReg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg)); + cursor = generateRXInstruction(cg, + TR::InstOpCode::STG, + node, + temp3Reg, + generateS390MemoryReference(targetReg, fej9->getOffsetOfContiguousDataAddrField(), cg)); + iComment("populateFirstDimDataAddrSlot."); } - else #endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */ - { - generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionDone); - } + + generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionDone); TR::RegisterDependencyConditions *dependencies = generateRegisterDependencyConditions(0,10,cg); dependencies->addPostCondition(dimReg, TR::RealRegister::AssignAny); @@ -5128,28 +5125,6 @@ static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node, generateS390LabelInstruction(cg, TR::InstOpCode::label, node, oolJumpLabel); generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, oolFailLabel); -#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. - */ - cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, populateFirstDimDataAddrSlot); - iComment("populateFirstDimDataAddrSlot."); - - generateRXInstruction(cg, - TR::InstOpCode::LA, - node, - temp3Reg, - generateS390MemoryReference(targetReg, temp1Reg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg)); - generateRXInstruction(cg, - TR::InstOpCode::STG, - node, - temp3Reg, - generateS390MemoryReference(targetReg, temp1Reg, fej9->getOffsetOfContiguousDataAddrField(), cg)); - } -#endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */ - generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionDone, dependencies); TR::Register *targetRegisterFinal = cg->allocateCollectedReferenceRegister(); @@ -11119,81 +11094,17 @@ J9::Z::TreeEvaluator::VMnewEvaluator(TR::Node * node, TR::CodeGenerator * cg) #ifdef J9VM_GC_SPARSE_HEAP_ALLOCATION if (TR::Compiler->om.isOffHeapAllocationEnabled()) { - /* Here we'll update dataAddr slot for both fixed and variable length arrays. Fixed length arrays are - * simple as we just need to check first child of the node for array size. For variable length arrays - * 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. + /* Here we'll update dataAddr slot for fixed and variable non-zero length arrays. DataAddr field + * should be left blank for zero length arrays. */ - TR::Register *offsetReg = NULL; - TR::MemoryReference *dataAddrMR = NULL; - TR::MemoryReference *dataAddrSlotMR = NULL; - - if (isVariableLen && TR::Compiler->om.compressObjectReferences()) - { - /* We need to check enumReg (array size) at runtime to determine correct offset of dataAddr field. - * Here we deal only with compressed refs because dataAddr offset for discontiguous - * and contiguous arrays is the same in full refs. - */ - if (comp->getOption(TR_TraceCG)) - traceMsg(comp, "Node (%p): Dealing with compressed refs variable length array.\n", node); - - TR_ASSERT_FATAL_WITH_NODE(node, - (fej9->getOffsetOfDiscontiguousDataAddrField() - fej9->getOffsetOfContiguousDataAddrField()) == 8, - "Offset of dataAddr field in discontiguous array is expected to be 8 bytes more than contiguous array. " - "But was %d bytes for discontiguous and %d bytes for contiguous array.\n", - fej9->getOffsetOfDiscontiguousDataAddrField(), fej9->getOffsetOfContiguousDataAddrField()); - - offsetReg = cg->allocateRegister(); - // Invert enumReg sign. 0 and negative numbers remain unchanged. - iCursor = generateRREInstruction(cg, TR::InstOpCode::LNGFR, node, offsetReg, enumReg, iCursor); - iCursor = generateRSInstruction(cg, TR::InstOpCode::SRLG, node, dataSizeReg, offsetReg, 63, iCursor); - iCursor = generateRSInstruction(cg, TR::InstOpCode::SLLG, node, offsetReg, dataSizeReg, 3, iCursor); - // Inverting the sign bit will leave us with either -8 (if enumCopyReg > 0) or 0 (if enumCopyReg == 0). - iCursor = generateRREInstruction(cg, TR::InstOpCode::LNGR, node, offsetReg, offsetReg, iCursor); - - dataAddrMR = generateS390MemoryReference(resReg, offsetReg, TR::Compiler->om.discontiguousArrayHeaderSizeInBytes(), cg); - dataAddrSlotMR = generateS390MemoryReference(resReg, offsetReg, fej9->getOffsetOfDiscontiguousDataAddrField(), cg); - } - else if (!isVariableLen && 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 = generateS390MemoryReference(resReg, TR::Compiler->om.discontiguousArrayHeaderSizeInBytes(), cg); - dataAddrSlotMR = generateS390MemoryReference(resReg, fej9->getOffsetOfDiscontiguousDataAddrField(), cg); - } - else - { - if (comp->getOption(TR_TraceCG)) - { - traceMsg(comp, - "Node (%p): Dealing with either full/compressed refs fixed length non-zero size array or full refs variable length array.\n", - node); - } - - if (!TR::Compiler->om.compressObjectReferences()) - { - TR_ASSERT_FATAL_WITH_NODE(node, - fej9->getOffsetOfDiscontiguousDataAddrField() == fej9->getOffsetOfContiguousDataAddrField(), - "dataAddr field offset is expected to be same for both contiguous and discontiguous arrays in full refs. " - "But was %d bytes for discontiguous and %d bytes for contiguous array.\n", - fej9->getOffsetOfDiscontiguousDataAddrField(), fej9->getOffsetOfContiguousDataAddrField()); - } - - dataAddrMR = generateS390MemoryReference(resReg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg); - dataAddrSlotMR = generateS390MemoryReference(resReg, fej9->getOffsetOfContiguousDataAddrField(), cg); - } + TR::MemoryReference *dataAddrMR = generateS390MemoryReference(resReg, TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), cg); + TR::MemoryReference *dataAddrSlotMR = generateS390MemoryReference(resReg, fej9->getOffsetOfContiguousDataAddrField(), cg); + dataAddrSlotMR = generateS390MemoryReference(resReg, fej9->getOffsetOfContiguousDataAddrField(), cg); iCursor = generateRXInstruction(cg, TR::InstOpCode::LA, node, dataSizeReg, dataAddrMR, iCursor); - iCursor = generateRXInstruction(cg, TR::InstOpCode::STG, node, dataSizeReg, dataAddrSlotMR, iCursor); + iCursor = generateRILInstruction(cg, TR::InstOpCode::CFI, node, enumReg, 0, iCursor); - if (offsetReg) - { - conditions->addPostCondition(offsetReg, TR::RealRegister::AssignAny); - cg->stopUsingRegister(offsetReg); - } + iCursor = generateRSInstruction(cg, TR::InstOpCode::STOCG, node, dataSizeReg, static_cast(0x2), dataAddrSlotMR, iCursor); } #endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */