Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Value type null-restricted array support #19911

Merged
merged 3 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions debugtools/DDR_VM/src/com/ibm/j9ddr/AuxFieldInfo29.dat
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
keithc-ca marked this conversation as resolved.
Show resolved Hide resolved
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()));
}
Expand Down
24 changes: 9 additions & 15 deletions runtime/codert_vm/cnathelp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down
6 changes: 6 additions & 0 deletions runtime/gc_structs/ClassArrayClassSlotIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) */
dmitripivkine marked this conversation as resolved.
Show resolved Hide resolved
case classArrayClassSlotIterator_state_componentType:
classPtr = ((J9ArrayClass *)_iterateClazz)->componentType;
_state += 1;
Expand Down
3 changes: 3 additions & 0 deletions runtime/gc_structs/ClassArrayClassSlotIterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
64 changes: 62 additions & 2 deletions runtime/gc_structs/ClassLoaderClassesIterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand Down Expand Up @@ -99,6 +102,58 @@ GC_ClassLoaderClassesIterator::switchToSystemMode()
return isSystemClassLoader;
}

J9Class *
GC_ClassLoaderClassesIterator::nextArrayClass()
{
dmitripivkine marked this conversation as resolved.
Show resolved Hide resolved
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;
}
}
dmitripivkine marked this conversation as resolved.
Show resolved Hide resolved
return _iterateArrayClazz;
}

J9Class *
GC_ClassLoaderClassesIterator::nextClass()
{
Expand All @@ -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;
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions runtime/gc_structs/ClassLoaderClassesIterator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
dmitripivkine marked this conversation as resolved.
Show resolved Hide resolved
ArrayClassState _arrayState; /**< array walk state */

protected:
public:
Expand Down Expand Up @@ -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:

Expand Down
62 changes: 57 additions & 5 deletions runtime/j9vm/javanextvmi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -764,15 +764,67 @@ JVM_IsImplicitlyConstructibleClass(JNIEnv *env, jclass cls)
JNIEXPORT jboolean JNICALL
JVM_IsNullRestrictedArray(JNIEnv *env, jobject obj)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it doesn't need to be done in this PR, but all Valhalla related functions should be moved to a different file (perhaps valhallavmi.cpp). For large features like valhalla, loom, etc. we should try to avoid bundling in the same file like we did in the past.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do this in a separate pr.

{
// 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));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should also check negative array size and throw J9VMCONSTANTPOOL_JAVALANGNEGATIVEARRAYSIZEEXCEPTION

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);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after classloading the j9class could be redefined, so you need to fetch the current one with VM_VMHelpers::currentClass

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);
theresa-m marked this conversation as resolved.
Show resolved Hide resolved
done:
vmFuncs->internalExitVMToJNI(currentThread);
return arrayRef;
}
#endif /* defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */

Expand Down
7 changes: 6 additions & 1 deletion runtime/oti/VMHelpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1786,16 +1786,21 @@ 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[]? */
if (0 != J9CLASS_DEPTH(componentType)) {
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;
}
Expand Down
6 changes: 5 additions & 1 deletion runtime/oti/j9.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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))

Expand Down
1 change: 1 addition & 0 deletions runtime/oti/j9consts.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading