• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
67   CodeBufferCheckScope(internal::AssemblerBase* assembler,
68                        size_t size,
69                        BufferSpacePolicy check_policy = kReserveBufferSpace,
70                        SizePolicy size_policy = kMaximumSize)
assembler_(NULL)71       : assembler_(NULL), initialised_(false) {
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() : assembler_(NULL), initialised_(false) {
79     // Nothing to do.
80   }
81 
~CodeBufferCheckScope()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);
91     assembler_ = assembler;
92     if (check_policy == kReserveBufferSpace) {
93       assembler->GetBuffer()->EnsureSpaceFor(size);
94     }
95 #ifdef VIXL_DEBUG
96     limit_ = assembler_->GetSizeOfCodeGenerated() + size;
97     assert_policy_ = size_policy;
98     previous_allow_assembler_ = assembler_->AllowAssembler();
99     assembler_->SetAllowAssembler(true);
100 #else
101     USE(size_policy);
102 #endif
103     initialised_ = true;
104   }
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.
Close()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     }
126 #endif
127     initialised_ = false;
128   }
129 
130  protected:
131   internal::AssemblerBase* assembler_;
132   SizePolicy assert_policy_;
133   size_t limit_;
134   bool previous_allow_assembler_;
135   bool initialised_;
136 };
137 
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.
148 class 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.
EmissionCheckScope()162   EmissionCheckScope() {}
163 
~EmissionCheckScope()164   virtual ~EmissionCheckScope() { Close(); }
165 
166   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   };
176 
177   void Open(MacroAssemblerInterface* masm,
178             size_t size,
179             SizePolicy size_policy = kMaximumSize) {
180     Open(masm, size, size_policy, kBlockPools);
181   }
182 
Close()183   void Close() {
184     if (!initialised_) {
185       return;
186     }
187     if (masm_ == NULL) {
188       // Nothing to do.
189       return;
190     }
191     // Perform the opposite of `Open`, which is:
192     //   - Check the code generation limit was not exceeded.
193     //   - Release the pools.
194     CodeBufferCheckScope::Close();
195     if (pool_policy_ == kBlockPools) {
196       masm_->ReleasePools();
197     }
198     VIXL_ASSERT(!initialised_);
199   }
200 
201  protected:
Open(MacroAssemblerInterface * masm,size_t size,SizePolicy size_policy,PoolPolicy pool_policy)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;
214     if (pool_policy_ == kBlockPools) {
215       // 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.
222     CodeBufferCheckScope::Open(masm->AsAssemblerBase(),
223                                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.
EmissionCheckScope(MacroAssemblerInterface * masm,size_t size,SizePolicy size_policy,PoolPolicy pool_policy)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_{nullptr};
239   PoolPolicy pool_policy_;
240 };
241 
242 // 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).
246 class 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,
253                      SizePolicy size_policy = kExactSize) {
254     Open(masm, size, size_policy);
255   }
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.
ExactAssemblyScope()260   ExactAssemblyScope() {}
261 
~ExactAssemblyScope()262   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 
Close()270   void Close() {
271     if (!initialised_) {
272       return;
273     }
274     if (masm_ == NULL) {
275       // Nothing to do.
276       return;
277     }
278 #ifdef VIXL_DEBUG
279     masm_->SetAllowMacroInstructions(previous_allow_macro_assembler_);
280 #else
281     USE(previous_allow_macro_assembler_);
282 #endif
283     EmissionCheckScope::Close();
284   }
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.
ExactAssemblyScope(MacroAssemblerInterface * masm,size_t size,SizePolicy assert_policy,PoolPolicy pool_policy)290   ExactAssemblyScope(MacroAssemblerInterface* masm,
291                      size_t size,
292                      SizePolicy assert_policy,
293                      PoolPolicy pool_policy) {
294     Open(masm, size, assert_policy, pool_policy);
295   }
296 
Open(MacroAssemblerInterface * masm,size_t size,SizePolicy size_policy,PoolPolicy pool_policy)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);
309 #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 
319 
320 }  // namespace vixl
321 
322 #endif  // VIXL_CODE_GENERATION_SCOPES_H_
323