Repository: eclipse-openj9/openj9
Pull request #21200: Implement JVM_GetProperties for jdk17+
Author: login: pshipton
Created: 2025-02-26T20:29:03Z | Merged: 2025-03-07T16:10:30Z

Related to https://github.com/eclipse-openj9/openj9/issues/21189

Move the code, more or less unchanged, from the jcl to the
vm so it can be called from multiple places. Remove unnecessary system
props from jdk17+, they are added by SystemProps.initProperties().


Diff:
diff --git a/jcl/src/java.base/share/classes/java/lang/System.java b/jcl/src/java.base/share/classes/java/lang/System.java
index 37cba04d128..55d23a690df 100644
--- a/jcl/src/java.base/share/classes/java/lang/System.java
+++ b/jcl/src/java.base/share/classes/java/lang/System.java
@@ -65,8 +65,10 @@
 
 /*[IF JAVA_SPEC_VERSION >= 20]*/
 import java.lang.reflect.Field;
-import jdk.internal.util.SystemProps;
 /*[ENDIF] JAVA_SPEC_VERSION >= 20 */
+/*[IF JAVA_SPEC_VERSION >= 17]*/
+import jdk.internal.util.SystemProps;
+/*[ENDIF] JAVA_SPEC_VERSION >= 17 */
 
 /*[IF JAVA_SPEC_VERSION >= 24]*/
 import java.net.URL;
@@ -170,10 +172,6 @@ public final class System {
 	 */
 	private static Charset consoleDefaultCharset;
 	/*[ENDIF] JAVA_SPEC_VERSION >= 11 */
-	/*[IF JAVA_SPEC_VERSION >= 19]*/
-	private static String stdoutProp;
-	private static String stderrProp;
-	/*[ENDIF] JAVA_SPEC_VERSION >= 19 */
 
 /*[IF JAVA_SPEC_VERSION >= 9]*/
 	static java.lang.ModuleLayer	bootLayer;
@@ -232,7 +230,7 @@ public final class System {
 	 */
 	static Charset getCharset(boolean isStdout, boolean fallback) {
 		/*[IF JAVA_SPEC_VERSION >= 19]*/
-		String primary = isStdout ? stdoutProp : stderrProp;
+		String primary = internalGetProperties().getProperty(isStdout ? "stdout.encoding" : "stderr.encoding"); //$NON-NLS-1$  //$NON-NLS-2$
 		/*[ELSE] JAVA_SPEC_VERSION >= 19 */
 		String primary = internalGetProperties().getProperty(isStdout ? "sun.stdout.encoding" : "sun.stderr.encoding"); //$NON-NLS-1$  //$NON-NLS-2$
 		/*[ENDIF] JAVA_SPEC_VERSION >= 19 */
@@ -273,20 +271,6 @@ static PrintStream createConsole(FileDescriptor desc, Charset charset) {
 		BufferedOutputStream bufStream = new BufferedOutputStream(new FileOutputStream(desc));
 		Charset consoleCharset = charset == null ? consoleDefaultCharset : charset;
 
-		/*[IF JAVA_SPEC_VERSION >= 19]*/
-		Properties props = internalGetProperties();
-		// If the user didn't set the encoding property, set it now.
-		if (FileDescriptor.out == desc) {
-			if (null == stdoutProp) {
-				props.put("stdout.encoding", consoleCharset.name()); //$NON-NLS-1$
-			}
-		} else if (FileDescriptor.err == desc) {
-			if (null == stderrProp) {
-				props.put("stderr.encoding", consoleCharset.name()); //$NON-NLS-1$
-			}
-		}
-		/*[ENDIF] JAVA_SPEC_VERSION >= 19 */
-
 		/*[IF PLATFORM-mz31 | PLATFORM-mz64]*/
 		return ConsolePrintStream.localize(bufStream, true, consoleCharset);
 		/*[ELSE]*/
@@ -317,12 +301,6 @@ static void finalizeConsoleEncoding() {
 				setOut(createConsole(FileDescriptor.out, stdoutCharset));
 			}
 		}
-
-		/*[IF JAVA_SPEC_VERSION >= 19]*/
-		// Cache the final system property values so they can be restored if ensureProperties(false) is called.
-		stdoutProp = systemProperties.getProperty("stdout.encoding"); //$NON-NLS-1$
-		stderrProp = systemProperties.getProperty("stderr.encoding"); //$NON-NLS-1$
-		/*[ENDIF] JAVA_SPEC_VERSION >= 19 */
 	}
 	/*[ELSE]*/
 	/*[IF Sidecar18-SE-OpenJ9]*/
@@ -383,9 +361,9 @@ static void afterClinitInitialization() {
 		// Fill in the properties from the VM information.
 		ensureProperties(true);
 
-		/*[IF JAVA_SPEC_VERSION >= 11]*/
+		/*[IF JAVA_SPEC_VERSION == 11]*/
 		initJCLPlatformEncoding();
-		/*[ENDIF] JAVA_SPEC_VERSION >= 11 */
+		/*[ENDIF] JAVA_SPEC_VERSION == 11 */
 
 		/*[REM] Initialize the JITHelpers needed in J9VMInternals since the class can't do it itself */
 		try {
@@ -719,7 +697,7 @@ private static void ensureProperties(boolean isInitialization) {
 /*[ENDIF] OpenJ9-RawBuild */
 
 /*[IF JAVA_SPEC_VERSION > 11]*/
-	Map<String, String> initializedProperties = new Hashtable<String, String>();
+	Map<String, String> initializedProperties = new HashMap<>();
 /*[ELSE] JAVA_SPEC_VERSION > 11
 	Properties initializedProperties = new Properties();
 /*[ENDIF] JAVA_SPEC_VERSION > 11 */
@@ -731,9 +709,11 @@ private static void ensureProperties(boolean isInitialization) {
 	if (osEncoding != null) {
 		initializedProperties.put("os.encoding", osEncoding); //$NON-NLS-1$
 	}
-	/*[PR The launcher apparently needs sun.jnu.encoding property or it does not work]*/
 	initializedProperties.put("ibm.system.encoding", platformEncoding); //$NON-NLS-1$
+	/*[IF JAVA_SPEC_VERSION < 17]*/
+	/*[PR The launcher apparently needs sun.jnu.encoding property or it does not work]*/
 	initializedProperties.put("sun.jnu.encoding", platformEncoding); //$NON-NLS-1$
+	/*[ENDIF] JAVA_SPEC_VERSION < 17 */
 	/*[IF JAVA_SPEC_VERSION == 8]*/
 	initializedProperties.put("file.encoding.pkg", "sun.io"); //$NON-NLS-1$ //$NON-NLS-2$
 	/*[ENDIF] JJAVA_SPEC_VERSION == 8 */
@@ -759,6 +739,9 @@ private static void ensureProperties(boolean isInitialization) {
 	initializedProperties.put("jfr.unsupported.vm", "true"); //$NON-NLS-1$ //$NON-NLS-2$
 	/*[ENDIF] JFR_SUPPORT */
 
+	/*[IF JAVA_SPEC_VERSION >= 17]*/
+	initializedProperties.putAll(SystemProps.initProperties());
+	/*[ELSE] JAVA_SPEC_VERSION >= 17 */
 	String[] list = getPropertyList();
 	for (int i = 0; i < list.length; i += 2) {
 		String key = list[i];
@@ -769,43 +752,12 @@ private static void ensureProperties(boolean isInitialization) {
 		initializedProperties.put(key, list[i+1]);
 	}
 	initializedProperties.put("file.encoding", fileEncoding); //$NON-NLS-1$
-
-	/*[IF JAVA_SPEC_VERSION >= 17]*/
-	/* Set native.encoding after setting all the defined properties, it can't be modified by using -D on the command line */
-	initializedProperties.put("native.encoding", platformEncoding); //$NON-NLS-1$
 	/*[ENDIF] JAVA_SPEC_VERSION >= 17 */
 
 	/*[IF (JAVA_SPEC_VERSION >= 21) & (PLATFORM-mz31 | PLATFORM-mz64)]*/
 	initializedProperties.put("com.ibm.autocvt", zOSAutoConvert); //$NON-NLS-1$
 	/*[ENDIF] (JAVA_SPEC_VERSION >= 21) & (PLATFORM-mz31 | PLATFORM-mz64) */
 
-	/*[IF JAVA_SPEC_VERSION >= 19]*/
-	if (null != stdoutProp) {
-		// Reinitialize required properties if ensureProperties(false) is called.
-		initializedProperties.put("stdout.encoding", stdoutProp); //$NON-NLS-1$
-	} else {
-		stdoutProp = initializedProperties.get("stdout.encoding"); //$NON-NLS-1$
-		if (null == stdoutProp) {
-			stdoutProp = initializedProperties.get("sun.stdout.encoding"); //$NON-NLS-1$
-			if (null != stdoutProp) {
-				initializedProperties.put("stdout.encoding", stdoutProp); //$NON-NLS-1$
-			}
-		}
-	}
-	if (null != stderrProp) {
-		// Reinitialize required properties if ensureProperties(false) is called.
-		initializedProperties.put("stderr.encoding", stderrProp); //$NON-NLS-1$
-	} else {
-		stderrProp = initializedProperties.get("stderr.encoding");
-		if (null == stderrProp) { //$NON-NLS-1$
-			stderrProp = initializedProperties.get("sun.stderr.encoding"); //$NON-NLS-1$
-			if (null != stderrProp) {
-				initializedProperties.put("stderr.encoding", stderrProp); //$NON-NLS-1$
-			}
-		}
-	}
-	/*[ENDIF] JAVA_SPEC_VERSION >= 19 */
-
 	/* java.lang.VersionProps.init() eventually calls into System.setProperty() where propertiesInitialized needs to be true */
 	propertiesInitialized = true;
 
@@ -1078,6 +1030,7 @@ public static String setProperty(String prop, String value) {
 	return (String)systemProperties.setProperty(prop, value);
 }
 
+/*[IF JAVA_SPEC_VERSION < 17]*/
 /**
  * Answers an array of Strings containing key..value pairs
  * (in consecutive array elements) which represent the
@@ -1087,13 +1040,14 @@ public static String setProperty(String prop, String value) {
  * @return		the default values for the system properties.
  */
 private static native String [] getPropertyList();
+/*[ENDIF] JAVA_SPEC_VERSION < 17 */
 
-/*[IF JAVA_SPEC_VERSION >= 11]*/
+/*[IF JAVA_SPEC_VERSION == 11]*/
 /**
  * Invoke JCL native to initialize platform encoding explicitly.
  */
 private static native void initJCLPlatformEncoding();
-/*[ENDIF] JAVA_SPEC_VERSION >= 11 */
+/*[ENDIF] JAVA_SPEC_VERSION == 11 */
 
 /**
  * Before propertiesInitialized is set to true,
diff --git a/runtime/j9vm/java11vmi.c b/runtime/j9vm/java11vmi.c
index 3a61379b7d8..4da0ef86244 100644
--- a/runtime/j9vm/java11vmi.c
+++ b/runtime/j9vm/java11vmi.c
@@ -1900,7 +1900,6 @@ JVM_IsUseContainerSupport(void)
 JNIEXPORT jobjectArray JNICALL
 JVM_GetProperties(JNIEnv *env)
 {
-	assert(!"JVM_GetProperties");
-	return NULL;
+	return ((J9VMThread *)env)->javaVM->internalVMFunctions->getSystemPropertyList(env);
 }
 #endif /* JAVA_SPEC_VERSION >= 17 */
diff --git a/runtime/jcl/common/system.c b/runtime/jcl/common/system.c
index 048eede667f..56e08e267d5 100644
--- a/runtime/jcl/common/system.c
+++ b/runtime/jcl/common/system.c
@@ -44,27 +44,7 @@
 #endif
 
 
-
-/* JCL_J2SE */
-#define JCL_J2SE
-
-
-
-typedef struct {
-	int errorOccurred;
-	jobject args;
-	jint nCommandLineDefines;
-	JNIEnv *env;
-	const char **defaultValues;
-	int defaultCount;
-	jclass stringClass;
-} CreateSystemPropertiesData;
-
-jint propertyListAddString( JNIEnv *env, jarray array, jint arrayIndex, const char *value);
-static void JNICALL systemPropertyIterator(char* key, char* value, void* userData);
-jobject getPropertyList(JNIEnv *env);
-
-#if JAVA_SPEC_VERSION >= 11
+#if JAVA_SPEC_VERSION == 11
 void JNICALL
 Java_java_lang_System_initJCLPlatformEncoding(JNIEnv *env, jclass clazz)
 {
@@ -93,7 +73,7 @@ Java_java_lang_System_initJCLPlatformEncoding(JNIEnv *env, jclass clazz)
 		}
 	}
 }
-#endif /* JAVA_SPEC_VERSION >= 11 */
+#endif /* JAVA_SPEC_VERSION == 11 */
 
 /**
  * sysPropID
@@ -203,10 +183,12 @@ Java_java_lang_System_getSysPropBeforePropertiesInitialized(JNIEnv *env, jclass
 	return result;
 }
 
+#if JAVA_SPEC_VERSION < 17
 jobject JNICALL Java_java_lang_System_getPropertyList(JNIEnv *env, jclass clazz)
 {
-	return getPropertyList(env);
+	return ((J9VMThread *)env)->javaVM->internalVMFunctions->getSystemPropertyList(env);
 }
+#endif /* JAVA_SPEC_VERSION < 17 */
 
 jstring JNICALL Java_java_lang_System_mapLibraryName(JNIEnv * env, jclass unusedClass, jstring inName)
 {
@@ -259,350 +241,6 @@ void JNICALL Java_java_lang_System_setFieldImpl(JNIEnv * env, jclass cls, jstrin
 	(*env)->SetStaticObjectField(env, cls, descriptorFID, stream);
 }
 
-
-jobject createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
-{
-	VMI_ACCESS_FROM_ENV(env);
-
-	jint i, nCommandLineDefines = 0;
-	jclass stringClass;
-	jarray args = NULL;
-	int propertyCount;
-
-	stringClass = (*env)->FindClass(env, "java/lang/String");
-	if (!stringClass) {
-/*		printf("\nFailed to find class java/lang/String");*/
-		return (jobject) 0;
-	}
-
-	(*VMI)->CountSystemProperties(VMI, &propertyCount);
-	if (propertyCount) {
-		CreateSystemPropertiesData iteratorData;
-
-		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
-		if (NULL == args) {
-			return NULL;
-		}
-
-		iteratorData.errorOccurred = 0;
-		iteratorData.args = args;
-		iteratorData.nCommandLineDefines = nCommandLineDefines;
-		iteratorData.env = env;
-		iteratorData.defaultValues = defaultValues;
-		iteratorData.defaultCount = defaultCount;
-
-		iteratorData.stringClass = stringClass;
-		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
-		if (iteratorData.errorOccurred) {
-			return NULL;
-		}
-		nCommandLineDefines = iteratorData.nCommandLineDefines;
-	}
-
-	if (NULL == args) {
-		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
-	}
-	if (NULL == args) {
-/*		printf("\nFailed to create arg array");*/
-		return NULL;
-	}
-
-	for (i = 0; i < defaultCount; ++i) {
-		if (defaultValues[i] == NULL) continue;
-		if (-1 == propertyListAddString( env, args, nCommandLineDefines, defaultValues[i]) ) {
-			return NULL;
-		}
-		nCommandLineDefines++;
-	}
-
-	return args;
-}
-
-/**
- * @return 0 on success, -1 on error
- */
-jint propertyListAddString( JNIEnv *env, jarray array, jint arrayIndex, const char *value)
-{
-	/* String must be well-formed modified UTF-8 */
-	jobject str = (*env)->NewStringUTF(env, value);
-	if (NULL != str) {
-		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
-	}
-	/* NewStringUTF does not throw an exception, other than OutOfMemory */
-	return ((*env)->ExceptionCheck(env) == JNI_TRUE) ? -1 : 0;
-}
-
-jobject getPropertyList(JNIEnv *env)
-{
-	PORT_ACCESS_FROM_ENV(env);
-	int propIndex = 0;
-	jobject propertyList = NULL;
-#define PROPERTY_COUNT 137
-	char *propertyKey = NULL;
-	const char * language = NULL;
-	const char * region = NULL;
-	const char * variant = NULL;
-	const char *strings[PROPERTY_COUNT] = {0};
-#define USERNAME_LENGTH 128
-	char username[USERNAME_LENGTH] = {0};
-	char *usernameAlloc = NULL;
-	/* buffer to hold the size of the maximum direct byte buffer allocations */
-	char maxDirectMemBuff[24] = {0};
-	IDATA result = 0;
-
-	J9VMThread *currentThread = (J9VMThread*)env;
-	J9JavaVM *javaVM = currentThread->javaVM;
-	J9InternalVMFunctions *vmFuncs = javaVM->internalVMFunctions;
-
-	/* Change the allocation value PROPERTY_COUNT above as you add/remove properties,
-	 * then follow the propIndex++ convention and consume 2 * slots for each property. 2 * number of property keys is the
-	 * correct allocation.
-	 * Also note the call to addSystemProperties below, which may add some configuration-specific properties.  Be sure to leave
-	 * enough room in the property list for all possibilities.
-	 */
-
-	if (J9_GC_POLICY_METRONOME == (javaVM->omrVM->gcPolicy)) {
-		strings[propIndex++] = "com.ibm.jvm.realtime";
-		strings[propIndex++] = "soft";
-	}
-
-#if defined(J9VM_OPT_SHARED_CLASSES)
-	strings[propIndex++] = "com.ibm.oti.shared.enabled";
-	if ((NULL != javaVM->sharedClassConfig)
-		&& J9_ARE_ALL_BITS_SET(javaVM->sharedClassConfig->runtimeFlags, J9SHR_RUNTIMEFLAG_ENABLE_CACHE_NON_BOOT_CLASSES)
-	) {
-		strings[propIndex++] = "true";
-	} else {
-		strings[propIndex++] = "false";
-	}
-#endif
-
-#if defined(JCL_J2SE)
-	strings[propIndex++] = "ibm.signalhandling.sigchain";
-	if (J9_ARE_ANY_BITS_SET(javaVM->sigFlags, J9_SIG_NO_SIG_CHAIN)) {
-		strings[propIndex++] = "false";
-	} else {
-		strings[propIndex++] = "true";
-	}
-	strings[propIndex++] = "ibm.signalhandling.sigint";
-	if (J9_ARE_ANY_BITS_SET(javaVM->sigFlags, J9_SIG_NO_SIG_INT)) {
-		strings[propIndex++] = "false";
-	} else {
-		strings[propIndex++] = "true";
-	}
-
-	/* The JCLs use ibm.signalhandling.rs to determine if they should prevent the registration of signal handlers for what
-	 * 	we consider to be asynchronous signals.
-	 * The JCLs do not install handlers for any synchronous signals */
-	strings[propIndex++] = "ibm.signalhandling.rs";
-	if (J9_ARE_ALL_BITS_SET(javaVM->sigFlags, J9_SIG_XRS_ASYNC)) {
-		strings[propIndex++] = "true";
-	} else {
-		strings[propIndex++] = "false";
-	}
-#endif
-
-	strings[propIndex++] = "com.ibm.vm.bitmode";
-#ifdef J9VM_ENV_DATA64
-	strings[propIndex++] = "64";
-#else
-	strings[propIndex++] = "32";
-#endif
-
-	strings[propIndex++] = "com.ibm.cpu.endian";
-#ifdef J9VM_ENV_LITTLE_ENDIAN
-	strings[propIndex++] = "little";
-#else
-	strings[propIndex++] = "big";
-#endif
-
-	strings[propIndex++] = "sun.cpu.endian";
-#ifdef J9VM_ENV_LITTLE_ENDIAN
-	strings[propIndex++] = "little";
-#else
-	strings[propIndex++] = "big";
-#endif
-
-/*	Don't set this property as the class library will look here first and when
-	there is a security manager you will get a security exception. The code
-	looks in this package by default, see URLConnection.getContentHandler()
-	strings[propIndex++] = "java.content.handler.pkgs";
-	strings[propIndex++] = "com.ibm.oti.www.content";
-*/
-
-	/*[PR 95709]*/
-
-	/* Get the language, region and variant */
-	language = j9nls_get_language();
-	region = j9nls_get_region();
-	variant = j9nls_get_variant();
-
-	/* CMVC 144405 : Norwegian Bokmal and Nynorsk need special consideration */
-	if ((0 == strcmp(language, "nn")) && (0 == strcmp(region, "NO"))) {
-		variant = "NY";
-	}
-	if ((0 == strcmp(language, "nn")) || (0 == strcmp(language, "nb"))) {
-		language = "no";
-	}
-
-	strings[propIndex++] = "user.language";
-	strings[propIndex++] = language;
-
-	propertyKey = "user.country";
-	strings[propIndex++] = propertyKey;
-	strings[propIndex++] = region;
-
-	/* Get the variant */
-	strings[propIndex++] = "user.variant";
-	strings[propIndex++] = variant;
-
-	/* Get the User name */
-	strings[propIndex++] = "user.name";
-	strings[propIndex] = "unknown";
-#if defined(J9VM_OPT_CRIU_SUPPORT)
-	/* Skip j9sysinfo_get_username if a checkpoint can be taken.
-	 * https://github.com/eclipse-openj9/openj9/issues/15800
-	 */
-	result = -1;
-	if (!vmFuncs->isCheckpointAllowed(javaVM))
-#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */
-	{
-		result = j9sysinfo_get_username(username, USERNAME_LENGTH);
-		if (0 == result) {
-			strings[propIndex] = username;
-		} else if (result > 0) {
-			usernameAlloc = jclmem_allocate_memory(env, result);
-			if (NULL != usernameAlloc) {
-				result = j9sysinfo_get_username(usernameAlloc, result);
-				if (0 == result) {
-					strings[propIndex] = usernameAlloc;
-				} else {
-					/* free the memory, try j9sysinfo_get_env later */
-					jclmem_free_memory(env, usernameAlloc);
-					usernameAlloc = NULL;
-				}
-			} else {
-				vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
-				goto failed;
-			}
-		}
-	}
-#if defined(LINUX) || defined(OSX)
-	if (0 != result) {
-		result = j9sysinfo_get_env("USER", username, USERNAME_LENGTH);
-		if (0 == result) {
-			strings[propIndex] = username;
-		} else if (result > 0) {
-			usernameAlloc = jclmem_allocate_memory(env, result);
-			if (NULL != usernameAlloc) {
-				result = j9sysinfo_get_env("USER", usernameAlloc, result);
-				if (0 == result) {
-					if (strlen(usernameAlloc) > 0) {
-						strings[propIndex] = usernameAlloc;
-					}
-					/* keep it as "unknown" if the env value is empty */
-				}
-				/* usernameAlloc to be freed before this method returns */
-			} else {
-				vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
-				goto failed;
-			}
-		}
-	}
-#endif /* defined(LINUX) || defined(OSX) */
-	propIndex += 1;
-#undef USERNAME_LENGTH
-
-#if defined(OPENJ9_BUILD) && JAVA_SPEC_VERSION == 8
-	/* Set the maximum direct byte buffer allocation property if it has not been set manually */
-	if ((~(UDATA)0) == javaVM->directByteBufferMemoryMax) {
-		UDATA heapSize = javaVM->memoryManagerFunctions->j9gc_get_maximum_heap_size(javaVM);
-		/* allow up to 7/8 of the heap to be direct byte buffers */
-		javaVM->directByteBufferMemoryMax = heapSize - (heapSize / 8);
-	}
-#endif /* defined(OPENJ9_BUILD) && JAVA_SPEC_VERSION == 8 */
-#if !defined(OPENJ9_BUILD)
-	/* Don't set a default value for IBM Java 8. */
-	if ((~(UDATA)0) != javaVM->directByteBufferMemoryMax)
-#endif /* !defined(OPENJ9_BUILD) */
-	{
-		strings[propIndex] = "sun.nio.MaxDirectMemorySize";
-		propIndex += 1;
-		if ((~(UDATA)0) == javaVM->directByteBufferMemoryMax) {
-			strcpy(maxDirectMemBuff, "-1");
-		} else {
-			j9str_printf(maxDirectMemBuff, sizeof(maxDirectMemBuff), "%zu", javaVM->directByteBufferMemoryMax);
-		}
-		strings[propIndex] = maxDirectMemBuff;
-		propIndex += 1;
-	}
-
-	propertyList = getPlatformPropertyList(env, strings, propIndex);
-
-failed:
-	if (NULL != usernameAlloc) {
-		jclmem_free_memory(env, usernameAlloc);
-	}
-	return propertyList;
-}
-
-static void JNICALL
-systemPropertyIterator(char* key, char* value, void* userData)
-{
-	CreateSystemPropertiesData * iteratorData = userData;
-	jobject args = iteratorData->args;
-	JNIEnv *env = iteratorData->env;
-	const char **defaultValues = iteratorData->defaultValues;
-	int defaultCount = iteratorData->defaultCount;
-	jint i;
-
-	/* CMVC 95717: if an error has already occurred get out of here */
-	if ( iteratorData->errorOccurred ) {
-		return;
-	}
-
-	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
-		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
-		return;
-	}
-
-#if JAVA_SPEC_VERSION >= 21
-	if (0 == strcmp("java.compiler", key)) {
-		PORT_ACCESS_FROM_ENV(env);
-		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
-			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_JCL_JAVA_COMPILER_WARNING_XJIT);
-		} else {
-			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_JCL_JAVA_COMPILER_WARNING_XINT);
-		}
-		return;
-	}
-#endif /* JAVA_SPEC_VERSION >= 21 */
-
-	/* check for overridden system properties, use linear scan for now */
-	for (i=0; i < defaultCount; i+=2) {
-		if (defaultValues[i] && !strcmp(key, defaultValues[i])) {
-			defaultValues[i] = NULL;
-			defaultValues[i+1] = NULL;
-			break;
-		}
-	}
-
-	/* First do the key */
-	if( propertyListAddString( env, args, iteratorData->nCommandLineDefines++, key) ) {
-		iteratorData->errorOccurred = 1;
-		return;
-	}
-
-	/* Then the value */
-	if( propertyListAddString( env, args, iteratorData->nCommandLineDefines++, value) ) {
-		iteratorData->errorOccurred = 1;
-		return;
-	}
-
-	Trc_JCL_systemPropertyIterator(env, key, value);
-}
-
-
 void JNICALL
 Java_java_lang_System_startSNMPAgent(JNIEnv *env, jclass jlClass)
 {
diff --git a/runtime/jcl/exports.cmake b/runtime/jcl/exports.cmake
index f4b04862ac0..14a9c80a9a0 100644
--- a/runtime/jcl/exports.cmake
+++ b/runtime/jcl/exports.cmake
@@ -350,7 +350,6 @@ omr_add_exports(jclse
 	Java_java_lang_J9VMInternals_getStackTrace
 	Java_java_lang_J9VMInternals_newInstance
 	Java_java_lang_System_getSysPropBeforePropertiesInitialized
-	Java_java_lang_System_getPropertyList
 	Java_java_lang_System_mapLibraryName
 	Java_java_lang_System_rasInitializeVersion
 	Java_java_lang_System_setFieldImpl
@@ -434,6 +433,7 @@ omr_add_exports(jclse
 
 if(JAVA_SPEC_VERSION LESS 17)
 omr_add_exports(jclse
+	Java_java_lang_System_getPropertyList
 	Java_sun_misc_Unsafe_defineAnonymousClass
 )
 endif()
@@ -599,13 +599,18 @@ if(NOT JAVA_SPEC_VERSION LESS 9)
 	)
 endif()
 
+if(JAVA_SPEC_VERSION EQUAL 11)
+	omr_add_exports(jclse
+		Java_java_lang_System_initJCLPlatformEncoding
+	)
+endif()
+
 # java 11+
 if(NOT JAVA_SPEC_VERSION LESS 11)
 	omr_add_exports(jclse
 		Java_java_lang_Class_getNestHostImpl
 		Java_java_lang_Class_getNestMembersImpl
 		Java_java_lang_invoke_MethodHandleResolver_getCPConstantDynamicAt
-		Java_java_lang_System_initJCLPlatformEncoding
 	)
 endif()
 
diff --git a/runtime/jcl/j9jcl.tdf b/runtime/jcl/j9jcl.tdf
index c64230a9bb3..0ec24ba02d6 100644
--- a/runtime/jcl/j9jcl.tdf
+++ b/runtime/jcl/j9jcl.tdf
@@ -467,7 +467,7 @@ TraceEvent=Trc_Java_com_ibm_lang_management_OperatingSystemMXBeanImpl_getProcess
 TraceExit=Trc_Java_com_ibm_lang_management_OperatingSystemMXBeanImpl_getProcessPrivateMemorySizeImpl_Exit Overhead=1 Level=3 Template="getProcessPrivateMemorySizeImpl Exit"
 
 TraceEvent=Trc_JCL_java_lang_J9VMInternals_mtTrace Overhead=1 Level=1 Template="J9VMInternals.mtTraceImpl: tenant = %s, message = %s"
-TraceEvent=Trc_JCL_systemPropertyIterator Overhead=1 Level=10 Template="systemPropertyIterator: added VM system property '%s'='%s'"
+TraceEvent=Trc_JCL_systemPropertyIterator Obsolete Overhead=1 Level=10 Template="systemPropertyIterator: added VM system property '%s'='%s'"
 
 TraceEvent=Trc_JCL_mtTrace Overhead=1 Level=1 Template="MT-trace: tenant = %s, message = %s"
 
diff --git a/runtime/jcl/uma/se11_exports.xml b/runtime/jcl/uma/se11_exports.xml
index 626a197be7a..d844c63d9ba 100644
--- a/runtime/jcl/uma/se11_exports.xml
+++ b/runtime/jcl/uma/se11_exports.xml
@@ -23,5 +23,7 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-ex
 	<export name="Java_java_lang_Class_getNestHostImpl"/>
 	<export name="Java_java_lang_Class_getNestMembersImpl"/>
 	<export name="Java_java_lang_invoke_MethodHandleResolver_getCPConstantDynamicAt"/>
-	<export name="Java_java_lang_System_initJCLPlatformEncoding" />
+	<export name="Java_java_lang_System_initJCLPlatformEncoding">
+		<exclude-if condition="spec.java12"/>
+	</export>
 </exports>
diff --git a/runtime/jcl/uma/se6_vm-side_natives_exports.xml b/runtime/jcl/uma/se6_vm-side_natives_exports.xml
index b8a780711eb..549a8712e3b 100644
--- a/runtime/jcl/uma/se6_vm-side_natives_exports.xml
+++ b/runtime/jcl/uma/se6_vm-side_natives_exports.xml
@@ -249,7 +249,9 @@
 	<export name="Java_java_lang_reflect_Proxy_defineClassImpl" />
 	<export name="Java_java_lang_reflect_Array_multiNewArrayImpl" />
 	<export name="Java_java_lang_System_getSysPropBeforePropertiesInitialized" />
-	<export name="Java_java_lang_System_getPropertyList" />
+	<export name="Java_java_lang_System_getPropertyList">
+		<exclude-if condition="spec.java17" />
+	</export>
 	<export name="Java_java_lang_System_mapLibraryName" />
 	<export name="Java_java_lang_System_setFieldImpl" />
 	<export name="Java_java_lang_System_rasInitializeVersion" />
diff --git a/runtime/jcl/unix/syshelp.c b/runtime/jcl/unix/syshelp.c
index d1f9ff46fb4..a1bae22f747 100644
--- a/runtime/jcl/unix/syshelp.c
+++ b/runtime/jcl/unix/syshelp.c
@@ -41,9 +41,6 @@
 #include "atoe.h"
 #endif
 
-/* JCL_J2SE */
-#define JCL_J2SE
-
 /* defineCodepageTable */
 /* NULL separated list of code page aliases. The first name is */
 /* the name of the System property, the names following before */
@@ -63,159 +60,6 @@ char* CodepageTable[] = {
 #endif
 };
 
-/**
- * Try to find the 'correct' unix temp directory, as taken from the man page for tmpnam.
- * As a last resort, the '.' representing the current directory is returned.
- */
-char * getTmpDir(JNIEnv *env, char**envSpace) {
-	PORT_ACCESS_FROM_ENV(env);
-	I_32 envSize;
-	if ((envSize = j9sysinfo_get_env("TMPDIR", NULL, 0))> 0) {
-		*envSpace = jclmem_allocate_memory(env,envSize);	/* trailing null taken into account */
-		if(*envSpace==NULL) return ".";
-		j9sysinfo_get_env("TMPDIR", *envSpace, envSize);
-		if (j9file_attr(*envSpace) > -1)
-			return *envSpace;
-		/* directory was not there, free up memory and continue */
-		jclmem_free_memory(env,*envSpace);
-		*envSpace = NULL;
-		}
-	if (j9file_attr(P_tmpdir) > -1)
-		return P_tmpdir;
-	if (j9file_attr("/tmp") > -1)
-		return "/tmp";
-	return ".";
-}
-
-jobject getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
-{
-	PORT_ACCESS_FROM_ENV(env);
-	char *charResult = NULL;
-	char *envSpace = NULL;
-	jobject plist = NULL;
-	char userdir[EsMaxPath] = {0};
-	char home[EsMaxPath] = {0};
-	char *homeAlloc = NULL;
-	J9VMThread *currentThread = (J9VMThread*)env;
-	J9JavaVM *vm = currentThread->javaVM;
-	J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
-
-	/* Hard coded file/path separators and other values */
-
-#if defined(J9ZOS390)
-	if (J2SE_VERSION_FROM_ENV(env)) {
-		strings[propIndex++] = "platform.notASCII";
-		strings[propIndex++] = "true";
-
-		strings[propIndex++] = "os.encoding";
-		strings[propIndex++] = "ISO8859_1";
-	}
-#endif
-
-	strings[propIndex++] = "file.separator";
-	strings[propIndex++] = "/";
-
-	strings[propIndex++] = "line.separator";
-	strings[propIndex++] = "\n";
-
-	/* Get the directory where the executable was started */
-	strings[propIndex++] = "user.dir";
-	charResult = getcwd(userdir, EsMaxPath);
-	if (charResult == NULL) {
-		strings[propIndex++] = ".";
-	} else {
-		strings[propIndex++] = charResult;
-	}
-
-	strings[propIndex++] = "user.home";
-	charResult = NULL;
-#if defined(J9ZOS390)
-	charResult = getenv("HOME");
-	if (NULL != charResult) {
-		strings[propIndex++] = charResult;
-	} else {
-		uid_t uid = geteuid();
-		if (0 != uid) {
-			struct passwd *userDescription = getpwuid(uid);
-			if (NULL != userDescription) {
-				charResult = userDescription->pw_dir;
-				strings[propIndex++] = charResult;
-			}
-		} else {
-			char *loginID = getlogin();
-			if (NULL != loginID) {
-				struct passwd *userDescription = getpwnam(loginID);
-				if (NULL != userDescription) {
-					charResult = userDescription->pw_dir;
-					strings[propIndex++] = charResult;
-				}
-			}
-		}
-	}
-
-	/* there exist situations where one of the above calls will fail.  Fall through to the Unix solution for those cases */
-#endif
-#if defined(J9VM_OPT_CRIU_SUPPORT)
-	/* Skip getpwuid if a checkpoint can be taken.
-	 * https://github.com/eclipse-openj9/openj9/issues/15800
-	 */
-	if (!vmFuncs->isCheckpointAllowed(vm))
-#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */
-	{
-		/*[PR 101939] user.home not set correctly when j9 invoked via execve(x,y,null) */
-		if (NULL == charResult) {
-			struct passwd *pwentry = getpwuid(getuid());
-			if (NULL != pwentry) {
-				charResult = pwentry->pw_dir;
-				strings[propIndex++] = charResult;
-			}
-		}
-	}
-
-	if (NULL == charResult) {
-		IDATA result = j9sysinfo_get_env("HOME", home, sizeof(home));
-		strings[propIndex] = ".";
-		if (0 == result) {
-			if (strlen(home) > 0) {
-				strings[propIndex] = home;
-			}
-		} else if (result > 0) {
-			homeAlloc = j9mem_allocate_memory(result, J9MEM_CATEGORY_VM_JCL);
-			if (NULL != homeAlloc) {
-				result = j9sysinfo_get_env("HOME", homeAlloc, result);
-				if (0 == result) {
-					strings[propIndex] = homeAlloc;
-				}
-			} else {
-				vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
-				goto failed;
-			}
-		}
-		propIndex += 1;
-	}
-
-	/* Get the Temp Dir name */
-	strings[propIndex++] = "java.io.tmpdir";
-	strings[propIndex++] = getTmpDir(env, &envSpace);
-
-	if (JAVA_SPEC_VERSION < 12) {
-		/* Get the timezone */
-		strings[propIndex++] = "user.timezone";
-		strings[propIndex++] = "";
-	}
-
-	plist = createSystemPropertyList(env, strings, propIndex);
-	if (NULL != envSpace) {
-		jclmem_free_memory(env,envSpace);
-	}
-
-failed:
-	if (NULL != homeAlloc) {
-		jclmem_free_memory(env, homeAlloc);
-	}
-	return plist;
-}
-
 /**
  * Turns a platform independent DLL name into a platform specific one.
  */	
diff --git a/runtime/jcl/win32/syshelp.c b/runtime/jcl/win32/syshelp.c
index c6adf96b6a4..7bd081a6614 100644
--- a/runtime/jcl/win32/syshelp.c
+++ b/runtime/jcl/win32/syshelp.c
@@ -43,139 +43,11 @@
 #include <VersionHelpers.h>
 #endif
 
-/* JCL_J2SE */
-#define JCL_J2SE
-
 
 char* getPlatformFileEncoding(JNIEnv *env, char *codepage, int size, int encodingType);
-I_32 convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size);
-char * getTmpDir(JNIEnv *env, char **tempdir);
-jobject getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex);
 void mapLibraryToPlatformName(const char *inPath, char *outPath);
 
 
-jobject getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex) {
-	PORT_ACCESS_FROM_ENV(env);
-#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
-	OSVERSIONINFO versionInfo;
-#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
-	I_32 envSize;
-	char *envSpace = NULL, *tempdir = NULL;
-	jobject result;
-	char userhome[EsMaxPath];
-	wchar_t unicodeTemp[EsMaxPath];
-	int i;
-	char userdir[EsMaxPath];
-	wchar_t unicodeHome[EsMaxPath];
-	HANDLE process, token;
-	UDATA handle;
-	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
-#if !defined(JCL_J2SE)
-	UINT codePage;
-	char codePageBuf[32];
-	CPINFO cpInfo;
-#endif
-
-	/* Hard coded file/path separators and other values */
-
-	strings[propIndex++] = "file.separator";
-	strings[propIndex++] = "\\";
-
-	strings[propIndex++] = "line.separator";
-	strings[propIndex++] = "\r\n";
-
-	/* Get the Temp Dir name */
-	strings[propIndex++] = "java.io.tmpdir";
-	strings[propIndex++] = getTmpDir(env, &tempdir);
-
-	strings[propIndex++] = "user.home";
-	i = propIndex;
-	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
-	if (-1 != envSize) {
-			envSpace = jclmem_allocate_memory(env, envSize); /* trailing null taken into account */
-			if (NULL == envSpace) {
-				strings[propIndex++] = "\\";
-			} else {
-				j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
-				strings[propIndex++] = envSpace;
-			}
-	}
-#if defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE)
-	/* dwPlatformId, VER_PLATFORM_WIN32_NT = https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
-	if ((i == propIndex) && IsWindowsVersionOrGreater( 5, 0, 0))
-#else /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
-	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-	if ((i == propIndex) && GetVersionEx(&versionInfo) && (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT))
-#endif /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
-	{
-		process = GetCurrentProcess();
-		if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
-			envSize = 0;
-			if (j9util_open_system_library("userenv", &handle, TRUE) == 0) {
-				if (i == propIndex) {
-					if (j9sl_lookup_name(handle, "GetUserProfileDirectoryW", (UDATA *)&func, "ZPLP") == 0) {
-						envSize = EsMaxPath;
-						if (func(token, unicodeHome, &envSize)) {
-							/* When the SystemDrive environment variable isn't set, such as when j9 is exec'ed
-							 * running JCK tests, we get %SystemDrive%/Documents and Settings/...
-							 */
-							if (!wcsncmp(unicodeHome, L"%SystemDrive%", 13)) {
-								/* Borrow userdir variable, which is used for real below */
-								if (GetSystemDirectoryW(unicodeTemp, EsMaxPath) > 1) {
-									unicodeHome[0] = unicodeTemp[0];
-									unicodeHome[1] = unicodeTemp[1];
-									wcsncpy(&unicodeHome[2], &unicodeHome[13], envSize - 13);
-								}
-							}
-							convertToUTF8(PORTLIB, unicodeHome, userhome, EsMaxPath);
-							strings[propIndex++] = userhome;
-						}
-					}
-				}
-			}
-		}
-	}
-
-	if (i == propIndex) {
-		/* Fallback to Windows Directory */
-		envSize = (I_32)j9sysinfo_get_env("WINDIR", NULL, 0);
-		if (-1 == envSize) {
-			strings[propIndex++] = "\\";
-		} else {
-			envSpace = jclmem_allocate_memory(env,envSize);	/* trailing null taken into account */
-			if(!envSpace) {
-				strings[propIndex++] = "\\";
-			} else {
-				j9sysinfo_get_env("WINDIR", envSpace, envSize);
-				strings[propIndex++] = envSpace;
-			}
-		}
-	}
-
-	/* Get the directory where the executable was started */
-	strings[propIndex++] = "user.dir";
-	if (GetCurrentDirectoryW(EsMaxPath, unicodeTemp) == 0) {
-		strings[propIndex++] = "\\";
-	} else {
-		convertToUTF8(PORTLIB, unicodeTemp, userdir, EsMaxPath);
-		strings[propIndex++] = userdir;
-	}
-
-	if (JAVA_SPEC_VERSION < 12) {
-		/* Get the timezone */
-		strings[propIndex++] = "user.timezone";
-		strings[propIndex++] = "";
-	}
-
-	/* Jazz 52075 JCL_J2SE is always true */
-
-	result = createSystemPropertyList(env, strings, propIndex);
-	if (tempdir) jclmem_free_memory(env,tempdir);
-	if (envSpace) jclmem_free_memory(env,envSpace);
-	return result;
-}
-
-
 char* getPlatformFileEncoding(JNIEnv *env, char *codepage, int size, int encodingType) {
 	PORT_ACCESS_FROM_ENV(env);
 	LCID threadLocale;
@@ -228,11 +100,7 @@ char* getPlatformFileEncoding(JNIEnv *env, char *codepage, int size, int encodin
 		codepage[1] = 'S';
 	} else {
 		codepage[0] = 'C';
-#if defined(JCL_J2SE)
 		codepage[1] = 'p';
-#else
-		codepage[1] = 'P';
-#endif
 	}
 
 	return codepage;
@@ -246,64 +114,3 @@ void mapLibraryToPlatformName(const char *inPath, char *outPath) {
 	strcpy(outPath,inPath);
 	strcat(outPath, ".dll");
 }
-
-
-/**
- * Try to find the 'correct' windows temp directory.
- */
-char * getTmpDir(JNIEnv *env, char **tempdir) {
-	PORT_ACCESS_FROM_ENV(env);
-
-	DWORD rc;
-	wchar_t unicodeBuffer[EsMaxPath];
-	char *buffer = NULL;
-	char *retVal = ".";
-
-	rc = GetTempPathW(EsMaxPath, unicodeBuffer);
-
-	/* If the function succeeds, the return value is the number of characters stored into 
-	the buffer, not including the terminating null character. If the buffer is not large enough, 
-	the return value will exceed the length parameter (i.e. the required size)
-	*/
-
-	if((rc != 0) && (rc < EsMaxPath)) {
-		/* convert */
-		rc = WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeBuffer, -1, NULL, 0, NULL, NULL);
-		if(rc != 0) {
-			buffer = jclmem_allocate_memory(env, rc);
-			if(NULL != buffer) {
-				rc = WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeBuffer, -1,  buffer, rc, NULL, NULL);
-				if(rc == 0) {
-					jclmem_free_memory(env, buffer);
-					buffer = NULL;
-				} else {
-					retVal = buffer;
-				}
-			}
-		}
-	}
-	*tempdir = buffer;
-	return retVal;
-}
-
-/**
- * @internal
- * Converts the Unicode string to UTF8 encoded data in the provided buffer.
- *
- * @param[in] portLibrary The port library
- * @param[in] unicodeString The unicode buffer to convert
- * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
- * @param[in] size The size of utf8Buffer
- *
- * @return 0 on success, -1 on failure.
- */
-I_32
-convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size)
-{
-	PORT_ACCESS_FROM_PORT(portLibrary);
-	if(0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
-		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
-		return -1;
-	}
-	return 0;
-}
diff --git a/runtime/nls/j9cl/j9jcl.nls b/runtime/nls/j9cl/j9jcl.nls
index a7912fb5583..ba13180f677 100644
--- a/runtime/nls/j9cl/j9jcl.nls
+++ b/runtime/nls/j9cl/j9jcl.nls
@@ -580,20 +580,16 @@ J9NLS_JCL_FIPS_MODE_SET_TO_INVALID_VALUE.system_action=The JVM will fail to star
 J9NLS_JCL_FIPS_MODE_SET_TO_INVALID_VALUE.user_response=Check the fips mode value is consistent with the FIPS 140-3 preview being enabled / disabled.
 # END NON-TRANSLATABLE
 
-# Note: "java.compiler" is a system property name and should not be translated.
-# Note: "-Xjit" is a command line parameter and should not be translated.
-J9NLS_JCL_JAVA_COMPILER_WARNING_XJIT=Setting the java.compiler system property is obsolete in version 21 and later, use -Xjit instead.
+J9NLS_JCL_JAVA_COMPILER_WARNING_XJIT=
 # START NON-TRANSLATABLE
-J9NLS_JCL_JAVA_COMPILER_WARNING_XJIT.explanation=The java.compiler system property can no longer be used to enable or disable the JIT.
-J9NLS_JCL_JAVA_COMPILER_WARNING_XJIT.system_action=Setting the java.compiler system property is ignored.
-J9NLS_JCL_JAVA_COMPILER_WARNING_XJIT.user_response=Use the -Xjit option to enable the JIT.
+J9NLS_JCL_JAVA_COMPILER_WARNING_XJIT.explanation=NOTAG
+J9NLS_JCL_JAVA_COMPILER_WARNING_XJIT.system_action=
+J9NLS_JCL_JAVA_COMPILER_WARNING_XJIT.user_response=
 # END NON-TRANSLATABLE
 
-# Note: "java.compiler" is a system property name and should not be translated.
-# Note: "-Xint" is a command line parameter and should not be translated.
-J9NLS_JCL_JAVA_COMPILER_WARNING_XINT=Setting the java.compiler system property is obsolete in version 21 and later, use -Xint instead.
+J9NLS_JCL_JAVA_COMPILER_WARNING_XINT=
 # START NON-TRANSLATABLE
-J9NLS_JCL_JAVA_COMPILER_WARNING_XINT.explanation=The java.compiler system property can no longer be used to enable or disable the JIT.
-J9NLS_JCL_JAVA_COMPILER_WARNING_XINT.system_action=Setting the java.compiler system property is ignored.
-J9NLS_JCL_JAVA_COMPILER_WARNING_XINT.user_response=Use the -Xint option to disable the JIT.
+J9NLS_JCL_JAVA_COMPILER_WARNING_XINT.explanation=NOTAG
+J9NLS_JCL_JAVA_COMPILER_WARNING_XINT.system_action=
+J9NLS_JCL_JAVA_COMPILER_WARNING_XINT.user_response=
 # END NON-TRANSLATABLE
diff --git a/runtime/nls/j9vm/j9vm.nls b/runtime/nls/j9vm/j9vm.nls
index 21495596345..73e295f0128 100644
--- a/runtime/nls/j9vm/j9vm.nls
+++ b/runtime/nls/j9vm/j9vm.nls
@@ -2430,3 +2430,21 @@ J9NLS_VM_OPENJ9_JFR_METADATA_FILE_NOT_LOAD.explanation=Couldn't find or load JFR
 J9NLS_VM_OPENJ9_JFR_METADATA_FILE_NOT_LOAD.system_action=The JVM will not generate a JFR file.
 J9NLS_VM_OPENJ9_JFR_METADATA_FILE_NOT_LOAD.user_response=Contact your service representative.
 # END NON-TRANSLATABLE
+
+# Note: "java.compiler" is a system property name and should not be translated.
+# Note: "-Xjit" is a command line parameter and should not be translated.
+J9NLS_VM_JAVA_COMPILER_WARNING_XJIT=Setting the java.compiler system property is obsolete in version 21 and later, use -Xjit instead.
+# START NON-TRANSLATABLE
+J9NLS_VM_JAVA_COMPILER_WARNING_XJIT.explanation=The java.compiler system property can no longer be used to enable or disable the JIT.
+J9NLS_VM_JAVA_COMPILER_WARNING_XJIT.system_action=Setting the java.compiler system property is ignored.
+J9NLS_VM_JAVA_COMPILER_WARNING_XJIT.user_response=Use the -Xjit option to enable the JIT.
+# END NON-TRANSLATABLE
+
+# Note: "java.compiler" is a system property name and should not be translated.
+# Note: "-Xint" is a command line parameter and should not be translated.
+J9NLS_VM_JAVA_COMPILER_WARNING_XINT=Setting the java.compiler system property is obsolete in version 21 and later, use -Xint instead.
+# START NON-TRANSLATABLE
+J9NLS_VM_JAVA_COMPILER_WARNING_XINT.explanation=The java.compiler system property can no longer be used to enable or disable the JIT.
+J9NLS_VM_JAVA_COMPILER_WARNING_XINT.system_action=Setting the java.compiler system property is ignored.
+J9NLS_VM_JAVA_COMPILER_WARNING_XINT.user_response=Use the -Xint option to disable the JIT.
+# END NON-TRANSLATABLE
diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h
index ff227c107f5..36fe4f7d708 100644
--- a/runtime/oti/j9nonbuilder.h
+++ b/runtime/oti/j9nonbuilder.h
@@ -5347,6 +5347,7 @@ typedef struct J9InternalVMFunctions {
 	struct J9ObjectMonitor * (*monitorTablePeek)(struct J9JavaVM *vm, j9object_t object);
 	jobject (*takeVirtualThreadListToUnblock)(struct J9VMThread *currentThread, struct J9JavaVM *vm);
 #endif /* JAVA_SPEC_VERSION >= 24 */
+	jobject (*getSystemPropertyList)(JNIEnv *env);
 } J9InternalVMFunctions;
 
 /* Jazz 99339: define a new structure to replace JavaVM so as to pass J9NativeLibrary to JVMTIEnv  */
diff --git a/runtime/oti/jclprots.h b/runtime/oti/jclprots.h
index e35676d0fae..f3a101a3ea3 100644
--- a/runtime/oti/jclprots.h
+++ b/runtime/oti/jclprots.h
@@ -190,11 +190,13 @@ Java_com_ibm_java_lang_management_internal_MemoryManagerMXBeanImpl_isManagedPool
 /* BBjclNativesCommonSystem*/
 void JNICALL Java_java_lang_System_setFieldImpl (JNIEnv * env, jclass cls, jstring name, jobject stream);
 jobject createSystemPropertyList (JNIEnv *env, const char *defaultValues[], int defaultCount);
-#if JAVA_SPEC_VERSION >= 11
+#if JAVA_SPEC_VERSION == 11
 void JNICALL Java_java_lang_System_initJCLPlatformEncoding (JNIEnv *env, jclass clazz);
-#endif /* JAVA_SPEC_VERSION >= 11 */
+#endif /* JAVA_SPEC_VERSION == 11 */
 jstring JNICALL Java_java_lang_System_getSysPropBeforePropertiesInitialized(JNIEnv *env, jclass clazz, jint sysPropID);
+#if JAVA_SPEC_VERSION < 17
 jobject JNICALL Java_java_lang_System_getPropertyList (JNIEnv *env, jclass clazz);
+#endif /* JAVA_SPEC_VERSION < 17 */
 jstring JNICALL Java_java_lang_System_mapLibraryName (JNIEnv * env, jclass unusedClass, jstring inName);
 void JNICALL Java_java_lang_System_initLocale (JNIEnv *env, jclass clazz);
 
@@ -800,10 +802,7 @@ jcharArray JNICALL Java_com_ibm_oti_io_NativeCharacterConverter_convertBytesToCh
 
 /* BBjclNativesWin32SystemHelpers*/
 char* getPlatformFileEncoding (JNIEnv *env, char *codepage, int size, int encodingType);
-I_32
-convertToUTF8 (J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size);
 char * getTmpDir (JNIEnv *env, char **tempdir);
-jobject getPlatformPropertyList (JNIEnv *env, const char *strings[], int propIndex);
 void mapLibraryToPlatformName (const char *inPath, char *outPath);
 
 /************************************************************
@@ -813,7 +812,6 @@ void mapLibraryToPlatformName (const char *inPath, char *outPath);
 /* BBjclNativesUNIXSystemHelpers*/
 char *getPlatformFileEncoding (JNIEnv * env, char *codepageProp, int propSize, int encodingType);
 char * getTmpDir (JNIEnv *env, char**envSpace);
-jobject getPlatformPropertyList (JNIEnv * env, const char *strings[], int propIndex);
 void mapLibraryToPlatformName (const char *inPath, char *outPath);
 
 /* orbvmhelpers.c */
diff --git a/runtime/oti/util_api.h b/runtime/oti/util_api.h
index 8cbe8e3aeb3..9e605c155c3 100644
--- a/runtime/oti/util_api.h
+++ b/runtime/oti/util_api.h
@@ -2665,6 +2665,12 @@ j9util_open_system_library(char *name, UDATA *descriptor, UDATA flags);
 
 #endif /*if defined(WIN32)*/
 
+/* ---------------- filehelp.c ---------------- */
+/**
+ * Try to find the 'correct' unix temp directory, as taken from the man page for tmpnam.
+ * As a last resort, '.' representing the current directory is returned.
+ */
+char * getTmpDir(JNIEnv *env, char **envSpace);
 
 #if defined(J9VM_JIT_FREE_SYSTEM_STACK_POINTER)
 /* ---------------- freessp.c ---------------- */
diff --git a/runtime/oti/vm_api.h b/runtime/oti/vm_api.h
index 9ac10a42602..8603835011b 100644
--- a/runtime/oti/vm_api.h
+++ b/runtime/oti/vm_api.h
@@ -4335,6 +4335,14 @@ setSystemPropertyValue(J9JavaVM * vm, J9VMSystemProperty * property, char * newV
  */
 UDATA
 addSystemProperty(J9JavaVM * vm, const char* propName,  const char* propValue, UDATA flags);
+
+/**
+ * @brief Get the default system properties.
+ *
+ * @return an Object array of system property key value pairs
+ */
+jobjectArray getSystemPropertyList(JNIEnv *env);
+
 /* ---------------- vmruntimestate.c ---------------- */
 
 /**
diff --git a/runtime/util/CMakeLists.txt b/runtime/util/CMakeLists.txt
index 394304ae25e..1487fb806a7 100644
--- a/runtime/util/CMakeLists.txt
+++ b/runtime/util/CMakeLists.txt
@@ -116,6 +116,12 @@ elseif(OMR_OS_ZOS)
 	target_sources(j9util PRIVATE zos/freessp.c)
 endif()
 
+if(OMR_OS_WINDOWS)
+	target_sources(j9util PRIVATE win32/filehelp.c)
+else()
+	target_sources(j9util PRIVATE unix/filehelp.c)
+endif()
+
 if(OMR_ARCH_X86)
 	target_sources(j9util
 		PRIVATE
diff --git a/runtime/util/module.xml b/runtime/util/module.xml
index 9e00e0836ea..c246c3bd583 100644
--- a/runtime/util/module.xml
+++ b/runtime/util/module.xml
@@ -50,6 +50,12 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-ex
 			</makefilestub>
 		</makefilestubs>
 		<vpaths>
+			<vpath pattern="filehelp.c" path="unix" augmentObjects="true" type="relativepath">
+				<exclude-if condition="spec.win_x86.*"/>
+			</vpath>
+			<vpath pattern="filehelp.c" path="win32" augmentObjects="true" type="relativepath">
+				<include-if condition="spec.win_x86.*"/>
+			</vpath>
 			<vpath pattern="freessp.c" path="zos" augmentObjects="true" type="relativepath">
 				<include-if condition="spec.zos.*"/>
 			</vpath>
diff --git a/runtime/util/unix/filehelp.c b/runtime/util/unix/filehelp.c
new file mode 100644
index 00000000000..343fbff4ecc
--- /dev/null
+++ b/runtime/util/unix/filehelp.c
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright IBM Corp. and others 2025
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which accompanies this
+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
+ * or the Apache License, Version 2.0 which accompanies this distribution and
+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * This Source Code may also be made available under the following
+ * Secondary Licenses when the conditions for such availability set
+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
+ * General Public License, version 2 with the GNU Classpath
+ * Exception [1] and GNU General Public License, version 2 with the
+ * OpenJDK Assembly Exception [2].
+ *
+ * [1] https://www.gnu.org/software/classpath/license.html
+ * [2] https://openjdk.org/legal/assembly-exception.html
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
+ *******************************************************************************/
+
+#include <stdio.h>
+#include "j9.h"
+
+/**
+ * Try to find the 'correct' unix temp directory, as taken from the man page for tmpnam.
+ * As a last resort, '.' representing the current directory is returned.
+ */
+char *
+getTmpDir(JNIEnv *env, char **envSpace)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	I_32 envSize = j9sysinfo_get_env("TMPDIR", NULL, 0);
+	if (envSize > 0) {
+		*envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+		if (NULL == *envSpace) {
+			return ".";
+		}
+		j9sysinfo_get_env("TMPDIR", *envSpace, envSize);
+		if (j9file_attr(*envSpace) > -1) {
+			return *envSpace;
+		}
+		/* directory was not there, free up memory and continue */
+		j9mem_free_memory(*envSpace);
+		*envSpace = NULL;
+	}
+	if (j9file_attr(P_tmpdir) > -1) {
+		return P_tmpdir;
+	}
+	if (j9file_attr("/tmp") > -1) {
+		return "/tmp";
+	}
+	return ".";
+}
diff --git a/runtime/util/win32/filehelp.c b/runtime/util/win32/filehelp.c
new file mode 100644
index 00000000000..55b241301c0
--- /dev/null
+++ b/runtime/util/win32/filehelp.c
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright IBM Corp. and others 2025
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which accompanies this
+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
+ * or the Apache License, Version 2.0 which accompanies this distribution and
+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * This Source Code may also be made available under the following
+ * Secondary Licenses when the conditions for such availability set
+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
+ * General Public License, version 2 with the GNU Classpath
+ * Exception [1] and GNU General Public License, version 2 with the
+ * OpenJDK Assembly Exception [2].
+ *
+ * [1] https://www.gnu.org/software/classpath/license.html
+ * [2] https://openjdk.org/legal/assembly-exception.html
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
+ *******************************************************************************/
+
+#include <windows.h>
+#include "j9.h"
+
+/**
+ * Try to find the 'correct' windows temp directory.
+ */
+char *
+getTmpDir(JNIEnv *env, char **tempdir)
+{
+	PORT_ACCESS_FROM_ENV(env);
+
+	wchar_t unicodeBuffer[EsMaxPath];
+	char *buffer = NULL;
+	char *retVal = ".";
+	DWORD rc = GetTempPathW(EsMaxPath, unicodeBuffer);
+
+	if ((0 != rc) && (rc < EsMaxPath)) {
+		/* convert */
+		rc = WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeBuffer, -1, NULL, 0, NULL, NULL);
+		if (0 != rc) {
+			buffer = j9mem_allocate_memory(rc, OMRMEM_CATEGORY_VM);
+			if (NULL != buffer) {
+				rc = WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeBuffer, -1, buffer, rc, NULL, NULL);
+				if (0 == rc) {
+					j9mem_free_memory(buffer);
+					buffer = NULL;
+				} else {
+					retVal = buffer;
+				}
+			}
+		}
+	}
+	*tempdir = buffer;
+	return retVal;
+}
diff --git a/runtime/vm/intfunc.c b/runtime/vm/intfunc.c
index 5cfdd0003fe..79558bccedd 100644
--- a/runtime/vm/intfunc.c
+++ b/runtime/vm/intfunc.c
@@ -484,4 +484,5 @@ J9InternalVMFunctions J9InternalFunctions = {
 	monitorTablePeek,
 	takeVirtualThreadListToUnblock,
 #endif /* JAVA_SPEC_VERSION >= 24 */
+	getSystemPropertyList,
 };
diff --git a/runtime/vm/j9vm.tdf b/runtime/vm/j9vm.tdf
index 5447aeb934d..c7d04229b2a 100644
--- a/runtime/vm/j9vm.tdf
+++ b/runtime/vm/j9vm.tdf
@@ -1017,3 +1017,5 @@ TraceEntry=Trc_VM_getTypeIdUTF8_Entry Overhead=1 Level=5 Template="getTypeIdUTF8
 TraceExit=Trc_VM_getTypeIdUTF8_Exit Overhead=1 Level=5 Template="getTypeIdUTF8 className %.*s clazz=%p result=%lli"
 TraceEntry=Trc_VM_getTypeId_Entry Overhead=1 Level=5 Template="getTypeId clazz=%p"
 TraceExit=Trc_VM_getTypeId_Exit Overhead=1 Level=5 Template="getTypeId clazz=%p result=%lli"
+
+TraceEvent=Trc_systemPropertyIterator Overhead=1 Level=10 Template="systemPropertyIterator: added VM system property '%s'='%s'"
diff --git a/runtime/vm/vmprops.c b/runtime/vm/vmprops.c
index 74f0f9327ec..5e4db9c54c3 100644
--- a/runtime/vm/vmprops.c
+++ b/runtime/vm/vmprops.c
@@ -20,6 +20,13 @@
  * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
  *******************************************************************************/
 
+#if defined(WIN32)
+#include <windows.h>
+#else /* defined(WIN32) */
+#include <pwd.h>
+#include <unistd.h>
+#endif /* defined(WIN32) */
+
 #include <string.h>
 #include "j9protos.h"
 #include "j9port.h"
@@ -32,24 +39,28 @@
 #include "vmargs_api.h"
 #include "vendor_version.h"
 
+#if defined(J9ZOS390)
+#include "atoe.h"
+#endif /* defined(J9ZOS390) */
+
 #if defined(LINUX)
 /* Copy the system properties names and values into malloced memory */
 static void copySystemProperties(J9JavaVM* vm);
 #endif /* defined(LINUX) */
 
-static U_8*  unicodeEscapeStringToMUtf8(J9JavaVM * vm, const char* escapeString, UDATA escapeLength);
+static U_8 *unicodeEscapeStringToMUtf8(J9JavaVM *vm, const char *escapeString, UDATA escapeLength);
 static UDATA getLibSubDir(J9JavaVM *VM, const char *subDir, char **value);
 
 #define JAVA_ENDORSED_DIRS "java.endorsed.dirs"
 #define JAVA_EXT_DIRS "java.ext.dirs"
 
-UDATA addSystemProperty(J9JavaVM * vm, const char* propName,  const char* propValue, UDATA flags);
-static char * getOptionArg(J9JavaVM *vm, IDATA argIndex, UDATA optionNameLen);
+UDATA addSystemProperty(J9JavaVM *vm, const char *propName,  const char *propValue, UDATA flags);
+static char *getOptionArg(J9JavaVM *vm, IDATA argIndex, UDATA optionNameLen);
 static UDATA addPropertyForOptionWithPathArg(J9JavaVM *vm, const char *optionName, UDATA optionNameLen, const char *propName);
 static UDATA addPropertyForOptionWithModuleListArg(J9JavaVM *vm, const char *optionName, IDATA optionNameLen, const char *propName);
 static UDATA addPropertiesForOptionWithAssignArg(J9JavaVM *vm, const char *optionName, UDATA optionNameLen, const char *basePropName, UDATA basePropNameLen, UDATA *propertyCount);
 static UDATA addPropertyForOptionWithEqualsArg(J9JavaVM *vm, const char *optionName, UDATA optionNameLen, const char *propName);
-static UDATA addModularitySystemProperties(J9JavaVM * vm);
+static UDATA addModularitySystemProperties(J9JavaVM *vm);
 
 /*
  * Create a copy of the given string in allocated memory.
@@ -168,7 +179,7 @@ getOptionArg(J9JavaVM *vm, IDATA argIndex, UDATA optionNameLen)
 {
 	char *option = NULL;
 	char *optionArg = NULL;
-	J9VMInitArgs* j9vm_args = vm->vmArgsArray;
+	J9VMInitArgs *j9vm_args = vm->vmArgsArray;
 
 	if ((argIndex < 0) || ((UDATA)argIndex >= vm->vmArgsArray->nOptions)) {
 		goto _end;
@@ -315,7 +326,7 @@ addPropertyForOptionWithModuleListArg(J9JavaVM *vm, const char *optionName, IDAT
 {
 	IDATA argIndex = -1;
 	UDATA rc = J9SYSPROP_ERROR_NONE;
-	J9VMInitArgs* j9vm_args	= vm->vmArgsArray;
+	J9VMInitArgs *j9vm_args = vm->vmArgsArray;
 	PORT_ACCESS_FROM_JAVAVM(vm);
 
 	argIndex = FIND_ARG_IN_VMARGS_FORWARD(OPTIONAL_LIST_MATCH_USING_EQUALS, optionName, NULL);
@@ -461,7 +472,7 @@ addPropertiesForOptionWithAssignArg(J9JavaVM *vm, const char *optionName, UDATA
  * @return returns J9SYSPROP_ERROR_NONE on success, any other J9SYSPROP_ERROR code on failure
  */
 static UDATA
-addModularitySystemProperties(J9JavaVM * vm)
+addModularitySystemProperties(J9JavaVM *vm)
 {
 	UDATA rc = J9SYSPROP_ERROR_NONE;
 
@@ -559,7 +570,7 @@ getLibSubDir(J9JavaVM *vm, const char *subDir, char **value)
 
 	rc = getSystemProperty(vm, "java.home", &javaHomeProp);
 	if (J9SYSPROP_ERROR_NONE == rc) {
-		char* libSubDir = j9mem_allocate_memory(strlen(javaHomeProp->value) + LITERAL_STRLEN(DIR_SEPARATOR_STR) + LITERAL_STRLEN("lib") + LITERAL_STRLEN(DIR_SEPARATOR_STR) + strlen(subDir) + 1, OMRMEM_CATEGORY_VM);
+		char *libSubDir = j9mem_allocate_memory(strlen(javaHomeProp->value) + LITERAL_STRLEN(DIR_SEPARATOR_STR) + LITERAL_STRLEN("lib") + LITERAL_STRLEN(DIR_SEPARATOR_STR) + strlen(subDir) + 1, OMRMEM_CATEGORY_VM);
 		if (NULL == libSubDir) {
 			rc = J9SYSPROP_ERROR_OUT_OF_MEMORY;
 			goto _end;
@@ -586,7 +597,7 @@ getLibSubDir(J9JavaVM *vm, const char *subDir, char **value)
  * @return On success J9SYSPROP_ERROR_NONE, otherwise a J9SYSPROP_ERR constant.
  */
 UDATA
-initializeSystemProperties(J9JavaVM * vm)
+initializeSystemProperties(J9JavaVM *vm)
 {
 	PORT_ACCESS_FROM_JAVAVM(vm);
 
@@ -595,22 +606,22 @@ initializeSystemProperties(J9JavaVM * vm)
 	JavaVMInitArgs *initArgs = NULL;
 	char *jclName = J9_JAVA_SE_DLL_NAME;
 	UDATA j2seVersion = J2SE_VERSION(vm);
-	const char* propValue = NULL;
+	const char *propValue = NULL;
 	UDATA rc = J9SYSPROP_ERROR_NONE;
 	const char *specificationVersion = NULL;
 	BOOLEAN addManagementModule = FALSE;
 
-	if (omrthread_monitor_init(&(vm->systemPropertiesMutex), 0) != 0) {
+	if (0 != omrthread_monitor_init(&(vm->systemPropertiesMutex), 0)) {
 		return J9SYSPROP_ERROR_OUT_OF_MEMORY;
 	}
 
 	/* Count the number of -D properties and find the JCL config */
 	initArgs = vm->vmArgsArray->actualVMArgs;
 	for (i = 0; i < initArgs->nOptions; ++i) {
-		char * optionString = initArgs->options[i].optionString;
+		char *optionString = initArgs->options[i].optionString;
 		Assert_VM_notNull(optionString);
 
-		if (strncmp("-Xjcl:", optionString, 6) == 0) {
+		if (0 == strncmp("-Xjcl:", optionString, 6)) {
 			jclName = optionString + 6;
 		}
 	}
@@ -621,7 +632,8 @@ initializeSystemProperties(J9JavaVM * vm)
 	}
 
 	/* Allocate the properties pool */
-	if ((vm->systemProperties = pool_new(sizeof(J9VMSystemProperty), 0, 0, 0, J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM, POOL_FOR_PORT(vm->portLibrary))) == NULL) {
+	vm->systemProperties = pool_new(sizeof(J9VMSystemProperty), 0, 0, 0, J9_GET_CALLSITE(), OMRMEM_CATEGORY_VM, POOL_FOR_PORT(vm->portLibrary));
+	if (NULL == vm->systemProperties) {
 		return J9SYSPROP_ERROR_OUT_OF_MEMORY;
 	}
 
@@ -632,7 +644,7 @@ initializeSystemProperties(J9JavaVM * vm)
 		}
 	}
 
-	if (JAVA_SPEC_VERSION == 8) {
+	if (8 == JAVA_SPEC_VERSION) {
 		specificationVersion = "1.8";
 	} else {
 		specificationVersion = JAVA_SPEC_VERSION_STRING;
@@ -656,7 +668,7 @@ initializeSystemProperties(J9JavaVM * vm)
 	}
 	{
 		const char *classVersion = NULL;
-		if (JAVA_SPEC_VERSION == 8) {
+		if (8 == JAVA_SPEC_VERSION) {
 			classVersion = "52.0";
 		} else {
 			classVersion = "55.0"; /* Java 11 */
@@ -746,14 +758,14 @@ initializeSystemProperties(J9JavaVM * vm)
 	if (J9SYSPROP_ERROR_NONE != rc) {
 		goto fail;
 	}
-#endif
+#endif /* defined(J9JDK_EXT_NAME) */
 
 #if defined(J9JDK_EXT_VERSION)
 	rc = addSystemProperty(vm, "jdk.extensions.version", J9JDK_EXT_VERSION, 0);
 	if (J9SYSPROP_ERROR_NONE != rc) {
 		goto fail;
 	}
-#endif
+#endif /* defined(J9JDK_EXT_VERSION) */
 
 #if JAVA_SPEC_VERSION < 21
 	/* Don't know the JIT yet, put in a placeholder and make it writeable for now */
@@ -766,9 +778,9 @@ initializeSystemProperties(J9JavaVM * vm)
 	/* We don't have enough information yet. Put in placeholders. */
 #if defined(J9VM_OPT_SIDECAR) && !defined(WIN32)
 	propValue = "../..";
-#else
+#else /* defined(J9VM_OPT_SIDECAR) && !defined(WIN32) */
 	propValue = "..";
-#endif
+#endif /* defined(J9VM_OPT_SIDECAR) && !defined(WIN32) */
 	rc = addSystemProperty(vm, "java.home", propValue, J9SYSPROP_FLAG_WRITEABLE);
 	if (J9SYSPROP_ERROR_NONE != rc) {
 		goto fail;
@@ -796,12 +808,12 @@ initializeSystemProperties(J9JavaVM * vm)
 	if (J9SYSPROP_ERROR_NONE != rc) {
 		goto fail;
 	}
-#endif
+#endif /* defined(J9VM_OPT_SIDECAR) */
 
 	/* Figure out the path separator by querying port library */
 	{
-		char *pathSep = (char*) j9mem_allocate_memory(2, OMRMEM_CATEGORY_VM);
-		if (pathSep == NULL) {
+		char *pathSep = (char *)j9mem_allocate_memory(2, OMRMEM_CATEGORY_VM);
+		if (NULL == pathSep) {
 			return J9SYSPROP_ERROR_OUT_OF_MEMORY;
 		}
 		pathSep[0] = (char) j9sysinfo_get_classpathSeparator();
@@ -911,16 +923,16 @@ initializeSystemProperties(J9JavaVM * vm)
 	/* Create the -D properties. This may override any of the writeable properties above.
 	    Should the command line override read-only props? */
 	for (i = 0; i < initArgs->nOptions; ++i) {
-		char * optionString = initArgs->options[i].optionString;
+		char *optionString = initArgs->options[i].optionString;
 
-		if (strncmp("-D", optionString, 2) == 0) {
+		if (0 == strncmp("-D", optionString, 2)) {
 			J9VMSystemProperty *currentProp = NULL;
 			char *propNameCopy = NULL;
 			char *propValueCopy = NULL;
 			UDATA propNameLen = 0;
 
 			propValue = strchr(optionString + 2, '=');
-			if (propValue == NULL) {
+			if (NULL == propValue) {
 				propNameLen = strlen(optionString) - 2;
 				propValue = optionString + 2 + propNameLen;
 			} else {
@@ -970,7 +982,7 @@ initializeSystemProperties(J9JavaVM * vm)
 				}
 			}
 
-			if (getSystemProperty(vm, propNameCopy, &currentProp) == J9SYSPROP_ERROR_NONE) {
+			if (J9SYSPROP_ERROR_NONE == getSystemProperty(vm, propNameCopy, &currentProp)) {
 				/* We already have a property of the given name, free the propNameCopy buffer */
 				j9mem_free_memory(propNameCopy);
 
@@ -1024,8 +1036,8 @@ initializeSystemProperties(J9JavaVM * vm)
 		}
 	} else {
 		/* look for java.endorsed.dirs and set if not set */
-		if ( getSystemProperty(vm, JAVA_ENDORSED_DIRS, &javaEndorsedDirsProperty) != J9SYSPROP_ERROR_NONE ) {
-			char *defaultEndorsedDir =  NULL;
+		if (J9SYSPROP_ERROR_NONE != getSystemProperty(vm, JAVA_ENDORSED_DIRS, &javaEndorsedDirsProperty)) {
+			char *defaultEndorsedDir = NULL;
 
 			rc = getLibSubDir(vm, "endorsed", &defaultEndorsedDir);
 			if (NULL != defaultEndorsedDir) {
@@ -1117,14 +1129,14 @@ initializeSystemProperties(J9JavaVM * vm)
 
 
 void
-freeSystemProperties(J9JavaVM * vm)
+freeSystemProperties(J9JavaVM *vm)
 {
 	if (NULL != vm->systemProperties) {
 		PORT_ACCESS_FROM_JAVAVM(vm);
 		pool_state walkState;
 
 		J9VMSystemProperty* property = pool_startDo(vm->systemProperties, &walkState);
-		while (property != NULL) {
+		while (NULL != property) {
 			if (property->flags & J9SYSPROP_FLAG_NAME_ALLOCATED) {
 				j9mem_free_memory(property->name);
 			}
@@ -1145,13 +1157,13 @@ freeSystemProperties(J9JavaVM * vm)
 
 
 UDATA
-getSystemProperty(J9JavaVM * vm, const char * name, J9VMSystemProperty ** propertyPtr)
+getSystemProperty(J9JavaVM *vm, const char *name, J9VMSystemProperty **propertyPtr)
 {
 	pool_state walkState;
 
-	J9VMSystemProperty* property = pool_startDo(vm->systemProperties, &walkState);
-	while (property != NULL) {
-		if (strcmp(property->name, name) == 0) {
+	J9VMSystemProperty *property = pool_startDo(vm->systemProperties, &walkState);
+	while (NULL != property) {
+		if (0 == strcmp(property->name, name)) {
 			if (NULL != propertyPtr) {
 				*propertyPtr = property;
 			}
@@ -1174,21 +1186,21 @@ getJ9VMVersionString(J9JavaVM *vm) {
 
 
 UDATA
-addSystemProperty(J9JavaVM * vm, const char* propName,  const char* propValue, UDATA flags)
+addSystemProperty(J9JavaVM *vm, const char *propName, const char *propValue, UDATA flags)
 {
-	J9VMSystemProperty* newProp = pool_newElement(vm->systemProperties);
+	J9VMSystemProperty *newProp = pool_newElement(vm->systemProperties);
 	if (NULL == newProp) {
 		return J9SYSPROP_ERROR_OUT_OF_MEMORY;
 	}
 
-	newProp->name = (char*)propName;
-	newProp->value = (char*)propValue;
+	newProp->name = (char *)propName;
+	newProp->value = (char *)propValue;
 	newProp->flags = flags;
 	return J9SYSPROP_ERROR_NONE;
 }
 
 UDATA
-setSystemPropertyValue(J9JavaVM * vm, J9VMSystemProperty * property, char * newValue, BOOLEAN allocated)
+setSystemPropertyValue(J9JavaVM *vm, J9VMSystemProperty *property, char *newValue, BOOLEAN allocated)
 {
 	/* Make sure the property is writeable */
 
@@ -1210,7 +1222,7 @@ setSystemPropertyValue(J9JavaVM * vm, J9VMSystemProperty * property, char * newV
 			property->flags |= J9SYSPROP_FLAG_VALUE_ALLOCATED;
 		}
 		property->value = newValue;
-		if (strcmp(property->name, "java.home") == 0) {
+		if (0 == strcmp(property->name, "java.home")) {
 			vm->javaHome = (U_8*)newValue;
 		}
 	}
@@ -1218,7 +1230,7 @@ setSystemPropertyValue(J9JavaVM * vm, J9VMSystemProperty * property, char * newV
 }
 
 UDATA
-setSystemProperty(J9JavaVM * vm, J9VMSystemProperty * property, const char * value)
+setSystemProperty(J9JavaVM *vm, J9VMSystemProperty *property, const char *value)
 {
 	/* Make sure the property is writeable */
 
@@ -1230,7 +1242,7 @@ setSystemProperty(J9JavaVM * vm, J9VMSystemProperty * property, const char * val
 
 	if (NULL != value) {
 		/* Make a copy of the value */
-		char * copiedValue = copyToMem(vm, value);
+		char *copiedValue = copyToMem(vm, value);
 
 		if (NULL == copiedValue) {
 			return J9SYSPROP_ERROR_OUT_OF_MEMORY;
@@ -1249,12 +1261,12 @@ setSystemProperty(J9JavaVM * vm, J9VMSystemProperty * property, const char * val
  * @return buffer containing the transliterated string or NULL in case of error
  */
 #define TRANSCODE_BUFFER_SIZE 64
-static U_8*
-unicodeEscapeStringToMUtf8(J9JavaVM * vm, const char* escapeString, UDATA escapeLength) {
+static U_8 *
+unicodeEscapeStringToMUtf8(J9JavaVM *vm, const char *escapeString, UDATA escapeLength) {
 	U_16 localUnicodeBuffer[TRANSCODE_BUFFER_SIZE]; /* handle short strings without allocating memory */
-	U_16* unicodeBuffer = localUnicodeBuffer;
-	UDATA bufferLength = (escapeLength+1)*2; /* This is an overestimate */
-	const char *cursor;
+	U_16 *unicodeBuffer = localUnicodeBuffer;
+	UDATA bufferLength = (escapeLength + 1) * 2; /* This is an overestimate */
+	const char *cursor = NULL;
 	const char *escapeStringEnd = escapeString + escapeLength;
 	IDATA unicodeDigitCounter = -1; /* for walking through "\\u1234" */
 	U_16 currentChar = 0;
@@ -1267,7 +1279,7 @@ unicodeEscapeStringToMUtf8(J9JavaVM * vm, const char* escapeString, UDATA escape
 	PORT_ACCESS_FROM_JAVAVM(vm);
 
 	if (bufferLength > TRANSCODE_BUFFER_SIZE) {
-		unicodeBuffer = (U_16*) j9mem_allocate_memory(bufferLength, OMRMEM_CATEGORY_VM);
+		unicodeBuffer = (U_16 *)j9mem_allocate_memory(bufferLength, OMRMEM_CATEGORY_VM);
 		if (NULL == unicodeBuffer) {
 			return NULL;
 		}
@@ -1275,7 +1287,7 @@ unicodeEscapeStringToMUtf8(J9JavaVM * vm, const char* escapeString, UDATA escape
 
 	cursor = escapeString;
 	while (cursor < escapeStringEnd) {
-		if (cursor[0]=='\\' && cursor[1]=='u') {
+		if (('\\' == cursor[0]) && ('u' == cursor[1])) {
 			slashChar = cursor[0];
 			unicodeDigitCounter = 0;
 			cursor += 2;
@@ -1317,14 +1329,14 @@ unicodeEscapeStringToMUtf8(J9JavaVM * vm, const char* escapeString, UDATA escape
 		cursor++;
 	}
 
-	mutf8Size = j9str_convert(J9STR_CODE_WIDE, J9STR_CODE_MUTF8, (char*)unicodeBuffer, unicodeCharacterCounter*2,
+	mutf8Size = j9str_convert(J9STR_CODE_WIDE, J9STR_CODE_MUTF8, (char *)unicodeBuffer, unicodeCharacterCounter * 2,
 			NULL, 0); /* get the size of the MUTF8 */
 	if (mutf8Size >= 0) {
 		++mutf8Size; /* leave enough space to null-terminate the string */
 		result = j9mem_allocate_memory(mutf8Size, OMRMEM_CATEGORY_VM); /* allow room for terminating null */
 		if (NULL != result) {
-			mutf8Size = j9str_convert(J9STR_CODE_WIDE, J9STR_CODE_MUTF8, (char*)unicodeBuffer, unicodeCharacterCounter*2,
-					(char*)result, mutf8Size);
+			mutf8Size = j9str_convert(J9STR_CODE_WIDE, J9STR_CODE_MUTF8, (char *)unicodeBuffer, unicodeCharacterCounter * 2,
+					(char *)result, mutf8Size);
 			if (mutf8Size < 0) {
 				j9mem_free_memory(result);
 				result = NULL;
@@ -1361,8 +1373,8 @@ containsBackslashU(const char *userString, UDATA stringLength) {
 	if (stringLength > 0) {
 		U_32 cursor = 0;
 		for (cursor = 0; cursor < (stringLength-1); cursor++) {
-			if (('\\' == userString[cursor]) && ('u' == userString[cursor+1])) {
-				/* cursor+1 is safe because the loop stops one character before the end */
+			if (('\\' == userString[cursor]) && ('u' == userString[cursor + 1])) {
+				/* cursor + 1 is safe because the loop stops one character before the end */
 				return TRUE;
 			}
 		}
@@ -1433,3 +1445,647 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env);
+}
+
+typedef struct {
+	jboolean errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData *iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = JNI_TRUE;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = JNI_TRUE;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jarray args = NULL;
+	int propertyCount = 0;
+	jclass stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (NULL == stringClass) {
+		return NULL;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (0 != propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = JNI_FALSE;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary *portLibrary, const wchar_t *unicodeString, char *utf8Buffer, UDATA size)
+{
+	PORT_ACCESS_FROM_PORT(portLibrary);
+	if (0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
+		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
+		return -1;
+	}
+	return 0;
+}
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
+	OSVERSIONINFO versionInfo;
+#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
+	I_32 envSize = 0;
+	char *envSpace = NULL;
+	char *tempdir = NULL;
+	jobject result = NULL;
+	char userhome[EsMaxPath];
+	wchar_t unicodeTemp[EsMaxPath];
+	int i = 0;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath];
+#endif /* JAVA_SPEC_VERSION < 17 */
+	wchar_t unicodeHome[EsMaxPath];
+	HANDLE process = 0;
+	HANDLE token = 0;
+	UDATA handle = 0;
+	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
+
+	/* Hard coded file/path separators and other values */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "\\";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\r\n";
+
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &tempdir);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	i = propIndex;
+	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
+	if (-1 != envSize) {
+		envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+		if (NULL == envSpace) {
+			strings[propIndex++] = "\\";
+		} else {
+			j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
+			strings[propIndex++] = envSpace;
+		}
+	}
+#if defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE)
+	/* dwPlatformId, VER_PLATFORM_WIN32_NT = https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
+	if ((i == propIndex) && IsWindowsVersionOrGreater(5, 0, 0))
+#else /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+#pragma warning(suppress : 4996) /* ignore warning 'GetVersionExA': was declared deprecated */
+	if ((i == propIndex) && GetVersionEx(&versionInfo) && (VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId))
+#endif /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	{
+		process = GetCurrentProcess();
+		if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
+			envSize = 0;
+			if (0 == j9util_open_system_library("userenv", &handle, TRUE)) {
+				if (i == propIndex) {
+					if (0 == j9sl_lookup_name(handle, "GetUserProfileDirectoryW", (UDATA *)&func, "ZPLP")) {
+						envSize = EsMaxPath;
+						if (func(token, unicodeHome, &envSize)) {
+							/* When the SystemDrive environment variable isn't set, such as when j9 is exec'ed
+							 * running JCK tests, we get %SystemDrive%/Documents and Settings/...
+							 */
+							if (0 == wcsncmp(unicodeHome, L"%SystemDrive%", 13)) {
+								/* Borrow userdir variable, which is used for real below */
+								if (GetSystemDirectoryW(unicodeTemp, EsMaxPath) > 1) {
+									unicodeHome[0] = unicodeTemp[0];
+									unicodeHome[1] = unicodeTemp[1];
+									wcsncpy(&unicodeHome[2], &unicodeHome[13], envSize - 13);
+								}
+							}
+							convertToUTF8(PORTLIB, unicodeHome, userhome, EsMaxPath);
+							strings[propIndex++] = userhome;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (i == propIndex) {
+		/* Fallback to Windows Directory */
+		envSize = (I_32)j9sysinfo_get_env("WINDIR", NULL, 0);
+		if (-1 == envSize) {
+			strings[propIndex++] = "\\";
+		} else {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM);	/* trailing null taken into account */
+			if (NULL == envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("WINDIR", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+		}
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	if (0 == GetCurrentDirectoryW(EsMaxPath, unicodeTemp)) {
+		strings[propIndex++] = "\\";
+	} else {
+		convertToUTF8(PORTLIB, unicodeTemp, userdir, EsMaxPath);
+		strings[propIndex++] = userdir;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	result = createSystemPropertyList(env, strings, propIndex);
+	j9mem_free_memory(tempdir);
+	j9mem_free_memory(envSpace);
+	return result;
+}
+
+#else /* defined(WIN32) */
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	char *charResult = NULL;
+	char *envSpace = NULL;
+	jobject plist = NULL;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath] = {0};
+#endif /* JAVA_SPEC_VERSION < 17 */
+	char home[EsMaxPath] = {0};
+	char *homeAlloc = NULL;
+	J9VMThread *currentThread = (J9VMThread*)env;
+	J9JavaVM *vm = currentThread->javaVM;
+	J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
+
+	/* Hard coded file/path separators and other values */
+
+#if defined(J9ZOS390)
+	if (J2SE_VERSION_FROM_ENV(env)) {
+		strings[propIndex++] = "platform.notASCII";
+		strings[propIndex++] = "true";
+
+		strings[propIndex++] = "os.encoding";
+		strings[propIndex++] = "ISO8859_1";
+	}
+#endif /* defined(J9ZOS390) */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "/";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\n";
+
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	charResult = getcwd(userdir, EsMaxPath);
+	if (NULL == charResult) {
+		strings[propIndex++] = ".";
+	} else {
+		strings[propIndex++] = charResult;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	charResult = NULL;
+#if defined(J9ZOS390)
+	charResult = getenv("HOME");
+	if (NULL != charResult) {
+		strings[propIndex++] = charResult;
+	} else {
+		uid_t uid = geteuid();
+		if (0 != uid) {
+			struct passwd *userDescription = getpwuid(uid);
+			if (NULL != userDescription) {
+				charResult = userDescription->pw_dir;
+				strings[propIndex++] = charResult;
+			}
+		} else {
+			char *loginID = getlogin();
+			if (NULL != loginID) {
+				struct passwd *userDescription = getpwnam(loginID);
+				if (NULL != userDescription) {
+					charResult = userDescription->pw_dir;
+					strings[propIndex++] = charResult;
+				}
+			}
+		}
+	}
+
+	/* There exist situations where one of the above calls will fail.
+	 * Fall through to the Unix solution for those cases.
+	 */
+#endif /* defined(J9ZOS390) */
+#if defined(J9VM_OPT_CRIU_SUPPORT)
+	/* Skip getpwuid if a checkpoint can be taken.
+	 * https://github.com/eclipse-openj9/openj9/issues/15800
+	 */
+	if (!vmFuncs->isCheckpointAllowed(vm))
+#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */
+	{
+		/*[PR 101939] user.home not set correctly when j9 invoked via execve(x,y,null) */
+		if (NULL == charResult) {
+			struct passwd *pwentry = getpwuid(getuid());
+			if (NULL != pwentry) {
+				charResult = pwentry->pw_dir;
+				strings[propIndex++] = charResult;
+			}
+		}
+	}
+
+	if (NULL == charResult) {
+		IDATA result = j9sysinfo_get_env("HOME", home, sizeof(home));
+		strings[propIndex] = ".";
+		if (0 == result) {
+			if (strlen(home) > 0) {
+				strings[propIndex] = home;
+			}
+		} else if (result > 0) {
+			homeAlloc = j9mem_allocate_memory(result, OMRMEM_CATEGORY_VM);
+			if (NULL != homeAlloc) {
+				result = j9sysinfo_get_env("HOME", homeAlloc, result);
+				if (0 == result) {
+					strings[propIndex] = homeAlloc;
+				}
+			} else {
+				vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
+				goto failed;
+			}
+		}
+		propIndex += 1;
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &envSpace);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	plist = createSystemPropertyList(env, strings, propIndex);
+	if (NULL != envSpace) {
+		j9mem_free_memory(envSpace);
+	}
+
+failed:
+	if (NULL != homeAlloc) {
+		j9mem_free_memory(homeAlloc);
+	}
+	return plist;
+}
+
+#endif /* defined(WIN32) */
+
+/**
+ * @brief Get the default system properties.
+ *
+ * @return an Object array of system property key value pairs
+ */
+jobjectArray
+getSystemPropertyList(JNIEnv *env)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	int propIndex = 0;
+	jobject propertyList = NULL;
+#define PROPERTY_COUNT 137
+#if JAVA_SPEC_VERSION < 17
+	char *propertyKey = NULL;
+	const char *language = NULL;
+	const char *region = NULL;
+	const char *variant = NULL;
+#endif /* JAVA_SPEC_VERSION < 17 */
+	const char *strings[PROPERTY_COUNT] = {0};
+#define USERNAME_LENGTH 128
+	char username[USERNAME_LENGTH] = {0};
+	char *usernameAlloc = NULL;
+	/* buffer to hold the size of the maximum direct byte buffer allocations */
+	char maxDirectMemBuff[24] = {0};
+	IDATA result = 0;
+
+	J9VMThread *currentThread = (J9VMThread *)env;
+	J9JavaVM *javaVM = currentThread->javaVM;
+	J9InternalVMFunctions *vmFuncs = javaVM->internalVMFunctions;
+
+	/* Change the allocation value PROPERTY_COUNT above as you add/remove properties,
+	 * then follow the propIndex++ convention and consume 2 * slots for each property.
+	 * 2 * number of property keys is the correct allocation. Also note the call to
+	 * addSystemProperties below, which may add some configuration-specific properties.
+	 * Be sure to leave enough room in the property list for all possibilities.
+	 */
+
+	if (J9_GC_POLICY_METRONOME == javaVM->omrVM->gcPolicy) {
+		strings[propIndex++] = "com.ibm.jvm.realtime";
+		strings[propIndex++] = "soft";
+	}
+
+#if defined(J9VM_OPT_SHARED_CLASSES)
+	strings[propIndex++] = "com.ibm.oti.shared.enabled";
+	if ((NULL != javaVM->sharedClassConfig)
+		&& J9_ARE_ALL_BITS_SET(javaVM->sharedClassConfig->runtimeFlags, J9SHR_RUNTIMEFLAG_ENABLE_CACHE_NON_BOOT_CLASSES)
+	) {
+		strings[propIndex++] = "true";
+	} else {
+		strings[propIndex++] = "false";
+	}
+#endif /* defined(J9VM_OPT_SHARED_CLASSES) */
+
+	strings[propIndex++] = "ibm.signalhandling.sigchain";
+	if (J9_ARE_ANY_BITS_SET(javaVM->sigFlags, J9_SIG_NO_SIG_CHAIN)) {
+		strings[propIndex++] = "false";
+	} else {
+		strings[propIndex++] = "true";
+	}
+	strings[propIndex++] = "ibm.signalhandling.sigint";
+	if (J9_ARE_ANY_BITS_SET(javaVM->sigFlags, J9_SIG_NO_SIG_INT)) {
+		strings[propIndex++] = "false";
+	} else {
+		strings[propIndex++] = "true";
+	}
+
+	/* The JCLs use ibm.signalhandling.rs to determine if they should prevent the
+	 * registration of signal handlers for what we consider to be asynchronous signals.
+	 * The JCLs do not install handlers for any synchronous signals.
+	 */
+	strings[propIndex++] = "ibm.signalhandling.rs";
+	if (J9_ARE_ALL_BITS_SET(javaVM->sigFlags, J9_SIG_XRS_ASYNC)) {
+		strings[propIndex++] = "true";
+	} else {
+		strings[propIndex++] = "false";
+	}
+
+	strings[propIndex++] = "com.ibm.vm.bitmode";
+#if defined(J9VM_ENV_DATA64)
+	strings[propIndex++] = "64";
+#else /* defined(J9VM_ENV_DATA64) */
+	strings[propIndex++] = "32";
+#endif /* defined(J9VM_ENV_DATA64) */
+
+	strings[propIndex++] = "com.ibm.cpu.endian";
+#if defined(J9VM_ENV_LITTLE_ENDIAN)
+	strings[propIndex++] = "little";
+#else /* defined(J9VM_ENV_LITTLE_ENDIAN) */
+	strings[propIndex++] = "big";
+#endif /* defined(J9VM_ENV_LITTLE_ENDIAN) */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "sun.cpu.endian";
+#if defined(J9VM_ENV_LITTLE_ENDIAN)
+	strings[propIndex++] = "little";
+#else /* defined(J9VM_ENV_LITTLE_ENDIAN) */
+	strings[propIndex++] = "big";
+#endif /* defined(J9VM_ENV_LITTLE_ENDIAN) */
+
+	/* Get the language, region and variant */
+	language = j9nls_get_language();
+	region = j9nls_get_region();
+	variant = j9nls_get_variant();
+
+	/* CMVC 144405 : Norwegian Bokmal and Nynorsk need special consideration */
+	if ((0 == strcmp(language, "nn")) && (0 == strcmp(region, "NO"))) {
+		variant = "NY";
+	}
+	if ((0 == strcmp(language, "nn")) || (0 == strcmp(language, "nb"))) {
+		language = "no";
+	}
+
+	strings[propIndex++] = "user.language";
+	strings[propIndex++] = language;
+
+	propertyKey = "user.country";
+	strings[propIndex++] = propertyKey;
+	strings[propIndex++] = region;
+
+	/* Get the variant */
+	strings[propIndex++] = "user.variant";
+	strings[propIndex++] = variant;
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	/* Get the User name */
+	strings[propIndex++] = "user.name";
+	strings[propIndex] = "unknown";
+#if defined(J9VM_OPT_CRIU_SUPPORT)
+	/* Skip j9sysinfo_get_username if a checkpoint can be taken.
+	 * https://github.com/eclipse-openj9/openj9/issues/15800
+	 */
+	result = -1;
+	if (!vmFuncs->isCheckpointAllowed(javaVM))
+#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */
+	{
+		result = j9sysinfo_get_username(username, USERNAME_LENGTH);
+		if (0 == result) {
+			strings[propIndex] = username;
+		} else if (result > 0) {
+			usernameAlloc = j9mem_allocate_memory(result, OMRMEM_CATEGORY_VM);
+			if (NULL != usernameAlloc) {
+				result = j9sysinfo_get_username(usernameAlloc, result);
+				if (0 == result) {
+					strings[propIndex] = usernameAlloc;
+				} else {
+					/* free the memory, try j9sysinfo_get_env later */
+					j9mem_free_memory(usernameAlloc);
+					usernameAlloc = NULL;
+				}
+			} else {
+				vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
+				goto failed;
+			}
+		}
+	}
+#if defined(LINUX) || defined(OSX)
+	if (0 != result) {
+		result = j9sysinfo_get_env("USER", username, USERNAME_LENGTH);
+		if (0 == result) {
+			strings[propIndex] = username;
+		} else if (result > 0) {
+			usernameAlloc = j9mem_allocate_memory(result, OMRMEM_CATEGORY_VM);
+			if (NULL != usernameAlloc) {
+				result = j9sysinfo_get_env("USER", usernameAlloc, result);
+				if (0 == result) {
+					if (strlen(usernameAlloc) > 0) {
+						strings[propIndex] = usernameAlloc;
+					}
+					/* keep it as "unknown" if the env value is empty */
+				}
+				/* usernameAlloc to be freed before this method returns */
+			} else {
+				vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
+				goto failed;
+			}
+		}
+	}
+#endif /* defined(LINUX) || defined(OSX) */
+	propIndex += 1;
+#undef USERNAME_LENGTH
+
+#if defined(OPENJ9_BUILD) && (JAVA_SPEC_VERSION == 8)
+	/* Set the maximum direct byte buffer allocation property if it has not been set manually */
+	if ((~(UDATA)0) == javaVM->directByteBufferMemoryMax) {
+		UDATA heapSize = javaVM->memoryManagerFunctions->j9gc_get_maximum_heap_size(javaVM);
+		/* allow up to 7/8 of the heap to be direct byte buffers */
+		javaVM->directByteBufferMemoryMax = heapSize - (heapSize / 8);
+	}
+#endif /* defined(OPENJ9_BUILD) && (JAVA_SPEC_VERSION == 8) */
+#if !defined(OPENJ9_BUILD)
+	/* Don't set a default value for IBM Java 8. */
+	if ((~(UDATA)0) != javaVM->directByteBufferMemoryMax)
+#endif /* !defined(OPENJ9_BUILD) */
+	{
+		strings[propIndex] = "sun.nio.MaxDirectMemorySize";
+		propIndex += 1;
+		if ((~(UDATA)0) == javaVM->directByteBufferMemoryMax) {
+			strcpy(maxDirectMemBuff, "-1");
+		} else {
+			j9str_printf(maxDirectMemBuff, sizeof(maxDirectMemBuff), "%zu", javaVM->directByteBufferMemoryMax);
+		}
+		strings[propIndex] = maxDirectMemBuff;
+		propIndex += 1;
+	}
+
+	propertyList = getPlatformPropertyList(env, strings, propIndex);
+
+failed:
+	if (NULL != usernameAlloc) {
+		j9mem_free_memory(usernameAlloc);
+	}
+	return propertyList;
+}


Reviews:
user: login: keithc-ca
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-28T21:37:32Z
user: login: keithc-ca
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T23:06:32Z
user: login: keithc-ca
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T15:04:07Z
user: login: keithc-ca
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T16:38:32Z
user: login: keithc-ca
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T20:34:11Z
user: login: pshipton
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-06T21:29:59Z
user: login: keithc-ca
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T16:10:14Z

Review comments:
diff_hunk: @@ -63,9 +63,11 @@
 import com.ibm.jvm.io.ConsolePrintStream;
 /*[ENDIF] PLATFORM-mz31 | PLATFORM-mz64 | !Sidecar18-SE-OpenJ9 */
 
+/*[IF JAVA_SPEC_VERSION >= 17]*/
+import jdk.internal.util.SystemProps;
+/*[ENDIF]*/
path: jcl/src/java.base/share/classes/java/lang/System.java
user: login: keithc-ca
body: Why did you reorder this rather than have it continue to appear after `Field`?
Please add the missing end comment.
created_at: 2025-02-28T21:24:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -719,7 +697,7 @@ private static void ensureProperties(boolean isInitialization) {
 /*[ENDIF] OpenJ9-RawBuild */
 
 /*[IF JAVA_SPEC_VERSION > 11]*/
-	Map<String, String> initializedProperties = new Hashtable<String, String>();
+	Map<String, String> initializedProperties = new HashMap<String, String>();
path: jcl/src/java.base/share/classes/java/lang/System.java
user: login: keithc-ca
body: While you're here, please remove the redundant type arguments:
```java
	Map<String, String> initializedProperties = new HashMap<>();
```
created_at: 2025-02-28T21:25:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -759,6 +739,10 @@ private static void ensureProperties(boolean isInitialization) {
 	initializedProperties.put("jfr.unsupported.vm", "true"); //$NON-NLS-1$ //$NON-NLS-2$
 	/*[ENDIF] JFR_SUPPORT */
 
+	/*[IF JAVA_SPEC_VERSION >= 17]*/
+	initializedProperties.putAll(SystemProps.initProperties());
+
path: jcl/src/java.base/share/classes/java/lang/System.java
user: login: keithc-ca
body: I don't think this blank line is helpful.
created_at: 2025-02-28T21:25:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1900,7 +1900,6 @@ JVM_IsUseContainerSupport(void)
 JNIEXPORT jobjectArray JNICALL
 JVM_GetProperties(JNIEnv *env)
 {
-	assert(!"JVM_GetProperties");
-	return NULL;
+	return ((J9VMThread*)env)->javaVM->internalVMFunctions->getSystemPropertyList(env);
path: runtime/j9vm/java11vmi.c
user: login: keithc-ca
body: Space before `*`, please.
created_at: 2025-02-28T21:26:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -435,6 +434,7 @@ omr_add_exports(jclse
 if(JAVA_SPEC_VERSION LESS 17)
 omr_add_exports(jclse
 	Java_sun_misc_Unsafe_defineAnonymousClass
+	Java_java_lang_System_getPropertyList
path: runtime/jcl/exports.cmake
user: login: keithc-ca
body: Please keep the names sorted:
```
	Java_java_lang_System_getPropertyList
	Java_sun_misc_Unsafe_defineAnonymousClass
```
created_at: 2025-02-28T21:27:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -23,5 +23,4 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-ex
 	<export name="Java_java_lang_Class_getNestHostImpl"/>
 	<export name="Java_java_lang_Class_getNestMembersImpl"/>
 	<export name="Java_java_lang_invoke_MethodHandleResolver_getCPConstantDynamicAt"/>
-	<export name="Java_java_lang_System_initJCLPlatformEncoding" />
path: runtime/jcl/uma/se11_exports.xml
user: login: keithc-ca
body: Instead of adding `se11only_exports.xml` and modifying `module.xml`, suggest this could be:
```
	<export name="Java_java_lang_System_initJCLPlatformEncoding">
		<exclude-if condition="spec.java12"/>
	</export>
```
created_at: 2025-02-28T21:30:18Z
author_association: CONTRIBUTOR
path: runtime/oti/jclprots.h
user: login: keithc-ca
body: The condition for the declaration of `Java_java_lang_System_initJCLPlatformEncoding()` should change to match `system.c`, etc.
```c
#if JAVA_SPEC_VERSION == 11
```
created_at: 2025-02-28T21:32:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2665,6 +2665,12 @@ j9util_open_system_library(char *name, UDATA *descriptor, UDATA flags);
 
 #endif /*if defined(WIN32)*/
 
+/* ---------------- filehelp.c ---------------- */
+/**
+ * Try to find the 'correct' unix temp directory, as taken from the man page for tmpnam.
+ * As a last resort, the '.' representing the current directory is returned.
path: runtime/oti/util_api.h
user: login: keithc-ca
body: Suggest removing "the" here (and in other copies of this comment).
created_at: 2025-02-28T21:33:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,13 +107,30 @@ j9vm_add_library(j9util STATIC
 )
 
 if(OMR_OS_LINUX)
-	target_sources(j9util PRIVATE linux/osinfo.c)
+	target_sources(j9util
+		PRIVATE
+			linux/osinfo.c
+			unix/filehelp.c
+	)
 elseif(OMR_OS_WINDOWS)
-	target_sources(j9util PRIVATE win32/openlibrary.c)
+	target_sources(j9util
+		PRIVATE
+			win32/filehelp.c
+			win32/openlibrary.c
+	)
 elseif(OMR_OS_AIX)
-	target_sources(j9util PRIVATE aix/sethwprefetch.c)
+	target_sources(j9util
+		PRIVATE
+			aix/sethwprefetch.c
+			unix/filehelp.c
+	)
+elseif(OMR_OS_OSX)
+	target_sources(j9util PRIVATE unix/filehelp.c)
 elseif(OMR_OS_ZOS)
-	target_sources(j9util PRIVATE zos/freessp.c)
+	target_sources(j9util
+		PRIVATE
+			unix/filehelp.c
+			zos/freessp.c)
 endif()
path: runtime/util/CMakeLists.txt
user: login: keithc-ca
body: Rather than modify all this, suggest adding the following:
```
if(OMR_OS_WINDOWS)
	target_sources(j9util PRIVATE win32/filehelp.c)
else()
	target_sources(j9util PRIVATE unix/filehelp.c)
endif()
```
created_at: 2025-02-28T21:34:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -32,6 +39,10 @@
 #include "vmargs_api.h"
 #include "vendor_version.h"
 
+#if defined(J9ZOS390)
+#include "atoe.h"
+#endif
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Please add the missing comment.
created_at: 2025-02-28T21:35:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1444,643 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return 0 on success, -1 on error
+ */
+static jint propertyListAddString( JNIEnv *env, jarray array, jint arrayIndex, const char *value)
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Formatting:
```c
static jint
propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
```
created_at: 2025-02-28T21:35:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1444,643 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return 0 on success, -1 on error
+ */
+static jint propertyListAddString( JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return ((*env)->ExceptionCheck(env) == JNI_TRUE) ? -1 : 0;
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Comparing with true is a kind of anti-pattern, suggest:
```c
	return (*env)->ExceptionCheck(env) ? -1 : 0;
```
created_at: 2025-02-28T21:36:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -190,9 +190,9 @@ Java_com_ibm_java_lang_management_internal_MemoryManagerMXBeanImpl_isManagedPool
 /* BBjclNativesCommonSystem*/
 void JNICALL Java_java_lang_System_setFieldImpl (JNIEnv * env, jclass cls, jstring name, jobject stream);
 jobject createSystemPropertyList (JNIEnv *env, const char *defaultValues[], int defaultCount);
-#if JAVA_SPEC_VERSION >= 11
+#if JAVA_SPEC_VERSION == 11
 void JNICALL Java_java_lang_System_initJCLPlatformEncoding (JNIEnv *env, jclass clazz);
-#endif /* JAVA_SPEC_VERSION >= 11 */
+#endif /* JAVA_SPEC_VERSION == 11 */
 jstring JNICALL Java_java_lang_System_getSysPropBeforePropertiesInitialized(JNIEnv *env, jclass clazz, jint sysPropID);
 jobject JNICALL Java_java_lang_System_getPropertyList (JNIEnv *env, jclass clazz);
path: runtime/oti/jclprots.h
user: login: keithc-ca
body: This should be conditional:
```c
#if JAVA_SPEC_VERSION < 17
jobject JNICALL Java_java_lang_System_getPropertyList(JNIEnv *env, jclass clazz);
#endif /* JAVA_SPEC_VERSION < 17 */
```
And `se6_vm-side_natives_exports.xml` should be updated:
```
	<export name="Java_java_lang_System_getPropertyList">
		<exclude-if condition="spec.java17" />
	</export>
```
created_at: 2025-03-05T18:23:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright IBM Corp. and others 2025
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which accompanies this
+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
+ * or the Apache License, Version 2.0 which accompanies this distribution and
+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * This Source Code may also be made available under the following
+ * Secondary Licenses when the conditions for such availability set
+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
+ * General Public License, version 2 with the GNU Classpath
+ * Exception [1] and GNU General Public License, version 2 with the
+ * OpenJDK Assembly Exception [2].
+ *
+ * [1] https://www.gnu.org/software/classpath/license.html
+ * [2] https://openjdk.org/legal/assembly-exception.html
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
+ *******************************************************************************/
+
+#include "j9.h"
+
+/**
+ * Try to find the 'correct' unix temp directory, as taken from the man page for tmpnam.
+ * As a last resort, '.' representing the current directory is returned.
+ */
+char * getTmpDir(JNIEnv *env, char **envSpace) {
path: runtime/util/unix/filehelp.c
user: login: keithc-ca
body: Formatting:
```c
char *
getTmpDir(JNIEnv *env, char **envSpace)
{
```
created_at: 2025-03-05T22:59:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright IBM Corp. and others 2025
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which accompanies this
+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
+ * or the Apache License, Version 2.0 which accompanies this distribution and
+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * This Source Code may also be made available under the following
+ * Secondary Licenses when the conditions for such availability set
+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
+ * General Public License, version 2 with the GNU Classpath
+ * Exception [1] and GNU General Public License, version 2 with the
+ * OpenJDK Assembly Exception [2].
+ *
+ * [1] https://www.gnu.org/software/classpath/license.html
+ * [2] https://openjdk.org/legal/assembly-exception.html
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
+ *******************************************************************************/
+
+#include <windows.h>
+#include "j9.h"
+
+/**
+ * Try to find the 'correct' windows temp directory.
+ */
+char * getTmpDir(JNIEnv *env, char **tempdir) {
+	PORT_ACCESS_FROM_ENV(env);
+
+	wchar_t unicodeBuffer[EsMaxPath];
+	char *buffer = NULL;
+	char *retVal = ".";
+	DWORD rc = GetTempPathW(EsMaxPath, unicodeBuffer);
+
+	/* If the function succeeds, the return value is the number of characters stored into
+	the buffer, not including the terminating null character. If the buffer is not large enough,
+	the return value will exceed the length parameter (i.e. the required size)
+	*/
path: runtime/util/win32/filehelp.c
user: login: keithc-ca
body: This comment is just wrong. Please fix or remove.
created_at: 2025-03-05T22:59:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright IBM Corp. and others 2025
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which accompanies this
+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
+ * or the Apache License, Version 2.0 which accompanies this distribution and
+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * This Source Code may also be made available under the following
+ * Secondary Licenses when the conditions for such availability set
+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
+ * General Public License, version 2 with the GNU Classpath
+ * Exception [1] and GNU General Public License, version 2 with the
+ * OpenJDK Assembly Exception [2].
+ *
+ * [1] https://www.gnu.org/software/classpath/license.html
+ * [2] https://openjdk.org/legal/assembly-exception.html
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
+ *******************************************************************************/
+
+#include <windows.h>
+#include "j9.h"
+
+/**
+ * Try to find the 'correct' windows temp directory.
+ */
+char * getTmpDir(JNIEnv *env, char **tempdir) {
path: runtime/util/win32/filehelp.c
user: login: keithc-ca
body: Formatting:
```c
char *
getTmpDir(JNIEnv *env, char **tempdir)
{
```
created_at: 2025-03-05T22:59:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright IBM Corp. and others 2025
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which accompanies this
+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
+ * or the Apache License, Version 2.0 which accompanies this distribution and
+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * This Source Code may also be made available under the following
+ * Secondary Licenses when the conditions for such availability set
+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
+ * General Public License, version 2 with the GNU Classpath
+ * Exception [1] and GNU General Public License, version 2 with the
+ * OpenJDK Assembly Exception [2].
+ *
+ * [1] https://www.gnu.org/software/classpath/license.html
+ * [2] https://openjdk.org/legal/assembly-exception.html
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
+ *******************************************************************************/
+
+#include <windows.h>
+#include "j9.h"
+
+/**
+ * Try to find the 'correct' windows temp directory.
+ */
+char * getTmpDir(JNIEnv *env, char **tempdir) {
+	PORT_ACCESS_FROM_ENV(env);
+
+	wchar_t unicodeBuffer[EsMaxPath];
+	char *buffer = NULL;
+	char *retVal = ".";
+	DWORD rc = GetTempPathW(EsMaxPath, unicodeBuffer);
+
+	/* If the function succeeds, the return value is the number of characters stored into
+	the buffer, not including the terminating null character. If the buffer is not large enough,
+	the return value will exceed the length parameter (i.e. the required size)
+	*/
+
+	if ((rc != 0) && (rc < EsMaxPath)) {
path: runtime/util/win32/filehelp.c
user: login: keithc-ca
body: Constants on the left of `==` and `!=`, please: lines 42 & 45.
created_at: 2025-03-05T23:00:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1444,644 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return 0 on success, -1 on error
+ */
+static jint
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? -1 : 0;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char* key, char* value, void* userData)
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Space before, not after `*`, please.
created_at: 2025-03-05T23:02:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1444,644 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return 0 on success, -1 on error
+ */
+static jint
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? -1 : 0;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char* key, char* value, void* userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if (defaultValues[i] && !strcmp(key, defaultValues[i])) {
+			defaultValues[i] = NULL;
+			defaultValues[i+1] = NULL;
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: `NULL` checks should be explicit; missing space either side of `+`:
```c
		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
			defaultValues[i] = NULL;
			defaultValues[i + 1] = NULL;
```
created_at: 2025-03-05T23:04:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1444,644 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return 0 on success, -1 on error
+ */
+static jint
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: This is used as if it returned a boolean value, suggest the return type should instead be `jboolean`.
created_at: 2025-03-05T23:05:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright IBM Corp. and others 2025
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which accompanies this
+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
+ * or the Apache License, Version 2.0 which accompanies this distribution and
+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * This Source Code may also be made available under the following
+ * Secondary Licenses when the conditions for such availability set
+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
+ * General Public License, version 2 with the GNU Classpath
+ * Exception [1] and GNU General Public License, version 2 with the
+ * OpenJDK Assembly Exception [2].
+ *
+ * [1] https://www.gnu.org/software/classpath/license.html
+ * [2] https://openjdk.org/legal/assembly-exception.html
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
+ *******************************************************************************/
+
+#include "j9.h"
path: runtime/util/unix/filehelp.c
user: login: keithc-ca
body: I think this should include `stdio.h` directly (for `P_tmpdir`).
created_at: 2025-03-06T14:47:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -43,139 +43,12 @@
 #include <VersionHelpers.h>
 #endif
 
-/* JCL_J2SE */
-#define JCL_J2SE
-
 
 char* getPlatformFileEncoding(JNIEnv *env, char *codepage, int size, int encodingType);
-I_32 convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size);
 char * getTmpDir(JNIEnv *env, char **tempdir);
path: runtime/jcl/win32/syshelp.c
user: login: keithc-ca
body: The declaration of `getTmpDir()` was never needed here, now it's not even referenced: please remove line 48.
created_at: 2025-03-06T14:49:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1024,7 +1036,7 @@ initializeSystemProperties(J9JavaVM * vm)
 		}
 	} else {
 		/* look for java.endorsed.dirs and set if not set */
-		if ( getSystemProperty(vm, JAVA_ENDORSED_DIRS, &javaEndorsedDirsProperty) != J9SYSPROP_ERROR_NONE ) {
+		if (J9SYSPROP_ERROR_NONE != getSystemProperty(vm, JAVA_ENDORSED_DIRS, &javaEndorsedDirsProperty)) {
 			char *defaultEndorsedDir =  NULL;
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Extra space after `=`.
created_at: 2025-03-06T14:50:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: `ExceptionCheck()` returns `jboolean`; this can be simplified:
```c
	return (*env)->ExceptionCheck(env);
```
created_at: 2025-03-06T14:51:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: This should use `jboolean` to match how it is used.
created_at: 2025-03-06T14:52:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: No space after `*`, please.
created_at: 2025-03-06T14:53:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jclass stringClass = NULL;
+	jarray args = NULL;
+	int propertyCount = 0;
+
+	stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (!stringClass) {
+		return (jobject) 0;
+	}
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: `stringClass` should be declared here, the null check should be explicit and `NULL` should be returned (see other returns in this function):
```c
	jclass stringClass = (*env)->FindClass(env, "java/lang/String");
	if (NULL == stringClass) {
		return NULL;
	}
```
created_at: 2025-03-06T14:56:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jclass stringClass = NULL;
+	jarray args = NULL;
+	int propertyCount = 0;
+
+	stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (!stringClass) {
+		return (jobject) 0;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size)
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Space before, not after each `*`.
created_at: 2025-03-06T14:57:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jclass stringClass = NULL;
+	jarray args = NULL;
+	int propertyCount = 0;
+
+	stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (!stringClass) {
+		return (jobject) 0;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size)
+{
+	PORT_ACCESS_FROM_PORT(portLibrary);
+	if (0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
+		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
+		return -1;
+	}
+	return 0;
+}
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
+	OSVERSIONINFO versionInfo;
+#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
+	I_32 envSize = 0;
+	char *envSpace = NULL;
+	char *tempdir = NULL;
+	jobject result = NULL;
+	char userhome[EsMaxPath];
+	wchar_t unicodeTemp[EsMaxPath];
+	int i = 0;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath];
+#endif /* JAVA_SPEC_VERSION < 17 */
+	wchar_t unicodeHome[EsMaxPath];
+	HANDLE process = 0;
+	HANDLE token = 0;
+	UDATA handle = 0;
+	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
+
+	/* Hard coded file/path separators and other values */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "\\";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\r\n";
+
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &tempdir);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	i = propIndex;
+	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
+	if (-1 != envSize) {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+			if (NULL == envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Please correct the indentation here.
created_at: 2025-03-06T14:57:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jclass stringClass = NULL;
+	jarray args = NULL;
+	int propertyCount = 0;
+
+	stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (!stringClass) {
+		return (jobject) 0;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size)
+{
+	PORT_ACCESS_FROM_PORT(portLibrary);
+	if (0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
+		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
+		return -1;
+	}
+	return 0;
+}
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
+	OSVERSIONINFO versionInfo;
+#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
+	I_32 envSize = 0;
+	char *envSpace = NULL;
+	char *tempdir = NULL;
+	jobject result = NULL;
+	char userhome[EsMaxPath];
+	wchar_t unicodeTemp[EsMaxPath];
+	int i = 0;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath];
+#endif /* JAVA_SPEC_VERSION < 17 */
+	wchar_t unicodeHome[EsMaxPath];
+	HANDLE process = 0;
+	HANDLE token = 0;
+	UDATA handle = 0;
+	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
+
+	/* Hard coded file/path separators and other values */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "\\";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\r\n";
+
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &tempdir);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	i = propIndex;
+	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
+	if (-1 != envSize) {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+			if (NULL == envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+	}
+#if defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE)
+	/* dwPlatformId, VER_PLATFORM_WIN32_NT = https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
+	if ((i == propIndex) && IsWindowsVersionOrGreater( 5, 0, 0))
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: No space before `5`, please.
created_at: 2025-03-06T14:57:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jclass stringClass = NULL;
+	jarray args = NULL;
+	int propertyCount = 0;
+
+	stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (!stringClass) {
+		return (jobject) 0;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size)
+{
+	PORT_ACCESS_FROM_PORT(portLibrary);
+	if (0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
+		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
+		return -1;
+	}
+	return 0;
+}
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
+	OSVERSIONINFO versionInfo;
+#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
+	I_32 envSize = 0;
+	char *envSpace = NULL;
+	char *tempdir = NULL;
+	jobject result = NULL;
+	char userhome[EsMaxPath];
+	wchar_t unicodeTemp[EsMaxPath];
+	int i = 0;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath];
+#endif /* JAVA_SPEC_VERSION < 17 */
+	wchar_t unicodeHome[EsMaxPath];
+	HANDLE process = 0;
+	HANDLE token = 0;
+	UDATA handle = 0;
+	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
+
+	/* Hard coded file/path separators and other values */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "\\";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\r\n";
+
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &tempdir);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	i = propIndex;
+	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
+	if (-1 != envSize) {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+			if (NULL == envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+	}
+#if defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE)
+	/* dwPlatformId, VER_PLATFORM_WIN32_NT = https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
+	if ((i == propIndex) && IsWindowsVersionOrGreater( 5, 0, 0))
+#else /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+#pragma warning(suppress : 4996) /* ignore warning 'GetVersionExA': was declared deprecated */
+	if ((i == propIndex) && GetVersionEx(&versionInfo) && (VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId))
+#endif /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	{
+		process = GetCurrentProcess();
+		if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
+			envSize = 0;
+			if (0 == j9util_open_system_library("userenv", &handle, TRUE)) {
+				if (i == propIndex) {
+					if (0 == j9sl_lookup_name(handle, "GetUserProfileDirectoryW", (UDATA *)&func, "ZPLP")) {
+						envSize = EsMaxPath;
+						if (func(token, unicodeHome, &envSize)) {
+							/* When the SystemDrive environment variable isn't set, such as when j9 is exec'ed
+							 * running JCK tests, we get %SystemDrive%/Documents and Settings/...
+							 */
+							if (!wcsncmp(unicodeHome, L"%SystemDrive%", 13)) {
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Please use `0 ==` instead of `!`.
created_at: 2025-03-06T14:58:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jclass stringClass = NULL;
+	jarray args = NULL;
+	int propertyCount = 0;
+
+	stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (!stringClass) {
+		return (jobject) 0;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size)
+{
+	PORT_ACCESS_FROM_PORT(portLibrary);
+	if (0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
+		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
+		return -1;
+	}
+	return 0;
+}
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
+	OSVERSIONINFO versionInfo;
+#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
+	I_32 envSize = 0;
+	char *envSpace = NULL;
+	char *tempdir = NULL;
+	jobject result = NULL;
+	char userhome[EsMaxPath];
+	wchar_t unicodeTemp[EsMaxPath];
+	int i = 0;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath];
+#endif /* JAVA_SPEC_VERSION < 17 */
+	wchar_t unicodeHome[EsMaxPath];
+	HANDLE process = 0;
+	HANDLE token = 0;
+	UDATA handle = 0;
+	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
+
+	/* Hard coded file/path separators and other values */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "\\";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\r\n";
+
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &tempdir);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	i = propIndex;
+	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
+	if (-1 != envSize) {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+			if (NULL == envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+	}
+#if defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE)
+	/* dwPlatformId, VER_PLATFORM_WIN32_NT = https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
+	if ((i == propIndex) && IsWindowsVersionOrGreater( 5, 0, 0))
+#else /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+#pragma warning(suppress : 4996) /* ignore warning 'GetVersionExA': was declared deprecated */
+	if ((i == propIndex) && GetVersionEx(&versionInfo) && (VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId))
+#endif /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	{
+		process = GetCurrentProcess();
+		if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
+			envSize = 0;
+			if (0 == j9util_open_system_library("userenv", &handle, TRUE)) {
+				if (i == propIndex) {
+					if (0 == j9sl_lookup_name(handle, "GetUserProfileDirectoryW", (UDATA *)&func, "ZPLP")) {
+						envSize = EsMaxPath;
+						if (func(token, unicodeHome, &envSize)) {
+							/* When the SystemDrive environment variable isn't set, such as when j9 is exec'ed
+							 * running JCK tests, we get %SystemDrive%/Documents and Settings/...
+							 */
+							if (!wcsncmp(unicodeHome, L"%SystemDrive%", 13)) {
+								/* Borrow userdir variable, which is used for real below */
+								if (GetSystemDirectoryW(unicodeTemp, EsMaxPath) > 1) {
+									unicodeHome[0] = unicodeTemp[0];
+									unicodeHome[1] = unicodeTemp[1];
+									wcsncpy(&unicodeHome[2], &unicodeHome[13], envSize - 13);
+								}
+							}
+							convertToUTF8(PORTLIB, unicodeHome, userhome, EsMaxPath);
+							strings[propIndex++] = userhome;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (i == propIndex) {
+		/* Fallback to Windows Directory */
+		envSize = (I_32)j9sysinfo_get_env("WINDIR", NULL, 0);
+		if (-1 == envSize) {
+			strings[propIndex++] = "\\";
+		} else {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM);	/* trailing null taken into account */
+			if (!envSpace) {
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: ```c
			if (NULL == envSpace) {
```
created_at: 2025-03-06T14:58:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jclass stringClass = NULL;
+	jarray args = NULL;
+	int propertyCount = 0;
+
+	stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (!stringClass) {
+		return (jobject) 0;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size)
+{
+	PORT_ACCESS_FROM_PORT(portLibrary);
+	if (0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
+		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
+		return -1;
+	}
+	return 0;
+}
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
+	OSVERSIONINFO versionInfo;
+#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
+	I_32 envSize = 0;
+	char *envSpace = NULL;
+	char *tempdir = NULL;
+	jobject result = NULL;
+	char userhome[EsMaxPath];
+	wchar_t unicodeTemp[EsMaxPath];
+	int i = 0;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath];
+#endif /* JAVA_SPEC_VERSION < 17 */
+	wchar_t unicodeHome[EsMaxPath];
+	HANDLE process = 0;
+	HANDLE token = 0;
+	UDATA handle = 0;
+	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
+
+	/* Hard coded file/path separators and other values */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "\\";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\r\n";
+
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &tempdir);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	i = propIndex;
+	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
+	if (-1 != envSize) {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+			if (NULL == envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+	}
+#if defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE)
+	/* dwPlatformId, VER_PLATFORM_WIN32_NT = https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
+	if ((i == propIndex) && IsWindowsVersionOrGreater( 5, 0, 0))
+#else /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+#pragma warning(suppress : 4996) /* ignore warning 'GetVersionExA': was declared deprecated */
+	if ((i == propIndex) && GetVersionEx(&versionInfo) && (VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId))
+#endif /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	{
+		process = GetCurrentProcess();
+		if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
+			envSize = 0;
+			if (0 == j9util_open_system_library("userenv", &handle, TRUE)) {
+				if (i == propIndex) {
+					if (0 == j9sl_lookup_name(handle, "GetUserProfileDirectoryW", (UDATA *)&func, "ZPLP")) {
+						envSize = EsMaxPath;
+						if (func(token, unicodeHome, &envSize)) {
+							/* When the SystemDrive environment variable isn't set, such as when j9 is exec'ed
+							 * running JCK tests, we get %SystemDrive%/Documents and Settings/...
+							 */
+							if (!wcsncmp(unicodeHome, L"%SystemDrive%", 13)) {
+								/* Borrow userdir variable, which is used for real below */
+								if (GetSystemDirectoryW(unicodeTemp, EsMaxPath) > 1) {
+									unicodeHome[0] = unicodeTemp[0];
+									unicodeHome[1] = unicodeTemp[1];
+									wcsncpy(&unicodeHome[2], &unicodeHome[13], envSize - 13);
+								}
+							}
+							convertToUTF8(PORTLIB, unicodeHome, userhome, EsMaxPath);
+							strings[propIndex++] = userhome;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (i == propIndex) {
+		/* Fallback to Windows Directory */
+		envSize = (I_32)j9sysinfo_get_env("WINDIR", NULL, 0);
+		if (-1 == envSize) {
+			strings[propIndex++] = "\\";
+		} else {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM);	/* trailing null taken into account */
+			if (!envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("WINDIR", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+		}
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	if (0 == GetCurrentDirectoryW(EsMaxPath, unicodeTemp)) {
+		strings[propIndex++] = "\\";
+	} else {
+		convertToUTF8(PORTLIB, unicodeTemp, userdir, EsMaxPath);
+		strings[propIndex++] = userdir;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	result = createSystemPropertyList(env, strings, propIndex);
+	if (tempdir) {
+		j9mem_free_memory(tempdir);
+	}
+	if (envSpace) {
+		j9mem_free_memory(envSpace);
+	}
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: The null checks should either be explicit, or just removed (`j9mem_free_memory(NULL)` does nothing).
created_at: 2025-03-06T14:59:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jclass stringClass = NULL;
+	jarray args = NULL;
+	int propertyCount = 0;
+
+	stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (!stringClass) {
+		return (jobject) 0;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size)
+{
+	PORT_ACCESS_FROM_PORT(portLibrary);
+	if (0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
+		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
+		return -1;
+	}
+	return 0;
+}
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
+	OSVERSIONINFO versionInfo;
+#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
+	I_32 envSize = 0;
+	char *envSpace = NULL;
+	char *tempdir = NULL;
+	jobject result = NULL;
+	char userhome[EsMaxPath];
+	wchar_t unicodeTemp[EsMaxPath];
+	int i = 0;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath];
+#endif /* JAVA_SPEC_VERSION < 17 */
+	wchar_t unicodeHome[EsMaxPath];
+	HANDLE process = 0;
+	HANDLE token = 0;
+	UDATA handle = 0;
+	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
+
+	/* Hard coded file/path separators and other values */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "\\";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\r\n";
+
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &tempdir);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	i = propIndex;
+	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
+	if (-1 != envSize) {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+			if (NULL == envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+	}
+#if defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE)
+	/* dwPlatformId, VER_PLATFORM_WIN32_NT = https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
+	if ((i == propIndex) && IsWindowsVersionOrGreater( 5, 0, 0))
+#else /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+#pragma warning(suppress : 4996) /* ignore warning 'GetVersionExA': was declared deprecated */
+	if ((i == propIndex) && GetVersionEx(&versionInfo) && (VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId))
+#endif /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	{
+		process = GetCurrentProcess();
+		if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
+			envSize = 0;
+			if (0 == j9util_open_system_library("userenv", &handle, TRUE)) {
+				if (i == propIndex) {
+					if (0 == j9sl_lookup_name(handle, "GetUserProfileDirectoryW", (UDATA *)&func, "ZPLP")) {
+						envSize = EsMaxPath;
+						if (func(token, unicodeHome, &envSize)) {
+							/* When the SystemDrive environment variable isn't set, such as when j9 is exec'ed
+							 * running JCK tests, we get %SystemDrive%/Documents and Settings/...
+							 */
+							if (!wcsncmp(unicodeHome, L"%SystemDrive%", 13)) {
+								/* Borrow userdir variable, which is used for real below */
+								if (GetSystemDirectoryW(unicodeTemp, EsMaxPath) > 1) {
+									unicodeHome[0] = unicodeTemp[0];
+									unicodeHome[1] = unicodeTemp[1];
+									wcsncpy(&unicodeHome[2], &unicodeHome[13], envSize - 13);
+								}
+							}
+							convertToUTF8(PORTLIB, unicodeHome, userhome, EsMaxPath);
+							strings[propIndex++] = userhome;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (i == propIndex) {
+		/* Fallback to Windows Directory */
+		envSize = (I_32)j9sysinfo_get_env("WINDIR", NULL, 0);
+		if (-1 == envSize) {
+			strings[propIndex++] = "\\";
+		} else {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM);	/* trailing null taken into account */
+			if (!envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("WINDIR", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+		}
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	if (0 == GetCurrentDirectoryW(EsMaxPath, unicodeTemp)) {
+		strings[propIndex++] = "\\";
+	} else {
+		convertToUTF8(PORTLIB, unicodeTemp, userdir, EsMaxPath);
+		strings[propIndex++] = userdir;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	result = createSystemPropertyList(env, strings, propIndex);
+	if (tempdir) {
+		j9mem_free_memory(tempdir);
+	}
+	if (envSpace) {
+		j9mem_free_memory(envSpace);
+	}
+	return result;
+}
+
+#else /* defined(WIN32) */
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	char *charResult = NULL;
+	char *envSpace = NULL;
+	jobject plist = NULL;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath] = {0};
+#endif /* JAVA_SPEC_VERSION < 17 */
+	char home[EsMaxPath] = {0};
+	char *homeAlloc = NULL;
+	J9VMThread *currentThread = (J9VMThread*)env;
+	J9JavaVM *vm = currentThread->javaVM;
+	J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
+
+	/* Hard coded file/path separators and other values */
+
+#if defined(J9ZOS390)
+	if (J2SE_VERSION_FROM_ENV(env)) {
+		strings[propIndex++] = "platform.notASCII";
+		strings[propIndex++] = "true";
+
+		strings[propIndex++] = "os.encoding";
+		strings[propIndex++] = "ISO8859_1";
+	}
+#endif
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Missing comment.
created_at: 2025-03-06T14:59:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jclass stringClass = NULL;
+	jarray args = NULL;
+	int propertyCount = 0;
+
+	stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (!stringClass) {
+		return (jobject) 0;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size)
+{
+	PORT_ACCESS_FROM_PORT(portLibrary);
+	if (0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
+		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
+		return -1;
+	}
+	return 0;
+}
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
+	OSVERSIONINFO versionInfo;
+#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
+	I_32 envSize = 0;
+	char *envSpace = NULL;
+	char *tempdir = NULL;
+	jobject result = NULL;
+	char userhome[EsMaxPath];
+	wchar_t unicodeTemp[EsMaxPath];
+	int i = 0;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath];
+#endif /* JAVA_SPEC_VERSION < 17 */
+	wchar_t unicodeHome[EsMaxPath];
+	HANDLE process = 0;
+	HANDLE token = 0;
+	UDATA handle = 0;
+	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
+
+	/* Hard coded file/path separators and other values */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "\\";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\r\n";
+
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &tempdir);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	i = propIndex;
+	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
+	if (-1 != envSize) {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+			if (NULL == envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+	}
+#if defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE)
+	/* dwPlatformId, VER_PLATFORM_WIN32_NT = https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
+	if ((i == propIndex) && IsWindowsVersionOrGreater( 5, 0, 0))
+#else /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+#pragma warning(suppress : 4996) /* ignore warning 'GetVersionExA': was declared deprecated */
+	if ((i == propIndex) && GetVersionEx(&versionInfo) && (VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId))
+#endif /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	{
+		process = GetCurrentProcess();
+		if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
+			envSize = 0;
+			if (0 == j9util_open_system_library("userenv", &handle, TRUE)) {
+				if (i == propIndex) {
+					if (0 == j9sl_lookup_name(handle, "GetUserProfileDirectoryW", (UDATA *)&func, "ZPLP")) {
+						envSize = EsMaxPath;
+						if (func(token, unicodeHome, &envSize)) {
+							/* When the SystemDrive environment variable isn't set, such as when j9 is exec'ed
+							 * running JCK tests, we get %SystemDrive%/Documents and Settings/...
+							 */
+							if (!wcsncmp(unicodeHome, L"%SystemDrive%", 13)) {
+								/* Borrow userdir variable, which is used for real below */
+								if (GetSystemDirectoryW(unicodeTemp, EsMaxPath) > 1) {
+									unicodeHome[0] = unicodeTemp[0];
+									unicodeHome[1] = unicodeTemp[1];
+									wcsncpy(&unicodeHome[2], &unicodeHome[13], envSize - 13);
+								}
+							}
+							convertToUTF8(PORTLIB, unicodeHome, userhome, EsMaxPath);
+							strings[propIndex++] = userhome;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (i == propIndex) {
+		/* Fallback to Windows Directory */
+		envSize = (I_32)j9sysinfo_get_env("WINDIR", NULL, 0);
+		if (-1 == envSize) {
+			strings[propIndex++] = "\\";
+		} else {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM);	/* trailing null taken into account */
+			if (!envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("WINDIR", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+		}
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	if (0 == GetCurrentDirectoryW(EsMaxPath, unicodeTemp)) {
+		strings[propIndex++] = "\\";
+	} else {
+		convertToUTF8(PORTLIB, unicodeTemp, userdir, EsMaxPath);
+		strings[propIndex++] = userdir;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	result = createSystemPropertyList(env, strings, propIndex);
+	if (tempdir) {
+		j9mem_free_memory(tempdir);
+	}
+	if (envSpace) {
+		j9mem_free_memory(envSpace);
+	}
+	return result;
+}
+
+#else /* defined(WIN32) */
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	char *charResult = NULL;
+	char *envSpace = NULL;
+	jobject plist = NULL;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath] = {0};
+#endif /* JAVA_SPEC_VERSION < 17 */
+	char home[EsMaxPath] = {0};
+	char *homeAlloc = NULL;
+	J9VMThread *currentThread = (J9VMThread*)env;
+	J9JavaVM *vm = currentThread->javaVM;
+	J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
+
+	/* Hard coded file/path separators and other values */
+
+#if defined(J9ZOS390)
+	if (J2SE_VERSION_FROM_ENV(env)) {
+		strings[propIndex++] = "platform.notASCII";
+		strings[propIndex++] = "true";
+
+		strings[propIndex++] = "os.encoding";
+		strings[propIndex++] = "ISO8859_1";
+	}
+#endif
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "/";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\n";
+
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	charResult = getcwd(userdir, EsMaxPath);
+	if (NULL == charResult) {
+		strings[propIndex++] = ".";
+	} else {
+		strings[propIndex++] = charResult;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	charResult = NULL;
+#if defined(J9ZOS390)
+	charResult = getenv("HOME");
+	if (NULL != charResult) {
+		strings[propIndex++] = charResult;
+	} else {
+		uid_t uid = geteuid();
+		if (0 != uid) {
+			struct passwd *userDescription = getpwuid(uid);
+			if (NULL != userDescription) {
+				charResult = userDescription->pw_dir;
+				strings[propIndex++] = charResult;
+			}
+		} else {
+			char *loginID = getlogin();
+			if (NULL != loginID) {
+				struct passwd *userDescription = getpwnam(loginID);
+				if (NULL != userDescription) {
+					charResult = userDescription->pw_dir;
+					strings[propIndex++] = charResult;
+				}
+			}
+		}
+	}
+
+	/* there exist situations where one of the above calls will fail.  Fall through to the Unix solution for those cases */
+#endif
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Please fold the comment, start sentences with a capital and finish with a period.
The comment is missing on line 1818.
created_at: 2025-03-06T15:00:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jclass stringClass = NULL;
+	jarray args = NULL;
+	int propertyCount = 0;
+
+	stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (!stringClass) {
+		return (jobject) 0;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size)
+{
+	PORT_ACCESS_FROM_PORT(portLibrary);
+	if (0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
+		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
+		return -1;
+	}
+	return 0;
+}
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
+	OSVERSIONINFO versionInfo;
+#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
+	I_32 envSize = 0;
+	char *envSpace = NULL;
+	char *tempdir = NULL;
+	jobject result = NULL;
+	char userhome[EsMaxPath];
+	wchar_t unicodeTemp[EsMaxPath];
+	int i = 0;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath];
+#endif /* JAVA_SPEC_VERSION < 17 */
+	wchar_t unicodeHome[EsMaxPath];
+	HANDLE process = 0;
+	HANDLE token = 0;
+	UDATA handle = 0;
+	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
+
+	/* Hard coded file/path separators and other values */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "\\";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\r\n";
+
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &tempdir);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	i = propIndex;
+	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
+	if (-1 != envSize) {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+			if (NULL == envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+	}
+#if defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE)
+	/* dwPlatformId, VER_PLATFORM_WIN32_NT = https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
+	if ((i == propIndex) && IsWindowsVersionOrGreater( 5, 0, 0))
+#else /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+#pragma warning(suppress : 4996) /* ignore warning 'GetVersionExA': was declared deprecated */
+	if ((i == propIndex) && GetVersionEx(&versionInfo) && (VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId))
+#endif /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	{
+		process = GetCurrentProcess();
+		if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
+			envSize = 0;
+			if (0 == j9util_open_system_library("userenv", &handle, TRUE)) {
+				if (i == propIndex) {
+					if (0 == j9sl_lookup_name(handle, "GetUserProfileDirectoryW", (UDATA *)&func, "ZPLP")) {
+						envSize = EsMaxPath;
+						if (func(token, unicodeHome, &envSize)) {
+							/* When the SystemDrive environment variable isn't set, such as when j9 is exec'ed
+							 * running JCK tests, we get %SystemDrive%/Documents and Settings/...
+							 */
+							if (!wcsncmp(unicodeHome, L"%SystemDrive%", 13)) {
+								/* Borrow userdir variable, which is used for real below */
+								if (GetSystemDirectoryW(unicodeTemp, EsMaxPath) > 1) {
+									unicodeHome[0] = unicodeTemp[0];
+									unicodeHome[1] = unicodeTemp[1];
+									wcsncpy(&unicodeHome[2], &unicodeHome[13], envSize - 13);
+								}
+							}
+							convertToUTF8(PORTLIB, unicodeHome, userhome, EsMaxPath);
+							strings[propIndex++] = userhome;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (i == propIndex) {
+		/* Fallback to Windows Directory */
+		envSize = (I_32)j9sysinfo_get_env("WINDIR", NULL, 0);
+		if (-1 == envSize) {
+			strings[propIndex++] = "\\";
+		} else {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM);	/* trailing null taken into account */
+			if (!envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("WINDIR", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+		}
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	if (0 == GetCurrentDirectoryW(EsMaxPath, unicodeTemp)) {
+		strings[propIndex++] = "\\";
+	} else {
+		convertToUTF8(PORTLIB, unicodeTemp, userdir, EsMaxPath);
+		strings[propIndex++] = userdir;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	result = createSystemPropertyList(env, strings, propIndex);
+	if (tempdir) {
+		j9mem_free_memory(tempdir);
+	}
+	if (envSpace) {
+		j9mem_free_memory(envSpace);
+	}
+	return result;
+}
+
+#else /* defined(WIN32) */
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	char *charResult = NULL;
+	char *envSpace = NULL;
+	jobject plist = NULL;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath] = {0};
+#endif /* JAVA_SPEC_VERSION < 17 */
+	char home[EsMaxPath] = {0};
+	char *homeAlloc = NULL;
+	J9VMThread *currentThread = (J9VMThread*)env;
+	J9JavaVM *vm = currentThread->javaVM;
+	J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
+
+	/* Hard coded file/path separators and other values */
+
+#if defined(J9ZOS390)
+	if (J2SE_VERSION_FROM_ENV(env)) {
+		strings[propIndex++] = "platform.notASCII";
+		strings[propIndex++] = "true";
+
+		strings[propIndex++] = "os.encoding";
+		strings[propIndex++] = "ISO8859_1";
+	}
+#endif
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "/";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\n";
+
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	charResult = getcwd(userdir, EsMaxPath);
+	if (NULL == charResult) {
+		strings[propIndex++] = ".";
+	} else {
+		strings[propIndex++] = charResult;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	charResult = NULL;
+#if defined(J9ZOS390)
+	charResult = getenv("HOME");
+	if (NULL != charResult) {
+		strings[propIndex++] = charResult;
+	} else {
+		uid_t uid = geteuid();
+		if (0 != uid) {
+			struct passwd *userDescription = getpwuid(uid);
+			if (NULL != userDescription) {
+				charResult = userDescription->pw_dir;
+				strings[propIndex++] = charResult;
+			}
+		} else {
+			char *loginID = getlogin();
+			if (NULL != loginID) {
+				struct passwd *userDescription = getpwnam(loginID);
+				if (NULL != userDescription) {
+					charResult = userDescription->pw_dir;
+					strings[propIndex++] = charResult;
+				}
+			}
+		}
+	}
+
+	/* there exist situations where one of the above calls will fail.  Fall through to the Unix solution for those cases */
+#endif
+#if defined(J9VM_OPT_CRIU_SUPPORT)
+	/* Skip getpwuid if a checkpoint can be taken.
+	 * https://github.com/eclipse-openj9/openj9/issues/15800
+	 */
+	if (!vmFuncs->isCheckpointAllowed(vm))
+#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */
+	{
+		/*[PR 101939] user.home not set correctly when j9 invoked via execve(x,y,null) */
+		if (NULL == charResult) {
+			struct passwd *pwentry = getpwuid(getuid());
+			if (NULL != pwentry) {
+				charResult = pwentry->pw_dir;
+				strings[propIndex++] = charResult;
+			}
+		}
+	}
+
+	if (NULL == charResult) {
+		IDATA result = j9sysinfo_get_env("HOME", home, sizeof(home));
+		strings[propIndex] = ".";
+		if (0 == result) {
+			if (strlen(home) > 0) {
+				strings[propIndex] = home;
+			}
+		} else if (result > 0) {
+			homeAlloc = j9mem_allocate_memory(result, OMRMEM_CATEGORY_VM);
+			if (NULL != homeAlloc) {
+				result = j9sysinfo_get_env("HOME", homeAlloc, result);
+				if (0 == result) {
+					strings[propIndex] = homeAlloc;
+				}
+			} else {
+				vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
+				goto failed;
+			}
+		}
+		propIndex += 1;
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &envSpace);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	plist = createSystemPropertyList(env, strings, propIndex);
+	if (NULL != envSpace) {
+		j9mem_free_memory(envSpace);
+	}
+
+failed:
+	if (NULL != homeAlloc) {
+		j9mem_free_memory(homeAlloc);
+	}
+	return plist;
+}
+
+#endif /* defined(WIN32) */
+
+/**
+ * @brief Get the default system properties.
+ *
+ * @return an Object array of system property key value pairs
+ */
+jobjectArray
+getSystemPropertyList(JNIEnv *env)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	int propIndex = 0;
+	jobject propertyList = NULL;
+#define PROPERTY_COUNT 137
+#if JAVA_SPEC_VERSION < 17
+	char *propertyKey = NULL;
+	const char * language = NULL;
+	const char * region = NULL;
+	const char * variant = NULL;
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: No space after `*` (like declarations before and after these).
created_at: 2025-03-06T15:01:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jclass stringClass = NULL;
+	jarray args = NULL;
+	int propertyCount = 0;
+
+	stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (!stringClass) {
+		return (jobject) 0;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size)
+{
+	PORT_ACCESS_FROM_PORT(portLibrary);
+	if (0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
+		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
+		return -1;
+	}
+	return 0;
+}
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
+	OSVERSIONINFO versionInfo;
+#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
+	I_32 envSize = 0;
+	char *envSpace = NULL;
+	char *tempdir = NULL;
+	jobject result = NULL;
+	char userhome[EsMaxPath];
+	wchar_t unicodeTemp[EsMaxPath];
+	int i = 0;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath];
+#endif /* JAVA_SPEC_VERSION < 17 */
+	wchar_t unicodeHome[EsMaxPath];
+	HANDLE process = 0;
+	HANDLE token = 0;
+	UDATA handle = 0;
+	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
+
+	/* Hard coded file/path separators and other values */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "\\";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\r\n";
+
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &tempdir);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	i = propIndex;
+	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
+	if (-1 != envSize) {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+			if (NULL == envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+	}
+#if defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE)
+	/* dwPlatformId, VER_PLATFORM_WIN32_NT = https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
+	if ((i == propIndex) && IsWindowsVersionOrGreater( 5, 0, 0))
+#else /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+#pragma warning(suppress : 4996) /* ignore warning 'GetVersionExA': was declared deprecated */
+	if ((i == propIndex) && GetVersionEx(&versionInfo) && (VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId))
+#endif /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	{
+		process = GetCurrentProcess();
+		if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
+			envSize = 0;
+			if (0 == j9util_open_system_library("userenv", &handle, TRUE)) {
+				if (i == propIndex) {
+					if (0 == j9sl_lookup_name(handle, "GetUserProfileDirectoryW", (UDATA *)&func, "ZPLP")) {
+						envSize = EsMaxPath;
+						if (func(token, unicodeHome, &envSize)) {
+							/* When the SystemDrive environment variable isn't set, such as when j9 is exec'ed
+							 * running JCK tests, we get %SystemDrive%/Documents and Settings/...
+							 */
+							if (!wcsncmp(unicodeHome, L"%SystemDrive%", 13)) {
+								/* Borrow userdir variable, which is used for real below */
+								if (GetSystemDirectoryW(unicodeTemp, EsMaxPath) > 1) {
+									unicodeHome[0] = unicodeTemp[0];
+									unicodeHome[1] = unicodeTemp[1];
+									wcsncpy(&unicodeHome[2], &unicodeHome[13], envSize - 13);
+								}
+							}
+							convertToUTF8(PORTLIB, unicodeHome, userhome, EsMaxPath);
+							strings[propIndex++] = userhome;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (i == propIndex) {
+		/* Fallback to Windows Directory */
+		envSize = (I_32)j9sysinfo_get_env("WINDIR", NULL, 0);
+		if (-1 == envSize) {
+			strings[propIndex++] = "\\";
+		} else {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM);	/* trailing null taken into account */
+			if (!envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("WINDIR", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+		}
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	if (0 == GetCurrentDirectoryW(EsMaxPath, unicodeTemp)) {
+		strings[propIndex++] = "\\";
+	} else {
+		convertToUTF8(PORTLIB, unicodeTemp, userdir, EsMaxPath);
+		strings[propIndex++] = userdir;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	result = createSystemPropertyList(env, strings, propIndex);
+	if (tempdir) {
+		j9mem_free_memory(tempdir);
+	}
+	if (envSpace) {
+		j9mem_free_memory(envSpace);
+	}
+	return result;
+}
+
+#else /* defined(WIN32) */
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	char *charResult = NULL;
+	char *envSpace = NULL;
+	jobject plist = NULL;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath] = {0};
+#endif /* JAVA_SPEC_VERSION < 17 */
+	char home[EsMaxPath] = {0};
+	char *homeAlloc = NULL;
+	J9VMThread *currentThread = (J9VMThread*)env;
+	J9JavaVM *vm = currentThread->javaVM;
+	J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
+
+	/* Hard coded file/path separators and other values */
+
+#if defined(J9ZOS390)
+	if (J2SE_VERSION_FROM_ENV(env)) {
+		strings[propIndex++] = "platform.notASCII";
+		strings[propIndex++] = "true";
+
+		strings[propIndex++] = "os.encoding";
+		strings[propIndex++] = "ISO8859_1";
+	}
+#endif
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "/";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\n";
+
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	charResult = getcwd(userdir, EsMaxPath);
+	if (NULL == charResult) {
+		strings[propIndex++] = ".";
+	} else {
+		strings[propIndex++] = charResult;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	charResult = NULL;
+#if defined(J9ZOS390)
+	charResult = getenv("HOME");
+	if (NULL != charResult) {
+		strings[propIndex++] = charResult;
+	} else {
+		uid_t uid = geteuid();
+		if (0 != uid) {
+			struct passwd *userDescription = getpwuid(uid);
+			if (NULL != userDescription) {
+				charResult = userDescription->pw_dir;
+				strings[propIndex++] = charResult;
+			}
+		} else {
+			char *loginID = getlogin();
+			if (NULL != loginID) {
+				struct passwd *userDescription = getpwnam(loginID);
+				if (NULL != userDescription) {
+					charResult = userDescription->pw_dir;
+					strings[propIndex++] = charResult;
+				}
+			}
+		}
+	}
+
+	/* there exist situations where one of the above calls will fail.  Fall through to the Unix solution for those cases */
+#endif
+#if defined(J9VM_OPT_CRIU_SUPPORT)
+	/* Skip getpwuid if a checkpoint can be taken.
+	 * https://github.com/eclipse-openj9/openj9/issues/15800
+	 */
+	if (!vmFuncs->isCheckpointAllowed(vm))
+#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */
+	{
+		/*[PR 101939] user.home not set correctly when j9 invoked via execve(x,y,null) */
+		if (NULL == charResult) {
+			struct passwd *pwentry = getpwuid(getuid());
+			if (NULL != pwentry) {
+				charResult = pwentry->pw_dir;
+				strings[propIndex++] = charResult;
+			}
+		}
+	}
+
+	if (NULL == charResult) {
+		IDATA result = j9sysinfo_get_env("HOME", home, sizeof(home));
+		strings[propIndex] = ".";
+		if (0 == result) {
+			if (strlen(home) > 0) {
+				strings[propIndex] = home;
+			}
+		} else if (result > 0) {
+			homeAlloc = j9mem_allocate_memory(result, OMRMEM_CATEGORY_VM);
+			if (NULL != homeAlloc) {
+				result = j9sysinfo_get_env("HOME", homeAlloc, result);
+				if (0 == result) {
+					strings[propIndex] = homeAlloc;
+				}
+			} else {
+				vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
+				goto failed;
+			}
+		}
+		propIndex += 1;
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &envSpace);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	plist = createSystemPropertyList(env, strings, propIndex);
+	if (NULL != envSpace) {
+		j9mem_free_memory(envSpace);
+	}
+
+failed:
+	if (NULL != homeAlloc) {
+		j9mem_free_memory(homeAlloc);
+	}
+	return plist;
+}
+
+#endif /* defined(WIN32) */
+
+/**
+ * @brief Get the default system properties.
+ *
+ * @return an Object array of system property key value pairs
+ */
+jobjectArray
+getSystemPropertyList(JNIEnv *env)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	int propIndex = 0;
+	jobject propertyList = NULL;
+#define PROPERTY_COUNT 137
+#if JAVA_SPEC_VERSION < 17
+	char *propertyKey = NULL;
+	const char * language = NULL;
+	const char * region = NULL;
+	const char * variant = NULL;
+#endif /* JAVA_SPEC_VERSION < 17 */
+	const char *strings[PROPERTY_COUNT] = {0};
+#define USERNAME_LENGTH 128
+	char username[USERNAME_LENGTH] = {0};
+	char *usernameAlloc = NULL;
+	/* buffer to hold the size of the maximum direct byte buffer allocations */
+	char maxDirectMemBuff[24] = {0};
+	IDATA result = 0;
+
+	J9VMThread *currentThread = (J9VMThread*)env;
+	J9JavaVM *javaVM = currentThread->javaVM;
+	J9InternalVMFunctions *vmFuncs = javaVM->internalVMFunctions;
+
+	/* Change the allocation value PROPERTY_COUNT above as you add/remove properties,
+	 * then follow the propIndex++ convention and consume 2 * slots for each property. 2 * number of property keys is the
+	 * correct allocation.
+	 * Also note the call to addSystemProperties below, which may add some configuration-specific properties.  Be sure to leave
+	 * enough room in the property list for all possibilities.
+	 */
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Please shorten the lines of this comment.
created_at: 2025-03-06T15:02:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jclass stringClass = NULL;
+	jarray args = NULL;
+	int propertyCount = 0;
+
+	stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (!stringClass) {
+		return (jobject) 0;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size)
+{
+	PORT_ACCESS_FROM_PORT(portLibrary);
+	if (0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
+		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
+		return -1;
+	}
+	return 0;
+}
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
+	OSVERSIONINFO versionInfo;
+#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
+	I_32 envSize = 0;
+	char *envSpace = NULL;
+	char *tempdir = NULL;
+	jobject result = NULL;
+	char userhome[EsMaxPath];
+	wchar_t unicodeTemp[EsMaxPath];
+	int i = 0;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath];
+#endif /* JAVA_SPEC_VERSION < 17 */
+	wchar_t unicodeHome[EsMaxPath];
+	HANDLE process = 0;
+	HANDLE token = 0;
+	UDATA handle = 0;
+	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
+
+	/* Hard coded file/path separators and other values */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "\\";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\r\n";
+
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &tempdir);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	i = propIndex;
+	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
+	if (-1 != envSize) {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+			if (NULL == envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+	}
+#if defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE)
+	/* dwPlatformId, VER_PLATFORM_WIN32_NT = https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
+	if ((i == propIndex) && IsWindowsVersionOrGreater( 5, 0, 0))
+#else /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+#pragma warning(suppress : 4996) /* ignore warning 'GetVersionExA': was declared deprecated */
+	if ((i == propIndex) && GetVersionEx(&versionInfo) && (VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId))
+#endif /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	{
+		process = GetCurrentProcess();
+		if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
+			envSize = 0;
+			if (0 == j9util_open_system_library("userenv", &handle, TRUE)) {
+				if (i == propIndex) {
+					if (0 == j9sl_lookup_name(handle, "GetUserProfileDirectoryW", (UDATA *)&func, "ZPLP")) {
+						envSize = EsMaxPath;
+						if (func(token, unicodeHome, &envSize)) {
+							/* When the SystemDrive environment variable isn't set, such as when j9 is exec'ed
+							 * running JCK tests, we get %SystemDrive%/Documents and Settings/...
+							 */
+							if (!wcsncmp(unicodeHome, L"%SystemDrive%", 13)) {
+								/* Borrow userdir variable, which is used for real below */
+								if (GetSystemDirectoryW(unicodeTemp, EsMaxPath) > 1) {
+									unicodeHome[0] = unicodeTemp[0];
+									unicodeHome[1] = unicodeTemp[1];
+									wcsncpy(&unicodeHome[2], &unicodeHome[13], envSize - 13);
+								}
+							}
+							convertToUTF8(PORTLIB, unicodeHome, userhome, EsMaxPath);
+							strings[propIndex++] = userhome;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (i == propIndex) {
+		/* Fallback to Windows Directory */
+		envSize = (I_32)j9sysinfo_get_env("WINDIR", NULL, 0);
+		if (-1 == envSize) {
+			strings[propIndex++] = "\\";
+		} else {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM);	/* trailing null taken into account */
+			if (!envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("WINDIR", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+		}
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	if (0 == GetCurrentDirectoryW(EsMaxPath, unicodeTemp)) {
+		strings[propIndex++] = "\\";
+	} else {
+		convertToUTF8(PORTLIB, unicodeTemp, userdir, EsMaxPath);
+		strings[propIndex++] = userdir;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	result = createSystemPropertyList(env, strings, propIndex);
+	if (tempdir) {
+		j9mem_free_memory(tempdir);
+	}
+	if (envSpace) {
+		j9mem_free_memory(envSpace);
+	}
+	return result;
+}
+
+#else /* defined(WIN32) */
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	char *charResult = NULL;
+	char *envSpace = NULL;
+	jobject plist = NULL;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath] = {0};
+#endif /* JAVA_SPEC_VERSION < 17 */
+	char home[EsMaxPath] = {0};
+	char *homeAlloc = NULL;
+	J9VMThread *currentThread = (J9VMThread*)env;
+	J9JavaVM *vm = currentThread->javaVM;
+	J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
+
+	/* Hard coded file/path separators and other values */
+
+#if defined(J9ZOS390)
+	if (J2SE_VERSION_FROM_ENV(env)) {
+		strings[propIndex++] = "platform.notASCII";
+		strings[propIndex++] = "true";
+
+		strings[propIndex++] = "os.encoding";
+		strings[propIndex++] = "ISO8859_1";
+	}
+#endif
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "/";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\n";
+
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	charResult = getcwd(userdir, EsMaxPath);
+	if (NULL == charResult) {
+		strings[propIndex++] = ".";
+	} else {
+		strings[propIndex++] = charResult;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	charResult = NULL;
+#if defined(J9ZOS390)
+	charResult = getenv("HOME");
+	if (NULL != charResult) {
+		strings[propIndex++] = charResult;
+	} else {
+		uid_t uid = geteuid();
+		if (0 != uid) {
+			struct passwd *userDescription = getpwuid(uid);
+			if (NULL != userDescription) {
+				charResult = userDescription->pw_dir;
+				strings[propIndex++] = charResult;
+			}
+		} else {
+			char *loginID = getlogin();
+			if (NULL != loginID) {
+				struct passwd *userDescription = getpwnam(loginID);
+				if (NULL != userDescription) {
+					charResult = userDescription->pw_dir;
+					strings[propIndex++] = charResult;
+				}
+			}
+		}
+	}
+
+	/* there exist situations where one of the above calls will fail.  Fall through to the Unix solution for those cases */
+#endif
+#if defined(J9VM_OPT_CRIU_SUPPORT)
+	/* Skip getpwuid if a checkpoint can be taken.
+	 * https://github.com/eclipse-openj9/openj9/issues/15800
+	 */
+	if (!vmFuncs->isCheckpointAllowed(vm))
+#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */
+	{
+		/*[PR 101939] user.home not set correctly when j9 invoked via execve(x,y,null) */
+		if (NULL == charResult) {
+			struct passwd *pwentry = getpwuid(getuid());
+			if (NULL != pwentry) {
+				charResult = pwentry->pw_dir;
+				strings[propIndex++] = charResult;
+			}
+		}
+	}
+
+	if (NULL == charResult) {
+		IDATA result = j9sysinfo_get_env("HOME", home, sizeof(home));
+		strings[propIndex] = ".";
+		if (0 == result) {
+			if (strlen(home) > 0) {
+				strings[propIndex] = home;
+			}
+		} else if (result > 0) {
+			homeAlloc = j9mem_allocate_memory(result, OMRMEM_CATEGORY_VM);
+			if (NULL != homeAlloc) {
+				result = j9sysinfo_get_env("HOME", homeAlloc, result);
+				if (0 == result) {
+					strings[propIndex] = homeAlloc;
+				}
+			} else {
+				vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
+				goto failed;
+			}
+		}
+		propIndex += 1;
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &envSpace);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	plist = createSystemPropertyList(env, strings, propIndex);
+	if (NULL != envSpace) {
+		j9mem_free_memory(envSpace);
+	}
+
+failed:
+	if (NULL != homeAlloc) {
+		j9mem_free_memory(homeAlloc);
+	}
+	return plist;
+}
+
+#endif /* defined(WIN32) */
+
+/**
+ * @brief Get the default system properties.
+ *
+ * @return an Object array of system property key value pairs
+ */
+jobjectArray
+getSystemPropertyList(JNIEnv *env)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	int propIndex = 0;
+	jobject propertyList = NULL;
+#define PROPERTY_COUNT 137
+#if JAVA_SPEC_VERSION < 17
+	char *propertyKey = NULL;
+	const char * language = NULL;
+	const char * region = NULL;
+	const char * variant = NULL;
+#endif /* JAVA_SPEC_VERSION < 17 */
+	const char *strings[PROPERTY_COUNT] = {0};
+#define USERNAME_LENGTH 128
+	char username[USERNAME_LENGTH] = {0};
+	char *usernameAlloc = NULL;
+	/* buffer to hold the size of the maximum direct byte buffer allocations */
+	char maxDirectMemBuff[24] = {0};
+	IDATA result = 0;
+
+	J9VMThread *currentThread = (J9VMThread*)env;
+	J9JavaVM *javaVM = currentThread->javaVM;
+	J9InternalVMFunctions *vmFuncs = javaVM->internalVMFunctions;
+
+	/* Change the allocation value PROPERTY_COUNT above as you add/remove properties,
+	 * then follow the propIndex++ convention and consume 2 * slots for each property. 2 * number of property keys is the
+	 * correct allocation.
+	 * Also note the call to addSystemProperties below, which may add some configuration-specific properties.  Be sure to leave
+	 * enough room in the property list for all possibilities.
+	 */
+
+	if (J9_GC_POLICY_METRONOME == javaVM->omrVM->gcPolicy) {
+		strings[propIndex++] = "com.ibm.jvm.realtime";
+		strings[propIndex++] = "soft";
+	}
+
+#if defined(J9VM_OPT_SHARED_CLASSES)
+	strings[propIndex++] = "com.ibm.oti.shared.enabled";
+	if ((NULL != javaVM->sharedClassConfig)
+		&& J9_ARE_ALL_BITS_SET(javaVM->sharedClassConfig->runtimeFlags, J9SHR_RUNTIMEFLAG_ENABLE_CACHE_NON_BOOT_CLASSES)
+	) {
+		strings[propIndex++] = "true";
+	} else {
+		strings[propIndex++] = "false";
+	}
+#endif
+
+	strings[propIndex++] = "ibm.signalhandling.sigchain";
+	if (J9_ARE_ANY_BITS_SET(javaVM->sigFlags, J9_SIG_NO_SIG_CHAIN)) {
+		strings[propIndex++] = "false";
+	} else {
+		strings[propIndex++] = "true";
+	}
+	strings[propIndex++] = "ibm.signalhandling.sigint";
+	if (J9_ARE_ANY_BITS_SET(javaVM->sigFlags, J9_SIG_NO_SIG_INT)) {
+		strings[propIndex++] = "false";
+	} else {
+		strings[propIndex++] = "true";
+	}
+
+	/* The JCLs use ibm.signalhandling.rs to determine if they should prevent the registration of signal handlers for what
+	 * 	we consider to be asynchronous signals.
+	 * The JCLs do not install handlers for any synchronous signals */
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Please shorten the lines of this comment; `*/` goes on a line by itself.
created_at: 2025-03-06T15:02:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,651 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env) ? JNI_TRUE : JNI_FALSE;
+}
+
+typedef struct {
+	int errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData * iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jclass stringClass = NULL;
+	jarray args = NULL;
+	int propertyCount = 0;
+
+	stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (!stringClass) {
+		return (jobject) 0;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary* portLibrary, const wchar_t* unicodeString, char* utf8Buffer, UDATA size)
+{
+	PORT_ACCESS_FROM_PORT(portLibrary);
+	if (0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
+		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
+		return -1;
+	}
+	return 0;
+}
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
+	OSVERSIONINFO versionInfo;
+#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
+	I_32 envSize = 0;
+	char *envSpace = NULL;
+	char *tempdir = NULL;
+	jobject result = NULL;
+	char userhome[EsMaxPath];
+	wchar_t unicodeTemp[EsMaxPath];
+	int i = 0;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath];
+#endif /* JAVA_SPEC_VERSION < 17 */
+	wchar_t unicodeHome[EsMaxPath];
+	HANDLE process = 0;
+	HANDLE token = 0;
+	UDATA handle = 0;
+	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
+
+	/* Hard coded file/path separators and other values */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "\\";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\r\n";
+
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &tempdir);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	i = propIndex;
+	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
+	if (-1 != envSize) {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+			if (NULL == envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+	}
+#if defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE)
+	/* dwPlatformId, VER_PLATFORM_WIN32_NT = https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
+	if ((i == propIndex) && IsWindowsVersionOrGreater( 5, 0, 0))
+#else /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+#pragma warning(suppress : 4996) /* ignore warning 'GetVersionExA': was declared deprecated */
+	if ((i == propIndex) && GetVersionEx(&versionInfo) && (VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId))
+#endif /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	{
+		process = GetCurrentProcess();
+		if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
+			envSize = 0;
+			if (0 == j9util_open_system_library("userenv", &handle, TRUE)) {
+				if (i == propIndex) {
+					if (0 == j9sl_lookup_name(handle, "GetUserProfileDirectoryW", (UDATA *)&func, "ZPLP")) {
+						envSize = EsMaxPath;
+						if (func(token, unicodeHome, &envSize)) {
+							/* When the SystemDrive environment variable isn't set, such as when j9 is exec'ed
+							 * running JCK tests, we get %SystemDrive%/Documents and Settings/...
+							 */
+							if (!wcsncmp(unicodeHome, L"%SystemDrive%", 13)) {
+								/* Borrow userdir variable, which is used for real below */
+								if (GetSystemDirectoryW(unicodeTemp, EsMaxPath) > 1) {
+									unicodeHome[0] = unicodeTemp[0];
+									unicodeHome[1] = unicodeTemp[1];
+									wcsncpy(&unicodeHome[2], &unicodeHome[13], envSize - 13);
+								}
+							}
+							convertToUTF8(PORTLIB, unicodeHome, userhome, EsMaxPath);
+							strings[propIndex++] = userhome;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (i == propIndex) {
+		/* Fallback to Windows Directory */
+		envSize = (I_32)j9sysinfo_get_env("WINDIR", NULL, 0);
+		if (-1 == envSize) {
+			strings[propIndex++] = "\\";
+		} else {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM);	/* trailing null taken into account */
+			if (!envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("WINDIR", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+		}
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	if (0 == GetCurrentDirectoryW(EsMaxPath, unicodeTemp)) {
+		strings[propIndex++] = "\\";
+	} else {
+		convertToUTF8(PORTLIB, unicodeTemp, userdir, EsMaxPath);
+		strings[propIndex++] = userdir;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	result = createSystemPropertyList(env, strings, propIndex);
+	if (tempdir) {
+		j9mem_free_memory(tempdir);
+	}
+	if (envSpace) {
+		j9mem_free_memory(envSpace);
+	}
+	return result;
+}
+
+#else /* defined(WIN32) */
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	char *charResult = NULL;
+	char *envSpace = NULL;
+	jobject plist = NULL;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath] = {0};
+#endif /* JAVA_SPEC_VERSION < 17 */
+	char home[EsMaxPath] = {0};
+	char *homeAlloc = NULL;
+	J9VMThread *currentThread = (J9VMThread*)env;
+	J9JavaVM *vm = currentThread->javaVM;
+	J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
+
+	/* Hard coded file/path separators and other values */
+
+#if defined(J9ZOS390)
+	if (J2SE_VERSION_FROM_ENV(env)) {
+		strings[propIndex++] = "platform.notASCII";
+		strings[propIndex++] = "true";
+
+		strings[propIndex++] = "os.encoding";
+		strings[propIndex++] = "ISO8859_1";
+	}
+#endif
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "/";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\n";
+
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	charResult = getcwd(userdir, EsMaxPath);
+	if (NULL == charResult) {
+		strings[propIndex++] = ".";
+	} else {
+		strings[propIndex++] = charResult;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	charResult = NULL;
+#if defined(J9ZOS390)
+	charResult = getenv("HOME");
+	if (NULL != charResult) {
+		strings[propIndex++] = charResult;
+	} else {
+		uid_t uid = geteuid();
+		if (0 != uid) {
+			struct passwd *userDescription = getpwuid(uid);
+			if (NULL != userDescription) {
+				charResult = userDescription->pw_dir;
+				strings[propIndex++] = charResult;
+			}
+		} else {
+			char *loginID = getlogin();
+			if (NULL != loginID) {
+				struct passwd *userDescription = getpwnam(loginID);
+				if (NULL != userDescription) {
+					charResult = userDescription->pw_dir;
+					strings[propIndex++] = charResult;
+				}
+			}
+		}
+	}
+
+	/* there exist situations where one of the above calls will fail.  Fall through to the Unix solution for those cases */
+#endif
+#if defined(J9VM_OPT_CRIU_SUPPORT)
+	/* Skip getpwuid if a checkpoint can be taken.
+	 * https://github.com/eclipse-openj9/openj9/issues/15800
+	 */
+	if (!vmFuncs->isCheckpointAllowed(vm))
+#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */
+	{
+		/*[PR 101939] user.home not set correctly when j9 invoked via execve(x,y,null) */
+		if (NULL == charResult) {
+			struct passwd *pwentry = getpwuid(getuid());
+			if (NULL != pwentry) {
+				charResult = pwentry->pw_dir;
+				strings[propIndex++] = charResult;
+			}
+		}
+	}
+
+	if (NULL == charResult) {
+		IDATA result = j9sysinfo_get_env("HOME", home, sizeof(home));
+		strings[propIndex] = ".";
+		if (0 == result) {
+			if (strlen(home) > 0) {
+				strings[propIndex] = home;
+			}
+		} else if (result > 0) {
+			homeAlloc = j9mem_allocate_memory(result, OMRMEM_CATEGORY_VM);
+			if (NULL != homeAlloc) {
+				result = j9sysinfo_get_env("HOME", homeAlloc, result);
+				if (0 == result) {
+					strings[propIndex] = homeAlloc;
+				}
+			} else {
+				vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
+				goto failed;
+			}
+		}
+		propIndex += 1;
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &envSpace);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	plist = createSystemPropertyList(env, strings, propIndex);
+	if (NULL != envSpace) {
+		j9mem_free_memory(envSpace);
+	}
+
+failed:
+	if (NULL != homeAlloc) {
+		j9mem_free_memory(homeAlloc);
+	}
+	return plist;
+}
+
+#endif /* defined(WIN32) */
+
+/**
+ * @brief Get the default system properties.
+ *
+ * @return an Object array of system property key value pairs
+ */
+jobjectArray
+getSystemPropertyList(JNIEnv *env)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	int propIndex = 0;
+	jobject propertyList = NULL;
+#define PROPERTY_COUNT 137
+#if JAVA_SPEC_VERSION < 17
+	char *propertyKey = NULL;
+	const char * language = NULL;
+	const char * region = NULL;
+	const char * variant = NULL;
+#endif /* JAVA_SPEC_VERSION < 17 */
+	const char *strings[PROPERTY_COUNT] = {0};
+#define USERNAME_LENGTH 128
+	char username[USERNAME_LENGTH] = {0};
+	char *usernameAlloc = NULL;
+	/* buffer to hold the size of the maximum direct byte buffer allocations */
+	char maxDirectMemBuff[24] = {0};
+	IDATA result = 0;
+
+	J9VMThread *currentThread = (J9VMThread*)env;
+	J9JavaVM *javaVM = currentThread->javaVM;
+	J9InternalVMFunctions *vmFuncs = javaVM->internalVMFunctions;
+
+	/* Change the allocation value PROPERTY_COUNT above as you add/remove properties,
+	 * then follow the propIndex++ convention and consume 2 * slots for each property. 2 * number of property keys is the
+	 * correct allocation.
+	 * Also note the call to addSystemProperties below, which may add some configuration-specific properties.  Be sure to leave
+	 * enough room in the property list for all possibilities.
+	 */
+
+	if (J9_GC_POLICY_METRONOME == javaVM->omrVM->gcPolicy) {
+		strings[propIndex++] = "com.ibm.jvm.realtime";
+		strings[propIndex++] = "soft";
+	}
+
+#if defined(J9VM_OPT_SHARED_CLASSES)
+	strings[propIndex++] = "com.ibm.oti.shared.enabled";
+	if ((NULL != javaVM->sharedClassConfig)
+		&& J9_ARE_ALL_BITS_SET(javaVM->sharedClassConfig->runtimeFlags, J9SHR_RUNTIMEFLAG_ENABLE_CACHE_NON_BOOT_CLASSES)
+	) {
+		strings[propIndex++] = "true";
+	} else {
+		strings[propIndex++] = "false";
+	}
+#endif
+
+	strings[propIndex++] = "ibm.signalhandling.sigchain";
+	if (J9_ARE_ANY_BITS_SET(javaVM->sigFlags, J9_SIG_NO_SIG_CHAIN)) {
+		strings[propIndex++] = "false";
+	} else {
+		strings[propIndex++] = "true";
+	}
+	strings[propIndex++] = "ibm.signalhandling.sigint";
+	if (J9_ARE_ANY_BITS_SET(javaVM->sigFlags, J9_SIG_NO_SIG_INT)) {
+		strings[propIndex++] = "false";
+	} else {
+		strings[propIndex++] = "true";
+	}
+
+	/* The JCLs use ibm.signalhandling.rs to determine if they should prevent the registration of signal handlers for what
+	 * 	we consider to be asynchronous signals.
+	 * The JCLs do not install handlers for any synchronous signals */
+	strings[propIndex++] = "ibm.signalhandling.rs";
+	if (J9_ARE_ALL_BITS_SET(javaVM->sigFlags, J9_SIG_XRS_ASYNC)) {
+		strings[propIndex++] = "true";
+	} else {
+		strings[propIndex++] = "false";
+	}
+
+	strings[propIndex++] = "com.ibm.vm.bitmode";
+#ifdef J9VM_ENV_DATA64
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Please use `#if defined(X)` instead of `#ifdef X` and add the missing comments (lines 1961-1980).
created_at: 2025-03-06T15:03:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -32,24 +39,28 @@
 #include "vmargs_api.h"
 #include "vendor_version.h"
 
+#if defined(J9ZOS390)
+#include "atoe.h"
+#endif /* defined(J9ZOS390) */
+
 #if defined(LINUX)
 /* Copy the system properties names and values into malloced memory */
 static void copySystemProperties(J9JavaVM* vm);
 #endif /* defined(LINUX) */
 
-static U_8*  unicodeEscapeStringToMUtf8(J9JavaVM * vm, const char* escapeString, UDATA escapeLength);
+static U_8 * unicodeEscapeStringToMUtf8(J9JavaVM *vm, const char *escapeString, UDATA escapeLength);
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: No space after `*`.
created_at: 2025-03-06T16:34:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -315,7 +326,7 @@ addPropertyForOptionWithModuleListArg(J9JavaVM *vm, const char *optionName, IDAT
 {
 	IDATA argIndex = -1;
 	UDATA rc = J9SYSPROP_ERROR_NONE;
-	J9VMInitArgs* j9vm_args	= vm->vmArgsArray;
+	J9VMInitArgs *j9vm_args	= vm->vmArgsArray;
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Please use a space before `=` (not a tab).
created_at: 2025-03-06T16:34:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1174,21 +1186,21 @@ getJ9VMVersionString(J9JavaVM *vm) {
 
 
 UDATA
-addSystemProperty(J9JavaVM * vm, const char* propName,  const char* propValue, UDATA flags)
+addSystemProperty(J9JavaVM *vm, const char *propName,  const char *propValue, UDATA flags)
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Just one space after each comma.
created_at: 2025-03-06T16:35:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1249,11 +1261,11 @@ setSystemProperty(J9JavaVM * vm, J9VMSystemProperty * property, const char * val
  * @return buffer containing the transliterated string or NULL in case of error
  */
 #define TRANSCODE_BUFFER_SIZE 64
-static U_8*
-unicodeEscapeStringToMUtf8(J9JavaVM * vm, const char* escapeString, UDATA escapeLength) {
+static U_8 *
+unicodeEscapeStringToMUtf8(J9JavaVM *vm, const char *escapeString, UDATA escapeLength) {
 	U_16 localUnicodeBuffer[TRANSCODE_BUFFER_SIZE]; /* handle short strings without allocating memory */
-	U_16* unicodeBuffer = localUnicodeBuffer;
-	UDATA bufferLength = (escapeLength+1)*2; /* This is an overestimate */
+	U_16 *unicodeBuffer = localUnicodeBuffer;
+	UDATA bufferLength = (escapeLength + 1) * 2; /* This is an overestimate */
 	const char *cursor;
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Missing initialization.
created_at: 2025-03-06T16:35:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,648 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env);
+}
+
+typedef struct {
+	jboolean errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData *iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Only `JNI_TRUE` or `JNI_FALSE` should be written to `errorOccurred`.
created_at: 2025-03-06T16:36:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,648 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env);
+}
+
+typedef struct {
+	jboolean errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData *iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jarray args = NULL;
+	int propertyCount = 0;
+	jclass stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (NULL == stringClass) {
+		return NULL;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Missing explicit comparison:
```
	if (0 != propertyCount) {
```
created_at: 2025-03-06T16:37:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,648 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env);
+}
+
+typedef struct {
+	jboolean errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData *iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jarray args = NULL;
+	int propertyCount = 0;
+	jclass stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (NULL == stringClass) {
+		return NULL;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Please tidy this up (no internal tabs).
```c
		/* printf("\nFailed to create arg array"); */
```
created_at: 2025-03-06T16:38:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,648 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env);
+}
+
+typedef struct {
+	jboolean errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData *iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	/* Then the value */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, value)) {
+		iteratorData->errorOccurred = 1;
+		return;
+	}
+
+	Trc_systemPropertyIterator(env, key, value);
+}
+
+jobject
+createSystemPropertyList(JNIEnv *env, const char *defaultValues[], int defaultCount)
+{
+	VMI_ACCESS_FROM_ENV(env);
+
+	jint i = 0;
+	jint nCommandLineDefines = 0;
+	jarray args = NULL;
+	int propertyCount = 0;
+	jclass stringClass = (*env)->FindClass(env, "java/lang/String");
+	if (NULL == stringClass) {
+		return NULL;
+	}
+
+	(*VMI)->CountSystemProperties(VMI, &propertyCount);
+	if (propertyCount) {
+		CreateSystemPropertiesData iteratorData;
+
+		args = (*env)->NewObjectArray(env, defaultCount + (propertyCount * 2), stringClass, NULL);
+		if (NULL == args) {
+			return NULL;
+		}
+
+		iteratorData.errorOccurred = 0;
+		iteratorData.args = args;
+		iteratorData.nCommandLineDefines = nCommandLineDefines;
+		iteratorData.env = env;
+		iteratorData.defaultValues = defaultValues;
+		iteratorData.defaultCount = defaultCount;
+
+		iteratorData.stringClass = stringClass;
+		(*VMI)->IterateSystemProperties(VMI, systemPropertyIterator, &iteratorData);
+		if (iteratorData.errorOccurred) {
+			return NULL;
+		}
+		nCommandLineDefines = iteratorData.nCommandLineDefines;
+	}
+
+	if (NULL == args) {
+		args = (*env)->NewObjectArray(env, defaultCount, stringClass, NULL);
+	}
+	if (NULL == args) {
+/*		printf("\nFailed to create arg array");*/
+		return NULL;
+	}
+
+	for (i = 0; i < defaultCount; ++i) {
+		if (NULL == defaultValues[i]) {
+			continue;
+		}
+		if (propertyListAddString(env, args, nCommandLineDefines, defaultValues[i])) {
+			return NULL;
+		}
+		nCommandLineDefines++;
+	}
+
+	return args;
+}
+
+#if defined(WIN32)
+
+/**
+ * @internal
+ * Converts the Unicode string to UTF8 encoded data in the provided buffer.
+ *
+ * @param[in] portLibrary The port library
+ * @param[in] unicodeString The unicode buffer to convert
+ * @param[in] utf8Buffer The buffer to store the UTF8 encoded bytes into
+ * @param[in] size The size of utf8Buffer
+ *
+ * @return 0 on success, -1 on failure.
+ */
+static I_32
+convertToUTF8(J9PortLibrary *portLibrary, const wchar_t *unicodeString, char *utf8Buffer, UDATA size)
+{
+	PORT_ACCESS_FROM_PORT(portLibrary);
+	if (0 == WideCharToMultiByte(OS_ENCODING_CODE_PAGE, OS_ENCODING_WC_FLAGS, unicodeString, -1, utf8Buffer, (int)size, NULL, NULL)) {
+		j9error_set_last_error(GetLastError(), J9PORT_ERROR_OPFAILED); /* continue */
+		return -1;
+	}
+	return 0;
+}
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+#if !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE)
+	OSVERSIONINFO versionInfo;
+#endif /* !defined(_WIN32_WINNT_WINBLUE) || (_WIN32_WINNT_MAXVER < _WIN32_WINNT_WINBLUE) */
+	I_32 envSize = 0;
+	char *envSpace = NULL;
+	char *tempdir = NULL;
+	jobject result = NULL;
+	char userhome[EsMaxPath];
+	wchar_t unicodeTemp[EsMaxPath];
+	int i = 0;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath];
+#endif /* JAVA_SPEC_VERSION < 17 */
+	wchar_t unicodeHome[EsMaxPath];
+	HANDLE process = 0;
+	HANDLE token = 0;
+	UDATA handle = 0;
+	BOOL (WINAPI *func)(HANDLE hToken, LPWSTR lpProfileDir, LPDWORD lpcchSize);
+
+	/* Hard coded file/path separators and other values */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "\\";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\r\n";
+
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &tempdir);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	i = propIndex;
+	envSize = (I_32)j9sysinfo_get_env("USERPROFILE", NULL, 0);
+	if (-1 != envSize) {
+		envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM); /* trailing null taken into account */
+		if (NULL == envSpace) {
+			strings[propIndex++] = "\\";
+		} else {
+			j9sysinfo_get_env("USERPROFILE", envSpace, envSize);
+			strings[propIndex++] = envSpace;
+		}
+	}
+#if defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE)
+	/* dwPlatformId, VER_PLATFORM_WIN32_NT = https://msdn.microsoft.com/en-us/library/windows/desktop/ms724834(v=vs.85).aspx */
+	if ((i == propIndex) && IsWindowsVersionOrGreater(5, 0, 0))
+#else /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+#pragma warning(suppress : 4996) /* ignore warning 'GetVersionExA': was declared deprecated */
+	if ((i == propIndex) && GetVersionEx(&versionInfo) && (VER_PLATFORM_WIN32_NT == versionInfo.dwPlatformId))
+#endif /* defined(_WIN32_WINNT_WINBLUE) && (_WIN32_WINNT_MAXVER >= _WIN32_WINNT_WINBLUE) */
+	{
+		process = GetCurrentProcess();
+		if (OpenProcessToken(process, TOKEN_QUERY, &token)) {
+			envSize = 0;
+			if (0 == j9util_open_system_library("userenv", &handle, TRUE)) {
+				if (i == propIndex) {
+					if (0 == j9sl_lookup_name(handle, "GetUserProfileDirectoryW", (UDATA *)&func, "ZPLP")) {
+						envSize = EsMaxPath;
+						if (func(token, unicodeHome, &envSize)) {
+							/* When the SystemDrive environment variable isn't set, such as when j9 is exec'ed
+							 * running JCK tests, we get %SystemDrive%/Documents and Settings/...
+							 */
+							if (0 == wcsncmp(unicodeHome, L"%SystemDrive%", 13)) {
+								/* Borrow userdir variable, which is used for real below */
+								if (GetSystemDirectoryW(unicodeTemp, EsMaxPath) > 1) {
+									unicodeHome[0] = unicodeTemp[0];
+									unicodeHome[1] = unicodeTemp[1];
+									wcsncpy(&unicodeHome[2], &unicodeHome[13], envSize - 13);
+								}
+							}
+							convertToUTF8(PORTLIB, unicodeHome, userhome, EsMaxPath);
+							strings[propIndex++] = userhome;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (i == propIndex) {
+		/* Fallback to Windows Directory */
+		envSize = (I_32)j9sysinfo_get_env("WINDIR", NULL, 0);
+		if (-1 == envSize) {
+			strings[propIndex++] = "\\";
+		} else {
+			envSpace = j9mem_allocate_memory(envSize, OMRMEM_CATEGORY_VM);	/* trailing null taken into account */
+			if (NULL == envSpace) {
+				strings[propIndex++] = "\\";
+			} else {
+				j9sysinfo_get_env("WINDIR", envSpace, envSize);
+				strings[propIndex++] = envSpace;
+			}
+		}
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	if (0 == GetCurrentDirectoryW(EsMaxPath, unicodeTemp)) {
+		strings[propIndex++] = "\\";
+	} else {
+		convertToUTF8(PORTLIB, unicodeTemp, userdir, EsMaxPath);
+		strings[propIndex++] = userdir;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	result = createSystemPropertyList(env, strings, propIndex);
+	j9mem_free_memory(tempdir);
+	j9mem_free_memory(envSpace);
+	return result;
+}
+
+#else /* defined(WIN32) */
+
+jobject
+getPlatformPropertyList(JNIEnv *env, const char *strings[], int propIndex)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	char *charResult = NULL;
+	char *envSpace = NULL;
+	jobject plist = NULL;
+#if JAVA_SPEC_VERSION < 17
+	char userdir[EsMaxPath] = {0};
+#endif /* JAVA_SPEC_VERSION < 17 */
+	char home[EsMaxPath] = {0};
+	char *homeAlloc = NULL;
+	J9VMThread *currentThread = (J9VMThread*)env;
+	J9JavaVM *vm = currentThread->javaVM;
+	J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
+
+	/* Hard coded file/path separators and other values */
+
+#if defined(J9ZOS390)
+	if (J2SE_VERSION_FROM_ENV(env)) {
+		strings[propIndex++] = "platform.notASCII";
+		strings[propIndex++] = "true";
+
+		strings[propIndex++] = "os.encoding";
+		strings[propIndex++] = "ISO8859_1";
+	}
+#endif /* defined(J9ZOS390) */
+
+#if JAVA_SPEC_VERSION < 17
+	strings[propIndex++] = "file.separator";
+	strings[propIndex++] = "/";
+
+	strings[propIndex++] = "line.separator";
+	strings[propIndex++] = "\n";
+
+	/* Get the directory where the executable was started */
+	strings[propIndex++] = "user.dir";
+	charResult = getcwd(userdir, EsMaxPath);
+	if (NULL == charResult) {
+		strings[propIndex++] = ".";
+	} else {
+		strings[propIndex++] = charResult;
+	}
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	strings[propIndex++] = "user.home";
+	charResult = NULL;
+#if defined(J9ZOS390)
+	charResult = getenv("HOME");
+	if (NULL != charResult) {
+		strings[propIndex++] = charResult;
+	} else {
+		uid_t uid = geteuid();
+		if (0 != uid) {
+			struct passwd *userDescription = getpwuid(uid);
+			if (NULL != userDescription) {
+				charResult = userDescription->pw_dir;
+				strings[propIndex++] = charResult;
+			}
+		} else {
+			char *loginID = getlogin();
+			if (NULL != loginID) {
+				struct passwd *userDescription = getpwnam(loginID);
+				if (NULL != userDescription) {
+					charResult = userDescription->pw_dir;
+					strings[propIndex++] = charResult;
+				}
+			}
+		}
+	}
+
+	/* There exist situations where one of the above calls will fail.
+	 * Fall through to the Unix solution for those cases.
+	 */
+#endif /* defined(J9ZOS390) */
+#if defined(J9VM_OPT_CRIU_SUPPORT)
+	/* Skip getpwuid if a checkpoint can be taken.
+	 * https://github.com/eclipse-openj9/openj9/issues/15800
+	 */
+	if (!vmFuncs->isCheckpointAllowed(vm))
+#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */
+	{
+		/*[PR 101939] user.home not set correctly when j9 invoked via execve(x,y,null) */
+		if (NULL == charResult) {
+			struct passwd *pwentry = getpwuid(getuid());
+			if (NULL != pwentry) {
+				charResult = pwentry->pw_dir;
+				strings[propIndex++] = charResult;
+			}
+		}
+	}
+
+	if (NULL == charResult) {
+		IDATA result = j9sysinfo_get_env("HOME", home, sizeof(home));
+		strings[propIndex] = ".";
+		if (0 == result) {
+			if (strlen(home) > 0) {
+				strings[propIndex] = home;
+			}
+		} else if (result > 0) {
+			homeAlloc = j9mem_allocate_memory(result, OMRMEM_CATEGORY_VM);
+			if (NULL != homeAlloc) {
+				result = j9sysinfo_get_env("HOME", homeAlloc, result);
+				if (0 == result) {
+					strings[propIndex] = homeAlloc;
+				}
+			} else {
+				vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
+				goto failed;
+			}
+		}
+		propIndex += 1;
+	}
+
+#if JAVA_SPEC_VERSION < 17
+	/* Get the Temp Dir name */
+	strings[propIndex++] = "java.io.tmpdir";
+	strings[propIndex++] = getTmpDir(env, &envSpace);
+#endif /* JAVA_SPEC_VERSION < 17 */
+
+	if (JAVA_SPEC_VERSION < 12) {
+		/* Get the timezone */
+		strings[propIndex++] = "user.timezone";
+		strings[propIndex++] = "";
+	}
+
+	plist = createSystemPropertyList(env, strings, propIndex);
+	if (NULL != envSpace) {
+		j9mem_free_memory(envSpace);
+	}
+
+failed:
+	if (NULL != homeAlloc) {
+		j9mem_free_memory(homeAlloc);
+	}
+	return plist;
+}
+
+#endif /* defined(WIN32) */
+
+/**
+ * @brief Get the default system properties.
+ *
+ * @return an Object array of system property key value pairs
+ */
+jobjectArray
+getSystemPropertyList(JNIEnv *env)
+{
+	PORT_ACCESS_FROM_ENV(env);
+	int propIndex = 0;
+	jobject propertyList = NULL;
+#define PROPERTY_COUNT 137
+#if JAVA_SPEC_VERSION < 17
+	char *propertyKey = NULL;
+	const char *language = NULL;
+	const char *region = NULL;
+	const char *variant = NULL;
+#endif /* JAVA_SPEC_VERSION < 17 */
+	const char *strings[PROPERTY_COUNT] = {0};
+#define USERNAME_LENGTH 128
+	char username[USERNAME_LENGTH] = {0};
+	char *usernameAlloc = NULL;
+	/* buffer to hold the size of the maximum direct byte buffer allocations */
+	char maxDirectMemBuff[24] = {0};
+	IDATA result = 0;
+
+	J9VMThread *currentThread = (J9VMThread*)env;
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Space before `*`, please.
created_at: 2025-03-06T16:38:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,648 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env);
+}
+
+typedef struct {
+	jboolean errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData *iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
path: runtime/vm/vmprops.c
user: login: keithc-ca
body: Line 1553 should use `JNI_FALSE` instead of `0`.
created_at: 2025-03-06T20:34:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1433,3 +1445,648 @@ getMUtf8String(J9JavaVM *vm, const char *userString, UDATA stringLength)
 	}
 	return result;
 }
+
+/**
+ * @return JNI_FALSE on success, JNI_TRUE on error
+ */
+static jboolean
+propertyListAddString(JNIEnv *env, jarray array, jint arrayIndex, const char *value)
+{
+	/* String must be well-formed modified UTF-8 */
+	jobject str = (*env)->NewStringUTF(env, value);
+	if (NULL != str) {
+		(*env)->SetObjectArrayElement(env, array, arrayIndex, str);
+	}
+	/* NewStringUTF does not throw an exception, other than OutOfMemory */
+	return (*env)->ExceptionCheck(env);
+}
+
+typedef struct {
+	jboolean errorOccurred;
+	jobject args;
+	jint nCommandLineDefines;
+	JNIEnv *env;
+	const char **defaultValues;
+	int defaultCount;
+	jclass stringClass;
+} CreateSystemPropertiesData;
+
+static void JNICALL
+systemPropertyIterator(char *key, char *value, void *userData)
+{
+	CreateSystemPropertiesData *iteratorData = userData;
+	jobject args = iteratorData->args;
+	JNIEnv *env = iteratorData->env;
+	const char **defaultValues = iteratorData->defaultValues;
+	int defaultCount = iteratorData->defaultCount;
+	jint i = 0;
+
+	/* CMVC 95717: if an error has already occurred get out of here */
+	if (iteratorData->errorOccurred) {
+		return;
+	}
+
+	if (0 == strcmp("com.ibm.oti.shared.enabled", key)) {
+		/* JAZZ103 85641: Prevent com.ibm.oti.shared.enabled from being overwritten by a command line option */
+		return;
+	}
+
+#if JAVA_SPEC_VERSION >= 21
+	if (0 == strcmp("java.compiler", key)) {
+		PORT_ACCESS_FROM_ENV(env);
+		if ((0 == strcmp("jitc", value)) || (0 == strcmp(J9_JIT_DLL_NAME, value))) {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XJIT);
+		} else {
+			j9nls_printf(PORTLIB, J9NLS_WARNING, J9NLS_VM_JAVA_COMPILER_WARNING_XINT);
+		}
+		return;
+	}
+#endif /* JAVA_SPEC_VERSION >= 21 */
+
+	/* check for overridden system properties, use linear scan for now */
+	for (i = 0; i < defaultCount; i += 2) {
+		if ((NULL != defaultValues[i]) && (0 == strcmp(key, defaultValues[i]))) {
+			defaultValues[i] = NULL;
+			defaultValues[i + 1] = NULL;
+			break;
+		}
+	}
+
+	/* First do the key */
+	if (propertyListAddString(env, args, iteratorData->nCommandLineDefines++, key)) {
+		iteratorData->errorOccurred = 1;
path: runtime/vm/vmprops.c
user: login: pshipton
body: Updated.
created_at: 2025-03-06T21:29:59Z
author_association: MEMBER

PR comments:
user: login: pshipton
created_at: 2025-02-26T20:31:30Z
body: @keithc-ca thoughts on this? I moved the code to the VM, but instead I could move it all to util. Atm it's called from both Java_java_lang_System_getPropertyList and JVM_GetProperties, but in the end jdk 8 - 11 will use the native and jdk17+ will use JVM_GetProperties.
author_association: MEMBER
user: login: keithc-ca
created_at: 2025-02-26T20:51:03Z
body: Moving it to `util` implies a copy of the code for each shared library that uses it - that doesn't appeal to me.

Ideally, `Java_java_lang_System_getPropertyList()` would just use `JVM_GetProperties()` (in all versions where the former is needed). What problems prevent that?
author_association: CONTRIBUTOR
user: login: pshipton
created_at: 2025-02-26T21:06:57Z
body: Once all the changes are done, we only need either Java_java_lang_System_getPropertyList() or JVM_GetProperties(), not both, there will only be one copy of getSystemPropertyList() linked in. The JCL natives or VM don't link with libjvm.so, I didn't find anything else in JCL or VM that calls a JVM function.

We need to phase the changes in, but I could start by stubbing JVM_GetProperties() so the extensions changes can be done, and then deliver everything on the VM side at once. It may be easier to review if I break it up though. I thought I'd move the code around mostly unchanged, and then start changing it separately.
author_association: MEMBER
user: login: pshipton
created_at: 2025-03-01T19:01:12Z
body: Updated.
author_association: MEMBER
user: login: pshipton
created_at: 2025-03-06T14:23:32Z
body: I've made the formatting changes.
author_association: MEMBER
user: login: pshipton
created_at: 2025-03-06T15:49:01Z
body: Updated.
author_association: MEMBER
user: login: pshipton
created_at: 2025-03-06T19:29:18Z
body: Updated.
author_association: MEMBER
user: login: keithc-ca
created_at: 2025-03-06T22:58:03Z
body: Jenkins test sanity win,win32,zlinux jdk8
author_association: CONTRIBUTOR
user: login: keithc-ca
created_at: 2025-03-06T23:10:05Z
body: Jenkins test sanity alinux,win jdk11,jdk17,jdk21


author_association: CONTRIBUTOR
user: login: keithc-ca
created_at: 2025-03-07T16:07:27Z
body: The jdk11 failure on aarch64_linux looks like https://github.com/eclipse-openj9/openj9/issues/13756.
Windows testing exceeded the time limit, but also appeared to hit https://github.com/eclipse-openj9/openj9/issues/18704, which is unrelated to this change.

author_association: CONTRIBUTOR
user: login: pshipton
created_at: 2025-03-07T23:34:32Z
body: Due to https://github.com/eclipse-openj9/openj9/issues/21311 I'm going to revert this until it can be fixed.
It's also failing in the jdk21 nightly build on amac.
author_association: MEMBER
user: login: pshipton
created_at: 2025-03-07T23:35:16Z
body: Reverted via https://github.com/eclipse-openj9/openj9/pull/21313
author_association: MEMBER