code_generator.h revision 0d5a281c671444bfa75d63caf1427a8c0e6e1177
1/*
2 * Copyright (C) 2014 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_OPTIMIZING_CODE_GENERATOR_H_
18#define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
19
20#include "arch/instruction_set.h"
21#include "arch/instruction_set_features.h"
22#include "base/arena_containers.h"
23#include "base/arena_object.h"
24#include "base/bit_field.h"
25#include "compiled_method.h"
26#include "driver/compiler_options.h"
27#include "globals.h"
28#include "graph_visualizer.h"
29#include "locations.h"
30#include "memory_region.h"
31#include "nodes.h"
32#include "optimizing_compiler_stats.h"
33#include "stack_map_stream.h"
34#include "utils/label.h"
35
36namespace art {
37
38// Binary encoding of 2^32 for type double.
39static int64_t constexpr k2Pow32EncodingForDouble = INT64_C(0x41F0000000000000);
40// Binary encoding of 2^31 for type double.
41static int64_t constexpr k2Pow31EncodingForDouble = INT64_C(0x41E0000000000000);
42
43// Minimum value for a primitive integer.
44static int32_t constexpr kPrimIntMin = 0x80000000;
45// Minimum value for a primitive long.
46static int64_t constexpr kPrimLongMin = INT64_C(0x8000000000000000);
47
48// Maximum value for a primitive integer.
49static int32_t constexpr kPrimIntMax = 0x7fffffff;
50// Maximum value for a primitive long.
51static int64_t constexpr kPrimLongMax = INT64_C(0x7fffffffffffffff);
52
53class Assembler;
54class CodeGenerator;
55class CompilerDriver;
56class LinkerPatch;
57class ParallelMoveResolver;
58
59class CodeAllocator {
60 public:
61  CodeAllocator() {}
62  virtual ~CodeAllocator() {}
63
64  virtual uint8_t* Allocate(size_t size) = 0;
65
66 private:
67  DISALLOW_COPY_AND_ASSIGN(CodeAllocator);
68};
69
70class SlowPathCode : public ArenaObject<kArenaAllocSlowPaths> {
71 public:
72  SlowPathCode() {
73    for (size_t i = 0; i < kMaximumNumberOfExpectedRegisters; ++i) {
74      saved_core_stack_offsets_[i] = kRegisterNotSaved;
75      saved_fpu_stack_offsets_[i] = kRegisterNotSaved;
76    }
77  }
78
79  virtual ~SlowPathCode() {}
80
81  virtual void EmitNativeCode(CodeGenerator* codegen) = 0;
82
83  virtual void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
84  virtual void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations);
85
86  bool IsCoreRegisterSaved(int reg) const {
87    return saved_core_stack_offsets_[reg] != kRegisterNotSaved;
88  }
89
90  bool IsFpuRegisterSaved(int reg) const {
91    return saved_fpu_stack_offsets_[reg] != kRegisterNotSaved;
92  }
93
94  uint32_t GetStackOffsetOfCoreRegister(int reg) const {
95    return saved_core_stack_offsets_[reg];
96  }
97
98  uint32_t GetStackOffsetOfFpuRegister(int reg) const {
99    return saved_fpu_stack_offsets_[reg];
100  }
101
102  virtual bool IsFatal() const { return false; }
103
104  virtual const char* GetDescription() const = 0;
105
106  Label* GetEntryLabel() { return &entry_label_; }
107  Label* GetExitLabel() { return &exit_label_; }
108
109 protected:
110  static constexpr size_t kMaximumNumberOfExpectedRegisters = 32;
111  static constexpr uint32_t kRegisterNotSaved = -1;
112  uint32_t saved_core_stack_offsets_[kMaximumNumberOfExpectedRegisters];
113  uint32_t saved_fpu_stack_offsets_[kMaximumNumberOfExpectedRegisters];
114
115 private:
116  Label entry_label_;
117  Label exit_label_;
118
119  DISALLOW_COPY_AND_ASSIGN(SlowPathCode);
120};
121
122class InvokeDexCallingConventionVisitor {
123 public:
124  virtual Location GetNextLocation(Primitive::Type type) = 0;
125  virtual Location GetReturnLocation(Primitive::Type type) const = 0;
126  virtual Location GetMethodLocation() const = 0;
127
128 protected:
129  InvokeDexCallingConventionVisitor() {}
130  virtual ~InvokeDexCallingConventionVisitor() {}
131
132  // The current index for core registers.
133  uint32_t gp_index_ = 0u;
134  // The current index for floating-point registers.
135  uint32_t float_index_ = 0u;
136  // The current stack index.
137  uint32_t stack_index_ = 0u;
138
139 private:
140  DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitor);
141};
142
143class FieldAccessCallingConvention {
144 public:
145  virtual Location GetObjectLocation() const = 0;
146  virtual Location GetFieldIndexLocation() const = 0;
147  virtual Location GetReturnLocation(Primitive::Type type) const = 0;
148  virtual Location GetSetValueLocation(Primitive::Type type, bool is_instance) const = 0;
149  virtual Location GetFpuLocation(Primitive::Type type) const = 0;
150  virtual ~FieldAccessCallingConvention() {}
151
152 protected:
153  FieldAccessCallingConvention() {}
154
155 private:
156  DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConvention);
157};
158
159class CodeGenerator {
160 public:
161  // Compiles the graph to executable instructions. Returns whether the compilation
162  // succeeded.
163  void CompileBaseline(CodeAllocator* allocator, bool is_leaf = false);
164  void CompileOptimized(CodeAllocator* allocator);
165  static CodeGenerator* Create(HGraph* graph,
166                               InstructionSet instruction_set,
167                               const InstructionSetFeatures& isa_features,
168                               const CompilerOptions& compiler_options,
169                               OptimizingCompilerStats* stats = nullptr);
170  virtual ~CodeGenerator() {}
171
172  // Get the graph. This is the outermost graph, never the graph of a method being inlined.
173  HGraph* GetGraph() const { return graph_; }
174
175  HBasicBlock* GetNextBlockToEmit() const;
176  HBasicBlock* FirstNonEmptyBlock(HBasicBlock* block) const;
177  bool GoesToNextBlock(HBasicBlock* current, HBasicBlock* next) const;
178
179  size_t GetStackSlotOfParameter(HParameterValue* parameter) const {
180    // Note that this follows the current calling convention.
181    return GetFrameSize()
182        + InstructionSetPointerSize(GetInstructionSet())  // Art method
183        + parameter->GetIndex() * kVRegSize;
184  }
185
186  virtual void Initialize() = 0;
187  virtual void Finalize(CodeAllocator* allocator);
188  virtual void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches);
189  virtual void GenerateFrameEntry() = 0;
190  virtual void GenerateFrameExit() = 0;
191  virtual void Bind(HBasicBlock* block) = 0;
192  virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) = 0;
193  virtual void MoveConstant(Location destination, int32_t value) = 0;
194  virtual void MoveLocation(Location dst, Location src, Primitive::Type dst_type) = 0;
195  virtual void AddLocationAsTemp(Location location, LocationSummary* locations) = 0;
196
197  virtual Assembler* GetAssembler() = 0;
198  virtual const Assembler& GetAssembler() const = 0;
199  virtual size_t GetWordSize() const = 0;
200  virtual size_t GetFloatingPointSpillSlotSize() const = 0;
201  virtual uintptr_t GetAddressOf(HBasicBlock* block) const = 0;
202  void InitializeCodeGeneration(size_t number_of_spill_slots,
203                                size_t maximum_number_of_live_core_registers,
204                                size_t maximum_number_of_live_fpu_registers,
205                                size_t number_of_out_slots,
206                                const ArenaVector<HBasicBlock*>& block_order);
207  int32_t GetStackSlot(HLocal* local) const;
208  Location GetTemporaryLocation(HTemporary* temp) const;
209
210  uint32_t GetFrameSize() const { return frame_size_; }
211  void SetFrameSize(uint32_t size) { frame_size_ = size; }
212  uint32_t GetCoreSpillMask() const { return core_spill_mask_; }
213  uint32_t GetFpuSpillMask() const { return fpu_spill_mask_; }
214
215  size_t GetNumberOfCoreRegisters() const { return number_of_core_registers_; }
216  size_t GetNumberOfFloatingPointRegisters() const { return number_of_fpu_registers_; }
217  virtual void SetupBlockedRegisters(bool is_baseline) const = 0;
218
219  virtual void ComputeSpillMask() {
220    core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
221    DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
222    fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
223  }
224
225  static uint32_t ComputeRegisterMask(const int* registers, size_t length) {
226    uint32_t mask = 0;
227    for (size_t i = 0, e = length; i < e; ++i) {
228      mask |= (1 << registers[i]);
229    }
230    return mask;
231  }
232
233  virtual void DumpCoreRegister(std::ostream& stream, int reg) const = 0;
234  virtual void DumpFloatingPointRegister(std::ostream& stream, int reg) const = 0;
235  virtual InstructionSet GetInstructionSet() const = 0;
236
237  const CompilerOptions& GetCompilerOptions() const { return compiler_options_; }
238
239  void MaybeRecordStat(MethodCompilationStat compilation_stat, size_t count = 1) const;
240
241  // Saves the register in the stack. Returns the size taken on stack.
242  virtual size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) = 0;
243  // Restores the register from the stack. Returns the size taken on stack.
244  virtual size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) = 0;
245
246  virtual size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) = 0;
247  virtual size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) = 0;
248
249  virtual bool NeedsTwoRegisters(Primitive::Type type) const = 0;
250  // Returns whether we should split long moves in parallel moves.
251  virtual bool ShouldSplitLongMoves() const { return false; }
252
253  size_t GetNumberOfCoreCalleeSaveRegisters() const {
254    return POPCOUNT(core_callee_save_mask_);
255  }
256
257  size_t GetNumberOfCoreCallerSaveRegisters() const {
258    DCHECK_GE(GetNumberOfCoreRegisters(), GetNumberOfCoreCalleeSaveRegisters());
259    return GetNumberOfCoreRegisters() - GetNumberOfCoreCalleeSaveRegisters();
260  }
261
262  bool IsCoreCalleeSaveRegister(int reg) const {
263    return (core_callee_save_mask_ & (1 << reg)) != 0;
264  }
265
266  bool IsFloatingPointCalleeSaveRegister(int reg) const {
267    return (fpu_callee_save_mask_ & (1 << reg)) != 0;
268  }
269
270  // Record native to dex mapping for a suspend point.  Required by runtime.
271  void RecordPcInfo(HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path = nullptr);
272  // Record additional native to dex mappings for native debugging/profiling tools.
273  void RecordNativeDebugInfo(uint32_t dex_pc, uintptr_t native_pc_begin, uintptr_t native_pc_end);
274
275  bool CanMoveNullCheckToUser(HNullCheck* null_check);
276  void MaybeRecordImplicitNullCheck(HInstruction* instruction);
277
278  // Records a stack map which the runtime might use to set catch phi values
279  // during exception delivery.
280  // TODO: Replace with a catch-entering instruction that records the environment.
281  void RecordCatchBlockInfo();
282
283  // Returns true if implicit null checks are allowed in the compiler options
284  // and if the null check is not inside a try block. We currently cannot do
285  // implicit null checks in that case because we need the NullCheckSlowPath to
286  // save live registers, which may be needed by the runtime to set catch phis.
287  bool IsImplicitNullCheckAllowed(HNullCheck* null_check) const;
288
289  void AddSlowPath(SlowPathCode* slow_path) {
290    slow_paths_.push_back(slow_path);
291  }
292
293  void BuildMappingTable(ArenaVector<uint8_t>* vector) const;
294  void BuildVMapTable(ArenaVector<uint8_t>* vector) const;
295  void BuildNativeGCMap(
296      ArenaVector<uint8_t>* vector, const CompilerDriver& compiler_driver) const;
297  void BuildStackMaps(MemoryRegion region);
298  size_t ComputeStackMapsSize();
299
300  bool IsBaseline() const {
301    return is_baseline_;
302  }
303
304  bool IsLeafMethod() const {
305    return is_leaf_;
306  }
307
308  void MarkNotLeaf() {
309    is_leaf_ = false;
310    requires_current_method_ = true;
311  }
312
313  void SetRequiresCurrentMethod() {
314    requires_current_method_ = true;
315  }
316
317  bool RequiresCurrentMethod() const {
318    return requires_current_method_;
319  }
320
321  // Clears the spill slots taken by loop phis in the `LocationSummary` of the
322  // suspend check. This is called when the code generator generates code
323  // for the suspend check at the back edge (instead of where the suspend check
324  // is, which is the loop entry). At this point, the spill slots for the phis
325  // have not been written to.
326  void ClearSpillSlotsFromLoopPhisInStackMap(HSuspendCheck* suspend_check) const;
327
328  bool* GetBlockedCoreRegisters() const { return blocked_core_registers_; }
329  bool* GetBlockedFloatingPointRegisters() const { return blocked_fpu_registers_; }
330
331  // Helper that returns the pointer offset of an index in an object array.
332  // Note: this method assumes we always have the same pointer size, regardless
333  // of the architecture.
334  static size_t GetCacheOffset(uint32_t index);
335  // Pointer variant for ArtMethod and ArtField arrays.
336  size_t GetCachePointerOffset(uint32_t index);
337
338  void EmitParallelMoves(Location from1,
339                         Location to1,
340                         Primitive::Type type1,
341                         Location from2,
342                         Location to2,
343                         Primitive::Type type2);
344
345  static bool StoreNeedsWriteBarrier(Primitive::Type type, HInstruction* value) {
346    // Check that null value is not represented as an integer constant.
347    DCHECK(type != Primitive::kPrimNot || !value->IsIntConstant());
348    return type == Primitive::kPrimNot && !value->IsNullConstant();
349  }
350
351  void ValidateInvokeRuntime(HInstruction* instruction, SlowPathCode* slow_path);
352
353  void AddAllocatedRegister(Location location) {
354    allocated_registers_.Add(location);
355  }
356
357  bool HasAllocatedRegister(bool is_core, int reg) const {
358    return is_core
359        ? allocated_registers_.ContainsCoreRegister(reg)
360        : allocated_registers_.ContainsFloatingPointRegister(reg);
361  }
362
363  void AllocateLocations(HInstruction* instruction);
364
365  // Tells whether the stack frame of the compiled method is
366  // considered "empty", that is either actually having a size of zero,
367  // or just containing the saved return address register.
368  bool HasEmptyFrame() const {
369    return GetFrameSize() == (CallPushesPC() ? GetWordSize() : 0);
370  }
371
372  static int32_t GetInt32ValueOf(HConstant* constant) {
373    if (constant->IsIntConstant()) {
374      return constant->AsIntConstant()->GetValue();
375    } else if (constant->IsNullConstant()) {
376      return 0;
377    } else {
378      DCHECK(constant->IsFloatConstant());
379      return bit_cast<int32_t, float>(constant->AsFloatConstant()->GetValue());
380    }
381  }
382
383  static int64_t GetInt64ValueOf(HConstant* constant) {
384    if (constant->IsIntConstant()) {
385      return constant->AsIntConstant()->GetValue();
386    } else if (constant->IsNullConstant()) {
387      return 0;
388    } else if (constant->IsFloatConstant()) {
389      return bit_cast<int32_t, float>(constant->AsFloatConstant()->GetValue());
390    } else if (constant->IsLongConstant()) {
391      return constant->AsLongConstant()->GetValue();
392    } else {
393      DCHECK(constant->IsDoubleConstant());
394      return bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
395    }
396  }
397
398  size_t GetFirstRegisterSlotInSlowPath() const {
399    return first_register_slot_in_slow_path_;
400  }
401
402  uint32_t FrameEntrySpillSize() const {
403    return GetFpuSpillSize() + GetCoreSpillSize();
404  }
405
406  virtual ParallelMoveResolver* GetMoveResolver() = 0;
407
408  static void CreateCommonInvokeLocationSummary(
409      HInvoke* invoke, InvokeDexCallingConventionVisitor* visitor);
410
411  void GenerateInvokeUnresolvedRuntimeCall(HInvokeUnresolved* invoke);
412
413  void CreateUnresolvedFieldLocationSummary(
414      HInstruction* field_access,
415      Primitive::Type field_type,
416      const FieldAccessCallingConvention& calling_convention);
417
418  void GenerateUnresolvedFieldAccess(
419      HInstruction* field_access,
420      Primitive::Type field_type,
421      uint32_t field_index,
422      uint32_t dex_pc,
423      const FieldAccessCallingConvention& calling_convention);
424
425  // TODO: This overlaps a bit with MoveFromReturnRegister. Refactor for a better design.
426  static void CreateLoadClassLocationSummary(HLoadClass* cls,
427                                             Location runtime_type_index_location,
428                                             Location runtime_return_location,
429                                             bool code_generator_supports_read_barrier = false);
430
431  static void CreateSystemArrayCopyLocationSummary(HInvoke* invoke);
432
433  void SetDisassemblyInformation(DisassemblyInformation* info) { disasm_info_ = info; }
434  DisassemblyInformation* GetDisassemblyInformation() const { return disasm_info_; }
435
436  virtual void InvokeRuntime(QuickEntrypointEnum entrypoint,
437                             HInstruction* instruction,
438                             uint32_t dex_pc,
439                             SlowPathCode* slow_path) = 0;
440
441  // Check if the desired_dispatch_info is supported. If it is, return it,
442  // otherwise return a fall-back info that should be used instead.
443  virtual HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
444      const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
445      MethodReference target_method) = 0;
446
447  // Generate a call to a static or direct method.
448  virtual void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) = 0;
449  // Generate a call to a virtual method.
450  virtual void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) = 0;
451
452  // Copy the result of a call into the given target.
453  virtual void MoveFromReturnRegister(Location trg, Primitive::Type type) = 0;
454
455  const ArenaVector<SrcMapElem>& GetSrcMappingTable() const {
456    return src_map_;
457  }
458
459 protected:
460  // Method patch info used for recording locations of required linker patches and
461  // target methods. The target method can be used for various purposes, whether for
462  // patching the address of the method or the code pointer or a PC-relative call.
463  template <typename LabelType>
464  struct MethodPatchInfo {
465    explicit MethodPatchInfo(MethodReference m) : target_method(m), label() { }
466
467    MethodReference target_method;
468    LabelType label;
469  };
470
471  CodeGenerator(HGraph* graph,
472                size_t number_of_core_registers,
473                size_t number_of_fpu_registers,
474                size_t number_of_register_pairs,
475                uint32_t core_callee_save_mask,
476                uint32_t fpu_callee_save_mask,
477                const CompilerOptions& compiler_options,
478                OptimizingCompilerStats* stats)
479      : frame_size_(0),
480        core_spill_mask_(0),
481        fpu_spill_mask_(0),
482        first_register_slot_in_slow_path_(0),
483        blocked_core_registers_(graph->GetArena()->AllocArray<bool>(number_of_core_registers,
484                                                                    kArenaAllocCodeGenerator)),
485        blocked_fpu_registers_(graph->GetArena()->AllocArray<bool>(number_of_fpu_registers,
486                                                                   kArenaAllocCodeGenerator)),
487        blocked_register_pairs_(graph->GetArena()->AllocArray<bool>(number_of_register_pairs,
488                                                                    kArenaAllocCodeGenerator)),
489        number_of_core_registers_(number_of_core_registers),
490        number_of_fpu_registers_(number_of_fpu_registers),
491        number_of_register_pairs_(number_of_register_pairs),
492        core_callee_save_mask_(core_callee_save_mask),
493        fpu_callee_save_mask_(fpu_callee_save_mask),
494        stack_map_stream_(graph->GetArena()),
495        block_order_(nullptr),
496        is_baseline_(false),
497        disasm_info_(nullptr),
498        stats_(stats),
499        graph_(graph),
500        compiler_options_(compiler_options),
501        src_map_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
502        slow_paths_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
503        current_slow_path_(nullptr),
504        current_block_index_(0),
505        is_leaf_(true),
506        requires_current_method_(false) {
507    slow_paths_.reserve(8);
508  }
509
510  // Register allocation logic.
511  void AllocateRegistersLocally(HInstruction* instruction) const;
512
513  // Backend specific implementation for allocating a register.
514  virtual Location AllocateFreeRegister(Primitive::Type type) const = 0;
515
516  static size_t FindFreeEntry(bool* array, size_t length);
517  static size_t FindTwoFreeConsecutiveAlignedEntries(bool* array, size_t length);
518
519  virtual Location GetStackLocation(HLoadLocal* load) const = 0;
520
521  virtual HGraphVisitor* GetLocationBuilder() = 0;
522  virtual HGraphVisitor* GetInstructionVisitor() = 0;
523
524  // Returns the location of the first spilled entry for floating point registers,
525  // relative to the stack pointer.
526  uint32_t GetFpuSpillStart() const {
527    return GetFrameSize() - FrameEntrySpillSize();
528  }
529
530  uint32_t GetFpuSpillSize() const {
531    return POPCOUNT(fpu_spill_mask_) * GetFloatingPointSpillSlotSize();
532  }
533
534  uint32_t GetCoreSpillSize() const {
535    return POPCOUNT(core_spill_mask_) * GetWordSize();
536  }
537
538  bool HasAllocatedCalleeSaveRegisters() const {
539    // We check the core registers against 1 because it always comprises the return PC.
540    return (POPCOUNT(allocated_registers_.GetCoreRegisters() & core_callee_save_mask_) != 1)
541      || (POPCOUNT(allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_) != 0);
542  }
543
544  bool CallPushesPC() const {
545    InstructionSet instruction_set = GetInstructionSet();
546    return instruction_set == kX86 || instruction_set == kX86_64;
547  }
548
549  // Arm64 has its own type for a label, so we need to templatize these methods
550  // to share the logic.
551
552  template <typename LabelType>
553  LabelType* CommonInitializeLabels() {
554    // We use raw array allocations instead of ArenaVector<> because Labels are
555    // non-constructible and non-movable and as such cannot be held in a vector.
556    size_t size = GetGraph()->GetBlocks().size();
557    LabelType* labels = GetGraph()->GetArena()->AllocArray<LabelType>(size,
558                                                                      kArenaAllocCodeGenerator);
559    for (size_t i = 0; i != size; ++i) {
560      new(labels + i) LabelType();
561    }
562    return labels;
563  }
564
565  template <typename LabelType>
566  LabelType* CommonGetLabelOf(LabelType* raw_pointer_to_labels_array, HBasicBlock* block) const {
567    block = FirstNonEmptyBlock(block);
568    return raw_pointer_to_labels_array + block->GetBlockId();
569  }
570
571  SlowPathCode* GetCurrentSlowPath() {
572    return current_slow_path_;
573  }
574
575  // Frame size required for this method.
576  uint32_t frame_size_;
577  uint32_t core_spill_mask_;
578  uint32_t fpu_spill_mask_;
579  uint32_t first_register_slot_in_slow_path_;
580
581  // Registers that were allocated during linear scan.
582  RegisterSet allocated_registers_;
583
584  // Arrays used when doing register allocation to know which
585  // registers we can allocate. `SetupBlockedRegisters` updates the
586  // arrays.
587  bool* const blocked_core_registers_;
588  bool* const blocked_fpu_registers_;
589  bool* const blocked_register_pairs_;
590  size_t number_of_core_registers_;
591  size_t number_of_fpu_registers_;
592  size_t number_of_register_pairs_;
593  const uint32_t core_callee_save_mask_;
594  const uint32_t fpu_callee_save_mask_;
595
596  StackMapStream stack_map_stream_;
597
598  // The order to use for code generation.
599  const ArenaVector<HBasicBlock*>* block_order_;
600
601  // Whether we are using baseline.
602  bool is_baseline_;
603
604  DisassemblyInformation* disasm_info_;
605
606 private:
607  void InitLocationsBaseline(HInstruction* instruction);
608  size_t GetStackOffsetOfSavedRegister(size_t index);
609  void GenerateSlowPaths();
610  void CompileInternal(CodeAllocator* allocator, bool is_baseline);
611  void BlockIfInRegister(Location location, bool is_out = false) const;
612  void EmitEnvironment(HEnvironment* environment, SlowPathCode* slow_path);
613
614  OptimizingCompilerStats* stats_;
615
616  HGraph* const graph_;
617  const CompilerOptions& compiler_options_;
618
619  // Native to dex_pc map used for native debugging/profiling tools.
620  ArenaVector<SrcMapElem> src_map_;
621  ArenaVector<SlowPathCode*> slow_paths_;
622
623  // The current slow path that we're generating code for.
624  SlowPathCode* current_slow_path_;
625
626  // The current block index in `block_order_` of the block
627  // we are generating code for.
628  size_t current_block_index_;
629
630  // Whether the method is a leaf method.
631  bool is_leaf_;
632
633  // Whether an instruction in the graph accesses the current method.
634  bool requires_current_method_;
635
636  friend class OptimizingCFITest;
637
638  DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
639};
640
641template <typename C, typename F>
642class CallingConvention {
643 public:
644  CallingConvention(const C* registers,
645                    size_t number_of_registers,
646                    const F* fpu_registers,
647                    size_t number_of_fpu_registers,
648                    size_t pointer_size)
649      : registers_(registers),
650        number_of_registers_(number_of_registers),
651        fpu_registers_(fpu_registers),
652        number_of_fpu_registers_(number_of_fpu_registers),
653        pointer_size_(pointer_size) {}
654
655  size_t GetNumberOfRegisters() const { return number_of_registers_; }
656  size_t GetNumberOfFpuRegisters() const { return number_of_fpu_registers_; }
657
658  C GetRegisterAt(size_t index) const {
659    DCHECK_LT(index, number_of_registers_);
660    return registers_[index];
661  }
662
663  F GetFpuRegisterAt(size_t index) const {
664    DCHECK_LT(index, number_of_fpu_registers_);
665    return fpu_registers_[index];
666  }
667
668  size_t GetStackOffsetOf(size_t index) const {
669    // We still reserve the space for parameters passed by registers.
670    // Add space for the method pointer.
671    return pointer_size_ + index * kVRegSize;
672  }
673
674 private:
675  const C* registers_;
676  const size_t number_of_registers_;
677  const F* fpu_registers_;
678  const size_t number_of_fpu_registers_;
679  const size_t pointer_size_;
680
681  DISALLOW_COPY_AND_ASSIGN(CallingConvention);
682};
683
684}  // namespace art
685
686#endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_H_
687