diff --git a/debugtools/DDR_VM/src/com/ibm/j9ddr/AuxFieldInfo29.dat b/debugtools/DDR_VM/src/com/ibm/j9ddr/AuxFieldInfo29.dat
index 1e15c4dd0e2..d5dc634fc65 100644
--- a/debugtools/DDR_VM/src/com/ibm/j9ddr/AuxFieldInfo29.dat
+++ b/debugtools/DDR_VM/src/com/ibm/j9ddr/AuxFieldInfo29.dat
@@ -71,6 +71,7 @@ J9AVLTreeNode.leftChild = required
J9AVLTreeNode.rightChild = required
J9AbstractThread.library = required
J9ArrayClass.arity = required
+J9ArrayClass.companionArray = J9Class*
J9ArrayClass.componentType = required
J9ArrayClass.flattenedElementSize = UDATA
J9ArrayClass.leafComponentType = required
diff --git a/debugtools/DDR_VM/src/com/ibm/j9ddr/vm29/j9/gc/GCClassArrayClassSlotIterator.java b/debugtools/DDR_VM/src/com/ibm/j9ddr/vm29/j9/gc/GCClassArrayClassSlotIterator.java
index 00d2f08da2b..95a7c3bb4bc 100644
--- a/debugtools/DDR_VM/src/com/ibm/j9ddr/vm29/j9/gc/GCClassArrayClassSlotIterator.java
+++ b/debugtools/DDR_VM/src/com/ibm/j9ddr/vm29/j9/gc/GCClassArrayClassSlotIterator.java
@@ -27,6 +27,7 @@
import com.ibm.j9ddr.CorruptDataException;
import com.ibm.j9ddr.vm29.pointer.VoidPointer;
import com.ibm.j9ddr.vm29.pointer.generated.J9ArrayClassPointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9BuildFlags;
import com.ibm.j9ddr.vm29.pointer.generated.J9ClassPointer;
import static com.ibm.j9ddr.vm29.structure.J9JavaAccessFlags.J9AccClassArray;
@@ -43,19 +44,30 @@ protected GCClassArrayClassSlotIterator(J9ClassPointer clazz) throws CorruptData
J9ClassPointer slot;
slot = clazz.arrayClass();
- if(slot.notNull()) {
+ if (slot.notNull()) {
slots.add(slot);
addresses.add(VoidPointer.cast(clazz.arrayClassEA()));
}
- if(clazz.romClass().modifiers().allBitsIn(J9AccClassArray)) {
+ if (clazz.romClass().modifiers().allBitsIn(J9AccClassArray)) {
J9ArrayClassPointer arrayClass = J9ArrayClassPointer.cast(clazz);
+ if (J9BuildFlags.J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) {
+ try {
+ slot = arrayClass.companionArray();
+ if (slot.notNull()) {
+ slots.add(slot);
+ addresses.add(VoidPointer.cast(arrayClass.companionArrayEA()));
+ }
+ } catch (NoSuchFieldException e) {
+ throw new CorruptDataException("J9ArrayClass.companionArray field does not exist", e);
+ }
+ }
slot = arrayClass.componentType();
- if(slot.notNull()) {
+ if (slot.notNull()) {
slots.add(slot);
addresses.add(VoidPointer.cast(arrayClass.componentTypeEA()));
}
slot = arrayClass.leafComponentType();
- if(slot.notNull()) {
+ if (slot.notNull()) {
slots.add(slot);
addresses.add(VoidPointer.cast(arrayClass.leafComponentTypeEA()));
}
diff --git a/runtime/codert_vm/cnathelp.cpp b/runtime/codert_vm/cnathelp.cpp
index 1594d1b9e80..fde7a7f0dee 100644
--- a/runtime/codert_vm/cnathelp.cpp
+++ b/runtime/codert_vm/cnathelp.cpp
@@ -1001,7 +1001,7 @@ old_fast_jitLoadFlattenableArrayElement(J9VMThread *currentThread)
value = (j9object_t) currentThread->javaVM->internalVMFunctions->loadFlattenableArrayElement(currentThread, arrayObject, index, true);
if (NULL == value) {
J9ArrayClass *arrayObjectClass = (J9ArrayClass *)J9OBJECT_CLAZZ(currentThread, arrayObject);
- if (J9_IS_J9CLASS_PRIMITIVE_VALUETYPE(arrayObjectClass->componentType)) {
+ if (J9_IS_J9ARRAYCLASS_NULL_RESTRICTED(arrayObjectClass)) {
goto slow;
}
}
@@ -1067,10 +1067,6 @@ old_fast_jitStoreFlattenableArrayElement(J9VMThread *currentThread)
if (false == VM_VMHelpers::objectArrayStoreAllowed(currentThread, arrayref, value)) {
goto slow;
}
- arrayrefClass = (J9ArrayClass *) J9OBJECT_CLAZZ(currentThread, arrayref);
- if ((J9_IS_J9CLASS_PRIMITIVE_VALUETYPE(arrayrefClass->componentType)) && (NULL == value)) {
- goto slow;
- }
currentThread->javaVM->internalVMFunctions->storeFlattenableArrayElement(currentThread, arrayref, index, value);
done:
return slowPath;
@@ -1474,11 +1470,10 @@ old_fast_jitCheckCast(J9VMThread *currentThread)
slowPath = (void*)old_slow_jitCheckCast;
}
}
-#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
- else if (J9_IS_J9CLASS_PRIMITIVE_VALUETYPE(castClass)) {
- slowPath = (void*)old_slow_jitThrowNullPointerException;
- }
-#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
+ /* In the future, Valhalla checkcast must throw an exception on
+ * null-restricted checkedType if object is null.
+ * See issue https://github.com/eclipse-openj9/openj9/issues/19764.
+ */
return slowPath;
}
@@ -3610,11 +3605,10 @@ fast_jitCheckCast(J9VMThread *currentThread, J9Class *castClass, j9object_t obje
slowPath = (void*)old_slow_jitCheckCast;
}
}
-#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
- else if (J9_IS_J9CLASS_PRIMITIVE_VALUETYPE(castClass)) {
- slowPath = (void*)old_slow_jitThrowNullPointerException;
- }
-#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
+ /* In the future, Valhalla checkcast must throw an exception on
+ * null-restricted checkedType if object is null.
+ * See issue https://github.com/eclipse-openj9/openj9/issues/19764.
+ */
return slowPath;
}
diff --git a/runtime/gc_structs/ClassArrayClassSlotIterator.cpp b/runtime/gc_structs/ClassArrayClassSlotIterator.cpp
index 219e70a7a40..6f91adda39b 100644
--- a/runtime/gc_structs/ClassArrayClassSlotIterator.cpp
+++ b/runtime/gc_structs/ClassArrayClassSlotIterator.cpp
@@ -50,6 +50,12 @@ GC_ClassArrayClassSlotIterator::nextSlot()
_state += 1;
}
break;
+#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
+ case classArrayClassSlotIterator_state_companionArray:
+ classPtr = ((J9ArrayClass *)_iterateClazz)->companionArray;
+ _state += 1;
+ break;
+#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
case classArrayClassSlotIterator_state_componentType:
classPtr = ((J9ArrayClass *)_iterateClazz)->componentType;
_state += 1;
diff --git a/runtime/gc_structs/ClassArrayClassSlotIterator.hpp b/runtime/gc_structs/ClassArrayClassSlotIterator.hpp
index f40434acb60..83f519c76cb 100644
--- a/runtime/gc_structs/ClassArrayClassSlotIterator.hpp
+++ b/runtime/gc_structs/ClassArrayClassSlotIterator.hpp
@@ -46,6 +46,9 @@ class GC_ClassArrayClassSlotIterator
enum {
classArrayClassSlotIterator_state_arrayClass = 0,
+#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
+ classArrayClassSlotIterator_state_companionArray,
+#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
classArrayClassSlotIterator_state_componentType,
classArrayClassSlotIterator_state_leafComponentType,
classArrayClassSlotIterator_state_done
diff --git a/runtime/gc_structs/ClassLoaderClassesIterator.cpp b/runtime/gc_structs/ClassLoaderClassesIterator.cpp
index e22d9028d5b..fc08f677f7e 100644
--- a/runtime/gc_structs/ClassLoaderClassesIterator.cpp
+++ b/runtime/gc_structs/ClassLoaderClassesIterator.cpp
@@ -36,12 +36,15 @@ GC_ClassLoaderClassesIterator::GC_ClassLoaderClassesIterator(MM_GCExtensionsBase
,_vmSegmentIterator(classLoader, MEMORY_TYPE_RAM_CLASS)
,_vmClassSlotIterator((J9JavaVM* )extensions->getOmrVM()->_language_vm)
,_mode(TABLE_CLASSES)
+ ,_iterateArrayClazz(NULL)
+ ,_arrayState(STATE_VALUETYPEARRAY)
{
if ((classLoader->flags & J9CLASSLOADER_ANON_CLASS_LOADER) != 0) {
_mode = ANONYMOUS_CLASSES;
}
_nextClass = firstClass();
+ _startingClass = _nextClass;
}
J9Class *
@@ -99,6 +102,58 @@ GC_ClassLoaderClassesIterator::switchToSystemMode()
return isSystemClassLoader;
}
+J9Class *
+GC_ClassLoaderClassesIterator::nextArrayClass()
+{
+ while (_arrayState != STATE_DONE) {
+ switch (_arrayState) {
+ case STATE_VALUETYPEARRAY:
+ {
+#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
+ J9Class *nullRestrictedArray = J9CLASS_GET_NULLRESTRICTED_ARRAY(_startingClass);
+ if (NULL != nullRestrictedArray) {
+ _iterateArrayClazz = nullRestrictedArray;
+ _arrayState = STATE_VALUETYPEARRAYLIST;
+ } else
+#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
+ {
+ _arrayState = STATE_ARRAY;
+ }
+ }
+ break;
+ case STATE_VALUETYPEARRAYLIST:
+ if (NULL != _iterateArrayClazz) {
+ _iterateArrayClazz = _iterateArrayClazz->arrayClass;
+ } else {
+ _arrayState = STATE_ARRAY;
+ }
+ break;
+ case STATE_ARRAY:
+ if (NULL != _startingClass->arrayClass) {
+ _iterateArrayClazz = _startingClass->arrayClass;
+ _arrayState = STATE_ARRAYLIST;
+ } else {
+ _arrayState = STATE_DONE;
+ }
+ break;
+ case STATE_ARRAYLIST:
+ if (NULL != _iterateArrayClazz) {
+ _iterateArrayClazz = _iterateArrayClazz->arrayClass;
+ } else {
+ _arrayState = STATE_DONE;
+ }
+ break;
+ case STATE_DONE:
+ default:
+ break;
+ }
+ if (NULL != _iterateArrayClazz) {
+ break;
+ }
+ }
+ return _iterateArrayClazz;
+}
+
J9Class *
GC_ClassLoaderClassesIterator::nextClass()
{
@@ -108,13 +163,18 @@ GC_ClassLoaderClassesIterator::nextClass()
if (ANONYMOUS_CLASSES == _mode) {
_nextClass = nextAnonymousClass();
} else {
- if ( (result->classLoader == _classLoader) && (NULL != result->arrayClass) ) {
+ J9Class *array = nextArrayClass();
+ if ((result->classLoader == _classLoader) && (NULL != array)) {
/* this class is defined in the loader, so follow its array classes */
- _nextClass = result->arrayClass;
+ _nextClass = array;
} else if (TABLE_CLASSES == _mode) {
_nextClass = nextTableClass();
+ _startingClass = _nextClass;
+ _arrayState = STATE_VALUETYPEARRAY;
} else {
_nextClass = nextSystemClass();
+ _startingClass = _nextClass;
+ _arrayState = STATE_VALUETYPEARRAY;
}
}
}
diff --git a/runtime/gc_structs/ClassLoaderClassesIterator.hpp b/runtime/gc_structs/ClassLoaderClassesIterator.hpp
index f2e925a1e3f..111aa0fbde2 100644
--- a/runtime/gc_structs/ClassLoaderClassesIterator.hpp
+++ b/runtime/gc_structs/ClassLoaderClassesIterator.hpp
@@ -62,6 +62,16 @@ class GC_ClassLoaderClassesIterator
ANONYMOUS_CLASSES
};
ScanModes _mode; /**< indicate type of classes to be iterated */
+ J9Class *_iterateArrayClazz; /**< current array walk class */
+ J9Class *_startingClass; /**< the most recent table or system class which is the starting point for each array walk */
+ enum ArrayClassState {
+ STATE_VALUETYPEARRAY = 0, /**< setup value type array list walk */
+ STATE_VALUETYPEARRAYLIST, /**< value type array list walk */
+ STATE_ARRAY, /**< setup array list walk */
+ STATE_ARRAYLIST, /**< array list walk */
+ STATE_DONE
+ };
+ ArrayClassState _arrayState; /**< array walk state */
protected:
public:
@@ -99,6 +109,16 @@ class GC_ClassLoaderClassesIterator
* @return true if this is the system class loader, false otherwise
*/
bool switchToSystemMode();
+
+ /**
+ * Iterate through all array classes of _nextClass. A base class may have
+ * a list of array classes starting at the J9Class fields nullRestrictedArrayClass
+ * and arrayClass. nullRestrictedArrayClass can only exist as a field of a value class
+ * and can only be an array of arity 1.
+ * After that its list will continue in the arrayClass field.
+ * @return the next array class, or NULL if finished
+ */
+ J9Class *nextArrayClass();
protected:
diff --git a/runtime/j9vm/javanextvmi.cpp b/runtime/j9vm/javanextvmi.cpp
index 6308573ea75..75bda5efb7c 100644
--- a/runtime/j9vm/javanextvmi.cpp
+++ b/runtime/j9vm/javanextvmi.cpp
@@ -764,15 +764,67 @@ JVM_IsImplicitlyConstructibleClass(JNIEnv *env, jclass cls)
JNIEXPORT jboolean JNICALL
JVM_IsNullRestrictedArray(JNIEnv *env, jobject obj)
{
- // TODO implement this with https://github.com/eclipse-openj9/openj9/issues/19460
- return JNI_FALSE;
+ jboolean result = JNI_FALSE;
+ J9VMThread *currentThread = (J9VMThread *)env;
+ J9InternalVMFunctions *vmFuncs = currentThread->javaVM->internalVMFunctions;
+ vmFuncs->internalEnterVMFromJNI(currentThread);
+ if (NULL == obj) {
+ vmFuncs->setCurrentException(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL);
+ } else {
+ J9Class *j9clazz = J9OBJECT_CLAZZ(currentThread, J9_JNI_UNWRAP_REFERENCE(obj));
+ if (J9_IS_J9ARRAYCLASS_NULL_RESTRICTED(j9clazz)) {
+ result = JNI_TRUE;
+ }
+ }
+ vmFuncs->internalExitVMToJNI(currentThread);
+ return result;
}
JNIEXPORT jarray JNICALL
-JVM_NewNullRestrictedArray(JNIEnv *env, jclass cls, jint length)
+JVM_NewNullRestrictedArray(JNIEnv *env, jclass componentType, jint length)
{
- assert(!"JVM_NewNullRestrictedArray unimplemented");
- return NULL;
+ J9VMThread *currentThread = (J9VMThread *)env;
+ J9JavaVM *vm = currentThread->javaVM;
+ J9InternalVMFunctions *vmFuncs = currentThread->javaVM->internalVMFunctions;
+ J9Class *ramClass = NULL;
+ j9object_t newArray = NULL;
+ jarray arrayRef = NULL;
+
+ vmFuncs->internalEnterVMFromJNI(currentThread);
+ ramClass = J9VMJAVALANGCLASS_VMREF(currentThread, J9_JNI_UNWRAP_REFERENCE(componentType));
+
+ if (length < 0) {
+ vmFuncs->setCurrentException(currentThread, J9VMCONSTANTPOOL_JAVALANGNEGATIVEARRAYSIZEEXCEPTION, NULL);
+ goto done;
+ }
+
+ if (!(J9_IS_J9CLASS_VALUETYPE(ramClass) && J9_IS_J9CLASS_ALLOW_DEFAULT_VALUE(ramClass))) {
+ vmFuncs->setCurrentException(currentThread, J9VMCONSTANTPOOL_JAVALANGILLEGALARGUMENTEXCEPTION, NULL);
+ goto done;
+ }
+
+ if (NULL == J9CLASS_GET_NULLRESTRICTED_ARRAY(ramClass)) {
+ J9ROMArrayClass *arrayOfObjectsROMClass = (J9ROMArrayClass *)J9ROMIMAGEHEADER_FIRSTCLASS(vm->arrayROMClasses);
+ vmFuncs->internalCreateArrayClassWithOptions(
+ currentThread, arrayOfObjectsROMClass, ramClass, J9_FINDCLASS_FLAG_CLASS_OPTION_NULL_RESTRICTED_ARRAY);
+ if (NULL != currentThread->currentException) {
+ goto done;
+ }
+ ramClass = VM_VMHelpers::currentClass(ramClass);
+ }
+
+ newArray = vm->memoryManagerFunctions->J9AllocateIndexableObject(
+ currentThread, J9CLASS_GET_NULLRESTRICTED_ARRAY(ramClass), length, J9_GC_ALLOCATE_OBJECT_NON_INSTRUMENTABLE);
+
+ if (NULL == newArray) {
+ vmFuncs->setHeapOutOfMemoryError(currentThread);
+ goto done;
+ }
+
+ arrayRef = (jarray)vmFuncs->j9jni_createLocalRef(env, newArray);
+done:
+ vmFuncs->internalExitVMToJNI(currentThread);
+ return arrayRef;
}
#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */
diff --git a/runtime/oti/VMHelpers.hpp b/runtime/oti/VMHelpers.hpp
index c630b49c834..6f6d368e99c 100644
--- a/runtime/oti/VMHelpers.hpp
+++ b/runtime/oti/VMHelpers.hpp
@@ -1786,9 +1786,10 @@ class VM_VMHelpers
objectArrayStoreAllowed(J9VMThread const *currentThread, j9object_t array, j9object_t storeValue)
{
bool rc = true;
+ J9ArrayClass *arrayClass = (J9ArrayClass *)J9OBJECT_CLAZZ(currentThread, array);
if (NULL != storeValue) {
J9Class *valueClass = J9OBJECT_CLAZZ(currentThread, storeValue);
- J9Class *componentType = ((J9ArrayClass*)J9OBJECT_CLAZZ(currentThread, array))->componentType;
+ J9Class *componentType = arrayClass->componentType;
/* quick check -- is this a store of a C into a C[]? */
if (valueClass != componentType) {
/* quick check -- is this a store of a C into a java.lang.Object[]? */
@@ -1796,6 +1797,10 @@ class VM_VMHelpers
rc = inlineCheckCast(valueClass, componentType);
}
}
+#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
+ } else if (J9_IS_J9ARRAYCLASS_NULL_RESTRICTED(arrayClass)) {
+ rc = FALSE;
+#endif /* if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
}
return rc;
}
diff --git a/runtime/oti/j9.h b/runtime/oti/j9.h
index c250f3cb880..1df71221bd0 100644
--- a/runtime/oti/j9.h
+++ b/runtime/oti/j9.h
@@ -331,7 +331,7 @@ static const struct { \
#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
#define J9CLASS_UNPADDED_INSTANCE_SIZE(clazz) J9_VALUETYPE_FLATTENED_SIZE(clazz)
-/* TODO replace with J9_IS_J9CLASS_ALLOW_DEFAULT_VALUE(clazz) J9_ARE_ALL_BITS_SET((clazz)->classFlags, J9ClassAllowsInitialDefaultValue)*/
+#define J9_IS_J9CLASS_ALLOW_DEFAULT_VALUE(clazz) J9_ARE_ALL_BITS_SET((clazz)->classFlags, J9ClassAllowsInitialDefaultValue)
#define J9_IS_J9CLASS_PRIMITIVE_VALUETYPE(clazz) J9_ARE_ALL_BITS_SET((clazz)->classFlags, J9ClassIsPrimitiveValueType)
#define J9_IS_J9CLASS_FLATTENED(clazz) J9_ARE_ALL_BITS_SET((clazz)->classFlags, J9ClassIsFlattened)
@@ -348,14 +348,18 @@ static const struct { \
J9_IS_J9CLASS_FLATTENED(fieldClazz) && \
(J9_ARE_NO_BITS_SET((romFieldShape)->modifiers, J9AccVolatile) || (J9CLASS_UNPADDED_INSTANCE_SIZE(fieldClazz) <= sizeof(U_64))))
#define J9_VALUETYPE_FLATTENED_SIZE(clazz) (J9CLASS_HAS_4BYTE_PREPADDING((clazz)) ? ((clazz)->totalInstanceSize - sizeof(U_32)) : (clazz)->totalInstanceSize)
+#define J9_IS_J9ARRAYCLASS_NULL_RESTRICTED(clazz) J9_ARE_ALL_BITS_SET((clazz)->classFlags, J9ClassArrayIsNullRestricted)
+#define J9CLASS_GET_NULLRESTRICTED_ARRAY(clazz) (J9_IS_J9CLASS_VALUETYPE(clazz) ? (clazz)->nullRestrictedArrayClass : NULL)
#else /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
#define J9CLASS_UNPADDED_INSTANCE_SIZE(clazz) ((clazz)->totalInstanceSize)
+#define J9_IS_J9CLASS_ALLOW_DEFAULT_VALUE(clazz) FALSE
#define J9_IS_J9CLASS_PRIMITIVE_VALUETYPE(clazz) FALSE
#define J9_IS_J9CLASS_FLATTENED(clazz) FALSE
#define J9ROMFIELD_IS_NULL_RESTRICTED(romField) FALSE
#define J9_IS_FIELD_FLATTENED(fieldClazz, romFieldShape) FALSE
#define J9_IS_NULL_RESTRICTED_FIELD_FLATTENED(fieldClazz, romFieldShape) FALSE
#define J9_VALUETYPE_FLATTENED_SIZE(clazz)((UDATA) 0) /* It is not possible for this macro to be used since we always check J9_IS_J9CLASS_FLATTENED before ever using it. */
+#define J9_IS_J9ARRAYCLASS_NULL_RESTRICTED(clazz) FALSE
#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
#define IS_REF_OR_VAL_SIGNATURE(firstChar) ('L' == (firstChar))
diff --git a/runtime/oti/j9consts.h b/runtime/oti/j9consts.h
index 52326ea1a95..17ae11ba9db 100644
--- a/runtime/oti/j9consts.h
+++ b/runtime/oti/j9consts.h
@@ -450,6 +450,7 @@ extern "C" {
#define J9_FINDCLASS_FLAG_DO_NOT_SHARE 0x100000
#define J9_FINDCLASS_FLAG_LAMBDA 0x200000
#define J9_FINDCLASS_FLAG_LAMBDAFORM 0x400000
+#define J9_FINDCLASS_FLAG_CLASS_OPTION_NULL_RESTRICTED_ARRAY 0x800000
#define J9_FINDKNOWNCLASS_FLAG_INITIALIZE 0x1
#define J9_FINDKNOWNCLASS_FLAG_EXISTING_ONLY 0x2
diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h
index b655b7b8df7..987b6740dbc 100644
--- a/runtime/oti/j9nonbuilder.h
+++ b/runtime/oti/j9nonbuilder.h
@@ -96,6 +96,7 @@
#define J9ClassAllowsInitialDefaultValue 0x400000
#define J9ClassAllowsNonAtomicCreation 0x800000
#define J9ClassNeedToPruneMemberNames 0x1000000
+#define J9ClassArrayIsNullRestricted 0x2000000
/* @ddr_namespace: map_to_type=J9FieldFlags */
@@ -3391,6 +3392,9 @@ typedef struct J9Class {
/* A linked list of weak global references to every resolved MemberName whose clazz is this class. */
J9MemberNameListNode *memberNames;
#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */
+#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
+ struct J9Class *nullRestrictedArrayClass;
+#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
} J9Class;
/* Interface classes can never be instantiated, so the following fields in J9Class will not be used:
@@ -3487,6 +3491,13 @@ typedef struct J9ArrayClass {
/* A linked list of weak global references to every resolved MemberName whose clazz is this class. */
J9MemberNameListNode *memberNames;
#endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */
+#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
+ /*
+ * A nullable J9ArrayClass points to its null-restricted companion, if one exists.
+ * A null-restricted J9ArrayClass points to its nullable companion, if one exists.
+ */
+ struct J9Class *companionArray;
+#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
} J9ArrayClass;
@@ -4800,6 +4811,7 @@ typedef struct J9InternalVMFunctions {
void (JNICALL *sendInit)(struct J9VMThread *vmContext, j9object_t object, struct J9Class *senderClass, UDATA lookupOptions) ;
void ( *internalAcquireVMAccessNoMutex)(struct J9VMThread * vmThread) ;
struct J9Class* ( *internalCreateArrayClass)(struct J9VMThread* vmThread, struct J9ROMArrayClass* romClass, struct J9Class* elementClass) ;
+ struct J9Class *(*internalCreateArrayClassWithOptions)(struct J9VMThread *vmThread, struct J9ROMArrayClass *romClass, struct J9Class *elementClass, UDATA options);
IDATA ( *attachSystemDaemonThread)(struct J9JavaVM * vm, struct J9VMThread ** p_env, const char * threadName) ;
void ( *internalAcquireVMAccessClearStatus)(struct J9VMThread * vmThread, UDATA flags) ;
#if defined(J9VM_OPT_REFLECT)
diff --git a/runtime/oti/vm_api.h b/runtime/oti/vm_api.h
index dfe6d80ff66..aa5513573a7 100644
--- a/runtime/oti/vm_api.h
+++ b/runtime/oti/vm_api.h
@@ -357,6 +357,19 @@ peekClassHashTable(J9VMThread* currentThread, J9ClassLoader* classLoader, U_8* c
J9Class*
internalCreateArrayClass(J9VMThread* vmThread, J9ROMArrayClass* romClass, J9Class* elementClass);
+/**
+ * @brief Create a new J9Class to represent an array of elementClass.
+ *
+ * @param vmThread current VM thread
+ * @param romClass the ROM class associated with new RAM class (for arrays
+ * this is always the object array ROM class "[L")
+ * @param elementClass element or base class or array to be created
+ * @param options creation options such as J9_FINDCLASS_FLAG_CLASS_OPTION_NULL_RESTRICTED_ARRAY
+ * @return J9Class* J9Class of an elementClass array
+ */
+J9Class *
+internalCreateArrayClassWithOptions(J9VMThread *vmThread, J9ROMArrayClass *romClass, J9Class *elementClass, UDATA options);
+
/**
* Load the class with the specified name in a given module
*
diff --git a/runtime/vm/BytecodeInterpreter.hpp b/runtime/vm/BytecodeInterpreter.hpp
index 45411a58905..d1b051aa534 100644
--- a/runtime/vm/BytecodeInterpreter.hpp
+++ b/runtime/vm/BytecodeInterpreter.hpp
@@ -6888,22 +6888,12 @@ class INTERPRETER_CLASS
if (false == VM_VMHelpers::objectArrayStoreAllowed(_currentThread, arrayref, value)) {
rc = THROW_ARRAY_STORE;
} else {
-#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
- J9ArrayClass *arrayrefClass = (J9ArrayClass *) J9OBJECT_CLAZZ(_currentThread, arrayref);
- if (J9_IS_J9CLASS_PRIMITIVE_VALUETYPE(arrayrefClass->componentType) && (NULL == value)) {
- rc = THROW_NPE;
- goto done;
- }
-#endif /* if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
VM_ValueTypeHelpers::storeFlattenableArrayElement(_currentThread, _objectAccessBarrier, arrayref, index, value);
_pc += 1;
_sp += 3;
}
}
}
-#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
-done:
-#endif /* if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
return rc;
}
diff --git a/runtime/vm/ValueTypeHelpers.hpp b/runtime/vm/ValueTypeHelpers.hpp
index 32490af20e6..4cb9f09c57f 100644
--- a/runtime/vm/ValueTypeHelpers.hpp
+++ b/runtime/vm/ValueTypeHelpers.hpp
@@ -512,7 +512,6 @@ class VM_ValueTypeHelpers {
I_32 srcEndIndex = srcIndex + lengthInSlots;
J9Class *srcClazz = J9OBJECT_CLAZZ(currentThread, srcObject);
J9Class *destClazz = J9OBJECT_CLAZZ(currentThread, destObject);
- J9Class *destComponentClass = ((J9ArrayClass *)destClazz)->componentType;
/* Array elements must be copied backwards if source and destination overlap in memory and source is before destination */
if ((srcObject == destObject) && (srcIndex < destIndex) && ((srcIndex + lengthInSlots) > destIndex)) {
@@ -566,10 +565,6 @@ class VM_ValueTypeHelpers {
}
if (typeChecksRequired) {
- if (J9_IS_J9CLASS_PRIMITIVE_VALUETYPE(destComponentClass) && (NULL == copyObject)) {
- /* Null objects cannot be stored in an array of primitive value types */
- return -2;
- }
if (!VM_VMHelpers::objectArrayStoreAllowed(currentThread, destObject, copyObject)) {
return -1;
}
diff --git a/runtime/vm/classsupport.c b/runtime/vm/classsupport.c
index 82ae71455d6..322e59f402c 100644
--- a/runtime/vm/classsupport.c
+++ b/runtime/vm/classsupport.c
@@ -194,24 +194,31 @@ findPrimitiveArrayClass(J9JavaVM* vm, jchar sigChar)
*
* Allocates and fills in the relevant fields of an array class
*/
-J9Class*
-internalCreateArrayClass(J9VMThread* vmThread, J9ROMArrayClass* romClass, J9Class* elementClass)
+J9Class *
+internalCreateArrayClass(J9VMThread *vmThread, J9ROMArrayClass *romClass, J9Class *elementClass)
+{
+ return internalCreateArrayClassWithOptions(vmThread, romClass, elementClass, 0);
+}
+
+J9Class *
+internalCreateArrayClassWithOptions(J9VMThread *vmThread, J9ROMArrayClass *romClass, J9Class *elementClass, UDATA options)
{
J9Class *result = NULL;
j9object_t heapClass = J9VM_J9CLASS_TO_HEAPCLASS(elementClass);
j9object_t protectionDomain = NULL;
- J9ROMClass* arrayRomClass = (J9ROMClass*) romClass;
+ J9ROMClass *arrayRomClass = (J9ROMClass *)romClass;
J9JavaVM *const javaVM = vmThread->javaVM;
- UDATA options = 0;
BOOLEAN elementInitSuccess = TRUE;
#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
- /* When creating an array of valuetype elements, the array elements are initialized to the defaultValue of the
- * element type. As a result the element type must be fully initialized (if its a valuetype) before creating an
- * instance of the array. Element class init must be done before the arrayClass is created so that in the case
- * of an init failure the arrayClass is not temporarily exposed.
+ /* When creating an array of implicitly constructible valuetype elements,
+ * the array elements are initialized to the defaultValue of the element
+ * type. As a result, the element type must be fully initialized before
+ * creating an instance of the array. Element class init must be done
+ * before the arrayClass is created so that in the case of an init failure
+ * the arrayClass is not temporarily exposed.
*/
- if (J9_IS_J9CLASS_PRIMITIVE_VALUETYPE(elementClass)) {
+ if (J9_IS_J9CLASS_ALLOW_DEFAULT_VALUE(elementClass)) {
UDATA initStatus = elementClass->initializeStatus;
if ((J9ClassInitSucceeded != initStatus) && ((UDATA)vmThread != initStatus)) {
initializeClass(vmThread, elementClass);
diff --git a/runtime/vm/createramclass.cpp b/runtime/vm/createramclass.cpp
index a72ea536024..9d4b0ec60a2 100644
--- a/runtime/vm/createramclass.cpp
+++ b/runtime/vm/createramclass.cpp
@@ -197,6 +197,19 @@ static void initializeClassLinks(J9Class *ramClass, J9Class *superclass, J9Memor
#define MAGIC_ACCESSOR_IMPL "jdk/internal/reflect/MagicAccessorImpl"
#endif /* JAVA_SPEC_VERSION == 8 */
+static VMINLINE J9Class *
+getArrayClass(J9Class *elementClass, UDATA options)
+{
+#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
+ if (J9_ARE_ALL_BITS_SET(options, J9_FINDCLASS_FLAG_CLASS_OPTION_NULL_RESTRICTED_ARRAY)) {
+ return elementClass->nullRestrictedArrayClass;
+ } else
+#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
+ {
+ return elementClass->arrayClass;
+ }
+}
+
/**
* Mark all of the interfaces supported by this class, including all interfaces
* inherited by superinterfaces. Unmark all interfaces which are inherited from
@@ -2175,7 +2188,7 @@ internalCreateRAMClassDone(J9VMThread *vmThread, J9ClassLoader *classLoader, J9C
if (elementClass == NULL) {
alreadyLoadedClass = hashClassTableAt(classLoader, J9UTF8_DATA(className), J9UTF8_LENGTH(className));
} else {
- alreadyLoadedClass = elementClass->arrayClass;
+ alreadyLoadedClass = getArrayClass(elementClass, options);
}
if (alreadyLoadedClass != NULL) {
/* We are discarding this class */
@@ -2374,7 +2387,7 @@ internalCreateRAMClassDone(J9VMThread *vmThread, J9ClassLoader *classLoader, J9C
if (elementClass == NULL) {
alreadyLoadedClass = hashClassTableAt(classLoader, J9UTF8_DATA(className), J9UTF8_LENGTH(className));
} else {
- alreadyLoadedClass = elementClass->arrayClass;
+ alreadyLoadedClass = getArrayClass(elementClass, options);
}
if (alreadyLoadedClass != NULL) {
goto alreadyLoaded;
@@ -2388,7 +2401,20 @@ internalCreateRAMClassDone(J9VMThread *vmThread, J9ClassLoader *classLoader, J9C
}
} else {
if (J9ROMCLASS_IS_ARRAY(romClass)) {
- ((J9ArrayClass *)elementClass)->arrayClass = state->ramClass;
+#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
+ if (J9_ARE_ALL_BITS_SET(options, J9_FINDCLASS_FLAG_CLASS_OPTION_NULL_RESTRICTED_ARRAY)) {
+ elementClass->nullRestrictedArrayClass = state->ramClass;
+ } else
+#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
+ {
+ ((J9ArrayClass *)elementClass)->arrayClass = state->ramClass;
+ }
+#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
+ if ((NULL != elementClass->nullRestrictedArrayClass) && (NULL != elementClass->arrayClass)) {
+ ((J9ArrayClass *)elementClass->arrayClass)->companionArray = elementClass->nullRestrictedArrayClass;
+ ((J9ArrayClass *)elementClass->nullRestrictedArrayClass)->companionArray = elementClass->arrayClass;
+ }
+#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
/* Assigning into the arrayClass field creates an implicit reference to the class from its class loader */
javaVM->memoryManagerFunctions->j9gc_objaccess_postStoreClassToClassLoader(vmThread, classLoader, state->ramClass);
}
@@ -2844,7 +2870,7 @@ internalCreateRAMClassFromROMClassImpl(J9VMThread *vmThread, J9ClassLoader *clas
if (elementClass == NULL) {
ramClass = hashClassTableAt(classLoader, J9UTF8_DATA(className), J9UTF8_LENGTH(className));
} else {
- ramClass = elementClass->arrayClass;
+ ramClass = getArrayClass(elementClass, options);
}
state->ramClass = ramClass;
@@ -3189,7 +3215,7 @@ internalCreateRAMClassFromROMClassImpl(J9VMThread *vmThread, J9ClassLoader *clas
* + J9ClassAllowsNonAtomicCreation
*
* + J9ClassNeedToPruneMemberNames
- * + Unused
+ * + J9ClassArrayIsNullRestricted
* + Unused
* + Unused
*
@@ -3419,14 +3445,7 @@ internalCreateRAMClassFromROMClassImpl(J9VMThread *vmThread, J9ClassLoader *clas
arity = elementArrayClass->arity + 1;
leafComponentType = elementArrayClass->leafComponentType;
} else {
- U_32 arrayFlags = J9ClassLargestAlignmentConstraintReference | J9ClassLargestAlignmentConstraintDouble;
-
- if (J9_ARE_ALL_BITS_SET(javaVM->extendedRuntimeFlags2, J9_EXTENDED_RUNTIME2_ENABLE_VT_ARRAY_FLATTENING)) {
- arrayFlags |= J9ClassIsFlattened;
- }
-
- arity = 1;
- leafComponentType = elementClass;
+#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
/* For arrays of valueType elements (where componentType is a valuetype), the arrays themselves are not
* valuetypes but they should inherit the layout characteristics (ie. flattenable, etc.)
* of the valuetype elements. A 2D (or more) array of valuetype elements (where leafComponentType is a Valuetype but
@@ -3434,7 +3453,20 @@ internalCreateRAMClassFromROMClassImpl(J9VMThread *vmThread, J9ClassLoader *clas
* properties from the leafComponentType. A 2D array is an array of references so it can never be flattened, however, its
* elements may be flattened arrays.
*/
+ U_32 arrayFlags = J9ClassLargestAlignmentConstraintReference | J9ClassLargestAlignmentConstraintDouble;
+ if (J9_ARE_ALL_BITS_SET(javaVM->extendedRuntimeFlags2, J9_EXTENDED_RUNTIME2_ENABLE_VT_ARRAY_FLATTENING)) {
+ /* TODO restrict this flag to be set only for null-restricted
+ * arrays once value type command line tests are updated.
+ */
+ arrayFlags |= J9ClassIsFlattened;
+ }
ramArrayClass->classFlags |= (elementClass->classFlags & arrayFlags);
+ if (J9_ARE_ALL_BITS_SET(options, J9_FINDCLASS_FLAG_CLASS_OPTION_NULL_RESTRICTED_ARRAY)) {
+ ramArrayClass->classFlags |= J9ClassArrayIsNullRestricted;
+ }
+#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
+ arity = 1;
+ leafComponentType = elementClass;
}
ramArrayClass->classFlags |= J9ClassHasIdentity;
ramArrayClass->leafComponentType = leafComponentType;
@@ -3458,7 +3490,7 @@ internalCreateRAMClassFromROMClassImpl(J9VMThread *vmThread, J9ClassLoader *clas
J9ARRAYCLASS_SET_STRIDE(ramClass, J9_VALUETYPE_FLATTENED_SIZE(elementClass));
}
} else {
- if (J9_IS_J9CLASS_PRIMITIVE_VALUETYPE(elementClass)) {
+ if (J9_IS_J9CLASS_ALLOW_DEFAULT_VALUE(elementClass)) {
ramArrayClass->classFlags |= J9ClassContainsUnflattenedFlattenables;
}
J9ARRAYCLASS_SET_STRIDE(ramClass, (((UDATA) 1) << (((J9ROMArrayClass*)romClass)->arrayShape & 0x0000FFFF)));
@@ -3651,7 +3683,7 @@ internalCreateRAMClassFromROMClass(J9VMThread *vmThread, J9ClassLoader *classLoa
#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
) {
#if defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES)
- if (flattenedClassCache != (J9FlattenedClassCache *) flattenedClassCacheBuffer) {
+ if (flattenedClassCache != (J9FlattenedClassCache *)flattenedClassCacheBuffer) {
j9mem_free_memory(flattenedClassCache);
}
#endif /* defined(J9VM_OPT_VALHALLA_FLATTENABLE_VALUE_TYPES) */
diff --git a/runtime/vm/intfunc.c b/runtime/vm/intfunc.c
index 46a1395b9b2..a68b2b98c02 100644
--- a/runtime/vm/intfunc.c
+++ b/runtime/vm/intfunc.c
@@ -81,6 +81,7 @@ J9InternalVMFunctions J9InternalFunctions = {
sendInit,
internalAcquireVMAccessNoMutex,
internalCreateArrayClass,
+ internalCreateArrayClassWithOptions,
attachSystemDaemonThread,
internalAcquireVMAccessClearStatus,
#if defined(J9VM_OPT_REFLECT)
diff --git a/test/functional/Valhalla/playlist.xml b/test/functional/Valhalla/playlist.xml
index e6acf1c8c48..3225144ba63 100644
--- a/test/functional/Valhalla/playlist.xml
+++ b/test/functional/Valhalla/playlist.xml
@@ -63,14 +63,14 @@
-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: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) \
@@ -98,11 +98,6 @@
ValueTypeArrayTests
-
-
- https://github.com/eclipse-openj9/openj9/issues/19460
-
-
-Xgcpolicy:optthruput
-Xgcpolicy:optthruput -XX:ValueTypeFlatteningThreshold=99999 -XX:-EnableArrayFlattening
@@ -142,7 +137,7 @@
ValueTypeArrayTestsJIT
- https://github.com/eclipse-openj9/openj9/issues/19460
+ https://github.com/eclipse-openj9/openj9/issues/19913
@@ -340,16 +335,12 @@
ValueTypeSystemArraycopyTests
-
-
- https://github.com/eclipse-openj9/openj9/issues/19460
-
-
-Xint
-Xint -Xgcpolicy:optthruput -XX:ValueTypeFlatteningThreshold=99999
-Xint -Xgcpolicy:optthruput -XX:ValueTypeFlatteningThreshold=99999 -XX:+EnableArrayFlattening
- -Xjit:count=0
+
+
- -Xjit:count=1,disableAsyncCompilation,initialOptLevel=warm -Xgcpolicy:optthruput
+
$(JAVA_COMMAND) $(JVM_OPTIONS) \
--enable-preview \
diff --git a/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeArrayTests.java b/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeArrayTests.java
index 86849f0a4c9..bf8719d7b8f 100644
--- a/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeArrayTests.java
+++ b/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeArrayTests.java
@@ -25,6 +25,8 @@
import static org.testng.Assert.*;
import org.testng.annotations.Test;
+import jdk.internal.value.CheckedType;
+import jdk.internal.value.NormalCheckedType;
import jdk.internal.value.NullRestrictedCheckedType;
import jdk.internal.value.ValueClass;
import jdk.internal.vm.annotation.ImplicitlyConstructible;
@@ -228,7 +230,7 @@ static void assignDispatch(Object[] arr, int idx, Object src, int arrKind, int s
new Class[] {null, null, null, null, null}, // All values can be assigned to Object[]
new Class[] {null, ASE, null, null, null}, // ASE for SomeIface[] = Object
new Class[] {null, ASE, ASE, null, ASE}, // ASE for PointV[] = PointPV, SomeIface
- new Class[] {NPE, ASE, ASE, ASE, null}, // NPE for PointPV[] = null; ASE for PointPV[] = PointV
+ new Class[] {ASE, ASE, ASE, ASE, null}, // ASE for PointPV[] = null; ASE for PointPV[] = PointV
};
/**
@@ -328,7 +330,8 @@ static void runTest(Object[] arr, Object sourceVal, int staticArrayKind, int sta
*/
@Test(priority=1,invocationCount=2)
static public void testValueTypeArrayAssignments() throws Throwable {
- Object[][] testArrays = new Object[][] {new Object[2], new SomeIface[2], new PointV[2], new PointPV[2]};
+ Object[][] testArrays = new Object[][] {new Object[2], new SomeIface[2], new PointV[2],
+ ValueClass.newArrayInstance(NullRestrictedCheckedType.of(PointPV.class), 2)};
int[] kinds = {OBJ_TYPE, IFACE_TYPE, VAL_TYPE, PRIM_TYPE};
Object[] vals = new Object[] {null, bogusIfaceObj, new PointV(1.0, 2.0), new PointPV(3.0, 4.0)};
@@ -753,11 +756,11 @@ static public void testStoreNullToNullRestrictedArrayElement1() throws Throwable
try {
arrayElementStoreNull(dstData, ARRAY_LENGTH/2);
- } catch (NullPointerException npe) {
+ } catch (ArrayStoreException ase) {
return; /* pass */
}
- Assert.fail("Expect a NullPointerException. No exception or wrong kind of exception thrown");
+ Assert.fail("Expect an ArrayStoreException. No exception or wrong kind of exception thrown");
}
@Test(priority=1,invocationCount=2)
@@ -769,10 +772,29 @@ static public void testStoreNullToNullRestrictedArrayElement2() throws Throwable
try {
arrayElementStore(dstData, ARRAY_LENGTH/2, obj);
- } catch (NullPointerException npe) {
+ } catch (ArrayStoreException ase) {
return; /* pass */
}
- Assert.fail("Expect a NullPointerException. No exception or wrong kind of exception thrown");
+ Assert.fail("Expect an ArrayStoreException. No exception or wrong kind of exception thrown");
+ }
+
+ @ImplicitlyConstructible
+ public static value class EmptyNullRestricted {
+ }
+
+ /* This test passes with Xint, disable until all cases are passing. */
+ /* Test JVM_IsNullRestrictedArray which is called by ValueClass.componentCheckedType */
+ @Test
+ public static void testJVMIsNullRestrictedArray() {
+ EmptyNullRestricted[] nrArray = (EmptyNullRestricted[])ValueClass.newArrayInstance(
+ NullRestrictedCheckedType.of(EmptyNullRestricted.class), 4);
+ CheckedType nrType = ValueClass.componentCheckedType(nrArray);
+ assertTrue(nrType instanceof NullRestrictedCheckedType);
+
+ EmptyNullRestricted[] normalArray = (EmptyNullRestricted[])ValueClass.newArrayInstance(
+ NormalCheckedType.of(EmptyNullRestricted.class), 4);
+ CheckedType normalType = ValueClass.componentCheckedType(normalArray);
+ assertTrue(normalType instanceof NormalCheckedType);
}
}
diff --git a/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeSystemArraycopyTests.java b/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeSystemArraycopyTests.java
index 10a538fb3a2..9e31a1a8bd7 100644
--- a/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeSystemArraycopyTests.java
+++ b/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeSystemArraycopyTests.java
@@ -165,7 +165,7 @@ static private void initArrays() {
}
}
- static private void initArraysForNPETest() {
+ static private void initArraysForASETest() {
for (int i=0; i < ARRAY_SIZE; i++) {
if (i >= ARRAY_SIZE/2) {
ifArray3[i] = null;
@@ -707,39 +707,39 @@ static public void testSystemArrayCopy21() throws Throwable {
static public void testSystemArrayCopy22() throws Throwable {
try {
- initArraysForNPETest(); // ifArray3[ARRAY_SIZE/2] is NULL
+ initArraysForASETest(); // ifArray3[ARRAY_SIZE/2] is NULL
testIFPVT(ifArray3, primitiveVtArrayDst);
- } catch (java.lang.NullPointerException npe1) {
+ } catch (java.lang.ArrayStoreException ase1) {
try {
checkResultsPartial(ifArray3, primitiveVtArrayDst, ARRAY_SIZE/2);
checkPVTArrayAfterException(ARRAY_SIZE/2);
- initArraysForNPETest();
+ initArraysForASETest();
testIFPVT(ifArray3, primitiveVtArrayDst);
- } catch (java.lang.NullPointerException npe2) {
+ } catch (java.lang.ArrayStoreException ase2) {
checkResultsPartial(ifArray3, primitiveVtArrayDst, ARRAY_SIZE/2);
// pass
return;
}
}
- Assert.fail("Expect a NullPointerException. No exception or wrong kind of exception thrown");
+ Assert.fail("Expect an ArrayStoreException. No exception or wrong kind of exception thrown");
}
@Test(priority=1)
static public void testSystemArrayCopy23() throws Throwable {
try {
- initArraysForNPETest(); // ifArray3[ARRAY_SIZE/2] is NULL
+ initArraysForASETest(); // ifArray3[ARRAY_SIZE/2] is NULL
testIFIF(ifArray3, primitiveVtArrayDst);
- } catch (java.lang.NullPointerException npe1) {
+ } catch (java.lang.ArrayStoreException ase1) {
try {
checkResultsPartial(ifArray3, primitiveVtArrayDst, ARRAY_SIZE/2);
checkPVTArrayAfterException(ARRAY_SIZE/2);
- initArraysForNPETest();
+ initArraysForASETest();
testIFIF(ifArray3, primitiveVtArrayDst);
- } catch (java.lang.NullPointerException npe2) {
+ } catch (java.lang.ArrayStoreException ase2) {
checkResultsPartial(ifArray3, primitiveVtArrayDst, ARRAY_SIZE/2);
checkPVTArrayAfterException(ARRAY_SIZE/2);
// pass
@@ -747,7 +747,7 @@ static public void testSystemArrayCopy23() throws Throwable {
}
}
- Assert.fail("Expect a NullPointerException. No exception or wrong kind of exception thrown");
+ Assert.fail("Expect a ArrayStoreException. No exception or wrong kind of exception thrown");
}
@Test(priority=1)
diff --git a/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeTests.java b/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeTests.java
index 7e8b125200b..943ed42e8fe 100644
--- a/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeTests.java
+++ b/test/functional/Valhalla/src_qtypes/org/openj9/test/lworld/ValueTypeTests.java
@@ -572,22 +572,6 @@ static public void testDefaultValueWithNonValueType() throws Throwable {
} catch (IncompatibleClassChangeError e) {}
}
- @Test(priority=4, invocationCount=2)
- static public void testNullWritesOnNonNullableArrays() throws Throwable {
- Object arrayObject = Array.newInstance(point2DClass, 3);
- try {
- Array.set(arrayObject, 1, null);
- Assert.fail("Should throw NPE. Cant write null to arrays of valuetypes");
- } catch(NullPointerException e) {}
-
- Object arrayObject2 = Array.newInstance(String.class, 3);
- try {
- Array.set(arrayObject2, 1, null);
- } catch(NullPointerException e) {
- Assert.fail("Should not throw NPE. Can write null to arrays of identity types");
- }
- }
-
@Test(priority=2, invocationCount=2)
static public void testBasicACMPTestOnIdentityTypes() throws Throwable {