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