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