Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / assembler / assembler / AssemblerBuffer.h
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 #include "jsstdint.h"
41
42 namespace JSC {
43
44     class AssemblerBuffer {
45         static const int inlineCapacity = 256;
46     public:
47         AssemblerBuffer()
48             : m_buffer(m_inlineBuffer)
49             , m_capacity(inlineCapacity)
50             , m_size(0)
51             , m_oom(false)
52         {
53         }
54
55         ~AssemblerBuffer()
56         {
57             if (m_buffer != m_inlineBuffer)
58                 free(m_buffer);
59         }
60
61         void ensureSpace(int space)
62         {
63             if (m_size > m_capacity - space)
64                 grow();
65         }
66
67         bool isAligned(int alignment) const
68         {
69             return !(m_size & (alignment - 1));
70         }
71
72         void putByteUnchecked(int value)
73         {
74             ASSERT(!(m_size > m_capacity - 4));
75             m_buffer[m_size] = char(value);
76             m_size++;
77         }
78
79         void putByte(int value)
80         {
81             if (m_size > m_capacity - 4)
82                 grow();
83             putByteUnchecked(value);
84         }
85
86         void putShortUnchecked(int value)
87         {
88             ASSERT(!(m_size > m_capacity - 4));
89             *reinterpret_cast<short*>(&m_buffer[m_size]) = short(value);
90             m_size += 2;
91         }
92
93         void putShort(int value)
94         {
95             if (m_size > m_capacity - 4)
96                 grow();
97             putShortUnchecked(value);
98         }
99
100         void putIntUnchecked(int value)
101         {
102             ASSERT(!(m_size > m_capacity - 4));
103             *reinterpret_cast<int*>(&m_buffer[m_size]) = value;
104             m_size += 4;
105         }
106
107         void putInt64Unchecked(int64_t value)
108         {
109             ASSERT(!(m_size > m_capacity - 8));
110             *reinterpret_cast<int64_t*>(&m_buffer[m_size]) = value;
111             m_size += 8;
112         }
113
114         void putInt(int value)
115         {
116             if (m_size > m_capacity - 4)
117                 grow();
118             putIntUnchecked(value);
119         }
120
121         void* data() const
122         {
123             return m_buffer;
124         }
125
126         int size() const
127         {
128             return m_size;
129         }
130
131         bool oom() const
132         {
133             return m_oom;
134         }
135
136         /*
137          * The user must check for a NULL return value, which means
138          * no code was generated, or there was an OOM.
139          */
140         void* executableCopy(ExecutablePool* allocator)
141         {
142             if (m_oom)
143                 return 0;
144
145             if (!m_size)
146                 return 0;
147
148             void* result = allocator->alloc(m_size);
149
150             if (!result)
151                 return 0;
152
153             ExecutableAllocator::makeWritable(result, m_size);
154
155             return memcpy(result, m_buffer, m_size);
156         }
157
158         unsigned char *buffer() const {
159             ASSERT(!m_oom);
160             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 |executableCopy| and |buffer| methods.
189          */
190
191         void grow(int extraCapacity = 0)
192         {
193             int newCapacity = m_capacity + m_capacity / 2 + extraCapacity;
194             char* newBuffer;
195
196             if (m_buffer == m_inlineBuffer) {
197                 newBuffer = static_cast<char*>(malloc(newCapacity));
198                 if (!newBuffer) {
199                     m_size = 0;
200                     m_oom = true;
201                     return;
202                 }
203                 memcpy(newBuffer, m_buffer, m_size);
204             } else {
205                 newBuffer = static_cast<char*>(realloc(m_buffer, newCapacity));
206                 if (!newBuffer) {
207                     m_size = 0;
208                     m_oom = true;
209                     return;
210                 }
211             }
212
213             m_buffer = newBuffer;
214             m_capacity = newCapacity;
215         }
216
217         char m_inlineBuffer[inlineCapacity];
218         char* m_buffer;
219         int m_capacity;
220         int m_size;
221         bool m_oom;
222     };
223
224 } // namespace JSC
225
226 #endif // ENABLE(ASSEMBLER)
227
228 #endif // AssemblerBuffer_h