1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=79:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Copyright (C) 2008 Apple Inc. All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : *
16 : * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
17 : * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
20 : * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 : * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 : *
28 : * ***** END LICENSE BLOCK ***** */
29 :
30 : #ifndef AssemblerBuffer_h
31 : #define AssemblerBuffer_h
32 :
33 : #include "assembler/wtf/Platform.h"
34 :
35 : #if ENABLE_ASSEMBLER
36 :
37 : #include <string.h>
38 : #include "assembler/jit/ExecutableAllocator.h"
39 : #include "assembler/wtf/Assertions.h"
40 :
41 : namespace JSC {
42 :
43 : class AssemblerBuffer {
44 : static const int inlineCapacity = 256;
45 : public:
46 763316 : AssemblerBuffer()
47 : : m_buffer(m_inlineBuffer)
48 : , m_capacity(inlineCapacity)
49 : , m_size(0)
50 763316 : , m_oom(false)
51 : {
52 763316 : }
53 :
54 763316 : ~AssemblerBuffer()
55 : {
56 763316 : if (m_buffer != m_inlineBuffer)
57 211480 : free(m_buffer);
58 763316 : }
59 :
60 125088467 : void ensureSpace(int space)
61 : {
62 125088467 : if (m_size > m_capacity - space)
63 559435 : grow();
64 125088467 : }
65 :
66 : bool isAligned(int alignment) const
67 : {
68 : return !(m_size & (alignment - 1));
69 : }
70 :
71 335874537 : void putByteUnchecked(int value)
72 : {
73 335874537 : ASSERT(!(m_size > m_capacity - 4));
74 335874537 : m_buffer[m_size] = char(value);
75 335874537 : m_size++;
76 335874537 : }
77 :
78 5075928 : void putByte(int value)
79 : {
80 5075928 : if (m_size > m_capacity - 4)
81 0 : grow();
82 5075928 : putByteUnchecked(value);
83 5075928 : }
84 :
85 281 : void putShortUnchecked(int value)
86 : {
87 281 : ASSERT(!(m_size > m_capacity - 4));
88 281 : *reinterpret_cast<short*>(&m_buffer[m_size]) = short(value);
89 281 : m_size += 2;
90 281 : }
91 :
92 : void putShort(int value)
93 : {
94 : if (m_size > m_capacity - 4)
95 : grow();
96 : putShortUnchecked(value);
97 : }
98 :
99 51691586 : void putIntUnchecked(int value)
100 : {
101 51691586 : ASSERT(!(m_size > m_capacity - 4));
102 51691586 : *reinterpret_cast<int*>(&m_buffer[m_size]) = value;
103 51691586 : m_size += 4;
104 51691586 : }
105 :
106 : void putInt64Unchecked(int64_t value)
107 : {
108 : ASSERT(!(m_size > m_capacity - 8));
109 : *reinterpret_cast<int64_t*>(&m_buffer[m_size]) = value;
110 : m_size += 8;
111 : }
112 :
113 : void putInt(int value)
114 : {
115 : if (m_size > m_capacity - 4)
116 : grow();
117 : putIntUnchecked(value);
118 : }
119 :
120 7602636 : void* data() const
121 : {
122 7602636 : return m_buffer;
123 : }
124 :
125 83271500 : int size() const
126 : {
127 83271500 : return m_size;
128 : }
129 :
130 2260344 : bool oom() const
131 : {
132 2260344 : return m_oom;
133 : }
134 :
135 : /*
136 : * The user must check for a NULL return value, which means
137 : * no code was generated, or there was an OOM.
138 : */
139 373153 : void* executableAllocAndCopy(ExecutableAllocator* allocator, ExecutablePool** poolp, CodeKind kind)
140 : {
141 373153 : if (m_oom || m_size == 0) {
142 0 : *poolp = NULL;
143 0 : return 0;
144 : }
145 :
146 373153 : void* result = allocator->alloc(m_size, poolp, kind);
147 373153 : if (!result) {
148 0 : *poolp = NULL;
149 0 : return 0;
150 : }
151 373153 : JS_ASSERT(*poolp);
152 :
153 373153 : ExecutableAllocator::makeWritable(result, m_size);
154 :
155 373153 : return memcpy(result, m_buffer, m_size);
156 : }
157 :
158 257654 : unsigned char *buffer() const {
159 257654 : ASSERT(!m_oom);
160 257654 : return reinterpret_cast<unsigned char *>(m_buffer);
161 : }
162 :
163 : protected:
164 : void append(const char* data, int size)
165 : {
166 : if (m_size > m_capacity - size)
167 : grow(size);
168 :
169 : // If we OOM and size > inlineCapacity, this would crash.
170 : if (m_oom)
171 : return;
172 : memcpy(m_buffer + m_size, data, size);
173 : m_size += size;
174 : }
175 :
176 : /*
177 : * OOM handling: This class can OOM in the grow() method trying to
178 : * allocate a new buffer. In response to an OOM, we need to avoid
179 : * crashing and report the error. We also want to make it so that
180 : * users of this class need to check for OOM only at certain points
181 : * and not after every operation.
182 : *
183 : * Our strategy for handling an OOM is to set m_oom, and then set
184 : * m_size to 0, preserving the current buffer. This way, the user
185 : * can continue assembling into the buffer, deferring OOM checking
186 : * until the user wants to read code out of the buffer.
187 : *
188 : * See also the |executableAllocAndCopy| and |buffer| methods.
189 : */
190 :
191 559435 : void grow(int extraCapacity = 0)
192 : {
193 : /*
194 : * If |extraCapacity| is zero (as it almost always is) this is an
195 : * allocator-friendly doubling growth strategy.
196 : */
197 559435 : int newCapacity = m_capacity + m_capacity + extraCapacity;
198 : char* newBuffer;
199 :
200 559435 : if (m_buffer == m_inlineBuffer) {
201 211480 : newBuffer = static_cast<char*>(malloc(newCapacity));
202 211480 : if (!newBuffer) {
203 0 : m_size = 0;
204 0 : m_oom = true;
205 0 : return;
206 : }
207 211480 : memcpy(newBuffer, m_buffer, m_size);
208 : } else {
209 347955 : newBuffer = static_cast<char*>(realloc(m_buffer, newCapacity));
210 347955 : if (!newBuffer) {
211 0 : m_size = 0;
212 0 : m_oom = true;
213 0 : return;
214 : }
215 : }
216 :
217 559435 : m_buffer = newBuffer;
218 559435 : m_capacity = newCapacity;
219 : }
220 :
221 : char m_inlineBuffer[inlineCapacity];
222 : char* m_buffer;
223 : int m_capacity;
224 : int m_size;
225 : bool m_oom;
226 : };
227 :
228 : } // namespace JSC
229 :
230 : #endif // ENABLE(ASSEMBLER)
231 :
232 : #endif // AssemblerBuffer_h
|