diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index b344d5ed932..ff199adc370 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -754,7 +754,6 @@ do_alias(appendToClassPathForInstrumentation_signature, string_void_signature) \ template(serializePropertiesToByteArray_name, "serializePropertiesToByteArray") \ template(serializeAgentPropertiesToByteArray_name, "serializeAgentPropertiesToByteArray") \ - template(serializeSavedPropertiesToByteArray_name, "serializeSavedPropertiesToByteArray") \ template(encodeThrowable_name, "encodeThrowable") \ template(encodeThrowable_signature, "(Ljava/lang/Throwable;JI)I") \ template(decodeAndThrowThrowable_name, "decodeAndThrowThrowable") \ diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index 430b7a59262..348604fa937 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -37,6 +37,7 @@ #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/deoptimization.hpp" +#include "runtime/fieldDescriptor.inline.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/javaCalls.hpp" #include "runtime/thread.inline.hpp" @@ -45,9 +46,6 @@ #include "jvmci/jvmciCompiler.hpp" #include "jvmci/jvmciRuntime.hpp" -jbyte* JVMCIEnv::_serialized_saved_properties = nullptr; -int JVMCIEnv::_serialized_saved_properties_len = 0; - JVMCICompileState::JVMCICompileState(CompileTask* task, JVMCICompiler* compiler): _task(task), _compiler(compiler), @@ -117,76 +115,6 @@ bool JVMCICompileState::jvmti_state_changed() const { return false; } -jbyte* JVMCIEnv::get_serialized_saved_properties(int& props_len, TRAPS) { - jbyte* props = _serialized_saved_properties; - if (props == nullptr) { - // load VMSupport - Symbol* klass = vmSymbols::jdk_internal_vm_VMSupport(); - Klass* k = SystemDictionary::resolve_or_fail(klass, true, CHECK_NULL); - - InstanceKlass* ik = InstanceKlass::cast(k); - if (ik->should_be_initialized()) { - ik->initialize(CHECK_NULL); - } - - // invoke the serializeSavedPropertiesToByteArray method - JavaValue result(T_OBJECT); - JavaCallArguments args; - - Symbol* signature = vmSymbols::void_byte_array_signature(); - JavaCalls::call_static(&result, - ik, - vmSymbols::serializeSavedPropertiesToByteArray_name(), - signature, - &args, - CHECK_NULL); - - oop res = result.get_oop(); - assert(res->is_typeArray(), "must be"); - assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "must be"); - typeArrayOop ba = typeArrayOop(res); - props_len = ba->length(); - - // Copy serialized saved properties from HotSpot object into C heap - props = NEW_C_HEAP_ARRAY(jbyte, props_len, mtJVMCI); - memcpy(props, ba->byte_at_addr(0), props_len); - - _serialized_saved_properties_len = props_len; - _serialized_saved_properties = props; - } else { - props_len = _serialized_saved_properties_len; - } - return props; -} - -void JVMCIEnv::copy_saved_properties(jbyte* properties, int properties_len, JVMCI_TRAPS) { - assert(!is_hotspot(), "can only copy saved properties from HotSpot to native image"); - JavaThread* thread = JavaThread::current(); // For exception macros. - - // Copy native buffer into shared library object - JVMCIPrimitiveArray buf = new_byteArray(properties_len, this); - if (has_pending_exception()) { - _runtime->fatal_exception(JVMCIENV, "Error in copy_saved_properties"); - } - copy_bytes_from(properties, buf, 0, properties_len); - if (has_pending_exception()) { - _runtime->fatal_exception(JVMCIENV, "Error in copy_saved_properties"); - } - - // Initialize saved properties in shared library - jclass servicesClass = JNIJVMCI::Services::clazz(); - jmethodID initializeSavedProperties = JNIJVMCI::Services::initializeSavedProperties_method(); - bool exception = false; - { - JNIAccessMark jni(this, thread); - jni()->CallStaticVoidMethod(servicesClass, initializeSavedProperties, buf.as_jobject()); - exception = jni()->ExceptionCheck(); - } - if (exception) { - _runtime->fatal_exception(JVMCIENV, "Error calling jdk.vm.ci.services.Services.initializeSavedProperties"); - } -} - void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env, bool jni_enomem_is_fatal) { assert(thread != nullptr, "npe"); _env = nullptr; @@ -1937,7 +1865,7 @@ nmethod* JVMCIEnv::get_nmethod(JVMCIObject obj) { } #define STATIC_INT_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jint, Int, EMPTY_CAST) #define STATIC_BOOLEAN_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jboolean, Boolean, EMPTY_CAST) -#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName) #define CONSTRUCTOR(className, signature) JVMCI_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OBJECT_FIELD, PRIMARRAY_FIELD, OBJECTARRAY_FIELD, STATIC_OBJECT_FIELD, STATIC_OBJECTARRAY_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD, METHOD, CONSTRUCTOR) diff --git a/src/hotspot/share/jvmci/jvmciEnv.hpp b/src/hotspot/share/jvmci/jvmciEnv.hpp index 0f25e8ce5c2..ce5922eaf9c 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.hpp +++ b/src/hotspot/share/jvmci/jvmciEnv.hpp @@ -183,12 +183,6 @@ class JVMCIEnv : public ResourceObj { // The translated exception is pending in hotspot_env upon returning. static void translate_from_jni_exception(JavaThread* THREAD, jthrowable throwable, JVMCIEnv* hotspot_env, JVMCIEnv* jni_env); - // Used by copy_saved_properties() to avoid OutOfMemoryErrors when - // initializing a libjvmci runtime in low HotSpot heap conditions. - // Must hold JVMCI_lock when initializing. - static jbyte* _serialized_saved_properties; - static int _serialized_saved_properties_len; - public: // Opens a JVMCIEnv scope for a Java to VM call (e.g., via CompilerToVM). // An exception occurring within the scope is left pending when the @@ -237,14 +231,6 @@ public: return _runtime; } - // Gets the serialized saved properties from the HotSpot heap. - // The length of the returned array is saved in `len`. - jbyte* get_serialized_saved_properties(int& len, TRAPS); - - // Initializes Services.savedProperties in the shared library from the given - // properties in the format produced by `get_serialized_saved_properties`. - void copy_saved_properties(jbyte* properties, int properties_len, JVMCI_TRAPS); - jboolean has_pending_exception(); void clear_pending_exception(); @@ -509,7 +495,7 @@ public: #define STATIC_BOOLEAN_FIELD(className, name) STATIC_FIELD(className, name, jboolean) #define STATIC_OBJECT_FIELD(className, name, signature) STATIC_OOPISH_FIELD(className, name, JVMCIObject, oop) #define STATIC_OBJECTARRAY_FIELD(className, name, signature) STATIC_OOPISH_FIELD(className, name, JVMCIObjectArray, objArrayOop) -#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName) #define CONSTRUCTOR(className, signature) JVMCI_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OBJECT_FIELD, PRIMARRAY_FIELD, OBJECTARRAY_FIELD, STATIC_OBJECT_FIELD, STATIC_OBJECTARRAY_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD, METHOD, CONSTRUCTOR) diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp index 4346c405094..8bec6aa37db 100644 --- a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp @@ -151,10 +151,10 @@ jmethodID JNIJVMCI::_HotSpotResolvedPrimitiveType_fromMetaspace_method; #define STATIC_INT_FIELD(className, name) FIELD(className, name, "I", true) #define STATIC_BOOLEAN_FIELD(className, name) FIELD(className, name, "Z", true) #ifdef PRODUCT -#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName) #define CONSTRUCTOR(className, signature) #else -#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) \ +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName) \ check_resolve_method(#hsCallType, k, vmSymbols::methodName##_name(), vmSymbols::signatureSymbolName(), CHECK); #define CONSTRUCTOR(className, signature) { \ TempNewSymbol sig = SymbolTable::new_symbol(signature); \ @@ -254,7 +254,7 @@ void HotSpotJVMCI::compute_offsets(TRAPS) { #define STATIC_INT_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jint) #define STATIC_BOOLEAN_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jboolean) -#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName) #define CONSTRUCTOR(className, signature) /** @@ -393,7 +393,7 @@ void JNIJVMCI::initialize_field_id(JNIEnv* env, jfieldID &fieldid, jclass clazz, #define GET_JNI_CONSTRUCTOR(clazz, signature) \ GET_JNI_METHOD(GetMethodID, JNIJVMCI::clazz::_constructor, clazz::_class, "", signature) \ -#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) \ +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName) \ GET_JNI_METHOD(jniGetMethod, \ className::_##methodName##_method, \ className::clazz(), \ @@ -406,6 +406,7 @@ void JNIJVMCI::initialize_field_id(JNIEnv* env, jfieldID &fieldid, jclass clazz, extern "C" { void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass); jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c); + jlong JNICALL JVM_ReadSystemPropertiesInfo(JNIEnv *env, jclass c, jintArray offsets_handle); } // Dumps symbols for public () and (String) methods of @@ -565,10 +566,12 @@ static void register_natives_for_class(JNIEnv* env, jclass clazz, const char* na void JNIJVMCI::register_natives(JNIEnv* env) { if (env != JavaThread::current()->jni_environment()) { JNINativeMethod CompilerToVM_nmethods[] = {{ CC"registerNatives", CC"()V", FN_PTR(JVM_RegisterJVMCINatives) }}; - JNINativeMethod JVMCI_nmethods[] = {{ CC"initializeRuntime", CC"()Ljdk/vm/ci/runtime/JVMCIRuntime;", FN_PTR(JVM_GetJVMCIRuntime) }}; + JNINativeMethod JVMCI_nmethods[] = {{ CC"initializeRuntime", CC"()Ljdk/vm/ci/runtime/JVMCIRuntime;", FN_PTR(JVM_GetJVMCIRuntime) }}; + JNINativeMethod Services_nmethods[] = {{ CC"readSystemPropertiesInfo", CC"([I)J", FN_PTR(JVM_ReadSystemPropertiesInfo) }}; register_natives_for_class(env, nullptr, "jdk/vm/ci/hotspot/CompilerToVM", CompilerToVM_nmethods, 1); register_natives_for_class(env, JVMCI::clazz(), "jdk/vm/ci/runtime/JVMCI", JVMCI_nmethods, 1); + register_natives_for_class(env, Services::clazz(), "jdk/vm/ci/services/Services", Services_nmethods, 1); } } @@ -583,7 +586,7 @@ void JNIJVMCI::register_natives(JNIEnv* env) { #define FIELD2(className, name) \ jfieldID JNIJVMCI::className::_##name##_field_id = 0; \ int HotSpotJVMCI::className::_##name##_offset = 0; -#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName) #define CONSTRUCTOR(className, signature) // Generates the definitions of static fields used by the accessors. For example: @@ -689,7 +692,7 @@ JVMCI_CLASSES_DO(EMPTY2, EMPTY0, FIELD2, FIELD2, FIELD2, FIELD2, FIELD2, FIELD3, #define STATIC_INT_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jint, Int, EMPTY_CAST) #define STATIC_BOOLEAN_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jboolean, Boolean, EMPTY_CAST) -#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) \ +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName) \ jmethodID JNIJVMCI::className::_##methodName##_method; #define CONSTRUCTOR(className, signature) \ diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp index c771f4e8f39..279e73fe880 100644 --- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp @@ -56,9 +56,6 @@ static_boolean_field, \ jvmci_method, \ jvmci_constructor) \ - start_class(Services, jdk_vm_ci_services_Services) \ - jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, Services, initializeSavedProperties, byte_array_void_signature, (JVMCIObject serializedProperties)) \ - end_class \ start_class(Architecture, jdk_vm_ci_code_Architecture) \ object_field(Architecture, wordKind, "Ljdk/vm/ci/meta/PlatformKind;") \ end_class \ @@ -160,7 +157,7 @@ start_class(JavaConstant, jdk_vm_ci_meta_JavaConstant) \ static_object_field(JavaConstant, ILLEGAL, "Ljdk/vm/ci/meta/PrimitiveConstant;") \ static_object_field(JavaConstant, NULL_POINTER, "Ljdk/vm/ci/meta/JavaConstant;") \ - jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JavaConstant, forPrimitive, forPrimitive_signature, (JVMCIObject kind, jlong value, JVMCI_TRAPS)) \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JavaConstant, forPrimitive, forPrimitive_signature) \ end_class \ start_class(ResolvedJavaMethod, jdk_vm_ci_meta_ResolvedJavaMethod) \ end_class \ @@ -200,34 +197,36 @@ end_class \ start_class(HotSpotJVMCIRuntime, jdk_vm_ci_hotspot_HotSpotJVMCIRuntime) \ objectarray_field(HotSpotJVMCIRuntime, excludeFromJVMCICompilation, "[Ljava/lang/Module;") \ - jvmci_method(CallNonvirtualObjectMethod, GetMethodID, call_special, JVMCIObject, HotSpotJVMCIRuntime, compileMethod, compileMethod_signature, (JVMCIObject runtime, JVMCIObject method, int entry_bci, jlong env, int id)) \ - jvmci_method(CallNonvirtualObjectMethod, GetMethodID, call_special, JVMCIObject, HotSpotJVMCIRuntime, isGCSupported, int_bool_signature, (JVMCIObject runtime, int gcIdentifier)) \ - jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, bootstrapFinished, void_method_signature, (JVMCIObject runtime, JVMCI_TRAPS)) \ - jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, shutdown, void_method_signature, (JVMCIObject runtime)) \ - jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, runtime, runtime_signature, (JVMCI_TRAPS)) \ - jvmci_method(CallObjectMethod, GetMethodID, call_virtual, JVMCIObject, HotSpotJVMCIRuntime, getCompiler, getCompiler_signature, (JVMCIObject runtime, JVMCI_TRAPS)) \ - jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, exceptionToString, exceptionToString_signature, (JVMCIObject object, bool toString, bool stackTrace, JVMCI_TRAPS)) \ - jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, HotSpotJVMCIRuntime, postTranslation, object_void_signature, (JVMCIObject object, JVMCI_TRAPS)) \ + jvmci_method(CallNonvirtualObjectMethod, GetMethodID, call_special, JVMCIObject, HotSpotJVMCIRuntime, compileMethod, compileMethod_signature) \ + jvmci_method(CallNonvirtualObjectMethod, GetMethodID, call_special, JVMCIObject, HotSpotJVMCIRuntime, isGCSupported, int_bool_signature) \ + jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, bootstrapFinished, void_method_signature) \ + jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, shutdown, void_method_signature) \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, runtime, runtime_signature) \ + jvmci_method(CallObjectMethod, GetMethodID, call_virtual, JVMCIObject, HotSpotJVMCIRuntime, getCompiler, getCompiler_signature) \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, exceptionToString, exceptionToString_signature) \ + jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, HotSpotJVMCIRuntime, postTranslation, object_void_signature) \ end_class \ start_class(JVMCIError, jdk_vm_ci_common_JVMCIError) \ jvmci_constructor(JVMCIError, "(Ljava/lang/String;)V") \ end_class \ start_class(InspectedFrameVisitor, jdk_vm_ci_code_stack_InspectedFrameVisitor) \ end_class \ + start_class(Services, jdk_vm_ci_services_Services) \ + end_class \ start_class(JVMCI, jdk_vm_ci_runtime_JVMCI) \ - jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JVMCI, getRuntime, getRuntime_signature, (JVMCI_TRAPS)) \ - jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JVMCI, initializeRuntime, initializeRuntime_signature, (JVMCI_TRAPS)) \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JVMCI, getRuntime, getRuntime_signature) \ + jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, JVMCI, initializeRuntime, initializeRuntime_signature) \ end_class \ start_class(Object, java_lang_Object) \ end_class \ start_class(String, java_lang_String) \ end_class \ start_class(Class, java_lang_Class) \ - jvmci_method(CallObjectMethod, GetMethodID, call_virtual, JVMCIObject, Class, getName, void_string_signature, (JVMCI_TRAPS)) \ + jvmci_method(CallObjectMethod, GetMethodID, call_virtual, JVMCIObject, Class, getName, void_string_signature) \ end_class \ start_class(VMSupport, jdk_internal_vm_VMSupport) \ - jvmci_method(CallStaticIntMethod, GetStaticMethodID, call_static, int, VMSupport, encodeThrowable, encodeThrowable_signature, (JVMCIObject throwable, jlong buffer, int buffer_size)) \ - jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, VMSupport, decodeAndThrowThrowable, decodeAndThrowThrowable_signature, (jlong buffer)) \ + jvmci_method(CallStaticIntMethod, GetStaticMethodID, call_static, int, VMSupport, encodeThrowable, encodeThrowable_signature) \ + jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, VMSupport, decodeAndThrowThrowable, decodeAndThrowThrowable_signature) \ end_class \ start_class(ArrayIndexOutOfBoundsException, java_lang_ArrayIndexOutOfBoundsException) \ jvmci_constructor(ArrayIndexOutOfBoundsException, "(Ljava/lang/String;)V") \ @@ -342,7 +341,7 @@ class JVMCIEnv; static hstype name(JVMCIEnv* env); \ static void set_ ## name(JVMCIEnv* env, hstype hstype); -#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, simpleClassName, methodName, signatureSymbolName, args) +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, simpleClassName, methodName, signatureSymbolName) #define CONSTRUCTOR(className, signature) /** @@ -435,7 +434,7 @@ public: #define STATIC_OOPISH_FIELD(simpleClassName, name, type, hstype) \ STATIC_FIELD(simpleClassName, name, type) -#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) \ +#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName) \ public: \ static jmethodID methodName##_method() { return _##methodName##_method; } \ private: \ diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index 6a1bc38b4d5..12616d26b46 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -754,6 +754,21 @@ JVM_ENTRY_NO_ENV(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c)) return JVMCIENV->get_jobject(runtime); JVM_END +// private static long Services.readSystemPropertiesInfo(int[] offsets) +JVM_ENTRY_NO_ENV(jlong, JVM_ReadSystemPropertiesInfo(JNIEnv *env, jclass c, jintArray offsets_handle)) + JNI_JVMCIENV(thread, env); + if (!EnableJVMCI) { + JVMCI_THROW_MSG_0(InternalError, "JVMCI is not enabled"); + } + JVMCIPrimitiveArray offsets = JVMCIENV->wrap(offsets_handle); + JVMCIENV->put_int_at(offsets, 0, SystemProperty::next_offset_in_bytes()); + JVMCIENV->put_int_at(offsets, 1, SystemProperty::key_offset_in_bytes()); + JVMCIENV->put_int_at(offsets, 2, PathString::value_offset_in_bytes()); + + return (jlong) Arguments::system_properties(); +JVM_END + + void JVMCIRuntime::call_getCompiler(TRAPS) { THREAD_JVMCIENV(JavaThread::current()); JVMCIObject jvmciRuntime = JVMCIRuntime::get_HotSpotJVMCIRuntime(JVMCI_CHECK); @@ -1399,9 +1414,6 @@ void JVMCIRuntime::initialize(JVMCI_TRAPS) { JavaThread* THREAD = JavaThread::current(); - int properties_len = 0; - jbyte* properties = nullptr; - MutexLocker locker(_lock); // Check again under _lock if (_init_state == fully_initialized) { @@ -1464,16 +1476,6 @@ void JVMCIRuntime::initialize(JVMCI_TRAPS) { create_jvmci_primitive_type(T_VOID, JVMCI_CHECK_EXIT_((void)0)); DEBUG_ONLY(CodeInstaller::verify_bci_constants(JVMCIENV);) - - if (!JVMCIENV->is_hotspot()) { - Handle properties_exception; - properties = JVMCIENV->get_serialized_saved_properties(properties_len, THREAD); - if (JVMCIEnv::transfer_pending_exception_to_jni(THREAD, nullptr, JVMCIENV)) { - JVMCI_event_1("error initializing system properties for JVMCI runtime %d", _id); - return; - } - JVMCIENV->copy_saved_properties(properties, properties_len, JVMCI_CHECK); - } } _init_state = fully_initialized; diff --git a/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp b/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp index eb1eaee2ac8..13d81d9f286 100644 --- a/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp +++ b/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp @@ -102,7 +102,6 @@ template(forPrimitive_name, "forPrimitive") \ template(forPrimitive_signature, "(CJ)Ljdk/vm/ci/meta/PrimitiveConstant;") \ template(method_string_bool_long_signature, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;Ljava/lang/String;ZJ)V") \ - template(initializeSavedProperties_name, "initializeSavedProperties") \ #endif diff --git a/src/hotspot/share/prims/nativeLookup.cpp b/src/hotspot/share/prims/nativeLookup.cpp index 0f73af197b6..e838c831ff1 100644 --- a/src/hotspot/share/prims/nativeLookup.cpp +++ b/src/hotspot/share/prims/nativeLookup.cpp @@ -210,6 +210,7 @@ extern "C" { void JNICALL JVM_RegisterVectorSupportMethods(JNIEnv *env, jclass vsclass); #if INCLUDE_JVMCI jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c); + jlong JNICALL JVM_ReadSystemPropertiesInfo(JNIEnv *env, jclass c, jintArray offsets); void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass); #endif } @@ -229,6 +230,7 @@ static JNINativeMethod lookup_special_native_methods[] = { { CC"Java_jdk_internal_vm_vector_VectorSupport_registerNatives", nullptr, FN_PTR(JVM_RegisterVectorSupportMethods)}, #if INCLUDE_JVMCI { CC"Java_jdk_vm_ci_runtime_JVMCI_initializeRuntime", nullptr, FN_PTR(JVM_GetJVMCIRuntime) }, + { CC"Java_jdk_vm_ci_services_Services_readSystemPropertiesInfo", nullptr, FN_PTR(JVM_ReadSystemPropertiesInfo) }, { CC"Java_jdk_vm_ci_hotspot_CompilerToVM_registerNatives", nullptr, FN_PTR(JVM_RegisterJVMCINatives) }, #endif #if INCLUDE_JFR diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index 977422a2961..61f5ef25560 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -75,6 +75,9 @@ class PathString : public CHeapObj { PathString(const char* value); ~PathString(); + + // for JVM_ReadSystemPropertiesInfo + static int value_offset_in_bytes() { return (int)offset_of(PathString, _value); } }; // ModulePatchPath records the module/path pair as specified to --patch-module. @@ -136,6 +139,10 @@ class SystemProperty : public PathString { // Constructor SystemProperty(const char* key, const char* value, bool writeable, bool internal = false); + + // for JVM_ReadSystemPropertiesInfo + static int key_offset_in_bytes() { return (int)offset_of(SystemProperty, _key); } + static int next_offset_in_bytes() { return (int)offset_of(SystemProperty, _next); } }; // Helper class for controlling the lifetime of JavaVMInitArgs objects. diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java index 659645a5006..b84d55454e7 100644 --- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,19 +101,6 @@ public class VMSupport { return serializePropertiesToByteArray(onlyStrings(getAgentProperties())); } - /** - * Serializes {@link VM#getSavedProperties()} to a byte array. - * - * Used by JVMCI to copy properties into libjvmci. - */ - public static byte[] serializeSavedPropertiesToByteArray() throws IOException { - Properties props = new Properties(); - for (var e : VM.getSavedProperties().entrySet()) { - props.put(e.getKey(), e.getValue()); - } - return serializePropertiesToByteArray(props); - } - /* * Return the temporary directory that the VM uses for the attach * and perf data files. diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index 06b141dcf22..ac0ed7bee41 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -278,6 +278,7 @@ module java.base { java.security.jgss, java.smartcardio, jdk.charsets, + jdk.internal.vm.ci, jdk.jlink, jdk.jpackage, jdk.net; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/TargetDescription.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/TargetDescription.java index c728fe578dd..e1e746c6fe3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/TargetDescription.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/TargetDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ import static jdk.vm.ci.meta.MetaUtil.identityHashCodeString; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.services.Services; +import jdk.internal.util.OperatingSystem; /** * Represents the target machine for a compiler, including the CPU architecture, the size of @@ -33,8 +34,8 @@ import jdk.vm.ci.services.Services; */ public class TargetDescription { - public final boolean linuxOs = Services.getSavedProperty("os.name", "").startsWith("Linux"); - public final boolean macOs = Services.getSavedProperty("os.name", "").startsWith("Mac"); + public final boolean linuxOs = OperatingSystem.isLinux(); + public final boolean macOs = OperatingSystem.isMacOS(); public final Architecture arch; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index 423b52e1832..fe736afbba8 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 273c99d294d..4327df1ba33 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -28,6 +28,7 @@ import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.services.Services; import jdk.internal.misc.Unsafe; +import jdk.internal.util.Architecture; /** * Used to access native configuration details. @@ -43,8 +44,6 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { return runtime().getConfig(); } - private final String osArch = getHostArchitectureName(); - HotSpotVMConfig(HotSpotVMConfigStore store) { super(store); @@ -57,13 +56,10 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { * {@linkplain HotSpotJVMCIBackendFactory backend}. */ String getHostArchitectureName() { - String arch = Services.getSavedProperty("os.arch"); + Architecture arch = Architecture.current(); switch (arch) { - case "x86_64": - return "amd64"; - - default: - return arch; + case X64: return "amd64"; + default: return arch.name().toLowerCase(); } } @@ -134,7 +130,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { final int jvmMiscFlagsDeclaresDefaultMethods = getConstant("InstanceKlassFlags::_misc_declares_nonstatic_concrete_methods", Integer.class); // This is only valid on AMD64. - final int runtimeCallStackSize = getConstant("frame::arg_reg_save_area_bytes", Integer.class, osArch.equals("amd64") ? null : 0); + final int runtimeCallStackSize = getConstant("frame::arg_reg_save_area_bytes", Integer.class, Architecture.isX64() ? null : 0); private final int markWordNoHashInPlace = getConstant("markWord::no_hash_in_place", Integer.class); private final int markWordNoLockInPlace = getConstant("markWord::no_lock_in_place", Integer.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java index a59db1f542d..b0e2f425dae 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package jdk.vm.ci.hotspot.amd64; import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; import jdk.vm.ci.services.Services; +import jdk.internal.util.OperatingSystem; /** * Used to access AMD64 specific native configuration details. @@ -35,7 +36,7 @@ class AMD64HotSpotVMConfig extends HotSpotVMConfigAccess { super(config); } - final boolean windowsOs = Services.getSavedProperty("os.name", "").startsWith("Windows"); + final boolean windowsOs = OperatingSystem.isWindows(); final boolean useCountLeadingZerosInstruction = getFlag("UseCountLeadingZerosInstruction", Boolean.class); final boolean useCountTrailingZerosInstruction = getFlag("UseCountTrailingZerosInstruction", Boolean.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/riscv64/RISCV64HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/riscv64/RISCV64HotSpotVMConfig.java index ce08b539111..0db2fecbce7 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/riscv64/RISCV64HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/riscv64/RISCV64HotSpotVMConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package jdk.vm.ci.hotspot.riscv64; import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; import jdk.vm.ci.services.Services; +import jdk.internal.util.OperatingSystem; /** * Used to access native configuration details. @@ -37,7 +38,7 @@ class RISCV64HotSpotVMConfig extends HotSpotVMConfigAccess { super(config); } - final boolean linuxOs = Services.getSavedProperty("os.name", "").startsWith("Linux"); + final boolean linuxOs = OperatingSystem.isLinux(); final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java index 3881662fd08..d4c657f9cd3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,16 +22,12 @@ */ package jdk.vm.ci.services; -import java.io.ByteArrayInputStream; -import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.Formatter; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Properties; import java.util.ServiceLoader; import java.util.Set; import java.util.function.Consumer; @@ -39,6 +35,9 @@ import java.util.function.Supplier; import jdk.internal.misc.TerminatingThreadLocal; import jdk.internal.misc.VM; +import jdk.internal.misc.Unsafe; +import jdk.internal.util.Architecture; +import jdk.internal.util.OperatingSystem; /** * Provides utilities needed by JVMCI clients. @@ -71,7 +70,7 @@ public final class Services { } /** - * In a native image, this field is initialized by {@link #initializeSavedProperties(byte[])}. + * Lazily initialized in {@link #getSavedProperties}. */ private static volatile Map savedProperties; @@ -87,25 +86,17 @@ public final class Services { } /** - * Gets an unmodifiable copy of the system properties saved when {@link System} is initialized. + * Gets an unmodifiable copy of the system properties parsed by {@code arguments.cpp} + * plus {@code java.specification.version}, {@code os.name} and {@code os.arch}. + * The latter two are forced to be the real OS and architecture. That is, values + * for these two properties set on the command line are ignored. */ public static Map getSavedProperties() { checkJVMCIEnabled(); - if (IS_IN_NATIVE_IMAGE) { - if (savedProperties == null) { - throw new InternalError("Saved properties not initialized"); - } - } else { - if (savedProperties == null) { - synchronized (Services.class) { - if (savedProperties == null) { - @SuppressWarnings("removal") - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new JVMCIPermission()); - } - savedProperties = VM.getSavedProperties(); - } + if (savedProperties == null) { + synchronized (Services.class) { + if (savedProperties == null) { + savedProperties = initProperties(); } } } @@ -261,22 +252,128 @@ public final class Services { }; } - /** - * Initializes {@link #savedProperties} from the byte array returned by - * {@code jdk.internal.vm.VMSupport.serializeSavedPropertiesToByteArray()}. - */ - @VMEntryPoint - private static void initializeSavedProperties(byte[] serializedProperties) throws IOException { - if (!IS_IN_NATIVE_IMAGE) { - throw new InternalError("Can only initialize saved properties in JVMCI shared library runtime"); + static String toJavaString(Unsafe unsafe, long cstring) { + if (cstring == 0) { + return null; } - Properties props = new Properties(); - props.load(new ByteArrayInputStream(serializedProperties)); - Map map = new HashMap<>(props.size()); - for (var e : props.entrySet()) { - map.put((String) e.getKey(), (String) e.getValue()); + int len = 0; + for (long p = cstring; unsafe.getByte(p) != 0; p++) { + len++; + } + byte[] buf = new byte[len]; + for (int i = 0; i < len; i++) { + buf[i] = unsafe.getByte(cstring + i); + } + return new String(buf, java.nio.charset.StandardCharsets.UTF_8); + } + + /** + * Gets the value of {@code Arguments::systemProperties()} and puts the offsets + * of {@code SystemProperty} fields into {@code offsets}. The values returned in + * {@code offsets} are: + * + *
+     *     [ next,  // SystemProperty::next_offset_in_bytes()
+     *       key,   // SystemProperty::key_offset_in_bytes()
+     *       value  // PathString::value_offset_in_bytes()
+     *     ]
+     * 
+ * + * Ideally this would be done with vmstructs but that code is in {@code jdk.vm.ci.hotspot}. + */ + private static native long readSystemPropertiesInfo(int[] offsets); + + /** + * Parses the native {@code Arguments::systemProperties()} data structure using Unsafe to + * create a properties map. This parsing is safe as argument parsing in completed in + * early VM start before this code can be executed, making {@code Arguments::systemProperties()} + * effectively read-only by now. + */ + private static Map initProperties() { + int[] offsets = new int[3]; + long systemProperties = readSystemPropertiesInfo(offsets); + int nextOffset = offsets[0]; + int keyOffset = offsets[1]; + int valueOffset = offsets[2]; + + int count = 0; + Unsafe unsafe = Unsafe.getUnsafe(); + for (long prop = systemProperties; prop != 0; prop = unsafe.getLong(prop + nextOffset)) { + if (unsafe.getLong(prop + valueOffset) != 0) { + count++; + } else { + // Some internal properties (e.g. jdk.boot.class.path.append) can have a null + // value and should just be ignored. Note that null is different than the empty string. + } + } + Map props = new HashMap<>(count + 1); + int i = 0; + for (long prop = systemProperties; prop != 0; prop = unsafe.getLong(prop + nextOffset)) { + String key = toJavaString(unsafe, unsafe.getLong(prop + keyOffset)); + long valueAddress = unsafe.getLong(prop + valueOffset); + if (valueAddress != 0) { + props.put(key, new SystemProperties.Value(unsafe, valueAddress)); + i++; + } + } + if (i != count) { + throw new InternalError(i + " != " + count); + } + if (!props.containsKey("java.specification.version")) { + SystemProperties.Value v = Objects.requireNonNull(props.get("java.vm.specification.version")); + props.put("java.specification.version", v); } - savedProperties = Collections.unmodifiableMap(map); + SystemProperties res = new SystemProperties(unsafe, sanitizeOSArch(props)); + if ("true".equals(res.get("debug.jvmci.PrintSavedProperties"))) { + System.out.println("[Saved system properties]"); + for (Map.Entry e : res.entrySet()) { + System.out.printf("%s=%s%n", e.getKey(), e.getValue()); + } + } + return res; + } + + // Force os.name and os.arch to reflect the actual OS and architecture. + // JVMCI configures itself based on these values and needs to be isolated + // from apps that set them on the command line. + private static Map sanitizeOSArch(Map props) { + props.put("os.arch", new SystemProperties.Value(realArch())); + props.put("os.name", new SystemProperties.Value(realOS())); + return props; + } + + private static String realOS() { + OperatingSystem os = OperatingSystem.current(); + switch (os) { + case LINUX: return "Linux"; + case MACOS: return "Mac OS X"; + case AIX: return "AIX"; + case WINDOWS: { + String osName = System.getProperty("os.name"); + if (osName.startsWith("Windows")) { + // Use original value which is often more "complete" + // E.g. "Windows Server 2012" + return osName; + } + return "Windows"; + } + default: throw new InternalError("missing case for " + os); + } + } + + private static String realArch() { + Architecture arch = Architecture.current(); + switch (arch) { + case X64: return "x86_64"; + case X86: return "x86"; + case AARCH64: return "aarch64"; + case RISCV64: return "riscv64"; + case ARM: return "arm"; + case S390: return "s390"; + case PPC64: return "ppc64"; + case OTHER: return "other"; + default: throw new InternalError("missing case for " + arch); + } } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/SystemProperties.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/SystemProperties.java new file mode 100644 index 00000000000..2b4f3141e6b --- /dev/null +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/SystemProperties.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.services; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import jdk.internal.misc.Unsafe; + +/** + * Unmodifiable map for storing system properties read from native memory whose values have their + * string representation constructed on first access. + */ +final class SystemProperties implements Map { + + private final Unsafe unsafe; + private final Map entries; + private Set> entrySet; + private Collection values; + + SystemProperties(Unsafe unsafe, Map entries) { + this.unsafe = unsafe; + this.entries = entries; + } + + @Override + public int size() { + return entries.size(); + } + + @Override + public boolean isEmpty() { + return entries.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return entries.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + for (Value v : entries.values()) { + if (v.getString(unsafe).equals(value)) { + return true; + } + } + return false; + } + + @Override + public String get(Object key) { + Value v = entries.get(key); + if (v != null) { + return v.getString(unsafe); + } + return null; + } + + @Override + public String put(String key, String value) { + throw new UnsupportedOperationException(); + } + + @Override + public String remove(Object key) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(Map m) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public Set keySet() { + return entries.keySet(); + } + + @Override + public Collection values() { + if (values == null) { + values = entries.values().stream().map(v -> v.getString(unsafe)).collect(Collectors.toUnmodifiableList()); + } + return values; + } + + static class Property implements Map.Entry { + private final Unsafe unsafe; + private final String key; + private final Value value; + + Property(Unsafe unsafe, Map.Entry e) { + this.unsafe = unsafe; + this.key = e.getKey(); + this.value = e.getValue(); + } + + @Override + public String getKey() { + return key; + } + + @Override + public String getValue() { + return value.getString(unsafe); + } + + @Override + public String setValue(String value) { + throw new UnsupportedOperationException(); + } + }; + + @Override + public Set> entrySet() { + if (entrySet == null) { + entrySet = entries.entrySet().stream().map(e -> new Property(unsafe, e)).collect(Collectors.toUnmodifiableSet()); + } + return entrySet; + } + + /** + * Represents a value in {@link SystemProperties}. + */ + static class Value { + private final long cstring; + private volatile String string; + + /** + * Creates a value whose string representation will be lazily constructed from {@code cstring}. + */ + Value(Unsafe unsafe, long cstring) { + this.cstring = cstring; + } + + /** + * Creates a value whose string representation is known at construction time. + */ + Value(String string) { + this.cstring = 0; + this.string = string; + } + + String getString(Unsafe unsafe) { + if (string == null) { + // Racy but it doesn't matter. + string = Services.toJavaString(unsafe, cstring); + } + return string; + } + } +} diff --git a/test/hotspot/jtreg/compiler/jvmci/TestJVMCISavedProperties.java b/test/hotspot/jtreg/compiler/jvmci/TestJVMCISavedProperties.java new file mode 100644 index 00000000000..423a575b6ea --- /dev/null +++ b/test/hotspot/jtreg/compiler/jvmci/TestJVMCISavedProperties.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test TestJVMCISavedProperties + * @bug 8309390 + * @summary Ensures Services.getSavedProperties() includes properties set on + * the command line as well some specified properties but not + * properties set programmatically. + * @requires vm.flagless + * @requires vm.jvmci + * @library /test/lib + * @run driver TestJVMCISavedProperties + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestJVMCISavedProperties { + + public static void main(String[] args) throws Exception { + if (args.length != 0) { + System.setProperty("app3.NotPresentInSavedProperties", "42"); + System.out.println("DONE IN MAIN"); + return; + } + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockExperimentalVMOptions", + "-XX:+EagerJVMCI", + "-XX:+UseJVMCICompiler", + "-Djvmci.Compiler=null", + "-Ddebug.jvmci.PrintSavedProperties=true", + "-Dapp1.propX=true", + "-Dapp2.propY=SomeStringValue", + "TestJVMCISavedProperties", "true"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.stdoutShouldContain("debug.jvmci.PrintSavedProperties=true"); + output.stdoutShouldContain("jvmci.Compiler=null"); + output.stdoutShouldContain("app1.propX=true"); + output.stdoutShouldContain("app2.propY=SomeStringValue"); + output.stdoutShouldContain("java.specification.version=" + Runtime.version().feature()); + output.stdoutShouldContain("os.name="); + output.stdoutShouldContain("os.arch="); + output.stdoutShouldNotContain("NotPresentInSavedProperties"); + } +}