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