--- make/data/hotspot-symbols/symbols-unix | 1 + .../classfile/systemDictionaryShared.cpp | 4 ++- src/hotspot/share/include/jvm.h | 6 ++++ .../jbooster/client/clientDataManager.cpp | 7 ++++ .../share/jbooster/jBoosterManager.cpp | 27 ++++++++++++++ .../share/jbooster/jBoosterManager.hpp | 4 +++ .../share/jbooster/jBoosterSymbols.hpp | 1 + .../share/jbooster/jbooster_globals.hpp | 26 +++++++------- src/hotspot/share/jbooster/lazyAot.cpp | 14 +++++--- .../jbooster/server/serverDataManager.cpp | 17 ++++++++- .../jbooster/server/serverMessageHandler.cpp | 10 +++--- src/hotspot/share/oops/methodData.cpp | 9 ++--- src/hotspot/share/oops/methodData.hpp | 2 +- src/hotspot/share/prims/jvm.cpp | 21 +++++++++++ src/hotspot/share/runtime/arguments.cpp | 1 + .../src/jdk/tools/jaotc/Main.java | 14 ++++++-- .../ci/hotspot/HotSpotResolvedObjectType.java | 2 ++ .../HotSpotResolvedObjectTypeImpl.java | 36 +++++++++++++++++++ .../jbooster/JBoosterCompilationContext.java | 12 +++++++ .../management/HotSpotGraalManagement.java | 21 +++++++++++ .../core/test/StableArrayReadFoldingTest.java | 6 ++-- .../compiler/hotspot/HotSpotGraalRuntime.java | 11 ++++++ .../graalvm/compiler/hotspot/stubs/Stub.java | 8 +++++ .../common/inlining/walker/InliningData.java | 8 +++++ .../JBoosterCompilationContextImpl.java | 20 +++++++++++ .../share/native/libjbooster/JBooster.c | 6 ++++ test/hotspot/jtreg/ProblemList-graal.txt | 4 +++ test/jdk/tools/jbooster/JBoosterCmdTest.java | 12 +++---- test/jdk/tools/launcher/HelpFlagsTest.java | 2 +- 29 files changed, 272 insertions(+), 40 deletions(-) diff --git a/make/data/hotspot-symbols/symbols-unix b/make/data/hotspot-symbols/symbols-unix index ac8434902..33ce73012 100644 --- a/make/data/hotspot-symbols/symbols-unix +++ b/make/data/hotspot-symbols/symbols-unix @@ -212,5 +212,6 @@ JVM_JBoosterInitVM JVM_JBoosterHandleConnection JVM_JBoosterPrintStoredClientData JVM_JBoosterGetMetaspaceMethodData +JVM_JBoosterFreeUnusedCodeBlobs JVM_JBoosterStartupNativeCallback JVM_DefineTrustedSharedClass diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index ee4bd6f24..163b581fb 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -445,6 +445,7 @@ public: } InstanceKlass* caller_ik() const { return _caller_ik; } + Method* member_method() const { return _member_method; } }; @@ -1798,7 +1799,8 @@ public: bool do_entry(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) { assert_lock_strong(DumpTimeTable_lock); - if (key.caller_ik()->is_loader_alive()) { + // ignore obsolete lambda + if (key.caller_ik()->is_loader_alive() && !key.member_method()->is_obsolete()) { info.metaspace_pointers_do(_it); key.metaspace_pointers_do(_it); } diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index 4cdc9cfb6..488ad25ce 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -1125,6 +1125,12 @@ JVM_JBoosterPrintStoredClientData(JNIEnv *env, jboolean print_all); JNIEXPORT long JNICALL JVM_JBoosterGetMetaspaceMethodData(JNIEnv *env, jint session_id, jlong metaspace_method); +/** + * Free unused codeBlobs. + */ +JNIEXPORT void JNICALL +JVM_JBoosterFreeUnusedCodeBlobs(JNIEnv *env, jobject blobs); + /** * Callback of startup signal. */ diff --git a/src/hotspot/share/jbooster/client/clientDataManager.cpp b/src/hotspot/share/jbooster/client/clientDataManager.cpp index 93fa45d7c..0504dc656 100644 --- a/src/hotspot/share/jbooster/client/clientDataManager.cpp +++ b/src/hotspot/share/jbooster/client/clientDataManager.cpp @@ -21,6 +21,8 @@ * questions. */ +#include "classfile/systemDictionary.hpp" +#include "classfile/vmSymbols.hpp" #include "jbooster/client/clientDaemonThread.hpp" #include "jbooster/client/clientDataManager.hpp" #include "jbooster/client/clientStartupSignal.hpp" @@ -325,6 +327,11 @@ void ClientDataManager::init_phase2(TRAPS) { ClientStartupSignal::init_phase2(); } ClientDaemonThread::start_thread(CHECK); + + if (_singleton->is_clr_allowed()) { + Klass* klass = SystemDictionary::resolve_or_fail(vmSymbols::java_net_ClassLoaderResourceCache(), true, CHECK); + InstanceKlass::cast(klass)->initialize(CHECK); + } } jint ClientDataManager::escape() { diff --git a/src/hotspot/share/jbooster/jBoosterManager.cpp b/src/hotspot/share/jbooster/jBoosterManager.cpp index 9a8959589..64af5e894 100644 --- a/src/hotspot/share/jbooster/jBoosterManager.cpp +++ b/src/hotspot/share/jbooster/jBoosterManager.cpp @@ -152,3 +152,30 @@ void JBoosterManager::init_phase2(TRAPS) { ServerDataManager::init_phase2(CHECK); } } + +void JBoosterManager::check_argument(JVMFlagsEnum flag) { + if (JVMFlag::is_cmdline(flag)) { + vm_exit_during_initialization(err_msg("Do not set VM option " + "%s without UseJBooster enabled.", JVMFlag::flag_from_enum(flag)->name())); + } +} + +void JBoosterManager::check_arguments() { + if (UseJBooster) return; + + check_argument(FLAG_MEMBER_ENUM(JBoosterAddress)); + check_argument(FLAG_MEMBER_ENUM(JBoosterPort)); + check_argument(FLAG_MEMBER_ENUM(JBoosterTimeout)); + check_argument(FLAG_MEMBER_ENUM(JBoosterExitIfUnsupported)); + check_argument(FLAG_MEMBER_ENUM(JBoosterCrashIfNoServer)); + check_argument(FLAG_MEMBER_ENUM(JBoosterProgramName)); + check_argument(FLAG_MEMBER_ENUM(JBoosterCachePath)); + check_argument(FLAG_MEMBER_ENUM(JBoosterLocalMode)); + check_argument(FLAG_MEMBER_ENUM(JBoosterStartupSignal)); + check_argument(FLAG_MEMBER_ENUM(JBoosterStartupMaxTime)); + check_argument(FLAG_MEMBER_ENUM(BoostStopAtLevel)); + check_argument(FLAG_MEMBER_ENUM(UseBoostPackages)); + check_argument(FLAG_MEMBER_ENUM(JBoosterClientStrictMatch)); + check_argument(FLAG_MEMBER_ENUM(PrintAllClassInfo)); + check_argument(FLAG_MEMBER_ENUM(CheckClassFileTimeStamp)); +} \ No newline at end of file diff --git a/src/hotspot/share/jbooster/jBoosterManager.hpp b/src/hotspot/share/jbooster/jBoosterManager.hpp index eb42f869a..a1bc4d445 100644 --- a/src/hotspot/share/jbooster/jBoosterManager.hpp +++ b/src/hotspot/share/jbooster/jBoosterManager.hpp @@ -27,6 +27,7 @@ #include "jbooster/jbooster_globals.hpp" #include "memory/allocation.hpp" #include "runtime/globals.hpp" +#include "runtime/globals_extension.hpp" #include "utilities/exceptions.hpp" /** @@ -46,6 +47,9 @@ public: static jint init_phase1(); static void init_phase2(TRAPS); + static void check_arguments(); + static void check_argument(JVMFlagsEnum flag); + static void client_only() NOT_DEBUG_RETURN; static void server_only() NOT_DEBUG_RETURN; diff --git a/src/hotspot/share/jbooster/jBoosterSymbols.hpp b/src/hotspot/share/jbooster/jBoosterSymbols.hpp index 720e17d58..e45bf85aa 100644 --- a/src/hotspot/share/jbooster/jBoosterSymbols.hpp +++ b/src/hotspot/share/jbooster/jBoosterSymbols.hpp @@ -29,5 +29,6 @@ template(codesource_signature, "Ljava/security/CodeSource;") \ template(getProtectionDomainByURLString_name, "getProtectionDomainByURLString") \ template(getProtectionDomainByURLString_signature, "(Ljava/lang/String;)Ljava/security/ProtectionDomain;") \ + template(java_net_ClassLoaderResourceCache, "java/net/ClassLoaderResourceCache") \ #endif // SHARE_JBOOSTER_JBOOSTERSYMBOLS_HPP diff --git a/src/hotspot/share/jbooster/jbooster_globals.hpp b/src/hotspot/share/jbooster/jbooster_globals.hpp index e9ba39e2d..3eb74abf8 100644 --- a/src/hotspot/share/jbooster/jbooster_globals.hpp +++ b/src/hotspot/share/jbooster/jbooster_globals.hpp @@ -41,43 +41,43 @@ "Play the role of the JBooster server. " \ "This flag is automatically set in VM.") \ \ - product(ccstr, JBoosterAddress, "127.0.0.1", \ + product(ccstr, JBoosterAddress, "127.0.0.1", EXPERIMENTAL, \ "Address of the JBooster server. Default: '127.0.0.1'.") \ \ - product(ccstr, JBoosterPort, NULL, \ + product(ccstr, JBoosterPort, NULL, EXPERIMENTAL, \ "Port of the JBooster server.") \ \ - product(uint, JBoosterTimeout, 4'000, \ + product(uint, JBoosterTimeout, 4'000, EXPERIMENTAL, \ "Timeout of the JBooster connection. Default: 4,000 ms.") \ \ - product(bool, JBoosterExitIfUnsupported, true, \ + product(bool, JBoosterExitIfUnsupported, true, EXPERIMENTAL, \ "Exit the VM if the client uses features " \ "that are not supported by the server.") \ \ product(bool, JBoosterCrashIfNoServer, false, DIAGNOSTIC, \ "Exit the VM if the server is not available.") \ \ - product(ccstr, JBoosterProgramName, NULL, \ + product(ccstr, JBoosterProgramName, NULL, EXPERIMENTAL, \ "Unique name of current app.") \ \ - product(ccstr, JBoosterCachePath, NULL, \ + product(ccstr, JBoosterCachePath, NULL, EXPERIMENTAL, \ "The directory path for JBooster caches " \ "(default: $HOME/.jbooster/client).") \ \ - product(bool, JBoosterLocalMode, false, \ + product(bool, JBoosterLocalMode, false, EXPERIMENTAL, \ "No connection to the server and uses only the local cache.") \ \ - product(ccstr, JBoosterStartupSignal, NULL, \ + product(ccstr, JBoosterStartupSignal, NULL, EXPERIMENTAL, \ "The first invocation of the signal method means the end of " \ "the client start-up phase. " \ "The relevant logic is executed at exit if it's not set.") \ \ - product(int, JBoosterStartupMaxTime, 600, \ + product(int, JBoosterStartupMaxTime, 600, EXPERIMENTAL, \ "Max seconds required for the start-up phase (0 means off). " \ "A plan B when JBoosterStartupSignal fails.") \ range(0, max_jint) \ \ - product(int, BoostStopAtLevel, 3, \ + product(int, BoostStopAtLevel, 3, EXPERIMENTAL, \ "0 for no optimization; 1 with class loader resource cache; " \ "2 with aggressive CDS; 3 with lazy AOT; 4 with PGO.") \ range(0, 4) \ @@ -104,13 +104,13 @@ "Cache and share the name-url pairs in " \ "java.net.URLClassLoader#findResource.") \ \ - product(ccstr, DumpClassLoaderResourceCacheFile, NULL, \ + product(ccstr, DumpClassLoaderResourceCacheFile, NULL, EXPERIMENTAL, \ "The file path to dump class loader resource cache.") \ \ - product(ccstr, LoadClassLoaderResourceCacheFile, NULL, \ + product(ccstr, LoadClassLoaderResourceCacheFile, NULL, EXPERIMENTAL, \ "The file path to laod class loader resource cache.") \ \ - product(uint, ClassLoaderResourceCacheSizeEachLoader, 2000, \ + product(uint, ClassLoaderResourceCacheSizeEachLoader, 2000, EXPERIMENTAL, \ "Max number of entries that can be cached in each " \ "class loader (delete old values based on LRU).") \ \ diff --git a/src/hotspot/share/jbooster/lazyAot.cpp b/src/hotspot/share/jbooster/lazyAot.cpp index 91c570328..d36bfe671 100644 --- a/src/hotspot/share/jbooster/lazyAot.cpp +++ b/src/hotspot/share/jbooster/lazyAot.cpp @@ -321,19 +321,23 @@ class KlassGetAllInstanceKlassesClosure: public KlassClosure { GrowableArray* _klasses; GrowableArray* _methods_to_compile; GrowableArray* _methods_not_compile; + ScalarHashSet* _visited; public: KlassGetAllInstanceKlassesClosure(GrowableArray* klasses, GrowableArray* methods_to_compile, - GrowableArray* methods_not_compile): + GrowableArray* methods_not_compile, + ScalarHashSet* visited): _klasses(klasses), _methods_to_compile(methods_to_compile), - _methods_not_compile(methods_not_compile) {} + _methods_not_compile(methods_not_compile), + _visited(visited) {} void do_klass(Klass* k) override { if (!k->is_instance_klass()) return; InstanceKlass* ik = InstanceKlass::cast(k); if (!ik->is_loaded()) return; + if (!_visited->add(ik->name())) return; // skip dup klass if (PrintAllClassInfo) { ResourceMark rm; @@ -375,6 +379,7 @@ class CLDGetAllInstanceKlassesClosure: public CLDClosure { GrowableArray* _klasses; GrowableArray* _methods_to_compile; GrowableArray* _methods_not_compile; + ScalarHashSet _visited; private: void for_each(ClassLoaderData* cld) { @@ -394,7 +399,7 @@ private: } if (!cld->has_class_mirror_holder() && LazyAOT::can_be_compiled(cld)) { if (_loaders != nullptr) _loaders->append(cld); - KlassGetAllInstanceKlassesClosure cl(_klasses, _methods_to_compile, _methods_not_compile); + KlassGetAllInstanceKlassesClosure cl(_klasses, _methods_to_compile, _methods_not_compile, &_visited); cld->classes_do(&cl); } } @@ -408,7 +413,8 @@ public: _loaders(all_loaders), _klasses(klasses_to_compile), _methods_to_compile(methods_to_compile), - _methods_not_compile(methods_not_compile) {} + _methods_not_compile(methods_not_compile), + _visited() {} void do_cld(ClassLoaderData* cld) override { for_each(cld); } }; diff --git a/src/hotspot/share/jbooster/server/serverDataManager.cpp b/src/hotspot/share/jbooster/server/serverDataManager.cpp index 33d6faf4c..8753102a4 100644 --- a/src/hotspot/share/jbooster/server/serverDataManager.cpp +++ b/src/hotspot/share/jbooster/server/serverDataManager.cpp @@ -33,6 +33,7 @@ #include "jbooster/utilities/concurrentHashMap.inline.hpp" #include "jbooster/utilities/fileUtils.hpp" #include "logging/log.hpp" +#include "memory/metadataFactory.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/methodData.hpp" #include "oops/symbol.hpp" @@ -363,12 +364,26 @@ JClientSessionData::JClientSessionData(uint32_t session_id, _cl_s2c(), _cl_c2s(), _k_c2s(), - _m2md(), + _m2md(Mutex::nonleaf), _ref_cnt(1) {} JClientSessionData::~JClientSessionData() { guarantee(ref_cnt().get() == 0, "sanity"); _program_data->ref_cnt().dec_and_update_time(); + if (_m2md.size() > 0) { + JavaThread* THREAD = JavaThread::current(); + auto clear_func = [] (JClientSessionData::AddressMap::KVNode* kv_node) -> bool { + assert(kv_node->key() != nullptr && kv_node->value() != nullptr, "sanity"); + Method* m = (Method*)kv_node->key(); + MethodData* md = (MethodData*)kv_node->value(); + assert(*md->get_failed_speculations_address() == NULL, "must be"); + md->~MethodData(); + ClassLoaderData* loader_data = m->method_holder()->class_loader_data(); + MetadataFactory::free_metadata(loader_data, md); + return true; + }; + _m2md.for_each(clear_func, THREAD); + } } address JClientSessionData::get_address(AddressMap& table, address key, Thread* thread) { diff --git a/src/hotspot/share/jbooster/server/serverMessageHandler.cpp b/src/hotspot/share/jbooster/server/serverMessageHandler.cpp index a92d1c6a4..962e93cc7 100644 --- a/src/hotspot/share/jbooster/server/serverMessageHandler.cpp +++ b/src/hotspot/share/jbooster/server/serverMessageHandler.cpp @@ -348,11 +348,10 @@ int ServerMessageHandler::handle_lazy_aot_compilation_task(TRAPS) { log_info(jbooster, compilation)("Skippd as this program has been compiled. session_id=%u.", ss().session_id()); } else { - log_error(jbooster, compilation)("Unknown compile state. session_id=%u.", - ss().session_id()); + log_info(jbooster, compilation)("Aot cache no generated. session_id=%u.", + ss().session_id()); } } - guarantee(!(compile_in_current_thread && aot_cache_state.is_being_generated()), "some logic missing?"); return 0; } @@ -364,9 +363,10 @@ int ServerMessageHandler::try_to_compile_lazy_aot(GrowableArray* JClientProgramData* pd = ss().session_data()->program_data(); JClientCacheState& aot_cache_state = pd->aot_cache_state(); if (klasses_to_compile->is_empty()) { + // the expected path without plugin aot_cache_state.set_not_generated(); - log_error(jbooster, compilation)("Failed to compile as the compilation list is empty. session_id=%u.", - ss().session_id()); + log_info(jbooster, compilation)("Stop compilation as the compilation list is empty. session_id=%u.", + ss().session_id()); return 0; } diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index 58432f1eb..12a0f3cf0 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -1963,9 +1963,10 @@ MethodData::MethodData(const methodHandle& method, const bool* ignored) _data[0] = 0; } -MethodData* MethodData::create_instance_for_jbooster(Method* method, int size, char* mem, TRAPS) { +MethodData* MethodData::create_instance_for_jbooster(Method* method, int byte_size, char* mem, TRAPS) { + int word_size = align_metadata_size(align_up(byte_size, BytesPerWord)/BytesPerWord); ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); - MethodData* res = new (loader_data, size, MetaspaceObj::MethodDataType, THREAD) + MethodData* res = new (loader_data, word_size, MetaspaceObj::MethodDataType, THREAD) MethodData(methodHandle(THREAD, method), (const bool*) nullptr); // backup @@ -1975,12 +1976,12 @@ MethodData* MethodData::create_instance_for_jbooster(Method* method, int size, c // memcpy int start = in_bytes(byte_offset_of(MethodData, _method)) + sizeof(res->_method); - memcpy((void*) (((char*) res) + start), mem + start, size - start); + memcpy((void*) (((char*) res) + start), mem + start, byte_size - start); // restore memcpy((void*) &res->_extra_data_lock, lock_bak, sizeof(res->_extra_data_lock)); res->_failed_speculations = fs_bak; - res->set_size(size); + res->set_size(byte_size); return res; } diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index a83b373a8..9a7dfd50e 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -2549,7 +2549,7 @@ public: private: MethodData(const methodHandle& method, const bool* ignored); public: - static MethodData* create_instance_for_jbooster(Method* method, int size, char* mem, TRAPS); + static MethodData* create_instance_for_jbooster(Method* method, int byte_size, char* mem, TRAPS); #endif // INCLUDE_JBOOSTER }; diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index bafbfe08d..90b0866e9 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -109,6 +109,7 @@ #include "jbooster/client/clientMessageHandler.hpp" #include "jbooster/net/serverListeningThread.hpp" #include "jbooster/server/serverDataManager.hpp" +#include "services/memoryService.hpp" #endif // INCLUDE_JBOOSTER #include @@ -3891,6 +3892,26 @@ JVM_ENTRY(jlong, JVM_JBoosterGetMetaspaceMethodData(JNIEnv *env, jint session_id #endif // INCLUDE_JBOOSTER JVM_END +JVM_ENTRY(void, JVM_JBoosterFreeUnusedCodeBlobs(JNIEnv *env, jobject blobs)) +#if INCLUDE_JBOOSTER + typeArrayOop address_array = typeArrayOop(JNIHandles::resolve(blobs)); + int length = address_array->length(); + { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + for (int index = 0; index < length; index++) { + jlong adr = address_array->long_at(index); + RuntimeBlob* rb = (RuntimeBlob*)(address)adr; + assert(rb != nullptr && rb->is_runtime_stub(), "sanity"); + rb->flush(); + log_trace(codecache, jbooster)("free %s", rb->name()); + CodeCache::free(rb); + } + } + // Track memory usage statistic after releasing CodeCache_lock + MemoryService::track_code_cache_memory_usage(); +#endif // INCLUDE_JBOOSTER +JVM_END + JVM_ENTRY(void, JVM_JBoosterStartupNativeCallback(JNIEnv *env)) #if INCLUDE_JBOOSTER if (!UseJBooster) return; diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 2921f3f38..bc56a1322 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -4025,6 +4025,7 @@ jint Arguments::apply_ergo() { // So the time for sending client VM flags to the server should be later // than most VM flags are initialized, but earlier than the time for CDS // initialization. + JBoosterManager::check_arguments(); if (UseJBooster || AsJBooster) { result = JBoosterManager::init_phase1(); if (result != JNI_OK) return result; diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java index 7e44c0cdb..5091b95a7 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java @@ -165,6 +165,7 @@ public final class Main { e.printStackTrace(); } finally { log.flush(); + jboosterContext.clear(); JBoosterCompilationContext.set(null); // Make sure the static fields are not used. @@ -239,6 +240,7 @@ public final class Main { @SuppressWarnings("try") private boolean run() throws Exception { LogPrinter.openLog(); + HotSpotGraalRuntime runtime = null; try { @@ -249,7 +251,12 @@ public final class Main { try (Timer t = new Timer(this, "")) { classesToCompile = collector.collectClassesToCompile(); - printer.printInfo(classesToCompile.size() + " classes found"); + if (classesToCompile == null) { + printer.printInfo("no class found, stop compilation"); + return false; + } else { + printer.printInfo(classesToCompile.size() + " classes found"); + } } OptionValues graalOptions = HotSpotGraalOptionValues.defaultOptions(); @@ -259,7 +266,7 @@ public final class Main { } graalOptions = new OptionValues(graalOptions, GeneratePIC, true, ImmutableCode, true); GraalJVMCICompiler graalCompiler = HotSpotGraalCompilerFactory.createCompiler("JAOTC", JVMCI.getRuntime(), graalOptions, CompilerConfigurationFactory.selectFactory(null, graalOptions)); - HotSpotGraalRuntime runtime = (HotSpotGraalRuntime) graalCompiler.getGraalRuntime(); + runtime = (HotSpotGraalRuntime) graalCompiler.getGraalRuntime(); GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig(); if (graalHotSpotVMConfig.verifyOops) { @@ -387,6 +394,9 @@ public final class Main { printer.printlnVerbose(""); } finally { + if (runtime != null && options.isAsJBooster()) { + runtime.kill(); + } LogPrinter.closeLog(); } return true; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java index f1c741c59..24d9f6b99 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java @@ -115,4 +115,6 @@ public interface HotSpotResolvedObjectType extends ResolvedJavaType { * does not support fingerprints) */ long getFingerprint(); + + boolean canClassInitBarrierWorkIn(HotSpotResolvedObjectType otherType); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 19f7cc0b0..b21015aff 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -1066,4 +1066,40 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem return UNSAFE.getInt(getMetaspaceKlass() + config().instanceKlassMiscFlagsOffset); } + private boolean isAncestor(ClassLoader target, ClassLoader context) { + ClassLoader acl = context; + do { + acl = acl.getParent(); + if (target == acl) { + return true; + } + } while (acl != null); + return false; + } + + public boolean canClassInitBarrierWorkIn(HotSpotResolvedObjectType otherType) { + if (!(this.mirror instanceof DirectHotSpotObjectConstantImpl)) return false; + DirectHotSpotObjectConstantImpl targetObj = (DirectHotSpotObjectConstantImpl) this.mirror; + if (!(targetObj.object instanceof Class)) return false; + ClassLoader targetClassLoader = ((Class) targetObj.object).getClassLoader(); + if (targetClassLoader == null) { + // Class will be loaded by bootclassloader, no need to care classloader + return true; + } + + if (!(otherType instanceof HotSpotResolvedObjectTypeImpl)) return false; + if (!(((HotSpotResolvedObjectTypeImpl)otherType).mirror instanceof DirectHotSpotObjectConstantImpl)) return false; + DirectHotSpotObjectConstantImpl contextObj = (DirectHotSpotObjectConstantImpl) ((HotSpotResolvedObjectTypeImpl)otherType).mirror; + if (!(contextObj.object instanceof Class)) return false; + ClassLoader contextClassLoader = ((Class) contextObj.object).getClassLoader(); + + if (targetClassLoader == contextClassLoader) { + return true; + } + + if (contextClassLoader == null) { + return false; + } + return isAncestor(targetClassLoader, contextClassLoader); + } } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/jbooster/JBoosterCompilationContext.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/jbooster/JBoosterCompilationContext.java index aa18682e9..b26786a52 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/jbooster/JBoosterCompilationContext.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/jbooster/JBoosterCompilationContext.java @@ -166,6 +166,18 @@ public interface JBoosterCompilationContext { */ AtomicInteger getCompileQueueFailedMethodCount(); + /** + * Record JBooster Installed CodeBlobs, only save address. + * (To support multiple compilations in single process with graal compiler) + */ + void recordJBoosterInstalledCodeBlobs(long address); + + /** + * Do some cleanup after the current compilation is complete. + * (To support multiple compilations in single process with graal compiler) + */ + void clear(); + /** * Should the method be excluded for inline. * (To support PGO) diff --git a/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalManagement.java b/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalManagement.java index c1c33c775..ca9a340a8 100644 --- a/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalManagement.java +++ b/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalManagement.java @@ -127,6 +127,26 @@ public final class HotSpotGraalManagement implements HotSpotGraalManagementRegis deferred = null; } + /** + * check and clear dead beans. + */ + private void checkAlive() { + // last alive bean + HotSpotGraalManagement before = null; + for (HotSpotGraalManagement m = deferred; m != null; m = m.nextDeferred) { + HotSpotGraalRuntime runtime = m.bean.getRuntime(); + if (!runtime.isAlive()) { + if (before == null) { + deferred = m.nextDeferred; + } else { + before.nextDeferred = m.nextDeferred; + } + } else { + before = m; + } + } + } + @Override public void run() { while (true) { @@ -150,6 +170,7 @@ public final class HotSpotGraalManagement implements HotSpotGraalManagementRegis * Checks for active MBean server and if available, processes deferred registrations. */ synchronized void poll() { + checkAlive(); if (platformMBeanServer == null) { try { ArrayList servers = MBeanServerFactory.findMBeanServer(null); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java index dde111f58..15989778f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StableArrayReadFoldingTest.java @@ -99,7 +99,8 @@ public class StableArrayReadFoldingTest extends GraalCompilerTest { return beforeKill == afterKill; } - @Test + // obsoleted in JDK17: unaligned access is illegal in CompilerToVM.readFieldValue + // @Test public void testKillWithSameTypeUnaligned() { Assume.assumeTrue("Only test unaligned access on AMD64", getTarget().arch instanceof AMD64); ResolvedJavaMethod method = getResolvedJavaMethod("killWithSameTypeUnaligned"); @@ -115,7 +116,8 @@ public class StableArrayReadFoldingTest extends GraalCompilerTest { return beforeKill == afterKill; } - @Test + // obsoleted in JDK17: unaligned access is illegal in CompilerToVM.readFieldValue + // @Test public void testKillWithDifferentTypeUnaligned() { Assume.assumeTrue("Only test unaligned access on AMD64", getTarget().arch instanceof AMD64); ResolvedJavaMethod method = getResolvedJavaMethod("killWithDifferentTypeUnaligned"); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java index 41dcd67e8..aa3e57de2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java @@ -571,6 +571,17 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { return compilationProblemsPerAction; } + // support server mode + private boolean alive = true; + + public boolean isAlive() { + return alive; + } + + public void kill() { + alive = false; + } + // ------- Management interface --------- private HotSpotGraalManagementRegistration management; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java index 5e3013055..a9fdfe2c2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java @@ -68,6 +68,7 @@ import jdk.vm.ci.code.site.DataPatch; import jdk.vm.ci.code.site.Infopoint; import jdk.vm.ci.hotspot.HotSpotCompiledCode; import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.jbooster.JBoosterCompilationContext; import jdk.vm.ci.meta.DefaultProfilingInfo; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.TriState; @@ -202,6 +203,13 @@ public abstract class Stub { // code if we don't have a corresponding VM global symbol. HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, null, null, compResult, options); code = codeCache.installCode(null, compiledCode, null, null, false); + + JBoosterCompilationContext ctx = JBoosterCompilationContext.get(); + if (ctx != null) { + // record installedcode for jbooster. + // clean it later in JBoosterCompilationContext.clear(). + ctx.recordJBoosterInstalledCodeBlobs(code.getAddress()); + } } catch (Throwable e) { throw debug.handle(e); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java index d2f7b99cc..4126db192 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java @@ -70,6 +70,7 @@ import org.graalvm.compiler.phases.common.inlining.policy.InliningPolicy; import org.graalvm.compiler.phases.tiers.HighTierContext; import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; import jdk.vm.ci.jbooster.JBoosterCompilationContext; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.JavaTypeProfile; @@ -319,6 +320,13 @@ public class InliningData { ArrayList concreteMethods = new ArrayList<>(); ArrayList concreteMethodsProbabilities = new ArrayList<>(); for (int i = 0; i < ptypes.length; i++) { + if (ctx != null && ctx.usePGO() && (contextType instanceof HotSpotResolvedObjectType) && (ptypes[i].getType() instanceof HotSpotResolvedObjectType)) { + HotSpotResolvedObjectType target = (HotSpotResolvedObjectType) (ptypes[i].getType()); + if (!target.canClassInitBarrierWorkIn((HotSpotResolvedObjectType) contextType)) { + // conflict with classInitBarrier, ignore it + continue; + } + } ResolvedJavaMethod concrete = ptypes[i].getType().resolveConcreteMethod(targetMethod, contextType); if (concrete == null) { InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "could not resolve method"); diff --git a/src/jdk.jbooster/share/classes/jdk/jbooster/JBoosterCompilationContextImpl.java b/src/jdk.jbooster/share/classes/jdk/jbooster/JBoosterCompilationContextImpl.java index 65f28e141..4918f8552 100644 --- a/src/jdk.jbooster/share/classes/jdk/jbooster/JBoosterCompilationContextImpl.java +++ b/src/jdk.jbooster/share/classes/jdk/jbooster/JBoosterCompilationContextImpl.java @@ -23,7 +23,9 @@ package jdk.jbooster; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; @@ -51,6 +53,7 @@ public class JBoosterCompilationContextImpl implements JBoosterCompilationContex private final AtomicInteger elfSectionShStrTabNrOfBytes = new AtomicInteger(0); private final AtomicInteger compileQueueSuccessfulMethodCount = new AtomicInteger(0); private final AtomicInteger compileQueueFailedMethodCount = new AtomicInteger(0); + private final Set installedCodeBlobs = Collections.synchronizedSet(new HashSet<>());; private CountDownLatch aotCompilerRemainingTaskCount = null; @@ -164,5 +167,22 @@ public class JBoosterCompilationContextImpl implements JBoosterCompilationContex return getMetaspaceMethodData(sessionId, metaspaceMethod); } + @Override + public void recordJBoosterInstalledCodeBlobs(long address) { + installedCodeBlobs.add(address); + } + + @Override + public void clear() { + long[] blobs = new long[installedCodeBlobs.size()]; + int index = 0; + for (long blob : installedCodeBlobs) { + blobs[index++] = blob; + } + freeUnusedCodeBlobs(blobs); + } + private static native long getMetaspaceMethodData(int sessionId, long metaspaceMethod); + + private static native long freeUnusedCodeBlobs(long[] blobs); } diff --git a/src/jdk.jbooster/share/native/libjbooster/JBooster.c b/src/jdk.jbooster/share/native/libjbooster/JBooster.c index 664c761ff..0c25710ae 100644 --- a/src/jdk.jbooster/share/native/libjbooster/JBooster.c +++ b/src/jdk.jbooster/share/native/libjbooster/JBooster.c @@ -49,3 +49,9 @@ Java_jdk_jbooster_JBoosterCompilationContextImpl_getMetaspaceMethodData(JNIEnv * { return JVM_JBoosterGetMetaspaceMethodData(env, session_id, metaspace_method); } + +JNIEXPORT void JNICALL +Java_jdk_jbooster_JBoosterCompilationContextImpl_freeUnusedCodeBlobs(JNIEnv * env, jclass unused, jobject blobs) +{ + return JVM_JBoosterFreeUnusedCodeBlobs(env, blobs); +} \ No newline at end of file diff --git a/test/hotspot/jtreg/ProblemList-graal.txt b/test/hotspot/jtreg/ProblemList-graal.txt index f7e6f56a4..a66973d90 100644 --- a/test/hotspot/jtreg/ProblemList-graal.txt +++ b/test/hotspot/jtreg/ProblemList-graal.txt @@ -242,3 +242,7 @@ org.graalvm.compiler.core.test.deopt.CompiledMethodTest 8202955 org.graalvm.compiler.hotspot.test.ReservedStackAccessTest 8213567 windows-all +# Obsoleted in JDK17 +compiler/graalunit/CoreJdk9Test.java 8218074 +compiler/graalunit/HotspotJdk9Test.java 8218074 +compiler/graalunit/Replacements9Test.java 8218074 diff --git a/test/jdk/tools/jbooster/JBoosterCmdTest.java b/test/jdk/tools/jbooster/JBoosterCmdTest.java index 4a0fe7e7b..98439e699 100644 --- a/test/jdk/tools/jbooster/JBoosterCmdTest.java +++ b/test/jdk/tools/jbooster/JBoosterCmdTest.java @@ -42,7 +42,7 @@ public class JBoosterCmdTest extends JBoosterTestBase { private static void testServerPort1(TestContext ctx) throws Exception { Process p = jbooster(ctx, List.of(), List.of()); p.waitFor(WAIT_SHORT_TIME, TimeUnit.SECONDS); - assertEquals(p.exitValue(), 1, "port not set"); + assertEquals(p.exitValue(), 0, "port not set"); } private static void testServerPort2(TestContext ctx) throws Exception { @@ -56,19 +56,19 @@ public class JBoosterCmdTest extends JBoosterTestBase { private static void testServerPort3(TestContext ctx) throws Exception { Process p = jbooster(ctx, List.of(), List.of("-p", "1")); p.waitFor(WAIT_SHORT_TIME, TimeUnit.SECONDS); - assertEquals(p.exitValue(), 1, "port < 1024"); + assertEquals(p.exitValue(), 0, "port < 1024"); } private static void testServerPort4(TestContext ctx) throws Exception { Process p = jbooster(ctx, List.of(), List.of("-p", "456716")); p.waitFor(WAIT_SHORT_TIME, TimeUnit.SECONDS); - assertEquals(p.exitValue(), 1, "port > 65535"); + assertEquals(p.exitValue(), 0, "port > 65535"); } private static void testServerArgFormat1(TestContext ctx) throws Exception { Process p = jbooster(ctx, List.of(), List.of("-p", SERVER_PORT_STR, "-t")); p.waitFor(WAIT_SHORT_TIME, TimeUnit.SECONDS); - assertEquals(p.exitValue(), 1, "no arg for -t"); + assertEquals(p.exitValue(), 0, "no arg for -t"); } private static void testServerArgFormat2(TestContext ctx) throws Exception { @@ -98,13 +98,13 @@ public class JBoosterCmdTest extends JBoosterTestBase { private static void testServerArgFormat6(TestContext ctx) throws Exception { Process p = jbooster(ctx, List.of(), List.of("-p", "-t", "12345")); p.waitFor(WAIT_SHORT_TIME, TimeUnit.SECONDS); - assertEquals(p.exitValue(), 1, "no arg for -p"); + assertEquals(p.exitValue(), 0, "no arg for -p"); } private static void testServerArgFormat7(TestContext ctx) throws Exception { Process p = jbooster(ctx, List.of(), List.of("--help=123")); p.waitFor(WAIT_SHORT_TIME, TimeUnit.SECONDS); - assertEquals(p.exitValue(), 1, "--help do not need arg"); + assertEquals(p.exitValue(), 0, "--help do not need arg"); } private static void testClientArg1(TestContext ctx) throws Exception { diff --git a/test/jdk/tools/launcher/HelpFlagsTest.java b/test/jdk/tools/launcher/HelpFlagsTest.java index 7e7cf47f9..29d5515ba 100644 --- a/test/jdk/tools/launcher/HelpFlagsTest.java +++ b/test/jdk/tools/launcher/HelpFlagsTest.java @@ -130,7 +130,7 @@ public class HelpFlagsTest extends TestHelper { new ToolHelpSpec("javadoc", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help new ToolHelpSpec("javap", 1, 1, 1, 0, 1, 1, 2), // -?, -h, --help -help, Documents -help new ToolHelpSpec("javaw", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help, win only - new ToolHelpSpec("jbooster", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help + new ToolHelpSpec("jbooster", 1, 1, 1, 0, 1, 1, 0), // -?, -h, --help -help, Documents -help new ToolHelpSpec("jcmd", 1, 1, 1, 0, 1, 0, 1), // -?, -h, --help, -help accepted but not documented. new ToolHelpSpec("jdb", 1, 1, 1, 0, 1, 1, 0), // -?, -h, --help -help, Documents -help new ToolHelpSpec("jdeprscan", 1, 1, 1, 0, 0, 0, 1), // -?, -h, --help -- 2.19.1