#ifndef RegisterFile_h
#define RegisterFile_h
#include "ExecutableAllocator.h"
#include "Register.h"
#include <wtf/Noncopyable.h>
#include <wtf/PageReservation.h>
#include <wtf/VMTags.h>
namespace JSC {
class ConservativeRoots;
class RegisterFile {
WTF_MAKE_NONCOPYABLE(RegisterFile);
public:
enum CallFrameHeaderEntry {
CallFrameHeaderSize = 6,
ArgumentCount = -6,
CallerFrame = -5,
Callee = -4,
ScopeChain = -3,
ReturnPC = -2, CodeBlock = -1,
};
enum { ProgramCodeThisRegister = -CallFrameHeaderSize - 1 };
static const size_t defaultCapacity = 512 * 1024;
static const size_t commitSize = 16 * 1024;
static const ptrdiff_t maxExcessCapacity = 8 * 1024;
RegisterFile(size_t capacity = defaultCapacity);
~RegisterFile();
void gatherConservativeRoots(ConservativeRoots&);
Register* begin() const { return static_cast<Register*>(m_reservation.base()); }
Register* end() const { return m_end; }
size_t size() const { return end() - begin(); }
bool grow(Register* newEnd);
void shrink(Register* newEnd);
static size_t committedByteCount();
static void initializeThreading();
Register* const * addressOfEnd() const
{
return &m_end;
}
private:
void releaseExcessCapacity();
void addToCommittedByteCount(long);
Register* m_end;
Register* m_commitEnd;
PageReservation m_reservation;
};
inline RegisterFile::RegisterFile(size_t capacity)
: m_end(0)
{
ASSERT(capacity && isPageAligned(capacity));
m_reservation = PageReservation::reserve(roundUpAllocationSize(capacity * sizeof(Register), commitSize), OSAllocator::JSVMStackPages);
m_end = static_cast<Register*>(m_reservation.base());
m_commitEnd = static_cast<Register*>(m_reservation.base());
}
inline void RegisterFile::shrink(Register* newEnd)
{
if (newEnd >= m_end)
return;
m_end = newEnd;
if (m_end == m_reservation.base() && (m_commitEnd - begin()) >= maxExcessCapacity)
releaseExcessCapacity();
}
inline bool RegisterFile::grow(Register* newEnd)
{
if (newEnd <= m_end)
return true;
if (newEnd <= m_commitEnd) {
m_end = newEnd;
return true;
}
long delta = roundUpAllocationSize(reinterpret_cast<char*>(newEnd) - reinterpret_cast<char*>(m_commitEnd), commitSize);
if (reinterpret_cast<char*>(m_commitEnd) + delta > static_cast<char*>(m_reservation.base()) + m_reservation.size())
return false;
m_reservation.commit(m_commitEnd, delta);
addToCommittedByteCount(delta);
m_commitEnd = reinterpret_cast_ptr<Register*>(reinterpret_cast<char*>(m_commitEnd) + delta);
m_end = newEnd;
return true;
}
}
#endif // RegisterFile_h