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_X86_H_
18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_H_
19 
20 #include "arch/x86/instruction_set_features_x86.h"
21 #include "base/enums.h"
22 #include "code_generator.h"
23 #include "dex/dex_file_types.h"
24 #include "driver/compiler_options.h"
25 #include "nodes.h"
26 #include "parallel_move_resolver.h"
27 #include "utils/x86/assembler_x86.h"
28 
29 namespace art {
30 namespace x86 {
31 
32 // Use a local definition to prevent copying mistakes.
33 static constexpr size_t kX86WordSize = static_cast<size_t>(kX86PointerSize);
34 
35 class CodeGeneratorX86;
36 
37 static constexpr Register kParameterCoreRegisters[] = { ECX, EDX, EBX };
38 static constexpr RegisterPair kParameterCorePairRegisters[] = { ECX_EDX, EDX_EBX };
39 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
40 static constexpr XmmRegister kParameterFpuRegisters[] = { XMM0, XMM1, XMM2, XMM3 };
41 static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters);
42 
43 static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX, EBX };
44 static constexpr size_t kRuntimeParameterCoreRegistersLength =
45     arraysize(kRuntimeParameterCoreRegisters);
46 static constexpr XmmRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1, XMM2, XMM3 };
47 static constexpr size_t kRuntimeParameterFpuRegistersLength =
48     arraysize(kRuntimeParameterFpuRegisters);
49 
50 class InvokeRuntimeCallingConvention : public CallingConvention<Register, XmmRegister> {
51  public:
InvokeRuntimeCallingConvention()52   InvokeRuntimeCallingConvention()
53       : CallingConvention(kRuntimeParameterCoreRegisters,
54                           kRuntimeParameterCoreRegistersLength,
55                           kRuntimeParameterFpuRegisters,
56                           kRuntimeParameterFpuRegistersLength,
57                           kX86PointerSize) {}
58 
59  private:
60   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
61 };
62 
63 class InvokeDexCallingConvention : public CallingConvention<Register, XmmRegister> {
64  public:
InvokeDexCallingConvention()65   InvokeDexCallingConvention() : CallingConvention(
66       kParameterCoreRegisters,
67       kParameterCoreRegistersLength,
68       kParameterFpuRegisters,
69       kParameterFpuRegistersLength,
70       kX86PointerSize) {}
71 
GetRegisterPairAt(size_t argument_index)72   RegisterPair GetRegisterPairAt(size_t argument_index) {
73     DCHECK_LT(argument_index + 1, GetNumberOfRegisters());
74     return kParameterCorePairRegisters[argument_index];
75   }
76 
77  private:
78   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
79 };
80 
81 class InvokeDexCallingConventionVisitorX86 : public InvokeDexCallingConventionVisitor {
82  public:
InvokeDexCallingConventionVisitorX86()83   InvokeDexCallingConventionVisitorX86() {}
~InvokeDexCallingConventionVisitorX86()84   virtual ~InvokeDexCallingConventionVisitorX86() {}
85 
86   Location GetNextLocation(DataType::Type type) override;
87   Location GetReturnLocation(DataType::Type type) const override;
88   Location GetMethodLocation() const override;
89 
90  private:
91   InvokeDexCallingConvention calling_convention;
92 
93   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorX86);
94 };
95 
96 class CriticalNativeCallingConventionVisitorX86 : public InvokeDexCallingConventionVisitor {
97  public:
CriticalNativeCallingConventionVisitorX86(bool for_register_allocation)98   explicit CriticalNativeCallingConventionVisitorX86(bool for_register_allocation)
99       : for_register_allocation_(for_register_allocation) {}
100 
~CriticalNativeCallingConventionVisitorX86()101   virtual ~CriticalNativeCallingConventionVisitorX86() {}
102 
103   Location GetNextLocation(DataType::Type type) override;
104   Location GetReturnLocation(DataType::Type type) const override;
105   Location GetMethodLocation() const override;
106 
GetStackOffset()107   size_t GetStackOffset() const { return stack_offset_; }
108 
109  private:
110   // Register allocator does not support adjusting frame size, so we cannot provide final locations
111   // of stack arguments for register allocation. We ask the register allocator for any location and
112   // move these arguments to the right place after adjusting the SP when generating the call.
113   const bool for_register_allocation_;
114   size_t stack_offset_ = 0u;
115 
116   DISALLOW_COPY_AND_ASSIGN(CriticalNativeCallingConventionVisitorX86);
117 };
118 
119 class FieldAccessCallingConventionX86 : public FieldAccessCallingConvention {
120  public:
FieldAccessCallingConventionX86()121   FieldAccessCallingConventionX86() {}
122 
GetObjectLocation()123   Location GetObjectLocation() const override {
124     return Location::RegisterLocation(ECX);
125   }
GetFieldIndexLocation()126   Location GetFieldIndexLocation() const override {
127     return Location::RegisterLocation(EAX);
128   }
GetReturnLocation(DataType::Type type)129   Location GetReturnLocation(DataType::Type type) const override {
130     return DataType::Is64BitType(type)
131         ? Location::RegisterPairLocation(EAX, EDX)
132         : Location::RegisterLocation(EAX);
133   }
GetSetValueLocation(DataType::Type type,bool is_instance)134   Location GetSetValueLocation(DataType::Type type, bool is_instance) const override {
135     return DataType::Is64BitType(type)
136         ? (is_instance
137             ? Location::RegisterPairLocation(EDX, EBX)
138             : Location::RegisterPairLocation(ECX, EDX))
139         : (is_instance
140             ? Location::RegisterLocation(EDX)
141             : Location::RegisterLocation(ECX));
142   }
GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED)143   Location GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED) const override {
144     return Location::FpuRegisterLocation(XMM0);
145   }
146 
147  private:
148   DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionX86);
149 };
150 
151 class ParallelMoveResolverX86 : public ParallelMoveResolverWithSwap {
152  public:
ParallelMoveResolverX86(ArenaAllocator * allocator,CodeGeneratorX86 * codegen)153   ParallelMoveResolverX86(ArenaAllocator* allocator, CodeGeneratorX86* codegen)
154       : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {}
155 
156   void EmitMove(size_t index) override;
157   void EmitSwap(size_t index) override;
158   void SpillScratch(int reg) override;
159   void RestoreScratch(int reg) override;
160 
161   X86Assembler* GetAssembler() const;
162 
163  private:
164   void Exchange(Register reg, int mem);
165   void Exchange32(XmmRegister reg, int mem);
166   void Exchange128(XmmRegister reg, int mem);
167   void ExchangeMemory(int mem1, int mem2, int number_of_words);
168   void MoveMemoryToMemory(int dst, int src, int number_of_words);
169 
170   CodeGeneratorX86* const codegen_;
171 
172   DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverX86);
173 };
174 
175 class LocationsBuilderX86 : public HGraphVisitor {
176  public:
LocationsBuilderX86(HGraph * graph,CodeGeneratorX86 * codegen)177   LocationsBuilderX86(HGraph* graph, CodeGeneratorX86* codegen)
178       : HGraphVisitor(graph), codegen_(codegen) {}
179 
180 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
181   void Visit##name(H##name* instr) override;
182 
183   FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_CONCRETE_INSTRUCTION_X86(DECLARE_VISIT_INSTRUCTION)184   FOR_EACH_CONCRETE_INSTRUCTION_X86(DECLARE_VISIT_INSTRUCTION)
185   FOR_EACH_CONCRETE_INSTRUCTION_X86_COMMON(DECLARE_VISIT_INSTRUCTION)
186 
187 #undef DECLARE_VISIT_INSTRUCTION
188 
189   void VisitInstruction(HInstruction* instruction) override {
190     LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
191                << " (id " << instruction->GetId() << ")";
192   }
193 
194  private:
195   void HandleBitwiseOperation(HBinaryOperation* instruction);
196   void HandleInvoke(HInvoke* invoke);
197   void HandleCondition(HCondition* condition);
198   void HandleShift(HBinaryOperation* instruction);
199   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
200   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
201   bool CpuHasAvxFeatureFlag();
202   bool CpuHasAvx2FeatureFlag();
203 
204   CodeGeneratorX86* const codegen_;
205   InvokeDexCallingConventionVisitorX86 parameter_visitor_;
206 
207   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86);
208 };
209 
210 class InstructionCodeGeneratorX86 : public InstructionCodeGenerator {
211  public:
212   InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen);
213 
214 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
215   void Visit##name(H##name* instr) override;
216 
217   FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_CONCRETE_INSTRUCTION_X86(DECLARE_VISIT_INSTRUCTION)218   FOR_EACH_CONCRETE_INSTRUCTION_X86(DECLARE_VISIT_INSTRUCTION)
219   FOR_EACH_CONCRETE_INSTRUCTION_X86_COMMON(DECLARE_VISIT_INSTRUCTION)
220 
221 #undef DECLARE_VISIT_INSTRUCTION
222 
223   void VisitInstruction(HInstruction* instruction) override {
224     LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
225                << " (id " << instruction->GetId() << ")";
226   }
227 
GetAssembler()228   X86Assembler* GetAssembler() const { return assembler_; }
229 
230   // The compare/jump sequence will generate about (1.5 * num_entries) instructions. A jump
231   // table version generates 7 instructions and num_entries literals. Compare/jump sequence will
232   // generates less code/data with a small num_entries.
233   static constexpr uint32_t kPackedSwitchJumpTableThreshold = 5;
234 
235  private:
236   // Generate code for the given suspend check. If not null, `successor`
237   // is the block to branch to if the suspend check is not needed, and after
238   // the suspend call.
239   void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
240   void GenerateClassInitializationCheck(SlowPathCode* slow_path, Register class_reg);
241   void GenerateBitstringTypeCheckCompare(HTypeCheckInstruction* check, Register temp);
242   void HandleBitwiseOperation(HBinaryOperation* instruction);
243   void GenerateDivRemIntegral(HBinaryOperation* instruction);
244   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
245   void DivByPowerOfTwo(HDiv* instruction);
246   void RemByPowerOfTwo(HRem* instruction);
247   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
248   void GenerateRemFP(HRem* rem);
249   void HandleCondition(HCondition* condition);
250   void HandleShift(HBinaryOperation* instruction);
251   void GenerateShlLong(const Location& loc, Register shifter);
252   void GenerateShrLong(const Location& loc, Register shifter);
253   void GenerateUShrLong(const Location& loc, Register shifter);
254   void GenerateShlLong(const Location& loc, int shift);
255   void GenerateShrLong(const Location& loc, int shift);
256   void GenerateUShrLong(const Location& loc, int shift);
257   void GenerateMinMaxInt(LocationSummary* locations, bool is_min, DataType::Type type);
258   void GenerateMinMaxFP(LocationSummary* locations, bool is_min, DataType::Type type);
259   void GenerateMinMax(HBinaryOperation* minmax, bool is_min);
260 
261   void HandleFieldSet(HInstruction* instruction,
262                       const FieldInfo& field_info,
263                       bool value_can_be_null);
264   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
265 
266   // Generate a heap reference load using one register `out`:
267   //
268   //   out <- *(out + offset)
269   //
270   // while honoring heap poisoning and/or read barriers (if any).
271   //
272   // Location `maybe_temp` is used when generating a read barrier and
273   // shall be a register in that case; it may be an invalid location
274   // otherwise.
275   void GenerateReferenceLoadOneRegister(HInstruction* instruction,
276                                         Location out,
277                                         uint32_t offset,
278                                         Location maybe_temp,
279                                         ReadBarrierOption read_barrier_option);
280   // Generate a heap reference load using two different registers
281   // `out` and `obj`:
282   //
283   //   out <- *(obj + offset)
284   //
285   // while honoring heap poisoning and/or read barriers (if any).
286   //
287   // Location `maybe_temp` is used when generating a Baker's (fast
288   // path) read barrier and shall be a register in that case; it may
289   // be an invalid location otherwise.
290   void GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
291                                          Location out,
292                                          Location obj,
293                                          uint32_t offset,
294                                          ReadBarrierOption read_barrier_option);
295   // Generate a GC root reference load:
296   //
297   //   root <- *address
298   //
299   // while honoring read barriers based on read_barrier_option.
300   void GenerateGcRootFieldLoad(HInstruction* instruction,
301                                Location root,
302                                const Address& address,
303                                Label* fixup_label,
304                                ReadBarrierOption read_barrier_option);
305 
306   // Push value to FPU stack. `is_fp` specifies whether the value is floating point or not.
307   // `is_wide` specifies whether it is long/double or not.
308   void PushOntoFPStack(Location source, uint32_t temp_offset,
309                        uint32_t stack_adjustment, bool is_fp, bool is_wide);
310 
311   template<class LabelType>
312   void GenerateTestAndBranch(HInstruction* instruction,
313                              size_t condition_input_index,
314                              LabelType* true_target,
315                              LabelType* false_target);
316   template<class LabelType>
317   void GenerateCompareTestAndBranch(HCondition* condition,
318                                     LabelType* true_target,
319                                     LabelType* false_target);
320   template<class LabelType>
321   void GenerateFPJumps(HCondition* cond, LabelType* true_label, LabelType* false_label);
322   template<class LabelType>
323   void GenerateLongComparesAndJumps(HCondition* cond,
324                                     LabelType* true_label,
325                                     LabelType* false_label);
326 
327   void HandleGoto(HInstruction* got, HBasicBlock* successor);
328   void GenPackedSwitchWithCompares(Register value_reg,
329                                    int32_t lower_bound,
330                                    uint32_t num_entries,
331                                    HBasicBlock* switch_block,
332                                    HBasicBlock* default_block);
333 
334   void GenerateFPCompare(Location lhs, Location rhs, HInstruction* insn, bool is_double);
335   bool CpuHasAvxFeatureFlag();
336   bool CpuHasAvx2FeatureFlag();
337 
338   X86Assembler* const assembler_;
339   CodeGeneratorX86* const codegen_;
340 
341   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorX86);
342 };
343 
344 class JumpTableRIPFixup;
345 
346 class CodeGeneratorX86 : public CodeGenerator {
347  public:
348   CodeGeneratorX86(HGraph* graph,
349                    const CompilerOptions& compiler_options,
350                    OptimizingCompilerStats* stats = nullptr);
~CodeGeneratorX86()351   virtual ~CodeGeneratorX86() {}
352 
353   void GenerateFrameEntry() override;
354   void GenerateFrameExit() override;
355   void Bind(HBasicBlock* block) override;
356   void MoveConstant(Location destination, int32_t value) override;
357   void MoveLocation(Location dst, Location src, DataType::Type dst_type) override;
358   void AddLocationAsTemp(Location location, LocationSummary* locations) override;
359 
360   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) override;
361   size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) override;
362   size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) override;
363   size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) override;
364 
365   // Generate code to invoke a runtime entry point.
366   void InvokeRuntime(QuickEntrypointEnum entrypoint,
367                      HInstruction* instruction,
368                      uint32_t dex_pc,
369                      SlowPathCode* slow_path = nullptr) override;
370 
371   // Generate code to invoke a runtime entry point, but do not record
372   // PC-related information in a stack map.
373   void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
374                                            HInstruction* instruction,
375                                            SlowPathCode* slow_path);
376 
377   void GenerateInvokeRuntime(int32_t entry_point_offset);
378 
GetWordSize()379   size_t GetWordSize() const override {
380     return kX86WordSize;
381   }
382 
GetSlowPathFPWidth()383   size_t GetSlowPathFPWidth() const override {
384     return GetGraph()->HasSIMD()
385         ? GetSIMDRegisterWidth()
386         : 2 * kX86WordSize;  //  8 bytes == 2 words for each spill
387   }
388 
GetCalleePreservedFPWidth()389   size_t GetCalleePreservedFPWidth() const override {
390     return 2 * kX86WordSize;
391   }
392 
GetSIMDRegisterWidth()393   size_t GetSIMDRegisterWidth() const override {
394     return 4 * kX86WordSize;
395   }
396 
GetLocationBuilder()397   HGraphVisitor* GetLocationBuilder() override {
398     return &location_builder_;
399   }
400 
GetInstructionVisitor()401   HGraphVisitor* GetInstructionVisitor() override {
402     return &instruction_visitor_;
403   }
404 
GetAssembler()405   X86Assembler* GetAssembler() override {
406     return &assembler_;
407   }
408 
GetAssembler()409   const X86Assembler& GetAssembler() const override {
410     return assembler_;
411   }
412 
GetAddressOf(HBasicBlock * block)413   uintptr_t GetAddressOf(HBasicBlock* block) override {
414     return GetLabelOf(block)->Position();
415   }
416 
417   void SetupBlockedRegisters() const override;
418 
419   void DumpCoreRegister(std::ostream& stream, int reg) const override;
420   void DumpFloatingPointRegister(std::ostream& stream, int reg) const override;
421 
GetMoveResolver()422   ParallelMoveResolverX86* GetMoveResolver() override {
423     return &move_resolver_;
424   }
425 
GetInstructionSet()426   InstructionSet GetInstructionSet() const override {
427     return InstructionSet::kX86;
428   }
429 
430   const X86InstructionSetFeatures& GetInstructionSetFeatures() const;
431 
432   // Helper method to move a 32bits value between two locations.
433   void Move32(Location destination, Location source);
434   // Helper method to move a 64bits value between two locations.
435   void Move64(Location destination, Location source);
436 
437   // Check if the desired_string_load_kind is supported. If it is, return it,
438   // otherwise return a fall-back kind that should be used instead.
439   HLoadString::LoadKind GetSupportedLoadStringKind(
440       HLoadString::LoadKind desired_string_load_kind) override;
441 
442   // Check if the desired_class_load_kind is supported. If it is, return it,
443   // otherwise return a fall-back kind that should be used instead.
444   HLoadClass::LoadKind GetSupportedLoadClassKind(
445       HLoadClass::LoadKind desired_class_load_kind) override;
446 
447   // Check if the desired_dispatch_info is supported. If it is, return it,
448   // otherwise return a fall-back info that should be used instead.
449   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
450       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
451       ArtMethod* method) override;
452 
453   // Generate a call to a static or direct method.
454   void GenerateStaticOrDirectCall(
455       HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
456   // Generate a call to a virtual method.
457   void GenerateVirtualCall(
458       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
459 
460   void RecordBootImageIntrinsicPatch(HX86ComputeBaseMethodAddress* method_address,
461                                      uint32_t intrinsic_data);
462   void RecordBootImageRelRoPatch(HX86ComputeBaseMethodAddress* method_address,
463                                  uint32_t boot_image_offset);
464   void RecordBootImageMethodPatch(HInvokeStaticOrDirect* invoke);
465   void RecordMethodBssEntryPatch(HInvokeStaticOrDirect* invoke);
466   void RecordBootImageTypePatch(HLoadClass* load_class);
467   Label* NewTypeBssEntryPatch(HLoadClass* load_class);
468   void RecordBootImageStringPatch(HLoadString* load_string);
469   Label* NewStringBssEntryPatch(HLoadString* load_string);
470 
471   void LoadBootImageAddress(Register reg,
472                             uint32_t boot_image_reference,
473                             HInvokeStaticOrDirect* invoke);
474   void AllocateInstanceForIntrinsic(HInvokeStaticOrDirect* invoke, uint32_t boot_image_offset);
475 
476   Label* NewJitRootStringPatch(const DexFile& dex_file,
477                                dex::StringIndex string_index,
478                                Handle<mirror::String> handle);
479   Label* NewJitRootClassPatch(const DexFile& dex_file,
480                               dex::TypeIndex type_index,
481                               Handle<mirror::Class> handle);
482 
483   void MoveFromReturnRegister(Location trg, DataType::Type type) override;
484 
485   // Emit linker patches.
486   void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) override;
487 
488   void PatchJitRootUse(uint8_t* code,
489                        const uint8_t* roots_data,
490                        const PatchInfo<Label>& info,
491                        uint64_t index_in_table) const;
492   void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) override;
493 
494   // Emit a write barrier.
495   void MarkGCCard(Register temp,
496                   Register card,
497                   Register object,
498                   Register value,
499                   bool value_can_be_null);
500 
501   void GenerateMemoryBarrier(MemBarrierKind kind);
502 
GetLabelOf(HBasicBlock * block)503   Label* GetLabelOf(HBasicBlock* block) const {
504     return CommonGetLabelOf<Label>(block_labels_, block);
505   }
506 
Initialize()507   void Initialize() override {
508     block_labels_ = CommonInitializeLabels<Label>();
509   }
510 
NeedsTwoRegisters(DataType::Type type)511   bool NeedsTwoRegisters(DataType::Type type) const override {
512     return type == DataType::Type::kInt64;
513   }
514 
ShouldSplitLongMoves()515   bool ShouldSplitLongMoves() const override { return true; }
516 
GetFrameEntryLabel()517   Label* GetFrameEntryLabel() { return &frame_entry_label_; }
518 
AddMethodAddressOffset(HX86ComputeBaseMethodAddress * method_base,int32_t offset)519   void AddMethodAddressOffset(HX86ComputeBaseMethodAddress* method_base, int32_t offset) {
520     method_address_offset_.Put(method_base->GetId(), offset);
521   }
522 
GetMethodAddressOffset(HX86ComputeBaseMethodAddress * method_base)523   int32_t GetMethodAddressOffset(HX86ComputeBaseMethodAddress* method_base) const {
524     return method_address_offset_.Get(method_base->GetId());
525   }
526 
ConstantAreaStart()527   int32_t ConstantAreaStart() const {
528     return constant_area_start_;
529   }
530 
531   Address LiteralDoubleAddress(double v, HX86ComputeBaseMethodAddress* method_base, Register reg);
532   Address LiteralFloatAddress(float v, HX86ComputeBaseMethodAddress* method_base, Register reg);
533   Address LiteralInt32Address(int32_t v, HX86ComputeBaseMethodAddress* method_base, Register reg);
534   Address LiteralInt64Address(int64_t v, HX86ComputeBaseMethodAddress* method_base, Register reg);
535 
536   // Load a 32-bit value into a register in the most efficient manner.
537   void Load32BitValue(Register dest, int32_t value);
538 
539   // Compare a register with a 32-bit value in the most efficient manner.
540   void Compare32BitValue(Register dest, int32_t value);
541 
542   // Compare int values. Supports only register locations for `lhs`.
543   void GenerateIntCompare(Location lhs, Location rhs);
544   void GenerateIntCompare(Register lhs, Location rhs);
545 
546   // Construct address for array access.
547   static Address ArrayAddress(Register obj,
548                               Location index,
549                               ScaleFactor scale,
550                               uint32_t data_offset);
551 
552   Address LiteralCaseTable(HX86PackedSwitch* switch_instr, Register reg, Register value);
553 
554   void Finalize(CodeAllocator* allocator) override;
555 
556   // Fast path implementation of ReadBarrier::Barrier for a heap
557   // reference field load when Baker's read barriers are used.
558   void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
559                                              Location ref,
560                                              Register obj,
561                                              uint32_t offset,
562                                              bool needs_null_check);
563   // Fast path implementation of ReadBarrier::Barrier for a heap
564   // reference array load when Baker's read barriers are used.
565   void GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
566                                              Location ref,
567                                              Register obj,
568                                              uint32_t data_offset,
569                                              Location index,
570                                              bool needs_null_check);
571   // Factored implementation, used by GenerateFieldLoadWithBakerReadBarrier,
572   // GenerateArrayLoadWithBakerReadBarrier and some intrinsics.
573   //
574   // Load the object reference located at address `src`, held by
575   // object `obj`, into `ref`, and mark it if needed.  The base of
576   // address `src` must be `obj`.
577   //
578   // If `always_update_field` is true, the value of the reference is
579   // atomically updated in the holder (`obj`).  This operation
580   // requires a temporary register, which must be provided as a
581   // non-null pointer (`temp`).
582   void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
583                                                  Location ref,
584                                                  Register obj,
585                                                  const Address& src,
586                                                  bool needs_null_check,
587                                                  bool always_update_field = false,
588                                                  Register* temp = nullptr);
589 
590   // Generate a read barrier for a heap reference within `instruction`
591   // using a slow path.
592   //
593   // A read barrier for an object reference read from the heap is
594   // implemented as a call to the artReadBarrierSlow runtime entry
595   // point, which is passed the values in locations `ref`, `obj`, and
596   // `offset`:
597   //
598   //   mirror::Object* artReadBarrierSlow(mirror::Object* ref,
599   //                                      mirror::Object* obj,
600   //                                      uint32_t offset);
601   //
602   // The `out` location contains the value returned by
603   // artReadBarrierSlow.
604   //
605   // When `index` is provided (i.e. for array accesses), the offset
606   // value passed to artReadBarrierSlow is adjusted to take `index`
607   // into account.
608   void GenerateReadBarrierSlow(HInstruction* instruction,
609                                Location out,
610                                Location ref,
611                                Location obj,
612                                uint32_t offset,
613                                Location index = Location::NoLocation());
614 
615   // If read barriers are enabled, generate a read barrier for a heap
616   // reference using a slow path. If heap poisoning is enabled, also
617   // unpoison the reference in `out`.
618   void MaybeGenerateReadBarrierSlow(HInstruction* instruction,
619                                     Location out,
620                                     Location ref,
621                                     Location obj,
622                                     uint32_t offset,
623                                     Location index = Location::NoLocation());
624 
625   // Generate a read barrier for a GC root within `instruction` using
626   // a slow path.
627   //
628   // A read barrier for an object reference GC root is implemented as
629   // a call to the artReadBarrierForRootSlow runtime entry point,
630   // which is passed the value in location `root`:
631   //
632   //   mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root);
633   //
634   // The `out` location contains the value returned by
635   // artReadBarrierForRootSlow.
636   void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root);
637 
638   // Ensure that prior stores complete to memory before subsequent loads.
639   // The locked add implementation will avoid serializing device memory, but will
640   // touch (but not change) the top of the stack.
641   // The 'non_temporal' parameter should be used to ensure ordering of non-temporal stores.
642   void MemoryFence(bool non_temporal = false) {
643     if (!non_temporal) {
644       assembler_.lock()->addl(Address(ESP, 0), Immediate(0));
645     } else {
646       assembler_.mfence();
647     }
648   }
649 
650   void IncreaseFrame(size_t adjustment) override;
651   void DecreaseFrame(size_t adjustment) override;
652 
653   void GenerateNop() override;
654   void GenerateImplicitNullCheck(HNullCheck* instruction) override;
655   void GenerateExplicitNullCheck(HNullCheck* instruction) override;
656 
657   void MaybeGenerateInlineCacheCheck(HInstruction* instruction, Register klass);
658   void MaybeIncrementHotness(bool is_frame_entry);
659 
660   // When we don't know the proper offset for the value, we use kPlaceholder32BitOffset.
661   // The correct value will be inserted when processing Assembler fixups.
662   static constexpr int32_t kPlaceholder32BitOffset = 256;
663 
664  private:
665   struct X86PcRelativePatchInfo : PatchInfo<Label> {
X86PcRelativePatchInfoX86PcRelativePatchInfo666     X86PcRelativePatchInfo(HX86ComputeBaseMethodAddress* address,
667                            const DexFile* target_dex_file,
668                            uint32_t target_index)
669         : PatchInfo(target_dex_file, target_index),
670           method_address(address) {}
671     HX86ComputeBaseMethodAddress* method_address;
672   };
673 
674   template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
675   void EmitPcRelativeLinkerPatches(const ArenaDeque<X86PcRelativePatchInfo>& infos,
676                                    ArenaVector<linker::LinkerPatch>* linker_patches);
677 
678   Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp);
679 
680   // Labels for each block that will be compiled.
681   Label* block_labels_;  // Indexed by block id.
682   Label frame_entry_label_;
683   LocationsBuilderX86 location_builder_;
684   InstructionCodeGeneratorX86 instruction_visitor_;
685   ParallelMoveResolverX86 move_resolver_;
686   X86Assembler assembler_;
687 
688   // PC-relative method patch info for kBootImageLinkTimePcRelative.
689   ArenaDeque<X86PcRelativePatchInfo> boot_image_method_patches_;
690   // PC-relative method patch info for kBssEntry.
691   ArenaDeque<X86PcRelativePatchInfo> method_bss_entry_patches_;
692   // PC-relative type patch info for kBootImageLinkTimePcRelative.
693   ArenaDeque<X86PcRelativePatchInfo> boot_image_type_patches_;
694   // PC-relative type patch info for kBssEntry.
695   ArenaDeque<X86PcRelativePatchInfo> type_bss_entry_patches_;
696   // PC-relative String patch info for kBootImageLinkTimePcRelative.
697   ArenaDeque<X86PcRelativePatchInfo> boot_image_string_patches_;
698   // PC-relative String patch info for kBssEntry.
699   ArenaDeque<X86PcRelativePatchInfo> string_bss_entry_patches_;
700   // PC-relative patch info for IntrinsicObjects for the boot image,
701   // and for method/type/string patches for kBootImageRelRo otherwise.
702   ArenaDeque<X86PcRelativePatchInfo> boot_image_other_patches_;
703 
704   // Patches for string root accesses in JIT compiled code.
705   ArenaDeque<PatchInfo<Label>> jit_string_patches_;
706   // Patches for class root accesses in JIT compiled code.
707   ArenaDeque<PatchInfo<Label>> jit_class_patches_;
708 
709   // Offset to the start of the constant area in the assembled code.
710   // Used for fixups to the constant area.
711   int32_t constant_area_start_;
712 
713   // Fixups for jump tables that need to be patched after the constant table is generated.
714   ArenaVector<JumpTableRIPFixup*> fixups_to_jump_tables_;
715 
716   // Maps a HX86ComputeBaseMethodAddress instruction id, to its offset in the
717   // compiled code.
718   ArenaSafeMap<uint32_t, int32_t> method_address_offset_;
719 
720   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86);
721 };
722 
723 }  // namespace x86
724 }  // namespace art
725 
726 #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_H_
727