/* * Copyright (C) 2011 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. AND ITS CONTRIBUTORS ``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 ITS 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. */ #ifndef HandleHeap_h #define HandleHeap_h #include "BlockStack.h" #include "Handle.h" #include "SentinelLinkedList.h" #include "SinglyLinkedList.h" namespace JSC { class HandleHeap; class HeapRootMarker; class JSGlobalData; class JSValue; class MarkStack; class TypeCounter; class WeakHandleOwner { public: virtual ~WeakHandleOwner(); virtual bool isReachableFromOpaqueRoots(Handle, void* context, MarkStack&); virtual void finalize(Handle, void* context); }; class HandleHeap { public: static HandleHeap* heapFor(HandleSlot); HandleHeap(JSGlobalData*); JSGlobalData* globalData(); HandleSlot allocate(); void deallocate(HandleSlot); void makeWeak(HandleSlot, WeakHandleOwner* = 0, void* context = 0); HandleSlot copyWeak(HandleSlot); void markStrongHandles(HeapRootMarker&); void markWeakHandles(HeapRootMarker&); void finalizeWeakHandles(); void writeBarrier(HandleSlot, const JSValue&); #if !ASSERT_DISABLED bool hasWeakOwner(HandleSlot, WeakHandleOwner*); #endif unsigned protectedGlobalObjectCount(); void protectedObjectTypeCounts(TypeCounter&); private: class Node { public: Node(WTF::SentinelTag); Node(HandleHeap*); HandleSlot slot(); HandleHeap* handleHeap(); void makeWeak(WeakHandleOwner*, void* context); bool isWeak(); WeakHandleOwner* weakOwner(); void* weakOwnerContext(); void setPrev(Node*); Node* prev(); void setNext(Node*); Node* next(); private: WeakHandleOwner* emptyWeakOwner(); JSValue m_value; HandleHeap* m_handleHeap; WeakHandleOwner* m_weakOwner; void* m_weakOwnerContext; Node* m_prev; Node* m_next; }; static HandleSlot toHandle(Node*); static Node* toNode(HandleSlot); void grow(); #if !ASSERT_DISABLED bool isValidWeakNode(Node*); #endif JSGlobalData* m_globalData; BlockStack m_blockStack; SentinelLinkedList m_strongList; SentinelLinkedList m_weakList; SentinelLinkedList m_immediateList; SinglyLinkedList m_freeList; Node* m_nextToFinalize; }; inline HandleHeap* HandleHeap::heapFor(HandleSlot handle) { return toNode(handle)->handleHeap(); } inline JSGlobalData* HandleHeap::globalData() { return m_globalData; } inline HandleSlot HandleHeap::toHandle(Node* node) { return reinterpret_cast(node); } inline HandleHeap::Node* HandleHeap::toNode(HandleSlot handle) { return reinterpret_cast(handle); } inline HandleSlot HandleHeap::allocate() { if (m_freeList.isEmpty()) grow(); Node* node = m_freeList.pop(); new (node) Node(this); m_immediateList.push(node); return toHandle(node); } inline void HandleHeap::deallocate(HandleSlot handle) { Node* node = toNode(handle); if (node == m_nextToFinalize) { m_nextToFinalize = node->next(); ASSERT(m_nextToFinalize->next()); } SentinelLinkedList::remove(node); m_freeList.push(node); } inline HandleSlot HandleHeap::copyWeak(HandleSlot other) { Node* node = toNode(allocate()); node->makeWeak(toNode(other)->weakOwner(), toNode(other)->weakOwnerContext()); writeBarrier(node->slot(), *other); *node->slot() = *other; return toHandle(node); } inline void HandleHeap::makeWeak(HandleSlot handle, WeakHandleOwner* weakOwner, void* context) { Node* node = toNode(handle); node->makeWeak(weakOwner, context); SentinelLinkedList::remove(node); if (!*handle || !handle->isCell()) { m_immediateList.push(node); return; } m_weakList.push(node); } #if !ASSERT_DISABLED inline bool HandleHeap::hasWeakOwner(HandleSlot handle, WeakHandleOwner* weakOwner) { return toNode(handle)->weakOwner() == weakOwner; } #endif inline HandleHeap::Node::Node(HandleHeap* handleHeap) : m_handleHeap(handleHeap) , m_weakOwner(0) , m_weakOwnerContext(0) { } inline HandleHeap::Node::Node(WTF::SentinelTag) : m_handleHeap(0) , m_weakOwner(0) , m_weakOwnerContext(0) { } inline HandleSlot HandleHeap::Node::slot() { return &m_value; } inline HandleHeap* HandleHeap::Node::handleHeap() { return m_handleHeap; } inline void HandleHeap::Node::makeWeak(WeakHandleOwner* weakOwner, void* context) { m_weakOwner = weakOwner ? weakOwner : emptyWeakOwner(); m_weakOwnerContext = context; } inline bool HandleHeap::Node::isWeak() { return m_weakOwner; // True for emptyWeakOwner(). } inline WeakHandleOwner* HandleHeap::Node::weakOwner() { return m_weakOwner == emptyWeakOwner() ? 0 : m_weakOwner; // 0 for emptyWeakOwner(). } inline void* HandleHeap::Node::weakOwnerContext() { ASSERT(weakOwner()); return m_weakOwnerContext; } inline void HandleHeap::Node::setPrev(Node* prev) { m_prev = prev; } inline HandleHeap::Node* HandleHeap::Node::prev() { return m_prev; } inline void HandleHeap::Node::setNext(Node* next) { m_next = next; } inline HandleHeap::Node* HandleHeap::Node::next() { return m_next; } // Sentinel to indicate that a node is weak, but its owner has no meaningful // callbacks. This allows us to optimize by skipping such nodes. inline WeakHandleOwner* HandleHeap::Node::emptyWeakOwner() { return reinterpret_cast(-1); } } #endif