1 // Copyright 2017, 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 #ifndef VIXL_POOL_MANAGER_H_ 28 #define VIXL_POOL_MANAGER_H_ 29 30 #include <cstddef> 31 #include <limits> 32 #include <map> 33 #include <stdint.h> 34 #include <vector> 35 36 #include "globals-vixl.h" 37 #include "macro-assembler-interface.h" 38 #include "utils-vixl.h" 39 namespace vixl { 40 41 class TestPoolManager; 42 43 // There are four classes declared in this header file: 44 // PoolManager, PoolObject, ForwardReference and LocationBase. 45 46 // The PoolManager manages both literal and veneer pools, and is designed to be 47 // shared between AArch32 and AArch64. A pool is represented as an abstract 48 // collection of references to objects. The manager does not need to know 49 // architecture-specific details about literals and veneers; the actual 50 // emission of the pool objects is delegated. 51 // 52 // Literal and Label will derive from LocationBase. The MacroAssembler will 53 // create these objects as instructions that reference pool objects are 54 // encountered, and ask the PoolManager to track them. The PoolManager will 55 // create an internal PoolObject object for each object derived from 56 // LocationBase. Some of these PoolObject objects will be deleted when placed 57 // (e.g. the ones corresponding to Literals), whereas others will be updated 58 // with a new range when placed (e.g. Veneers) and deleted when Bind() is 59 // called on the PoolManager with their corresponding object as a parameter. 60 // 61 // A ForwardReference represents a reference to a PoolObject that will be 62 // placed later in the instruction stream. Each ForwardReference may only refer 63 // to one PoolObject, but many ForwardReferences may refer to the same 64 // object. 65 // 66 // A PoolObject represents an object that has not yet been placed. The final 67 // location of a PoolObject (and hence the LocationBase object to which it 68 // corresponds) is constrained mostly by the instructions that refer to it, but 69 // PoolObjects can also have inherent constraints, such as alignment. 70 // 71 // LocationBase objects, unlike PoolObject objects, can be used outside of the 72 // pool manager (e.g. as manually placed literals, which may still have 73 // forward references that need to be resolved). 74 // 75 // At the moment, each LocationBase will have at most one PoolObject that keeps 76 // the relevant information for placing this object in the pool. When that 77 // object is placed, all forward references of the object are resolved. For 78 // that reason, we do not need to keep track of the ForwardReference objects in 79 // the PoolObject. 80 81 // T is an integral type used for representing locations. For a 32-bit 82 // architecture it will typically be int32_t, whereas for a 64-bit 83 // architecture it will be int64_t. 84 template <typename T> 85 class ForwardReference; 86 template <typename T> 87 class PoolObject; 88 template <typename T> 89 class PoolManager; 90 91 // Represents an object that has a size and alignment, and either has a known 92 // location or has not been placed yet. An object of a subclass of LocationBase 93 // will typically keep track of a number of ForwardReferences when it has not 94 // yet been placed, but LocationBase does not assume or implement that 95 // functionality. LocationBase provides virtual methods for emitting the 96 // object, updating all the forward references, and giving the PoolManager 97 // information on the lifetime of this object and the corresponding PoolObject. 98 template <typename T> 99 class LocationBase { 100 public: 101 // The size of a LocationBase object is restricted to 4KB, in order to avoid 102 // situations where the size of the pool becomes larger than the range of 103 // an unconditional branch. This cannot happen without having large objects, 104 // as typically the range of an unconditional branch is the larger range 105 // an instruction supports. 106 // TODO: This would ideally be an architecture-specific value, perhaps 107 // another template parameter. 108 static const int kMaxObjectSize = 4 * KBytes; 109 110 // By default, LocationBase objects are aligned naturally to their size. LocationBase(uint32_t type, int size)111 LocationBase(uint32_t type, int size) 112 : pool_object_size_(size), 113 pool_object_alignment_(size), 114 pool_object_type_(type), 115 is_bound_(false), 116 location_(0) { 117 VIXL_ASSERT(size > 0); 118 VIXL_ASSERT(size <= kMaxObjectSize); 119 VIXL_ASSERT(IsPowerOf2(size)); 120 } 121 122 // Allow alignment to be specified, as long as it is smaller than the size. LocationBase(uint32_t type, int size, int alignment)123 LocationBase(uint32_t type, int size, int alignment) 124 : pool_object_size_(size), 125 pool_object_alignment_(alignment), 126 pool_object_type_(type), 127 is_bound_(false), 128 location_(0) { 129 VIXL_ASSERT(size > 0); 130 VIXL_ASSERT(size <= kMaxObjectSize); 131 VIXL_ASSERT(IsPowerOf2(alignment)); 132 VIXL_ASSERT(alignment <= size); 133 } 134 135 // Constructor for locations that are already bound. LocationBase(T location)136 explicit LocationBase(T location) 137 : pool_object_size_(-1), 138 pool_object_alignment_(-1), 139 pool_object_type_(0), 140 is_bound_(true), 141 location_(location) {} 142 143 virtual ~LocationBase() VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION {} 144 145 // The PoolManager should assume ownership of some objects, and delete them 146 // after they have been placed. This can happen for example for literals that 147 // are created internally to the MacroAssembler and the user doesn't get a 148 // handle to. By default, the PoolManager will not do this. ShouldBeDeletedOnPlacementByPoolManager() const149 virtual bool ShouldBeDeletedOnPlacementByPoolManager() const { return false; } 150 // The PoolManager should assume ownership of some objects, and delete them 151 // when it is destroyed. By default, the PoolManager will not do this. ShouldBeDeletedOnPoolManagerDestruction() const152 virtual bool ShouldBeDeletedOnPoolManagerDestruction() const { return false; } 153 154 // Emit the PoolObject. Derived classes will implement this method to emit 155 // the necessary data and/or code (for example, to emit a literal or a 156 // veneer). This should not add padding, as it is added explicitly by the pool 157 // manager. 158 virtual void EmitPoolObject(MacroAssemblerInterface* masm) = 0; 159 160 // Resolve the references to this object. Will encode the necessary offset 161 // in the instruction corresponding to each reference and then delete it. 162 // TODO: An alternative here would be to provide a ResolveReference() 163 // method that only asks the LocationBase to resolve a specific reference 164 // (thus allowing the pool manager to resolve some of the references only). 165 // This would mean we need to have some kind of API to get all the references 166 // to a LabelObject. 167 virtual void ResolveReferences(internal::AssemblerBase* assembler) = 0; 168 169 // Returns true when the PoolObject corresponding to this LocationBase object 170 // needs to be removed from the pool once placed, and false if it needs to 171 // be updated instead (in which case UpdatePoolObject will be called). ShouldDeletePoolObjectOnPlacement() const172 virtual bool ShouldDeletePoolObjectOnPlacement() const { return true; } 173 174 // Update the PoolObject after placing it, if necessary. This will happen for 175 // example in the case of a placed veneer, where we need to use a new updated 176 // range and a new reference (from the newly added branch instruction). 177 // By default, this does nothing, to avoid forcing objects that will not need 178 // this to have an empty implementation. UpdatePoolObject(PoolObject<T>*)179 virtual void UpdatePoolObject(PoolObject<T>*) {} 180 181 // Implement heuristics for emitting this object. If a margin is to be used 182 // as a hint during pool emission, we will try not to emit the object if we 183 // are further away from the maximum reachable location by more than the 184 // margin. UsePoolObjectEmissionMargin() const185 virtual bool UsePoolObjectEmissionMargin() const { return false; } GetPoolObjectEmissionMargin() const186 virtual T GetPoolObjectEmissionMargin() const { 187 VIXL_ASSERT(UsePoolObjectEmissionMargin() == false); 188 return 0; 189 } 190 GetPoolObjectSizeInBytes() const191 int GetPoolObjectSizeInBytes() const { return pool_object_size_; } GetPoolObjectAlignment() const192 int GetPoolObjectAlignment() const { return pool_object_alignment_; } GetPoolObjectType() const193 uint32_t GetPoolObjectType() const { return pool_object_type_; } 194 IsBound() const195 bool IsBound() const { return is_bound_; } GetLocation() const196 T GetLocation() const { return location_; } 197 198 // This function can be called multiple times before the object is marked as 199 // bound with MarkBound() below. This is because some objects (e.g. the ones 200 // used to represent labels) can have veneers; every time we place a veneer 201 // we need to keep track of the location in order to resolve the references 202 // to the object. Reusing the location_ field for this is convenient. SetLocation(internal::AssemblerBase* assembler, T location)203 void SetLocation(internal::AssemblerBase* assembler, T location) { 204 #ifndef PANDA_BUILD 205 VIXL_ASSERT(!is_bound_); 206 #endif 207 location_ = location; 208 ResolveReferences(assembler); 209 } 210 MarkBound()211 void MarkBound() { 212 #ifndef PANDA_BUILD 213 VIXL_ASSERT(!is_bound_); 214 #endif 215 is_bound_ = true; 216 } 217 218 // The following two functions are used when an object is bound by a call to 219 // PoolManager<T>::Bind(). GetMaxAlignment() const220 virtual int GetMaxAlignment() const { 221 VIXL_ASSERT(!ShouldDeletePoolObjectOnPlacement()); 222 return 1; 223 } GetMinLocation() const224 virtual T GetMinLocation() const { 225 VIXL_ASSERT(!ShouldDeletePoolObjectOnPlacement()); 226 return 0; 227 } 228 229 private: 230 // The size of the corresponding PoolObject, in bytes. 231 int pool_object_size_; 232 // The alignment of the corresponding PoolObject; this must be a power of two. 233 int pool_object_alignment_; 234 235 // Different derived classes should have different type values. This can be 236 // used internally by the PoolManager for grouping of objects. 237 uint32_t pool_object_type_; 238 // Has the object been bound to a location yet? 239 bool is_bound_; 240 241 protected: 242 // See comment on SetLocation() for the use of this field. 243 T location_; 244 }; 245 246 template <typename T> 247 class PoolObject { 248 public: 249 // By default, PoolObjects have no inherent position constraints. PoolObject(LocationBase<T>* parent)250 explicit PoolObject(LocationBase<T>* parent) 251 : label_base_(parent), 252 min_location_(0), 253 max_location_(std::numeric_limits<T>::max()), 254 alignment_(parent->GetPoolObjectAlignment()), 255 skip_until_location_hint_(0), 256 type_(parent->GetPoolObjectType()) { 257 VIXL_ASSERT(IsPowerOf2(alignment_)); 258 UpdateLocationHint(); 259 } 260 261 // Reset the minimum and maximum location and the alignment of the object. 262 // This function is public in order to allow the LocationBase corresponding to 263 // this PoolObject to update the PoolObject when placed, e.g. in the case of 264 // veneers. The size and type of the object cannot be modified. Update(T min, T max, int alignment)265 void Update(T min, T max, int alignment) { 266 // We don't use RestrictRange here as the new range is independent of the 267 // old range (and the maximum location is typically larger). 268 min_location_ = min; 269 max_location_ = max; 270 RestrictAlignment(alignment); 271 UpdateLocationHint(); 272 } 273 274 private: RestrictRange(T min, T max)275 void RestrictRange(T min, T max) { 276 VIXL_ASSERT(min <= max_location_); 277 VIXL_ASSERT(max >= min_location_); 278 min_location_ = std::max(min_location_, min); 279 max_location_ = std::min(max_location_, max); 280 UpdateLocationHint(); 281 } 282 RestrictAlignment(int alignment)283 void RestrictAlignment(int alignment) { 284 VIXL_ASSERT(IsPowerOf2(alignment)); 285 VIXL_ASSERT(IsPowerOf2(alignment_)); 286 alignment_ = std::max(alignment_, alignment); 287 } 288 UpdateLocationHint()289 void UpdateLocationHint() { 290 if (label_base_->UsePoolObjectEmissionMargin()) { 291 skip_until_location_hint_ = 292 max_location_ - label_base_->GetPoolObjectEmissionMargin(); 293 } 294 } 295 296 // The LocationBase that this pool object represents. 297 LocationBase<T>* label_base_; 298 299 // Hard, precise location constraints for the start location of the object. 300 // They are both inclusive, that is the start location of the object can be 301 // at any location between min_location_ and max_location_, themselves 302 // included. 303 T min_location_; 304 T max_location_; 305 306 // The alignment must be a power of two. 307 int alignment_; 308 309 // Avoid generating this object until skip_until_location_hint_. This 310 // supports cases where placing the object in the pool has an inherent cost 311 // that could be avoided in some other way. Veneers are a typical example; we 312 // would prefer to branch directly (over a pool) rather than use veneers, so 313 // this value can be set using some heuristic to leave them in the pool. 314 // This value is only a hint, which will be ignored if it has to in order to 315 // meet the hard constraints we have. 316 T skip_until_location_hint_; 317 318 // Used only to group objects of similar type together. The PoolManager does 319 // not know what the types represent. 320 uint32_t type_; 321 322 friend class PoolManager<T>; 323 }; 324 325 // Class that represents a forward reference. It is the responsibility of 326 // LocationBase objects to keep track of forward references and patch them when 327 // an object is placed - this class is only used by the PoolManager in order to 328 // restrict the requirements on PoolObjects it is tracking. 329 template <typename T> 330 class ForwardReference { 331 public: ForwardReference(T location, int size, T min_object_location, T max_object_location, int object_alignment = 1)332 ForwardReference(T location, 333 int size, 334 T min_object_location, 335 T max_object_location, 336 int object_alignment = 1) 337 : location_(location), 338 size_(size), 339 object_alignment_(object_alignment), 340 min_object_location_(min_object_location), 341 max_object_location_(max_object_location) { 342 VIXL_ASSERT(AlignDown(max_object_location, object_alignment) >= 343 min_object_location); 344 } 345 LocationIsEncodable(T location) const346 bool LocationIsEncodable(T location) const { 347 return location >= min_object_location_ && 348 location <= max_object_location_ && 349 IsAligned(location, object_alignment_); 350 } 351 GetLocation() const352 T GetLocation() const { return location_; } GetMinLocation() const353 T GetMinLocation() const { return min_object_location_; } GetMaxLocation() const354 T GetMaxLocation() const { return max_object_location_; } GetAlignment() const355 int GetAlignment() const { return object_alignment_; } 356 357 // Needed for InvalSet. SetLocationToInvalidateOnly(T location)358 void SetLocationToInvalidateOnly(T location) { location_ = location; } 359 360 private: 361 // The location of the thing that contains the reference. For example, this 362 // can be the location of the branch or load instruction. 363 T location_; 364 365 // The size of the instruction that makes the reference, in bytes. 366 int size_; 367 368 // The alignment that the object must satisfy for this reference - must be a 369 // power of two. 370 int object_alignment_; 371 372 // Specify the possible locations where the object could be stored. AArch32's 373 // PC offset, and T32's PC alignment calculations should be applied by the 374 // Assembler, not here. The PoolManager deals only with simple locations. 375 // Including min_object_address_ is necessary to handle AArch32 some 376 // instructions which have a minimum offset of 0, but also have the implicit 377 // PC offset. 378 // Note that this structure cannot handle sparse ranges, such as A32's ADR, 379 // but doing so is costly and probably not useful in practice. The min and 380 // and max object location both refer to the beginning of the object, are 381 // inclusive and are not affected by the object size. E.g. if 382 // max_object_location_ is equal to X, we can place the object at location X 383 // regardless of its size. 384 T min_object_location_; 385 T max_object_location_; 386 387 friend class PoolManager<T>; 388 }; 389 390 391 template <typename T> 392 class PoolManager { 393 public: 394 #ifdef PANDA_BUILD PoolManager(PandaAllocator* allocator, int header_size, int alignment, int buffer_alignment)395 PoolManager(PandaAllocator* allocator, int header_size, int alignment, int buffer_alignment) 396 : allocator_(allocator), objects_(allocator_.Adapter()), 397 delete_on_destruction_(allocator_.Adapter()), 398 header_size_(header_size), 399 #else 400 PoolManager(int header_size, int alignment, int buffer_alignment) 401 : header_size_(header_size), 402 #endif 403 alignment_(alignment), 404 buffer_alignment_(buffer_alignment), 405 checkpoint_(std::numeric_limits<T>::max()), 406 max_pool_size_(0), 407 monitor_(0) {} 408 409 ~PoolManager() VIXL_NEGATIVE_TESTING_ALLOW_EXCEPTION; 410 411 // Check if we will need to emit the pool at location 'pc', when planning to 412 // generate a certain number of bytes. This optionally takes a 413 // ForwardReference we are about to generate, in which case the size of the 414 // reference must be included in 'num_bytes'. 415 bool MustEmit(T pc, 416 int num_bytes = 0, 417 ForwardReference<T>* reference = NULL, 418 LocationBase<T>* object = NULL) const; 419 420 enum EmitOption { kBranchRequired, kNoBranchRequired }; 421 422 // Emit the pool at location 'pc', using 'masm' as the macroassembler. 423 // The branch over the header can be optionally omitted using 'option'. 424 // Returns the new PC after pool emission. 425 // This expects a number of bytes that are about to be emitted, to be taken 426 // into account in heuristics for pool object emission. 427 // This also optionally takes a forward reference and an object as 428 // parameters, to be used in the case where emission of the pool is triggered 429 // by adding a new reference to the pool that does not fit. The pool manager 430 // will need this information in order to apply its heuristics correctly. 431 T Emit(MacroAssemblerInterface* masm, 432 T pc, 433 int num_bytes = 0, 434 ForwardReference<T>* new_reference = NULL, 435 LocationBase<T>* new_object = NULL, 436 EmitOption option = kBranchRequired); 437 438 // Add 'reference' to 'object'. Should not be preceded by a call to MustEmit() 439 // that returned true, unless Emit() has been successfully afterwards. 440 void AddObjectReference(const ForwardReference<T>* reference, 441 LocationBase<T>* object); 442 443 // This is to notify the pool that a LocationBase has been bound to a location 444 // and does not need to be tracked anymore. 445 // This will happen, for example, for Labels, which are manually bound by the 446 // user. 447 // This can potentially add some padding bytes in order to meet the object 448 // requirements, and will return the new location. 449 T Bind(MacroAssemblerInterface* masm, LocationBase<T>* object, T location); 450 451 // Functions for blocking and releasing the pools. Block()452 void Block() { monitor_++; } 453 void Release(T pc); IsBlocked() const454 bool IsBlocked() const { return monitor_ != 0; } 455 456 private: 457 #ifndef PANDA_BUILD 458 typedef typename std::vector<PoolObject<T> >::iterator objects_iter; 459 typedef 460 typename std::vector<PoolObject<T> >::const_iterator const_objects_iter; 461 #else 462 typedef typename Vector<PoolObject<T> >::iterator objects_iter; 463 typedef 464 typename Vector<PoolObject<T> >::const_iterator const_objects_iter; 465 #endif 466 GetObjectIfTracked(LocationBase<T>* label)467 PoolObject<T>* GetObjectIfTracked(LocationBase<T>* label) { 468 return const_cast<PoolObject<T>*>( 469 static_cast<const PoolManager<T>*>(this)->GetObjectIfTracked(label)); 470 } 471 GetObjectIfTracked(LocationBase<T>* label) const472 const PoolObject<T>* GetObjectIfTracked(LocationBase<T>* label) const { 473 for (const_objects_iter iter = objects_.begin(); iter != objects_.end(); 474 ++iter) { 475 const PoolObject<T>& current = *iter; 476 if (current.label_base_ == label) return ¤t; 477 } 478 return NULL; 479 } 480 481 // Helper function for calculating the checkpoint. 482 enum SortOption { kSortRequired, kNoSortRequired }; 483 void RecalculateCheckpoint(SortOption sort_option = kSortRequired); 484 485 // Comparison function for using std::sort() on objects_. PoolObject A is 486 // ordered before PoolObject B when A should be emitted before B. The 487 // comparison depends on the max_location_, size_, alignment_ and 488 // min_location_. 489 static bool PoolObjectLessThan(const PoolObject<T>& a, 490 const PoolObject<T>& b); 491 492 // Helper function used in the checkpoint calculation. 'checkpoint' is the 493 // current checkpoint, which is modified to take 'object' into account. The 494 // new checkpoint is returned. 495 static T UpdateCheckpointForObject(T checkpoint, const PoolObject<T>* object); 496 497 // Helper function to add a new object into a sorted objects_ array. 498 void Insert(const PoolObject<T>& new_object); 499 500 // Helper functions to remove an object from objects_ and delete the 501 // corresponding LocationBase object, if necessary. This will be called 502 // either after placing the object, or when Bind() is called. 503 void RemoveAndDelete(PoolObject<T>* object); 504 objects_iter RemoveAndDelete(objects_iter iter); 505 506 // Helper function to check if we should skip emitting an object. 507 bool ShouldSkipObject(PoolObject<T>* pool_object, 508 T pc, 509 int num_bytes, 510 ForwardReference<T>* new_reference, 511 LocationBase<T>* new_object, 512 PoolObject<T>* existing_object) const; 513 514 // Used only for debugging. 515 void DumpCurrentState(T pc) const; 516 517 // Methods used for testing only, via the test friend classes. PoolIsEmptyForTest() const518 bool PoolIsEmptyForTest() const { return objects_.empty(); } GetCheckpointForTest() const519 T GetCheckpointForTest() const { return checkpoint_; } 520 int GetPoolSizeForTest() const; 521 522 // The objects we are tracking references to. The objects_ vector is sorted 523 // at all times between calls to the public members of the PoolManager. It 524 // is sorted every time we add, delete or update a PoolObject. 525 // TODO: Consider a more efficient data structure here, to allow us to delete 526 // elements as we emit them. 527 #ifndef PANDA_BUILD 528 std::vector<PoolObject<T> > objects_; 529 530 // Objects to be deleted on pool destruction. 531 std::vector<LocationBase<T>*> delete_on_destruction_; 532 #else 533 AllocatorWrapper allocator_; 534 Vector<PoolObject<T> > objects_; 535 536 // Objects to be deleted on pool destruction. 537 Vector<LocationBase<T>*> delete_on_destruction_; 538 #endif 539 540 // The header_size_ and alignment_ values are hardcoded for each instance of 541 // PoolManager. The PoolManager does not know how to emit the header, and 542 // relies on the EmitPoolHeader and EndPool methods of the 543 // MacroAssemblerInterface for that. It will also emit padding if necessary, 544 // both for the header and at the end of the pool, according to alignment_, 545 // and using the EmitNopBytes and EmitPaddingBytes method of the 546 // MacroAssemblerInterface. 547 548 // The size of the header, in bytes. 549 int header_size_; 550 // The alignment of the header - must be a power of two. 551 int alignment_; 552 // The alignment of the buffer - we cannot guarantee any object alignment 553 // larger than this alignment. When a buffer is grown, this alignment has 554 // to be guaranteed. 555 // TODO: Consider extending this to describe the guaranteed alignment as the 556 // modulo of a known number. 557 int buffer_alignment_; 558 559 // The current checkpoint. This is the latest location at which the pool 560 // *must* be emitted. This should not be visible outside the pool manager 561 // and should only be updated in RecalculateCheckpoint. 562 T checkpoint_; 563 564 // Maximum size of the pool, assuming we need the maximum possible padding 565 // for each object and for the header. It is only updated in 566 // RecalculateCheckpoint. 567 T max_pool_size_; 568 569 // Indicates whether the emission of this pool is blocked. 570 int monitor_; 571 572 friend class vixl::TestPoolManager; 573 }; 574 575 576 } // namespace vixl 577 578 #endif // VIXL_POOL_MANAGER_H_ 579