summaryrefslogtreecommitdiffstats
path: root/runtime/thread.cc
diff options
context:
space:
mode:
authorMathieu Chartier <mathieuc@google.com>2015-04-03 11:21:55 -0700
committerMathieu Chartier <mathieuc@google.com>2015-04-06 10:44:37 -0700
commitbb87e0f1a52de656bc77cb01cb887e51a0e5198b (patch)
tree113f014c6e20fab3e936a3ac05f9f738639541f6 /runtime/thread.cc
parente57fc0f0260fcb1d08cbb720ec95c04c0f394b91 (diff)
downloadart-bb87e0f1a52de656bc77cb01cb887e51a0e5198b.tar.gz
art-bb87e0f1a52de656bc77cb01cb887e51a0e5198b.tar.bz2
art-bb87e0f1a52de656bc77cb01cb887e51a0e5198b.zip
Refactor and improve GC root handling
Changed GcRoot to use compressed references. Changed root visiting to use virtual functions instead of function pointers. Changed root visting interface to be an array of roots instead of a single root at a time. Added buffered root marking helper to avoid dispatch overhead. Root marking seems a bit faster on EvaluateAndApplyChanges due to batch marking. Pause times unaffected. Mips64 is untested but might work, maybe. Before: MarkConcurrentRoots: Sum: 67.678ms 99% C.I. 2us-664.999us Avg: 161.138us Max: 671us After: MarkConcurrentRoots: Sum: 54.806ms 99% C.I. 2us-499.986us Avg: 136.333us Max: 602us Bug: 19264997 Change-Id: I0a71ebb5928f205b9b3f7945b25db6489d5657ca
Diffstat (limited to 'runtime/thread.cc')
-rw-r--r--runtime/thread.cc128
1 files changed, 64 insertions, 64 deletions
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 8a6422d4e5..79d2b13e8a 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1196,26 +1196,37 @@ void Thread::AssertNoPendingExceptionForNewException(const char* msg) const {
}
}
-static void MonitorExitVisitor(mirror::Object** object, void* arg, const RootInfo& /*root_info*/)
- NO_THREAD_SAFETY_ANALYSIS {
- Thread* self = reinterpret_cast<Thread*>(arg);
- mirror::Object* entered_monitor = *object;
- if (self->HoldsLock(entered_monitor)) {
- LOG(WARNING) << "Calling MonitorExit on object "
- << object << " (" << PrettyTypeOf(entered_monitor) << ")"
- << " left locked by native thread "
- << *Thread::Current() << " which is detaching";
- entered_monitor->MonitorExit(self);
+class MonitorExitVisitor : public SingleRootVisitor {
+ public:
+ explicit MonitorExitVisitor(Thread* self) : self_(self) { }
+
+ // NO_THREAD_SAFETY_ANALYSIS due to MonitorExit.
+ void VisitRoot(mirror::Object* entered_monitor, const RootInfo& info ATTRIBUTE_UNUSED)
+ OVERRIDE NO_THREAD_SAFETY_ANALYSIS {
+ if (self_->HoldsLock(entered_monitor)) {
+ LOG(WARNING) << "Calling MonitorExit on object "
+ << entered_monitor << " (" << PrettyTypeOf(entered_monitor) << ")"
+ << " left locked by native thread "
+ << *Thread::Current() << " which is detaching";
+ entered_monitor->MonitorExit(self_);
+ }
}
-}
+
+ private:
+ Thread* const self_;
+};
void Thread::Destroy() {
Thread* self = this;
DCHECK_EQ(self, Thread::Current());
if (tlsPtr_.jni_env != nullptr) {
- // On thread detach, all monitors entered with JNI MonitorEnter are automatically exited.
- tlsPtr_.jni_env->monitors.VisitRoots(MonitorExitVisitor, self, RootInfo(kRootVMInternal));
+ {
+ ScopedObjectAccess soa(self);
+ MonitorExitVisitor visitor(self);
+ // On thread detach, all monitors entered with JNI MonitorEnter are automatically exited.
+ tlsPtr_.jni_env->monitors.VisitRoots(&visitor, RootInfo(kRootVMInternal));
+ }
// Release locally held global references which releasing may require the mutator lock.
if (tlsPtr_.jpeer != nullptr) {
// If pthread_create fails we don't have a jni env here.
@@ -1373,18 +1384,11 @@ bool Thread::HandleScopeContains(jobject obj) const {
return tlsPtr_.managed_stack.ShadowFramesContain(hs_entry);
}
-void Thread::HandleScopeVisitRoots(RootCallback* visitor, void* arg, uint32_t thread_id) {
+void Thread::HandleScopeVisitRoots(RootVisitor* visitor, uint32_t thread_id) {
+ BufferedRootVisitor<128> buffered_visitor(visitor, RootInfo(kRootNativeStack, thread_id));
for (HandleScope* cur = tlsPtr_.top_handle_scope; cur; cur = cur->GetLink()) {
- size_t num_refs = cur->NumberOfReferences();
- for (size_t j = 0; j < num_refs; ++j) {
- mirror::Object* object = cur->GetReference(j);
- if (object != nullptr) {
- mirror::Object* old_obj = object;
- visitor(&object, arg, RootInfo(kRootNativeStack, thread_id));
- if (old_obj != object) {
- cur->SetReference(j, object);
- }
- }
+ for (size_t j = 0, count = cur->NumberOfReferences(); j < count; ++j) {
+ buffered_visitor.VisitRootIfNonNull(cur->GetHandle(j).GetReference());
}
}
}
@@ -2084,7 +2088,7 @@ bool Thread::HoldsLock(mirror::Object* object) const {
template <typename RootVisitor>
class ReferenceMapVisitor : public StackVisitor {
public:
- ReferenceMapVisitor(Thread* thread, Context* context, const RootVisitor& visitor)
+ ReferenceMapVisitor(Thread* thread, Context* context, RootVisitor& visitor)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
: StackVisitor(thread, context), visitor_(visitor) {}
@@ -2248,55 +2252,50 @@ class ReferenceMapVisitor : public StackVisitor {
}
// Visitor for when we visit a root.
- const RootVisitor& visitor_;
+ RootVisitor& visitor_;
};
class RootCallbackVisitor {
public:
- RootCallbackVisitor(RootCallback* callback, void* arg, uint32_t tid)
- : callback_(callback), arg_(arg), tid_(tid) {}
+ RootCallbackVisitor(RootVisitor* visitor, uint32_t tid) : visitor_(visitor), tid_(tid) {}
- void operator()(mirror::Object** obj, size_t vreg, const StackVisitor* stack_visitor) const {
- callback_(obj, arg_, JavaFrameRootInfo(tid_, stack_visitor, vreg));
+ void operator()(mirror::Object** obj, size_t vreg, const StackVisitor* stack_visitor) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ visitor_->VisitRoot(obj, JavaFrameRootInfo(tid_, stack_visitor, vreg));
}
private:
- RootCallback* const callback_;
- void* const arg_;
+ RootVisitor* const visitor_;
const uint32_t tid_;
};
-void Thread::VisitRoots(RootCallback* visitor, void* arg) {
- uint32_t thread_id = GetThreadId();
- if (tlsPtr_.opeer != nullptr) {
- visitor(&tlsPtr_.opeer, arg, RootInfo(kRootThreadObject, thread_id));
- }
+void Thread::VisitRoots(RootVisitor* visitor) {
+ const uint32_t thread_id = GetThreadId();
+ visitor->VisitRootIfNonNull(&tlsPtr_.opeer, RootInfo(kRootThreadObject, thread_id));
if (tlsPtr_.exception != nullptr && tlsPtr_.exception != GetDeoptimizationException()) {
- visitor(reinterpret_cast<mirror::Object**>(&tlsPtr_.exception), arg,
- RootInfo(kRootNativeStack, thread_id));
- }
- if (tlsPtr_.monitor_enter_object != nullptr) {
- visitor(&tlsPtr_.monitor_enter_object, arg, RootInfo(kRootNativeStack, thread_id));
+ visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&tlsPtr_.exception),
+ RootInfo(kRootNativeStack, thread_id));
}
- tlsPtr_.jni_env->locals.VisitRoots(visitor, arg, RootInfo(kRootJNILocal, thread_id));
- tlsPtr_.jni_env->monitors.VisitRoots(visitor, arg, RootInfo(kRootJNIMonitor, thread_id));
- HandleScopeVisitRoots(visitor, arg, thread_id);
+ visitor->VisitRootIfNonNull(&tlsPtr_.monitor_enter_object, RootInfo(kRootNativeStack, thread_id));
+ tlsPtr_.jni_env->locals.VisitRoots(visitor, RootInfo(kRootJNILocal, thread_id));
+ tlsPtr_.jni_env->monitors.VisitRoots(visitor, RootInfo(kRootJNIMonitor, thread_id));
+ HandleScopeVisitRoots(visitor, thread_id);
if (tlsPtr_.debug_invoke_req != nullptr) {
- tlsPtr_.debug_invoke_req->VisitRoots(visitor, arg, RootInfo(kRootDebugger, thread_id));
+ tlsPtr_.debug_invoke_req->VisitRoots(visitor, RootInfo(kRootDebugger, thread_id));
}
if (tlsPtr_.single_step_control != nullptr) {
- tlsPtr_.single_step_control->VisitRoots(visitor, arg, RootInfo(kRootDebugger, thread_id));
+ tlsPtr_.single_step_control->VisitRoots(visitor, RootInfo(kRootDebugger, thread_id));
}
if (tlsPtr_.deoptimization_shadow_frame != nullptr) {
- RootCallbackVisitor visitorToCallback(visitor, arg, thread_id);
- ReferenceMapVisitor<RootCallbackVisitor> mapper(this, nullptr, visitorToCallback);
+ RootCallbackVisitor visitor_to_callback(visitor, thread_id);
+ ReferenceMapVisitor<RootCallbackVisitor> mapper(this, nullptr, visitor_to_callback);
for (ShadowFrame* shadow_frame = tlsPtr_.deoptimization_shadow_frame; shadow_frame != nullptr;
shadow_frame = shadow_frame->GetLink()) {
mapper.VisitShadowFrame(shadow_frame);
}
}
if (tlsPtr_.shadow_frame_under_construction != nullptr) {
- RootCallbackVisitor visitor_to_callback(visitor, arg, thread_id);
+ RootCallbackVisitor visitor_to_callback(visitor, thread_id);
ReferenceMapVisitor<RootCallbackVisitor> mapper(this, nullptr, visitor_to_callback);
for (ShadowFrame* shadow_frame = tlsPtr_.shadow_frame_under_construction;
shadow_frame != nullptr;
@@ -2305,33 +2304,34 @@ void Thread::VisitRoots(RootCallback* visitor, void* arg) {
}
}
if (tlsPtr_.method_verifier != nullptr) {
- tlsPtr_.method_verifier->VisitRoots(visitor, arg, RootInfo(kRootNativeStack, thread_id));
+ tlsPtr_.method_verifier->VisitRoots(visitor, RootInfo(kRootNativeStack, thread_id));
}
// Visit roots on this thread's stack
Context* context = GetLongJumpContext();
- RootCallbackVisitor visitor_to_callback(visitor, arg, thread_id);
+ RootCallbackVisitor visitor_to_callback(visitor, thread_id);
ReferenceMapVisitor<RootCallbackVisitor> mapper(this, context, visitor_to_callback);
mapper.WalkStack();
ReleaseLongJumpContext(context);
for (instrumentation::InstrumentationStackFrame& frame : *GetInstrumentationStack()) {
- if (frame.this_object_ != nullptr) {
- visitor(&frame.this_object_, arg, RootInfo(kRootVMInternal, thread_id));
- }
- DCHECK(frame.method_ != nullptr);
- visitor(reinterpret_cast<mirror::Object**>(&frame.method_), arg,
- RootInfo(kRootVMInternal, thread_id));
+ visitor->VisitRootIfNonNull(&frame.this_object_, RootInfo(kRootVMInternal, thread_id));
+ visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&frame.method_),
+ RootInfo(kRootVMInternal, thread_id));
}
}
-static void VerifyRoot(mirror::Object** root, void* /*arg*/, const RootInfo& /*root_info*/)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- VerifyObject(*root);
-}
+class VerifyRootVisitor : public SingleRootVisitor {
+ public:
+ void VisitRoot(mirror::Object* root, const RootInfo& info ATTRIBUTE_UNUSED)
+ OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ VerifyObject(root);
+ }
+};
void Thread::VerifyStackImpl() {
+ VerifyRootVisitor visitor;
std::unique_ptr<Context> context(Context::Create());
- RootCallbackVisitor visitorToCallback(VerifyRoot, Runtime::Current()->GetHeap(), GetThreadId());
- ReferenceMapVisitor<RootCallbackVisitor> mapper(this, context.get(), visitorToCallback);
+ RootCallbackVisitor visitor_to_callback(&visitor, GetThreadId());
+ ReferenceMapVisitor<RootCallbackVisitor> mapper(this, context.get(), visitor_to_callback);
mapper.WalkStack();
}