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