diff --git a/runtime/compiler/env/VMJ9.cpp b/runtime/compiler/env/VMJ9.cpp index ab58e0c67a7..7c257556ccc 100644 --- a/runtime/compiler/env/VMJ9.cpp +++ b/runtime/compiler/env/VMJ9.cpp @@ -2937,6 +2937,12 @@ TR_J9VMBase::testIsClassArrayType(TR::Node *j9ClassRefNode) return testAreSomeClassDepthAndFlagsSet(j9ClassRefNode, getFlagValueForArrayCheck()); } +TR::Node * +TR_J9VMBase::testIsArrayClassNullRestrictedType(TR::Node *j9ClassRefNode) + { + return testAreSomeClassFlagsSet(j9ClassRefNode, J9ClassArrayIsNullRestricted); + } + TR::Node * TR_J9VMBase::loadArrayClassComponentType(TR::Node *j9ClassRefNode) { @@ -2959,12 +2965,6 @@ TR_J9VMBase::checkSomeArrayCompClassFlags(TR::Node *arrayBaseAddressNode, TR::IL return ifNode; } -TR::Node * -TR_J9VMBase::checkArrayCompClassPrimitiveValueType(TR::Node *arrayBaseAddressNode, TR::ILOpCodes ifCmpOp) - { - return checkSomeArrayCompClassFlags(arrayBaseAddressNode, ifCmpOp, J9ClassIsPrimitiveValueType); - } - TR::Node * TR_J9VMBase::checkArrayCompClassValueType(TR::Node *arrayBaseAddressNode, TR::ILOpCodes ifCmpOp) { diff --git a/runtime/compiler/env/VMJ9.h b/runtime/compiler/env/VMJ9.h index b68fcfd517f..336795de5d6 100644 --- a/runtime/compiler/env/VMJ9.h +++ b/runtime/compiler/env/VMJ9.h @@ -1321,6 +1321,15 @@ class TR_J9VMBase : public TR_FrontEnd */ TR::Node * testIsClassArrayType(TR::Node *j9ClassRefNode); + /** + * \brief Generate IL to test whether the array's class is null-restricted + * \param j9ClassRefNode A node representing a reference to a \ref J9Class + * \return \ref TR::Node that tests whether the array's class flags has the + * \ref J9ClassArrayIsNullRestricted flag set, yielding a non-zero result if the + * flag is set, or zero otherwise. + */ + TR::Node * testIsArrayClassNullRestrictedType(TR::Node *j9ClassRefNode); + /** * \brief Test whether any of the specified flags is set on the array's component class * \param arrayBaseAddressNode A node representing a reference to the array base address @@ -1338,14 +1347,6 @@ class TR_J9VMBase : public TR_FrontEnd */ TR::Node * checkArrayCompClassValueType(TR::Node *arrayBaseAddressNode, TR::ILOpCodes ifCmpOp); - /** - * \brief Check whether or not the array component class is a primitive value type - * \param arrayBaseAddressNode A node representing a reference to the array base address - * \param ifCmpOp If comparison opCode such as ificmpeq or ificmpne - * \return \ref TR::Node that compares the array component class J9ClassIsPrimitiveValueType flag to a zero integer - */ - TR::Node * checkArrayCompClassPrimitiveValueType(TR::Node *arrayBaseAddressNode, TR::ILOpCodes ifCmpOp); - virtual J9JITConfig *getJ9JITConfig() { return _jitConfig; } virtual int32_t getCompThreadIDForVMThread(void *vmThread); diff --git a/runtime/compiler/optimizer/J9ValuePropagation.cpp b/runtime/compiler/optimizer/J9ValuePropagation.cpp index 78ee3536e5d..7e8e829a31a 100644 --- a/runtime/compiler/optimizer/J9ValuePropagation.cpp +++ b/runtime/compiler/optimizer/J9ValuePropagation.cpp @@ -2653,8 +2653,9 @@ J9::ValuePropagation::transformFlattenedArrayElementStore(TR_OpaqueClassBlock *a // The value that is being stored into the array element has to be non null. if (needsNullValueCheck) { - TR::Node *passThru = TR::Node::create(callNode, TR::PassThrough, 1, valueNode); - TR::Node *nullCheck = TR::Node::createWithSymRef(callNode, TR::NULLCHK, 1, passThru, comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol())); + TR::Node *isNonNull = TR::Node::create(callNode, TR::acmpne, 2, valueNode, TR::Node::aconst(0)); + TR::Node *nullCheck = TR::Node::createWithSymRef(callNode, TR::ZEROCHK, 1, isNonNull, + comp()->getSymRefTab()->findOrCreateArrayStoreExceptionSymbolRef(comp()->getMethodSymbol())); callTree->insertBefore(TR::TreeTop::create(comp(), nullCheck)); if (trace()) { diff --git a/runtime/compiler/optimizer/TreeLowering.cpp b/runtime/compiler/optimizer/TreeLowering.cpp index b84c37de8f7..cde2292a655 100644 --- a/runtime/compiler/optimizer/TreeLowering.cpp +++ b/runtime/compiler/optimizer/TreeLowering.cpp @@ -690,20 +690,14 @@ NonNullableArrayNullStoreCheckTransformer::lower(TR::Node* const node, TR::TreeT // | BBEnd | | // +--------------------------------+ | // | BBStart (Extension) | | - // | ificmpeq -->------------------*---------+ - // | iand | | - // | iloadi | | - // | aloadi | | + // | ZEROCHK jitArrayStoreException | | + // | icmpeq | | + // | iand | | + // | iloadi | | // | aloadi | | // | ==> | | - // | iconst J9ClassIsPrimitiveValueType | - // | iconst 0 | | - // | BBEnd | | - // +--------------------------------+ | - // | BBStart (Extension) | | - // | NULLCHK | | - // | Passthrough | | - // | ==> | | + // | iconst J9ClassArrayIsNullRestricted| + // | iconst 0 | | // | BBEnd | | // +--------------------------------+ | // | | @@ -731,17 +725,18 @@ NonNullableArrayNullStoreCheckTransformer::lower(TR::Node* const node, TR::TreeT tt->getPrevTreeTop()->join(nextTT); TR::Block *nextBlock = prevBlock->splitPostGRA(nextTT, cfg); - TR::Node *ifNode = comp()->fej9()->checkArrayCompClassPrimitiveValueType(destChild, TR::ificmpeq); + TR::SymbolReference* const vftSymRef = comp()->getSymRefTab()->findOrCreateVftSymbolRef(); - ifNode->setBranchDestination(nextBlock->getEntry()); + TR::Node *vftNode = TR::Node::createWithSymRef(node, TR::aloadi, 1, destChild, vftSymRef); - // Copy register dependencies from the end of the block split - // to the ificmpeq, which checks for a value type, that's being - // added to the end of that block - // - copyRegisterDependency(prevBlock->getExit()->getNode(), ifNode); + TR::Node *testIsNullRestrictedArray = comp()->fej9()->testIsArrayClassNullRestrictedType(vftNode); + TR::Node *testIsNotNullRestrictedArray = TR::Node::create(TR::icmpeq, 2, testIsNullRestrictedArray, TR::Node::iconst(0)); - TR::TreeTop *ifArrayCompClassPrimitiveValueTypeTT = prevBlock->append(TR::TreeTop::create(comp(), ifNode)); + TR::ResolvedMethodSymbol *currentMethod = comp()->getMethodSymbol(); + + TR::SymbolReference *jitThrowArrayStoreException = comp()->getSymRefTab()->findOrCreateArrayStoreExceptionSymbolRef(currentMethod); + TR::Node *checkNotNullRestrictedArray = TR::Node::createWithSymRef(TR::ZEROCHK, 1, 1, testIsNotNullRestrictedArray, jitThrowArrayStoreException); + TR::TreeTop *checkNotNullRestrictedArrayTT = prevBlock->append(TR::TreeTop::create(comp(), checkNotNullRestrictedArray)); bool enableTrace = trace(); auto* const nullConst = TR::Node::aconst(0); @@ -753,35 +748,24 @@ NonNullableArrayNullStoreCheckTransformer::lower(TR::Node* const node, TR::TreeT // copyRegisterDependency(prevBlock->getExit()->getNode(), checkValueNull); - TR::TreeTop *checkValueNullTT = ifArrayCompClassPrimitiveValueTypeTT->insertBefore(TR::TreeTop::create(comp(), checkValueNull)); + TR::TreeTop *checkValueNullTT = checkNotNullRestrictedArrayTT->insertBefore(TR::TreeTop::create(comp(), checkValueNull)); if (enableTrace) { - traceMsg(comp(),"checkValueNull n%dn is inserted before n%dn in prevBlock %d\n", checkValueNull->getGlobalIndex(), ifNode->getGlobalIndex(), prevBlock->getNumber()); + traceMsg(comp(),"checkValueNull n%dn is inserted before n%dn in prevBlock %d\n", checkValueNull->getGlobalIndex(), checkNotNullRestrictedArray->getGlobalIndex(), prevBlock->getNumber()); } - TR::Block *compTypeTestBlock = prevBlock->split(ifArrayCompClassPrimitiveValueTypeTT, cfg); - compTypeTestBlock->setIsExtensionOfPreviousBlock(true); + TR::Block *checkNotNullRestrictedBlock = prevBlock->split(checkNotNullRestrictedArrayTT, cfg); + checkNotNullRestrictedBlock->setIsExtensionOfPreviousBlock(true); cfg->addEdge(prevBlock, nextBlock); if (enableTrace) { - traceMsg(comp(),"ifArrayCompClassValueTypeTT n%dn is isolated in compTypeTestBlock %d\n", ifNode->getGlobalIndex(), compTypeTestBlock->getNumber()); + traceMsg(comp(),"checkNotNullRestrictedArray n%dn is isolated in checkNotNullRestrictedBlock %d\n", checkNotNullRestrictedArray->getGlobalIndex(), checkNotNullRestrictedBlock->getNumber()); } - TR::ResolvedMethodSymbol *currentMethod = comp()->getMethodSymbol(); - - TR::Node *passThru = TR::Node::create(node, TR::PassThrough, 1, sourceChild); - TR::Node *nullCheck = TR::Node::createWithSymRef(node, TR::NULLCHK, 1, passThru, - comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(currentMethod)); - TR::TreeTop *nullCheckTT = compTypeTestBlock->append(TR::TreeTop::create(comp(), nullCheck)); - - TR::Block *nullCheckBlock = compTypeTestBlock->split(nullCheckTT, cfg); - - nullCheckBlock->setIsExtensionOfPreviousBlock(true); - - cfg->addEdge(compTypeTestBlock, nextBlock); + cfg->addEdge(checkNotNullRestrictedBlock, nextBlock); } else { @@ -901,6 +885,9 @@ static bool skipBoundChecks(TR::Compilation *comp, TR::Node *node) * Before: +----------------------------------------+ + |NULLCHK | + | PassThrough | + | ==>iRegLoad (array address) | |treetop | | acall jitLoadFlattenableArrayElement | | ==>iRegLoad | @@ -911,15 +898,16 @@ static bool skipBoundChecks(TR::Compilation *comp, TR::Node *node) After: +------------------------------------------+ |BBStart | - |treetop | - | ==>iRegLoad | + |NULLCHK | + | PassThrough | + | ==>iRegLoad (array address) | |treetop | | ==>aRegLoad | |ificmpne ----->---------------------------+-----------+ | iand | | | iloadi | | | ... | | - | iconst J9ClassIsPrimitiveValueType | | + | iconst J9ClassArrayIsNullRestricted | | | iconst 0 | | | GlRegDeps () | | | ==>aRegLoad | | @@ -1120,8 +1108,13 @@ LoadArrayElementTransformer::lower(TR::Node* const node, TR::TreeTop* const tt) /////////////////////////////////////// // 9. Create ificmpne node that checks classFlags + TR::SymbolReference* const vftSymRef = comp->getSymRefTab()->findOrCreateVftSymbolRef(); + + TR::Node *vftNode = TR::Node::createWithSymRef(node, TR::aloadi, 1, anchoredArrayBaseAddressNode, vftSymRef); + TR::Node *testIsArrayClassNullRestrictedNode = comp->fej9()->testIsArrayClassNullRestrictedType(vftNode); + // The branch destination will be set up later - TR::Node *ifNode = comp->fej9()->checkArrayCompClassPrimitiveValueType(anchoredArrayBaseAddressNode, TR::ificmpne); + TR::Node *ifNode = TR::Node::createif(TR::ificmpne, testIsArrayClassNullRestrictedNode, TR::Node::iconst(0)); // Copy register dependency to the ificmpne node that's being appended to the current block copyRegisterDependency(arrayElementLoadBlock->getExit()->getNode(), ifNode); @@ -1226,6 +1219,9 @@ static bool skipArrayStoreChecks(TR::Compilation *comp, TR::Node *node) * Before: +-------------------------------------------+ + |NULLCHK | + | PassThrough | + | aload | |treetop | | acall jitStoreFlattenableArrayElement | | aload | @@ -1237,8 +1233,9 @@ static bool skipArrayStoreChecks(TR::Compilation *comp, TR::Node *node) After: +-------------------------------------------+ |BBStart | - |treetop | - | aload | + |NULLCHK | + | PassThrough | + | aload | |treetop | | aload | |treetop | @@ -1247,7 +1244,7 @@ static bool skipArrayStoreChecks(TR::Compilation *comp, TR::Node *node) | iand | | | iloadi | | | ... | | - | iconst J9ClassIsPrimitiveValueType | | + | iconst J9ClassArrayIsNullRestricted | | | iconst 0 | | | GlRegDeps () | | | PassThrough rcx | | @@ -1260,8 +1257,6 @@ static bool skipArrayStoreChecks(TR::Compilation *comp, TR::Node *node) +-------------------------------------------+ | +-------------------------------------------+ | |BBStart (extension of previous block) | | - |NULLCHK on n82n [if required] | | - | ... | | |BNDCHK | | | ... | | |treetop | | @@ -1476,8 +1471,13 @@ StoreArrayElementTransformer::lower(TR::Node* const node, TR::TreeTop* const tt) /////////////////////////////////////// // 8. Create the ificmpne node that checks classFlags + TR::SymbolReference* const vftSymRef = comp->getSymRefTab()->findOrCreateVftSymbolRef(); + + TR::Node *vftNode = TR::Node::createWithSymRef(node, TR::aloadi, 1, anchoredArrayBaseAddressNode, vftSymRef); + TR::Node *testIsArrayClassNullRestrictedNode = comp->fej9()->testIsArrayClassNullRestrictedType(vftNode); + // The branch destination will be set up later - TR::Node *ifNode = comp->fej9()->checkArrayCompClassPrimitiveValueType(anchoredArrayBaseAddressNode, TR::ificmpne); + TR::Node *ifNode = TR::Node::createif(TR::ificmpne, testIsArrayClassNullRestrictedNode, TR::Node::iconst(0)); // Copy register dependency to the ificmpne node that's being appended to the current block copyRegisterDependency(arrayElementStoreBlock->getExit()->getNode(), ifNode);