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 ¤t; 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