blob: 5c962c3b26f20757d59928988017e785beec3e0e [file] [log] [blame]
Andreas Gampe93104952017-12-13 17:13:15 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_MONITOR_OBJECTS_STACK_VISITOR_H_
18#define ART_RUNTIME_MONITOR_OBJECTS_STACK_VISITOR_H_
19
20#include <android-base/logging.h>
21
22#include "art_method.h"
23#include "base/mutex.h"
24#include "monitor.h"
25#include "stack.h"
26#include "thread.h"
27#include "thread_state.h"
28
29namespace art {
30
31namespace mirror {
32class Object;
33}
34
35class Context;
36
37class MonitorObjectsStackVisitor : public StackVisitor {
38 public:
39 MonitorObjectsStackVisitor(Thread* thread_in,
40 Context* context,
41 bool check_suspended = true,
42 bool dump_locks_in = true)
43 REQUIRES_SHARED(Locks::mutator_lock_)
44 : StackVisitor(thread_in,
45 context,
46 StackVisitor::StackWalkKind::kIncludeInlinedFrames,
47 check_suspended),
48 frame_count(0u),
49 dump_locks(dump_locks_in) {}
50
51 enum class VisitMethodResult {
52 kContinueMethod,
53 kSkipMethod,
54 kEndStackWalk,
55 };
56
57 bool VisitFrame() FINAL REQUIRES_SHARED(Locks::mutator_lock_) {
58 ArtMethod* m = GetMethod();
59 if (m->IsRuntimeMethod()) {
60 return true;
61 }
62
63 VisitMethodResult vmrEntry = StartMethod(m, frame_count);
64 switch (vmrEntry) {
65 case VisitMethodResult::kContinueMethod:
66 break;
67 case VisitMethodResult::kSkipMethod:
68 return true;
69 case VisitMethodResult::kEndStackWalk:
70 return false;
71 }
72
73 if (frame_count == 0) {
74 // Top frame, check for blocked state.
75
76 mirror::Object* monitor_object;
77 uint32_t lock_owner_tid;
78 ThreadState state = Monitor::FetchState(GetThread(),
79 &monitor_object,
80 &lock_owner_tid);
81 switch (state) {
82 case kWaiting:
83 case kTimedWaiting:
84 VisitWaitingObject(monitor_object, state);
85 break;
86 case kSleeping:
87 VisitSleepingObject(monitor_object);
88 break;
89
90 case kBlocked:
91 case kWaitingForLockInflation:
92 VisitBlockedOnObject(monitor_object, state, lock_owner_tid);
93 break;
94
95 default:
96 break;
97 }
98 }
99
100 if (dump_locks) {
101 // Visit locks, but do not abort on errors. This could trigger a nested abort.
102 // Skip visiting locks if dump_locks is false as it would cause a bad_mutexes_held in
103 // RegTypeCache::RegTypeCache due to thread_list_lock.
104 Monitor::VisitLocks(this, VisitLockedObject, this, false);
105 }
106
107 ++frame_count;
108
109 VisitMethodResult vmrExit = EndMethod(m);
110 switch (vmrExit) {
111 case VisitMethodResult::kContinueMethod:
112 case VisitMethodResult::kSkipMethod:
113 return true;
114
115 case VisitMethodResult::kEndStackWalk:
116 return false;
117 }
118 LOG(FATAL) << "Unreachable";
119 UNREACHABLE();
120 }
121
122 protected:
123 virtual VisitMethodResult StartMethod(ArtMethod* m, size_t frame_nr)
124 REQUIRES_SHARED(Locks::mutator_lock_) = 0;
125 virtual VisitMethodResult EndMethod(ArtMethod* m)
126 REQUIRES_SHARED(Locks::mutator_lock_) = 0;
127
128 virtual void VisitWaitingObject(mirror::Object* obj, ThreadState state)
129 REQUIRES_SHARED(Locks::mutator_lock_) = 0;
130 virtual void VisitSleepingObject(mirror::Object* obj)
131 REQUIRES_SHARED(Locks::mutator_lock_) = 0;
132 virtual void VisitBlockedOnObject(mirror::Object* obj, ThreadState state, uint32_t owner_tid)
133 REQUIRES_SHARED(Locks::mutator_lock_) = 0;
134 virtual void VisitLockedObject(mirror::Object* obj)
135 REQUIRES_SHARED(Locks::mutator_lock_) = 0;
136
137 size_t frame_count;
138
139 private:
140 static void VisitLockedObject(mirror::Object* o, void* context)
141 REQUIRES_SHARED(Locks::mutator_lock_) {
142 MonitorObjectsStackVisitor* self = reinterpret_cast<MonitorObjectsStackVisitor*>(context);
143 if (o != nullptr) {
144 if (kUseReadBarrier && Thread::Current()->GetIsGcMarking()) {
145 // We may call Thread::Dump() in the middle of the CC thread flip and this thread's stack
146 // may have not been flipped yet and "o" may be a from-space (stale) ref, in which case the
147 // IdentityHashCode call below will crash. So explicitly mark/forward it here.
148 o = ReadBarrier::Mark(o);
149 }
150 }
151 self->VisitLockedObject(o);
152 }
153
154 const bool dump_locks;
155};
156
157} // namespace art
158
159#endif // ART_RUNTIME_MONITOR_OBJECTS_STACK_VISITOR_H_