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_ARM_H_
18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_H_
19
20 #include "base/enums.h"
21 #include "code_generator.h"
22 #include "dex_file_types.h"
23 #include "driver/compiler_options.h"
24 #include "nodes.h"
25 #include "string_reference.h"
26 #include "parallel_move_resolver.h"
27 #include "utils/arm/assembler_thumb2.h"
28 #include "utils/type_reference.h"
29
30 namespace art {
31 namespace arm {
32
33 class CodeGeneratorARM;
34
35 // Use a local definition to prevent copying mistakes.
36 static constexpr size_t kArmWordSize = static_cast<size_t>(kArmPointerSize);
37 static constexpr size_t kArmBitsPerWord = kArmWordSize * kBitsPerByte;
38
39 static constexpr Register kParameterCoreRegisters[] = { R1, R2, R3 };
40 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
41 static constexpr SRegister kParameterFpuRegisters[] =
42 { S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15 };
43 static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters);
44
45 static constexpr Register kArtMethodRegister = R0;
46
47 static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2, R3 };
48 static constexpr size_t kRuntimeParameterCoreRegistersLength =
49 arraysize(kRuntimeParameterCoreRegisters);
50 static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0, S1, S2, S3 };
51 static constexpr size_t kRuntimeParameterFpuRegistersLength =
52 arraysize(kRuntimeParameterFpuRegisters);
53
54 class SlowPathCodeARM : public SlowPathCode {
55 public:
SlowPathCodeARM(HInstruction * instruction)56 explicit SlowPathCodeARM(HInstruction* instruction) : SlowPathCode(instruction) {}
57
58 void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) FINAL;
59 void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) FINAL;
60
61 private:
62 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM);
63 };
64
65
66 class InvokeRuntimeCallingConvention : public CallingConvention<Register, SRegister> {
67 public:
InvokeRuntimeCallingConvention()68 InvokeRuntimeCallingConvention()
69 : CallingConvention(kRuntimeParameterCoreRegisters,
70 kRuntimeParameterCoreRegistersLength,
71 kRuntimeParameterFpuRegisters,
72 kRuntimeParameterFpuRegistersLength,
73 kArmPointerSize) {}
74
75 private:
76 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
77 };
78
FromLowSToD(SRegister reg)79 constexpr DRegister FromLowSToD(SRegister reg) {
80 DCHECK_EQ(reg % 2, 0);
81 return static_cast<DRegister>(reg / 2);
82 }
83
84
85 class InvokeDexCallingConvention : public CallingConvention<Register, SRegister> {
86 public:
InvokeDexCallingConvention()87 InvokeDexCallingConvention()
88 : CallingConvention(kParameterCoreRegisters,
89 kParameterCoreRegistersLength,
90 kParameterFpuRegisters,
91 kParameterFpuRegistersLength,
92 kArmPointerSize) {}
93
94 private:
95 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
96 };
97
98 class InvokeDexCallingConventionVisitorARM : public InvokeDexCallingConventionVisitor {
99 public:
InvokeDexCallingConventionVisitorARM()100 InvokeDexCallingConventionVisitorARM() {}
~InvokeDexCallingConventionVisitorARM()101 virtual ~InvokeDexCallingConventionVisitorARM() {}
102
103 Location GetNextLocation(Primitive::Type type) OVERRIDE;
104 Location GetReturnLocation(Primitive::Type type) const OVERRIDE;
105 Location GetMethodLocation() const OVERRIDE;
106
107 private:
108 InvokeDexCallingConvention calling_convention;
109 uint32_t double_index_ = 0;
110
111 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorARM);
112 };
113
114 class FieldAccessCallingConventionARM : public FieldAccessCallingConvention {
115 public:
FieldAccessCallingConventionARM()116 FieldAccessCallingConventionARM() {}
117
GetObjectLocation()118 Location GetObjectLocation() const OVERRIDE {
119 return Location::RegisterLocation(R1);
120 }
GetFieldIndexLocation()121 Location GetFieldIndexLocation() const OVERRIDE {
122 return Location::RegisterLocation(R0);
123 }
GetReturnLocation(Primitive::Type type)124 Location GetReturnLocation(Primitive::Type type) const OVERRIDE {
125 return Primitive::Is64BitType(type)
126 ? Location::RegisterPairLocation(R0, R1)
127 : Location::RegisterLocation(R0);
128 }
GetSetValueLocation(Primitive::Type type,bool is_instance)129 Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE {
130 return Primitive::Is64BitType(type)
131 ? Location::RegisterPairLocation(R2, R3)
132 : (is_instance
133 ? Location::RegisterLocation(R2)
134 : Location::RegisterLocation(R1));
135 }
GetFpuLocation(Primitive::Type type)136 Location GetFpuLocation(Primitive::Type type) const OVERRIDE {
137 return Primitive::Is64BitType(type)
138 ? Location::FpuRegisterPairLocation(S0, S1)
139 : Location::FpuRegisterLocation(S0);
140 }
141
142 private:
143 DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionARM);
144 };
145
146 class ParallelMoveResolverARM : public ParallelMoveResolverWithSwap {
147 public:
ParallelMoveResolverARM(ArenaAllocator * allocator,CodeGeneratorARM * codegen)148 ParallelMoveResolverARM(ArenaAllocator* allocator, CodeGeneratorARM* codegen)
149 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {}
150
151 void EmitMove(size_t index) OVERRIDE;
152 void EmitSwap(size_t index) OVERRIDE;
153 void SpillScratch(int reg) OVERRIDE;
154 void RestoreScratch(int reg) OVERRIDE;
155
156 ArmAssembler* GetAssembler() const;
157
158 private:
159 void Exchange(Register reg, int mem);
160 void Exchange(int mem1, int mem2);
161
162 CodeGeneratorARM* const codegen_;
163
164 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverARM);
165 };
166
167 class LocationsBuilderARM : public HGraphVisitor {
168 public:
LocationsBuilderARM(HGraph * graph,CodeGeneratorARM * codegen)169 LocationsBuilderARM(HGraph* graph, CodeGeneratorARM* codegen)
170 : HGraphVisitor(graph), codegen_(codegen) {}
171
172 #define DECLARE_VISIT_INSTRUCTION(name, super) \
173 void Visit##name(H##name* instr) OVERRIDE;
174
175 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)176 FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)
177 FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION)
178
179 #undef DECLARE_VISIT_INSTRUCTION
180
181 void VisitInstruction(HInstruction* instruction) OVERRIDE {
182 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
183 << " (id " << instruction->GetId() << ")";
184 }
185
186 private:
187 void HandleInvoke(HInvoke* invoke);
188 void HandleBitwiseOperation(HBinaryOperation* operation, Opcode opcode);
189 void HandleCondition(HCondition* condition);
190 void HandleIntegerRotate(LocationSummary* locations);
191 void HandleLongRotate(LocationSummary* locations);
192 void HandleShift(HBinaryOperation* operation);
193 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
194 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
195
196 Location ArithmeticZeroOrFpuRegister(HInstruction* input);
197 Location ArmEncodableConstantOrRegister(HInstruction* constant, Opcode opcode);
198 bool CanEncodeConstantAsImmediate(HConstant* input_cst, Opcode opcode);
199 bool CanEncodeConstantAsImmediate(uint32_t value, Opcode opcode, SetCc set_cc = kCcDontCare);
200
201 CodeGeneratorARM* const codegen_;
202 InvokeDexCallingConventionVisitorARM parameter_visitor_;
203
204 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARM);
205 };
206
207 class InstructionCodeGeneratorARM : public InstructionCodeGenerator {
208 public:
209 InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen);
210
211 #define DECLARE_VISIT_INSTRUCTION(name, super) \
212 void Visit##name(H##name* instr) OVERRIDE;
213
214 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)215 FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)
216 FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION)
217
218 #undef DECLARE_VISIT_INSTRUCTION
219
220 void VisitInstruction(HInstruction* instruction) OVERRIDE {
221 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
222 << " (id " << instruction->GetId() << ")";
223 }
224
GetAssembler()225 ArmAssembler* GetAssembler() const { return assembler_; }
226
227 private:
228 // Generate code for the given suspend check. If not null, `successor`
229 // is the block to branch to if the suspend check is not needed, and after
230 // the suspend call.
231 void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
232 void GenerateClassInitializationCheck(SlowPathCodeARM* slow_path, Register class_reg);
233 void GenerateAndConst(Register out, Register first, uint32_t value);
234 void GenerateOrrConst(Register out, Register first, uint32_t value);
235 void GenerateEorConst(Register out, Register first, uint32_t value);
236 void GenerateAddLongConst(Location out, Location first, uint64_t value);
237 void HandleBitwiseOperation(HBinaryOperation* operation);
238 void HandleCondition(HCondition* condition);
239 void HandleIntegerRotate(LocationSummary* locations);
240 void HandleLongRotate(HRor* ror);
241 void HandleShift(HBinaryOperation* operation);
242
243 void GenerateWideAtomicStore(Register addr, uint32_t offset,
244 Register value_lo, Register value_hi,
245 Register temp1, Register temp2,
246 HInstruction* instruction);
247 void GenerateWideAtomicLoad(Register addr, uint32_t offset,
248 Register out_lo, Register out_hi);
249
250 void HandleFieldSet(HInstruction* instruction,
251 const FieldInfo& field_info,
252 bool value_can_be_null);
253 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
254
255 // Generate a heap reference load using one register `out`:
256 //
257 // out <- *(out + offset)
258 //
259 // while honoring heap poisoning and/or read barriers (if any).
260 //
261 // Location `maybe_temp` is used when generating a read barrier and
262 // shall be a register in that case; it may be an invalid location
263 // otherwise.
264 void GenerateReferenceLoadOneRegister(HInstruction* instruction,
265 Location out,
266 uint32_t offset,
267 Location maybe_temp,
268 ReadBarrierOption read_barrier_option);
269 // Generate a heap reference load using two different registers
270 // `out` and `obj`:
271 //
272 // out <- *(obj + offset)
273 //
274 // while honoring heap poisoning and/or read barriers (if any).
275 //
276 // Location `maybe_temp` is used when generating a Baker's (fast
277 // path) read barrier and shall be a register in that case; it may
278 // be an invalid location otherwise.
279 void GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
280 Location out,
281 Location obj,
282 uint32_t offset,
283 Location maybe_temp,
284 ReadBarrierOption read_barrier_option);
285 // Generate a GC root reference load:
286 //
287 // root <- *(obj + offset)
288 //
289 // while honoring read barriers based on read_barrier_option.
290 void GenerateGcRootFieldLoad(HInstruction* instruction,
291 Location root,
292 Register obj,
293 uint32_t offset,
294 ReadBarrierOption read_barrier_option);
295 void GenerateTestAndBranch(HInstruction* instruction,
296 size_t condition_input_index,
297 Label* true_target,
298 Label* false_target);
299 void GenerateCompareTestAndBranch(HCondition* condition,
300 Label* true_target,
301 Label* false_target);
302 void GenerateLongComparesAndJumps(HCondition* cond, Label* true_label, Label* false_label);
303 void DivRemOneOrMinusOne(HBinaryOperation* instruction);
304 void DivRemByPowerOfTwo(HBinaryOperation* instruction);
305 void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
306 void GenerateDivRemConstantIntegral(HBinaryOperation* instruction);
307 void HandleGoto(HInstruction* got, HBasicBlock* successor);
308
309 ArmAssembler* const assembler_;
310 CodeGeneratorARM* const codegen_;
311
312 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorARM);
313 };
314
315 class CodeGeneratorARM : public CodeGenerator {
316 public:
317 CodeGeneratorARM(HGraph* graph,
318 const ArmInstructionSetFeatures& isa_features,
319 const CompilerOptions& compiler_options,
320 OptimizingCompilerStats* stats = nullptr);
~CodeGeneratorARM()321 virtual ~CodeGeneratorARM() {}
322
323 void GenerateFrameEntry() OVERRIDE;
324 void GenerateFrameExit() OVERRIDE;
325 void Bind(HBasicBlock* block) OVERRIDE;
326 void MoveConstant(Location destination, int32_t value) OVERRIDE;
327 void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
328 void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
329
330 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
331 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
332 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
333 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
334
GetWordSize()335 size_t GetWordSize() const OVERRIDE {
336 return kArmWordSize;
337 }
338
GetFloatingPointSpillSlotSize()339 size_t GetFloatingPointSpillSlotSize() const OVERRIDE {
340 // Allocated in S registers, which are word sized.
341 return kArmWordSize;
342 }
343
GetLocationBuilder()344 HGraphVisitor* GetLocationBuilder() OVERRIDE {
345 return &location_builder_;
346 }
347
GetInstructionVisitor()348 HGraphVisitor* GetInstructionVisitor() OVERRIDE {
349 return &instruction_visitor_;
350 }
351
GetAssembler()352 ArmAssembler* GetAssembler() OVERRIDE {
353 return &assembler_;
354 }
355
GetAssembler()356 const ArmAssembler& GetAssembler() const OVERRIDE {
357 return assembler_;
358 }
359
GetAddressOf(HBasicBlock * block)360 uintptr_t GetAddressOf(HBasicBlock* block) OVERRIDE {
361 return GetLabelOf(block)->Position();
362 }
363
364 void SetupBlockedRegisters() const OVERRIDE;
365
366 void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
367 void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
368
GetMoveResolver()369 ParallelMoveResolverARM* GetMoveResolver() OVERRIDE {
370 return &move_resolver_;
371 }
372
GetInstructionSet()373 InstructionSet GetInstructionSet() const OVERRIDE {
374 return InstructionSet::kThumb2;
375 }
376
377 // Helper method to move a 32bits value between two locations.
378 void Move32(Location destination, Location source);
379 // Helper method to move a 64bits value between two locations.
380 void Move64(Location destination, Location source);
381
382 void LoadOrStoreToOffset(Primitive::Type type,
383 Location loc,
384 Register base,
385 int32_t offset,
386 bool is_load,
387 Condition cond = AL);
388
389 void LoadFromShiftedRegOffset(Primitive::Type type,
390 Location out_loc,
391 Register base,
392 Register reg_offset,
393 Condition cond = AL);
394 void StoreToShiftedRegOffset(Primitive::Type type,
395 Location out_loc,
396 Register base,
397 Register reg_offset,
398 Condition cond = AL);
399
400 // Generate code to invoke a runtime entry point.
401 void InvokeRuntime(QuickEntrypointEnum entrypoint,
402 HInstruction* instruction,
403 uint32_t dex_pc,
404 SlowPathCode* slow_path = nullptr) OVERRIDE;
405
406 // Generate code to invoke a runtime entry point, but do not record
407 // PC-related information in a stack map.
408 void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
409 HInstruction* instruction,
410 SlowPathCode* slow_path);
411
412 void GenerateInvokeRuntime(int32_t entry_point_offset);
413
414 // Emit a write barrier.
415 void MarkGCCard(Register temp, Register card, Register object, Register value, bool can_be_null);
416
417 void GenerateMemoryBarrier(MemBarrierKind kind);
418
GetLabelOf(HBasicBlock * block)419 Label* GetLabelOf(HBasicBlock* block) const {
420 return CommonGetLabelOf<Label>(block_labels_, block);
421 }
422
423 Label* GetFinalLabel(HInstruction* instruction, Label* final_label);
424
Initialize()425 void Initialize() OVERRIDE {
426 block_labels_ = CommonInitializeLabels<Label>();
427 }
428
429 void Finalize(CodeAllocator* allocator) OVERRIDE;
430
GetInstructionSetFeatures()431 const ArmInstructionSetFeatures& GetInstructionSetFeatures() const {
432 return isa_features_;
433 }
434
NeedsTwoRegisters(Primitive::Type type)435 bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE {
436 return type == Primitive::kPrimDouble || type == Primitive::kPrimLong;
437 }
438
439 void ComputeSpillMask() OVERRIDE;
440
GetFrameEntryLabel()441 Label* GetFrameEntryLabel() { return &frame_entry_label_; }
442
443 // Check if the desired_string_load_kind is supported. If it is, return it,
444 // otherwise return a fall-back kind that should be used instead.
445 HLoadString::LoadKind GetSupportedLoadStringKind(
446 HLoadString::LoadKind desired_string_load_kind) OVERRIDE;
447
448 // Check if the desired_class_load_kind is supported. If it is, return it,
449 // otherwise return a fall-back kind that should be used instead.
450 HLoadClass::LoadKind GetSupportedLoadClassKind(
451 HLoadClass::LoadKind desired_class_load_kind) OVERRIDE;
452
453 // Check if the desired_dispatch_info is supported. If it is, return it,
454 // otherwise return a fall-back info that should be used instead.
455 HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
456 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
457 HInvokeStaticOrDirect* invoke) OVERRIDE;
458
459 Location GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
460 void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
461 void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
462
463 void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
464
465 // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays
466 // and boot image strings/types. The only difference is the interpretation of the
467 // offset_or_index. The PC-relative address is loaded with three instructions,
468 // MOVW+MOVT to load the offset to base_reg and then ADD base_reg, PC. The offset
469 // is calculated from the ADD's effective PC, i.e. PC+4 on Thumb2. Though we
470 // currently emit these 3 instructions together, instruction scheduling could
471 // split this sequence apart, so we keep separate labels for each of them.
472 struct PcRelativePatchInfo {
PcRelativePatchInfoPcRelativePatchInfo473 PcRelativePatchInfo(const DexFile& dex_file, uint32_t off_or_idx)
474 : target_dex_file(dex_file), offset_or_index(off_or_idx) { }
475 PcRelativePatchInfo(PcRelativePatchInfo&& other) = default;
476
477 const DexFile& target_dex_file;
478 // Either the dex cache array element offset or the string/type index.
479 uint32_t offset_or_index;
480 Label movw_label;
481 Label movt_label;
482 Label add_pc_label;
483 };
484
485 PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file,
486 dex::StringIndex string_index);
487 PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
488 PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, dex::TypeIndex type_index);
489 PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
490 uint32_t element_offset);
491 Literal* DeduplicateBootImageStringLiteral(const DexFile& dex_file,
492 dex::StringIndex string_index);
493 Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, dex::TypeIndex type_index);
494 Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
495 Literal* DeduplicateJitStringLiteral(const DexFile& dex_file,
496 dex::StringIndex string_index,
497 Handle<mirror::String> handle);
498 Literal* DeduplicateJitClassLiteral(const DexFile& dex_file,
499 dex::TypeIndex type_index,
500 Handle<mirror::Class> handle);
501
502 void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
503
504 void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
505
506 // Fast path implementation of ReadBarrier::Barrier for a heap
507 // reference field load when Baker's read barriers are used.
508 void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
509 Location ref,
510 Register obj,
511 uint32_t offset,
512 Location temp,
513 bool needs_null_check);
514 // Fast path implementation of ReadBarrier::Barrier for a heap
515 // reference array load when Baker's read barriers are used.
516 void GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
517 Location ref,
518 Register obj,
519 uint32_t data_offset,
520 Location index,
521 Location temp,
522 bool needs_null_check);
523 // Factored implementation, used by GenerateFieldLoadWithBakerReadBarrier,
524 // GenerateArrayLoadWithBakerReadBarrier and some intrinsics.
525 //
526 // Load the object reference located at the address
527 // `obj + offset + (index << scale_factor)`, held by object `obj`, into
528 // `ref`, and mark it if needed.
529 //
530 // If `always_update_field` is true, the value of the reference is
531 // atomically updated in the holder (`obj`). This operation
532 // requires an extra temporary register, which must be provided as a
533 // non-null pointer (`temp2`).
534 void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
535 Location ref,
536 Register obj,
537 uint32_t offset,
538 Location index,
539 ScaleFactor scale_factor,
540 Location temp,
541 bool needs_null_check,
542 bool always_update_field = false,
543 Register* temp2 = nullptr);
544
545 // Generate a heap reference load (with no read barrier).
546 void GenerateRawReferenceLoad(HInstruction* instruction,
547 Location ref,
548 Register obj,
549 uint32_t offset,
550 Location index,
551 ScaleFactor scale_factor,
552 bool needs_null_check);
553
554 // Generate a read barrier for a heap reference within `instruction`
555 // using a slow path.
556 //
557 // A read barrier for an object reference read from the heap is
558 // implemented as a call to the artReadBarrierSlow runtime entry
559 // point, which is passed the values in locations `ref`, `obj`, and
560 // `offset`:
561 //
562 // mirror::Object* artReadBarrierSlow(mirror::Object* ref,
563 // mirror::Object* obj,
564 // uint32_t offset);
565 //
566 // The `out` location contains the value returned by
567 // artReadBarrierSlow.
568 //
569 // When `index` is provided (i.e. for array accesses), the offset
570 // value passed to artReadBarrierSlow is adjusted to take `index`
571 // into account.
572 void GenerateReadBarrierSlow(HInstruction* instruction,
573 Location out,
574 Location ref,
575 Location obj,
576 uint32_t offset,
577 Location index = Location::NoLocation());
578
579 // If read barriers are enabled, generate a read barrier for a heap
580 // reference using a slow path. If heap poisoning is enabled, also
581 // unpoison the reference in `out`.
582 void MaybeGenerateReadBarrierSlow(HInstruction* instruction,
583 Location out,
584 Location ref,
585 Location obj,
586 uint32_t offset,
587 Location index = Location::NoLocation());
588
589 // Generate a read barrier for a GC root within `instruction` using
590 // a slow path.
591 //
592 // A read barrier for an object reference GC root is implemented as
593 // a call to the artReadBarrierForRootSlow runtime entry point,
594 // which is passed the value in location `root`:
595 //
596 // mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root);
597 //
598 // The `out` location contains the value returned by
599 // artReadBarrierForRootSlow.
600 void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root);
601
602 void GenerateNop() OVERRIDE;
603
604 void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE;
605 void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE;
606
607 private:
608 Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp);
609
610 using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, Literal*>;
611 using MethodToLiteralMap = ArenaSafeMap<MethodReference, Literal*, MethodReferenceComparator>;
612 using StringToLiteralMap = ArenaSafeMap<StringReference,
613 Literal*,
614 StringReferenceValueComparator>;
615 using TypeToLiteralMap = ArenaSafeMap<TypeReference,
616 Literal*,
617 TypeReferenceValueComparator>;
618
619 Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map);
620 Literal* DeduplicateMethodLiteral(MethodReference target_method, MethodToLiteralMap* map);
621 PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file,
622 uint32_t offset_or_index,
623 ArenaDeque<PcRelativePatchInfo>* patches);
624 template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
625 static void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
626 ArenaVector<LinkerPatch>* linker_patches);
627
628 // Labels for each block that will be compiled.
629 Label* block_labels_; // Indexed by block id.
630 Label frame_entry_label_;
631 LocationsBuilderARM location_builder_;
632 InstructionCodeGeneratorARM instruction_visitor_;
633 ParallelMoveResolverARM move_resolver_;
634 Thumb2Assembler assembler_;
635 const ArmInstructionSetFeatures& isa_features_;
636
637 // Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
638 Uint32ToLiteralMap uint32_literals_;
639 // PC-relative patch info for each HArmDexCacheArraysBase.
640 ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_;
641 // Deduplication map for boot string literals for kBootImageLinkTimeAddress.
642 StringToLiteralMap boot_image_string_patches_;
643 // PC-relative String patch info; type depends on configuration (app .bss or boot image PIC).
644 ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_;
645 // Deduplication map for boot type literals for kBootImageLinkTimeAddress.
646 TypeToLiteralMap boot_image_type_patches_;
647 // PC-relative type patch info for kBootImageLinkTimePcRelative.
648 ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_;
649 // PC-relative type patch info for kBssEntry.
650 ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_;
651
652 // Patches for string literals in JIT compiled code.
653 StringToLiteralMap jit_string_patches_;
654 // Patches for class literals in JIT compiled code.
655 TypeToLiteralMap jit_class_patches_;
656
657 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM);
658 };
659
660 } // namespace arm
661 } // namespace art
662
663 #endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_H_
664