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) assembler_(NULL)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. CodeBufferCheckScope()78 CodeBufferCheckScope() : assembler_(NULL), initialised_(false) { 79 // Nothing to do. 80 } 81 ~CodeBufferCheckScope()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. Close()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. EmissionCheckScope()162 EmissionCheckScope() {} 163 ~EmissionCheckScope()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 Close()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: Open(MacroAssemblerInterface * masm,size_t size,SizePolicy size_policy,PoolPolicy pool_policy)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. EmissionCheckScope(MacroAssemblerInterface * masm,size_t size,SizePolicy size_policy,PoolPolicy pool_policy)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_{nullptr}; 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. ExactAssemblyScope()260 ExactAssemblyScope() {} 261 ~ExactAssemblyScope()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 Close()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. ExactAssemblyScope(MacroAssemblerInterface * masm,size_t size,SizePolicy assert_policy,PoolPolicy pool_policy)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 Open(MacroAssemblerInterface * masm,size_t size,SizePolicy size_policy,PoolPolicy pool_policy)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