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 &current;
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