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_AARCH32_LABEL_AARCH32_H_ 28 #define VIXL_AARCH32_LABEL_AARCH32_H_ 29 30 extern "C" { 31 #include <stdint.h> 32 } 33 34 #include <algorithm> 35 #include <cstddef> 36 #include <iomanip> 37 #include <list> 38 39 #include "invalset-vixl.h" 40 #include "pool-manager.h" 41 #include "utils-vixl.h" 42 43 #include "constants-aarch32.h" 44 #include "instructions-aarch32.h" 45 46 namespace vixl { 47 48 namespace aarch32 { 49 50 class MacroAssembler; 51 52 class Location : public LocationBase<int32_t> { 53 friend class Assembler; 54 friend class MacroAssembler; 55 56 public: 57 // Unbound location that can be used with the assembler bind() method and 58 // with the assembler methods for generating instructions, but will never 59 // be handled by the pool manager. 60 Location() 61 : LocationBase<int32_t>(kRawLocation, 1 /* dummy size*/), 62 referenced_(false) {} 63 64 typedef int32_t Offset; 65 66 ~Location() { 67 #ifdef VIXL_DEBUG 68 if (IsReferenced() && !IsBound()) { 69 VIXL_ABORT_WITH_MSG("Location, label or literal used but not bound.\n"); 70 } 71 #endif 72 } 73 74 bool IsReferenced() const { return referenced_; } 75 76 private: 77 class EmitOperator { 78 public: 79 explicit EmitOperator(InstructionSet isa) : isa_(isa) { 80 #if defined(VIXL_INCLUDE_TARGET_A32_ONLY) 81 USE(isa_); 82 VIXL_ASSERT(isa == A32); 83 #elif defined(VIXL_INCLUDE_TARGET_T32_ONLY) 84 USE(isa_); 85 VIXL_ASSERT(isa == T32); 86 #endif 87 } 88 virtual ~EmitOperator() {} 89 virtual uint32_t Encode(uint32_t /*instr*/, 90 Location::Offset /*pc*/, 91 const Location* /*label*/) const { 92 return 0; 93 } 94 #if defined(VIXL_INCLUDE_TARGET_A32_ONLY) 95 bool IsUsingT32() const { return false; } 96 #elif defined(VIXL_INCLUDE_TARGET_T32_ONLY) 97 bool IsUsingT32() const { return true; } 98 #else 99 bool IsUsingT32() const { return isa_ == T32; } 100 #endif 101 102 private: 103 InstructionSet isa_; 104 }; 105 106 protected: 107 class ForwardRef : public ForwardReference<int32_t> { 108 public: 109 // Default constructor for InvalSet. 110 ForwardRef() : ForwardReference<int32_t>(0, 0, 0, 0, 1), op_(NULL) {} 111 112 ForwardRef(const Location::EmitOperator* op, 113 int32_t location, 114 int size, 115 int32_t min_object_location, 116 int32_t max_object_location, 117 int object_alignment = 1) 118 : ForwardReference<int32_t>(location, 119 size, 120 min_object_location, 121 max_object_location, 122 object_alignment), 123 op_(op) {} 124 125 const Location::EmitOperator* op() const { return op_; } 126 127 // We must provide comparison operators to work with InvalSet. 128 bool operator==(const ForwardRef& other) const { 129 return GetLocation() == other.GetLocation(); 130 } 131 bool operator<(const ForwardRef& other) const { 132 return GetLocation() < other.GetLocation(); 133 } 134 bool operator<=(const ForwardRef& other) const { 135 return GetLocation() <= other.GetLocation(); 136 } 137 bool operator>(const ForwardRef& other) const { 138 return GetLocation() > other.GetLocation(); 139 } 140 141 private: 142 const Location::EmitOperator* op_; 143 }; 144 145 static const int kNPreallocatedElements = 4; 146 // The following parameters will not affect ForwardRefList in practice, as we 147 // resolve all references at once and clear the list, so we do not need to 148 // remove individual elements by invalidating them. 149 static const int32_t kInvalidLinkKey = INT32_MAX; 150 static const size_t kReclaimFrom = 512; 151 static const size_t kReclaimFactor = 2; 152 153 typedef InvalSet<ForwardRef, 154 kNPreallocatedElements, 155 int32_t, 156 kInvalidLinkKey, 157 kReclaimFrom, 158 kReclaimFactor> 159 ForwardRefListBase; 160 typedef InvalSetIterator<ForwardRefListBase> ForwardRefListIteratorBase; 161 162 class ForwardRefList : public ForwardRefListBase { 163 public: 164 ForwardRefList() : ForwardRefListBase() {} 165 166 using ForwardRefListBase::Back; 167 using ForwardRefListBase::Front; 168 }; 169 170 class ForwardRefListIterator : public ForwardRefListIteratorBase { 171 public: 172 explicit ForwardRefListIterator(Location* location) 173 : ForwardRefListIteratorBase(&location->forward_) {} 174 175 // TODO: Remove these and use the STL-like interface instead. We'll need a 176 // const_iterator implemented for this. 177 using ForwardRefListIteratorBase::Advance; 178 using ForwardRefListIteratorBase::Current; 179 }; 180 181 // For InvalSet::GetKey() and InvalSet::SetKey(). 182 friend class InvalSet<ForwardRef, 183 kNPreallocatedElements, 184 int32_t, 185 kInvalidLinkKey, 186 kReclaimFrom, 187 kReclaimFactor>; 188 189 private: 190 virtual void ResolveReferences(internal::AssemblerBase* assembler) 191 VIXL_OVERRIDE; 192 193 void SetReferenced() { referenced_ = true; } 194 195 bool HasForwardReferences() const { return !forward_.empty(); } 196 197 ForwardRef GetLastForwardReference() const { 198 VIXL_ASSERT(HasForwardReferences()); 199 return forward_.Back(); 200 } 201 202 // Add forward reference to this object. Called from the assembler. 203 void AddForwardRef(int32_t instr_location, 204 const EmitOperator& op, 205 const ReferenceInfo* info); 206 207 // Check if we need to add padding when binding this object, in order to 208 // meet the minimum location requirement. 209 bool Needs16BitPadding(int location) const; 210 211 void EncodeLocationFor(internal::AssemblerBase* assembler, 212 int32_t from, 213 const Location::EmitOperator* encoder); 214 215 // True if the label has been used at least once. 216 bool referenced_; 217 218 protected: 219 // Types passed to LocationBase. Must be distinct for unbound Locations (not 220 // relevant for bound locations, as they don't have a correspoding 221 // PoolObject). 222 static const int kRawLocation = 0; // Will not be used by the pool manager. 223 static const int kVeneerType = 1; 224 static const int kLiteralType = 2; 225 226 // Contains the references to the unbound label 227 ForwardRefList forward_; 228 229 // To be used only by derived classes. 230 Location(uint32_t type, int size, int alignment) 231 : LocationBase<int32_t>(type, size, alignment), referenced_(false) {} 232 233 // To be used only by derived classes. 234 explicit Location(Offset location) 235 : LocationBase<int32_t>(location), referenced_(false) {} 236 237 virtual int GetMaxAlignment() const VIXL_OVERRIDE; 238 virtual int GetMinLocation() const VIXL_OVERRIDE; 239 240 private: 241 // Included to make the class concrete, however should never be called. 242 virtual void EmitPoolObject(MacroAssemblerInterface* masm) VIXL_OVERRIDE { 243 USE(masm); 244 VIXL_UNREACHABLE(); 245 } 246 }; 247 248 class Label : public Location { 249 static const int kVeneerSize = 4; 250 // Use an alignment of 1 for all architectures. Even though we can bind an 251 // unused label, because of the way the MacroAssembler works we can always be 252 // sure to have the correct buffer alignment for the instruction set we are 253 // using, so we do not need to enforce additional alignment requirements 254 // here. 255 // TODO: Consider modifying the interface of the pool manager to pass an 256 // optional additional alignment to Bind() in order to handle cases where the 257 // buffer could be unaligned. 258 static const int kVeneerAlignment = 1; 259 260 public: 261 Label() : Location(kVeneerType, kVeneerSize, kVeneerAlignment) {} 262 explicit Label(Offset location) : Location(location) {} 263 264 private: 265 virtual bool ShouldBeDeletedOnPlacementByPoolManager() const VIXL_OVERRIDE { 266 return false; 267 } 268 virtual bool ShouldDeletePoolObjectOnPlacement() const VIXL_OVERRIDE { 269 return false; 270 } 271 272 virtual void UpdatePoolObject(PoolObject<int32_t>* object) VIXL_OVERRIDE; 273 virtual void EmitPoolObject(MacroAssemblerInterface* masm) VIXL_OVERRIDE; 274 275 virtual bool UsePoolObjectEmissionMargin() const VIXL_OVERRIDE { 276 return true; 277 } 278 virtual int32_t GetPoolObjectEmissionMargin() const VIXL_OVERRIDE { 279 VIXL_ASSERT(UsePoolObjectEmissionMargin() == true); 280 return 1 * KBytes; 281 } 282 }; 283 284 class RawLiteral : public Location { 285 // Some load instructions require alignment to 4 bytes. Since we do 286 // not know what instructions will reference a literal after we place 287 // it, we enforce a 4 byte alignment for literals that are 4 bytes or 288 // larger. 289 static const int kLiteralAlignment = 4; 290 291 public: 292 enum PlacementPolicy { kPlacedWhenUsed, kManuallyPlaced }; 293 294 enum DeletionPolicy { 295 kDeletedOnPlacementByPool, 296 kDeletedOnPoolDestruction, 297 kManuallyDeleted 298 }; 299 300 RawLiteral(const void* addr, 301 int size, 302 PlacementPolicy placement_policy = kPlacedWhenUsed, 303 DeletionPolicy deletion_policy = kManuallyDeleted) 304 : Location(kLiteralType, 305 size, 306 (size < kLiteralAlignment) ? size : kLiteralAlignment), 307 addr_(addr), 308 manually_placed_(placement_policy == kManuallyPlaced), 309 deletion_policy_(deletion_policy) { 310 // We can't have manually placed literals that are not manually deleted. 311 VIXL_ASSERT(!IsManuallyPlaced() || 312 (GetDeletionPolicy() == kManuallyDeleted)); 313 } 314 RawLiteral(const void* addr, int size, DeletionPolicy deletion_policy) 315 : Location(kLiteralType, 316 size, 317 (size < kLiteralAlignment) ? size : kLiteralAlignment), 318 addr_(addr), 319 manually_placed_(false), 320 deletion_policy_(deletion_policy) {} 321 const void* GetDataAddress() const { return addr_; } 322 int GetSize() const { return GetPoolObjectSizeInBytes(); } 323 324 bool IsManuallyPlaced() const { return manually_placed_; } 325 326 private: 327 DeletionPolicy GetDeletionPolicy() const { return deletion_policy_; } 328 329 virtual bool ShouldBeDeletedOnPlacementByPoolManager() const VIXL_OVERRIDE { 330 return GetDeletionPolicy() == kDeletedOnPlacementByPool; 331 } 332 virtual bool ShouldBeDeletedOnPoolManagerDestruction() const VIXL_OVERRIDE { 333 return GetDeletionPolicy() == kDeletedOnPoolDestruction; 334 } 335 virtual void EmitPoolObject(MacroAssemblerInterface* masm) VIXL_OVERRIDE; 336 337 // Data address before it's moved into the code buffer. 338 const void* const addr_; 339 // When this flag is true, the label will be placed manually. 340 bool manually_placed_; 341 // When is the literal to be removed from the memory 342 // Can be delete'd when: 343 // moved into the code buffer: kDeletedOnPlacementByPool 344 // the pool is delete'd: kDeletedOnPoolDestruction 345 // or left to the application: kManuallyDeleted. 346 DeletionPolicy deletion_policy_; 347 348 friend class MacroAssembler; 349 }; 350 351 template <typename T> 352 class Literal : public RawLiteral { 353 public: 354 explicit Literal(const T& value, 355 PlacementPolicy placement_policy = kPlacedWhenUsed, 356 DeletionPolicy deletion_policy = kManuallyDeleted) 357 : RawLiteral(&value_, sizeof(T), placement_policy, deletion_policy), 358 value_(value) {} 359 explicit Literal(const T& value, DeletionPolicy deletion_policy) 360 : RawLiteral(&value_, sizeof(T), deletion_policy), value_(value) {} 361 void UpdateValue(const T& value, CodeBuffer* buffer) { 362 value_ = value; 363 if (IsBound()) { 364 buffer->UpdateData(GetLocation(), GetDataAddress(), GetSize()); 365 } 366 } 367 368 private: 369 T value_; 370 }; 371 372 class StringLiteral : public RawLiteral { 373 public: 374 explicit StringLiteral(const char* str, 375 PlacementPolicy placement_policy = kPlacedWhenUsed, 376 DeletionPolicy deletion_policy = kManuallyDeleted) 377 : RawLiteral(str, 378 static_cast<int>(strlen(str) + 1), 379 placement_policy, 380 deletion_policy) { 381 VIXL_ASSERT((strlen(str) + 1) <= kMaxObjectSize); 382 } 383 explicit StringLiteral(const char* str, DeletionPolicy deletion_policy) 384 : RawLiteral(str, static_cast<int>(strlen(str) + 1), deletion_policy) { 385 VIXL_ASSERT((strlen(str) + 1) <= kMaxObjectSize); 386 } 387 }; 388 389 } // namespace aarch32 390 391 392 // Required InvalSet template specialisations. 393 #define INVAL_SET_TEMPLATE_PARAMETERS \ 394 aarch32::Location::ForwardRef, aarch32::Location::kNPreallocatedElements, \ 395 int32_t, aarch32::Location::kInvalidLinkKey, \ 396 aarch32::Location::kReclaimFrom, aarch32::Location::kReclaimFactor 397 template <> 398 inline int32_t InvalSet<INVAL_SET_TEMPLATE_PARAMETERS>::GetKey( 399 const aarch32::Location::ForwardRef& element) { 400 return element.GetLocation(); 401 } 402 template <> 403 inline void InvalSet<INVAL_SET_TEMPLATE_PARAMETERS>::SetKey( 404 aarch32::Location::ForwardRef* element, int32_t key) { 405 element->SetLocationToInvalidateOnly(key); 406 } 407 #undef INVAL_SET_TEMPLATE_PARAMETERS 408 409 } // namespace vixl 410 411 #endif // VIXL_AARCH32_LABEL_AARCH32_H_ 412