Merge "Remove breakpoints from redefined classes"
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h
index e5d34e1..86af6d4 100644
--- a/runtime/jdwp/jdwp.h
+++ b/runtime/jdwp/jdwp.h
@@ -22,6 +22,7 @@
#include "jdwp/jdwp_bits.h"
#include "jdwp/jdwp_constants.h"
#include "jdwp/jdwp_expand_buf.h"
+#include "obj_ptr.h"
#include <pthread.h>
#include <stddef.h>
@@ -286,6 +287,10 @@
REQUIRES(!event_list_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
+ void UnregisterLocationEventsOnClass(ObjPtr<mirror::Class> klass)
+ REQUIRES(!event_list_lock_)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
/*
* Unregister all events.
*/
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index 172f52a..96249f9 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -251,6 +251,43 @@
return ERR_NONE;
}
+void JdwpState::UnregisterLocationEventsOnClass(ObjPtr<mirror::Class> klass) {
+ VLOG(jdwp) << "Removing events within " << klass->PrettyClass();
+ StackHandleScope<1> hs(Thread::Current());
+ Handle<mirror::Class> h_klass(hs.NewHandle(klass));
+ std::vector<JdwpEvent*> to_remove;
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ for (JdwpEvent* cur_event = event_list_; cur_event != nullptr; cur_event = cur_event->next) {
+ // Fill in the to_remove list
+ bool found_event = false;
+ for (int i = 0; i < cur_event->modCount && !found_event; i++) {
+ JdwpEventMod& mod = cur_event->mods[i];
+ switch (mod.modKind) {
+ case MK_LOCATION_ONLY: {
+ JdwpLocation& loc = mod.locationOnly.loc;
+ JdwpError error;
+ ObjPtr<mirror::Class> breakpoint_class(
+ Dbg::GetObjectRegistry()->Get<art::mirror::Class*>(loc.class_id, &error));
+ DCHECK_EQ(error, ERR_NONE);
+ if (breakpoint_class == h_klass.Get()) {
+ to_remove.push_back(cur_event);
+ found_event = true;
+ }
+ break;
+ }
+ default:
+ // TODO Investigate how we should handle non-locationOnly events.
+ break;
+ }
+ }
+ }
+
+ for (JdwpEvent* event : to_remove) {
+ UnregisterEvent(event);
+ EventFree(event);
+ }
+}
+
/*
* Remove an event from the list. This will also remove the event from
* any optimization tables, e.g. breakpoints.
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index c35419c..5e6a23f 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -38,12 +38,17 @@
#include "art_jvmti.h"
#include "base/array_slice.h"
#include "base/logging.h"
+#include "debugger.h"
#include "dex_file.h"
#include "dex_file_types.h"
#include "events-inl.h"
#include "gc/allocation_listener.h"
#include "gc/heap.h"
#include "instrumentation.h"
+#include "jdwp/jdwp.h"
+#include "jdwp/jdwp_constants.h"
+#include "jdwp/jdwp_event.h"
+#include "jdwp/object_registry.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
#include "jni_env_ext-inl.h"
@@ -971,6 +976,23 @@
return true;
}
+void Redefiner::ClassRedefinition::UnregisterBreakpoints() {
+ DCHECK(art::Dbg::IsDebuggerActive());
+ art::JDWP::JdwpState* state = art::Dbg::GetJdwpState();
+ if (state != nullptr) {
+ state->UnregisterLocationEventsOnClass(GetMirrorClass());
+ }
+}
+
+void Redefiner::UnregisterAllBreakpoints() {
+ if (LIKELY(!art::Dbg::IsDebuggerActive())) {
+ return;
+ }
+ for (Redefiner::ClassRedefinition& redef : redefinitions_) {
+ redef.UnregisterBreakpoints();
+ }
+}
+
bool Redefiner::CheckAllRedefinitionAreValid() {
for (Redefiner::ClassRedefinition& redef : redefinitions_) {
if (!redef.CheckRedefinitionIsValid()) {
@@ -1049,6 +1071,7 @@
// cleaned up by the GC eventually.
return result_;
}
+ // At this point we can no longer fail without corrupting the runtime state.
int32_t counter = 0;
for (Redefiner::ClassRedefinition& redef : redefinitions_) {
if (holder.GetSourceClassLoader(counter) == nullptr) {
@@ -1056,6 +1079,7 @@
}
counter++;
}
+ UnregisterAllBreakpoints();
// Disable GC and wait for it to be done if we are a moving GC. This is fine since we are done
// allocating so no deadlocks.
art::gc::Heap* heap = runtime_->GetHeap();
@@ -1088,9 +1112,7 @@
holder.GetOriginalDexFileBytes(counter));
counter++;
}
- // TODO Verify the new Class.
// TODO Shrink the obsolete method maps if possible?
- // TODO find appropriate class loader.
// TODO Put this into a scoped thing.
runtime_->GetThreadList()->ResumeAll();
// Get back shared mutator lock as expected for return.
diff --git a/runtime/openjdkjvmti/ti_redefine.h b/runtime/openjdkjvmti/ti_redefine.h
index 421d22e..c441377 100644
--- a/runtime/openjdkjvmti/ti_redefine.h
+++ b/runtime/openjdkjvmti/ti_redefine.h
@@ -207,6 +207,8 @@
void ReleaseDexFile() REQUIRES_SHARED(art::Locks::mutator_lock_);
+ void UnregisterBreakpoints() REQUIRES_SHARED(art::Locks::mutator_lock_);
+
private:
Redefiner* driver_;
jclass klass_;
@@ -250,6 +252,7 @@
bool FinishAllRemainingAllocations(RedefinitionDataHolder& holder)
REQUIRES_SHARED(art::Locks::mutator_lock_);
void ReleaseAllDexFiles() REQUIRES_SHARED(art::Locks::mutator_lock_);
+ void UnregisterAllBreakpoints() REQUIRES_SHARED(art::Locks::mutator_lock_);
void RecordFailure(jvmtiError result, const std::string& class_sig, const std::string& error_msg);
void RecordFailure(jvmtiError result, const std::string& error_msg) {