#ifndef RegisterFile_h
#define RegisterFile_h
#include "Register.h"
#include "Collector.h"
#include <wtf/Noncopyable.h>
#if HAVE(MMAP)
#include <errno.h>
#include <stdio.h>
#include <sys/mman.h>
#endif
namespace JSC {
class JSGlobalObject;
class RegisterFile : Noncopyable {
friend class JIT;
public:
enum CallFrameHeaderEntry {
CallFrameHeaderSize = 8,
CodeBlock = -8,
ScopeChain = -7,
CallerFrame = -6,
ReturnPC = -5, ReturnValueRegister = -4,
ArgumentCount = -3,
Callee = -2,
OptionalCalleeArguments = -1,
};
enum { ProgramCodeThisRegister = -CallFrameHeaderSize - 1 };
enum { ArgumentsRegister = 0 };
static const size_t defaultCapacity = 524288;
static const size_t defaultMaxGlobals = 8192;
static const size_t allocationSize = 1 << 14;
static const size_t allocationSizeMask = allocationSize - 1;
RegisterFile(size_t capacity = defaultCapacity, size_t maxGlobals = defaultMaxGlobals)
: m_numGlobals(0)
, m_maxGlobals(maxGlobals)
, m_start(0)
, m_end(0)
, m_max(0)
, m_buffer(0)
, m_globalObject(0)
{
size_t bufferLength = (capacity + maxGlobals) * sizeof(Register);
#if HAVE(MMAP)
m_buffer = static_cast<Register*>(mmap(0, bufferLength, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0));
if (m_buffer == MAP_FAILED) {
fprintf(stderr, "Could not allocate register file: %d\n", errno);
CRASH();
}
#elif HAVE(VIRTUALALLOC)
bufferLength = (bufferLength + allocationSizeMask) & ~allocationSizeMask;
m_buffer = static_cast<Register*>(VirtualAlloc(0, bufferLength, MEM_RESERVE, PAGE_READWRITE));
if (!m_buffer) {
fprintf(stderr, "Could not allocate register file: %d\n", errno);
CRASH();
}
int initialAllocation = (maxGlobals * sizeof(Register) + allocationSizeMask) & ~allocationSizeMask;
void* commitCheck = VirtualAlloc(m_buffer, initialAllocation, MEM_COMMIT, PAGE_READWRITE);
if (commitCheck != m_buffer) {
fprintf(stderr, "Could not allocate register file: %d\n", errno);
CRASH();
}
m_maxCommitted = reinterpret_cast<Register*>(reinterpret_cast<char*>(m_buffer) + initialAllocation);
#else
#error "Don't know how to reserve virtual memory on this platform."
#endif
m_start = m_buffer + maxGlobals;
m_end = m_start;
m_max = m_start + capacity;
}
~RegisterFile();
Register* start() const { return m_start; }
Register* end() const { return m_end; }
size_t size() const { return m_end - m_start; }
void setGlobalObject(JSGlobalObject* globalObject) { m_globalObject = globalObject; }
JSGlobalObject* globalObject() { return m_globalObject; }
void shrink(Register* newEnd)
{
if (newEnd < m_end)
m_end = newEnd;
}
bool grow(Register* newEnd)
{
if (newEnd > m_end) {
if (newEnd > m_max)
return false;
#if !HAVE(MMAP) && HAVE(VIRTUALALLOC)
if (newEnd > m_maxCommitted) {
ptrdiff_t additionalAllocation = ((reinterpret_cast<char*>(newEnd) - reinterpret_cast<char*>(m_maxCommitted)) + allocationSizeMask) & ~allocationSizeMask;
if (!VirtualAlloc(m_maxCommitted, additionalAllocation, MEM_COMMIT, PAGE_READWRITE)) {
fprintf(stderr, "Could not allocate register file: %d\n", errno);
CRASH();
}
m_maxCommitted = reinterpret_cast<Register*>(reinterpret_cast<char*>(m_maxCommitted) + additionalAllocation);
}
#endif
m_end = newEnd;
}
return true;
}
void setNumGlobals(size_t numGlobals) { m_numGlobals = numGlobals; }
int numGlobals() const { return m_numGlobals; }
size_t maxGlobals() const { return m_maxGlobals; }
Register* lastGlobal() const { return m_start - m_numGlobals; }
void markGlobals(Heap* heap) { heap->markConservatively(lastGlobal(), m_start); }
void markCallFrames(Heap* heap) { heap->markConservatively(m_start, m_end); }
private:
size_t m_numGlobals;
const size_t m_maxGlobals;
Register* m_start;
Register* m_end;
Register* m_max;
Register* m_buffer;
#if HAVE(VIRTUALALLOC)
Register* m_maxCommitted;
#endif
JSGlobalObject* m_globalObject; };
}
#endif // RegisterFile_h