Home | History | Annotate | Download | only in src
      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)
     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.
     78   CodeBufferCheckScope() : assembler_(NULL), initialised_(false) {
     79     // Nothing to do.
     80   }
     81 
     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.
    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.
    162   EmissionCheckScope() {}
    163 
    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 
    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:
    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.
    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_;
    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.
    260   ExactAssemblyScope() {}
    261 
    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 
    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.
    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 
    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