#ifndef AssemblerBufferWithConstantPool_h
#define AssemblerBufferWithConstantPool_h
-#include <wtf/Platform.h>
-
#if ENABLE(ASSEMBLER)
#include "AssemblerBuffer.h"
#include <wtf/SegmentedVector.h>
+#define ASSEMBLER_HAS_CONSTANT_POOL 1
+
namespace JSC {
/*
*/
template <int maxPoolSize, int barrierSize, int maxInstructionSize, class AssemblerType>
-class AssemblerBufferWithConstantPool: public AssemblerBuffer {
- typedef WTF::SegmentedVector<uint32_t, 512> LoadOffsets;
+class AssemblerBufferWithConstantPool : public AssemblerBuffer {
+ typedef SegmentedVector<uint32_t, 512> LoadOffsets;
+ using AssemblerBuffer::putIntegral;
+ using AssemblerBuffer::putIntegralUnchecked;
public:
+ typedef struct {
+ short high;
+ short low;
+ } TwoShorts;
+
enum {
UniqueConst,
ReusableConst,
AssemblerBuffer::ensureSpace(insnSpace);
}
+ void ensureSpaceForAnyInstruction(int amount = 1)
+ {
+ flushIfNoSpaceFor(amount * maxInstructionSize, amount * sizeof(uint64_t));
+ }
+
bool isAligned(int alignment)
{
flushIfNoSpaceFor(alignment);
correctDeltas(8);
}
- int size()
+ void putIntegral(TwoShorts value)
{
- flushIfNoSpaceFor(maxInstructionSize, sizeof(uint64_t));
- return AssemblerBuffer::size();
+ putIntegral(value.high);
+ putIntegral(value.low);
}
- void* executableCopy(ExecutablePool* allocator)
+ void putIntegralUnchecked(TwoShorts value)
{
- flushConstantPool(false);
- return AssemblerBuffer::executableCopy(allocator);
+ putIntegralUnchecked(value.high);
+ putIntegralUnchecked(value.low);
}
- void putIntWithConstantInt(uint32_t insn, uint32_t constant, bool isReusable = false)
+ PassRefPtr<ExecutableMemoryHandle> executableCopy(VM& vm, void* ownerUID, JITCompilationEffort effort)
{
- flushIfNoSpaceFor(4, 4);
-
- m_loadOffsets.append(AssemblerBuffer::size());
- if (isReusable)
- for (int i = 0; i < m_numConsts; ++i) {
- if (m_mask[i] == ReusableConst && m_pool[i] == constant) {
- AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, i));
- correctDeltas(4);
- return;
- }
- }
-
- m_pool[m_numConsts] = constant;
- m_mask[m_numConsts] = static_cast<char>(isReusable ? ReusableConst : UniqueConst);
+ flushConstantPool(false);
+ return AssemblerBuffer::executableCopy(vm, ownerUID, effort);
+ }
- AssemblerBuffer::putInt(AssemblerType::patchConstantPoolLoad(insn, m_numConsts));
- ++m_numConsts;
+ void putShortWithConstantInt(uint16_t insn, uint32_t constant, bool isReusable = false)
+ {
+ putIntegralWithConstantInt(insn, constant, isReusable);
+ }
- correctDeltas(4, 4);
+ void putIntWithConstantInt(uint32_t insn, uint32_t constant, bool isReusable = false)
+ {
+ putIntegralWithConstantInt(insn, constant, isReusable);
}
// This flushing mechanism can be called after any unconditional jumps.
- void flushWithoutBarrier()
+ void flushWithoutBarrier(bool isForced = false)
{
// Flush if constant pool is more than 60% full to avoid overuse of this function.
- if (5 * m_numConsts > 3 * maxPoolSize / sizeof(uint32_t))
+ if (isForced || 5 * static_cast<uint32_t>(m_numConsts) > 3 * maxPoolSize / sizeof(uint32_t))
flushConstantPool(false);
}
return m_pool;
}
+ int sizeOfConstantPool()
+ {
+ return m_numConsts;
+ }
+
private:
void correctDeltas(int insnSize)
{
m_lastConstDelta = constSize;
}
+ template<typename IntegralType>
+ void putIntegralWithConstantInt(IntegralType insn, uint32_t constant, bool isReusable)
+ {
+ if (!m_numConsts)
+ m_maxDistance = maxPoolSize;
+ flushIfNoSpaceFor(sizeof(IntegralType), 4);
+
+ m_loadOffsets.append(codeSize());
+ if (isReusable) {
+ for (int i = 0; i < m_numConsts; ++i) {
+ if (m_mask[i] == ReusableConst && m_pool[i] == constant) {
+ putIntegral(static_cast<IntegralType>(AssemblerType::patchConstantPoolLoad(insn, i)));
+ correctDeltas(sizeof(IntegralType));
+ return;
+ }
+ }
+ }
+
+ m_pool[m_numConsts] = constant;
+ m_mask[m_numConsts] = static_cast<char>(isReusable ? ReusableConst : UniqueConst);
+
+ putIntegral(static_cast<IntegralType>(AssemblerType::patchConstantPoolLoad(insn, m_numConsts)));
+ ++m_numConsts;
+
+ correctDeltas(sizeof(IntegralType), 4);
+ }
+
void flushConstantPool(bool useBarrier = true)
{
if (m_numConsts == 0)
return;
- int alignPool = (AssemblerBuffer::size() + (useBarrier ? barrierSize : 0)) & (sizeof(uint64_t) - 1);
+ int alignPool = (codeSize() + (useBarrier ? barrierSize : 0)) & (sizeof(uint64_t) - 1);
if (alignPool)
alignPool = sizeof(uint64_t) - alignPool;
// Callback to protect the constant pool from execution
if (useBarrier)
- AssemblerBuffer::putInt(AssemblerType::placeConstantPoolBarrier(m_numConsts * sizeof(uint32_t) + alignPool));
+ putIntegral(AssemblerType::placeConstantPoolBarrier(m_numConsts * sizeof(uint32_t) + alignPool));
if (alignPool) {
if (alignPool & 1)
AssemblerBuffer::putInt(AssemblerType::padForAlign32);
}
- int constPoolOffset = AssemblerBuffer::size();
+ int constPoolOffset = codeSize();
append(reinterpret_cast<char*>(m_pool), m_numConsts * sizeof(uint32_t));
// Patch each PC relative load
for (LoadOffsets::Iterator iter = m_loadOffsets.begin(); iter != m_loadOffsets.end(); ++iter) {
- void* loadAddr = reinterpret_cast<void*>(m_buffer + *iter);
- AssemblerType::patchConstantPoolLoad(loadAddr, reinterpret_cast<void*>(m_buffer + constPoolOffset));
+ void* loadAddr = reinterpret_cast<char*>(data()) + *iter;
+ AssemblerType::patchConstantPoolLoad(loadAddr, reinterpret_cast<char*>(data()) + constPoolOffset);
}
m_loadOffsets.clear();
m_numConsts = 0;
- m_maxDistance = maxPoolSize;
}
void flushIfNoSpaceFor(int nextInsnSize)
{
if (m_numConsts == 0)
return;
- if ((m_maxDistance < nextInsnSize + m_lastConstDelta + barrierSize + (int)sizeof(uint32_t)))
+ int lastConstDelta = m_lastConstDelta > nextInsnSize ? m_lastConstDelta - nextInsnSize : 0;
+ if ((m_maxDistance < nextInsnSize + lastConstDelta + barrierSize + (int)sizeof(uint32_t)))
flushConstantPool();
}
{
if (m_numConsts == 0)
return;
- if ((m_maxDistance < nextInsnSize + m_lastConstDelta + barrierSize + (int)sizeof(uint32_t)) ||
- (m_numConsts + nextConstSize / sizeof(uint32_t) >= maxPoolSize))
+ if ((m_maxDistance < nextInsnSize + m_lastConstDelta + nextConstSize + barrierSize + (int)sizeof(uint32_t)) ||
+ (m_numConsts * sizeof(uint32_t) + nextConstSize >= maxPoolSize))
flushConstantPool();
}