| /* | 
 |  * Copyright (C) 2011 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 "lock_count_data.h" | 
 |  | 
 | #include <algorithm> | 
 | #include <string> | 
 |  | 
 | #include "android-base/logging.h" | 
 | #include "mirror/object-inl.h" | 
 | #include "thread.h" | 
 |  | 
 | namespace art { | 
 |  | 
 | void LockCountData::AddMonitor(Thread* self, mirror::Object* obj) { | 
 |   if (obj == nullptr) { | 
 |     return; | 
 |   } | 
 |  | 
 |   // If there's an error during enter, we won't have locked the monitor. So check there's no | 
 |   // exception. | 
 |   if (self->IsExceptionPending()) { | 
 |     return; | 
 |   } | 
 |  | 
 |   if (monitors_ == nullptr) { | 
 |     monitors_.reset(new std::vector<mirror::Object*>()); | 
 |   } | 
 |   monitors_->push_back(obj); | 
 | } | 
 |  | 
 | void LockCountData::RemoveMonitorOrThrow(Thread* self, const mirror::Object* obj) { | 
 |   if (obj == nullptr) { | 
 |     return; | 
 |   } | 
 |   bool found_object = false; | 
 |   if (monitors_ != nullptr) { | 
 |     // We need to remove one pointer to ref, as duplicates are used for counting recursive locks. | 
 |     // We arbitrarily choose the first one. | 
 |     auto it = std::find(monitors_->begin(), monitors_->end(), obj); | 
 |     if (it != monitors_->end()) { | 
 |       monitors_->erase(it); | 
 |       found_object = true; | 
 |     } | 
 |   } | 
 |   if (!found_object) { | 
 |     // The object wasn't found. Time for an IllegalMonitorStateException. | 
 |     // The order here isn't fully clear. Assume that any other pending exception is swallowed. | 
 |     // TODO: Maybe make already pending exception a suppressed exception. | 
 |     self->ClearException(); | 
 |     self->ThrowNewExceptionF("Ljava/lang/IllegalMonitorStateException;", | 
 |                              "did not lock monitor on object of type '%s' before unlocking", | 
 |                              const_cast<mirror::Object*>(obj)->PrettyTypeOf().c_str()); | 
 |   } | 
 | } | 
 |  | 
 | // Helper to unlock a monitor. Must be NO_THREAD_SAFETY_ANALYSIS, as we can't statically show | 
 | // that the object was locked. | 
 | void MonitorExitHelper(Thread* self, mirror::Object* obj) NO_THREAD_SAFETY_ANALYSIS { | 
 |   DCHECK(self != nullptr); | 
 |   DCHECK(obj != nullptr); | 
 |   obj->MonitorExit(self); | 
 | } | 
 |  | 
 | bool LockCountData::CheckAllMonitorsReleasedOrThrow(Thread* self) { | 
 |   DCHECK(self != nullptr); | 
 |   if (monitors_ != nullptr) { | 
 |     if (!monitors_->empty()) { | 
 |       // There may be an exception pending, if the method is terminating abruptly. Clear it. | 
 |       // TODO: Should we add this as a suppressed exception? | 
 |       self->ClearException(); | 
 |  | 
 |       // OK, there are monitors that are still locked. To enforce structured locking (and avoid | 
 |       // deadlocks) we unlock all of them before we raise the IllegalMonitorState exception. | 
 |       for (mirror::Object* obj : *monitors_) { | 
 |         MonitorExitHelper(self, obj); | 
 |         // If this raised an exception, ignore. TODO: Should we add this as suppressed | 
 |         // exceptions? | 
 |         if (self->IsExceptionPending()) { | 
 |           self->ClearException(); | 
 |         } | 
 |       } | 
 |       // Raise an exception, just give the first object as the sample. | 
 |       mirror::Object* first = (*monitors_)[0]; | 
 |       self->ThrowNewExceptionF("Ljava/lang/IllegalMonitorStateException;", | 
 |                                "did not unlock monitor on object of type '%s'", | 
 |                                mirror::Object::PrettyTypeOf(first).c_str()); | 
 |  | 
 |       // To make sure this path is not triggered again, clean out the monitors. | 
 |       monitors_->clear(); | 
 |  | 
 |       return false; | 
 |     } | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | }  // namespace art |