Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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 jit_x86_shared_AssemblerBuffer_x86_shared_h
31 : #define jit_x86_shared_AssemblerBuffer_x86_shared_h
32 :
33 : #include <stdarg.h>
34 : #include <string.h>
35 :
36 : #include "ds/PageProtectingVector.h"
37 : #include "jit/ExecutableAllocator.h"
38 : #include "jit/JitSpewer.h"
39 :
40 : // Spew formatting helpers.
41 : #define PRETTYHEX(x) (((x)<0)?"-":""),(((x)<0)?-(x):(x))
42 :
43 : #define MEM_o "%s0x%x"
44 : #define MEM_os MEM_o "(,%s,%d)"
45 : #define MEM_ob MEM_o "(%s)"
46 : #define MEM_obs MEM_o "(%s,%s,%d)"
47 :
48 : #define MEM_o32 "%s0x%04x"
49 : #define MEM_o32s MEM_o32 "(,%s,%d)"
50 : #define MEM_o32b MEM_o32 "(%s)"
51 : #define MEM_o32bs MEM_o32 "(%s,%s,%d)"
52 : #define MEM_o32r ".Lfrom%d(%%rip)"
53 :
54 : #define ADDR_o(offset) PRETTYHEX(offset)
55 : #define ADDR_os(offset, index, scale) ADDR_o(offset), GPRegName((index)), (1<<(scale))
56 : #define ADDR_ob(offset, base) ADDR_o(offset), GPRegName((base))
57 : #define ADDR_obs(offset, base, index, scale) ADDR_ob(offset, base), GPRegName((index)), (1<<(scale))
58 :
59 : #define ADDR_o32(offset) ADDR_o(offset)
60 : #define ADDR_o32s(offset, index, scale) ADDR_os(offset, index, scale)
61 : #define ADDR_o32b(offset, base) ADDR_ob(offset, base)
62 : #define ADDR_o32bs(offset, base, index, scale) ADDR_obs(offset, base, index, scale)
63 : #define ADDR_o32r(offset) (offset)
64 :
65 : namespace js {
66 :
67 : class Sprinter;
68 :
69 : namespace jit {
70 :
71 4503 : class AssemblerBuffer
72 : {
73 : template<size_t size, typename T>
74 3724296 : MOZ_ALWAYS_INLINE void sizedAppendUnchecked(T value)
75 : {
76 3724296 : m_buffer.infallibleAppend(reinterpret_cast<unsigned char*>(&value), size);
77 3724853 : }
78 :
79 : template<size_t size, typename T>
80 306 : MOZ_ALWAYS_INLINE void sizedAppend(T value)
81 : {
82 306 : if (MOZ_UNLIKELY(!m_buffer.append(reinterpret_cast<unsigned char*>(&value), size)))
83 0 : oomDetected();
84 306 : }
85 :
86 : public:
87 4503 : AssemblerBuffer() : m_oom(false) {}
88 :
89 1119893 : void ensureSpace(size_t space)
90 : {
91 1119893 : if (MOZ_UNLIKELY(!m_buffer.reserve(m_buffer.length() + space)))
92 0 : oomDetected();
93 1119939 : }
94 :
95 25908 : bool isAligned(size_t alignment) const
96 : {
97 25908 : return !(m_buffer.length() & (alignment - 1));
98 : }
99 :
100 3338469 : MOZ_ALWAYS_INLINE void putByteUnchecked(int value) { sizedAppendUnchecked<1>(value); }
101 1040 : MOZ_ALWAYS_INLINE void putShortUnchecked(int value) { sizedAppendUnchecked<2>(value); }
102 303320 : MOZ_ALWAYS_INLINE void putIntUnchecked(int value) { sizedAppendUnchecked<4>(value); }
103 81378 : MOZ_ALWAYS_INLINE void putInt64Unchecked(int64_t value) { sizedAppendUnchecked<8>(value); }
104 :
105 306 : MOZ_ALWAYS_INLINE void putByte(int value) { sizedAppend<1>(value); }
106 : MOZ_ALWAYS_INLINE void putShort(int value) { sizedAppend<2>(value); }
107 : MOZ_ALWAYS_INLINE void putInt(int value) { sizedAppend<4>(value); }
108 : MOZ_ALWAYS_INLINE void putInt64(int64_t value) { sizedAppend<8>(value); }
109 :
110 0 : MOZ_MUST_USE bool append(const unsigned char* values, size_t size)
111 : {
112 0 : if (MOZ_UNLIKELY(!m_buffer.append(values, size))) {
113 0 : oomDetected();
114 0 : return false;
115 : }
116 0 : return true;
117 : }
118 :
119 636903 : size_t size() const
120 : {
121 636903 : return m_buffer.length();
122 : }
123 :
124 256035 : bool oom() const
125 : {
126 256035 : return m_oom;
127 : }
128 :
129 4499 : const unsigned char* buffer() const
130 : {
131 4499 : MOZ_RELEASE_ASSERT(!m_oom);
132 4499 : return m_buffer.begin();
133 : }
134 :
135 142599 : unsigned char* data()
136 : {
137 142599 : return m_buffer.begin();
138 : }
139 :
140 : #ifndef RELEASE_OR_BETA
141 0 : void disableProtection() { m_buffer.disableProtection(); }
142 : void enableProtection() { m_buffer.enableProtection(); }
143 : void setLowerBoundForProtection(size_t size)
144 : {
145 : m_buffer.setLowerBoundForProtection(size);
146 : }
147 : void unprotectRegion(unsigned char* first, size_t size)
148 : {
149 : m_buffer.unprotectRegion(first, size);
150 : }
151 : void reprotectRegion(unsigned char* first, size_t size)
152 : {
153 : m_buffer.reprotectRegion(first, size);
154 : }
155 : #else
156 : void disableProtection() {}
157 : void enableProtection() {}
158 : void setLowerBoundForProtection(size_t) {}
159 : void unprotectRegion(unsigned char*, size_t) {}
160 : void reprotectRegion(unsigned char*, size_t) {}
161 : #endif
162 :
163 : protected:
164 : /*
165 : * OOM handling: This class can OOM in the ensureSpace() method trying
166 : * to allocate a new buffer. In response to an OOM, we need to avoid
167 : * crashing and report the error. We also want to make it so that
168 : * users of this class need to check for OOM only at certain points
169 : * and not after every operation.
170 : *
171 : * Our strategy for handling an OOM is to set m_oom, and then clear (but
172 : * not free) m_buffer, preserving the current buffer. This way, the user
173 : * can continue assembling into the buffer, deferring OOM checking
174 : * until the user wants to read code out of the buffer.
175 : *
176 : * See also the |buffer| method.
177 : */
178 0 : void oomDetected()
179 : {
180 0 : m_oom = true;
181 0 : m_buffer.clear();
182 0 : }
183 :
184 : #ifndef RELEASE_OR_BETA
185 : PageProtectingVector<unsigned char, 256, ProtectedReallocPolicy,
186 : /* ProtectUsed = */ false, /* ProtectUnused = */ false> m_buffer;
187 : #else
188 : mozilla::Vector<unsigned char, 256, SystemAllocPolicy> m_buffer;
189 : #endif
190 : bool m_oom;
191 : };
192 :
193 : class GenericAssembler
194 : {
195 : #ifdef JS_JITSPEW
196 : Sprinter* printer;
197 : #endif
198 : public:
199 :
200 4503 : GenericAssembler()
201 : #ifdef JS_JITSPEW
202 4503 : : printer(nullptr)
203 : #endif
204 4503 : {}
205 :
206 0 : void setPrinter(Sprinter* sp)
207 : {
208 : #ifdef JS_JITSPEW
209 0 : printer = sp;
210 : #endif
211 0 : }
212 :
213 : #ifdef JS_JITSPEW
214 1367819 : inline void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3)
215 : {
216 1367819 : if (MOZ_UNLIKELY(printer || JitSpewEnabled(JitSpew_Codegen))) {
217 : va_list va;
218 0 : va_start(va, fmt);
219 0 : spew(fmt, va);
220 0 : va_end(va);
221 : }
222 1367817 : }
223 : #else
224 : MOZ_ALWAYS_INLINE void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3)
225 : { }
226 : #endif
227 :
228 : #ifdef JS_JITSPEW
229 : MOZ_COLD void spew(const char* fmt, va_list va) MOZ_FORMAT_PRINTF(2, 0);
230 : #endif
231 : };
232 :
233 : } // namespace jit
234 : } // namespace js
235 :
236 : #endif /* jit_x86_shared_AssemblerBuffer_x86_shared_h */
|