diff options
Diffstat (limited to 'openjdkjvmti')
| -rw-r--r-- | openjdkjvmti/deopt_manager.cc | 3 | ||||
| -rw-r--r-- | openjdkjvmti/events.cc | 100 | ||||
| -rw-r--r-- | openjdkjvmti/events.h | 2 |
3 files changed, 101 insertions, 4 deletions
diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc index 8bac38a355..d456d83368 100644 --- a/openjdkjvmti/deopt_manager.cc +++ b/openjdkjvmti/deopt_manager.cc @@ -139,6 +139,9 @@ void DeoptManager::FinishSetup() { // OnLoad since the runtime hasn't started up sufficiently. This is only expected to happen // on userdebug/eng builds. LOG(INFO) << "Attempting to start jit for openjdkjvmti plugin."; + // Note: use rwx allowed = true, because if this is the system server, we will not be + // allowed to allocate any JIT code cache, anyways. + runtime->CreateJitCodeCache(/*rwx_memory_allowed=*/true); runtime->CreateJit(); if (runtime->GetJit() == nullptr) { LOG(WARNING) << "Could not start jit for openjdkjvmti plugin. This process might be " diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc index 48df53a143..a96436e95a 100644 --- a/openjdkjvmti/events.cc +++ b/openjdkjvmti/events.cc @@ -32,6 +32,7 @@ #include "events-inl.h" #include <array> +#include <sys/time.h> #include "art_field-inl.h" #include "art_jvmti.h" @@ -56,6 +57,7 @@ #include "thread-inl.h" #include "thread_list.h" #include "ti_phase.h" +#include "well_known_classes.h" namespace openjdkjvmti { @@ -410,14 +412,103 @@ class JvmtiMonitorListener : public art::MonitorCallback { EventHandler* handler_; }; -static void SetupMonitorListener(art::MonitorCallback* listener, bool enable) { +class JvmtiParkListener : public art::ParkCallback { + public: + explicit JvmtiParkListener(EventHandler* handler) : handler_(handler) {} + + void ThreadParkStart(bool is_absolute, int64_t timeout) + override REQUIRES_SHARED(art::Locks::mutator_lock_) { + if (handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kMonitorWait)) { + art::Thread* self = art::Thread::Current(); + art::JNIEnvExt* jnienv = self->GetJniEnv(); + art::ArtField* parkBlockerField = art::jni::DecodeArtField( + art::WellKnownClasses::java_lang_Thread_parkBlocker); + art::ObjPtr<art::mirror::Object> blocker_obj = parkBlockerField->GetObj(self->GetPeer()); + if (blocker_obj.IsNull()) { + blocker_obj = self->GetPeer(); + } + int64_t timeout_ms; + if (!is_absolute) { + if (timeout == 0) { + timeout_ms = 0; + } else { + timeout_ms = timeout / 1000000; + if (timeout_ms == 0) { + // If we were instructed to park for a nonzero number of nanoseconds, but not enough + // to be a full millisecond, round up to 1 ms. A nonzero park() call will return + // soon, but a 0 wait or park call will wait indefinitely. + timeout_ms = 1; + } + } + } else { + struct timeval tv; + gettimeofday(&tv, (struct timezone *) nullptr); + int64_t now = tv.tv_sec * 1000LL + tv.tv_usec / 1000; + if (now < timeout) { + timeout_ms = timeout - now; + } else { + // Waiting for 0 ms is an indefinite wait; parking until a time in + // the past or the current time will return immediately, so emulate + // the shortest possible wait event. + timeout_ms = 1; + } + } + ScopedLocalRef<jobject> blocker(jnienv, AddLocalRef<jobject>(jnienv, blocker_obj.Ptr())); + RunEventCallback<ArtJvmtiEvent::kMonitorWait>( + handler_, + self, + jnienv, + blocker.get(), + static_cast<jlong>(timeout_ms)); + } + } + + + // Our interpretation of the spec is that the JVMTI_EVENT_MONITOR_WAITED will be sent immediately + // after a thread has woken up from a sleep caused by a call to Object#wait. If the thread will + // never go to sleep (due to not having the lock, having bad arguments, or having an exception + // propogated from JVMTI_EVENT_MONITOR_WAIT) we will not send this event. + // + // This does not fully match the RI semantics. Specifically, we will not send the + // JVMTI_EVENT_MONITOR_WAITED event in one situation where the RI would, there was an exception in + // the JVMTI_EVENT_MONITOR_WAIT event but otherwise the call was fine. In that case the RI would + // send this event and return without going to sleep. + // + // See b/65558434 for more discussion. + void ThreadParkFinished(bool timeout) override REQUIRES_SHARED(art::Locks::mutator_lock_) { + if (handler_->IsEventEnabledAnywhere(ArtJvmtiEvent::kMonitorWaited)) { + art::Thread* self = art::Thread::Current(); + art::JNIEnvExt* jnienv = self->GetJniEnv(); + art::ArtField* parkBlockerField = art::jni::DecodeArtField( + art::WellKnownClasses::java_lang_Thread_parkBlocker); + art::ObjPtr<art::mirror::Object> blocker_obj = parkBlockerField->GetObj(self->GetPeer()); + if (blocker_obj.IsNull()) { + blocker_obj = self->GetPeer(); + } + ScopedLocalRef<jobject> blocker(jnienv, AddLocalRef<jobject>(jnienv, blocker_obj.Ptr())); + RunEventCallback<ArtJvmtiEvent::kMonitorWaited>( + handler_, + self, + jnienv, + blocker.get(), + static_cast<jboolean>(timeout)); + } + } + + private: + EventHandler* handler_; +}; + +static void SetupMonitorListener(art::MonitorCallback* monitor_listener, art::ParkCallback* park_listener, bool enable) { // We must not hold the mutator lock here, but if we're in FastJNI, for example, we might. For // now, do a workaround: (possibly) acquire and release. art::ScopedObjectAccess soa(art::Thread::Current()); if (enable) { - art::Runtime::Current()->GetRuntimeCallbacks()->AddMonitorCallback(listener); + art::Runtime::Current()->GetRuntimeCallbacks()->AddMonitorCallback(monitor_listener); + art::Runtime::Current()->GetRuntimeCallbacks()->AddParkCallback(park_listener); } else { - art::Runtime::Current()->GetRuntimeCallbacks()->RemoveMonitorCallback(listener); + art::Runtime::Current()->GetRuntimeCallbacks()->RemoveMonitorCallback(monitor_listener); + art::Runtime::Current()->GetRuntimeCallbacks()->RemoveParkCallback(park_listener); } } @@ -1053,7 +1144,7 @@ void EventHandler::HandleEventType(ArtJvmtiEvent event, bool enable) { case ArtJvmtiEvent::kMonitorWait: case ArtJvmtiEvent::kMonitorWaited: if (!OtherMonitorEventsEnabledAnywhere(event)) { - SetupMonitorListener(monitor_listener_.get(), enable); + SetupMonitorListener(monitor_listener_.get(), park_listener_.get(), enable); } return; default: @@ -1204,6 +1295,7 @@ EventHandler::EventHandler() gc_pause_listener_.reset(new JvmtiGcPauseListener(this)); method_trace_listener_.reset(new JvmtiMethodTraceListener(this)); monitor_listener_.reset(new JvmtiMonitorListener(this)); + park_listener_.reset(new JvmtiParkListener(this)); } EventHandler::~EventHandler() { diff --git a/openjdkjvmti/events.h b/openjdkjvmti/events.h index 9f91a08b8b..abb15cc329 100644 --- a/openjdkjvmti/events.h +++ b/openjdkjvmti/events.h @@ -35,6 +35,7 @@ class JvmtiDdmChunkListener; class JvmtiGcPauseListener; class JvmtiMethodTraceListener; class JvmtiMonitorListener; +class JvmtiParkListener; // an enum for ArtEvents. This differs from the JVMTI events only in that we distinguish between // retransformation capable and incapable loading @@ -331,6 +332,7 @@ class EventHandler { std::unique_ptr<JvmtiGcPauseListener> gc_pause_listener_; std::unique_ptr<JvmtiMethodTraceListener> method_trace_listener_; std::unique_ptr<JvmtiMonitorListener> monitor_listener_; + std::unique_ptr<JvmtiParkListener> park_listener_; // True if frame pop has ever been enabled. Since we store pointers to stack frames we need to // continue to listen to this event even if it has been disabled. |