• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef PANDA_BUILD
Location()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 
~Location()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 
IsReferenced()83   bool IsReferenced() const { return referenced_; }
84 
85  private:
86   class EmitOperator {
87    public:
EmitOperator(InstructionSet isa)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     }
~EmitOperator()97     virtual ~EmitOperator() {}
Encode(uint32_t,Location::Offset,const Location *)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)
IsUsingT32()104     bool IsUsingT32() const { return false; }
105 #elif defined(VIXL_INCLUDE_TARGET_T32_ONLY)
IsUsingT32()106     bool IsUsingT32() const { return true; }
107 #else
IsUsingT32()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.
ForwardRef()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 
op()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
ForwardRefList()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:
ForwardRefListIterator(Location * location)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 
SetReferenced()206   void SetReferenced() { referenced_ = true; }
207 
HasForwardReferences()208   bool HasForwardReferences() const { return !forward_.empty(); }
209 
GetLastForwardReference()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 correspoding
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.
Location(uint32_t type,int size,int alignment)244   Location(uint32_t type, int size, int alignment)
245       : LocationBase<int32_t>(type, size, alignment), referenced_(false) {}
246 #else
Location(AllocatorWrapper allocator,uint32_t type,int size,int alignment)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.
Location(Offset location)253   explicit Location(Offset location)
254       : LocationBase<int32_t>(location), referenced_(false) {}
255 #else
256   explicit Location(Offset location) = delete;
Location(AllocatorWrapper allocator,Offset location)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.
EmitPoolObject(MacroAssemblerInterface * masm)266   virtual void EmitPoolObject(MacroAssemblerInterface* masm) VIXL_OVERRIDE {
267     USE(masm);
268     VIXL_UNREACHABLE();
269   }
270 };
271 
272 class 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
Label()286   Label() : Location(kVeneerType, kVeneerSize, kVeneerAlignment) {}
Label(Offset location)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:
ShouldBeDeletedOnPlacementByPoolManager()296   virtual bool ShouldBeDeletedOnPlacementByPoolManager() const VIXL_OVERRIDE {
297     return false;
298   }
ShouldDeletePoolObjectOnPlacement()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 
UsePoolObjectEmissionMargin()306   virtual bool UsePoolObjectEmissionMargin() const VIXL_OVERRIDE {
307     return true;
308   }
GetPoolObjectEmissionMargin()309   virtual int32_t GetPoolObjectEmissionMargin() const VIXL_OVERRIDE {
310     VIXL_ASSERT(UsePoolObjectEmissionMargin() == true);
311     return 1 * KBytes;
312   }
313 };
314 
315 class 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   }
RawLiteral(const void * addr,int size,DeletionPolicy deletion_policy)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
354 RawLiteral(const void* addr,
355            int size,
356            PlacementPolicy placement_policy = kPlacedWhenUsed,
357            DeletionPolicy deletion_policy = kManuallyDeleted) = delete;
358 RawLiteral(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 }
372 RawLiteral(const void* addr, int size, DeletionPolicy deletion_policy) = delete;
373 
RawLiteral(AllocatorWrapper allocator,const void * addr,int size,DeletionPolicy deletion_policy)374 RawLiteral(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
GetDataAddress()383   const void* GetDataAddress() const { return addr_; }
GetSize()384   int GetSize() const { return GetPoolObjectSizeInBytes(); }
385 
IsManuallyPlaced()386   bool IsManuallyPlaced() const { return manually_placed_; }
387 
388  private:
GetDeletionPolicy()389   DeletionPolicy GetDeletionPolicy() const { return deletion_policy_; }
390 
ShouldBeDeletedOnPlacementByPoolManager()391   virtual bool ShouldBeDeletedOnPlacementByPoolManager() const VIXL_OVERRIDE {
392     return GetDeletionPolicy() == kDeletedOnPlacementByPool;
393   }
ShouldBeDeletedOnPoolManagerDestruction()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 
413 template <typename T>
414 class 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) {}
Literal(const T & value,DeletionPolicy deletion_policy)422   explicit Literal(const T& value, DeletionPolicy deletion_policy)
423       : RawLiteral(&value_, sizeof(T), deletion_policy), value_(value) {}
424 #else
425 explicit Literal(const T& ,
426                  PlacementPolicy placement_policy = kPlacedWhenUsed,
427                  DeletionPolicy deletion_policy = kManuallyDeleted) = delete;
428 explicit Literal(const T& value, DeletionPolicy deletion_policy) = delete;
429 explicit 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) {}
434 explicit Literal(AllocatorWrapper allocator, const T& value, DeletionPolicy deletion_policy)
435     : RawLiteral(allocator, &value_, sizeof(T), deletion_policy), value_(value) {}
436 
437 #endif
UpdateValue(const T & value,CodeBuffer * buffer)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 
449 class 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   }
StringLiteral(const char * str,DeletionPolicy deletion_policy)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
466 explicit StringLiteral(const char* str,
467                        PlacementPolicy placement_policy = kPlacedWhenUsed,
468                        DeletionPolicy deletion_policy = kManuallyDeleted) = delete;
469 StringLiteral(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 }
478 explicit StringLiteral(const char* str, DeletionPolicy deletion_policy) = delete;
479 explicit 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
494 template <>
GetKey(const aarch32::Location::ForwardRef & element)495 inline int32_t InvalSet<INVAL_SET_TEMPLATE_PARAMETERS>::GetKey(
496     const aarch32::Location::ForwardRef& element) {
497   return element.GetLocation();
498 }
499 template <>
SetKey(aarch32::Location::ForwardRef * element,int32_t key)500 inline 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