blob: 2faad282273aeda929e3359538c2d7fe1ac1f0d8 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CallbackStack_h
#define CallbackStack_h
#include "platform/heap/BlinkGC.h"
#include "wtf/Allocator.h"
#include "wtf/Assertions.h"
namespace blink {
// The CallbackStack contains all the visitor callbacks used to trace and mark
// objects. A specific CallbackStack instance contains at most bufferSize elements.
// If more space is needed a new CallbackStack instance is created and chained
// together with the former instance. I.e. a logical CallbackStack can be made of
// multiple chained CallbackStack object instances.
class CallbackStack final {
USING_FAST_MALLOC(CallbackStack);
public:
class Item {
DISALLOW_NEW();
public:
Item() { }
Item(void* object, VisitorCallback callback)
: m_object(object)
, m_callback(callback)
{
}
void* object() { return m_object; }
VisitorCallback callback() { return m_callback; }
void call(Visitor* visitor) { m_callback(visitor, m_object); }
private:
void* m_object;
VisitorCallback m_callback;
};
explicit CallbackStack(size_t blockSize = kDefaultBlockSize);
~CallbackStack();
void clear();
void decommit();
Item* allocateEntry();
Item* pop();
bool isEmpty() const;
void invokeEphemeronCallbacks(Visitor*);
#if ENABLE(ASSERT)
bool hasCallbackForObject(const void*);
#endif
static const size_t kMinimalBlockSize;
static const size_t kDefaultBlockSize = (1 << 13);
private:
class Block {
USING_FAST_MALLOC(Block);
public:
Block(Block* next, size_t blockSize);
~Block();
#if ENABLE(ASSERT)
void clear();
#endif
void decommit();
Block* next() const { return m_next; }
void setNext(Block* next) { m_next = next; }
bool isEmptyBlock() const
{
return m_current == &(m_buffer[0]);
}
size_t blockSize() const { return m_blockSize; }
Item* allocateEntry()
{
if (LIKELY(m_current < m_limit))
return m_current++;
return nullptr;
}
Item* pop()
{
if (UNLIKELY(isEmptyBlock()))
return nullptr;
return --m_current;
}
void invokeEphemeronCallbacks(Visitor*);
#if ENABLE(ASSERT)
bool hasCallbackForObject(const void*);
#endif
private:
size_t m_blockSize;
Item* m_buffer;
Item* m_limit;
Item* m_current;
Block* m_next;
};
Item* popSlow();
Item* allocateEntrySlow();
void invokeOldestCallbacks(Block*, Block*, Visitor*);
bool hasJustOneBlock() const;
Block* m_first;
Block* m_last;
};
ALWAYS_INLINE CallbackStack::Item* CallbackStack::allocateEntry()
{
Item* item = m_first->allocateEntry();
if (LIKELY(!!item))
return item;
return allocateEntrySlow();
}
ALWAYS_INLINE CallbackStack::Item* CallbackStack::pop()
{
Item* item = m_first->pop();
if (LIKELY(!!item))
return item;
return popSlow();
}
} // namespace blink
#endif // CallbackStack_h