diff --git a/runtime/compiler/env/VMJ9.cpp b/runtime/compiler/env/VMJ9.cpp index abc179bd168..4afceabb4c6 100644 --- a/runtime/compiler/env/VMJ9.cpp +++ b/runtime/compiler/env/VMJ9.cpp @@ -2883,6 +2883,28 @@ TR_J9VMBase::testAreSomeClassFlagsSet(TR::Node *j9ClassRefNode, uint32_t flagsTo return maskedFlags; } +TR::Node * +TR_J9VMBase::testAreSomeClassAndDepthFlagsSet(TR::Node *j9ClassRefNode, uint32_t flagsToTest) + { + TR::SymbolReference *classAndDepthFlagsSymRef = TR::comp()->getSymRefTab()->findOrCreateClassAndDepthFlagsSymbolRef(); + TR::Node *classFlags = NULL; + + if (TR::comp()->target().is32Bit()) + { + classFlags = TR::Node::createWithSymRef(TR::iloadi, 1, 1, j9ClassRefNode, classAndDepthFlagsSymRef); + } + else + { + classFlags = TR::Node::createWithSymRef(TR::lloadi, 1, 1, j9ClassRefNode, classAndDepthFlagsSymRef); + classFlags = TR::Node::create(TR::l2i, 1, classFlags); + } + + TR::Node *maskedFlags = TR::Node::create(TR::iand, 2, classFlags, TR::Node::iconst(j9ClassRefNode, flagsToTest)); + + return maskedFlags; + } + + TR::Node * TR_J9VMBase::testIsClassValueType(TR::Node *j9ClassRefNode) { @@ -2902,13 +2924,21 @@ TR_J9VMBase::testIsClassIdentityType(TR::Node *j9ClassRefNode) } TR::Node * -TR_J9VMBase::checkSomeArrayCompClassFlags(TR::Node *arrayBaseAddressNode, TR::ILOpCodes ifCmpOp, uint32_t flagsToTest) +TR_J9VMBase::loadArrayClassComponentType(TR::Node *j9ClassRefNode) { - TR::SymbolReference *vftSymRef = TR::comp()->getSymRefTab()->findOrCreateVftSymbolRef(); TR::SymbolReference *arrayCompSymRef = TR::comp()->getSymRefTab()->findOrCreateArrayComponentTypeSymbolRef(); + TR::Node *arrayCompClass = TR::Node::createWithSymRef(TR::aloadi, 1, 1, j9ClassRefNode, arrayCompSymRef); + + return arrayCompClass; + } +TR::Node * +TR_J9VMBase::checkSomeArrayCompClassFlags(TR::Node *arrayBaseAddressNode, TR::ILOpCodes ifCmpOp, uint32_t flagsToTest) + { + TR::SymbolReference *vftSymRef = TR::comp()->getSymRefTab()->findOrCreateVftSymbolRef(); TR::Node *vft = TR::Node::createWithSymRef(TR::aloadi, 1, 1, arrayBaseAddressNode, vftSymRef); - TR::Node *arrayCompClass = TR::Node::createWithSymRef(TR::aloadi, 1, 1, vft, arrayCompSymRef); + + TR::Node *arrayCompClass = loadArrayClassComponentType(vft); TR::Node *maskedFlagsNode = testAreSomeClassFlagsSet(arrayCompClass, flagsToTest); TR::Node *ifNode = TR::Node::createif(ifCmpOp, maskedFlagsNode, TR::Node::iconst(arrayBaseAddressNode, 0)); @@ -7642,6 +7672,7 @@ TR_J9VM::inlineNativeCall(TR::Compilation * comp, TR::TreeTop * callNodeTreeTop, TR::Node::recreate(callNode, TR::aloadi); callNode->setSymbolReference(comp->getSymRefTab()->findOrCreateVftSymbolRef()); callNode = TR::Node::createWithSymRef(TR::aloadi, 1, 1, callNode, comp->getSymRefTab()->findOrCreateJavaLangClassFromClassSymbolRef()); + callNode->setIsNonNull(true); return callNode; // Note: these cases are not tested and thus are commented out: diff --git a/runtime/compiler/env/VMJ9.h b/runtime/compiler/env/VMJ9.h index a5d717be928..927a5228074 100644 --- a/runtime/compiler/env/VMJ9.h +++ b/runtime/compiler/env/VMJ9.h @@ -1263,6 +1263,8 @@ class TR_J9VMBase : public TR_FrontEnd */ TR::Node * testAreSomeClassFlagsSet(TR::Node *j9ClassRefNode, uint32_t flagsToTest); + TR::Node * testAreSomeClassAndDepthFlagsSet(TR::Node *j9ClassRefNode, uint32_t flagsToTest); + /** * \brief Load class flags field of the specified class and test whether the value type * flag is set. @@ -1290,6 +1292,8 @@ class TR_J9VMBase : public TR_FrontEnd */ TR::Node * testIsClassIdentityType(TR::Node *j9ClassRefNode); + TR::Node * loadArrayClassComponentType(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 diff --git a/runtime/compiler/optimizer/J9ValuePropagation.cpp b/runtime/compiler/optimizer/J9ValuePropagation.cpp index 169d623d158..11dfa5eac4d 100644 --- a/runtime/compiler/optimizer/J9ValuePropagation.cpp +++ b/runtime/compiler/optimizer/J9ValuePropagation.cpp @@ -1691,8 +1691,11 @@ J9::ValuePropagation::constrainRecognizedMethod(TR::Node *node) TR::Node *classChild = node->getLastChild(); bool classChildGlobal; TR::VPConstraint *classChildConstraint = getConstraint(classChild, classChildGlobal); - if (classChildConstraint && classChildConstraint->isJavaLangClassObject() == TR_yes - && classChildConstraint->isNonNullObject() + bool isNonNullJavaLangClass = classChildConstraint + && classChildConstraint->isJavaLangClassObject() == TR_yes + && classChildConstraint->isNonNullObject(); + + if (isNonNullJavaLangClass && classChildConstraint->getClassType() && classChildConstraint->getClassType()->asFixedClass()) { @@ -1748,6 +1751,65 @@ J9::ValuePropagation::constrainRecognizedMethod(TR::Node *node) return; } } + else if (isNonNullJavaLangClass) + { + if (!performTransformation(comp(), "%sTransforming %s on node %p to load component type inline\n", OPT_DETAILS, signature, node)) + break; + + // Consider two cases: + // + // (i) The operand is an instance of java.lang.Class indirectly loaded through a vft. In that case, + // we can work with the vft directly + // (ii) The operand is definitely a non-null instance of java.lang.Class. In that case, load the + // J9Class from the java.lang.Class by way of + // + + TR::SymbolReference *symRef = classChild->getOpCode().hasSymbolReference() ? classChild->getSymbolReference() : NULL; + TR::SymbolReference *jlcFromClassSymRef = comp()->getSymRefTab()->findOrCreateJavaLangClassFromClassSymbolRef(); + TR::Node *classOperand = NULL; + + if ((symRef != NULL) && (symRef == jlcFromClassSymRef)) + { + classOperand = classChild->getFirstChild(); + } + else + { + classOperand = TR::Node::createWithSymRef(TR::aloadi, 1, 1, classChild, + comp()->getSymRefTab()->findOrCreateClassFromJavaLangClassSymbolRef()); + } + + TR::Node *loadComponentTypeNode = comp()->fej9()->loadArrayClassComponentType(classOperand); + TR::Node *jlcOfComponentTypeNode = NULL; + + if ((classChildConstraint == NULL) + || (classChildConstraint->getClassType() == NULL) + || !comp()->fej9()->isClassArray(classChildConstraint->getClass())) + { + TR::Node *testIsArrayClassNode = + TR::Node::create(node, TR::icmpne, 2, + comp()->fej9()->testAreSomeClassAndDepthFlagsSet(classOperand, comp()->fej9()->getFlagValueForArrayCheck()), + TR::Node::iconst(node, 0)); + loadComponentTypeNode = + TR::Node::create(TR::aselect, 3, + testIsArrayClassNode, + loadComponentTypeNode, + classOperand); + loadComponentTypeNode = + TR::Node::createWithSymRef(node, TR::aloadi, 1, loadComponentTypeNode, jlcFromClassSymRef); + jlcOfComponentTypeNode = + TR::Node::create(TR::aselect, 3, + testIsArrayClassNode, + loadComponentTypeNode, + TR::Node::aconst(node, 0)); + } + else + { + jlcOfComponentTypeNode = + TR::Node::createWithSymRef(node, TR::aloadi, 1, loadComponentTypeNode, jlcFromClassSymRef); + } + + transformCallToNodeDelayedTransformations(_curTree, jlcOfComponentTypeNode, false); + } break; } case TR::java_lang_J9VMInternals_getSuperclass: