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