diff --git a/runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp b/runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp index cd179d4d24c..fe2b724f0ab 100644 --- a/runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp +++ b/runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp @@ -483,6 +483,8 @@ LastVectorMethod = LastVectorIntrinsicMethod, java_lang_reflect_Array_getLength, + jdk_internal_value_ValueClass_newArrayInstance, + jdk_internal_value_ValueClass_newNullRestrictedArray, java_lang_reflect_Method_invoke, java_util_Arrays_fill, java_util_Arrays_equals, diff --git a/runtime/compiler/env/j9method.cpp b/runtime/compiler/env/j9method.cpp index 41c7b767625..c4d1e610358 100644 --- a/runtime/compiler/env/j9method.cpp +++ b/runtime/compiler/env/j9method.cpp @@ -3847,6 +3847,13 @@ void TR_ResolvedJ9Method::construct() { TR::unknownMethod} }; + static X ValueClassMethods[] = + { + {x(TR::jdk_internal_value_ValueClass_newArrayInstance, "newArrayInstance", "(Ljdk/internal/value/CheckedType;I)[Ljava/lang/Object;")}, + {x(TR::jdk_internal_value_ValueClass_newNullRestrictedArray, "newNullRestrictedArray", "(Ljava/lang/Class;I)[Ljava/lang/Object;")}, + { TR::unknownMethod} + }; + static X SpreadHandleMethods[] = { {x(TR::java_lang_invoke_SpreadHandle_numArgsToPassThrough, "numArgsToPassThrough", "()I")}, @@ -4183,6 +4190,7 @@ void TR_ResolvedJ9Method::construct() { "sun/nio/cs/ISO_8859_1$Decoder", EncodeMethods }, { "java/io/ByteArrayOutputStream", ByteArrayOutputStreamMethods }, { "java/lang/ScopedValue$Carrier", ScopedValueMethods }, + { "jdk/internal/value/ValueClass", ValueClassMethods }, { 0 } }; @@ -7765,6 +7773,12 @@ TR_OpaqueClassBlock * TR_J9MethodParameterIterator::getOpaqueClass() TR_J9VMBase *fej9 = (TR_J9VMBase *)(_comp.fe()); TR_ASSERT(*_sig == '[' || *_sig == 'L', "Asked for class of incorrect Java parameter."); if (_nextIncrBy == 0) getDataType(); + + // We can't trust the array class returned by signature if flattenable array is enabled. + // Both regular nullable array and null-restricted array have the same signature. + if (*_sig == '[' && TR::Compiler->om.areFlattenableValueTypesEnabled()) + return NULL; + return _resolvedMethod == NULL ? NULL : fej9->getClassFromSignature(_sig, _nextIncrBy, _resolvedMethod); } diff --git a/runtime/compiler/optimizer/J9ValuePropagation.cpp b/runtime/compiler/optimizer/J9ValuePropagation.cpp index 7e8e829a31a..8e114f39dcf 100644 --- a/runtime/compiler/optimizer/J9ValuePropagation.cpp +++ b/runtime/compiler/optimizer/J9ValuePropagation.cpp @@ -973,7 +973,7 @@ J9::ValuePropagation::constrainRecognizedMethod(TR::Node *node) TR::Node *indexNode = node->getChild(elementIndexOpIndex); TR::Node *arrayRefNode = node->getChild(arrayRefOpIndex); TR::VPConstraint *arrayConstraint = getConstraint(arrayRefNode, arrayRefGlobal); - TR_YesNoMaybe isCompTypePrimVT = isArrayCompTypePrimitiveValueType(arrayConstraint); + TR_YesNoMaybe isNullRestrictedArray = isArrayNullRestricted(arrayConstraint); TR::Node *storeValueNode = NULL; TR::VPConstraint *storeValueConstraint = NULL; @@ -1053,21 +1053,21 @@ J9::ValuePropagation::constrainRecognizedMethod(TR::Node *node) } // Transform the helper call to regular aaload and aastore if array flattening is not enabled, - // or the array is known to be of a primitive value type that is not flattened. + // or the array is known to be of a null-restricted array that is not flattened. bool canTransformUnflattenedArrayElementLoadStore = TR::Compiler->om.isValueTypeArrayFlatteningEnabled() ? false : true; if (!canTransformUnflattenedArrayElementLoadStore && arrayConstraint && - (isCompTypePrimVT == TR_yes) && + (isNullRestrictedArray == TR_yes) && !TR::Compiler->cls.isValueTypeClassFlattened(arrayConstraint->getClass())) { canTransformUnflattenedArrayElementLoadStore = true; } - // If the array is known to have a component type that is not a primitive value type or + // If the array is not a null-restricted array or // the value being stored is known not to be a value type, transform the helper // call to a regular aaload or aastore bool canTransformIdentityArrayElementLoadStore = false; - if ((arrayConstraint != NULL && isCompTypePrimVT == TR_no) + if ((arrayConstraint != NULL && isNullRestrictedArray == TR_no) || (isStoreFlattenableArrayElement && isStoreValueVT == TR_no)) { canTransformIdentityArrayElementLoadStore = true; @@ -1076,7 +1076,9 @@ J9::ValuePropagation::constrainRecognizedMethod(TR::Node *node) bool canTransformFlattenedArrayElementLoadStoreUseTypeHint = false; bool canTransformUnflattenedArrayElementLoadStoreUseTypeHint = false; bool canTransformIdentityArrayElementLoadStoreUseTypeHint = false; - static const char *disableFlattenedArrayElementTypeHintXForm = feGetEnv("TR_DisableFlattenedArrayElementTypeHintXForm"); + // Disable transformation based on type hint which is no longer sufficient enough + // to decide whether the array is null-restricted or not + static const char *enableFlattenedArrayElementTypeHintXForm = feGetEnv("TR_EnableFlattenedArrayElementTypeHintXForm"); static const char *enableUnflattenedArrayElementTypeHintXForm = feGetEnv("TR_EnableUnflattenedArrayElementTypeHintXForm"); TR_OpaqueClassBlock *typeHintClass = arrayConstraint ? arrayConstraint->getTypeHintClass() : NULL; @@ -1098,7 +1100,7 @@ J9::ValuePropagation::constrainRecognizedMethod(TR::Node *node) { if (TR::Compiler->cls.isValueTypeClassFlattened(hintComponentClass)) { - if (!disableFlattenedArrayElementTypeHintXForm) + if (enableFlattenedArrayElementTypeHintXForm) { if (isLoadFlattenableArrayElement) { @@ -1260,8 +1262,8 @@ J9::ValuePropagation::constrainRecognizedMethod(TR::Node *node) // if (storeValueBaseNode == NULL || getValueNumber(storeValueBaseNode) != getValueNumber(arrayRefNode)) { - // If storing to an array whose component type is or might be a primitive value - // type and the value that's being assigned is or might be null, both a run-time + // If storing to an array that is or might be null-restricted + // and the value that's being assigned is or might be null, both a run-time // NULLCHK of the value is required (guarded by a check of whether the // component type is a value type) and an ArrayStoreCHK are required; // otherwise, only the ArrayStoreCHK is required. @@ -1276,7 +1278,7 @@ J9::ValuePropagation::constrainRecognizedMethod(TR::Node *node) // If the value being stored is NULL and the destination array component is null-restricted at runtime, // a NPE is expected to throw. Therefore, when the array component type is not known to be identity type // in compilation time, a NULLCHK on store value is required - if ((isCompTypePrimVT != TR_no) && + if ((isNullRestrictedArray != TR_no) && (storeValueConstraint == NULL || !storeValueConstraint->isNonNullObject()) && !owningMethodDoesNotContainNonNullableArrayNullStoreCheck(this, node)) { @@ -1317,8 +1319,8 @@ J9::ValuePropagation::constrainRecognizedMethod(TR::Node *node) // if (storeValueBaseNode == NULL || getValueNumber(storeValueBaseNode) != getValueNumber(arrayRefNode)) { - // If storing to an array whose component type is or might be a primitive value - // type and the value that's being assigned is or might be null, both a run-time + // If storing to an array that is or might be null restricted + // and the value that's being assigned is or might be null, both a run-time // NULLCHK of the value is required (guarded by a check of whether the // component type is a value type) and an ArrayStoreCHK are required; // otherwise, only the ArrayStoreCHK is required. @@ -1385,11 +1387,11 @@ J9::ValuePropagation::constrainRecognizedMethod(TR::Node *node) { reason = "no-array-constraint"; } - else if (isCompTypePrimVT == TR_yes) + else if (isNullRestrictedArray == TR_yes) { reason = "comp-type-is-vt"; } - else if (isCompTypePrimVT == TR_maybe) + else if (isNullRestrictedArray == TR_maybe) { reason = "comp-type-may-be-vt"; } @@ -2949,9 +2951,9 @@ J9::ValuePropagation::isArrayElementFlattened(TR::VPConstraint *arrayConstraint) return TR_no; } - TR_YesNoMaybe isCompTypePrimVT = isArrayCompTypePrimitiveValueType(arrayConstraint); + TR_YesNoMaybe isNullRestrictedArray = isArrayNullRestricted(arrayConstraint); - if (isCompTypePrimVT == TR_yes) + if (isNullRestrictedArray == TR_yes) { TR_OpaqueClassBlock *arrayClass = arrayConstraint->getClass(); if (TR::Compiler->cls.isValueTypeClassFlattened(arrayClass)) @@ -2965,73 +2967,71 @@ J9::ValuePropagation::isArrayElementFlattened(TR::VPConstraint *arrayConstraint) } // Return TR_maybe or TR_no - return isCompTypePrimVT; + return isNullRestrictedArray; } TR_YesNoMaybe -J9::ValuePropagation::isArrayCompTypePrimitiveValueType(TR::VPConstraint *arrayConstraint) +J9::ValuePropagation::isArrayNullRestricted(TR::VPConstraint *arrayConstraint) { if (!TR::Compiler->om.areValueTypesEnabled() || - !TR::Compiler->om.areFlattenableValueTypesEnabled()) // Only null-restricted or primitive value type are flattenable + !TR::Compiler->om.areFlattenableValueTypesEnabled()) // Only null-restricted arrays are flattenable { return TR_no; } // If there's no constraint for the array operand, or no information // is available about the class of the array, or the operand is not - // even definitely known to be an array, VP has to assume that it might - // have a component type that is a primitive value type + // even definitely known to be an array, VP has to assume that the array + // might be null-restricted // if (!(arrayConstraint && arrayConstraint->getClass() && arrayConstraint->getClassType()->isArray() == TR_yes)) { + if (trace()) + traceMsg(comp(), "%s: return TR_maybe. arrayConstraint %p\n", __FUNCTION__, arrayConstraint); return TR_maybe; } - TR_OpaqueClassBlock *arrayComponentClass = fe()->getComponentClassFromArrayClass(arrayConstraint->getClass()); - - // Cases to consider: - // - // - Is no information available about the component type of the array? - // If not, assume it might be a primitive value type. - // - Is the component type definitely a identity type? - // - Is the component type definitely a primitive value type? - // - Is the component type definitely a value type, but not primitive? - // - Is the component type either an abstract class or an interface - // (i.e., not a concrete class)? If so, it might be a value type. - // - Is the array an array of java/lang/Object? See below. - // - Otherwise, it must be a concrete class known not to be a value - // type - // - if (!arrayComponentClass) - { - return TR_maybe; - } - - // No need to check array class type because array classes should be marked as having identity. - if (TR::Compiler->cls.classHasIdentity(arrayComponentClass)) - { - return TR_no; - } + TR_OpaqueClassBlock *arrayClass = arrayConstraint->getClass(); - if (TR::Compiler->cls.isPrimitiveValueTypeClass(arrayComponentClass)) + if (TR::Compiler->cls.isArrayNullRestricted(comp(), arrayClass)) { + if (trace()) + traceMsg(comp(), "%s: return TR_yes. arrayClass %p\n", __FUNCTION__, arrayClass); return TR_yes; } - if (TR::Compiler->cls.isValueTypeClass(arrayComponentClass)) + TR_OpaqueClassBlock *arrayComponentClass = fe()->getComponentClassFromArrayClass(arrayConstraint->getClass()); + + if (!arrayComponentClass) { - return TR_no; + if (trace()) + traceMsg(comp(), "%s: return TR_maybe. arrayComponentClass NULL\n", __FUNCTION__); + return TR_maybe; } if (!TR::Compiler->cls.isConcreteClass(comp(), arrayComponentClass)) { - return TR_maybe; + // Interface shouldn't have identity flag set and it can be implemented by both + // value class and identity class. + // If abstract class has identity flag set, it cannot be extended by value class. + if (TR::Compiler->cls.classHasIdentity(arrayComponentClass)) + { + if (trace()) + traceMsg(comp(), "%s: return TR_no. abstract classHasIdentity\n", __FUNCTION__); + return TR_no; + } + else + { + if (trace()) + traceMsg(comp(), "%s: return TR_maybe. Not concrete class\n", __FUNCTION__); + return TR_maybe; + } } int32_t len; const char *sig = arrayConstraint->getClassSignature(len); - + TR_YesNoMaybe ret; // If the array is an array of java/lang/Object, and it is fixed to // that type, the component type is not a value type (though it // can still hold references to instances of value types). If it is @@ -3041,14 +3041,20 @@ J9::ValuePropagation::isArrayCompTypePrimitiveValueType(TR::VPConstraint *arrayC if (sig && sig[0] == '[' && len == 19 && !strncmp(sig, "[Ljava/lang/Object;", 19)) { - return (arrayConstraint->isFixedClass()) ? TR_no : TR_maybe; + ret = (arrayConstraint->isFixedClass()) ? TR_no : TR_maybe; + if (trace()) + traceMsg(comp(), "%s: return %s. java.lang.Object\n", __FUNCTION__, (ret == TR_no) ? "TR_no" : "TR_maybe"); + return ret; } // If we get to this point, we know this is not an array of // java/lang/Object, and we know the component must be a concrete - // class that is not a value type. + // class. // - return TR_no; + ret = TR::Compiler->cls.classHasIdentity(arrayComponentClass) ? TR_no : TR_maybe; + if (trace()) + traceMsg(comp(), "%s: return %s. Concrete class\n", __FUNCTION__, (ret == TR_no) ? "TR_no" : "TR_maybe"); + return ret; } void @@ -4121,8 +4127,47 @@ J9::ValuePropagation::innerConstrainAcall(TR::Node *node) addGlobalConstraint(node, TR::VPNonNullObject::create(this)); } } + else if ((method->getRecognizedMethod() == TR::jdk_internal_value_ValueClass_newArrayInstance) && + (node->getFirstChild()->getOpCodeValue() == TR::acall)) + { + /* + * n12n acall jdk/internal/value/ValueClass.newArrayInstance(Ljdk/internal/value/CheckedType;I)[Ljava/lang/Object; + * n9n acall jdk/internal/value/NullRestrictedCheckedType.of(Ljava/lang/Class;)Ljdk/internal/value/NullRestrictedCheckedType; + * n8n aloadi + * n7n loadaddr SomeValueClass + * n11n iload Test.ARRAY_SIZE + */ + bool isGlobal; + constraint = getConstraint(node->getFirstChild(), isGlobal); + TR_ResolvedMethod *owningMethod = symRef->getOwningMethod(comp()); + TR_OpaqueClassBlock *nullRestrictedCheckedTypeClass = fe()->getClassFromSignature("jdk/internal/value/NullRestrictedCheckedType", 44, owningMethod); + + if (constraint && + constraint->isFixedClass() && + nullRestrictedCheckedTypeClass && + (comp()->fej9()->isInstanceOf(constraint->getClass(), nullRestrictedCheckedTypeClass, true, true) == TR_yes)) + { + if (trace()) + traceMsg(comp(), "%s: node n%dn fixed class %p is an instance of nullRestrictedCheckedTypeClass\n", __FUNCTION__, node->getGlobalIndex(), constraint->getClass()); + + constraint = getConstraint(node->getFirstChild()->getFirstChild(), isGlobal); + TR_OpaqueClassBlock *arrayComponentClass = (constraint && constraint->isFixedClass()) ? constraint->getClass() : NULL; + TR_OpaqueClassBlock *nullRestrictedArrayClass = arrayComponentClass ? fe()->getNullRestrictedArrayClassFromComponentClass(arrayComponentClass) : NULL; + + if (trace()) + traceMsg(comp(), "%s: node n%dn arrayComponentClass %p nullRestrictedArrayClass %p\n", __FUNCTION__, node->getGlobalIndex(), arrayComponentClass, nullRestrictedArrayClass); + + if (nullRestrictedArrayClass) + { + TR::VPConstraint *newConstraint = TR::VPFixedClass::create(this, nullRestrictedArrayClass); + addBlockOrGlobalConstraint(node, newConstraint, isGlobal); + addGlobalConstraint(node, TR::VPNonNullObject::create(this)); + return node; + } + } + } } - else + else // if (!node->getOpCode().isIndirect()) { if ((method->getRecognizedMethod() == TR::java_math_BigDecimal_add) || (method->getRecognizedMethod() == TR::java_math_BigDecimal_subtract) || diff --git a/runtime/compiler/optimizer/J9ValuePropagation.hpp b/runtime/compiler/optimizer/J9ValuePropagation.hpp index 467375cae51..3f11d45871a 100644 --- a/runtime/compiler/optimizer/J9ValuePropagation.hpp +++ b/runtime/compiler/optimizer/J9ValuePropagation.hpp @@ -76,14 +76,14 @@ class ValuePropagation : public OMR::ValuePropagation virtual TR_YesNoMaybe isValue(TR::VPConstraint *constraint, TR_OpaqueClassBlock *& clazz); /** - * Determine whether the component type of an array is, or might be, a primitive value - * type. + * Determine whether the array is, or might be, null-restricted + * * \param arrayConstraint The \ref TR::VPConstraint type constraint for the array reference - * \returns \c TR_yes if the array's component type is definitely a primitive value type;\n - * \c TR_no if it is definitely not a primitive value type; or\n + * \returns \c TR_yes if the array is definitely a null-restricted array;\n + * \c TR_no if it is definitely not a null-restricted array; or\n * \c TR_maybe otherwise. */ - virtual TR_YesNoMaybe isArrayCompTypePrimitiveValueType(TR::VPConstraint *arrayConstraint); + virtual TR_YesNoMaybe isArrayNullRestricted(TR::VPConstraint *arrayConstraint); /** * \brief diff --git a/test/functional/Valhalla/playlist.xml b/test/functional/Valhalla/playlist.xml index 3225144ba63..a5cc52815db 100644 --- a/test/functional/Valhalla/playlist.xml +++ b/test/functional/Valhalla/playlist.xml @@ -64,13 +64,12 @@ -Xjit:count=0 -Xjit:count=1,disableAsyncCompilation -Xgcpolicy:optthruput -Xjit:count=1,disableAsyncCompilation -Xgcpolicy:optthruput -XX:ValueTypeFlatteningThreshold=99999 -XX:-EnableArrayFlattening - - + -Xjit:count=1,disableAsyncCompilation -Xgcpolicy:optthruput -XX:ValueTypeFlatteningThreshold=99999 -XX:+EnableArrayFlattening -Xjit:count=1,disableAsyncCompilation -Xgcpolicy:gencon -XX:ValueTypeFlatteningThreshold=12 -XX:-EnableArrayFlattening -Xjit:count=1,disableAsyncCompilation -Xgcpolicy:gencon -XX:ValueTypeFlatteningThreshold=99999 -XX:-EnableArrayFlattening - - - + -Xjit:count=1,disableAsyncCompilation -Xgcpolicy:gencon -XX:ValueTypeFlatteningThreshold=99999 -XX:+EnableArrayFlattening + -Xjit:count=1,disableAsyncCompilation -Xnocompressedrefs -Xgcpolicy:optthruput -XX:ValueTypeFlatteningThreshold=99999 -XX:+EnableArrayFlattening + -Xjit:count=1,disableAsyncCompilation -Xnocompressedrefs -Xgcpolicy:gencon -XX:ValueTypeFlatteningThreshold=99999 -XX:+EnableArrayFlattening -Xjit:count=1,disableAsyncCompilation -Xnocompressedrefs -Xgcpolicy:gencon $(JAVA_COMMAND) $(JVM_OPTIONS) \ @@ -135,11 +134,6 @@ ValueTypeArrayTestsJIT - - - https://github.com/eclipse-openj9/openj9/issues/19913 - - -Xjit:count=0 -Xjit:count=1,disableAsyncCompilation -Xgcpolicy:optthruput @@ -339,8 +333,7 @@ -Xint -Xint -Xgcpolicy:optthruput -XX:ValueTypeFlatteningThreshold=99999 -Xint -Xgcpolicy:optthruput -XX:ValueTypeFlatteningThreshold=99999 -XX:+EnableArrayFlattening - - + -Xjit:count=1,disableAsyncCompilation -Xnocompressedrefs -Xgcpolicy:gencon - + -Xjit:count=1,disableAsyncCompilation,initialOptLevel=warm -Xnocompressedrefs -Xgcpolicy:gencon $(JAVA_COMMAND) $(JVM_OPTIONS) \ --enable-preview \