Correctly perform read-barriers on cross-thread reg access
For debug workloads we will sometimes read stack registers on other
threads. This generally only happens when the target thread is
suspended due to a running GC and the debugger thread tries to access
stack registers from a compiled method. This could lead to a missed
read-barrier and a From-Space reference being returned. To fix this we
manually perform a read-barrier after pulling the reference out of the
compiled stack.
Test: ./test.py --host
Test: ./art/tools/run-libjdwp-tests.sh --mode=host
Test: ./test.py --host --all-compiler --all-gc -t 1966
Bug: 141590021
Change-Id: I5540c03bfdaecddbc1329ff6c7c58c6f18d6a090
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 6d1e384..2a07051 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -15,6 +15,7 @@
*/
#include "stack.h"
+#include <limits>
#include "android-base/stringprintf.h"
@@ -224,7 +225,15 @@
DCHECK_EQ(*val, val2);
return ok;
}
- return GetVRegFromOptimizedCode(m, vreg, kind, val);
+ bool res = GetVRegFromOptimizedCode(m, vreg, kind, val);
+ if (kind == kReferenceVReg) {
+ // Perform a read barrier in case we are in a different thread and GC is ongoing.
+ mirror::Object* out = reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(*val));
+ uintptr_t ptr_out = reinterpret_cast<uintptr_t>(GcRoot<mirror::Object>(out).Read());
+ DCHECK_LT(ptr_out, std::numeric_limits<uint32_t>::max());
+ *val = static_cast<uint32_t>(ptr_out);
+ }
+ return res;
} else {
DCHECK(cur_shadow_frame_ != nullptr);
if (kind == kReferenceVReg) {