/*
* 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<Unknown>, void* context, MarkStack&);
virtual void finalize(Handle<Unknown>, 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<Node> m_blockStack;
SentinelLinkedList<Node> m_strongList;
SentinelLinkedList<Node> m_weakList;
SentinelLinkedList<Node> m_immediateList;
SinglyLinkedList<Node> 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<HandleSlot>(node);
}
inline HandleHeap::Node* HandleHeap::toNode(HandleSlot handle)
{
return reinterpret_cast<Node*>(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<Node>::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<Node>::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<WeakHandleOwner*>(-1);
}
}
#endif