| // Copyright 2016, VIXL authors |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // * Redistributions of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // * Neither the name of ARM Limited nor the names of its contributors may be |
| // used to endorse or promote products derived from this software without |
| // specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND |
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| |
| #ifndef VIXL_CODE_GENERATION_SCOPES_H_ |
| #define VIXL_CODE_GENERATION_SCOPES_H_ |
| |
| |
| #include "assembler-base-vixl.h" |
| #include "macro-assembler-interface.h" |
| |
| |
| namespace vixl { |
| |
| // This scope will: |
| // - Allow code emission from the specified `Assembler`. |
| // - Optionally reserve space in the `CodeBuffer` (if it is managed by VIXL). |
| // - Optionally, on destruction, check the size of the generated code. |
| // (The size can be either exact or a maximum size.) |
| class CodeBufferCheckScope { |
| public: |
| // Tell whether or not the scope needs to ensure the associated CodeBuffer |
| // has enough space for the requested size. |
| enum BufferSpacePolicy { |
| kReserveBufferSpace, |
| kDontReserveBufferSpace, |
| |
| // Deprecated, but kept for backward compatibility. |
| kCheck = kReserveBufferSpace, |
| kNoCheck = kDontReserveBufferSpace |
| }; |
| |
| // Tell whether or not the scope should assert the amount of code emitted |
| // within the scope is consistent with the requested amount. |
| enum SizePolicy { |
| kNoAssert, // Do not check the size of the code emitted. |
| kExactSize, // The code emitted must be exactly size bytes. |
| kMaximumSize // The code emitted must be at most size bytes. |
| }; |
| |
| // This constructor implicitly calls `Open` to initialise the scope |
| // (`assembler` must not be `NULL`), so it is ready to use immediately after |
| // it has been constructed. |
| CodeBufferCheckScope(internal::AssemblerBase* assembler, |
| size_t size, |
| BufferSpacePolicy check_policy = kReserveBufferSpace, |
| SizePolicy size_policy = kMaximumSize) |
| : assembler_(NULL), initialised_(false) { |
| Open(assembler, size, check_policy, size_policy); |
| } |
| |
| // This constructor does not implicitly initialise the scope. Instead, the |
| // user is required to explicitly call the `Open` function before using the |
| // scope. |
| CodeBufferCheckScope() : assembler_(NULL), initialised_(false) { |
| // Nothing to do. |
| } |
| |
| virtual ~CodeBufferCheckScope() { Close(); } |
| |
| // This function performs the actual initialisation work. |
| void Open(internal::AssemblerBase* assembler, |
| size_t size, |
| BufferSpacePolicy check_policy = kReserveBufferSpace, |
| SizePolicy size_policy = kMaximumSize) { |
| VIXL_ASSERT(!initialised_); |
| VIXL_ASSERT(assembler != NULL); |
| assembler_ = assembler; |
| if (check_policy == kReserveBufferSpace) { |
| assembler->GetBuffer()->EnsureSpaceFor(size); |
| } |
| #ifdef VIXL_DEBUG |
| limit_ = assembler_->GetSizeOfCodeGenerated() + size; |
| assert_policy_ = size_policy; |
| previous_allow_assembler_ = assembler_->AllowAssembler(); |
| assembler_->SetAllowAssembler(true); |
| #else |
| USE(size_policy); |
| #endif |
| initialised_ = true; |
| } |
| |
| // This function performs the cleaning-up work. It must succeed even if the |
| // scope has not been opened. It is safe to call multiple times. |
| void Close() { |
| #ifdef VIXL_DEBUG |
| if (!initialised_) { |
| return; |
| } |
| assembler_->SetAllowAssembler(previous_allow_assembler_); |
| switch (assert_policy_) { |
| case kNoAssert: |
| break; |
| case kExactSize: |
| VIXL_ASSERT(assembler_->GetSizeOfCodeGenerated() == limit_); |
| break; |
| case kMaximumSize: |
| VIXL_ASSERT(assembler_->GetSizeOfCodeGenerated() <= limit_); |
| break; |
| default: |
| VIXL_UNREACHABLE(); |
| } |
| #endif |
| initialised_ = false; |
| } |
| |
| protected: |
| internal::AssemblerBase* assembler_; |
| SizePolicy assert_policy_; |
| size_t limit_; |
| bool previous_allow_assembler_; |
| bool initialised_; |
| }; |
| |
| |
| // This scope will: |
| // - Do the same as `CodeBufferCheckSCope`, but: |
| // - If managed by VIXL, always reserve space in the `CodeBuffer`. |
| // - Always check the size (exact or maximum) of the generated code on |
| // destruction. |
| // - Emit pools if the specified size would push them out of range. |
| // - Block pools emission for the duration of the scope. |
| // This scope allows the `Assembler` and `MacroAssembler` to be freely and |
| // safely mixed for its duration. |
| class EmissionCheckScope : public CodeBufferCheckScope { |
| public: |
| // This constructor implicitly calls `Open` (when `masm` is not `NULL`) to |
| // initialise the scope, so it is ready to use immediately after it has been |
| // constructed. |
| EmissionCheckScope(MacroAssemblerInterface* masm, |
| size_t size, |
| SizePolicy size_policy = kMaximumSize) { |
| Open(masm, size, size_policy); |
| } |
| |
| // This constructor does not implicitly initialise the scope. Instead, the |
| // user is required to explicitly call the `Open` function before using the |
| // scope. |
| EmissionCheckScope() {} |
| |
| virtual ~EmissionCheckScope() { Close(); } |
| |
| enum PoolPolicy { |
| // Do not forbid pool emission inside the scope. Pools will not be emitted |
| // on `Open` either. |
| kIgnorePools, |
| // Force pools to be generated on `Open` if necessary and block their |
| // emission inside the scope. |
| kBlockPools, |
| // Deprecated, but kept for backward compatibility. |
| kCheckPools = kBlockPools |
| }; |
| |
| void Open(MacroAssemblerInterface* masm, |
| size_t size, |
| SizePolicy size_policy = kMaximumSize) { |
| Open(masm, size, size_policy, kBlockPools); |
| } |
| |
| void Close() { |
| if (!initialised_) { |
| return; |
| } |
| if (masm_ == NULL) { |
| // Nothing to do. |
| return; |
| } |
| // Perform the opposite of `Open`, which is: |
| // - Check the code generation limit was not exceeded. |
| // - Release the pools. |
| CodeBufferCheckScope::Close(); |
| if (pool_policy_ == kBlockPools) { |
| masm_->ReleasePools(); |
| } |
| VIXL_ASSERT(!initialised_); |
| } |
| |
| protected: |
| void Open(MacroAssemblerInterface* masm, |
| size_t size, |
| SizePolicy size_policy, |
| PoolPolicy pool_policy) { |
| if (masm == NULL) { |
| // Nothing to do. |
| // We may reach this point in a context of conditional code generation. |
| // See `aarch64::MacroAssembler::MoveImmediateHelper()` for an example. |
| return; |
| } |
| masm_ = masm; |
| pool_policy_ = pool_policy; |
| if (pool_policy_ == kBlockPools) { |
| // To avoid duplicating the work to check that enough space is available |
| // in the buffer, do not use the more generic `EnsureEmitFor()`. It is |
| // done below when opening `CodeBufferCheckScope`. |
| masm->EnsureEmitPoolsFor(size); |
| masm->BlockPools(); |
| } |
| // The buffer should be checked *after* we emit the pools. |
| CodeBufferCheckScope::Open(masm->AsAssemblerBase(), |
| size, |
| kReserveBufferSpace, |
| size_policy); |
| VIXL_ASSERT(initialised_); |
| } |
| |
| // This constructor should only be used from code that is *currently |
| // generating* the pools, to avoid an infinite loop. |
| EmissionCheckScope(MacroAssemblerInterface* masm, |
| size_t size, |
| SizePolicy size_policy, |
| PoolPolicy pool_policy) { |
| Open(masm, size, size_policy, pool_policy); |
| } |
| |
| MacroAssemblerInterface* masm_; |
| PoolPolicy pool_policy_; |
| }; |
| |
| // Use this scope when you need a one-to-one mapping between methods and |
| // instructions. This scope will: |
| // - Do the same as `EmissionCheckScope`. |
| // - Block access to the MacroAssemblerInterface (using run-time assertions). |
| class ExactAssemblyScope : public EmissionCheckScope { |
| public: |
| // This constructor implicitly calls `Open` (when `masm` is not `NULL`) to |
| // initialise the scope, so it is ready to use immediately after it has been |
| // constructed. |
| ExactAssemblyScope(MacroAssemblerInterface* masm, |
| size_t size, |
| SizePolicy size_policy = kExactSize) { |
| Open(masm, size, size_policy); |
| } |
| |
| // This constructor does not implicitly initialise the scope. Instead, the |
| // user is required to explicitly call the `Open` function before using the |
| // scope. |
| ExactAssemblyScope() {} |
| |
| virtual ~ExactAssemblyScope() { Close(); } |
| |
| void Open(MacroAssemblerInterface* masm, |
| size_t size, |
| SizePolicy size_policy = kExactSize) { |
| Open(masm, size, size_policy, kBlockPools); |
| } |
| |
| void Close() { |
| if (!initialised_) { |
| return; |
| } |
| if (masm_ == NULL) { |
| // Nothing to do. |
| return; |
| } |
| #ifdef VIXL_DEBUG |
| masm_->SetAllowMacroInstructions(previous_allow_macro_assembler_); |
| #else |
| USE(previous_allow_macro_assembler_); |
| #endif |
| EmissionCheckScope::Close(); |
| } |
| |
| protected: |
| // This protected constructor allows overriding the pool policy. It is |
| // available to allow this scope to be used in code that handles generation |
| // of pools. |
| ExactAssemblyScope(MacroAssemblerInterface* masm, |
| size_t size, |
| SizePolicy assert_policy, |
| PoolPolicy pool_policy) { |
| Open(masm, size, assert_policy, pool_policy); |
| } |
| |
| void Open(MacroAssemblerInterface* masm, |
| size_t size, |
| SizePolicy size_policy, |
| PoolPolicy pool_policy) { |
| VIXL_ASSERT(size_policy != kNoAssert); |
| if (masm == NULL) { |
| // Nothing to do. |
| return; |
| } |
| // Rely on EmissionCheckScope::Open to initialise `masm_` and |
| // `pool_policy_`. |
| EmissionCheckScope::Open(masm, size, size_policy, pool_policy); |
| #ifdef VIXL_DEBUG |
| previous_allow_macro_assembler_ = masm->AllowMacroInstructions(); |
| masm->SetAllowMacroInstructions(false); |
| #endif |
| } |
| |
| private: |
| bool previous_allow_macro_assembler_; |
| }; |
| |
| |
| } // namespace vixl |
| |
| #endif // VIXL_CODE_GENERATION_SCOPES_H_ |