diff options
Diffstat (limited to 'openjdkjvmti/jvmti_weak_table.h')
-rw-r--r-- | openjdkjvmti/jvmti_weak_table.h | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/openjdkjvmti/jvmti_weak_table.h b/openjdkjvmti/jvmti_weak_table.h new file mode 100644 index 0000000000..5a821c964b --- /dev/null +++ b/openjdkjvmti/jvmti_weak_table.h @@ -0,0 +1,227 @@ +/* Copyright (C) 2017 The Android Open Source Project + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This file implements interfaces from the file jvmti.h. This implementation + * is licensed under the same terms as the file jvmti.h. The + * copyright and license information for the file jvmti.h follows. + * + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_H_ +#define ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_H_ + +#include <unordered_map> + +#include "base/macros.h" +#include "base/mutex.h" +#include "gc/system_weak.h" +#include "gc_root-inl.h" +#include "globals.h" +#include "jvmti.h" +#include "jvmti_allocator.h" +#include "mirror/object.h" +#include "thread-current-inl.h" + +namespace openjdkjvmti { + +class EventHandler; + +// A system-weak container mapping objects to elements of the template type. This corresponds +// to a weak hash map. For historical reasons the stored value is called "tag." +template <typename T> +class JvmtiWeakTable : public art::gc::SystemWeakHolder { + public: + JvmtiWeakTable() + : art::gc::SystemWeakHolder(art::kTaggingLockLevel), + update_since_last_sweep_(false) { + } + + // Remove the mapping for the given object, returning whether such a mapping existed (and the old + // value). + ALWAYS_INLINE bool Remove(art::mirror::Object* obj, /* out */ T* tag) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(!allow_disallow_lock_); + ALWAYS_INLINE bool RemoveLocked(art::mirror::Object* obj, /* out */ T* tag) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(allow_disallow_lock_); + + // Set the mapping for the given object. Returns true if this overwrites an already existing + // mapping. + ALWAYS_INLINE virtual bool Set(art::mirror::Object* obj, T tag) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(!allow_disallow_lock_); + ALWAYS_INLINE virtual bool SetLocked(art::mirror::Object* obj, T tag) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(allow_disallow_lock_); + + // Return the value associated with the given object. Returns true if the mapping exists, false + // otherwise. + bool GetTag(art::mirror::Object* obj, /* out */ T* result) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(!allow_disallow_lock_) { + art::Thread* self = art::Thread::Current(); + art::MutexLock mu(self, allow_disallow_lock_); + Wait(self); + + return GetTagLocked(self, obj, result); + } + bool GetTagLocked(art::mirror::Object* obj, /* out */ T* result) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(allow_disallow_lock_) { + art::Thread* self = art::Thread::Current(); + allow_disallow_lock_.AssertHeld(self); + Wait(self); + + return GetTagLocked(self, obj, result); + } + + // Sweep the container. DO NOT CALL MANUALLY. + ALWAYS_INLINE void Sweep(art::IsMarkedVisitor* visitor) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(!allow_disallow_lock_); + + // Return all objects that have a value mapping in tags. + ALWAYS_INLINE + jvmtiError GetTaggedObjects(jvmtiEnv* jvmti_env, + jint tag_count, + const T* tags, + /* out */ jint* count_ptr, + /* out */ jobject** object_result_ptr, + /* out */ T** tag_result_ptr) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(!allow_disallow_lock_); + + // Locking functions, to allow coarse-grained locking and amortization. + ALWAYS_INLINE void Lock() ACQUIRE(allow_disallow_lock_); + ALWAYS_INLINE void Unlock() RELEASE(allow_disallow_lock_); + ALWAYS_INLINE void AssertLocked() ASSERT_CAPABILITY(allow_disallow_lock_); + + ALWAYS_INLINE art::mirror::Object* Find(T tag) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(!allow_disallow_lock_); + + protected: + // Should HandleNullSweep be called when Sweep detects the release of an object? + virtual bool DoesHandleNullOnSweep() { + return false; + } + // If DoesHandleNullOnSweep returns true, this function will be called. + virtual void HandleNullSweep(T tag ATTRIBUTE_UNUSED) {} + + private: + ALWAYS_INLINE + bool SetLocked(art::Thread* self, art::mirror::Object* obj, T tag) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(allow_disallow_lock_); + + ALWAYS_INLINE + bool RemoveLocked(art::Thread* self, art::mirror::Object* obj, /* out */ T* tag) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(allow_disallow_lock_); + + bool GetTagLocked(art::Thread* self, art::mirror::Object* obj, /* out */ T* result) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(allow_disallow_lock_) { + auto it = tagged_objects_.find(art::GcRoot<art::mirror::Object>(obj)); + if (it != tagged_objects_.end()) { + *result = it->second; + return true; + } + + // Performance optimization: To avoid multiple table updates, ensure that during GC we + // only update once. See the comment on the implementation of GetTagSlowPath. + if (art::kUseReadBarrier && + self != nullptr && + self->GetIsGcMarking() && + !update_since_last_sweep_) { + return GetTagSlowPath(self, obj, result); + } + + return false; + } + + // Slow-path for GetTag. We didn't find the object, but we might be storing from-pointers and + // are asked to retrieve with a to-pointer. + ALWAYS_INLINE + bool GetTagSlowPath(art::Thread* self, art::mirror::Object* obj, /* out */ T* result) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(allow_disallow_lock_); + + // Update the table by doing read barriers on each element, ensuring that to-space pointers + // are stored. + ALWAYS_INLINE + void UpdateTableWithReadBarrier() + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(allow_disallow_lock_); + + template <bool kHandleNull> + void SweepImpl(art::IsMarkedVisitor* visitor) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(!allow_disallow_lock_); + + enum TableUpdateNullTarget { + kIgnoreNull, + kRemoveNull, + kCallHandleNull + }; + + template <typename Updater, TableUpdateNullTarget kTargetNull> + void UpdateTableWith(Updater& updater) + REQUIRES_SHARED(art::Locks::mutator_lock_) + REQUIRES(allow_disallow_lock_); + + template <typename Storage, class Allocator = JvmtiAllocator<T>> + struct ReleasableContainer; + + struct HashGcRoot { + size_t operator()(const art::GcRoot<art::mirror::Object>& r) const + REQUIRES_SHARED(art::Locks::mutator_lock_) { + return reinterpret_cast<uintptr_t>(r.Read<art::kWithoutReadBarrier>()); + } + }; + + struct EqGcRoot { + bool operator()(const art::GcRoot<art::mirror::Object>& r1, + const art::GcRoot<art::mirror::Object>& r2) const + REQUIRES_SHARED(art::Locks::mutator_lock_) { + return r1.Read<art::kWithoutReadBarrier>() == r2.Read<art::kWithoutReadBarrier>(); + } + }; + + using TagAllocator = JvmtiAllocator<std::pair<const art::GcRoot<art::mirror::Object>, T>>; + std::unordered_map<art::GcRoot<art::mirror::Object>, + T, + HashGcRoot, + EqGcRoot, + TagAllocator> tagged_objects_ + GUARDED_BY(allow_disallow_lock_) + GUARDED_BY(art::Locks::mutator_lock_); + // To avoid repeatedly scanning the whole table, remember if we did that since the last sweep. + bool update_since_last_sweep_; +}; + +} // namespace openjdkjvmti + +#endif // ART_OPENJDKJVMTI_JVMTI_WEAK_TABLE_H_ |