blob: b7ea2d92b001c9ae80ffd9b55f72771e35a14847 [file] [log] [blame]
Alexandre Rames9dd6fa32016-10-12 13:26:54 +01001// Copyright 2016, VIXL authors
2// 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 are met:
6//
7// * Redistributions of source code must retain the above copyright notice,
8// this list of conditions and the following disclaimer.
9// * Redistributions in binary form must reproduce the above copyright notice,
10// this list of conditions and the following disclaimer in the documentation
11// and/or other materials provided with the distribution.
12// * Neither the name of ARM Limited nor the names of its contributors may be
13// used to endorse or promote products derived from this software without
14// specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27
28#ifndef VIXL_CODE_GENERATION_SCOPES_H_
29#define VIXL_CODE_GENERATION_SCOPES_H_
30
31
32#include "assembler-base-vixl.h"
Alexandre Ramesc0b25f22016-10-19 13:53:55 +010033#include "macro-assembler-interface.h"
Alexandre Rames9dd6fa32016-10-12 13:26:54 +010034
35
36namespace vixl {
37
38// This scope will:
39// - Allow code emission from the specified `Assembler`.
40// - Optionally reserve space in the `CodeBuffer` (if it is managed by VIXL).
41// - Optionally, on destruction, check the size of the generated code.
42// (The size can be either exact or a maximum size.)
43class CodeBufferCheckScope {
44 public:
45 // Tell whether or not the scope needs to ensure the associated CodeBuffer
46 // has enough space for the requested size.
47 enum BufferSpacePolicy {
48 kReserveBufferSpace,
49 kDontReserveBufferSpace,
50
51 // Deprecated, but kept for backward compatibility.
52 kCheck = kReserveBufferSpace,
53 kNoCheck = kDontReserveBufferSpace
54 };
55
56 // Tell whether or not the scope should assert the amount of code emitted
57 // within the scope is consistent with the requested amount.
58 enum SizePolicy {
59 kNoAssert, // Do not check the size of the code emitted.
60 kExactSize, // The code emitted must be exactly size bytes.
61 kMaximumSize // The code emitted must be at most size bytes.
62 };
63
64 // This constructor implicitly calls `Open` to initialise the scope
65 // (`assembler` must not be `NULL`), so it is ready to use immediately after
66 // it has been constructed.
67 CodeBufferCheckScope(internal::AssemblerBase* assembler,
68 size_t size,
69 BufferSpacePolicy check_policy = kReserveBufferSpace,
70 SizePolicy size_policy = kMaximumSize)
Alexandre Ramesc0b25f22016-10-19 13:53:55 +010071 : assembler_(NULL), initialised_(false) {
Alexandre Rames9dd6fa32016-10-12 13:26:54 +010072 Open(assembler, size, check_policy, size_policy);
73 }
74
75 // This constructor does not implicitly initialise the scope. Instead, the
76 // user is required to explicitly call the `Open` function before using the
77 // scope.
Alexandre Ramesc0b25f22016-10-19 13:53:55 +010078 CodeBufferCheckScope() : assembler_(NULL), initialised_(false) {
Alexandre Rames9dd6fa32016-10-12 13:26:54 +010079 // Nothing to do.
80 }
81
82 virtual ~CodeBufferCheckScope() { Close(); }
83
84 // This function performs the actual initialisation work.
85 void Open(internal::AssemblerBase* assembler,
86 size_t size,
87 BufferSpacePolicy check_policy = kReserveBufferSpace,
88 SizePolicy size_policy = kMaximumSize) {
89 VIXL_ASSERT(!initialised_);
90 VIXL_ASSERT(assembler != NULL);
Alexandre Ramesc0b25f22016-10-19 13:53:55 +010091 assembler_ = assembler;
Alexandre Rames9dd6fa32016-10-12 13:26:54 +010092 if (check_policy == kReserveBufferSpace) {
93 assembler->GetBuffer()->EnsureSpaceFor(size);
94 }
95#ifdef VIXL_DEBUG
Alexandre Rames9dd6fa32016-10-12 13:26:54 +010096 limit_ = assembler_->GetSizeOfCodeGenerated() + size;
97 assert_policy_ = size_policy;
98 previous_allow_assembler_ = assembler_->AllowAssembler();
99 assembler_->SetAllowAssembler(true);
Alexandre Rames9dd6fa32016-10-12 13:26:54 +0100100#else
101 USE(size_policy);
102#endif
Alexandre Ramesc0b25f22016-10-19 13:53:55 +0100103 initialised_ = true;
Alexandre Rames9dd6fa32016-10-12 13:26:54 +0100104 }
105
106 // This function performs the cleaning-up work. It must succeed even if the
107 // scope has not been opened. It is safe to call multiple times.
108 void Close() {
109#ifdef VIXL_DEBUG
110 if (!initialised_) {
111 return;
112 }
113 assembler_->SetAllowAssembler(previous_allow_assembler_);
114 switch (assert_policy_) {
115 case kNoAssert:
116 break;
117 case kExactSize:
118 VIXL_ASSERT(assembler_->GetSizeOfCodeGenerated() == limit_);
119 break;
120 case kMaximumSize:
121 VIXL_ASSERT(assembler_->GetSizeOfCodeGenerated() <= limit_);
122 break;
123 default:
124 VIXL_UNREACHABLE();
125 }
Alexandre Rames9dd6fa32016-10-12 13:26:54 +0100126#endif
Alexandre Ramesc0b25f22016-10-19 13:53:55 +0100127 initialised_ = false;
Alexandre Rames9dd6fa32016-10-12 13:26:54 +0100128 }
129
130 protected:
131 internal::AssemblerBase* assembler_;
132 SizePolicy assert_policy_;
133 size_t limit_;
134 bool previous_allow_assembler_;
135 bool initialised_;
136};
Alexandre Ramesc0b25f22016-10-19 13:53:55 +0100137
138
139// This scope will:
140// - Do the same as `CodeBufferCheckSCope`, but:
141// - If managed by VIXL, always reserve space in the `CodeBuffer`.
142// - Always check the size (exact or maximum) of the generated code on
143// destruction.
144// - Emit pools if the specified size would push them out of range.
145// - Block pools emission for the duration of the scope.
146// This scope allows the `Assembler` and `MacroAssembler` to be freely and
147// safely mixed for its duration.
148class EmissionCheckScope : public CodeBufferCheckScope {
149 public:
150 // This constructor implicitly calls `Open` (when `masm` is not `NULL`) to
151 // initialise the scope, so it is ready to use immediately after it has been
152 // constructed.
153 EmissionCheckScope(MacroAssemblerInterface* masm,
154 size_t size,
155 SizePolicy size_policy = kMaximumSize) {
156 Open(masm, size, size_policy);
157 }
158
159 // This constructor does not implicitly initialise the scope. Instead, the
160 // user is required to explicitly call the `Open` function before using the
161 // scope.
162 EmissionCheckScope() {}
163
164 virtual ~EmissionCheckScope() { Close(); }
165
Pierre Langloisd56f6092017-01-11 14:00:39 +0000166 enum PoolPolicy {
167 // Do not forbid pool emission inside the scope. Pools will not be emitted
168 // on `Open` either.
169 kIgnorePools,
170 // Force pools to be generated on `Open` if necessary and block their
171 // emission inside the scope.
172 kBlockPools,
173 // Deprecated, but kept for backward compatibility.
174 kCheckPools = kBlockPools
175 };
Alexandre Ramesc0b25f22016-10-19 13:53:55 +0100176
177 void Open(MacroAssemblerInterface* masm,
178 size_t size,
179 SizePolicy size_policy = kMaximumSize) {
Pierre Langloisd56f6092017-01-11 14:00:39 +0000180 Open(masm, size, size_policy, kBlockPools);
Alexandre Ramesc0b25f22016-10-19 13:53:55 +0100181 }
182
183 void Close() {
184 if (!initialised_) {
185 return;
186 }
187 if (masm_ == NULL) {
188 // Nothing to do.
189 return;
190 }
Pierre Langlois6ee09782017-01-09 18:33:13 +0000191 // Perform the opposite of `Open`, which is:
192 // - Check the code generation limit was not exceeded.
193 // - Release the pools.
194 CodeBufferCheckScope::Close();
Pierre Langloisd56f6092017-01-11 14:00:39 +0000195 if (pool_policy_ == kBlockPools) {
Alexandre Ramesc0b25f22016-10-19 13:53:55 +0100196 masm_->ReleasePools();
197 }
Alexandre Ramesc0b25f22016-10-19 13:53:55 +0100198 VIXL_ASSERT(!initialised_);
199 }
200
201 protected:
202 void Open(MacroAssemblerInterface* masm,
203 size_t size,
204 SizePolicy size_policy,
205 PoolPolicy pool_policy) {
206 if (masm == NULL) {
207 // Nothing to do.
208 // We may reach this point in a context of conditional code generation.
209 // See `aarch64::MacroAssembler::MoveImmediateHelper()` for an example.
210 return;
211 }
212 masm_ = masm;
213 pool_policy_ = pool_policy;
Pierre Langloisd56f6092017-01-11 14:00:39 +0000214 if (pool_policy_ == kBlockPools) {
Alexandre Ramesc0b25f22016-10-19 13:53:55 +0100215 // To avoid duplicating the work to check that enough space is available
216 // in the buffer, do not use the more generic `EnsureEmitFor()`. It is
217 // done below when opening `CodeBufferCheckScope`.
218 masm->EnsureEmitPoolsFor(size);
219 masm->BlockPools();
220 }
221 // The buffer should be checked *after* we emit the pools.
Alexandre Rames8d191ab2016-11-29 11:23:27 +0000222 CodeBufferCheckScope::Open(masm->AsAssemblerBase(),
Alexandre Ramesc0b25f22016-10-19 13:53:55 +0100223 size,
224 kReserveBufferSpace,
225 size_policy);
226 VIXL_ASSERT(initialised_);
227 }
228
229 // This constructor should only be used from code that is *currently
230 // generating* the pools, to avoid an infinite loop.
231 EmissionCheckScope(MacroAssemblerInterface* masm,
232 size_t size,
233 SizePolicy size_policy,
234 PoolPolicy pool_policy) {
235 Open(masm, size, size_policy, pool_policy);
236 }
237
238 MacroAssemblerInterface* masm_;
239 PoolPolicy pool_policy_;
240};
241
Alexandre Rames07d1aa52016-10-25 17:20:51 +0100242// Use this scope when you need a one-to-one mapping between methods and
243// instructions. This scope will:
244// - Do the same as `EmissionCheckScope`.
245// - Block access to the MacroAssemblerInterface (using run-time assertions).
246class ExactAssemblyScope : public EmissionCheckScope {
247 public:
248 // This constructor implicitly calls `Open` (when `masm` is not `NULL`) to
249 // initialise the scope, so it is ready to use immediately after it has been
250 // constructed.
251 ExactAssemblyScope(MacroAssemblerInterface* masm,
252 size_t size,
Pierre Langlois45262d62017-01-12 15:27:32 +0000253 SizePolicy size_policy = kExactSize) {
254 Open(masm, size, size_policy);
Alexandre Rames07d1aa52016-10-25 17:20:51 +0100255 }
256
257 // This constructor does not implicitly initialise the scope. Instead, the
258 // user is required to explicitly call the `Open` function before using the
259 // scope.
260 ExactAssemblyScope() {}
261
Pierre Langlois45262d62017-01-12 15:27:32 +0000262 virtual ~ExactAssemblyScope() { Close(); }
263
264 void Open(MacroAssemblerInterface* masm,
265 size_t size,
266 SizePolicy size_policy = kExactSize) {
267 Open(masm, size, size_policy, kBlockPools);
268 }
269
270 void Close() {
271 if (!initialised_) {
272 return;
273 }
274 if (masm_ == NULL) {
275 // Nothing to do.
276 return;
277 }
Alexandre Rames07d1aa52016-10-25 17:20:51 +0100278#ifdef VIXL_DEBUG
Scott Wakelingc521a8b2016-11-17 14:42:07 +0000279 masm_->SetAllowMacroInstructions(previous_allow_macro_assembler_);
Pierre Langlois45262d62017-01-12 15:27:32 +0000280#else
281 USE(previous_allow_macro_assembler_);
Alexandre Rames07d1aa52016-10-25 17:20:51 +0100282#endif
Pierre Langlois45262d62017-01-12 15:27:32 +0000283 EmissionCheckScope::Close();
Alexandre Rames07d1aa52016-10-25 17:20:51 +0100284 }
285
286 protected:
287 // This protected constructor allows overriding the pool policy. It is
288 // available to allow this scope to be used in code that handles generation
289 // of pools.
290 ExactAssemblyScope(MacroAssemblerInterface* masm,
291 size_t size,
292 SizePolicy assert_policy,
Pierre Langlois45262d62017-01-12 15:27:32 +0000293 PoolPolicy pool_policy) {
294 Open(masm, size, assert_policy, pool_policy);
295 }
296
297 void Open(MacroAssemblerInterface* masm,
298 size_t size,
299 SizePolicy size_policy,
300 PoolPolicy pool_policy) {
301 VIXL_ASSERT(size_policy != kNoAssert);
302 if (masm == NULL) {
303 // Nothing to do.
304 return;
305 }
306 // Rely on EmissionCheckScope::Open to initialise `masm_` and
307 // `pool_policy_`.
308 EmissionCheckScope::Open(masm, size, size_policy, pool_policy);
Alexandre Rames07d1aa52016-10-25 17:20:51 +0100309#ifdef VIXL_DEBUG
310 previous_allow_macro_assembler_ = masm->AllowMacroInstructions();
311 masm->SetAllowMacroInstructions(false);
312#endif
313 }
314
315 private:
316 bool previous_allow_macro_assembler_;
317};
318
Alexandre Ramesc0b25f22016-10-19 13:53:55 +0100319
Alexandre Rames9dd6fa32016-10-12 13:26:54 +0100320} // namespace vixl
321
322#endif // VIXL_CODE_GENERATION_SCOPES_H_