| /* |
| * Copyright (C) 2021 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #pragma once |
| |
| #include "AbstractSlotVisitor.h" |
| #include "Heap.h" |
| #include "WeakInlines.h" |
| #include "WriteBarrier.h" |
| |
| namespace JSC { |
| |
| using ReferrerToken = AbstractSlotVisitor::ReferrerToken; |
| |
| inline ReferrerToken::ReferrerToken(HeapCell* cell) |
| : m_bits(bitwise_cast<uintptr_t>(cell) | HeapCellToken) |
| { |
| } |
| |
| inline ReferrerToken::ReferrerToken(OpaqueRootTag, void* opaqueRoot) |
| : m_bits(bitwise_cast<uintptr_t>(opaqueRoot) | OpaqueRootToken) |
| { |
| ASSERT(opaqueRoot); |
| } |
| |
| inline ReferrerToken::ReferrerToken(RootMarkReason reason) |
| : m_bits((static_cast<uintptr_t>(reason) << tokenTypeShift) | RootMarkReasonToken) |
| { |
| } |
| |
| inline HeapCell* ReferrerToken::asCell() const |
| { |
| return isHeapCell() ? bitwise_cast<HeapCell*>(m_bits & ~tokenTypeMask) : nullptr; |
| } |
| |
| inline void* ReferrerToken::asOpaqueRoot() const |
| { |
| return isOpaqueRoot() ? bitwise_cast<HeapCell*>(m_bits & ~tokenTypeMask) : nullptr; |
| } |
| |
| inline RootMarkReason ReferrerToken::asRootMarkReason() const |
| { |
| return isRootMarkReason() ? static_cast<RootMarkReason>(m_bits >> tokenTypeShift) : RootMarkReason::None; |
| } |
| |
| inline AbstractSlotVisitor::ReferrerContext::ReferrerContext(AbstractSlotVisitor& visitor, ReferrerToken referrer) |
| : m_visitor(visitor) |
| , m_referrer(referrer) |
| { |
| m_previous = m_visitor.m_context; |
| if (m_previous) { |
| // An OpaqueRoot contexts can only be on the leaf. |
| RELEASE_ASSERT(!m_previous->m_isOpaqueRootContext); |
| } |
| IGNORE_GCC_WARNINGS_BEGIN("dangling-pointer") |
| m_visitor.m_context = this; |
| IGNORE_GCC_WARNINGS_END |
| } |
| |
| inline AbstractSlotVisitor::ReferrerContext::ReferrerContext(AbstractSlotVisitor& visitor, AbstractSlotVisitor::OpaqueRootTag) |
| : m_visitor(visitor) |
| , m_isOpaqueRootContext(true) |
| { |
| m_previous = m_visitor.m_context; |
| if (m_previous) { |
| // An OpaqueRoot contexts can only be on the leaf. |
| RELEASE_ASSERT(!m_previous->m_isOpaqueRootContext); |
| } |
| m_visitor.m_context = this; |
| } |
| |
| inline AbstractSlotVisitor::ReferrerContext::~ReferrerContext() |
| { |
| m_visitor.m_context = m_previous; |
| } |
| |
| inline AbstractSlotVisitor::AbstractSlotVisitor(Heap& heap, CString codeName, ConcurrentPtrHashSet& opaqueRoots) |
| : m_heap(heap) |
| , m_codeName(codeName) |
| , m_opaqueRoots(opaqueRoots) |
| { |
| } |
| |
| inline Heap* AbstractSlotVisitor::heap() const |
| { |
| return &m_heap; |
| } |
| |
| inline VM& AbstractSlotVisitor::vm() |
| { |
| return m_heap.vm(); |
| } |
| |
| inline const VM& AbstractSlotVisitor::vm() const |
| { |
| return m_heap.vm(); |
| } |
| |
| inline bool AbstractSlotVisitor::addOpaqueRoot(void* ptr) |
| { |
| if (!ptr) |
| return false; |
| if (m_ignoreNewOpaqueRoots) |
| return false; |
| if (!m_opaqueRoots.add(ptr)) |
| return false; |
| if (UNLIKELY(m_needsExtraOpaqueRootHandling)) |
| didAddOpaqueRoot(ptr); |
| m_visitCount++; |
| return true; |
| } |
| |
| inline bool AbstractSlotVisitor::containsOpaqueRoot(void* ptr) const |
| { |
| bool found = m_opaqueRoots.contains(ptr); |
| if (UNLIKELY(found && m_needsExtraOpaqueRootHandling)) { |
| auto* nonConstThis = const_cast<AbstractSlotVisitor*>(this); |
| nonConstThis->didFindOpaqueRoot(ptr); |
| } |
| return found; |
| } |
| |
| template<typename T> |
| ALWAYS_INLINE void AbstractSlotVisitor::append(const Weak<T>& weak) |
| { |
| appendUnbarriered(weak.get()); |
| } |
| |
| template<typename T, typename Traits> |
| ALWAYS_INLINE void AbstractSlotVisitor::append(const WriteBarrierBase<T, Traits>& slot) |
| { |
| appendUnbarriered(slot.get()); |
| } |
| |
| template<typename T, typename Traits> |
| ALWAYS_INLINE void AbstractSlotVisitor::appendHidden(const WriteBarrierBase<T, Traits>& slot) |
| { |
| appendHiddenUnbarriered(slot.get()); |
| } |
| |
| ALWAYS_INLINE void AbstractSlotVisitor::append(const WriteBarrierStructureID& slot) |
| { |
| appendUnbarriered(reinterpret_cast<JSCell*>(slot.get())); |
| } |
| |
| ALWAYS_INLINE void AbstractSlotVisitor::appendHidden(const WriteBarrierStructureID& slot) |
| { |
| appendHiddenUnbarriered(reinterpret_cast<JSCell*>(slot.get())); |
| } |
| |
| ALWAYS_INLINE void AbstractSlotVisitor::appendHiddenUnbarriered(JSValue value) |
| { |
| if (value.isCell()) |
| appendHiddenUnbarriered(value.asCell()); |
| } |
| |
| template<typename Iterator> |
| ALWAYS_INLINE void AbstractSlotVisitor::append(Iterator begin, Iterator end) |
| { |
| for (auto it = begin; it != end; ++it) |
| append(*it); |
| } |
| |
| ALWAYS_INLINE void AbstractSlotVisitor::appendValues(const WriteBarrierBase<Unknown>* barriers, size_t count) |
| { |
| for (size_t i = 0; i < count; ++i) |
| append(barriers[i]); |
| } |
| |
| ALWAYS_INLINE void AbstractSlotVisitor::appendValuesHidden(const WriteBarrierBase<Unknown>* barriers, size_t count) |
| { |
| for (size_t i = 0; i < count; ++i) |
| appendHidden(barriers[i]); |
| } |
| |
| ALWAYS_INLINE void AbstractSlotVisitor::appendUnbarriered(JSValue value) |
| { |
| if (value.isCell()) |
| appendUnbarriered(value.asCell()); |
| } |
| |
| ALWAYS_INLINE void AbstractSlotVisitor::appendUnbarriered(JSValue* slot, size_t count) |
| { |
| for (size_t i = count; i--;) |
| appendUnbarriered(slot[i]); |
| } |
| |
| ALWAYS_INLINE ReferrerToken AbstractSlotVisitor::referrer() const |
| { |
| if (!m_context) |
| return nullptr; |
| return m_context->referrer(); |
| } |
| |
| ALWAYS_INLINE void AbstractSlotVisitor::reset() |
| { |
| m_visitCount = 0; |
| } |
| |
| } // namespace JSC |