/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2012, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#if ENABLE(ASSEMBLER)
+#include "ExecutableAllocator.h"
+#include "JITCompilationEffort.h"
#include "stdint.h"
#include <string.h>
-#include <jit/ExecutableAllocator.h>
#include <wtf/Assertions.h>
#include <wtf/FastMalloc.h>
+#include <wtf/StdLibExtras.h>
namespace JSC {
- class AssemblerBuffer {
- static const int inlineCapacity = 256;
- public:
- AssemblerBuffer()
- : m_buffer(m_inlineBuffer)
- , m_capacity(inlineCapacity)
- , m_size(0)
+ struct AssemblerLabel {
+ AssemblerLabel()
+ : m_offset(std::numeric_limits<uint32_t>::max())
{
}
- ~AssemblerBuffer()
+ explicit AssemblerLabel(uint32_t offset)
+ : m_offset(offset)
{
- if (m_buffer != m_inlineBuffer)
- fastFree(m_buffer);
}
- void ensureSpace(int space)
+ bool isSet() const { return (m_offset != std::numeric_limits<uint32_t>::max()); }
+
+ AssemblerLabel labelAtOffset(int offset) const
{
- if (m_size > m_capacity - space)
- grow();
+ return AssemblerLabel(m_offset + offset);
}
- bool isAligned(int alignment) const
+ uint32_t m_offset;
+ };
+
+ class AssemblerData {
+ public:
+ AssemblerData()
+ : m_buffer(nullptr)
+ , m_capacity(0)
{
- return !(m_size & (alignment - 1));
}
- void putByteUnchecked(int value)
+ AssemblerData(unsigned initialCapacity)
{
- ASSERT(!(m_size > m_capacity - 4));
- m_buffer[m_size] = value;
- m_size++;
+ m_capacity = fastMallocGoodSize(initialCapacity);
+ m_buffer = static_cast<char*>(fastMalloc(m_capacity));
}
- void putByte(int value)
+ AssemblerData(AssemblerData&& other)
{
- if (m_size > m_capacity - 4)
- grow();
- putByteUnchecked(value);
+ m_buffer = other.m_buffer;
+ other.m_buffer = nullptr;
+ m_capacity = other.m_capacity;
+ other.m_capacity = 0;
}
- void putShortUnchecked(int value)
+ AssemblerData& operator=(AssemblerData&& other)
{
- ASSERT(!(m_size > m_capacity - 4));
- *reinterpret_cast<short*>(&m_buffer[m_size]) = value;
- m_size += 2;
+ m_buffer = other.m_buffer;
+ other.m_buffer = nullptr;
+ m_capacity = other.m_capacity;
+ other.m_capacity = 0;
+ return *this;
}
- void putShort(int value)
+ ~AssemblerData()
{
- if (m_size > m_capacity - 4)
- grow();
- putShortUnchecked(value);
+ fastFree(m_buffer);
}
- void putIntUnchecked(int value)
+ char* buffer() const { return m_buffer; }
+
+ unsigned capacity() const { return m_capacity; }
+
+ void grow(unsigned extraCapacity = 0)
+ {
+ m_capacity = fastMallocGoodSize(m_capacity + m_capacity / 2 + extraCapacity);
+ m_buffer = static_cast<char*>(fastRealloc(m_buffer, m_capacity));
+ }
+
+ private:
+ char* m_buffer;
+ unsigned m_capacity;
+ };
+
+ class AssemblerBuffer {
+ static const int initialCapacity = 128;
+ public:
+ AssemblerBuffer()
+ : m_storage(initialCapacity)
+ , m_index(0)
{
- ASSERT(!(m_size > m_capacity - 4));
- *reinterpret_cast<int*>(&m_buffer[m_size]) = value;
- m_size += 4;
}
- void putInt64Unchecked(int64_t value)
+ bool isAvailable(int space)
{
- ASSERT(!(m_size > m_capacity - 8));
- *reinterpret_cast<int64_t*>(&m_buffer[m_size]) = value;
- m_size += 8;
+ return m_index + space <= m_storage.capacity();
}
- void putInt(int value)
+ void ensureSpace(int space)
{
- if (m_size > m_capacity - 4)
+ if (!isAvailable(space))
grow();
- putIntUnchecked(value);
}
+ bool isAligned(int alignment) const
+ {
+ return !(m_index & (alignment - 1));
+ }
+
+ void putByteUnchecked(int8_t value) { putIntegralUnchecked(value); }
+ void putByte(int8_t value) { putIntegral(value); }
+ void putShortUnchecked(int16_t value) { putIntegralUnchecked(value); }
+ void putShort(int16_t value) { putIntegral(value); }
+ void putIntUnchecked(int32_t value) { putIntegralUnchecked(value); }
+ void putInt(int32_t value) { putIntegral(value); }
+ void putInt64Unchecked(int64_t value) { putIntegralUnchecked(value); }
+ void putInt64(int64_t value) { putIntegral(value); }
+
void* data() const
{
- return m_buffer;
+ return m_storage.buffer();
}
- int size() const
+ size_t codeSize() const
{
- return m_size;
+ return m_index;
}
- void* executableCopy(ExecutablePool* allocator)
+ AssemblerLabel label() const
{
- if (!m_size)
- return 0;
+ return AssemblerLabel(m_index);
+ }
- void* result = allocator->alloc(m_size);
+ unsigned debugOffset() { return m_index; }
- if (!result)
- return 0;
+ AssemblerData releaseAssemblerData() { return WTF::move(m_storage); }
- ExecutableAllocator::makeWritable(result, m_size);
+ protected:
+ template<typename IntegralType>
+ void putIntegral(IntegralType value)
+ {
+ unsigned nextIndex = m_index + sizeof(IntegralType);
+ if (UNLIKELY(nextIndex > m_storage.capacity()))
+ grow();
+ ASSERT(isAvailable(sizeof(IntegralType)));
+ *reinterpret_cast_ptr<IntegralType*>(m_storage.buffer() + m_index) = value;
+ m_index = nextIndex;
+ }
- return memcpy(result, m_buffer, m_size);
+ template<typename IntegralType>
+ void putIntegralUnchecked(IntegralType value)
+ {
+ ASSERT(isAvailable(sizeof(IntegralType)));
+ *reinterpret_cast_ptr<IntegralType*>(m_storage.buffer() + m_index) = value;
+ m_index += sizeof(IntegralType);
}
- protected:
void append(const char* data, int size)
{
- if (m_size > m_capacity - size)
+ if (!isAvailable(size))
grow(size);
- memcpy(m_buffer + m_size, data, size);
- m_size += size;
+ memcpy(m_storage.buffer() + m_index, data, size);
+ m_index += size;
}
void grow(int extraCapacity = 0)
{
- m_capacity += m_capacity / 2 + extraCapacity;
-
- if (m_buffer == m_inlineBuffer) {
- char* newBuffer = static_cast<char*>(fastMalloc(m_capacity));
- m_buffer = static_cast<char*>(memcpy(newBuffer, m_buffer, m_size));
- } else
- m_buffer = static_cast<char*>(fastRealloc(m_buffer, m_capacity));
+ m_storage.grow(extraCapacity);
}
- char m_inlineBuffer[inlineCapacity];
- char* m_buffer;
- int m_capacity;
- int m_size;
+ private:
+ AssemblerData m_storage;
+ unsigned m_index;
};
} // namespace JSC