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