xref: /third_party/vixl/src/pool-manager.h (revision b8021494)
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"
39namespace vixl {
40
41class 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.
84template <typename T>
85class ForwardReference;
86template <typename T>
87class PoolObject;
88template <typename T>
89class 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.
98template <typename T>
99class 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.
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.
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.
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.
149  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.
152  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).
172  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.
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.
185  virtual bool UsePoolObjectEmissionMargin() const { return false; }
186  virtual T GetPoolObjectEmissionMargin() const {
187    VIXL_ASSERT(UsePoolObjectEmissionMargin() == false);
188    return 0;
189  }
190
191  int GetPoolObjectSizeInBytes() const { return pool_object_size_; }
192  int GetPoolObjectAlignment() const { return pool_object_alignment_; }
193  uint32_t GetPoolObjectType() const { return pool_object_type_; }
194
195  bool IsBound() const { return is_bound_; }
196  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.
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
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().
220  virtual int GetMaxAlignment() const {
221    VIXL_ASSERT(!ShouldDeletePoolObjectOnPlacement());
222    return 1;
223  }
224  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
246template <typename T>
247class PoolObject {
248 public:
249  // By default, PoolObjects have no inherent position constraints.
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.
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:
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
283  void RestrictAlignment(int alignment) {
284    VIXL_ASSERT(IsPowerOf2(alignment));
285    VIXL_ASSERT(IsPowerOf2(alignment_));
286    alignment_ = std::max(alignment_, alignment);
287  }
288
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.
329template <typename T>
330class ForwardReference {
331 public:
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
346  bool LocationIsEncodable(T location) const {
347    return location >= min_object_location_ &&
348           location <= max_object_location_ &&
349           IsAligned(location, object_alignment_);
350  }
351
352  T GetLocation() const { return location_; }
353  T GetMinLocation() const { return min_object_location_; }
354  T GetMaxLocation() const { return max_object_location_; }
355  int GetAlignment() const { return object_alignment_; }
356
357  // Needed for InvalSet.
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
391template <typename T>
392class PoolManager {
393 public:
394#ifdef PANDA_BUILD
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.
452  void Block() { monitor_++; }
453  void Release(T pc);
454  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
467  PoolObject<T>* GetObjectIfTracked(LocationBase<T>* label) {
468    return const_cast<PoolObject<T>*>(
469        static_cast<const PoolManager<T>*>(this)->GetObjectIfTracked(label));
470  }
471
472  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.
518  bool PoolIsEmptyForTest() const { return objects_.empty(); }
519  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