| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "monitor_objects_stack_visitor.h" |
| |
| #include "obj_ptr-inl.h" |
| #include "read_barrier-inl.h" |
| #include "thread-current-inl.h" |
| |
| namespace art { |
| |
| bool MonitorObjectsStackVisitor::VisitFrame() { |
| ArtMethod* m = GetMethod(); |
| if (m->IsRuntimeMethod()) { |
| return true; |
| } |
| |
| VisitMethodResult vmrEntry = StartMethod(m, frame_count); |
| switch (vmrEntry) { |
| case VisitMethodResult::kContinueMethod: |
| break; |
| case VisitMethodResult::kSkipMethod: |
| return true; |
| case VisitMethodResult::kEndStackWalk: |
| return false; |
| } |
| |
| if (frame_count == 0) { |
| // Top frame, check for blocked state. |
| |
| ObjPtr<mirror::Object> monitor_object; |
| uint32_t lock_owner_tid; |
| ThreadState state = Monitor::FetchState(GetThread(), |
| &monitor_object, |
| &lock_owner_tid); |
| switch (state) { |
| case ThreadState::kWaiting: |
| case ThreadState::kTimedWaiting: |
| VisitWaitingObject(monitor_object, state); |
| break; |
| case ThreadState::kSleeping: |
| VisitSleepingObject(monitor_object); |
| break; |
| |
| case ThreadState::kBlocked: |
| case ThreadState::kWaitingForLockInflation: |
| VisitBlockedOnObject(monitor_object, state, lock_owner_tid); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| if (dump_locks) { |
| // Visit locks, but do not abort on errors. This could trigger a nested abort. |
| // Skip visiting locks if dump_locks is false as it would cause a bad_mutexes_held in |
| // RegTypeCache::RegTypeCache due to thread_list_lock. |
| Monitor::VisitLocks(this, VisitLockedObject, this, false); |
| } |
| |
| ++frame_count; |
| |
| VisitMethodResult vmrExit = EndMethod(m); |
| switch (vmrExit) { |
| case VisitMethodResult::kContinueMethod: |
| case VisitMethodResult::kSkipMethod: |
| return true; |
| |
| case VisitMethodResult::kEndStackWalk: |
| return false; |
| } |
| LOG(FATAL) << "Unreachable"; |
| UNREACHABLE(); |
| } |
| |
| void MonitorObjectsStackVisitor::VisitLockedObject(ObjPtr<mirror::Object> o, void* context) { |
| MonitorObjectsStackVisitor* self = reinterpret_cast<MonitorObjectsStackVisitor*>(context); |
| if (o != nullptr) { |
| if (gUseReadBarrier && Thread::Current()->GetIsGcMarking()) { |
| // We may call Thread::Dump() in the middle of the CC thread flip and this thread's stack |
| // may have not been flipped yet and "o" may be a from-space (stale) ref, in which case the |
| // IdentityHashCode call below will crash. So explicitly mark/forward it here. |
| o = ReadBarrier::Mark(o.Ptr()); |
| } |
| } |
| self->VisitLockedObject(o); |
| } |
| |
| } // namespace art |