19dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// Copyright 2016, VIXL authors
29dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// All rights reserved.
39dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames//
49dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// Redistribution and use in source and binary forms, with or without
59dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// modification, are permitted provided that the following conditions are met:
69dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames//
79dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames//   * Redistributions of source code must retain the above copyright notice,
89dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames//     this list of conditions and the following disclaimer.
99dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames//   * Redistributions in binary form must reproduce the above copyright notice,
109dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames//     this list of conditions and the following disclaimer in the documentation
119dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames//     and/or other materials provided with the distribution.
129dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames//   * Neither the name of ARM Limited nor the names of its contributors may be
139dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames//     used to endorse or promote products derived from this software without
149dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames//     specific prior written permission.
159dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames//
169dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
179dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
189dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
199dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
209dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
219dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
229dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
239dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
249dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
259dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
269dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
279dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
289dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames#ifndef VIXL_CODE_GENERATION_SCOPES_H_
299dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames#define VIXL_CODE_GENERATION_SCOPES_H_
309dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
319dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
329dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames#include "assembler-base-vixl.h"
33c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames#include "macro-assembler-interface.h"
349dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
359dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
369dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Ramesnamespace vixl {
379dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
389dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// This scope will:
399dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// - Allow code emission from the specified `Assembler`.
409dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// - Optionally reserve space in the `CodeBuffer` (if it is managed by VIXL).
419dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames// - Optionally, on destruction, check the size of the generated code.
429dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames//   (The size can be either exact or a maximum size.)
439dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Ramesclass CodeBufferCheckScope {
449dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames public:
459dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  // Tell whether or not the scope needs to ensure the associated CodeBuffer
469dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  // has enough space for the requested size.
479dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  enum BufferSpacePolicy {
489dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    kReserveBufferSpace,
499dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    kDontReserveBufferSpace,
509dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
519dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    // Deprecated, but kept for backward compatibility.
529dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    kCheck = kReserveBufferSpace,
539dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    kNoCheck = kDontReserveBufferSpace
549dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  };
559dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
569dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  // Tell whether or not the scope should assert the amount of code emitted
579dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  // within the scope is consistent with the requested amount.
589dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  enum SizePolicy {
599dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    kNoAssert,    // Do not check the size of the code emitted.
609dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    kExactSize,   // The code emitted must be exactly size bytes.
619dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    kMaximumSize  // The code emitted must be at most size bytes.
629dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  };
639dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
649dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  // This constructor implicitly calls `Open` to initialise the scope
659dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  // (`assembler` must not be `NULL`), so it is ready to use immediately after
669dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  // it has been constructed.
679dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  CodeBufferCheckScope(internal::AssemblerBase* assembler,
689dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames                       size_t size,
699dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames                       BufferSpacePolicy check_policy = kReserveBufferSpace,
709dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames                       SizePolicy size_policy = kMaximumSize)
71c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      : assembler_(NULL), initialised_(false) {
729dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    Open(assembler, size, check_policy, size_policy);
739dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  }
749dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
759dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  // This constructor does not implicitly initialise the scope. Instead, the
769dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  // user is required to explicitly call the `Open` function before using the
779dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  // scope.
78c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  CodeBufferCheckScope() : assembler_(NULL), initialised_(false) {
799dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    // Nothing to do.
809dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  }
819dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
829dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  virtual ~CodeBufferCheckScope() { Close(); }
839dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
849dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  // This function performs the actual initialisation work.
859dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  void Open(internal::AssemblerBase* assembler,
869dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames            size_t size,
879dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames            BufferSpacePolicy check_policy = kReserveBufferSpace,
889dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames            SizePolicy size_policy = kMaximumSize) {
899dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    VIXL_ASSERT(!initialised_);
909dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    VIXL_ASSERT(assembler != NULL);
91c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    assembler_ = assembler;
929dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    if (check_policy == kReserveBufferSpace) {
939dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames      assembler->GetBuffer()->EnsureSpaceFor(size);
949dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    }
959dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames#ifdef VIXL_DEBUG
969dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    limit_ = assembler_->GetSizeOfCodeGenerated() + size;
979dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    assert_policy_ = size_policy;
989dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    previous_allow_assembler_ = assembler_->AllowAssembler();
999dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    assembler_->SetAllowAssembler(true);
1009dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames#else
1019dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    USE(size_policy);
1029dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames#endif
103c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    initialised_ = true;
1049dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  }
1059dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
1069dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  // This function performs the cleaning-up work. It must succeed even if the
1079dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  // scope has not been opened. It is safe to call multiple times.
1089dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  void Close() {
1099dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames#ifdef VIXL_DEBUG
1109dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    if (!initialised_) {
1119dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames      return;
1129dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    }
1139dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    assembler_->SetAllowAssembler(previous_allow_assembler_);
1149dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    switch (assert_policy_) {
1159dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames      case kNoAssert:
1169dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames        break;
1179dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames      case kExactSize:
1189dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames        VIXL_ASSERT(assembler_->GetSizeOfCodeGenerated() == limit_);
1199dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames        break;
1209dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames      case kMaximumSize:
1219dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames        VIXL_ASSERT(assembler_->GetSizeOfCodeGenerated() <= limit_);
1229dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames        break;
1239dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames      default:
1249dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames        VIXL_UNREACHABLE();
1259dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames    }
1269dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames#endif
127c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    initialised_ = false;
1289dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  }
1299dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
1309dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames protected:
1319dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  internal::AssemblerBase* assembler_;
1329dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  SizePolicy assert_policy_;
1339dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  size_t limit_;
1349dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  bool previous_allow_assembler_;
1359dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames  bool initialised_;
1369dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames};
137c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames
138c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames
139c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames// This scope will:
140c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames// - Do the same as `CodeBufferCheckSCope`, but:
141c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames//   - If managed by VIXL, always reserve space in the `CodeBuffer`.
142c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames//   - Always check the size (exact or maximum) of the generated code on
143c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames//     destruction.
144c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames// - Emit pools if the specified size would push them out of range.
145c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames// - Block pools emission for the duration of the scope.
146c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames// This scope allows the `Assembler` and `MacroAssembler` to be freely and
147c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames// safely mixed for its duration.
148c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Ramesclass EmissionCheckScope : public CodeBufferCheckScope {
149c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames public:
150c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  // This constructor implicitly calls `Open` (when `masm` is not `NULL`) to
151c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  // initialise the scope, so it is ready to use immediately after it has been
152c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  // constructed.
153c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  EmissionCheckScope(MacroAssemblerInterface* masm,
154c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames                     size_t size,
155c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames                     SizePolicy size_policy = kMaximumSize) {
156c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    Open(masm, size, size_policy);
157c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  }
158c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames
159c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  // This constructor does not implicitly initialise the scope. Instead, the
160c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  // user is required to explicitly call the `Open` function before using the
161c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  // scope.
162c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  EmissionCheckScope() {}
163c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames
164c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  virtual ~EmissionCheckScope() { Close(); }
165c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames
166d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois  enum PoolPolicy {
167d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois    // Do not forbid pool emission inside the scope. Pools will not be emitted
168d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois    // on `Open` either.
169d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois    kIgnorePools,
170d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois    // Force pools to be generated on `Open` if necessary and block their
171d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois    // emission inside the scope.
172d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois    kBlockPools,
173d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois    // Deprecated, but kept for backward compatibility.
174d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois    kCheckPools = kBlockPools
175d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois  };
176c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames
177c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  void Open(MacroAssemblerInterface* masm,
178c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames            size_t size,
179c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames            SizePolicy size_policy = kMaximumSize) {
180d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois    Open(masm, size, size_policy, kBlockPools);
181c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  }
182c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames
183c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  void Close() {
184c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    if (!initialised_) {
185c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      return;
186c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    }
187c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    if (masm_ == NULL) {
188c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      // Nothing to do.
189c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      return;
190c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    }
1916ee0978e4e0462cdaa4c92591e9a36fdeaef704dPierre Langlois    // Perform the opposite of `Open`, which is:
1926ee0978e4e0462cdaa4c92591e9a36fdeaef704dPierre Langlois    //   - Check the code generation limit was not exceeded.
1936ee0978e4e0462cdaa4c92591e9a36fdeaef704dPierre Langlois    //   - Release the pools.
1946ee0978e4e0462cdaa4c92591e9a36fdeaef704dPierre Langlois    CodeBufferCheckScope::Close();
195d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois    if (pool_policy_ == kBlockPools) {
196c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      masm_->ReleasePools();
197c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    }
198c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    VIXL_ASSERT(!initialised_);
199c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  }
200c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames
201c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames protected:
202c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  void Open(MacroAssemblerInterface* masm,
203c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames            size_t size,
204c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames            SizePolicy size_policy,
205c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames            PoolPolicy pool_policy) {
206c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    if (masm == NULL) {
207c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      // Nothing to do.
208c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      // We may reach this point in a context of conditional code generation.
209c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      // See `aarch64::MacroAssembler::MoveImmediateHelper()` for an example.
210c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      return;
211c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    }
212c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    masm_ = masm;
213c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    pool_policy_ = pool_policy;
214d56f609907e454dd41bb8b2d98e078e69c4feafaPierre Langlois    if (pool_policy_ == kBlockPools) {
215c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      // To avoid duplicating the work to check that enough space is available
216c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      // in the buffer, do not use the more generic `EnsureEmitFor()`. It is
217c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      // done below when opening `CodeBufferCheckScope`.
218c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      masm->EnsureEmitPoolsFor(size);
219c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames      masm->BlockPools();
220c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    }
221c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    // The buffer should be checked *after* we emit the pools.
2228d191abf32edf41421f68f35585e4fce8da4d50cAlexandre Rames    CodeBufferCheckScope::Open(masm->AsAssemblerBase(),
223c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames                               size,
224c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames                               kReserveBufferSpace,
225c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames                               size_policy);
226c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    VIXL_ASSERT(initialised_);
227c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  }
228c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames
229c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  // This constructor should only be used from code that is *currently
230c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  // generating* the pools, to avoid an infinite loop.
231c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  EmissionCheckScope(MacroAssemblerInterface* masm,
232c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames                     size_t size,
233c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames                     SizePolicy size_policy,
234c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames                     PoolPolicy pool_policy) {
235c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames    Open(masm, size, size_policy, pool_policy);
236c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  }
237c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames
238c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  MacroAssemblerInterface* masm_;
239c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames  PoolPolicy pool_policy_;
240c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames};
241c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames
24207d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames// Use this scope when you need a one-to-one mapping between methods and
24307d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames// instructions. This scope will:
24407d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames// - Do the same as `EmissionCheckScope`.
24507d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames// - Block access to the MacroAssemblerInterface (using run-time assertions).
24607d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Ramesclass ExactAssemblyScope : public EmissionCheckScope {
24707d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames public:
24807d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  // This constructor implicitly calls `Open` (when `masm` is not `NULL`) to
24907d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  // initialise the scope, so it is ready to use immediately after it has been
25007d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  // constructed.
25107d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  ExactAssemblyScope(MacroAssemblerInterface* masm,
25207d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames                     size_t size,
25345262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois                     SizePolicy size_policy = kExactSize) {
25445262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    Open(masm, size, size_policy);
25507d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  }
25607d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames
25707d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  // This constructor does not implicitly initialise the scope. Instead, the
25807d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  // user is required to explicitly call the `Open` function before using the
25907d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  // scope.
26007d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  ExactAssemblyScope() {}
26107d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames
26245262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois  virtual ~ExactAssemblyScope() { Close(); }
26345262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois
26445262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois  void Open(MacroAssemblerInterface* masm,
26545262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois            size_t size,
26645262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois            SizePolicy size_policy = kExactSize) {
26745262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    Open(masm, size, size_policy, kBlockPools);
26845262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois  }
26945262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois
27045262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois  void Close() {
27145262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    if (!initialised_) {
27245262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois      return;
27345262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    }
27445262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    if (masm_ == NULL) {
27545262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois      // Nothing to do.
27645262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois      return;
27745262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    }
27807d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames#ifdef VIXL_DEBUG
279c521a8b486f0da6a9d7bb7940766a2eca542cd98Scott Wakeling    masm_->SetAllowMacroInstructions(previous_allow_macro_assembler_);
28045262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois#else
28145262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    USE(previous_allow_macro_assembler_);
28207d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames#endif
28345262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    EmissionCheckScope::Close();
28407d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  }
28507d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames
28607d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames protected:
28707d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  // This protected constructor allows overriding the pool policy. It is
28807d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  // available to allow this scope to be used in code that handles generation
28907d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  // of pools.
29007d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  ExactAssemblyScope(MacroAssemblerInterface* masm,
29107d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames                     size_t size,
29207d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames                     SizePolicy assert_policy,
29345262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois                     PoolPolicy pool_policy) {
29445262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    Open(masm, size, assert_policy, pool_policy);
29545262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois  }
29645262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois
29745262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois  void Open(MacroAssemblerInterface* masm,
29845262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois            size_t size,
29945262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois            SizePolicy size_policy,
30045262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois            PoolPolicy pool_policy) {
30145262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    VIXL_ASSERT(size_policy != kNoAssert);
30245262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    if (masm == NULL) {
30345262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois      // Nothing to do.
30445262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois      return;
30545262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    }
30645262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    // Rely on EmissionCheckScope::Open to initialise `masm_` and
30745262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    // `pool_policy_`.
30845262d6ba1f736aaebfa6f7ef50a3e83cd4e5e70Pierre Langlois    EmissionCheckScope::Open(masm, size, size_policy, pool_policy);
30907d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames#ifdef VIXL_DEBUG
31007d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames    previous_allow_macro_assembler_ = masm->AllowMacroInstructions();
31107d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames    masm->SetAllowMacroInstructions(false);
31207d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames#endif
31307d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  }
31407d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames
31507d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames private:
31607d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames  bool previous_allow_macro_assembler_;
31707d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames};
31807d1aa5b941ace15deb01e5df2c79e677039c4aeAlexandre Rames
319c0b25f28106fbbbf8880e0b259de1a639ea1e73fAlexandre Rames
3209dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames}  // namespace vixl
3219dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames
3229dd6fa37dbb79f62177aebd04d7e945ce1dc3108Alexandre Rames#endif  // VIXL_CODE_GENERATION_SCOPES_H_
323