1 // 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"
33 #include "macro-assembler-interface.h"
34 
35 
36 namespace 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.)
43 class 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.
CodeBufferCheckScope(internal::AssemblerBase* assembler, size_t size, BufferSpacePolicy check_policy = kReserveBufferSpace, SizePolicy size_policy = kMaximumSize)67   CodeBufferCheckScope(internal::AssemblerBase* assembler,
68                        size_t size,
69                        BufferSpacePolicy check_policy = kReserveBufferSpace,
70                        SizePolicy size_policy = kMaximumSize)
71       : CodeBufferCheckScope() {
72     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.
CodeBufferCheckScope()78   CodeBufferCheckScope()
79       : assembler_(NULL),
80         assert_policy_(kMaximumSize),
81         limit_(0),
82         previous_allow_assembler_(false),
83         initialised_(false) {
84     // Nothing to do.
85   }
86 
~CodeBufferCheckScope()87   virtual ~CodeBufferCheckScope() { Close(); }
88 
89   // This function performs the actual initialisation work.
Open(internal::AssemblerBase* assembler, size_t size, BufferSpacePolicy check_policy = kReserveBufferSpace, SizePolicy size_policy = kMaximumSize)90   void Open(internal::AssemblerBase* assembler,
91             size_t size,
92             BufferSpacePolicy check_policy = kReserveBufferSpace,
93             SizePolicy size_policy = kMaximumSize) {
94     VIXL_ASSERT(!initialised_);
95     VIXL_ASSERT(assembler != NULL);
96     assembler_ = assembler;
97     if (check_policy == kReserveBufferSpace) {
98       assembler->GetBuffer()->EnsureSpaceFor(size);
99     }
100 #ifdef VIXL_DEBUG
101     limit_ = assembler_->GetSizeOfCodeGenerated() + size;
102     assert_policy_ = size_policy;
103     previous_allow_assembler_ = assembler_->AllowAssembler();
104     assembler_->SetAllowAssembler(true);
105 #else
106     USE(size_policy);
107 #endif
108     initialised_ = true;
109   }
110 
111   // This function performs the cleaning-up work. It must succeed even if the
112   // scope has not been opened. It is safe to call multiple times.
Close()113   void Close() {
114 #ifdef VIXL_DEBUG
115     if (!initialised_) {
116       return;
117     }
118     assembler_->SetAllowAssembler(previous_allow_assembler_);
119     switch (assert_policy_) {
120       case kNoAssert:
121         break;
122       case kExactSize:
123         VIXL_ASSERT(assembler_->GetSizeOfCodeGenerated() == limit_);
124         break;
125       case kMaximumSize:
126         VIXL_ASSERT(assembler_->GetSizeOfCodeGenerated() <= limit_);
127         break;
128       default:
129         VIXL_UNREACHABLE();
130     }
131 #endif
132     initialised_ = false;
133   }
134 
135  protected:
136   internal::AssemblerBase* assembler_;
137   SizePolicy assert_policy_;
138   size_t limit_;
139   bool previous_allow_assembler_;
140   bool initialised_;
141 };
142 
143 
144 // This scope will:
145 // - Do the same as `CodeBufferCheckSCope`, but:
146 //   - If managed by VIXL, always reserve space in the `CodeBuffer`.
147 //   - Always check the size (exact or maximum) of the generated code on
148 //     destruction.
149 // - Emit pools if the specified size would push them out of range.
150 // - Block pools emission for the duration of the scope.
151 // This scope allows the `Assembler` and `MacroAssembler` to be freely and
152 // safely mixed for its duration.
153 class EmissionCheckScope : public CodeBufferCheckScope {
154  public:
155   // This constructor implicitly calls `Open` (when `masm` is not `NULL`) to
156   // initialise the scope, so it is ready to use immediately after it has been
157   // constructed.
EmissionCheckScope(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy = kMaximumSize)158   EmissionCheckScope(MacroAssemblerInterface* masm,
159                      size_t size,
160                      SizePolicy size_policy = kMaximumSize)
161       : EmissionCheckScope() {
162     Open(masm, size, size_policy);
163   }
164 
165   // This constructor does not implicitly initialise the scope. Instead, the
166   // user is required to explicitly call the `Open` function before using the
167   // scope.
EmissionCheckScope()168   EmissionCheckScope() : masm_(nullptr), pool_policy_(kBlockPools) {}
169 
~EmissionCheckScope()170   virtual ~EmissionCheckScope() { Close(); }
171 
172   enum PoolPolicy {
173     // Do not forbid pool emission inside the scope. Pools will not be emitted
174     // on `Open` either.
175     kIgnorePools,
176     // Force pools to be generated on `Open` if necessary and block their
177     // emission inside the scope.
178     kBlockPools,
179     // Deprecated, but kept for backward compatibility.
180     kCheckPools = kBlockPools
181   };
182 
Open(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy = kMaximumSize)183   void Open(MacroAssemblerInterface* masm,
184             size_t size,
185             SizePolicy size_policy = kMaximumSize) {
186     Open(masm, size, size_policy, kBlockPools);
187   }
188 
Close()189   void Close() {
190     if (!initialised_) {
191       return;
192     }
193     if (masm_ == NULL) {
194       // Nothing to do.
195       return;
196     }
197     // Perform the opposite of `Open`, which is:
198     //   - Check the code generation limit was not exceeded.
199     //   - Release the pools.
200     CodeBufferCheckScope::Close();
201     if (pool_policy_ == kBlockPools) {
202       masm_->ReleasePools();
203     }
204     VIXL_ASSERT(!initialised_);
205   }
206 
207  protected:
Open(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy, PoolPolicy pool_policy)208   void Open(MacroAssemblerInterface* masm,
209             size_t size,
210             SizePolicy size_policy,
211             PoolPolicy pool_policy) {
212     if (masm == NULL) {
213       // Nothing to do.
214       // We may reach this point in a context of conditional code generation.
215       // See `aarch64::MacroAssembler::MoveImmediateHelper()` for an example.
216       return;
217     }
218     masm_ = masm;
219     pool_policy_ = pool_policy;
220     if (pool_policy_ == kBlockPools) {
221       // To avoid duplicating the work to check that enough space is available
222       // in the buffer, do not use the more generic `EnsureEmitFor()`. It is
223       // done below when opening `CodeBufferCheckScope`.
224       masm->EnsureEmitPoolsFor(size);
225       masm->BlockPools();
226     }
227     // The buffer should be checked *after* we emit the pools.
228     CodeBufferCheckScope::Open(masm->AsAssemblerBase(),
229                                size,
230                                kReserveBufferSpace,
231                                size_policy);
232     VIXL_ASSERT(initialised_);
233   }
234 
235   // This constructor should only be used from code that is *currently
236   // generating* the pools, to avoid an infinite loop.
EmissionCheckScope(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy, PoolPolicy pool_policy)237   EmissionCheckScope(MacroAssemblerInterface* masm,
238                      size_t size,
239                      SizePolicy size_policy,
240                      PoolPolicy pool_policy) {
241     Open(masm, size, size_policy, pool_policy);
242   }
243 
244   MacroAssemblerInterface* masm_{nullptr};
245   PoolPolicy pool_policy_;
246 };
247 
248 // Use this scope when you need a one-to-one mapping between methods and
249 // instructions. This scope will:
250 // - Do the same as `EmissionCheckScope`.
251 // - Block access to the MacroAssemblerInterface (using run-time assertions).
252 class ExactAssemblyScope : public EmissionCheckScope {
253  public:
254   // This constructor implicitly calls `Open` (when `masm` is not `NULL`) to
255   // initialise the scope, so it is ready to use immediately after it has been
256   // constructed.
ExactAssemblyScope(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy = kExactSize)257   ExactAssemblyScope(MacroAssemblerInterface* masm,
258                      size_t size,
259                      SizePolicy size_policy = kExactSize)
260       : ExactAssemblyScope() {
261     Open(masm, size, size_policy);
262   }
263 
264   // This constructor does not implicitly initialise the scope. Instead, the
265   // user is required to explicitly call the `Open` function before using the
266   // scope.
ExactAssemblyScope()267   ExactAssemblyScope() : previous_allow_macro_assembler_(false) {}
268 
~ExactAssemblyScope()269   virtual ~ExactAssemblyScope() { Close(); }
270 
Open(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy = kExactSize)271   void Open(MacroAssemblerInterface* masm,
272             size_t size,
273             SizePolicy size_policy = kExactSize) {
274     Open(masm, size, size_policy, kBlockPools);
275   }
276 
Close()277   void Close() {
278     if (!initialised_) {
279       return;
280     }
281     if (masm_ == NULL) {
282       // Nothing to do.
283       return;
284     }
285 #ifdef VIXL_DEBUG
286     masm_->SetAllowMacroInstructions(previous_allow_macro_assembler_);
287 #else
288     USE(previous_allow_macro_assembler_);
289 #endif
290     EmissionCheckScope::Close();
291   }
292 
293  protected:
294   // This protected constructor allows overriding the pool policy. It is
295   // available to allow this scope to be used in code that handles generation
296   // of pools.
ExactAssemblyScope(MacroAssemblerInterface* masm, size_t size, SizePolicy assert_policy, PoolPolicy pool_policy)297   ExactAssemblyScope(MacroAssemblerInterface* masm,
298                      size_t size,
299                      SizePolicy assert_policy,
300                      PoolPolicy pool_policy) {
301     Open(masm, size, assert_policy, pool_policy);
302   }
303 
Open(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy, PoolPolicy pool_policy)304   void Open(MacroAssemblerInterface* masm,
305             size_t size,
306             SizePolicy size_policy,
307             PoolPolicy pool_policy) {
308     VIXL_ASSERT(size_policy != kNoAssert);
309     if (masm == NULL) {
310       // Nothing to do.
311       return;
312     }
313     // Rely on EmissionCheckScope::Open to initialise `masm_` and
314     // `pool_policy_`.
315     EmissionCheckScope::Open(masm, size, size_policy, pool_policy);
316 #ifdef VIXL_DEBUG
317     previous_allow_macro_assembler_ = masm->AllowMacroInstructions();
318     masm->SetAllowMacroInstructions(false);
319 #endif
320   }
321 
322  private:
323   bool previous_allow_macro_assembler_;
324 };
325 
326 
327 }  // namespace vixl
328 
329 #endif  // VIXL_CODE_GENERATION_SCOPES_H_
330