1 /*
2 * Copyright (C) 2016 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_VIXL_H_
18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_VIXL_H_
19
20 #include "base/macros.h"
21 #include "base/pointer_size.h"
22 #include "class_root.h"
23 #include "code_generator.h"
24 #include "common_arm.h"
25 #include "dex/string_reference.h"
26 #include "dex/type_reference.h"
27 #include "driver/compiler_options.h"
28 #include "nodes.h"
29 #include "parallel_move_resolver.h"
30 #include "utils/arm/assembler_arm_vixl.h"
31
32 // TODO(VIXL): make vixl clean wrt -Wshadow.
33 #pragma GCC diagnostic push
34 #pragma GCC diagnostic ignored "-Wshadow"
35 #include "aarch32/constants-aarch32.h"
36 #include "aarch32/instructions-aarch32.h"
37 #include "aarch32/macro-assembler-aarch32.h"
38 #pragma GCC diagnostic pop
39
40 namespace art HIDDEN {
41
42 namespace linker {
43 class Thumb2RelativePatcherTest;
44 } // namespace linker
45
46 namespace arm {
47
48 // This constant is used as an approximate margin when emission of veneer and literal pools
49 // must be blocked.
50 static constexpr int kMaxMacroInstructionSizeInBytes =
51 15 * vixl::aarch32::kMaxInstructionSizeInBytes;
52
53 static const vixl::aarch32::Register kParameterCoreRegistersVIXL[] = {
54 vixl::aarch32::r1,
55 vixl::aarch32::r2,
56 vixl::aarch32::r3
57 };
58 static const size_t kParameterCoreRegistersLengthVIXL = arraysize(kParameterCoreRegistersVIXL);
59 static const vixl::aarch32::SRegister kParameterFpuRegistersVIXL[] = {
60 vixl::aarch32::s0,
61 vixl::aarch32::s1,
62 vixl::aarch32::s2,
63 vixl::aarch32::s3,
64 vixl::aarch32::s4,
65 vixl::aarch32::s5,
66 vixl::aarch32::s6,
67 vixl::aarch32::s7,
68 vixl::aarch32::s8,
69 vixl::aarch32::s9,
70 vixl::aarch32::s10,
71 vixl::aarch32::s11,
72 vixl::aarch32::s12,
73 vixl::aarch32::s13,
74 vixl::aarch32::s14,
75 vixl::aarch32::s15
76 };
77 static const size_t kParameterFpuRegistersLengthVIXL = arraysize(kParameterFpuRegistersVIXL);
78
79 static const vixl::aarch32::Register kMethodRegister = vixl::aarch32::r0;
80
81 // Callee saves core registers r5, r6, r7, r8 (except when emitting Baker
82 // read barriers, where it is used as Marking Register), r10, r11, and lr.
83 static const vixl::aarch32::RegisterList kCoreCalleeSaves = vixl::aarch32::RegisterList::Union(
84 vixl::aarch32::RegisterList(vixl::aarch32::r5,
85 vixl::aarch32::r6,
86 vixl::aarch32::r7),
87 // Do not consider r8 as a callee-save register with Baker read barriers.
88 (kReserveMarkingRegister
89 ? vixl::aarch32::RegisterList()
90 : vixl::aarch32::RegisterList(vixl::aarch32::r8)),
91 vixl::aarch32::RegisterList(vixl::aarch32::r10,
92 vixl::aarch32::r11,
93 vixl::aarch32::lr));
94
95 // Callee saves FP registers s16 to s31 inclusive.
96 static const vixl::aarch32::SRegisterList kFpuCalleeSaves =
97 vixl::aarch32::SRegisterList(vixl::aarch32::s16, 16);
98
99 static const vixl::aarch32::Register kRuntimeParameterCoreRegistersVIXL[] = {
100 vixl::aarch32::r0,
101 vixl::aarch32::r1,
102 vixl::aarch32::r2,
103 vixl::aarch32::r3
104 };
105 static const size_t kRuntimeParameterCoreRegistersLengthVIXL =
106 arraysize(kRuntimeParameterCoreRegistersVIXL);
107 static const vixl::aarch32::SRegister kRuntimeParameterFpuRegistersVIXL[] = {
108 vixl::aarch32::s0,
109 vixl::aarch32::s1,
110 vixl::aarch32::s2,
111 vixl::aarch32::s3
112 };
113 static const size_t kRuntimeParameterFpuRegistersLengthVIXL =
114 arraysize(kRuntimeParameterFpuRegistersVIXL);
115
116 class LoadClassSlowPathARMVIXL;
117 class CodeGeneratorARMVIXL;
118
119 using VIXLInt32Literal = vixl::aarch32::Literal<int32_t>;
120 using VIXLUInt32Literal = vixl::aarch32::Literal<uint32_t>;
121
122 #define UNIMPLEMENTED_INTRINSIC_LIST_ARM(V) \
123 V(MathRoundDouble) /* Could be done by changing rounding mode, maybe? */ \
124 V(UnsafeCASLong) /* High register pressure */ \
125 V(SystemArrayCopyChar) \
126 V(LongDivideUnsigned) \
127 V(IntegerRemainderUnsigned) \
128 V(LongRemainderUnsigned) \
129 V(CRC32Update) \
130 V(CRC32UpdateBytes) \
131 V(CRC32UpdateByteBuffer) \
132 V(FP16ToFloat) \
133 V(FP16ToHalf) \
134 V(FP16Floor) \
135 V(FP16Ceil) \
136 V(FP16Rint) \
137 V(FP16Greater) \
138 V(FP16GreaterEquals) \
139 V(FP16Less) \
140 V(FP16LessEquals) \
141 V(FP16Compare) \
142 V(FP16Min) \
143 V(FP16Max) \
144 V(MathMultiplyHigh) \
145 V(StringStringIndexOf) \
146 V(StringStringIndexOfAfter) \
147 V(StringBufferAppend) \
148 V(StringBufferLength) \
149 V(StringBufferToString) \
150 V(StringBuilderAppendObject) \
151 V(StringBuilderAppendString) \
152 V(StringBuilderAppendCharSequence) \
153 V(StringBuilderAppendCharArray) \
154 V(StringBuilderAppendBoolean) \
155 V(StringBuilderAppendChar) \
156 V(StringBuilderAppendInt) \
157 V(StringBuilderAppendLong) \
158 V(StringBuilderAppendFloat) \
159 V(StringBuilderAppendDouble) \
160 V(StringBuilderLength) \
161 V(StringBuilderToString) \
162 V(SystemArrayCopyByte) \
163 V(SystemArrayCopyInt) \
164 /* 1.8 */ \
165 V(MathFmaDouble) \
166 V(MathFmaFloat) \
167 V(MethodHandleInvokeExact) \
168 V(MethodHandleInvoke) \
169 /* OpenJDK 11 */ \
170 V(JdkUnsafeCASLong) /* High register pressure */ \
171 V(JdkUnsafeCompareAndSetLong)
172
GetStoreOperandType(DataType::Type type)173 ALWAYS_INLINE inline StoreOperandType GetStoreOperandType(DataType::Type type) {
174 switch (type) {
175 case DataType::Type::kReference:
176 return kStoreWord;
177 case DataType::Type::kBool:
178 case DataType::Type::kUint8:
179 case DataType::Type::kInt8:
180 return kStoreByte;
181 case DataType::Type::kUint16:
182 case DataType::Type::kInt16:
183 return kStoreHalfword;
184 case DataType::Type::kInt32:
185 return kStoreWord;
186 case DataType::Type::kInt64:
187 return kStoreWordPair;
188 case DataType::Type::kFloat32:
189 return kStoreSWord;
190 case DataType::Type::kFloat64:
191 return kStoreDWord;
192 default:
193 LOG(FATAL) << "Unreachable type " << type;
194 UNREACHABLE();
195 }
196 }
197
198 class JumpTableARMVIXL : public DeletableArenaObject<kArenaAllocSwitchTable> {
199 public:
JumpTableARMVIXL(HPackedSwitch * switch_instr)200 explicit JumpTableARMVIXL(HPackedSwitch* switch_instr)
201 : switch_instr_(switch_instr),
202 table_start_(),
203 bb_addresses_(switch_instr->GetAllocator()->Adapter(kArenaAllocCodeGenerator)) {
204 uint32_t num_entries = switch_instr_->GetNumEntries();
205 for (uint32_t i = 0; i < num_entries; i++) {
206 VIXLInt32Literal *lit = new VIXLInt32Literal(0, vixl32::RawLiteral::kManuallyPlaced);
207 bb_addresses_.emplace_back(lit);
208 }
209 }
210
GetTableStartLabel()211 vixl::aarch32::Label* GetTableStartLabel() { return &table_start_; }
212
213 void EmitTable(CodeGeneratorARMVIXL* codegen);
214 void FixTable(CodeGeneratorARMVIXL* codegen);
215
216 private:
217 HPackedSwitch* const switch_instr_;
218 vixl::aarch32::Label table_start_;
219 ArenaVector<std::unique_ptr<VIXLInt32Literal>> bb_addresses_;
220
221 DISALLOW_COPY_AND_ASSIGN(JumpTableARMVIXL);
222 };
223
224 class InvokeRuntimeCallingConventionARMVIXL
225 : public CallingConvention<vixl::aarch32::Register, vixl::aarch32::SRegister> {
226 public:
InvokeRuntimeCallingConventionARMVIXL()227 InvokeRuntimeCallingConventionARMVIXL()
228 : CallingConvention(kRuntimeParameterCoreRegistersVIXL,
229 kRuntimeParameterCoreRegistersLengthVIXL,
230 kRuntimeParameterFpuRegistersVIXL,
231 kRuntimeParameterFpuRegistersLengthVIXL,
232 kArmPointerSize) {}
233
234 private:
235 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConventionARMVIXL);
236 };
237
238 class InvokeDexCallingConventionARMVIXL
239 : public CallingConvention<vixl::aarch32::Register, vixl::aarch32::SRegister> {
240 public:
InvokeDexCallingConventionARMVIXL()241 InvokeDexCallingConventionARMVIXL()
242 : CallingConvention(kParameterCoreRegistersVIXL,
243 kParameterCoreRegistersLengthVIXL,
244 kParameterFpuRegistersVIXL,
245 kParameterFpuRegistersLengthVIXL,
246 kArmPointerSize) {}
247
248 private:
249 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionARMVIXL);
250 };
251
252 class InvokeDexCallingConventionVisitorARMVIXL : public InvokeDexCallingConventionVisitor {
253 public:
InvokeDexCallingConventionVisitorARMVIXL()254 InvokeDexCallingConventionVisitorARMVIXL() {}
~InvokeDexCallingConventionVisitorARMVIXL()255 virtual ~InvokeDexCallingConventionVisitorARMVIXL() {}
256
257 Location GetNextLocation(DataType::Type type) override;
258 Location GetReturnLocation(DataType::Type type) const override;
259 Location GetMethodLocation() const override;
260
261 private:
262 InvokeDexCallingConventionARMVIXL calling_convention;
263 uint32_t double_index_ = 0;
264
265 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorARMVIXL);
266 };
267
268 class CriticalNativeCallingConventionVisitorARMVIXL : public InvokeDexCallingConventionVisitor {
269 public:
CriticalNativeCallingConventionVisitorARMVIXL(bool for_register_allocation)270 explicit CriticalNativeCallingConventionVisitorARMVIXL(bool for_register_allocation)
271 : for_register_allocation_(for_register_allocation) {}
272
~CriticalNativeCallingConventionVisitorARMVIXL()273 virtual ~CriticalNativeCallingConventionVisitorARMVIXL() {}
274
275 Location GetNextLocation(DataType::Type type) override;
276 Location GetReturnLocation(DataType::Type type) const override;
277 Location GetMethodLocation() const override;
278
GetStackOffset()279 size_t GetStackOffset() const { return stack_offset_; }
280
281 private:
282 // Register allocator does not support adjusting frame size, so we cannot provide final locations
283 // of stack arguments for register allocation. We ask the register allocator for any location and
284 // move these arguments to the right place after adjusting the SP when generating the call.
285 const bool for_register_allocation_;
286 size_t gpr_index_ = 0u;
287 size_t stack_offset_ = 0u;
288
289 DISALLOW_COPY_AND_ASSIGN(CriticalNativeCallingConventionVisitorARMVIXL);
290 };
291
292 class FieldAccessCallingConventionARMVIXL : public FieldAccessCallingConvention {
293 public:
FieldAccessCallingConventionARMVIXL()294 FieldAccessCallingConventionARMVIXL() {}
295
GetObjectLocation()296 Location GetObjectLocation() const override {
297 return helpers::LocationFrom(vixl::aarch32::r1);
298 }
GetFieldIndexLocation()299 Location GetFieldIndexLocation() const override {
300 return helpers::LocationFrom(vixl::aarch32::r0);
301 }
GetReturnLocation(DataType::Type type)302 Location GetReturnLocation(DataType::Type type) const override {
303 return DataType::Is64BitType(type)
304 ? helpers::LocationFrom(vixl::aarch32::r0, vixl::aarch32::r1)
305 : helpers::LocationFrom(vixl::aarch32::r0);
306 }
GetSetValueLocation(DataType::Type type,bool is_instance)307 Location GetSetValueLocation(DataType::Type type, bool is_instance) const override {
308 return DataType::Is64BitType(type)
309 ? helpers::LocationFrom(vixl::aarch32::r2, vixl::aarch32::r3)
310 : (is_instance
311 ? helpers::LocationFrom(vixl::aarch32::r2)
312 : helpers::LocationFrom(vixl::aarch32::r1));
313 }
GetFpuLocation(DataType::Type type)314 Location GetFpuLocation(DataType::Type type) const override {
315 return DataType::Is64BitType(type)
316 ? helpers::LocationFrom(vixl::aarch32::s0, vixl::aarch32::s1)
317 : helpers::LocationFrom(vixl::aarch32::s0);
318 }
319
320 private:
321 DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionARMVIXL);
322 };
323
324 class SlowPathCodeARMVIXL : public SlowPathCode {
325 public:
SlowPathCodeARMVIXL(HInstruction * instruction)326 explicit SlowPathCodeARMVIXL(HInstruction* instruction)
327 : SlowPathCode(instruction), entry_label_(), exit_label_() {}
328
GetEntryLabel()329 vixl::aarch32::Label* GetEntryLabel() { return &entry_label_; }
GetExitLabel()330 vixl::aarch32::Label* GetExitLabel() { return &exit_label_; }
331
332 void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) override;
333 void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) override;
334
335 private:
336 vixl::aarch32::Label entry_label_;
337 vixl::aarch32::Label exit_label_;
338
339 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARMVIXL);
340 };
341
342 class ParallelMoveResolverARMVIXL : public ParallelMoveResolverWithSwap {
343 public:
ParallelMoveResolverARMVIXL(ArenaAllocator * allocator,CodeGeneratorARMVIXL * codegen)344 ParallelMoveResolverARMVIXL(ArenaAllocator* allocator, CodeGeneratorARMVIXL* codegen)
345 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {}
346
347 void EmitMove(size_t index) override;
348 void EmitSwap(size_t index) override;
349 void SpillScratch(int reg) override;
350 void RestoreScratch(int reg) override;
351
352 ArmVIXLAssembler* GetAssembler() const;
353
354 private:
355 void Exchange(vixl32::Register reg, int mem);
356 void Exchange(int mem1, int mem2);
357
358 CodeGeneratorARMVIXL* const codegen_;
359
360 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverARMVIXL);
361 };
362
363 class LocationsBuilderARMVIXL : public HGraphVisitor {
364 public:
LocationsBuilderARMVIXL(HGraph * graph,CodeGeneratorARMVIXL * codegen)365 LocationsBuilderARMVIXL(HGraph* graph, CodeGeneratorARMVIXL* codegen)
366 : HGraphVisitor(graph), codegen_(codegen) {}
367
368 #define DECLARE_VISIT_INSTRUCTION(name, super) \
369 void Visit##name(H##name* instr) override;
370
371 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)372 FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)
373 FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION)
374
375 #undef DECLARE_VISIT_INSTRUCTION
376
377 void VisitInstruction(HInstruction* instruction) override {
378 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
379 << " (id " << instruction->GetId() << ")";
380 }
381
382 private:
383 void HandleInvoke(HInvoke* invoke);
384 void HandleBitwiseOperation(HBinaryOperation* operation, Opcode opcode);
385 void HandleCondition(HCondition* condition);
386 void HandleIntegerRotate(LocationSummary* locations);
387 void HandleLongRotate(LocationSummary* locations);
388 void HandleShift(HBinaryOperation* operation);
389 void HandleFieldSet(HInstruction* instruction,
390 const FieldInfo& field_info,
391 WriteBarrierKind write_barrier_kind);
392 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
393
394 Location ArithmeticZeroOrFpuRegister(HInstruction* input);
395 Location ArmEncodableConstantOrRegister(HInstruction* constant, Opcode opcode);
396 bool CanEncodeConstantAsImmediate(HConstant* input_cst, Opcode opcode);
397
398 CodeGeneratorARMVIXL* const codegen_;
399 InvokeDexCallingConventionVisitorARMVIXL parameter_visitor_;
400
401 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARMVIXL);
402 };
403
404 class InstructionCodeGeneratorARMVIXL : public InstructionCodeGenerator {
405 public:
406 InstructionCodeGeneratorARMVIXL(HGraph* graph, CodeGeneratorARMVIXL* codegen);
407
408 #define DECLARE_VISIT_INSTRUCTION(name, super) \
409 void Visit##name(H##name* instr) override;
410
411 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)412 FOR_EACH_CONCRETE_INSTRUCTION_ARM(DECLARE_VISIT_INSTRUCTION)
413 FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION)
414
415 #undef DECLARE_VISIT_INSTRUCTION
416
417 void VisitInstruction(HInstruction* instruction) override {
418 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
419 << " (id " << instruction->GetId() << ")";
420 }
421
GetAssembler()422 ArmVIXLAssembler* GetAssembler() const { return assembler_; }
GetVIXLAssembler()423 ArmVIXLMacroAssembler* GetVIXLAssembler() { return GetAssembler()->GetVIXLAssembler(); }
424
425 void GenerateAndConst(vixl::aarch32::Register out, vixl::aarch32::Register first, uint32_t value);
426
427 private:
428 // Generate code for the given suspend check. If not null, `successor`
429 // is the block to branch to if the suspend check is not needed, and after
430 // the suspend call.
431 void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor);
432 void GenerateClassInitializationCheck(LoadClassSlowPathARMVIXL* slow_path,
433 vixl32::Register class_reg);
434 void GenerateBitstringTypeCheckCompare(HTypeCheckInstruction* check,
435 vixl::aarch32::Register temp,
436 vixl::aarch32::FlagsUpdate flags_update);
437 void GenerateOrrConst(vixl::aarch32::Register out, vixl::aarch32::Register first, uint32_t value);
438 void GenerateEorConst(vixl::aarch32::Register out, vixl::aarch32::Register first, uint32_t value);
439 void GenerateAddLongConst(Location out, Location first, uint64_t value);
440 void HandleBitwiseOperation(HBinaryOperation* operation);
441 void HandleCondition(HCondition* condition);
442 void HandleIntegerRotate(HRor* ror);
443 void HandleLongRotate(HRor* ror);
444 void HandleShift(HBinaryOperation* operation);
445
446 void GenerateWideAtomicStore(vixl::aarch32::Register addr,
447 uint32_t offset,
448 vixl::aarch32::Register value_lo,
449 vixl::aarch32::Register value_hi,
450 vixl::aarch32::Register temp1,
451 vixl::aarch32::Register temp2,
452 HInstruction* instruction);
453 void GenerateWideAtomicLoad(vixl::aarch32::Register addr,
454 uint32_t offset,
455 vixl::aarch32::Register out_lo,
456 vixl::aarch32::Register out_hi);
457
458 void HandleFieldSet(HInstruction* instruction,
459 const FieldInfo& field_info,
460 bool value_can_be_null,
461 WriteBarrierKind write_barrier_kind);
462 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
463
464 void GenerateMinMaxInt(LocationSummary* locations, bool is_min);
465 void GenerateMinMaxLong(LocationSummary* locations, bool is_min);
466 void GenerateMinMaxFloat(HInstruction* minmax, bool is_min);
467 void GenerateMinMaxDouble(HInstruction* minmax, bool is_min);
468 void GenerateMinMax(HBinaryOperation* minmax, bool is_min);
469
470 // Generate a heap reference load using one register `out`:
471 //
472 // out <- *(out + offset)
473 //
474 // while honoring heap poisoning and/or read barriers (if any).
475 //
476 // Location `maybe_temp` is used when generating a read barrier and
477 // shall be a register in that case; it may be an invalid location
478 // otherwise.
479 void GenerateReferenceLoadOneRegister(HInstruction* instruction,
480 Location out,
481 uint32_t offset,
482 Location maybe_temp,
483 ReadBarrierOption read_barrier_option);
484 // Generate a heap reference load using two different registers
485 // `out` and `obj`:
486 //
487 // out <- *(obj + offset)
488 //
489 // while honoring heap poisoning and/or read barriers (if any).
490 //
491 // Location `maybe_temp` is used when generating a Baker's (fast
492 // path) read barrier and shall be a register in that case; it may
493 // be an invalid location otherwise.
494 void GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
495 Location out,
496 Location obj,
497 uint32_t offset,
498 Location maybe_temp,
499 ReadBarrierOption read_barrier_option);
500 void GenerateTestAndBranch(HInstruction* instruction,
501 size_t condition_input_index,
502 vixl::aarch32::Label* true_target,
503 vixl::aarch32::Label* false_target,
504 bool far_target = true);
505 void GenerateCompareTestAndBranch(HCondition* condition,
506 vixl::aarch32::Label* true_target,
507 vixl::aarch32::Label* false_target,
508 bool is_far_target = true);
509 void DivRemOneOrMinusOne(HBinaryOperation* instruction);
510 void DivRemByPowerOfTwo(HBinaryOperation* instruction);
511 void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
512 void GenerateDivRemConstantIntegral(HBinaryOperation* instruction);
513 void HandleGoto(HInstruction* got, HBasicBlock* successor);
514 void GenerateMethodEntryExitHook(HInstruction* instruction);
515
516 vixl::aarch32::MemOperand VecAddress(
517 HVecMemoryOperation* instruction,
518 // This function may acquire a scratch register.
519 vixl::aarch32::UseScratchRegisterScope* temps_scope,
520 /*out*/ vixl32::Register* scratch);
521 vixl::aarch32::AlignedMemOperand VecAddressUnaligned(
522 HVecMemoryOperation* instruction,
523 // This function may acquire a scratch register.
524 vixl::aarch32::UseScratchRegisterScope* temps_scope,
525 /*out*/ vixl32::Register* scratch);
526
527 ArmVIXLAssembler* const assembler_;
528 CodeGeneratorARMVIXL* const codegen_;
529
530 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorARMVIXL);
531 };
532
533 class CodeGeneratorARMVIXL : public CodeGenerator {
534 public:
535 CodeGeneratorARMVIXL(HGraph* graph,
536 const CompilerOptions& compiler_options,
537 OptimizingCompilerStats* stats = nullptr);
~CodeGeneratorARMVIXL()538 virtual ~CodeGeneratorARMVIXL() {}
539
540 void GenerateFrameEntry() override;
541 void GenerateFrameExit() override;
542 void Bind(HBasicBlock* block) override;
543 void MoveConstant(Location destination, int32_t value) override;
544 void MoveLocation(Location dst, Location src, DataType::Type dst_type) override;
545 void AddLocationAsTemp(Location location, LocationSummary* locations) override;
546
547 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) override;
548 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) override;
549 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) override;
550 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) override;
551
GetWordSize()552 size_t GetWordSize() const override {
553 return static_cast<size_t>(kArmPointerSize);
554 }
555
GetCalleePreservedFPWidth()556 size_t GetCalleePreservedFPWidth() const override {
557 return vixl::aarch32::kSRegSizeInBytes;
558 }
559
GetSIMDRegisterWidth()560 size_t GetSIMDRegisterWidth() const override {
561 // ARM 32-bit backend doesn't support Q registers in vectorizer, only D
562 // registers (due to register allocator restrictions: overlapping s/d/q
563 // registers).
564 return vixl::aarch32::kDRegSizeInBytes;
565 }
566
GetLocationBuilder()567 HGraphVisitor* GetLocationBuilder() override { return &location_builder_; }
568
GetInstructionVisitor()569 HGraphVisitor* GetInstructionVisitor() override { return &instruction_visitor_; }
570
GetAssembler()571 ArmVIXLAssembler* GetAssembler() override { return &assembler_; }
572
GetAssembler()573 const ArmVIXLAssembler& GetAssembler() const override { return assembler_; }
574
GetVIXLAssembler()575 ArmVIXLMacroAssembler* GetVIXLAssembler() { return GetAssembler()->GetVIXLAssembler(); }
576
GetAddressOf(HBasicBlock * block)577 uintptr_t GetAddressOf(HBasicBlock* block) override {
578 vixl::aarch32::Label* block_entry_label = GetLabelOf(block);
579 DCHECK(block_entry_label->IsBound());
580 return block_entry_label->GetLocation();
581 }
582
583 void FixJumpTables();
584 void SetupBlockedRegisters() const override;
585
586 void DumpCoreRegister(std::ostream& stream, int reg) const override;
587 void DumpFloatingPointRegister(std::ostream& stream, int reg) const override;
588
GetMoveResolver()589 ParallelMoveResolver* GetMoveResolver() override { return &move_resolver_; }
GetInstructionSet()590 InstructionSet GetInstructionSet() const override { return InstructionSet::kThumb2; }
591
592 const ArmInstructionSetFeatures& GetInstructionSetFeatures() const;
593
594 // Helper method to move a 32-bit value between two locations.
595 void Move32(Location destination, Location source);
596
597 void LoadFromShiftedRegOffset(DataType::Type type,
598 Location out_loc,
599 vixl::aarch32::Register base,
600 vixl::aarch32::Register reg_index,
601 vixl::aarch32::Condition cond = vixl::aarch32::al);
602 void StoreToShiftedRegOffset(DataType::Type type,
603 Location out_loc,
604 vixl::aarch32::Register base,
605 vixl::aarch32::Register reg_index,
606 vixl::aarch32::Condition cond = vixl::aarch32::al);
607
608 // Generate code to invoke a runtime entry point.
609 void InvokeRuntime(QuickEntrypointEnum entrypoint,
610 HInstruction* instruction,
611 uint32_t dex_pc,
612 SlowPathCode* slow_path = nullptr) override;
613
614 // Generate code to invoke a runtime entry point, but do not record
615 // PC-related information in a stack map.
616 void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
617 HInstruction* instruction,
618 SlowPathCode* slow_path);
619
620 // Emit a write barrier if:
621 // A) emit_null_check is false
622 // B) emit_null_check is true, and value is not null.
623 void MaybeMarkGCCard(vixl::aarch32::Register temp,
624 vixl::aarch32::Register card,
625 vixl::aarch32::Register object,
626 vixl::aarch32::Register value,
627 bool emit_null_check);
628
629 // Emit a write barrier unconditionally.
630 void MarkGCCard(vixl::aarch32::Register temp,
631 vixl::aarch32::Register card,
632 vixl::aarch32::Register object);
633
634 // Crash if the card table is not valid. This check is only emitted for the CC GC. We assert
635 // `(!clean || !self->is_gc_marking)`, since the card table should not be set to clean when the CC
636 // GC is marking for eliminated write barriers.
637 void CheckGCCardIsValid(vixl::aarch32::Register temp,
638 vixl::aarch32::Register card,
639 vixl::aarch32::Register object);
640
641 void GenerateMemoryBarrier(MemBarrierKind kind);
642
GetLabelOf(HBasicBlock * block)643 vixl::aarch32::Label* GetLabelOf(HBasicBlock* block) {
644 block = FirstNonEmptyBlock(block);
645 return &(block_labels_[block->GetBlockId()]);
646 }
647
648 vixl32::Label* GetFinalLabel(HInstruction* instruction, vixl32::Label* final_label);
649
Initialize()650 void Initialize() override {
651 block_labels_.resize(GetGraph()->GetBlocks().size());
652 }
653
654 void Finalize() override;
655
NeedsTwoRegisters(DataType::Type type)656 bool NeedsTwoRegisters(DataType::Type type) const override {
657 return type == DataType::Type::kFloat64 || type == DataType::Type::kInt64;
658 }
659
660 void ComputeSpillMask() override;
661
GetFrameEntryLabel()662 vixl::aarch32::Label* GetFrameEntryLabel() { return &frame_entry_label_; }
663
664 // Check if the desired_string_load_kind is supported. If it is, return it,
665 // otherwise return a fall-back kind that should be used instead.
666 HLoadString::LoadKind GetSupportedLoadStringKind(
667 HLoadString::LoadKind desired_string_load_kind) override;
668
669 // Check if the desired_class_load_kind is supported. If it is, return it,
670 // otherwise return a fall-back kind that should be used instead.
671 HLoadClass::LoadKind GetSupportedLoadClassKind(
672 HLoadClass::LoadKind desired_class_load_kind) override;
673
674 // Check if the desired_dispatch_info is supported. If it is, return it,
675 // otherwise return a fall-back info that should be used instead.
676 HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
677 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
678 ArtMethod* method) override;
679
680 void LoadMethod(MethodLoadKind load_kind, Location temp, HInvoke* invoke);
681 void GenerateStaticOrDirectCall(
682 HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
683 void GenerateVirtualCall(
684 HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
685
686 void MoveFromReturnRegister(Location trg, DataType::Type type) override;
687
688 // The PcRelativePatchInfo is used for PC-relative addressing of methods/strings/types,
689 // whether through .data.img.rel.ro, .bss, or directly in the boot image.
690 //
691 // The PC-relative address is loaded with three instructions,
692 // MOVW+MOVT to load the offset to base_reg and then ADD base_reg, PC. The offset
693 // is calculated from the ADD's effective PC, i.e. PC+4 on Thumb2. Though we
694 // currently emit these 3 instructions together, instruction scheduling could
695 // split this sequence apart, so we keep separate labels for each of them.
696 struct PcRelativePatchInfo {
PcRelativePatchInfoPcRelativePatchInfo697 PcRelativePatchInfo(const DexFile* dex_file, uint32_t off_or_idx)
698 : target_dex_file(dex_file), offset_or_index(off_or_idx) { }
699
700 // Target dex file or null for boot image .data.img.rel.ro patches.
701 const DexFile* target_dex_file;
702 // Either the boot image offset (to write to .data.img.rel.ro) or string/type/method index.
703 uint32_t offset_or_index;
704 vixl::aarch32::Label movw_label;
705 vixl::aarch32::Label movt_label;
706 vixl::aarch32::Label add_pc_label;
707 };
708
709 PcRelativePatchInfo* NewBootImageIntrinsicPatch(uint32_t intrinsic_data);
710 PcRelativePatchInfo* NewBootImageRelRoPatch(uint32_t boot_image_offset);
711 PcRelativePatchInfo* NewBootImageMethodPatch(MethodReference target_method);
712 PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method);
713 PcRelativePatchInfo* NewBootImageTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
714 PcRelativePatchInfo* NewAppImageTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
715 PcRelativePatchInfo* NewTypeBssEntryPatch(HLoadClass* load_class);
716 PcRelativePatchInfo* NewBootImageStringPatch(const DexFile& dex_file,
717 dex::StringIndex string_index);
718 PcRelativePatchInfo* NewStringBssEntryPatch(const DexFile& dex_file,
719 dex::StringIndex string_index);
720
721 // Emit the BL instruction for entrypoint thunk call and record the associated patch for AOT.
722 void EmitEntrypointThunkCall(ThreadOffset32 entrypoint_offset);
723
724 // Emit the BNE instruction for baker read barrier and record
725 // the associated patch for AOT or slow path for JIT.
726 void EmitBakerReadBarrierBne(uint32_t custom_data);
727
728 VIXLUInt32Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
729 VIXLUInt32Literal* DeduplicateJitStringLiteral(const DexFile& dex_file,
730 dex::StringIndex string_index,
731 Handle<mirror::String> handle);
732 VIXLUInt32Literal* DeduplicateJitClassLiteral(const DexFile& dex_file,
733 dex::TypeIndex type_index,
734 Handle<mirror::Class> handle);
735
736 void LoadBootImageRelRoEntry(vixl::aarch32::Register reg, uint32_t boot_image_offset);
737 void LoadBootImageAddress(vixl::aarch32::Register reg, uint32_t boot_image_reference);
738 void LoadTypeForBootImageIntrinsic(vixl::aarch32::Register reg, TypeReference type_reference);
739 void LoadIntrinsicDeclaringClass(vixl::aarch32::Register reg, HInvoke* invoke);
740 void LoadClassRootForIntrinsic(vixl::aarch32::Register reg, ClassRoot class_root);
741
742 void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) override;
743 bool NeedsThunkCode(const linker::LinkerPatch& patch) const override;
744 void EmitThunkCode(const linker::LinkerPatch& patch,
745 /*out*/ ArenaVector<uint8_t>* code,
746 /*out*/ std::string* debug_name) override;
747
748 void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) override;
749
750 // Generate a GC root reference load:
751 //
752 // root <- *(obj + offset)
753 //
754 // while honoring read barriers based on read_barrier_option.
755 void GenerateGcRootFieldLoad(HInstruction* instruction,
756 Location root,
757 vixl::aarch32::Register obj,
758 uint32_t offset,
759 ReadBarrierOption read_barrier_option);
760 // Generate MOV for an intrinsic to mark the old value with Baker read barrier.
761 void GenerateIntrinsicMoveWithBakerReadBarrier(vixl::aarch32::Register marked_old_value,
762 vixl::aarch32::Register old_value);
763 // Fast path implementation of ReadBarrier::Barrier for a heap
764 // reference field load when Baker's read barriers are used.
765 // Overload suitable for Unsafe.getObject/-Volatile() intrinsic.
766 void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
767 Location ref,
768 vixl::aarch32::Register obj,
769 const vixl::aarch32::MemOperand& src,
770 bool needs_null_check);
771 // Fast path implementation of ReadBarrier::Barrier for a heap
772 // reference field load when Baker's read barriers are used.
773 void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
774 Location ref,
775 vixl::aarch32::Register obj,
776 uint32_t offset,
777 Location maybe_temp,
778 bool needs_null_check);
779 // Fast path implementation of ReadBarrier::Barrier for a heap
780 // reference array load when Baker's read barriers are used.
781 void GenerateArrayLoadWithBakerReadBarrier(Location ref,
782 vixl::aarch32::Register obj,
783 uint32_t data_offset,
784 Location index,
785 Location temp,
786 bool needs_null_check);
787
788 // Emit code checking the status of the Marking Register, and
789 // aborting the program if MR does not match the value stored in the
790 // art::Thread object. Code is only emitted in debug mode and if
791 // CompilerOptions::EmitRunTimeChecksInDebugMode returns true.
792 //
793 // Argument `code` is used to identify the different occurrences of
794 // MaybeGenerateMarkingRegisterCheck in the code generator, and is
795 // used together with kMarkingRegisterCheckBreakCodeBaseCode to
796 // create the value passed to the BKPT instruction. Note that unlike
797 // in the ARM64 code generator, where `__LINE__` is passed as `code`
798 // argument to
799 // CodeGeneratorARM64::MaybeGenerateMarkingRegisterCheck, we cannot
800 // realistically do that here, as Encoding T1 for the BKPT
801 // instruction only accepts 8-bit immediate values.
802 //
803 // If `temp_loc` is a valid location, it is expected to be a
804 // register and will be used as a temporary to generate code;
805 // otherwise, a temporary will be fetched from the core register
806 // scratch pool.
807 virtual void MaybeGenerateMarkingRegisterCheck(int code,
808 Location temp_loc = Location::NoLocation());
809
810 // Create slow path for a read barrier for a heap reference within `instruction`.
811 //
812 // This is a helper function for GenerateReadBarrierSlow() that has the same
813 // arguments. The creation and adding of the slow path is exposed for intrinsics
814 // that cannot use GenerateReadBarrierSlow() from their own slow paths.
815 SlowPathCodeARMVIXL* AddReadBarrierSlowPath(HInstruction* instruction,
816 Location out,
817 Location ref,
818 Location obj,
819 uint32_t offset,
820 Location index);
821
822 // Generate a read barrier for a heap reference within `instruction`
823 // using a slow path.
824 //
825 // A read barrier for an object reference read from the heap is
826 // implemented as a call to the artReadBarrierSlow runtime entry
827 // point, which is passed the values in locations `ref`, `obj`, and
828 // `offset`:
829 //
830 // mirror::Object* artReadBarrierSlow(mirror::Object* ref,
831 // mirror::Object* obj,
832 // uint32_t offset);
833 //
834 // The `out` location contains the value returned by
835 // artReadBarrierSlow.
836 //
837 // When `index` is provided (i.e. for array accesses), the offset
838 // value passed to artReadBarrierSlow is adjusted to take `index`
839 // into account.
840 void GenerateReadBarrierSlow(HInstruction* instruction,
841 Location out,
842 Location ref,
843 Location obj,
844 uint32_t offset,
845 Location index = Location::NoLocation());
846
847 // If read barriers are enabled, generate a read barrier for a heap
848 // reference using a slow path. If heap poisoning is enabled, also
849 // unpoison the reference in `out`.
850 void MaybeGenerateReadBarrierSlow(HInstruction* instruction,
851 Location out,
852 Location ref,
853 Location obj,
854 uint32_t offset,
855 Location index = Location::NoLocation());
856
857 // Generate a read barrier for a GC root within `instruction` using
858 // a slow path.
859 //
860 // A read barrier for an object reference GC root is implemented as
861 // a call to the artReadBarrierForRootSlow runtime entry point,
862 // which is passed the value in location `root`:
863 //
864 // mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root);
865 //
866 // The `out` location contains the value returned by
867 // artReadBarrierForRootSlow.
868 void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root);
869
870 void IncreaseFrame(size_t adjustment) override;
871 void DecreaseFrame(size_t adjustment) override;
872
873 void GenerateNop() override;
874
875 void GenerateImplicitNullCheck(HNullCheck* instruction) override;
876 void GenerateExplicitNullCheck(HNullCheck* instruction) override;
877
CreateJumpTable(HPackedSwitch * switch_instr)878 JumpTableARMVIXL* CreateJumpTable(HPackedSwitch* switch_instr) {
879 jump_tables_.emplace_back(new (GetGraph()->GetAllocator()) JumpTableARMVIXL(switch_instr));
880 return jump_tables_.back().get();
881 }
882 void EmitJumpTables();
883
884 void EmitMovwMovtPlaceholder(CodeGeneratorARMVIXL::PcRelativePatchInfo* labels,
885 vixl::aarch32::Register out);
886
887 // `temp` is an extra temporary register that is used for some conditions;
888 // callers may not specify it, in which case the method will use a scratch
889 // register instead.
890 void GenerateConditionWithZero(IfCondition condition,
891 vixl::aarch32::Register out,
892 vixl::aarch32::Register in,
893 vixl::aarch32::Register temp = vixl32::Register());
894
MaybeRecordImplicitNullCheck(HInstruction * instr)895 void MaybeRecordImplicitNullCheck(HInstruction* instr) final {
896 // The function must be only be called within special scopes
897 // (EmissionCheckScope, ExactAssemblyScope) which prevent generation of
898 // veneer/literal pools by VIXL assembler.
899 CHECK_EQ(GetVIXLAssembler()->ArePoolsBlocked(), true)
900 << "The function must only be called within EmissionCheckScope or ExactAssemblyScope";
901 CodeGenerator::MaybeRecordImplicitNullCheck(instr);
902 }
903
904 void MaybeGenerateInlineCacheCheck(HInstruction* instruction, vixl32::Register klass);
905 void MaybeIncrementHotness(HSuspendCheck* suspend_check, bool is_frame_entry);
906
907 private:
908 // Encoding of thunk type and data for link-time generated thunks for Baker read barriers.
909
910 enum class BakerReadBarrierKind : uint8_t {
911 kField, // Field get or array get with constant offset (i.e. constant index).
912 kArray, // Array get with index in register.
913 kGcRoot, // GC root load.
914 kIntrinsicCas, // Unsafe/VarHandle CAS intrinsic.
915 kLast = kIntrinsicCas
916 };
917
918 enum class BakerReadBarrierWidth : uint8_t {
919 kWide, // 32-bit LDR (and 32-bit NEG if heap poisoning is enabled).
920 kNarrow, // 16-bit LDR (and 16-bit NEG if heap poisoning is enabled).
921 kLast = kNarrow
922 };
923
924 static constexpr uint32_t kBakerReadBarrierInvalidEncodedReg = /* pc is invalid */ 15u;
925
926 static constexpr size_t kBitsForBakerReadBarrierKind =
927 MinimumBitsToStore(static_cast<size_t>(BakerReadBarrierKind::kLast));
928 static constexpr size_t kBakerReadBarrierBitsForRegister =
929 MinimumBitsToStore(kBakerReadBarrierInvalidEncodedReg);
930 using BakerReadBarrierKindField =
931 BitField<BakerReadBarrierKind, 0, kBitsForBakerReadBarrierKind>;
932 using BakerReadBarrierFirstRegField =
933 BitField<uint32_t, kBitsForBakerReadBarrierKind, kBakerReadBarrierBitsForRegister>;
934 using BakerReadBarrierSecondRegField =
935 BitField<uint32_t,
936 kBitsForBakerReadBarrierKind + kBakerReadBarrierBitsForRegister,
937 kBakerReadBarrierBitsForRegister>;
938 static constexpr size_t kBitsForBakerReadBarrierWidth =
939 MinimumBitsToStore(static_cast<size_t>(BakerReadBarrierWidth::kLast));
940 using BakerReadBarrierWidthField =
941 BitField<BakerReadBarrierWidth,
942 kBitsForBakerReadBarrierKind + 2 * kBakerReadBarrierBitsForRegister,
943 kBitsForBakerReadBarrierWidth>;
944
CheckValidReg(uint32_t reg)945 static void CheckValidReg(uint32_t reg) {
946 DCHECK(reg < vixl::aarch32::ip.GetCode() && reg != mr.GetCode()) << reg;
947 }
948
EncodeBakerReadBarrierFieldData(uint32_t base_reg,uint32_t holder_reg,bool narrow)949 static uint32_t EncodeBakerReadBarrierFieldData(uint32_t base_reg,
950 uint32_t holder_reg,
951 bool narrow) {
952 CheckValidReg(base_reg);
953 CheckValidReg(holder_reg);
954 DCHECK_IMPLIES(narrow, base_reg < 8u) << base_reg;
955 BakerReadBarrierWidth width =
956 narrow ? BakerReadBarrierWidth::kNarrow : BakerReadBarrierWidth::kWide;
957 return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kField) |
958 BakerReadBarrierFirstRegField::Encode(base_reg) |
959 BakerReadBarrierSecondRegField::Encode(holder_reg) |
960 BakerReadBarrierWidthField::Encode(width);
961 }
962
EncodeBakerReadBarrierArrayData(uint32_t base_reg)963 static uint32_t EncodeBakerReadBarrierArrayData(uint32_t base_reg) {
964 CheckValidReg(base_reg);
965 return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kArray) |
966 BakerReadBarrierFirstRegField::Encode(base_reg) |
967 BakerReadBarrierSecondRegField::Encode(kBakerReadBarrierInvalidEncodedReg) |
968 BakerReadBarrierWidthField::Encode(BakerReadBarrierWidth::kWide);
969 }
970
EncodeBakerReadBarrierGcRootData(uint32_t root_reg,bool narrow)971 static uint32_t EncodeBakerReadBarrierGcRootData(uint32_t root_reg, bool narrow) {
972 CheckValidReg(root_reg);
973 DCHECK_IMPLIES(narrow, root_reg < 8u) << root_reg;
974 BakerReadBarrierWidth width =
975 narrow ? BakerReadBarrierWidth::kNarrow : BakerReadBarrierWidth::kWide;
976 return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kGcRoot) |
977 BakerReadBarrierFirstRegField::Encode(root_reg) |
978 BakerReadBarrierSecondRegField::Encode(kBakerReadBarrierInvalidEncodedReg) |
979 BakerReadBarrierWidthField::Encode(width);
980 }
981
EncodeBakerReadBarrierIntrinsicCasData(uint32_t root_reg)982 static uint32_t EncodeBakerReadBarrierIntrinsicCasData(uint32_t root_reg) {
983 CheckValidReg(root_reg);
984 return BakerReadBarrierKindField::Encode(BakerReadBarrierKind::kIntrinsicCas) |
985 BakerReadBarrierFirstRegField::Encode(root_reg) |
986 BakerReadBarrierSecondRegField::Encode(kBakerReadBarrierInvalidEncodedReg) |
987 BakerReadBarrierWidthField::Encode(BakerReadBarrierWidth::kWide);
988 }
989
990 void CompileBakerReadBarrierThunk(ArmVIXLAssembler& assembler,
991 uint32_t encoded_data,
992 /*out*/ std::string* debug_name);
993
994 using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, VIXLUInt32Literal*>;
995 using StringToLiteralMap = ArenaSafeMap<StringReference,
996 VIXLUInt32Literal*,
997 StringReferenceValueComparator>;
998 using TypeToLiteralMap = ArenaSafeMap<TypeReference,
999 VIXLUInt32Literal*,
1000 TypeReferenceValueComparator>;
1001
1002 struct BakerReadBarrierPatchInfo {
BakerReadBarrierPatchInfoBakerReadBarrierPatchInfo1003 explicit BakerReadBarrierPatchInfo(uint32_t data) : label(), custom_data(data) { }
1004
1005 vixl::aarch32::Label label;
1006 uint32_t custom_data;
1007 };
1008
1009 VIXLUInt32Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map);
1010 PcRelativePatchInfo* NewPcRelativePatch(const DexFile* dex_file,
1011 uint32_t offset_or_index,
1012 ArenaDeque<PcRelativePatchInfo>* patches);
1013 template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
1014 static void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
1015 ArenaVector<linker::LinkerPatch>* linker_patches);
1016
1017 // Labels for each block that will be compiled.
1018 // We use a deque so that the `vixl::aarch32::Label` objects do not move in memory.
1019 ArenaDeque<vixl::aarch32::Label> block_labels_; // Indexed by block id.
1020 vixl::aarch32::Label frame_entry_label_;
1021
1022 ArenaVector<std::unique_ptr<JumpTableARMVIXL>> jump_tables_;
1023 LocationsBuilderARMVIXL location_builder_;
1024 InstructionCodeGeneratorARMVIXL instruction_visitor_;
1025 ParallelMoveResolverARMVIXL move_resolver_;
1026
1027 ArmVIXLAssembler assembler_;
1028
1029 // PC-relative method patch info for kBootImageLinkTimePcRelative.
1030 ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_;
1031 // PC-relative method patch info for kBssEntry.
1032 ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
1033 // PC-relative type patch info for kBootImageLinkTimePcRelative.
1034 ArenaDeque<PcRelativePatchInfo> boot_image_type_patches_;
1035 // PC-relative type patch info for kAppImageRelRo.
1036 ArenaDeque<PcRelativePatchInfo> app_image_type_patches_;
1037 // PC-relative type patch info for kBssEntry.
1038 ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_;
1039 // PC-relative public type patch info for kBssEntryPublic.
1040 ArenaDeque<PcRelativePatchInfo> public_type_bss_entry_patches_;
1041 // PC-relative package type patch info for kBssEntryPackage.
1042 ArenaDeque<PcRelativePatchInfo> package_type_bss_entry_patches_;
1043 // PC-relative String patch info for kBootImageLinkTimePcRelative.
1044 ArenaDeque<PcRelativePatchInfo> boot_image_string_patches_;
1045 // PC-relative String patch info for kBssEntry.
1046 ArenaDeque<PcRelativePatchInfo> string_bss_entry_patches_;
1047 // PC-relative patch info for IntrinsicObjects for the boot image,
1048 // and for method/type/string patches for kBootImageRelRo otherwise.
1049 ArenaDeque<PcRelativePatchInfo> boot_image_other_patches_;
1050 // Patch info for calls to entrypoint dispatch thunks. Used for slow paths.
1051 ArenaDeque<PatchInfo<vixl::aarch32::Label>> call_entrypoint_patches_;
1052 // Baker read barrier patch info.
1053 ArenaDeque<BakerReadBarrierPatchInfo> baker_read_barrier_patches_;
1054
1055 // Deduplication map for 32-bit literals, used for JIT for boot image addresses.
1056 Uint32ToLiteralMap uint32_literals_;
1057 // Patches for string literals in JIT compiled code.
1058 StringToLiteralMap jit_string_patches_;
1059 // Patches for class literals in JIT compiled code.
1060 TypeToLiteralMap jit_class_patches_;
1061
1062 // Baker read barrier slow paths, mapping custom data (uint32_t) to label.
1063 // Wrap the label to work around vixl::aarch32::Label being non-copyable
1064 // and non-moveable and as such unusable in ArenaSafeMap<>.
1065 struct LabelWrapper {
LabelWrapperLabelWrapper1066 LabelWrapper(const LabelWrapper& src)
1067 : label() {
1068 DCHECK(!src.label.IsReferenced() && !src.label.IsBound());
1069 }
1070 LabelWrapper() = default;
1071 vixl::aarch32::Label label;
1072 };
1073 ArenaSafeMap<uint32_t, LabelWrapper> jit_baker_read_barrier_slow_paths_;
1074
1075 friend class linker::Thumb2RelativePatcherTest;
1076 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARMVIXL);
1077 };
1078
1079 } // namespace arm
1080 } // namespace art
1081
1082 #endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM_VIXL_H_
1083