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