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. CodeBufferCheckScope(internal::AssemblerBase* assembler, size_t size, BufferSpacePolicy check_policy = kReserveBufferSpace, SizePolicy size_policy = kMaximumSize)67 CodeBufferCheckScope(internal::AssemblerBase* assembler, 68 size_t size, 69 BufferSpacePolicy check_policy = kReserveBufferSpace, 70 SizePolicy size_policy = kMaximumSize) 71 : CodeBufferCheckScope() { 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. CodeBufferCheckScope()78 CodeBufferCheckScope() 79 : assembler_(NULL), 80 assert_policy_(kMaximumSize), 81 limit_(0), 82 previous_allow_assembler_(false), 83 initialised_(false) { 84 // Nothing to do. 85 } 86 ~CodeBufferCheckScope()87 virtual ~CodeBufferCheckScope() { Close(); } 88 89 // This function performs the actual initialisation work. Open(internal::AssemblerBase* assembler, size_t size, BufferSpacePolicy check_policy = kReserveBufferSpace, SizePolicy size_policy = kMaximumSize)90 void Open(internal::AssemblerBase* assembler, 91 size_t size, 92 BufferSpacePolicy check_policy = kReserveBufferSpace, 93 SizePolicy size_policy = kMaximumSize) { 94 VIXL_ASSERT(!initialised_); 95 VIXL_ASSERT(assembler != NULL); 96 assembler_ = assembler; 97 if (check_policy == kReserveBufferSpace) { 98 assembler->GetBuffer()->EnsureSpaceFor(size); 99 } 100 #ifdef VIXL_DEBUG 101 limit_ = assembler_->GetSizeOfCodeGenerated() + size; 102 assert_policy_ = size_policy; 103 previous_allow_assembler_ = assembler_->AllowAssembler(); 104 assembler_->SetAllowAssembler(true); 105 #else 106 USE(size_policy); 107 #endif 108 initialised_ = true; 109 } 110 111 // This function performs the cleaning-up work. It must succeed even if the 112 // scope has not been opened. It is safe to call multiple times. Close()113 void Close() { 114 #ifdef VIXL_DEBUG 115 if (!initialised_) { 116 return; 117 } 118 assembler_->SetAllowAssembler(previous_allow_assembler_); 119 switch (assert_policy_) { 120 case kNoAssert: 121 break; 122 case kExactSize: 123 VIXL_ASSERT(assembler_->GetSizeOfCodeGenerated() == limit_); 124 break; 125 case kMaximumSize: 126 VIXL_ASSERT(assembler_->GetSizeOfCodeGenerated() <= limit_); 127 break; 128 default: 129 VIXL_UNREACHABLE(); 130 } 131 #endif 132 initialised_ = false; 133 } 134 135 protected: 136 internal::AssemblerBase* assembler_; 137 SizePolicy assert_policy_; 138 size_t limit_; 139 bool previous_allow_assembler_; 140 bool initialised_; 141 }; 142 143 144 // This scope will: 145 // - Do the same as `CodeBufferCheckSCope`, but: 146 // - If managed by VIXL, always reserve space in the `CodeBuffer`. 147 // - Always check the size (exact or maximum) of the generated code on 148 // destruction. 149 // - Emit pools if the specified size would push them out of range. 150 // - Block pools emission for the duration of the scope. 151 // This scope allows the `Assembler` and `MacroAssembler` to be freely and 152 // safely mixed for its duration. 153 class EmissionCheckScope : public CodeBufferCheckScope { 154 public: 155 // This constructor implicitly calls `Open` (when `masm` is not `NULL`) to 156 // initialise the scope, so it is ready to use immediately after it has been 157 // constructed. EmissionCheckScope(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy = kMaximumSize)158 EmissionCheckScope(MacroAssemblerInterface* masm, 159 size_t size, 160 SizePolicy size_policy = kMaximumSize) 161 : EmissionCheckScope() { 162 Open(masm, size, size_policy); 163 } 164 165 // This constructor does not implicitly initialise the scope. Instead, the 166 // user is required to explicitly call the `Open` function before using the 167 // scope. EmissionCheckScope()168 EmissionCheckScope() : masm_(nullptr), pool_policy_(kBlockPools) {} 169 ~EmissionCheckScope()170 virtual ~EmissionCheckScope() { Close(); } 171 172 enum PoolPolicy { 173 // Do not forbid pool emission inside the scope. Pools will not be emitted 174 // on `Open` either. 175 kIgnorePools, 176 // Force pools to be generated on `Open` if necessary and block their 177 // emission inside the scope. 178 kBlockPools, 179 // Deprecated, but kept for backward compatibility. 180 kCheckPools = kBlockPools 181 }; 182 Open(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy = kMaximumSize)183 void Open(MacroAssemblerInterface* masm, 184 size_t size, 185 SizePolicy size_policy = kMaximumSize) { 186 Open(masm, size, size_policy, kBlockPools); 187 } 188 Close()189 void Close() { 190 if (!initialised_) { 191 return; 192 } 193 if (masm_ == NULL) { 194 // Nothing to do. 195 return; 196 } 197 // Perform the opposite of `Open`, which is: 198 // - Check the code generation limit was not exceeded. 199 // - Release the pools. 200 CodeBufferCheckScope::Close(); 201 if (pool_policy_ == kBlockPools) { 202 masm_->ReleasePools(); 203 } 204 VIXL_ASSERT(!initialised_); 205 } 206 207 protected: Open(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy, PoolPolicy pool_policy)208 void Open(MacroAssemblerInterface* masm, 209 size_t size, 210 SizePolicy size_policy, 211 PoolPolicy pool_policy) { 212 if (masm == NULL) { 213 // Nothing to do. 214 // We may reach this point in a context of conditional code generation. 215 // See `aarch64::MacroAssembler::MoveImmediateHelper()` for an example. 216 return; 217 } 218 masm_ = masm; 219 pool_policy_ = pool_policy; 220 if (pool_policy_ == kBlockPools) { 221 // To avoid duplicating the work to check that enough space is available 222 // in the buffer, do not use the more generic `EnsureEmitFor()`. It is 223 // done below when opening `CodeBufferCheckScope`. 224 masm->EnsureEmitPoolsFor(size); 225 masm->BlockPools(); 226 } 227 // The buffer should be checked *after* we emit the pools. 228 CodeBufferCheckScope::Open(masm->AsAssemblerBase(), 229 size, 230 kReserveBufferSpace, 231 size_policy); 232 VIXL_ASSERT(initialised_); 233 } 234 235 // This constructor should only be used from code that is *currently 236 // generating* the pools, to avoid an infinite loop. EmissionCheckScope(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy, PoolPolicy pool_policy)237 EmissionCheckScope(MacroAssemblerInterface* masm, 238 size_t size, 239 SizePolicy size_policy, 240 PoolPolicy pool_policy) { 241 Open(masm, size, size_policy, pool_policy); 242 } 243 244 MacroAssemblerInterface* masm_{nullptr}; 245 PoolPolicy pool_policy_; 246 }; 247 248 // Use this scope when you need a one-to-one mapping between methods and 249 // instructions. This scope will: 250 // - Do the same as `EmissionCheckScope`. 251 // - Block access to the MacroAssemblerInterface (using run-time assertions). 252 class ExactAssemblyScope : public EmissionCheckScope { 253 public: 254 // This constructor implicitly calls `Open` (when `masm` is not `NULL`) to 255 // initialise the scope, so it is ready to use immediately after it has been 256 // constructed. ExactAssemblyScope(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy = kExactSize)257 ExactAssemblyScope(MacroAssemblerInterface* masm, 258 size_t size, 259 SizePolicy size_policy = kExactSize) 260 : ExactAssemblyScope() { 261 Open(masm, size, size_policy); 262 } 263 264 // This constructor does not implicitly initialise the scope. Instead, the 265 // user is required to explicitly call the `Open` function before using the 266 // scope. ExactAssemblyScope()267 ExactAssemblyScope() : previous_allow_macro_assembler_(false) {} 268 ~ExactAssemblyScope()269 virtual ~ExactAssemblyScope() { Close(); } 270 Open(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy = kExactSize)271 void Open(MacroAssemblerInterface* masm, 272 size_t size, 273 SizePolicy size_policy = kExactSize) { 274 Open(masm, size, size_policy, kBlockPools); 275 } 276 Close()277 void Close() { 278 if (!initialised_) { 279 return; 280 } 281 if (masm_ == NULL) { 282 // Nothing to do. 283 return; 284 } 285 #ifdef VIXL_DEBUG 286 masm_->SetAllowMacroInstructions(previous_allow_macro_assembler_); 287 #else 288 USE(previous_allow_macro_assembler_); 289 #endif 290 EmissionCheckScope::Close(); 291 } 292 293 protected: 294 // This protected constructor allows overriding the pool policy. It is 295 // available to allow this scope to be used in code that handles generation 296 // of pools. ExactAssemblyScope(MacroAssemblerInterface* masm, size_t size, SizePolicy assert_policy, PoolPolicy pool_policy)297 ExactAssemblyScope(MacroAssemblerInterface* masm, 298 size_t size, 299 SizePolicy assert_policy, 300 PoolPolicy pool_policy) { 301 Open(masm, size, assert_policy, pool_policy); 302 } 303 Open(MacroAssemblerInterface* masm, size_t size, SizePolicy size_policy, PoolPolicy pool_policy)304 void Open(MacroAssemblerInterface* masm, 305 size_t size, 306 SizePolicy size_policy, 307 PoolPolicy pool_policy) { 308 VIXL_ASSERT(size_policy != kNoAssert); 309 if (masm == NULL) { 310 // Nothing to do. 311 return; 312 } 313 // Rely on EmissionCheckScope::Open to initialise `masm_` and 314 // `pool_policy_`. 315 EmissionCheckScope::Open(masm, size, size_policy, pool_policy); 316 #ifdef VIXL_DEBUG 317 previous_allow_macro_assembler_ = masm->AllowMacroInstructions(); 318 masm->SetAllowMacroInstructions(false); 319 #endif 320 } 321 322 private: 323 bool previous_allow_macro_assembler_; 324 }; 325 326 327 } // namespace vixl 328 329 #endif // VIXL_CODE_GENERATION_SCOPES_H_ 330