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