1/*
2 * Copyright (C) 2008, 2012, 2014 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef AssemblerBuffer_h
27#define AssemblerBuffer_h
28
29#if ENABLE(ASSEMBLER)
30
31#include "ExecutableAllocator.h"
32#include "JITCompilationEffort.h"
33#include "stdint.h"
34#include <string.h>
35#include <wtf/Assertions.h>
36#include <wtf/FastMalloc.h>
37#include <wtf/StdLibExtras.h>
38
39namespace JSC {
40
41    struct AssemblerLabel {
42        AssemblerLabel()
43            : m_offset(std::numeric_limits<uint32_t>::max())
44        {
45        }
46
47        explicit AssemblerLabel(uint32_t offset)
48            : m_offset(offset)
49        {
50        }
51
52        bool isSet() const { return (m_offset != std::numeric_limits<uint32_t>::max()); }
53
54        AssemblerLabel labelAtOffset(int offset) const
55        {
56            return AssemblerLabel(m_offset + offset);
57        }
58
59        uint32_t m_offset;
60    };
61
62    class AssemblerData {
63    public:
64        AssemblerData()
65            : m_buffer(nullptr)
66            , m_capacity(0)
67        {
68        }
69
70        AssemblerData(unsigned initialCapacity)
71        {
72            m_capacity = fastMallocGoodSize(initialCapacity);
73            m_buffer = static_cast<char*>(fastMalloc(m_capacity));
74        }
75
76        AssemblerData(AssemblerData&& other)
77        {
78            m_buffer = other.m_buffer;
79            other.m_buffer = nullptr;
80            m_capacity = other.m_capacity;
81            other.m_capacity = 0;
82        }
83
84        AssemblerData& operator=(AssemblerData&& other)
85        {
86            m_buffer = other.m_buffer;
87            other.m_buffer = nullptr;
88            m_capacity = other.m_capacity;
89            other.m_capacity = 0;
90            return *this;
91        }
92
93        ~AssemblerData()
94        {
95            fastFree(m_buffer);
96        }
97
98        char* buffer() const { return m_buffer; }
99
100        unsigned capacity() const { return m_capacity; }
101
102        void grow(unsigned extraCapacity = 0)
103        {
104            m_capacity = fastMallocGoodSize(m_capacity + m_capacity / 2 + extraCapacity);
105            m_buffer = static_cast<char*>(fastRealloc(m_buffer, m_capacity));
106        }
107
108    private:
109        char* m_buffer;
110        unsigned m_capacity;
111    };
112
113    class AssemblerBuffer {
114        static const int initialCapacity = 128;
115    public:
116        AssemblerBuffer()
117            : m_storage(initialCapacity)
118            , m_index(0)
119        {
120        }
121
122        bool isAvailable(int space)
123        {
124            return m_index + space <= m_storage.capacity();
125        }
126
127        void ensureSpace(int space)
128        {
129            if (!isAvailable(space))
130                grow();
131        }
132
133        bool isAligned(int alignment) const
134        {
135            return !(m_index & (alignment - 1));
136        }
137
138        void putByteUnchecked(int8_t value) { putIntegralUnchecked(value); }
139        void putByte(int8_t value) { putIntegral(value); }
140        void putShortUnchecked(int16_t value) { putIntegralUnchecked(value); }
141        void putShort(int16_t value) { putIntegral(value); }
142        void putIntUnchecked(int32_t value) { putIntegralUnchecked(value); }
143        void putInt(int32_t value) { putIntegral(value); }
144        void putInt64Unchecked(int64_t value) { putIntegralUnchecked(value); }
145        void putInt64(int64_t value) { putIntegral(value); }
146
147        void* data() const
148        {
149            return m_storage.buffer();
150        }
151
152        size_t codeSize() const
153        {
154            return m_index;
155        }
156
157        AssemblerLabel label() const
158        {
159            return AssemblerLabel(m_index);
160        }
161
162        unsigned debugOffset() { return m_index; }
163
164        AssemblerData releaseAssemblerData() { return WTF::move(m_storage); }
165
166    protected:
167        template<typename IntegralType>
168        void putIntegral(IntegralType value)
169        {
170            unsigned nextIndex = m_index + sizeof(IntegralType);
171            if (UNLIKELY(nextIndex > m_storage.capacity()))
172                grow();
173            ASSERT(isAvailable(sizeof(IntegralType)));
174            *reinterpret_cast_ptr<IntegralType*>(m_storage.buffer() + m_index) = value;
175            m_index = nextIndex;
176        }
177
178        template<typename IntegralType>
179        void putIntegralUnchecked(IntegralType value)
180        {
181            ASSERT(isAvailable(sizeof(IntegralType)));
182            *reinterpret_cast_ptr<IntegralType*>(m_storage.buffer() + m_index) = value;
183            m_index += sizeof(IntegralType);
184        }
185
186        void append(const char* data, int size)
187        {
188            if (!isAvailable(size))
189                grow(size);
190
191            memcpy(m_storage.buffer() + m_index, data, size);
192            m_index += size;
193        }
194
195        void grow(int extraCapacity = 0)
196        {
197            m_storage.grow(extraCapacity);
198        }
199
200    private:
201        AssemblerData m_storage;
202        unsigned m_index;
203    };
204
205} // namespace JSC
206
207#endif // ENABLE(ASSEMBLER)
208
209#endif // AssemblerBuffer_h
210