blob: 4fdfe1a5bc1c6f351cafaa94c8f635f081b25565 [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
166 enum PoolPolicy { kIgnorePools, kCheckPools };
167
168 void Open(MacroAssemblerInterface* masm,
169 size_t size,
170 SizePolicy size_policy = kMaximumSize) {
171 Open(masm, size, size_policy, kCheckPools);
172 }
173
174 void Close() {
175 if (!initialised_) {
176 return;
177 }
178 if (masm_ == NULL) {
179 // Nothing to do.
180 return;
181 }
182 if (pool_policy_ == kCheckPools) {
183 masm_->ReleasePools();
184 }
185 CodeBufferCheckScope::Close();
186 VIXL_ASSERT(!initialised_);
187 }
188
189 protected:
190 void Open(MacroAssemblerInterface* masm,
191 size_t size,
192 SizePolicy size_policy,
193 PoolPolicy pool_policy) {
194 if (masm == NULL) {
195 // Nothing to do.
196 // We may reach this point in a context of conditional code generation.
197 // See `aarch64::MacroAssembler::MoveImmediateHelper()` for an example.
198 return;
199 }
200 masm_ = masm;
201 pool_policy_ = pool_policy;
202 if (pool_policy_ == kCheckPools) {
203 // To avoid duplicating the work to check that enough space is available
204 // in the buffer, do not use the more generic `EnsureEmitFor()`. It is
205 // done below when opening `CodeBufferCheckScope`.
206 masm->EnsureEmitPoolsFor(size);
207 masm->BlockPools();
208 }
209 // The buffer should be checked *after* we emit the pools.
Alexandre Rames8d191ab2016-11-29 11:23:27 +0000210 CodeBufferCheckScope::Open(masm->AsAssemblerBase(),
Alexandre Ramesc0b25f22016-10-19 13:53:55 +0100211 size,
212 kReserveBufferSpace,
213 size_policy);
214 VIXL_ASSERT(initialised_);
215 }
216
217 // This constructor should only be used from code that is *currently
218 // generating* the pools, to avoid an infinite loop.
219 EmissionCheckScope(MacroAssemblerInterface* masm,
220 size_t size,
221 SizePolicy size_policy,
222 PoolPolicy pool_policy) {
223 Open(masm, size, size_policy, pool_policy);
224 }
225
226 MacroAssemblerInterface* masm_;
227 PoolPolicy pool_policy_;
228};
229
Alexandre Rames07d1aa52016-10-25 17:20:51 +0100230// Use this scope when you need a one-to-one mapping between methods and
231// instructions. This scope will:
232// - Do the same as `EmissionCheckScope`.
233// - Block access to the MacroAssemblerInterface (using run-time assertions).
234class ExactAssemblyScope : public EmissionCheckScope {
235 public:
236 // This constructor implicitly calls `Open` (when `masm` is not `NULL`) to
237 // initialise the scope, so it is ready to use immediately after it has been
238 // constructed.
239 ExactAssemblyScope(MacroAssemblerInterface* masm,
240 size_t size,
241 SizePolicy assert_policy = kExactSize)
242 : EmissionCheckScope(masm, size, assert_policy) {
243 VIXL_ASSERT(assert_policy != kNoAssert);
244#ifdef VIXL_DEBUG
245 previous_allow_macro_assembler_ = masm->AllowMacroInstructions();
246 masm->SetAllowMacroInstructions(false);
247#else
248 USE(previous_allow_macro_assembler_);
249#endif
250 }
251
252 // This constructor does not implicitly initialise the scope. Instead, the
253 // user is required to explicitly call the `Open` function before using the
254 // scope.
255 ExactAssemblyScope() {}
256
257 virtual ~ExactAssemblyScope() {
258#ifdef VIXL_DEBUG
Scott Wakelingc521a8b2016-11-17 14:42:07 +0000259 masm_->SetAllowMacroInstructions(previous_allow_macro_assembler_);
Alexandre Rames07d1aa52016-10-25 17:20:51 +0100260#endif
261 }
262
263 protected:
264 // This protected constructor allows overriding the pool policy. It is
265 // available to allow this scope to be used in code that handles generation
266 // of pools.
267 ExactAssemblyScope(MacroAssemblerInterface* masm,
268 size_t size,
269 SizePolicy assert_policy,
270 PoolPolicy pool_policy)
271 : EmissionCheckScope(masm, size, assert_policy, pool_policy) {
272 VIXL_ASSERT(assert_policy != kNoAssert);
273#ifdef VIXL_DEBUG
274 previous_allow_macro_assembler_ = masm->AllowMacroInstructions();
275 masm->SetAllowMacroInstructions(false);
276#endif
277 }
278
279 private:
280 bool previous_allow_macro_assembler_;
281};
282
Alexandre Ramesc0b25f22016-10-19 13:53:55 +0100283
Alexandre Rames9dd6fa32016-10-12 13:26:54 +0100284} // namespace vixl
285
286#endif // VIXL_CODE_GENERATION_SCOPES_H_