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