Z: Inline any length 2d array allocation - #22548
Conversation
1e70d33 to
46eb3fc
Compare
46eb3fc to
8550a97
Compare
|
@r30shah this PR is ready for review I upload a full compilation logs with compressed and non compressed references here: |
6863661 to
0e9c5ae
Compare
r30shah
left a comment
There was a problem hiding this comment.
I am going to load this PR and do in more depth review, some initial comments.
6f6c4f0 to
53f5d29
Compare
|
@r30shah I addressed the change requests. Please take another look when you have time. Thanks! |
| { | ||
| generateRRInstruction(cg, TR::InstOpCode::LGR, node, temp1Reg, targetReg); | ||
| generateRILInstruction(cg, TR::InstOpCode::AGFI, node, temp1Reg, zeroArraySizeAligned); | ||
| traceMsg(comp, "Inline allocation for multianewarray with element size:%d and leaf component size:%d", elementSize, componentSize); |
There was a problem hiding this comment.
| traceMsg(comp, "Inline allocation for multianewarray with element size:%d and leaf component size:%d", elementSize, componentSize); | |
| traceMsg(comp, "Inline allocation for multianewarray with element size: %d and leaf component size: %d", elementSize, componentSize); |
| #endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */ | ||
| TR::LabelSymbol *controlFlowStartLabel = generateLabelSymbol(cg); | ||
| controlFlowStartLabel->setStartInternalControlFlow(); | ||
| generateS390LabelInstruction(cg, TR::InstOpCode::label, node, controlFlowStartLabel); |
There was a problem hiding this comment.
Internal control flow starts after LTGF - not here.
| int32_t alignmentConstant = TR::Compiler->om.getObjectAlignmentInBytes(); | ||
| bool useCompRefs = TR::Compiler->om.compressObjectReferences(); | ||
| // Skip alignment if both header and elements are aligned. | ||
| bool alignFirstDim = !OMR::aligned(headerSize, alignmentConstant) || !OMR::aligned(elementSize, alignmentConstant); |
There was a problem hiding this comment.
First use if the alignFirstDim is at line 4915 - is there specific reason - it is defined here?
Also it would have been easier to read is you have something like following,
| bool alignFirstDim = !OMR::aligned(headerSize, alignmentConstant) || !OMR::aligned(elementSize, alignmentConstant); | |
| bool alignFirstDim = !(OMR::aligned(headerSize, alignmentConstant) && OMR::aligned(elementSize, alignmentConstant)); |
This is self-explanatory, you would not need the comment above.
| bool useCompRefs = TR::Compiler->om.compressObjectReferences(); | ||
| // Skip alignment if both header and elements are aligned. | ||
| bool alignFirstDim = !OMR::aligned(headerSize, alignmentConstant) || !OMR::aligned(elementSize, alignmentConstant); | ||
| bool alignSecondDim = !OMR::aligned(headerSize, alignmentConstant) || !OMR::aligned(componentSize, alignmentConstant); |
There was a problem hiding this comment.
Similar comment as previous comment.
| // Skip alignment if both header and elements are aligned. | ||
| bool alignFirstDim = !OMR::aligned(headerSize, alignmentConstant) || !OMR::aligned(elementSize, alignmentConstant); | ||
| bool alignSecondDim = !OMR::aligned(headerSize, alignmentConstant) || !OMR::aligned(componentSize, alignmentConstant); | ||
| // If any dimension length is zero, resulting array have discontiguous array size |
There was a problem hiding this comment.
I think the comment is bit unclear - please elaborate a bit.
| * \details | ||
| * Allocate 2 dimensional multi new arrays of any type with inline instructions if the size is within the range of TLH. | ||
| * This helper needs the following conditions to work properly and the caller should check these before calling: | ||
| * 1. Must be a 64bit system. |
There was a problem hiding this comment.
I think having Asserts for these conditions makes more sense (Rather than having it in caller.)
There was a problem hiding this comment.
I used simple ASSERT to emphasize the conditions. I do not expect to get invalid data since the caller check those. Please let me know if you prefer ASSERT_FATAL
There was a problem hiding this comment.
I would prefer FATAL assert, it is not so much as current callers, this asserts are there to prevent in future using this generate helper function with the conditions with which current function is implemented
There was a problem hiding this comment.
I converted to fatal assert
| // Need dimReg for helper. | ||
| TR::Register *dimReg = cg->evaluate(node->getSecondChild()); | ||
| TR::Register *classReg = cg->gprClobberEvaluate(node->getThirdChild()); | ||
| TR::Register *vmThreadReg = cg->getMethodMetaDataRealRegister(); |
There was a problem hiding this comment.
Move declaration and definition of this register closer to where it is used (It is not needed for deps as well)
dc27cf3 to
bc0f923
Compare
r30shah
left a comment
There was a problem hiding this comment.
I think I am 70% done with review - Only need to go through code that deals with the allocation / bookkeeping of second dimension arrays - but some minor comments / questions / suggestions based on the review done so far. Just cosmetic changes, no structural changes.
| /////////////////////////////////////////////////////////////////////////////////////// | ||
| // Generate code for multianewarray | ||
| // Checks the number of dimensions. For 1 dimensional arrays call the helper, for >1 call | ||
| // Checks the number of dimensions. For 1 dimensional arrays call the helper, for 2 call |
There was a problem hiding this comment.
I think a better comment here would need some more details. We are generating the inlined code for 2 dimensions. For all other cases we generate helper call, it is not only the 1 dimensional array.
Also out of curiosity - Why can't we generate inline code for 1 dimensional array, can we have multianewarray for 1-D array ?
There was a problem hiding this comment.
since the number of dimensions is static, It would be very odd to receive a call to allocate one dimension array here! anewarray would gets called for those cases.
| TR_ASSERT_FATAL(secondChild->getOpCodeValue() == TR::iconst, "dims of multianewarray must be iconst"); | ||
|
|
||
| // Only generate inline code if nDims > 1 | ||
| uint32_t nDims = secondChild->get32bitIntegralValue(); |
There was a problem hiding this comment.
Though, it was already there, suggestion,
| uint32_t nDims = secondChild->get32bitIntegralValue(); | |
| uint32_t nDims = static_cast<uint32_t>(secondChild->get32bitIntegralValue()); |
| static TR::Register * generateMultianewArrayWithInlineAllocators(TR::Node *node, TR::CodeGenerator *cg) | ||
| /** | ||
| * \brief | ||
| * Inline allocation of two dimensional new array. |
There was a problem hiding this comment.
The name and brief do not match - I am ok to simply use multi dimensional array here. We can mention here that the helper currently only supports two dimensional array.
| * Inline allocation of two dimensional new array. | ||
| * | ||
| * \details | ||
| * Allocate 2 dimensional multi new arrays of any type with inline instructions if the size is within the range of TLH. |
There was a problem hiding this comment.
Name of the function and the comment (brief and details) is bit mismatching. I would convey the message in the details that this helper only supports multianew array with 2 dimensions. Also would spin the conditions you listed as current support statement (Mode definitive - compare to what you have right not (work properly))
| * This helper allocate any non negative size 2D array if it fits inside the TLH. | ||
| * | ||
| * \param node | ||
| * The node. |
|
|
||
| cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, zeroSecondDimLabel, cursor); | ||
| // If jumping from zero second dim match, set second dim size to discontiguous. Otherwise this wont change values. | ||
| cursor = generateRRInstruction(cg, TR::InstOpCode::LR, node, dim2SizeReg, sizeReg, cursor); |
There was a problem hiding this comment.
Why LR and not LGR - I assume the sizeReg here is the discontiguous size which you loaded at the beginning in the evaluator. Eventhough this would not cause any functional issue given the dim2SizeReg is loaded with LTGF - Please use LGR here.
There was a problem hiding this comment.
the purpuse of LTGF is to zero the higher 32 bits of the 64bit register. Since we know that this size is less than 32bits and the higher 32bit is already zero, we can use LR here with is a 4byte instruction. LGR is a 8byte instruction.
There was a problem hiding this comment.
This kind of assumptions are the one that could cause code to become difficult to understand / manage and may cause bug if something changes. What different does LR/LGR makes ? In your evaluator, operand is 64-bit - Why do we make assumption that it will never have upper half with some value so only load the 32-bit value.
There was a problem hiding this comment.
I was trying to reduce code size by using LR but if you think LGR makes the code more readable, I'll use that.
There was a problem hiding this comment.
It's more about the kind of assumptions - that later on leads to issues with upper half containing some stale values - you have written the code so you know about the assumption, I have reviewed the code so I know. But in future due to some issues if there is some change happens before this LR/LGR - this kind of change is so implicit that it is easy to forget. We would have the code in - and in rare highly intermittent case we would hit some unexpected result. This is the reason, we should try to work with the operand type as much as possible.
| // If jumping from zero second dim match, set second dim size to discontiguous. Otherwise this wont change values. | ||
| cursor = generateRRInstruction(cg, TR::InstOpCode::LR, node, dim2SizeReg, sizeReg, cursor); | ||
| // Total size = (second dim size * number of second dim arrays) + first dim size. | ||
| // Max possible value is uint32.max * int32.max which will not overflow. |
There was a problem hiding this comment.
Which operand is uint32? I think this comment is bit misleading - Please add more context with the assumption that you are taking - which is max number of bytes would not overflow 64-bit range.
| if (alignFirstDim) | ||
| cursor = generateRILInstruction(cg, TR::InstOpCode::NILF, node, dim1SizeReg, -alignmentConstant, cursor); | ||
|
|
||
| cursor = generateRREInstruction(cg, TR::InstOpCode::AGR, node, sizeReg, dim1SizeReg, cursor); |
There was a problem hiding this comment.
If we reach here, do we expect to be dealing with negative values ? What would be the consequences of using ALGR?
There was a problem hiding this comment.
We already checked for negatives and max possible value is guaranteed to be a positive int64 value so both AGR and ALGR work fine here.
There was a problem hiding this comment.
So can you use ALGR? that would guarantee to not cause fixed point overflow.
| cursor = generateRREInstruction(cg, TR::InstOpCode::AGR, node, sizeReg, dim1SizeReg, cursor); | ||
| iComment("Total size in sizeReg."); | ||
| // Only a positive number with no overflow is acceptable. | ||
| cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRNP, node, inlineAllocFailLabel, cursor); |
There was a problem hiding this comment.
Given the zero length and negative length is already dealt - can we have 0/negative outcome ?
There was a problem hiding this comment.
No it is not possible to have negative or zero. We only need to check for overflow here but since it has no cost, I used COND_BRNP to emphasize that the size after this branch is a positive integer!
There was a problem hiding this comment.
Please adjust the condition based on the instruction change recommended in #22548 (comment)
There was a problem hiding this comment.
I remove this branch since this adding can not overflow.
| // Update heap alloc. | ||
| cursor = generateRXInstruction(cg, TR::InstOpCode::STG, node, sizeReg, generateS390MemoryReference(vmThreadReg, heapAllocOffset, cg), cursor); | ||
| iComment("Heap top test pass. Update heap alloc."); | ||
| TR::Register *miscellaneousReg = cg->allocateRegister(); |
There was a problem hiding this comment.
I think scratchReg is better suitable name.
5708636 to
56ef740
Compare
|
Thanks @r30shah for your review. I addressed all the changes and the only thing left is the |
|
I get some failures in my jdk21 testing on Jenkins. I investigate to see if it is related to my changes. |
56ef740 to
04f9af2
Compare
| if (componentSize == 1) | ||
| { | ||
| // Make sure second dim length is not negative. | ||
| cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BL, node, inlineAllocFailLabel, cursor); |
There was a problem hiding this comment.
So my point about using the appropriate instruction for the data type was to ensure that we do not run into issues where some other change that happens causes incompatibility with your change down the road with such implicit assumptions like using SLA to only working with 32-bit signed length (# bytes) and assuming that we would never have the overflow with MSGR because different paths in your ICF and set of instructions you selected does not let the case which can have an overflow for long multiplication.
I do see the current implementation you have works on z196 or newer. We have instruction that is available in z14 or newer (Multiply Single) that you can use which can set the condition code that you can use. Second option is using multiply and check upper 64-bit with zero by using CGIJ instruction.
Bit hesitant with current logic you have though it simplifies the instruction you generated - it puts limitation on the size of the array you are allocating and that restriction is implicit - not something documented / written in the comment, and also some third person reading the code would not find easy to make enhancement / change and may introduce the bugs, but it you really think that this is the best sequence we can have and in field even with large TLH size, restricting a dimension length to the value you have due to very limited cases, I am ok with current change, and in that case, I would recommend you to put a detailed comments so that it becomes clear when someone looks/modifies the code.
| TR::Node::recreate(node, TR::acall); | ||
| TR::Register *targetReg2 = TR::TreeEvaluator::performCall(node, false, cg); | ||
| TR::Node *secondChild = node->getSecondChild(); | ||
| if (secondChild->getOpCode().isLoadConst() || secondChild->getOpCodeValue() == TR::iRegLoad) |
There was a problem hiding this comment.
@r30shah No sure if this is necessary to convert to long. It doesn't cause any issue but I am wondering is having garbage data in the higher32 bits of the parameter register can cause any issues in any case.
Let me know if I should revert this change.
There was a problem hiding this comment.
I do not think you need to do anything here. The child will be evaluated into parameter register by the parameter type that a helper call expects - Is there specific reason you need this change?
There was a problem hiding this comment.
Thanks, A few tests started to fail and I saw wrong parameter value and thought maybe it is because of the higher half of the parameter register. Later I find that the register was evaluated after the branching to the helper therefore the value was wrong but I decided to make sure about this.
| TR::Node::recreate(node, TR::acall); | ||
| TR::Register *targetReg2 = TR::TreeEvaluator::performCall(node, false, cg); | ||
| TR::Node *secondChild = node->getSecondChild(); | ||
| if (secondChild->getOpCode().isLoadConst() || secondChild->getOpCodeValue() == TR::iRegLoad) |
There was a problem hiding this comment.
I do not think you need to do anything here. The child will be evaluated into parameter register by the parameter type that a helper call expects - Is there specific reason you need this change?
2d3c0b3 to
70c4c81
Compare
|
Sanity tests are passing. |
| TR::Register *targetReg = cg->allocateRegister(); | ||
| TR::Instruction *cursor = NULL; | ||
| int32_t elementSize = TR::Compiler->om.sizeofReferenceField(); | ||
| TR_ASSERT_FATAL(comp->target().is64Bit(), "multianewArrayEvaluator is only supported on 64-bit JVMs!"); |
There was a problem hiding this comment.
It is getting bit crowded here. Can we add some spacing between ASSERTs? to make each ASSERT message and condition clear?
| generateS390LabelInstruction(cg, TR::InstOpCode::label, node, cFlowRegionStart); | ||
| /********************************************* Register setup *********************************************/ | ||
| TR::Register *dimsPtrReg = cg->evaluate(node->getFirstChild()); | ||
| TR::Register *classReg = cg->gprClobberEvaluate(node->getThirdChild()); |
There was a problem hiding this comment.
Going to let this one pass - but this variable is used bit late.
| cursor = generateRXInstruction(cg, TR::InstOpCode::LGF, node, firstDimLenReg, generateS390MemoryReference(dimsPtrReg, 4, cg)); | ||
| if (node->getSecondChild()->getReferenceCount() > 1) | ||
| { | ||
| // If dimensions child is referenced elsewhere, evaluate it before ICF. |
There was a problem hiding this comment.
I do not think this comment it needed. I believe this is pretty self explanatory (Given you are doing ref count check)
| // Load int32 second dim length to a 64 bit register. | ||
| cursor = generateRXInstruction(cg, TR::InstOpCode::LGF, node, dim2SizeReg, generateS390MemoryReference(dimsPtrReg, 0, cg), cursor); | ||
| iComment("Load 2st dim length."); | ||
| // To guarantee no overflow in size calculation, the `length * componentSize` should not be larger than int32.max. Additionaly, the |
There was a problem hiding this comment.
Here are the points I want to make clear here so that in future if we decide to go with using the other multiplication version or investigate why we fail allocating inline even when we set large enough TLH.
- Dimension length type is Int32. For given component, if total number of bytes are larger than INT_MAX, there is a possibility that total bytes to allocate may overflow 64-bit range.
- By using
SLAinstruction, even though we put a cap on allocating inline array way below the range that can cause 64-bit overflow, it will simplify the instructions you are generating and avoid the overflow check after multiplying dimension 1 bytes and dimension 2 bytes as well as at places which contributes to total bytes calculation. - So add the assumption that we are making with the dimension length.
Need to be clear on what we are choosing here - Choosing the simplicity / platform compatibility over the allocation limit (Which I do expect to be very rare)
There was a problem hiding this comment.
Also this is source code that is going to be opened in the IDE or browser which will not be rendered for the mark down - using the special characters for markdown would not help at all - Looks bit odd.
There was a problem hiding this comment.
Updated the comment
| cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_MASK5, node, inlineAllocFailLabel, cursor); | ||
|
|
||
| int32_t headerSize= TR::Compiler->om.contiguousArrayHeaderSizeInBytes(); | ||
| // `size = (size + alignmentConstant - 1) & -alignmentConstant` equation round up the size to a factor of alignmentConstant. |
There was a problem hiding this comment.
No need to put `` in the source code.
| // Fist dim class and length: | ||
| bool useCompRefs = TR::Compiler->om.compressObjectReferences(); | ||
| cursor = generateRXInstruction(cg, useCompRefs ? TR::InstOpCode::ST : TR::InstOpCode::STG, node, classReg, | ||
| generateS390MemoryReference(resultReg, (int32_t)TR::Compiler->om.offsetOfObjectVftField(), cg), cursor); |
There was a problem hiding this comment.
Please use static_cast<int32_t>... - Also if other places in this evaluator does use C++ casting, please change that.
| cursor = generateRXInstruction(cg, TR::InstOpCode::LA, node, dim1SizeReg, generateS390MemoryReference(dim1SizeReg, resultReg, 0, cg), cursor); | ||
| iComment("dim1SizeReg points to the fist leaf array."); | ||
| // Load component class to class register. In case of comp refs, class is in high order! | ||
| cursor = generateRXInstruction(cg, TR::InstOpCode::LG, node, classReg, generateS390MemoryReference(classReg, offsetof(J9ArrayClass, componentType)+(useCompRefs ? 4 : 0), cg), cursor); |
There was a problem hiding this comment.
| cursor = generateRXInstruction(cg, TR::InstOpCode::LG, node, classReg, generateS390MemoryReference(classReg, offsetof(J9ArrayClass, componentType)+(useCompRefs ? 4 : 0), cg), cursor); | |
| cursor = generateRXInstruction(cg, TR::InstOpCode::LG, node, classReg, generateS390MemoryReference(classReg, offsetof(J9ArrayClass, componentType) + (useCompRefs ? 4 : 0), cg), cursor); |
|
|
||
| cursor = generateRXInstruction(cg, TR::InstOpCode::LA, node, dim1SizeReg, generateS390MemoryReference(dim1SizeReg, resultReg, 0, cg), cursor); | ||
| iComment("dim1SizeReg points to the fist leaf array."); | ||
| // Load component class to class register. In case of comp refs, class is in high order! |
There was a problem hiding this comment.
What is high order ? Class is in the lower half of the double word right.
There was a problem hiding this comment.
Thats correct, made the comment more clear.
| // dataAddr field. secondDimLenReg is expected to be NULL at this point. | ||
| cursor = generateRXInstruction(cg, TR::InstOpCode::STG, node, firstDimLenReg, generateS390MemoryReference(targetReg, fej9->getOffsetOfDiscontiguousDataAddrField(), cg)); | ||
| iComment("Clear 1st dim dataAddr field."); | ||
| // Keep a compressed version of dim2 size in higher 32 bits. |
There was a problem hiding this comment.
This seems like an odd comment. It suggest compressed version of dim2 size not the compressed refs. Please update the comment to make it clear. Also having some layout information here would enhance the comment.
There was a problem hiding this comment.
Updated the comment and added diagram
| generateRRInstruction(cg, TR::InstOpCode::LGR, node, temp2Reg, targetReg); | ||
| generateRRInstruction(cg, TR::InstOpCode::AGR, node, temp2Reg, temp1Reg); | ||
| if (cg->comp()->target().cpu.isAtLeast(OMR_PROCESSOR_S390_Z196)) | ||
| // Load the address of the first element of the first dimension array in sizeReg. |
There was a problem hiding this comment.
Can you add some comment on the layout here to share how some of the initialization you are doing is done here?
There was a problem hiding this comment.
Added comments to summarize the second dim allocation plan
r30shah
left a comment
There was a problem hiding this comment.
@ehsankianifar I think we are closer, some more changes.
| cursor = generateS390CompareAndBranchInstruction(cg, TR::InstOpCode::CL, node, scratchReg, 0, TR::InstOpCode::COND_BE, controlFlowEndLabel, false /* needsCC */, cursor); | ||
|
|
||
| cursor = generateRXInstruction(cg, TR::InstOpCode::LA, node, dim1SizeReg, generateS390MemoryReference(dim1SizeReg, resultReg, 0, cg), cursor); | ||
| iComment("dim1SizeReg points to the fist leaf array."); |
|
|
||
| cursor = generateRXInstruction(cg, TR::InstOpCode::LA, node, dim1SizeReg, generateS390MemoryReference(dim1SizeReg, resultReg, 0, cg), cursor); | ||
| iComment("dim1SizeReg points to the fist leaf array."); | ||
| // Load component class to class register. In case of comp refs, the calss is 32bits long so using this register for leaf array length value as well. |
There was a problem hiding this comment.
Another typo, and please do not shorten compressedrefs to comp refs (We do not use that throughout our code and also comp is used throughout for the compiler object). Class pointer is is 32-bit wide (Opposite to long which is more suitable for array).
| // Load component class to class register. In case of comp refs, the calss is 32bits long so using this register for leaf array length value as well. | ||
| // ClassReg when non-comp refs: | class | | ||
| // ClassReg when comp refs: | class | length | | ||
| cursor = generateRXInstruction(cg, TR::InstOpCode::LG, node, classReg, generateS390MemoryReference(classReg, offsetof(J9ArrayClass, componentType) + (useCompRefs ? 4 : 0), cg), cursor); |
There was a problem hiding this comment.
Hmm, I do get your intention to smartly combine the field to reduce number of operations we need to do. It does work now but is not easily extensible if for any reason object layout changes or in future we can not guarantee J9Class* to be 32-bit wide for compressed refs. So do not do that.
This is also bug/error prune - We are loading double word from middle of the field offset for componentType which will also load upper half of itable into the register which you are later updating by loading the length register.
So please revert to old way of updating the header.
There was a problem hiding this comment.
It save us one store operation in the leaf allocation loop. It is very easy to change but should't we change it if the layout changes in future?
There was a problem hiding this comment.
My point is that - If the layout changes or compressed ref address for J9Class is not guaranteed to fit 32-bits, kind of changes needed would be a lot, and it wouldn't be that simple.
There was a problem hiding this comment.
You are also doing an extra operation to fit both class and length in one register, right?
There was a problem hiding this comment.
Chenged to simple load/store
| cursor = generateRXInstruction(cg, TR::InstOpCode::L, node, classReg, generateS390MemoryReference(dimsPtrReg, 0, cg), cursor); | ||
| if (shiftAmount > 0) | ||
| { | ||
| // Keep a compressed dim2 size in higher 32 bits. |
There was a problem hiding this comment.
I do not think you addressed my previous comment, what is compressed dim2 size? Keep a compressed dim2 size in higher 32-bits has completely different meaning then For compressedref, dim2 size in higher 32-bits
There was a problem hiding this comment.
I compressed the size by shifting to the right. So we have the actual size in lower 32bits and the shifted size in higher 32 bits. This way I can add this value to the compressed reference of the leaf array and get the compressed reference of the next leaf.
There was a problem hiding this comment.
It is not termed as compressed size. You are shifting the size not compressing it.
| // dim2SizeReg when shift amount is 0: | unused | leaf array size | | ||
| // dim2SizeReg when shift amount is > 0: | compressed leaf array size | leaf array size | | ||
| cursor = generateRIEInstruction(cg, TR::InstOpCode::RISBG, node, dim2SizeReg, dim2SizeReg, 0, 31, 32-shiftAmount, cursor); | ||
| iComment("Compressed dim2 size in higher 32bits."); |
There was a problem hiding this comment.
Fix this comment. You are not compressing the dim2 size.
| // scratchReg when shift amount is 0: | leaf array length | number of leaf arrays | | ||
| // scratchReg when shift amount is > 0: | compressed leaf array address | number of leaf arrays | | ||
| cursor = generateRIEInstruction(cg, TR::InstOpCode::RISBG, node, scratchReg, dim1SizeReg, 0, 31, 32-shiftAmount, cursor); | ||
| iComment("Compressed dim2 reference in higher 32 bits."); |
| // Start setting second dim: | ||
| TR::LabelSymbol *secondDimLabel = generateLabelSymbol(cg); | ||
| cursor = generateS390LabelInstruction(cg, TR::InstOpCode::label, node, secondDimLabel, cursor); | ||
| // Store the class field. In case of comp refs, store the class and length fields. |
There was a problem hiding this comment.
Please update the short for comp refs to compressedrefs throughout this evaluator.
| cursor = generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_B, node, controlFlowEndLabel, cursor); | ||
| iComment("Allocation done!"); | ||
|
|
||
| /********************************************* Unreachable zone *********************************************/ |
There was a problem hiding this comment.
What do you mean by unreachable zone ?
There was a problem hiding this comment.
Any code here will not be executed. I put it here to make it clear why the EXRL target is here.
There was a problem hiding this comment.
Ok, so I do not like having two XC instruction to perform the clearing and having EXRL separate target. We should be able to generate better loop for that. In any case, this comment is not that clear. Can we rewrite the loop so that we do not need extra XC to be generated ?
| static bool disableBatchClear = feGetEnv("TR_DisableBatchClear") != NULL; | ||
| bool needInitialization = disableBatchClear && !node->canSkipZeroInitialization(); | ||
| TR::LabelSymbol *memoryInitializationExrlTargetLabel = NULL; | ||
| if (needInitialization) |
There was a problem hiding this comment.
Hmm, Did you change the login for memclear ? Usually we would use XC and for residue, use the EXRL. Current implementation have two XC generated. We should simplify this code it does look messy.
r30shah
left a comment
There was a problem hiding this comment.
@ehsankianifar Some more suggestions, I think we are closer.
ab0751c to
1c51da8
Compare
Thanks @r30shah, |
|
Thanks @ehsankianifar - Just confirming before I go for final review, have you addressed comment in #22548 (comment) ? |
|
@r30shah I changed the order of memory initialization instructions. |
db78475 to
c7f5f89
Compare
I changed the order of operations in my last commit so I clean 256 byte chunks first the clean the residual bytes. Also moved the EXRL target next to EXRL instruction. |
c7f5f89 to
91a89d2
Compare
r30shah
left a comment
There was a problem hiding this comment.
@ehsankianifar Looks OK to me, but will skim over once again to make sure if there is anything left to address. One comment I had - Please not it is comment, I do not expect you to make change, but just an answer. I am going to launch test.
|
|
||
| generateRRInstruction(cg, TR::InstOpCode::LGR, node, targetReg, targetReg2); | ||
| generateS390BranchInstruction(cg, TR::InstOpCode::BRC, TR::InstOpCode::COND_BRC, node, cFlowRegionDone); | ||
| generateRRInstruction(cg, TR::InstOpCode::LGR, node, resultReg, slowResultReg); |
There was a problem hiding this comment.
Asking, would it be possible to copy this to collectedResultReg ? so that we do not perform copy again in the mainline?
There was a problem hiding this comment.
I was afraid using the collected reference register in the slow path may add it to the GC point but never tested to see what happens.
There was a problem hiding this comment.
Ok. It would be good to understand if this can be issue or not. I do see other evaluators using the allocated collected reference register throughout the evaluator (Take a look at VMNew). Now it may be possible that these register is added to dependency list which is merged in OOL with the dependency list generated for the helper call and it is ok (It won't be spilled), in which case I think current way in multianewarray is fine, but something to look into in future.
|
Can you squash commits? |
Adding instructions to inline allocation of two dimensional arrays with any length. Before this change, we only inline 2d arrays if at least one dimension length is zero. signed-off-by: Ehsan Kiani Far <ehsan.kianifar@gmail.com>
91a89d2 to
9452d2d
Compare
Thanks for the review. Comments squashed! |
|
jenkins test sanity zlinux jdk8,jdk21 |
r30shah
left a comment
There was a problem hiding this comment.
All tests have passed, and changes LGTM. I am merging this one.
multianewarray opcode instructions was updated in eclipse-openj9#22548 and the evaluation of the second child was changed to evaluate only if reference count is > 1. This caused the last multianewarray tree to have wrong dims register child and some failures. Remove the condition for evaluating children. Fix: eclipse-openj9#22757 signed-off-by: Ehsan Kiani Far <ehsan.kianifar@gmail.com>
multianewarray opcode instructions was updated in eclipse-openj9#22548 and the evaluation of the second child was changed to evaluate only if reference count is > 1. This caused the last multianewarray tree to have wrong dims register child and some failures. Remove the condition for evaluating children. Fix: eclipse-openj9#22757 signed-off-by: Ehsan Kiani Far <ehsan.kianifar@gmail.com>
multianewarray opcode instructions was updated in eclipse-openj9#22548 and the evaluation of the second child was changed to evaluate only if reference count is > 1. This caused the last multianewarray tree to have wrong dims register child and some failures. Remove the condition for evaluating children. Fix: eclipse-openj9#22757 signed-off-by: Ehsan Kiani Far <ehsan.kianifar@gmail.com>
multianewarray opcode instructions was updated in eclipse-openj9#22548 and the evaluation of the second child was changed to evaluate only if reference count is > 1. This caused the last multianewarray tree to have wrong dims register child and some failures. Remove the condition for evaluating children. Fix: eclipse-openj9#22757 signed-off-by: Ehsan Kiani Far <ehsan.kianifar@gmail.com>
Adding instructions to inline allocation of two dimensional arrays with any length. Before this change, we only inline 2d arrays if at least one dimension length is zero.