# HG changeset patch # User michaelm # Date 1574763733 0 # Node ID bfc8074ea4ef5f99f7d1a42d4e02db9ea91af775 # Parent aa516a7cf95e8ce743c78f423b066e9d7b58e559# Parent d9a3bddcffccd5597301c6d8f0e466962e3071d6 Merge diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/classfile/classLoaderDataGraph.cpp --- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp Tue Nov 26 10:22:13 2019 +0000 @@ -186,10 +186,7 @@ // GC root of class loader data created. ClassLoaderData* volatile ClassLoaderDataGraph::_head = NULL; ClassLoaderData* ClassLoaderDataGraph::_unloading = NULL; -ClassLoaderData* ClassLoaderDataGraph::_saved_unloading = NULL; -ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL; -bool ClassLoaderDataGraph::_should_purge = false; bool ClassLoaderDataGraph::_should_clean_deallocate_lists = false; bool ClassLoaderDataGraph::_safepoint_cleanup_needed = false; bool ClassLoaderDataGraph::_metaspace_oom = false; @@ -249,9 +246,7 @@ void ClassLoaderDataGraph::cld_unloading_do(CLDClosure* cl) { assert_locked_or_safepoint_weak(ClassLoaderDataGraph_lock); - // Only walk the head until any clds not purged from prior unloading - // (CMS doesn't purge right away). - for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + for (ClassLoaderData* cld = _unloading; cld != NULL; cld = cld->next()) { assert(cld->is_unloading(), "invariant"); cl->do_cld(cld); } @@ -381,9 +376,7 @@ void ClassLoaderDataGraph::modules_unloading_do(void f(ModuleEntry*)) { assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - // Only walk the head until any clds not purged from prior unloading - // (CMS doesn't purge right away). - for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + for (ClassLoaderData* cld = _unloading; cld != NULL; cld = cld->next()) { assert(cld->is_unloading(), "invariant"); cld->modules_do(f); } @@ -399,9 +392,7 @@ void ClassLoaderDataGraph::packages_unloading_do(void f(PackageEntry*)) { assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - // Only walk the head until any clds not purged from prior unloading - // (CMS doesn't purge right away). - for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + for (ClassLoaderData* cld = _unloading; cld != NULL; cld = cld->next()) { assert(cld->is_unloading(), "invariant"); cld->packages_do(f); } @@ -424,9 +415,7 @@ void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) { assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - // Only walk the head until any clds not purged from prior unloading - // (CMS doesn't purge right away). - for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + for (ClassLoaderData* cld = _unloading; cld != NULL; cld = cld->next()) { assert(cld->is_unloading(), "invariant"); cld->classes_do(f); } @@ -476,32 +465,6 @@ } } -GrowableArray* ClassLoaderDataGraph::new_clds() { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?"); - - GrowableArray* array = new GrowableArray(); - - // The CLDs in [_head, _saved_head] were all added during last call to remember_new_clds(true); - ClassLoaderData* curr = _head; - while (curr != _saved_head) { - if (!curr->claimed(ClassLoaderData::_claim_strong)) { - array->push(curr); - LogTarget(Debug, class, loader, data) lt; - if (lt.is_enabled()) { - LogStream ls(lt); - ls.print("found new CLD: "); - curr->print_value_on(&ls); - ls.cr(); - } - } - - curr = curr->_next; - } - - return array; -} - #ifndef PRODUCT bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) { assert_locked_or_safepoint(ClassLoaderDataGraph_lock); @@ -544,10 +507,6 @@ uint loaders_processed = 0; uint loaders_removed = 0; - // Save previous _unloading pointer for CMS which may add to unloading list before - // purging and we don't want to rewalk the previously unloaded class loader data. - _saved_unloading = _unloading; - data = _head; while (data != NULL) { if (data->is_alive()) { diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/classfile/classLoaderDataGraph.hpp --- a/src/hotspot/share/classfile/classLoaderDataGraph.hpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/classfile/classLoaderDataGraph.hpp Tue Nov 26 10:22:13 2019 +0000 @@ -43,10 +43,6 @@ // All CLDs (except the null CLD) can be reached by walking _head->_next->... static ClassLoaderData* volatile _head; static ClassLoaderData* _unloading; - // CMS support. - static ClassLoaderData* _saved_head; - static ClassLoaderData* _saved_unloading; - static bool _should_purge; // Set if there's anything to purge in the deallocate lists or previous versions // during a safepoint after class unloading in a full GC. @@ -115,18 +111,6 @@ static void print_dictionary(outputStream* st); static void print_table_statistics(outputStream* st); - // CMS support. - static void remember_new_clds(bool remember) { _saved_head = (remember ? _head : NULL); } - static GrowableArray* new_clds(); - - static void set_should_purge(bool b) { _should_purge = b; } - static bool should_purge_and_reset() { - bool res = _should_purge; - // reset for next time. - set_should_purge(false); - return res; - } - static int resize_dictionaries(); static bool has_metaspace_oom() { return _metaspace_oom; } diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp --- a/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp Tue Nov 26 10:22:13 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -32,7 +32,9 @@ #include "jfr/support/jfrEventClass.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" +#include "prims/jvmtiEnvBase.hpp" #include "prims/jvmtiExport.hpp" +#include "prims/jvmtiUtil.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/thread.inline.hpp" #include "utilities/exceptions.hpp" @@ -52,19 +54,17 @@ } } -static jvmtiError set_event_notification_mode(jvmtiEventMode mode, - jvmtiEvent event, - jthread event_thread, - ...) { - if (jfr_jvmti_env == NULL) { - return JVMTI_ERROR_NONE; - } +static bool set_event_notification_mode(jvmtiEventMode mode, + jvmtiEvent event, + jthread event_thread, + ...) { + assert(jfr_jvmti_env != NULL, "invariant"); const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventNotificationMode(mode, event, event_thread); check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventNotificationMode"); - return jvmti_ret_code; + return jvmti_ret_code == JVMTI_ERROR_NONE; } -static jvmtiError update_class_file_load_hook_event(jvmtiEventMode mode) { +static bool update_class_file_load_hook_event(jvmtiEventMode mode) { return set_event_notification_mode(mode, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); } @@ -117,12 +117,23 @@ return classes; } -static void log_and_throw(TRAPS) { +// caller needs ResourceMark +static void log_and_throw(jvmtiError error, TRAPS) { if (!HAS_PENDING_EXCEPTION) { DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); ThreadInVMfromNative tvmfn((JavaThread*)THREAD); - log_error(jfr, system)("JfrJvmtiAgent::retransformClasses failed"); - JfrJavaSupport::throw_class_format_error("JfrJvmtiAgent::retransformClasses failed", THREAD); + const char base_error_msg[] = "JfrJvmtiAgent::retransformClasses failed: "; + size_t length = sizeof base_error_msg; // includes terminating null + const char* const jvmti_error_name = JvmtiUtil::error_name(error); + assert(jvmti_error_name != NULL, "invariant"); + length += strlen(jvmti_error_name); + char* error_msg = NEW_RESOURCE_ARRAY(char, length); + jio_snprintf(error_msg, length, "%s%s", base_error_msg, jvmti_error_name); + if (JVMTI_ERROR_INVALID_CLASS_FORMAT == error) { + JfrJavaSupport::throw_class_format_error(error_msg, THREAD); + } else { + JfrJavaSupport::throw_runtime_exception(error_msg, THREAD); + } } } @@ -137,12 +148,15 @@ } } +static bool is_valid_jvmti_phase() { + return JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE; +} + void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, TRAPS) { assert(env != NULL, "invariant"); + assert(classes_array != NULL, "invariant"); + assert(is_valid_jvmti_phase(), "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); - if (classes_array == NULL) { - return; - } const jint classes_count = env->GetArrayLength(classes_array); if (classes_count <= 0) { return; @@ -153,27 +167,27 @@ for (jint i = 0; i < classes_count; i++) { jclass clz = (jclass)env->GetObjectArrayElement(classes_array, i); check_exception_and_log(env, THREAD); - + classes[i] = clz; + } + { // inspecting the oop/klass requires a thread transition - { - ThreadInVMfromNative transition((JavaThread*)THREAD); - if (JdkJfrEvent::is_a(clz)) { - // should have been tagged already - assert(JdkJfrEvent::is_subklass(clz), "invariant"); - } else { + ThreadInVMfromNative transition((JavaThread*)THREAD); + for (jint i = 0; i < classes_count; ++i) { + jclass clz = classes[i]; + if (!JdkJfrEvent::is_a(clz)) { // outside the event hierarchy JdkJfrEvent::tag_as_host(clz); } } - - classes[i] = clz; } - if (jfr_jvmti_env->RetransformClasses(classes_count, classes) != JVMTI_ERROR_NONE) { - log_and_throw(THREAD); + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); + const jvmtiError result = jfr_jvmti_env->RetransformClasses(classes_count, classes); + if (result != JVMTI_ERROR_NONE) { + log_and_throw(result, THREAD); } } -static jvmtiError register_callbacks(JavaThread* jt) { +static bool register_callbacks(JavaThread* jt) { assert(jfr_jvmti_env != NULL, "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); jvmtiEventCallbacks callbacks; @@ -182,10 +196,10 @@ callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook; const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); - return jvmti_ret_code; + return jvmti_ret_code == JVMTI_ERROR_NONE; } -static jvmtiError register_capabilities(JavaThread* jt) { +static bool register_capabilities(JavaThread* jt) { assert(jfr_jvmti_env != NULL, "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); jvmtiCapabilities capabilities; @@ -195,7 +209,7 @@ capabilities.can_retransform_any_class = 1; const jvmtiError jvmti_ret_code = jfr_jvmti_env->AddCapabilities(&capabilities); check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "Add Capabilities"); - return jvmti_ret_code; + return jvmti_ret_code == JVMTI_ERROR_NONE; } static jint create_jvmti_env(JavaThread* jt) { @@ -206,16 +220,14 @@ return vm->GetEnv((void **)&jfr_jvmti_env, JVMTI_VERSION); } -static jvmtiError unregister_callbacks(JavaThread* jt) { - if (jfr_jvmti_env == NULL) { - return JVMTI_ERROR_NONE; - } +static bool unregister_callbacks(JavaThread* jt) { + assert(jfr_jvmti_env != NULL, "invariant"); jvmtiEventCallbacks callbacks; /* Set empty callbacks */ memset(&callbacks, 0, sizeof(callbacks)); const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); - return jvmti_ret_code; + return jvmti_ret_code == JVMTI_ERROR_NONE; } JfrJvmtiAgent::JfrJvmtiAgent() {} @@ -223,20 +235,17 @@ JfrJvmtiAgent::~JfrJvmtiAgent() { JavaThread* jt = current_java_thread(); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); - ThreadToNativeFromVM transition(jt); - update_class_file_load_hook_event(JVMTI_DISABLE); - unregister_callbacks(jt); if (jfr_jvmti_env != NULL) { + ThreadToNativeFromVM transition(jt); + update_class_file_load_hook_event(JVMTI_DISABLE); + unregister_callbacks(jt); jfr_jvmti_env->DisposeEnvironment(); jfr_jvmti_env = NULL; } - agent = NULL; } -static bool initialize() { - JavaThread* const jt = current_java_thread(); +static bool initialize(JavaThread* jt) { assert(jt != NULL, "invariant"); - assert(jt->thread_state() == _thread_in_vm, "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); ThreadToNativeFromVM transition(jt); if (create_jvmti_env(jt) != JNI_OK) { @@ -244,25 +253,36 @@ return false; } assert(jfr_jvmti_env != NULL, "invariant"); - if (register_capabilities(jt) != JVMTI_ERROR_NONE) { + if (!register_capabilities(jt)) { + return false; + } + if (!register_callbacks(jt)) { return false; } - if (register_callbacks(jt) != JVMTI_ERROR_NONE) { - return false; - } - if (update_class_file_load_hook_event(JVMTI_ENABLE) != JVMTI_ERROR_NONE) { - return false; - } - return true; + return update_class_file_load_hook_event(JVMTI_ENABLE); +} + +static void log_and_throw_illegal_state_exception(TRAPS) { + DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); + const char* const illegal_state_msg = "An attempt was made to start JFR too early in the VM initialization sequence."; + log_error(jfr, system)(illegal_state_msg); + log_error(jfr, system)("JFR uses JVMTI RetransformClasses and requires the JVMTI state to have entered JVMTI_PHASE_LIVE."); + log_error(jfr, system)("Please initialize JFR in response to event JVMTI_EVENT_VM_INIT instead of JVMTI_EVENT_VM_START."); + JfrJavaSupport::throw_illegal_state_exception(illegal_state_msg, THREAD); } bool JfrJvmtiAgent::create() { - assert(jfr_jvmti_env == NULL, "invariant"); + assert(agent == NULL, "invariant"); + JavaThread* const jt = current_java_thread(); + if (!is_valid_jvmti_phase()) { + log_and_throw_illegal_state_exception(jt); + return false; + } agent = new JfrJvmtiAgent(); if (agent == NULL) { return false; } - if (!initialize()) { + if (!initialize(jt)) { delete agent; agent = NULL; return false; @@ -276,4 +296,3 @@ agent = NULL; } } - diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/jfr/jfr.cpp --- a/src/hotspot/share/jfr/jfr.cpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/jfr/jfr.cpp Tue Nov 26 10:22:13 2019 +0000 @@ -45,15 +45,21 @@ return JfrRecorder::is_recording(); } -void Jfr::on_vm_init() { - if (!JfrRecorder::on_vm_init()) { - vm_exit_during_initialization("Failure when starting JFR on_vm_init"); +void Jfr::on_create_vm_1() { + if (!JfrRecorder::on_create_vm_1()) { + vm_exit_during_initialization("Failure when starting JFR on_create_vm_1"); } } -void Jfr::on_vm_start() { - if (!JfrRecorder::on_vm_start()) { - vm_exit_during_initialization("Failure when starting JFR on_vm_start"); +void Jfr::on_create_vm_2() { + if (!JfrRecorder::on_create_vm_2()) { + vm_exit_during_initialization("Failure when starting JFR on_create_vm_2"); + } +} + +void Jfr::on_create_vm_3() { + if (!JfrRecorder::on_create_vm_3()) { + vm_exit_during_initialization("Failure when starting JFR on_create_vm_3"); } } diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/jfr/jfr.hpp --- a/src/hotspot/share/jfr/jfr.hpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/jfr/jfr.hpp Tue Nov 26 10:22:13 2019 +0000 @@ -43,8 +43,9 @@ static bool is_enabled(); static bool is_disabled(); static bool is_recording(); - static void on_vm_init(); - static void on_vm_start(); + static void on_create_vm_1(); + static void on_create_vm_2(); + static void on_create_vm_3(); static void on_unloading_classes(); static void on_thread_start(Thread* thread); static void on_thread_exit(Thread* thread); diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/jfr/jni/jfrJavaSupport.cpp --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp Tue Nov 26 10:22:13 2019 +0000 @@ -540,6 +540,10 @@ create_and_throw(vmSymbols::java_lang_ClassFormatError(), message, THREAD); } +void JfrJavaSupport::throw_runtime_exception(const char* message, TRAPS) { + create_and_throw(vmSymbols::java_lang_RuntimeException(), message, THREAD); +} + void JfrJavaSupport::abort(jstring errorMsg, Thread* t) { DEBUG_ONLY(check_java_thread_in_vm(t)); diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/jfr/jni/jfrJavaSupport.hpp --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp Tue Nov 26 10:22:13 2019 +0000 @@ -84,6 +84,7 @@ static void throw_internal_error(const char* message, TRAPS); static void throw_out_of_memory_error(const char* message, TRAPS); static void throw_class_format_error(const char* message, TRAPS); + static void throw_runtime_exception(const char* message, TRAPS); static bool is_jdk_jfr_module_available(); static bool is_jdk_jfr_module_available(outputStream* stream, TRAPS); diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/jfr/jni/jfrJniMethod.cpp --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp Tue Nov 26 10:22:13 2019 +0000 @@ -192,7 +192,9 @@ return JNI_TRUE; } if (!JfrRecorder::create(simulate_failure == JNI_TRUE)) { - JfrJavaSupport::throw_illegal_state_exception("Unable to start Jfr", thread); + if (!thread->has_pending_exception()) { + JfrJavaSupport::throw_illegal_state_exception("Unable to start Jfr", thread); + } return JNI_FALSE; } return JNI_TRUE; diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Tue Nov 26 10:22:13 2019 +0000 @@ -461,7 +461,6 @@ } size_t JfrCheckpointManager::flush_type_set() { - assert(!SafepointSynchronize::is_at_safepoint(), "invariant"); size_t elements = 0; { JfrCheckpointWriter writer(Thread::current()); diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/jfr/recorder/jfrRecorder.cpp --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp Tue Nov 26 10:22:13 2019 +0000 @@ -46,6 +46,9 @@ #include "runtime/handles.inline.hpp" #include "runtime/globals_extension.hpp" #include "utilities/growableArray.hpp" +#ifdef ASSERT +#include "prims/jvmtiEnvBase.hpp" +#endif bool JfrRecorder::is_disabled() { // True if -XX:-FlightRecorder has been explicitly set on the @@ -57,7 +60,9 @@ static bool enable() { assert(!_enabled, "invariant"); - FLAG_SET_MGMT(FlightRecorder, true); + if (!FlightRecorder) { + FLAG_SET_MGMT(FlightRecorder, true); + } _enabled = FlightRecorder; assert(_enabled, "invariant"); return _enabled; @@ -67,7 +72,7 @@ return _enabled; } -bool JfrRecorder::on_vm_init() { +bool JfrRecorder::on_create_vm_1() { if (!is_disabled()) { if (FlightRecorder || StartFlightRecording != NULL) { enable(); @@ -92,7 +97,7 @@ static void teardown_startup_support() { release_recordings(); - JfrOptionSet::release_startup_recording_options(); + JfrOptionSet::release_start_flight_recording_options(); } // Parsing options here to detect errors as soon as possible @@ -110,7 +115,7 @@ } static bool validate_recording_options(TRAPS) { - const GrowableArray* options = JfrOptionSet::startup_recording_options(); + const GrowableArray* options = JfrOptionSet::start_flight_recording_options(); if (options == NULL) { return true; } @@ -143,7 +148,7 @@ return true; } -static bool launch_recordings(TRAPS) { +static bool launch_command_line_recordings(TRAPS) { bool result = true; if (dcmd_recordings_array != NULL) { const int length = dcmd_recordings_array->length(); @@ -168,7 +173,7 @@ static bool is_cds_dump_requested() { // we will not be able to launch recordings if a cds dump is being requested - if (Arguments::is_dumping_archive() && (JfrOptionSet::startup_recording_options() != NULL)) { + if (Arguments::is_dumping_archive() && (JfrOptionSet::start_flight_recording_options() != NULL)) { warning("JFR will be disabled during CDS dumping"); teardown_startup_support(); return true; @@ -176,7 +181,7 @@ return false; } -bool JfrRecorder::on_vm_start() { +bool JfrRecorder::on_create_vm_2() { if (is_cds_dump_requested()) { return true; } @@ -187,9 +192,7 @@ if (!register_jfr_dcmds()) { return false; } - const bool in_graph = JfrJavaSupport::is_jdk_jfr_module_available(); - if (in_graph) { if (!validate_recording_options(thread)) { return false; @@ -198,17 +201,19 @@ return false; } } - if (!is_enabled()) { return true; } - if (!in_graph) { log_jdk_jfr_module_resolution_error(thread); return false; } + return true; +} - return launch_recordings(thread); +bool JfrRecorder::on_create_vm_3() { + assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence"); + return launch_command_line_recordings(Thread::current()); } static bool _created = false; @@ -277,7 +282,6 @@ } // subsystems -static JfrJvmtiAgent* _jvmti_agent = NULL; static JfrPostBox* _post_box = NULL; static JfrStorage* _storage = NULL; static JfrCheckpointManager* _checkpoint_manager = NULL; diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/jfr/recorder/jfrRecorder.hpp --- a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp Tue Nov 26 10:22:13 2019 +0000 @@ -38,6 +38,9 @@ friend class Jfr; friend void recorderthread_entry(JavaThread*, Thread*); private: + static bool on_create_vm_1(); + static bool on_create_vm_2(); + static bool on_create_vm_3(); static bool create_checkpoint_manager(); static bool create_chunk_repository(); static bool create_java_event_writer(); @@ -52,8 +55,6 @@ static bool create_components(); static void destroy_components(); static void on_recorder_thread_exit(); - static bool on_vm_start(); - static bool on_vm_init(); public: static bool is_enabled(); diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp --- a/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp Tue Nov 26 10:22:13 2019 +0000 @@ -677,7 +677,7 @@ return false; } -static GrowableArray* startup_recording_options_array = NULL; +static GrowableArray* start_flight_recording_options_array = NULL; bool JfrOptionSet::parse_start_flight_recording_option(const JavaVMOption** option, char* delimiter) { assert(option != NULL, "invariant"); @@ -700,28 +700,28 @@ assert(value != NULL, "invariant"); const size_t value_length = strlen(value); - if (startup_recording_options_array == NULL) { - startup_recording_options_array = new (ResourceObj::C_HEAP, mtTracing) GrowableArray(8, true, mtTracing); + if (start_flight_recording_options_array == NULL) { + start_flight_recording_options_array = new (ResourceObj::C_HEAP, mtTracing) GrowableArray(8, true, mtTracing); } - assert(startup_recording_options_array != NULL, "invariant"); + assert(start_flight_recording_options_array != NULL, "invariant"); char* const startup_value = NEW_C_HEAP_ARRAY(char, value_length + 1, mtTracing); strncpy(startup_value, value, value_length + 1); assert(strncmp(startup_value, value, value_length) == 0, "invariant"); - startup_recording_options_array->append(startup_value); + start_flight_recording_options_array->append(startup_value); return false; } -const GrowableArray* JfrOptionSet::startup_recording_options() { - return startup_recording_options_array; +const GrowableArray* JfrOptionSet::start_flight_recording_options() { + return start_flight_recording_options_array; } -void JfrOptionSet::release_startup_recording_options() { - if (startup_recording_options_array != NULL) { - const int length = startup_recording_options_array->length(); +void JfrOptionSet::release_start_flight_recording_options() { + if (start_flight_recording_options_array != NULL) { + const int length = start_flight_recording_options_array->length(); for (int i = 0; i < length; ++i) { - FREE_C_HEAP_ARRAY(char, startup_recording_options_array->at(i)); + FREE_C_HEAP_ARRAY(char, start_flight_recording_options_array->at(i)); } - delete startup_recording_options_array; - startup_recording_options_array = NULL; + delete start_flight_recording_options_array; + start_flight_recording_options_array = NULL; } } diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/jfr/recorder/service/jfrOptionSet.hpp --- a/src/hotspot/share/jfr/recorder/service/jfrOptionSet.hpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.hpp Tue Nov 26 10:22:13 2019 +0000 @@ -80,8 +80,8 @@ static bool parse_flight_recorder_option(const JavaVMOption** option, char* delimiter); static bool parse_start_flight_recording_option(const JavaVMOption** option, char* delimiter); - static const GrowableArray* startup_recording_options(); - static void release_startup_recording_options(); + static const GrowableArray* start_flight_recording_options(); + static void release_start_flight_recording_options(); }; #endif // SHARE_JFR_RECORDER_SERVICE_JFROPTIONSET_HPP diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/jvmci/jvmciRuntime.cpp --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp Tue Nov 26 10:22:13 2019 +0000 @@ -702,7 +702,7 @@ } void JVMCINMethodData::invalidate_nmethod_mirror(nmethod* nm) { - oop nmethod_mirror = get_nmethod_mirror(nm, /* phantom_ref */ true); + oop nmethod_mirror = get_nmethod_mirror(nm, /* phantom_ref */ false); if (nmethod_mirror == NULL) { return; } diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/runtime/safepoint.cpp --- a/src/hotspot/share/runtime/safepoint.cpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/runtime/safepoint.cpp Tue Nov 26 10:22:13 2019 +0000 @@ -620,19 +620,6 @@ } } - if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_CLD_PURGE)) { - if (ClassLoaderDataGraph::should_purge_and_reset()) { - // CMS delays purging the CLDG until the beginning of the next safepoint and to - // make sure concurrent sweep is done - const char* name = "purging class loader data graph"; - EventSafepointCleanupTask event; - TraceTime timer(name, TRACETIME_LOG(Info, safepoint, cleanup)); - ClassLoaderDataGraph::purge(); - - post_safepoint_cleanup_task_event(event, safepoint_id, name); - } - } - if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_SYSTEM_DICTIONARY_RESIZE)) { if (Dictionary::does_any_dictionary_needs_resizing()) { const char* name = "resizing system dictionaries"; diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/runtime/safepoint.hpp --- a/src/hotspot/share/runtime/safepoint.hpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/runtime/safepoint.hpp Tue Nov 26 10:22:13 2019 +0000 @@ -75,7 +75,6 @@ SAFEPOINT_CLEANUP_COMPILATION_POLICY, SAFEPOINT_CLEANUP_SYMBOL_TABLE_REHASH, SAFEPOINT_CLEANUP_STRING_TABLE_REHASH, - SAFEPOINT_CLEANUP_CLD_PURGE, SAFEPOINT_CLEANUP_SYSTEM_DICTIONARY_RESIZE, SAFEPOINT_CLEANUP_REQUEST_OOPSTORAGE_CLEANUP, // Leave this one last. diff -r aa516a7cf95e -r bfc8074ea4ef src/hotspot/share/runtime/thread.cpp --- a/src/hotspot/share/runtime/thread.cpp Mon Nov 25 15:16:29 2019 +0000 +++ b/src/hotspot/share/runtime/thread.cpp Tue Nov 26 10:22:13 2019 +0000 @@ -3887,7 +3887,7 @@ return status; } - JFR_ONLY(Jfr::on_vm_init();) + JFR_ONLY(Jfr::on_create_vm_1();) // Should be done after the heap is fully created main_thread->cache_global_variables(); @@ -4026,6 +4026,8 @@ // loaded until phase 2 completes call_initPhase2(CHECK_JNI_ERR); + JFR_ONLY(Jfr::on_create_vm_2();) + // Always call even when there are not JVMTI environments yet, since environments // may be attached late and JVMTI must track phases of VM execution JvmtiExport::enter_start_phase(); @@ -4061,7 +4063,7 @@ // Notify JVMTI agents that VM initialization is complete - nop if no agents. JvmtiExport::post_vm_initialized(); - JFR_ONLY(Jfr::on_vm_start();) + JFR_ONLY(Jfr::on_create_vm_3();) #if INCLUDE_MANAGEMENT Management::initialize(THREAD); diff -r aa516a7cf95e -r bfc8074ea4ef src/java.base/share/classes/java/io/File.java --- a/src/java.base/share/classes/java/io/File.java Mon Nov 25 15:16:29 2019 +0000 +++ b/src/java.base/share/classes/java/io/File.java Tue Nov 26 10:22:13 2019 +0000 @@ -29,6 +29,7 @@ import java.net.URL; import java.net.MalformedURLException; import java.net.URISyntaxException; +import java.nio.file.FileStore; import java.nio.file.FileSystems; import java.nio.file.Path; import java.security.SecureRandom; @@ -1798,10 +1799,13 @@ /** * Returns the size of the partition named by this - * abstract pathname. + * abstract pathname. If the total number of bytes in the partition is + * greater than {@link Long#MAX_VALUE}, then {@code Long.MAX_VALUE} will be + * returned. * * @return The size, in bytes, of the partition or {@code 0L} if this - * abstract pathname does not name a partition + * abstract pathname does not name a partition or if the size + * cannot be obtained * * @throws SecurityException * If a security manager has been installed and it denies @@ -1810,6 +1814,7 @@ * read access to the file named by this abstract pathname * * @since 1.6 + * @see FileStore#getTotalSpace */ public long getTotalSpace() { SecurityManager sm = System.getSecurityManager(); @@ -1820,12 +1825,15 @@ if (isInvalid()) { return 0L; } - return fs.getSpace(this, FileSystem.SPACE_TOTAL); + long space = fs.getSpace(this, FileSystem.SPACE_TOTAL); + return space >= 0L ? space : Long.MAX_VALUE; } /** * Returns the number of unallocated bytes in the partition named by this abstract path name. + * href="#partName">named by this abstract path name. If the + * number of unallocated bytes in the partition is greater than + * {@link Long#MAX_VALUE}, then {@code Long.MAX_VALUE} will be returned. * *

The returned number of unallocated bytes is a hint, but not * a guarantee, that it is possible to use most or any of these @@ -1837,9 +1845,10 @@ * will succeed. * * @return The number of unallocated bytes on the partition or {@code 0L} - * if the abstract pathname does not name a partition. This - * value will be less than or equal to the total file system size - * returned by {@link #getTotalSpace}. + * if the abstract pathname does not name a partition or if this + * number cannot be obtained. This value will be less than or + * equal to the total file system size returned by + * {@link #getTotalSpace}. * * @throws SecurityException * If a security manager has been installed and it denies @@ -1848,6 +1857,7 @@ * read access to the file named by this abstract pathname * * @since 1.6 + * @see FileStore#getUnallocatedSpace */ public long getFreeSpace() { SecurityManager sm = System.getSecurityManager(); @@ -1858,16 +1868,19 @@ if (isInvalid()) { return 0L; } - return fs.getSpace(this, FileSystem.SPACE_FREE); + long space = fs.getSpace(this, FileSystem.SPACE_FREE); + return space >= 0L ? space : Long.MAX_VALUE; } /** * Returns the number of bytes available to this virtual machine on the - * partition named by this abstract pathname. When - * possible, this method checks for write permissions and other operating - * system restrictions and will therefore usually provide a more accurate - * estimate of how much new data can actually be written than {@link - * #getFreeSpace}. + * partition named by this abstract pathname. If + * the number of available bytes in the partition is greater than + * {@link Long#MAX_VALUE}, then {@code Long.MAX_VALUE} will be returned. + * When possible, this method checks for write permissions and other + * operating system restrictions and will therefore usually provide a more + * accurate estimate of how much new data can actually be written than + * {@link #getFreeSpace}. * *

The returned number of available bytes is a hint, but not a * guarantee, that it is possible to use most or any of these bytes. The @@ -1878,9 +1891,10 @@ * to this file system will succeed. * * @return The number of available bytes on the partition or {@code 0L} - * if the abstract pathname does not name a partition. On - * systems where this information is not available, this method - * will be equivalent to a call to {@link #getFreeSpace}. + * if the abstract pathname does not name a partition or if this + * number cannot be obtained. On systems where this information + * is not available, this method will be equivalent to a call to + * {@link #getFreeSpace}. * * @throws SecurityException * If a security manager has been installed and it denies @@ -1889,6 +1903,7 @@ * read access to the file named by this abstract pathname * * @since 1.6 + * @see FileStore#getUsableSpace */ public long getUsableSpace() { SecurityManager sm = System.getSecurityManager(); @@ -1899,7 +1914,8 @@ if (isInvalid()) { return 0L; } - return fs.getSpace(this, FileSystem.SPACE_USABLE); + long space = fs.getSpace(this, FileSystem.SPACE_USABLE); + return space >= 0L ? space : Long.MAX_VALUE; } /* -- Temporary files -- */ diff -r aa516a7cf95e -r bfc8074ea4ef src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Mon Nov 25 15:16:29 2019 +0000 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Tue Nov 26 10:22:13 2019 +0000 @@ -2266,8 +2266,7 @@ boolean isProtectedInSuperClassOfEnclosingClassInOtherPackage() { return ((tree.sym.flags() & PROTECTED) != 0 && - tree.sym.packge() != owner.packge() && - !owner.enclClass().isSubClass(tree.sym.owner, types)); + tree.sym.packge() != owner.packge()); } /** diff -r aa516a7cf95e -r bfc8074ea4ef src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java Mon Nov 25 15:16:29 2019 +0000 +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java Tue Nov 26 10:22:13 2019 +0000 @@ -37,7 +37,6 @@ import java.util.Set; import jdk.internal.misc.VM; -import jdk.internal.reflect.Reflection; /** * Provides utilities needed by JVMCI clients. @@ -136,29 +135,6 @@ } } - private static boolean jvmciEnabled = true; - - /** - * When {@code -XX:-UseJVMCIClassLoader} is in use, JVMCI classes are loaded via the boot class - * loader. When {@code null} is the second argument to - * {@link ServiceLoader#load(Class, ClassLoader)}, service lookup will use the system class - * loader and thus find application classes which violates the API of {@link #load} and - * {@link #loadSingle}. To avoid this, a class loader that simply delegates to the boot class - * loader is used. - */ - static class LazyBootClassPath { - static final ClassLoader bootClassPath = new ClassLoader(null) { - }; - } - - private static ClassLoader findBootClassLoaderChild(ClassLoader start) { - ClassLoader cl = start; - while (cl.getParent() != null) { - cl = cl.getParent(); - } - return cl; - } - private static final Map, List> servicesCache = IS_BUILDING_NATIVE_IMAGE ? new HashMap<>() : null; @SuppressWarnings("unchecked") @@ -173,33 +149,7 @@ } } - Iterable providers = Collections.emptyList(); - if (jvmciEnabled) { - ClassLoader cl = null; - try { - cl = getJVMCIClassLoader(); - if (cl == null) { - cl = LazyBootClassPath.bootClassPath; - // JVMCI classes are loaded via the boot class loader. - // If we use null as the second argument to ServiceLoader.load, - // service loading will use the system class loader - // and find classes on the application class path. Since we - // don't want this, we use a loader that is as close to the - // boot class loader as possible (since it is impossible - // to force service loading to use only the boot class loader). - cl = findBootClassLoaderChild(ClassLoader.getSystemClassLoader()); - } - providers = ServiceLoader.load(service, cl); - } catch (UnsatisfiedLinkError e) { - jvmciEnabled = false; - } catch (InternalError e) { - if (e.getMessage().equals("JVMCI is not enabled")) { - jvmciEnabled = false; - } else { - throw e; - } - } - } + Iterable providers = ServiceLoader.load(service, ClassLoader.getSystemClassLoader()); if (IS_BUILDING_NATIVE_IMAGE) { synchronized (servicesCache) { ArrayList providersList = new ArrayList<>(); @@ -278,23 +228,6 @@ return singleProvider; } - static { - Reflection.registerMethodsToFilter(Services.class, Set.of("getJVMCIClassLoader")); - } - - /** - * Gets the JVMCI class loader. - * - * @throws InternalError with the {@linkplain Throwable#getMessage() message} - * {@code "JVMCI is not enabled"} iff JVMCI is not enabled - */ - private static ClassLoader getJVMCIClassLoader() { - if (IS_IN_NATIVE_IMAGE) { - return null; - } - return ClassLoader.getSystemClassLoader(); - } - /** * A Java {@code char} has a maximal UTF8 length of 3. */ diff -r aa516a7cf95e -r bfc8074ea4ef src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java Mon Nov 25 15:16:29 2019 +0000 +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java Tue Nov 26 10:22:13 2019 +0000 @@ -203,6 +203,8 @@ * Call to invoke event tagging and retransformation of the passed classes * * @param classes + * + * @throws IllegalStateException if wrong JVMTI phase. */ public native synchronized void retransformClasses(Class[] classes); diff -r aa516a7cf95e -r bfc8074ea4ef src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JDKEvents.java --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JDKEvents.java Mon Nov 25 15:16:29 2019 +0000 +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JDKEvents.java Tue Nov 26 10:22:13 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -123,6 +123,8 @@ list.add(java.lang.Error.class); Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Retransformed JDK classes"); jvm.retransformClasses(list.toArray(new Class[list.size()])); + } catch (IllegalStateException ise) { + throw ise; } catch (Exception e) { Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Could not add instrumentation for JDK events. " + e.getMessage()); } diff -r aa516a7cf95e -r bfc8074ea4ef test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetThreadState/thrstat001/thrstat001.cpp --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetThreadState/thrstat001/thrstat001.cpp Mon Nov 25 15:16:29 2019 +0000 +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetThreadState/thrstat001/thrstat001.cpp Tue Nov 26 10:22:13 2019 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2019, 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 @@ -39,63 +39,72 @@ static jvmtiCapabilities caps; static jvmtiEventCallbacks callbacks; static jrawMonitorID access_lock; +static jrawMonitorID wait_lock; static jint result = PASSED; -static jboolean printdump = JNI_FALSE; static jthread thr_ptr = NULL; + static jint state[] = { JVMTI_THREAD_STATE_RUNNABLE, JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER, JVMTI_THREAD_STATE_IN_OBJECT_WAIT }; -static int entry_count = 0; -static int entry_error_count = 0; -static int exit_count = 0; -static int exit_error_count = 0; +static void +lock(const char* func_name, jrawMonitorID lock) { + jvmtiError err = jvmti->RawMonitorEnter(lock); + if (err != JVMTI_ERROR_NONE) { + printf("%s: unexpected error in RawMonitorEnter: %s (%d)\n", + func_name, TranslateError(err), err); + result = STATUS_FAILED; + } +} -void JNICALL VMInit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thr) { - jvmtiError err; - - err = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, - JVMTI_EVENT_THREAD_START, NULL); +static void +unlock(const char* func_name, jrawMonitorID lock) { + jvmtiError err = jvmti->RawMonitorExit(lock); if (err != JVMTI_ERROR_NONE) { - printf("Failed to enable THREAD_START event: %s (%d)\n", - TranslateError(err), err); + printf("%s: unexpected error in RawMonitorExit: %s (%d)\n", + func_name, TranslateError(err), err); result = STATUS_FAILED; } +} - if (caps.can_generate_method_entry_events) { - err = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, - JVMTI_EVENT_METHOD_ENTRY, NULL); - if (err != JVMTI_ERROR_NONE) { - printf("Failed to enable METHOD_ENTRY event: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } +static void +wait(const char* func_name, jrawMonitorID lock, jint millis) { + jvmtiError err = jvmti->RawMonitorWait(lock, (jlong)millis); + if (err != JVMTI_ERROR_NONE) { + printf("%s: unexpected error in RawMonitorWait: %s (%d)\n", + func_name, TranslateError(err), err); + result = STATUS_FAILED; } +} - if (caps.can_generate_method_exit_events) { - err = jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, - JVMTI_EVENT_METHOD_EXIT, NULL); - if (err != JVMTI_ERROR_NONE) { - printf("Failed to enable METHOD_EXIT event: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } +static void +set_notification_mode(const char* event_name, + jvmtiEventMode mode, + jvmtiEvent event_type, + jthread event_thread) { + const char* action = (mode == JVMTI_ENABLE) ? "enable" : "disable"; + jvmtiError err = jvmti->SetEventNotificationMode(mode, event_type, event_thread); + + if (err != JVMTI_ERROR_NONE) { + printf("Failed to %s %s event: %s (%d)\n", + action, event_name, TranslateError(err), err); + result = STATUS_FAILED; } } +void JNICALL VMInit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thr) { + set_notification_mode("JVMTI_EVENT_THREAD_START", JVMTI_ENABLE, + JVMTI_EVENT_THREAD_START, NULL); +} + void JNICALL ThreadStart(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) { jvmtiError err; jvmtiThreadInfo thrInfo; - err = jvmti_env->RawMonitorEnter(access_lock); - if (err != JVMTI_ERROR_NONE) { - printf("(RawMonitorEnter#TS) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } + lock("ThreadStart", access_lock); err = jvmti_env->GetThreadInfo(thread, &thrInfo); if (err != JVMTI_ERROR_NONE) { @@ -105,111 +114,12 @@ } if (thrInfo.name != NULL && strcmp(thrInfo.name, "thr1") == 0) { thr_ptr = env->NewGlobalRef(thread); - if (printdump == JNI_TRUE) { - printf(">>> ThreadStart: \"%s\", 0x%p\n", thrInfo.name, thr_ptr); - } - } - - err = jvmti_env->RawMonitorExit(access_lock); - if (err != JVMTI_ERROR_NONE) { - printf("(RawMonitorExit#TS) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } -} - -void JNICALL MethodEntry(jvmtiEnv *jvmti_env, JNIEnv *env, - jthread thread, jmethodID mid) { - jvmtiError err; - jvmtiThreadInfo thrInfo; - jint thrState; - - err = jvmti_env->RawMonitorEnter(access_lock); - if (err != JVMTI_ERROR_NONE) { - printf("(RawMonitorEnter#ME) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } - - entry_count++; - err = jvmti_env->GetThreadState(thread, &thrState); - if (err != JVMTI_ERROR_NONE) { - printf("(GetThreadState#ME) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } - if ((thrState & JVMTI_THREAD_STATE_RUNNABLE) == 0) { - if (entry_error_count == 0) { - err = jvmti_env->GetThreadInfo(thread, &thrInfo); - if (err != JVMTI_ERROR_NONE) { - printf("(GetThreadInfo#ME) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } - printf("Wrong thread \"%s\" state on MethodEntry event:\n", - thrInfo.name); - printf(" expected: JVMTI_THREAD_STATE_RUNNABLE\n"); - printf(" got: %s (%d)\n", - TranslateState(thrState), thrState); - } - entry_error_count++; - result = STATUS_FAILED; + printf(">>> ThreadStart: \"%s\", 0x%p\n", thrInfo.name, thr_ptr); + set_notification_mode("JVMTI_EVENT_THREAD_START", JVMTI_DISABLE, + JVMTI_EVENT_THREAD_START, NULL); } - err = jvmti_env->RawMonitorExit(access_lock); - if (err != JVMTI_ERROR_NONE) { - printf("(RawMonitorExit#ME) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } - -} - -void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env, - jthread thread, jmethodID mid, - jboolean was_poped_by_exception, jvalue return_value) { - jvmtiError err; - jvmtiThreadInfo thrInfo; - jint thrState; - - err = jvmti_env->RawMonitorEnter(access_lock); - if (err != JVMTI_ERROR_NONE) { - printf("(RawMonitorEnter#MX) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } - - exit_count++; - err = jvmti_env->GetThreadState(thread, &thrState); - if (err != JVMTI_ERROR_NONE) { - printf("(GetThreadState#MX) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } - if ((thrState & JVMTI_THREAD_STATE_RUNNABLE) == 0) { - if (exit_error_count == 0) { - err = jvmti_env->GetThreadInfo(thread, &thrInfo); - if (err != JVMTI_ERROR_NONE) { - printf("(GetThreadInfo#MX) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } - printf("Wrong thread \"%s\" state on MethodExit event:\n", - thrInfo.name); - printf(" expected: JVMTI_THREAD_STATE_RUNNABLE\n"); - printf(" got: %s (%d)\n", - TranslateState(thrState), thrState); - } - exit_error_count++; - result = STATUS_FAILED; - } - - err = jvmti_env->RawMonitorExit(access_lock); - if (err != JVMTI_ERROR_NONE) { - printf("(RawMonitorExit#MX) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } + unlock("ThreadStart", access_lock); } #ifdef STATIC_BUILD @@ -223,13 +133,12 @@ return JNI_VERSION_1_8; } #endif + jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { jint res; jvmtiError err; - if (options != NULL && strcmp(options, "printdump") == 0) { - printdump = JNI_TRUE; - } + printf("Agent_Initialize started\n"); res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); if (res != JNI_OK || jvmti == NULL) { @@ -260,23 +169,20 @@ err = jvmti->CreateRawMonitor("_access_lock", &access_lock); if (err != JVMTI_ERROR_NONE) { - printf("(CreateRawMonitor) unexpected error: %s (%d)\n", + printf("(CreateRawMonitor)#access_lock unexpected error: %s (%d)\n", + TranslateError(err), err); + return JNI_ERR; + } + + err = jvmti->CreateRawMonitor("_wait_lock", &wait_lock); + if (err != JVMTI_ERROR_NONE) { + printf("(CreateRawMonitor#wait_lock) unexpected error: %s (%d)\n", TranslateError(err), err); return JNI_ERR; } callbacks.VMInit = &VMInit; callbacks.ThreadStart = &ThreadStart; - if (caps.can_generate_method_entry_events) { - callbacks.MethodEntry = &MethodEntry; - } else { - printf("Warning: MethodEntry event is not implemented\n"); - } - if (caps.can_generate_method_exit_events) { - callbacks.MethodExit = &MethodExit; - } else { - printf("Warning: MethodExit event is not implemented\n"); - } err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); if (err != JVMTI_ERROR_NONE) { printf("(SetEventCallbacks) unexpected error: %s (%d)\n", @@ -284,14 +190,10 @@ return JNI_ERR; } - err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, - JVMTI_EVENT_VM_INIT, NULL); - if (err != JVMTI_ERROR_NONE) { - printf("Failed to enable VM_INIT event: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } + set_notification_mode("JVMTI_EVENT_VM_INIT", JVMTI_ENABLE, + JVMTI_EVENT_VM_INIT, NULL); + printf("Agent_Initialize finished\n\n"); return JNI_OK; } @@ -299,10 +201,10 @@ Java_nsk_jvmti_GetThreadState_thrstat001_checkStatus(JNIEnv *env, jclass cls, jint statInd) { jvmtiError err; - jrawMonitorID wait_lock; jint thrState; jint millis; + printf("native method checkStatus started\n"); if (jvmti == NULL) { printf("JVMTI client was not properly loaded!\n"); result = STATUS_FAILED; @@ -316,12 +218,6 @@ } /* wait until thread gets an expected state */ - err = jvmti->CreateRawMonitor("_wait_lock", &wait_lock); - if (err != JVMTI_ERROR_NONE) { - printf("(CreateRawMonitor) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } for (millis = WAIT_START; millis < WAIT_TIME; millis <<= 1) { err = jvmti->GetThreadState(thr_ptr, &thrState); if (err != JVMTI_ERROR_NONE) { @@ -332,36 +228,13 @@ if ((thrState & state[statInd]) != 0) { break; } - err = jvmti->RawMonitorEnter(wait_lock); - if (err != JVMTI_ERROR_NONE) { - printf("(RawMonitorEnter) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } - err = jvmti->RawMonitorWait(wait_lock, (jlong)millis); - if (err != JVMTI_ERROR_NONE) { - printf("(RawMonitorWait) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } - err = jvmti->RawMonitorExit(wait_lock); - if (err != JVMTI_ERROR_NONE) { - printf("(RawMonitorExit) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } - } - err = jvmti->DestroyRawMonitor(wait_lock); - if (err != JVMTI_ERROR_NONE) { - printf("(DestroyRawMonitor) unexpected error: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; + lock("checkStatus", wait_lock); + wait("checkStatus", wait_lock, millis); + unlock("checkStatus", wait_lock); } - if (printdump == JNI_TRUE) { - printf(">>> thread \"thr1\" (0x%p) state: %s (%d)\n", + printf(">>> thread \"thr1\" (0x%p) state: %s (%d)\n", thr_ptr, TranslateState(thrState), thrState); - } if ((thrState & state[statInd]) == 0) { printf("Wrong thread \"thr1\" (0x%p) state:\n", thr_ptr); @@ -371,55 +244,12 @@ TranslateState(thrState), thrState); result = STATUS_FAILED; } + printf("native method checkStatus finished\n\n"); } JNIEXPORT jint JNICALL Java_nsk_jvmti_GetThreadState_thrstat001_getRes(JNIEnv *env, jclass cls) { - jvmtiError err; - - err = jvmti->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_THREAD_START, NULL); - if (err != JVMTI_ERROR_NONE) { - printf("Failed to disable THREAD_START event: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } - - if (caps.can_generate_method_entry_events) { - err = jvmti->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_METHOD_ENTRY, NULL); - if (err != JVMTI_ERROR_NONE) { - printf("Failed to disable METHOD_ENTRY event: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } - } - - if (caps.can_generate_method_exit_events) { - err = jvmti->SetEventNotificationMode(JVMTI_DISABLE, - JVMTI_EVENT_METHOD_EXIT, NULL); - if (err != JVMTI_ERROR_NONE) { - printf("Failed to disable METHOD_EXIT event: %s (%d)\n", - TranslateError(err), err); - result = STATUS_FAILED; - } - } - - if (printdump == JNI_TRUE) { - printf(">>> total number of method entry events = %d\n", entry_count); - printf(">>> total number of method exit events = %d\n", exit_count); - } - - if (entry_error_count != 0) { - printf("Total number of errors on METHOD_ENTRY: %d of %d events\n", - entry_error_count, entry_count); - } - - if (exit_error_count != 0) { - printf("Total number of errors on METHOD_EXIT: %d of %d events\n", - exit_error_count, exit_count); - } - + printf("native method getRes: result: %d\n\n", result); return result; } diff -r aa516a7cf95e -r bfc8074ea4ef test/langtools/tools/javac/lambda/methodReference/ProtectedInaccessibleMethodRefTest2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/javac/lambda/methodReference/ProtectedInaccessibleMethodRefTest2.java Tue Nov 26 10:22:13 2019 +0000 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019, 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 + * @bug 8234729 + * @summary Javac should eagerly change code generation for method references to avert IllegalAccessError in future. + * @run main ProtectedInaccessibleMethodRefTest2 + */ + +import pack.I; +import pack.J; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.function.Function; +import java.lang.reflect.Method; +import java.util.concurrent.Callable; + +public final class ProtectedInaccessibleMethodRefTest2 extends I { + + public static void main(String... args) { + ProtectedInaccessibleMethodRefTest2 m = new ProtectedInaccessibleMethodRefTest2(); + m.test(Paths.get("test")); + // Verify that the method reference has been folded into a lambda. + boolean lambdaFound = false; + for (Method meth : ProtectedInaccessibleMethodRefTest2.class.getDeclaredMethods()) { + if (meth.getName().equals("lambda$test$0")) { + lambdaFound = true; + break; + } + } + if (!lambdaFound) { + throw new AssertionError("Did not find evidence of new code generation"); + } + } + + void test(Path outputDir) { + Sub c = new Sub(this::readFile); + c.check(outputDir); + } + public class Sub extends J { + Sub(Function fileReader) { + super(fileReader); + } + } +} diff -r aa516a7cf95e -r bfc8074ea4ef test/langtools/tools/javac/lambda/methodReference/pack/I.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/javac/lambda/methodReference/pack/I.java Tue Nov 26 10:22:13 2019 +0000 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019, 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 pack; + +import java.nio.file.Path; + +public class I { + protected String readFile(Path file) { + return file.toString(); + } +} diff -r aa516a7cf95e -r bfc8074ea4ef test/langtools/tools/javac/lambda/methodReference/pack/J.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/javac/lambda/methodReference/pack/J.java Tue Nov 26 10:22:13 2019 +0000 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019, 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 pack; + +import java.nio.file.Path; +import java.util.function.Function; + +public class J { + protected final Function fileReader; + + public J(Function fileReader) { + this.fileReader = fileReader; + } + + protected void checkFile(Path file) { + fileReader.apply(file); + } + + public void check(Path file) { + checkFile(file); + } +}