1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_COMPILER_UTILS_ASSEMBLER_H_
18#define ART_COMPILER_UTILS_ASSEMBLER_H_
19
20#include <vector>
21
22#include "arch/instruction_set.h"
23#include "arch/instruction_set_features.h"
24#include "arm/constants_arm.h"
25#include "base/arena_allocator.h"
26#include "base/arena_object.h"
27#include "base/logging.h"
28#include "base/macros.h"
29#include "debug/dwarf/debug_frame_opcode_writer.h"
30#include "label.h"
31#include "managed_register.h"
32#include "memory_region.h"
33#include "mips/constants_mips.h"
34#include "offsets.h"
35#include "x86/constants_x86.h"
36#include "x86_64/constants_x86_64.h"
37
38namespace art {
39
40class Assembler;
41class AssemblerBuffer;
42
43// Assembler fixups are positions in generated code that require processing
44// after the code has been copied to executable memory. This includes building
45// relocation information.
46class AssemblerFixup {
47 public:
48  virtual void Process(const MemoryRegion& region, int position) = 0;
49  virtual ~AssemblerFixup() {}
50
51 private:
52  AssemblerFixup* previous_;
53  int position_;
54
55  AssemblerFixup* previous() const { return previous_; }
56  void set_previous(AssemblerFixup* previous_in) { previous_ = previous_in; }
57
58  int position() const { return position_; }
59  void set_position(int position_in) { position_ = position_in; }
60
61  friend class AssemblerBuffer;
62};
63
64// Parent of all queued slow paths, emitted during finalization
65class SlowPath : public DeletableArenaObject<kArenaAllocAssembler> {
66 public:
67  SlowPath() : next_(nullptr) {}
68  virtual ~SlowPath() {}
69
70  Label* Continuation() { return &continuation_; }
71  Label* Entry() { return &entry_; }
72  // Generate code for slow path
73  virtual void Emit(Assembler *sp_asm) = 0;
74
75 protected:
76  // Entry branched to by fast path
77  Label entry_;
78  // Optional continuation that is branched to at the end of the slow path
79  Label continuation_;
80  // Next in linked list of slow paths
81  SlowPath *next_;
82
83 private:
84  friend class AssemblerBuffer;
85  DISALLOW_COPY_AND_ASSIGN(SlowPath);
86};
87
88class AssemblerBuffer {
89 public:
90  explicit AssemblerBuffer(ArenaAllocator* arena);
91  ~AssemblerBuffer();
92
93  ArenaAllocator* GetArena() {
94    return arena_;
95  }
96
97  // Basic support for emitting, loading, and storing.
98  template<typename T> void Emit(T value) {
99    CHECK(HasEnsuredCapacity());
100    *reinterpret_cast<T*>(cursor_) = value;
101    cursor_ += sizeof(T);
102  }
103
104  template<typename T> T Load(size_t position) {
105    CHECK_LE(position, Size() - static_cast<int>(sizeof(T)));
106    return *reinterpret_cast<T*>(contents_ + position);
107  }
108
109  template<typename T> void Store(size_t position, T value) {
110    CHECK_LE(position, Size() - static_cast<int>(sizeof(T)));
111    *reinterpret_cast<T*>(contents_ + position) = value;
112  }
113
114  void Resize(size_t new_size) {
115    if (new_size > Capacity()) {
116      ExtendCapacity(new_size);
117    }
118    cursor_ = contents_ + new_size;
119  }
120
121  void Move(size_t newposition, size_t oldposition, size_t size) {
122    // Move a chunk of the buffer from oldposition to newposition.
123    DCHECK_LE(oldposition + size, Size());
124    DCHECK_LE(newposition + size, Size());
125    memmove(contents_ + newposition, contents_ + oldposition, size);
126  }
127
128  // Emit a fixup at the current location.
129  void EmitFixup(AssemblerFixup* fixup) {
130    fixup->set_previous(fixup_);
131    fixup->set_position(Size());
132    fixup_ = fixup;
133  }
134
135  void EnqueueSlowPath(SlowPath* slowpath) {
136    if (slow_path_ == nullptr) {
137      slow_path_ = slowpath;
138    } else {
139      SlowPath* cur = slow_path_;
140      for ( ; cur->next_ != nullptr ; cur = cur->next_) {}
141      cur->next_ = slowpath;
142    }
143  }
144
145  void EmitSlowPaths(Assembler* sp_asm) {
146    SlowPath* cur = slow_path_;
147    SlowPath* next = nullptr;
148    slow_path_ = nullptr;
149    for ( ; cur != nullptr ; cur = next) {
150      cur->Emit(sp_asm);
151      next = cur->next_;
152      delete cur;
153    }
154  }
155
156  // Get the size of the emitted code.
157  size_t Size() const {
158    CHECK_GE(cursor_, contents_);
159    return cursor_ - contents_;
160  }
161
162  uint8_t* contents() const { return contents_; }
163
164  // Copy the assembled instructions into the specified memory block
165  // and apply all fixups.
166  void FinalizeInstructions(const MemoryRegion& region);
167
168  // To emit an instruction to the assembler buffer, the EnsureCapacity helper
169  // must be used to guarantee that the underlying data area is big enough to
170  // hold the emitted instruction. Usage:
171  //
172  //     AssemblerBuffer buffer;
173  //     AssemblerBuffer::EnsureCapacity ensured(&buffer);
174  //     ... emit bytes for single instruction ...
175
176#ifndef NDEBUG
177
178  class EnsureCapacity {
179   public:
180    explicit EnsureCapacity(AssemblerBuffer* buffer) {
181      if (buffer->cursor() > buffer->limit()) {
182        buffer->ExtendCapacity(buffer->Size() + kMinimumGap);
183      }
184      // In debug mode, we save the assembler buffer along with the gap
185      // size before we start emitting to the buffer. This allows us to
186      // check that any single generated instruction doesn't overflow the
187      // limit implied by the minimum gap size.
188      buffer_ = buffer;
189      gap_ = ComputeGap();
190      // Make sure that extending the capacity leaves a big enough gap
191      // for any kind of instruction.
192      CHECK_GE(gap_, kMinimumGap);
193      // Mark the buffer as having ensured the capacity.
194      CHECK(!buffer->HasEnsuredCapacity());  // Cannot nest.
195      buffer->has_ensured_capacity_ = true;
196    }
197
198    ~EnsureCapacity() {
199      // Unmark the buffer, so we cannot emit after this.
200      buffer_->has_ensured_capacity_ = false;
201      // Make sure the generated instruction doesn't take up more
202      // space than the minimum gap.
203      int delta = gap_ - ComputeGap();
204      CHECK_LE(delta, kMinimumGap);
205    }
206
207   private:
208    AssemblerBuffer* buffer_;
209    int gap_;
210
211    int ComputeGap() { return buffer_->Capacity() - buffer_->Size(); }
212  };
213
214  bool has_ensured_capacity_;
215  bool HasEnsuredCapacity() const { return has_ensured_capacity_; }
216
217#else
218
219  class EnsureCapacity {
220   public:
221    explicit EnsureCapacity(AssemblerBuffer* buffer) {
222      if (buffer->cursor() > buffer->limit()) {
223        buffer->ExtendCapacity(buffer->Size() + kMinimumGap);
224      }
225    }
226  };
227
228  // When building the C++ tests, assertion code is enabled. To allow
229  // asserting that the user of the assembler buffer has ensured the
230  // capacity needed for emitting, we add a dummy method in non-debug mode.
231  bool HasEnsuredCapacity() const { return true; }
232
233#endif
234
235  // Returns the position in the instruction stream.
236  int GetPosition() { return  cursor_ - contents_; }
237
238  size_t Capacity() const {
239    CHECK_GE(limit_, contents_);
240    return (limit_ - contents_) + kMinimumGap;
241  }
242
243  // Unconditionally increase the capacity.
244  // The provided `min_capacity` must be higher than current `Capacity()`.
245  void ExtendCapacity(size_t min_capacity);
246
247 private:
248  // The limit is set to kMinimumGap bytes before the end of the data area.
249  // This leaves enough space for the longest possible instruction and allows
250  // for a single, fast space check per instruction.
251  static const int kMinimumGap = 32;
252
253  ArenaAllocator* arena_;
254  uint8_t* contents_;
255  uint8_t* cursor_;
256  uint8_t* limit_;
257  AssemblerFixup* fixup_;
258#ifndef NDEBUG
259  bool fixups_processed_;
260#endif
261
262  // Head of linked list of slow paths
263  SlowPath* slow_path_;
264
265  uint8_t* cursor() const { return cursor_; }
266  uint8_t* limit() const { return limit_; }
267
268  // Process the fixup chain starting at the given fixup. The offset is
269  // non-zero for fixups in the body if the preamble is non-empty.
270  void ProcessFixups(const MemoryRegion& region);
271
272  // Compute the limit based on the data area and the capacity. See
273  // description of kMinimumGap for the reasoning behind the value.
274  static uint8_t* ComputeLimit(uint8_t* data, size_t capacity) {
275    return data + capacity - kMinimumGap;
276  }
277
278  friend class AssemblerFixup;
279};
280
281// The purpose of this class is to ensure that we do not have to explicitly
282// call the AdvancePC method (which is good for convenience and correctness).
283class DebugFrameOpCodeWriterForAssembler FINAL
284    : public dwarf::DebugFrameOpCodeWriter<> {
285 public:
286  struct DelayedAdvancePC {
287    uint32_t stream_pos;
288    uint32_t pc;
289  };
290
291  // This method is called the by the opcode writers.
292  virtual void ImplicitlyAdvancePC() FINAL;
293
294  explicit DebugFrameOpCodeWriterForAssembler(Assembler* buffer)
295      : dwarf::DebugFrameOpCodeWriter<>(false /* enabled */),
296        assembler_(buffer),
297        delay_emitting_advance_pc_(false),
298        delayed_advance_pcs_() {
299  }
300
301  ~DebugFrameOpCodeWriterForAssembler() {
302    DCHECK(delayed_advance_pcs_.empty());
303  }
304
305  // Tell the writer to delay emitting advance PC info.
306  // The assembler must explicitly process all the delayed advances.
307  void DelayEmittingAdvancePCs() {
308    delay_emitting_advance_pc_ = true;
309  }
310
311  // Override the last delayed PC. The new PC can be out of order.
312  void OverrideDelayedPC(size_t pc) {
313    DCHECK(delay_emitting_advance_pc_);
314    DCHECK(!delayed_advance_pcs_.empty());
315    delayed_advance_pcs_.back().pc = pc;
316  }
317
318  // Return the number of delayed advance PC entries.
319  size_t NumberOfDelayedAdvancePCs() const {
320    return delayed_advance_pcs_.size();
321  }
322
323  // Release the CFI stream and advance PC infos so that the assembler can patch it.
324  std::pair<std::vector<uint8_t>, std::vector<DelayedAdvancePC>>
325  ReleaseStreamAndPrepareForDelayedAdvancePC() {
326    DCHECK(delay_emitting_advance_pc_);
327    delay_emitting_advance_pc_ = false;
328    std::pair<std::vector<uint8_t>, std::vector<DelayedAdvancePC>> result;
329    result.first.swap(opcodes_);
330    result.second.swap(delayed_advance_pcs_);
331    return result;
332  }
333
334  // Reserve space for the CFI stream.
335  void ReserveCFIStream(size_t capacity) {
336    opcodes_.reserve(capacity);
337  }
338
339  // Append raw data to the CFI stream.
340  void AppendRawData(const std::vector<uint8_t>& raw_data, size_t first, size_t last) {
341    DCHECK_LE(0u, first);
342    DCHECK_LE(first, last);
343    DCHECK_LE(last, raw_data.size());
344    opcodes_.insert(opcodes_.end(), raw_data.begin() + first, raw_data.begin() + last);
345  }
346
347 private:
348  Assembler* assembler_;
349  bool delay_emitting_advance_pc_;
350  std::vector<DelayedAdvancePC> delayed_advance_pcs_;
351};
352
353class Assembler : public DeletableArenaObject<kArenaAllocAssembler> {
354 public:
355  static std::unique_ptr<Assembler> Create(
356      ArenaAllocator* arena,
357      InstructionSet instruction_set,
358      const InstructionSetFeatures* instruction_set_features = nullptr);
359
360  // Finalize the code; emit slow paths, fixup branches, add literal pool, etc.
361  virtual void FinalizeCode() { buffer_.EmitSlowPaths(this); }
362
363  // Size of generated code
364  virtual size_t CodeSize() const { return buffer_.Size(); }
365  virtual const uint8_t* CodeBufferBaseAddress() const { return buffer_.contents(); }
366
367  // Copy instructions out of assembly buffer into the given region of memory
368  virtual void FinalizeInstructions(const MemoryRegion& region) {
369    buffer_.FinalizeInstructions(region);
370  }
371
372  // TODO: Implement with disassembler.
373  virtual void Comment(const char* format ATTRIBUTE_UNUSED, ...) {}
374
375  // Emit code that will create an activation on the stack
376  virtual void BuildFrame(size_t frame_size, ManagedRegister method_reg,
377                          const std::vector<ManagedRegister>& callee_save_regs,
378                          const ManagedRegisterEntrySpills& entry_spills) = 0;
379
380  // Emit code that will remove an activation from the stack
381  virtual void RemoveFrame(size_t frame_size,
382                           const std::vector<ManagedRegister>& callee_save_regs) = 0;
383
384  virtual void IncreaseFrameSize(size_t adjust) = 0;
385  virtual void DecreaseFrameSize(size_t adjust) = 0;
386
387  // Store routines
388  virtual void Store(FrameOffset offs, ManagedRegister src, size_t size) = 0;
389  virtual void StoreRef(FrameOffset dest, ManagedRegister src) = 0;
390  virtual void StoreRawPtr(FrameOffset dest, ManagedRegister src) = 0;
391
392  virtual void StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
393                                     ManagedRegister scratch) = 0;
394
395  virtual void StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm,
396                                        ManagedRegister scratch);
397  virtual void StoreImmediateToThread64(ThreadOffset<8> dest, uint32_t imm,
398                                        ManagedRegister scratch);
399
400  virtual void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs,
401                                          FrameOffset fr_offs,
402                                          ManagedRegister scratch);
403  virtual void StoreStackOffsetToThread64(ThreadOffset<8> thr_offs,
404                                          FrameOffset fr_offs,
405                                          ManagedRegister scratch);
406
407  virtual void StoreStackPointerToThread32(ThreadOffset<4> thr_offs);
408  virtual void StoreStackPointerToThread64(ThreadOffset<8> thr_offs);
409
410  virtual void StoreSpanning(FrameOffset dest, ManagedRegister src,
411                             FrameOffset in_off, ManagedRegister scratch) = 0;
412
413  // Load routines
414  virtual void Load(ManagedRegister dest, FrameOffset src, size_t size) = 0;
415
416  virtual void LoadFromThread32(ManagedRegister dest, ThreadOffset<4> src, size_t size);
417  virtual void LoadFromThread64(ManagedRegister dest, ThreadOffset<8> src, size_t size);
418
419  virtual void LoadRef(ManagedRegister dest, FrameOffset src) = 0;
420  // If unpoison_reference is true and kPoisonReference is true, then we negate the read reference.
421  virtual void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs,
422                       bool unpoison_reference) = 0;
423
424  virtual void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) = 0;
425
426  virtual void LoadRawPtrFromThread32(ManagedRegister dest, ThreadOffset<4> offs);
427  virtual void LoadRawPtrFromThread64(ManagedRegister dest, ThreadOffset<8> offs);
428
429  // Copying routines
430  virtual void Move(ManagedRegister dest, ManagedRegister src, size_t size) = 0;
431
432  virtual void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs,
433                                      ManagedRegister scratch);
434  virtual void CopyRawPtrFromThread64(FrameOffset fr_offs, ThreadOffset<8> thr_offs,
435                                      ManagedRegister scratch);
436
437  virtual void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs,
438                                    ManagedRegister scratch);
439  virtual void CopyRawPtrToThread64(ThreadOffset<8> thr_offs, FrameOffset fr_offs,
440                                    ManagedRegister scratch);
441
442  virtual void CopyRef(FrameOffset dest, FrameOffset src,
443                       ManagedRegister scratch) = 0;
444
445  virtual void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) = 0;
446
447  virtual void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset,
448                    ManagedRegister scratch, size_t size) = 0;
449
450  virtual void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src,
451                    ManagedRegister scratch, size_t size) = 0;
452
453  virtual void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset,
454                    ManagedRegister scratch, size_t size) = 0;
455
456  virtual void Copy(ManagedRegister dest, Offset dest_offset,
457                    ManagedRegister src, Offset src_offset,
458                    ManagedRegister scratch, size_t size) = 0;
459
460  virtual void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset,
461                    ManagedRegister scratch, size_t size) = 0;
462
463  virtual void MemoryBarrier(ManagedRegister scratch) = 0;
464
465  // Sign extension
466  virtual void SignExtend(ManagedRegister mreg, size_t size) = 0;
467
468  // Zero extension
469  virtual void ZeroExtend(ManagedRegister mreg, size_t size) = 0;
470
471  // Exploit fast access in managed code to Thread::Current()
472  virtual void GetCurrentThread(ManagedRegister tr) = 0;
473  virtual void GetCurrentThread(FrameOffset dest_offset,
474                                ManagedRegister scratch) = 0;
475
476  // Set up out_reg to hold a Object** into the handle scope, or to be null if the
477  // value is null and null_allowed. in_reg holds a possibly stale reference
478  // that can be used to avoid loading the handle scope entry to see if the value is
479  // null.
480  virtual void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset,
481                               ManagedRegister in_reg, bool null_allowed) = 0;
482
483  // Set up out_off to hold a Object** into the handle scope, or to be null if the
484  // value is null and null_allowed.
485  virtual void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset,
486                               ManagedRegister scratch, bool null_allowed) = 0;
487
488  // src holds a handle scope entry (Object**) load this into dst
489  virtual void LoadReferenceFromHandleScope(ManagedRegister dst,
490                                     ManagedRegister src) = 0;
491
492  // Heap::VerifyObject on src. In some cases (such as a reference to this) we
493  // know that src may not be null.
494  virtual void VerifyObject(ManagedRegister src, bool could_be_null) = 0;
495  virtual void VerifyObject(FrameOffset src, bool could_be_null) = 0;
496
497  // Call to address held at [base+offset]
498  virtual void Call(ManagedRegister base, Offset offset,
499                    ManagedRegister scratch) = 0;
500  virtual void Call(FrameOffset base, Offset offset,
501                    ManagedRegister scratch) = 0;
502  virtual void CallFromThread32(ThreadOffset<4> offset, ManagedRegister scratch);
503  virtual void CallFromThread64(ThreadOffset<8> offset, ManagedRegister scratch);
504
505  // Generate code to check if Thread::Current()->exception_ is non-null
506  // and branch to a ExceptionSlowPath if it is.
507  virtual void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) = 0;
508
509  virtual void Bind(Label* label) = 0;
510  virtual void Jump(Label* label) = 0;
511
512  virtual ~Assembler() {}
513
514  /**
515   * @brief Buffer of DWARF's Call Frame Information opcodes.
516   * @details It is used by debuggers and other tools to unwind the call stack.
517   */
518  DebugFrameOpCodeWriterForAssembler& cfi() { return cfi_; }
519
520 protected:
521  explicit Assembler(ArenaAllocator* arena) : buffer_(arena), cfi_(this) {}
522
523  ArenaAllocator* GetArena() {
524    return buffer_.GetArena();
525  }
526
527  AssemblerBuffer buffer_;
528
529  DebugFrameOpCodeWriterForAssembler cfi_;
530};
531
532}  // namespace art
533
534#endif  // ART_COMPILER_UTILS_ASSEMBLER_H_
535