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