Flutter Engine
The Flutter Engine
instructions_arm64.h
Go to the documentation of this file.
1// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4// Classes that describe assembly patterns as used by inline caches.
5
6#ifndef RUNTIME_VM_INSTRUCTIONS_ARM64_H_
7#define RUNTIME_VM_INSTRUCTIONS_ARM64_H_
8
9#ifndef RUNTIME_VM_INSTRUCTIONS_H_
10#error Do not include instructions_arm64.h directly; use instructions.h instead.
11#endif
12
13#include "vm/allocation.h"
14#include "vm/constants.h"
15#include "vm/native_function.h"
16#include "vm/tagged_pointer.h"
17
18#if !defined(DART_PRECOMPILED_RUNTIME)
20#endif // !defined(DART_PRECOMPILED_RUNTIME)
21
22namespace dart {
23
24class Code;
25class ICData;
26class Object;
27class ObjectPool;
28
29class InstructionPattern : public AllStatic {
30 public:
31 // Decodes a load sequence ending at 'end' (the last instruction of the
32 // load sequence is the instruction before the one at end). Returns the
33 // address of the first instruction in the sequence. Returns the register
34 // being loaded and the loaded immediate value in the output parameters
35 // 'reg' and 'value' respectively.
37 Register* reg,
38 intptr_t* value);
39
40 // Decodes a load sequence ending at 'end' (the last instruction of the
41 // load sequence is the instruction before the one at end). Returns the
42 // address of the first instruction in the sequence. Returns the register
43 // being loaded and the index in the pool being read from in the output
44 // parameters 'reg' and 'index' respectively.
45 // IMPORTANT: When generating code loading values from pool on ARM64 use
46 // LoadWordFromPool macro instruction instead of emitting direct load.
47 // The macro instruction takes care of pool offsets that can't be
48 // encoded as immediates.
50 Register* reg,
51 intptr_t* index);
52
53 // Decodes a load sequence ending at 'end' (the last instruction of the
54 // load sequence is the instruction before the one at end). Returns the
55 // address of the first instruction in the sequence. Returns the registers
56 // being loaded and the index in the pool being read from in the output
57 // parameters 'reg1', 'reg2' and 'index' respectively.
58 // IMPORTANT: When generating code loading values from pool on ARM64 use
59 // LoadDoubleWordFromPool macro instruction instead of emitting direct load.
60 // The macro instruction takes care of pool offsets that can't be
61 // encoded as immediates.
63 Register* reg1,
64 Register* reg2,
65 intptr_t* index);
66
67 // Encodes a load sequence ending at 'end'. Encodes a fixed length two
68 // instruction load from the pool pointer in PP using the destination
69 // register reg as a temporary for the base address.
70 static void EncodeLoadWordFromPoolFixed(uword end, int32_t offset);
71};
72
73class CallPattern : public ValueObject {
74 public:
76
77 CodePtr TargetCode() const;
78 void SetTargetCode(const Code& target) const;
79
80 private:
81 const ObjectPool& object_pool_;
82
83 intptr_t target_code_pool_index_;
84
85 DISALLOW_COPY_AND_ASSIGN(CallPattern);
86};
87
88class ICCallPattern : public ValueObject {
89 public:
90 ICCallPattern(uword pc, const Code& caller_code);
91
92 ObjectPtr Data() const;
93 void SetData(const Object& data) const;
94
95 CodePtr TargetCode() const;
96 void SetTargetCode(const Code& target) const;
97
98 private:
99 const ObjectPool& object_pool_;
100
101 intptr_t target_pool_index_;
102 intptr_t data_pool_index_;
103
104 DISALLOW_COPY_AND_ASSIGN(ICCallPattern);
105};
106
107class NativeCallPattern : public ValueObject {
108 public:
110
111 CodePtr target() const;
112 void set_target(const Code& target) const;
113
116
117 private:
118 const ObjectPool& object_pool_;
119
120 uword end_;
121 intptr_t native_function_pool_index_;
122 intptr_t target_code_pool_index_;
123
124 DISALLOW_COPY_AND_ASSIGN(NativeCallPattern);
125};
126
127// Instance call that can switch between a direct monomorphic call, an IC call,
128// and a megamorphic call.
129// load guarded cid load ICData load MegamorphicCache
130// load monomorphic target <-> load ICLookup stub -> load MMLookup stub
131// call target.entry call stub.entry call stub.entry
133 public:
134 explicit SwitchableCallPatternBase(const ObjectPool& object_pool);
135
137 void SetData(const Object& data) const;
138
139 protected:
141 intptr_t data_pool_index_;
142 intptr_t target_pool_index_;
143
144 private:
145 DISALLOW_COPY_AND_ASSIGN(SwitchableCallPatternBase);
146};
147
148// See [SwitchableCallBase] for a switchable calls in general.
149//
150// The target slot is always a [Code] object: Either the code of the
151// monomorphic function or a stub code.
153 public:
155
157 void SetTarget(const Code& target) const;
158
159 private:
160 DISALLOW_COPY_AND_ASSIGN(SwitchableCallPattern);
161};
162
163// See [SwitchableCallBase] for a switchable calls in general.
164//
165// The target slot is always a direct entrypoint address: Either the entry point
166// of the monomorphic function or a stub entry point.
168 public:
170
172 void SetTarget(const Code& target) const;
173
174 private:
175 DISALLOW_COPY_AND_ASSIGN(BareSwitchableCallPattern);
176};
177
178class ReturnPattern : public ValueObject {
179 public:
180 explicit ReturnPattern(uword pc);
181
182 // bx_lr = 1.
183 static constexpr int kLengthInBytes = 1 * Instr::kInstrSize;
184
186
187 bool IsValid() const;
188
189 private:
190 const uword pc_;
191};
192
194 public:
195 // 26 bit signed integer which will get multiplied by 4.
196 static constexpr intptr_t kLowerCallingRange = -(1 << 27);
197 static constexpr intptr_t kUpperCallingRange = (1 << 27) - Instr::kInstrSize;
198
199 explicit PcRelativePatternBase(uword pc) : pc_(pc) {}
200
201 static constexpr int kLengthInBytes = 1 * Instr::kInstrSize;
202
203 int32_t distance() {
204#if !defined(DART_PRECOMPILED_RUNTIME)
206 *reinterpret_cast<int32_t*>(pc_));
207#else
208 UNREACHABLE();
209 return 0;
210#endif
211 }
212
213 void set_distance(int32_t distance) {
214#if !defined(DART_PRECOMPILED_RUNTIME)
215 int32_t* word = reinterpret_cast<int32_t*>(pc_);
217#else
218 UNREACHABLE();
219#endif
220 }
221
222 bool IsValid() const;
223
224 protected:
226};
227
229 public:
231
232 bool IsValid() const;
233};
234
236 public:
238
239 bool IsValid() const;
240};
241
242// Instruction pattern for a tail call to a signed 32-bit PC-relative offset
243//
244// The AOT compiler can emit PC-relative calls. If the destination of such a
245// call is not in range for the "bl <offset>" instruction, the AOT compiler will
246// emit a trampoline which is in range. That trampoline will then tail-call to
247// the final destination (also via PC-relative offset, but it supports a full
248// signed 32-bit offset).
249//
250// The pattern of the trampoline looks like:
251//
252// adr TMP, #lower16 (same as TMP = PC + #lower16)
253// movz TMP2, #higher16 lsl 16
254// add TMP, TMP, TMP2, SXTW
255// br TMP
256//
258 public:
260 : pattern_start_(pattern_start) {
261 USE(pattern_start_);
262 }
263
264 static constexpr int kLengthInBytes = 4 * Instr::kInstrSize;
265
267
268 int32_t distance();
269 void set_distance(int32_t distance);
270 bool IsValid() const;
271
272 private:
273 // This offset must be applied to account for the fact that
274 // a) the actual "branch" is only in the 3rd instruction
275 // b) when reading the PC it reports current instruction + 8
276 static constexpr intptr_t kDistanceOffset = -5 * Instr::kInstrSize;
277
278 // adr TMP, #lower16 (same as TMP = PC + #lower16)
279 static constexpr uint32_t kAdrEncoding = (1 << 28) | (TMP << kRdShift);
280
281 // movz TMP2, #higher16 lsl 16
282 static constexpr uint32_t kMovzEncoding = MOVZ | (1 << kHWShift) | TMP2;
283
284 // add TMP, TMP, TMP2, SXTW
285 static constexpr uint32_t kAddTmpTmp2 = 0x8b31c210;
286
287 // br TMP
288 static constexpr uint32_t kJumpEncoding = BR | (TMP << kRnShift);
289
290 uword pattern_start_;
291};
292
293} // namespace dart
294
295#endif // RUNTIME_VM_INSTRUCTIONS_ARM64_H_
#define UNREACHABLE()
Definition: assert.h:248
void SetTarget(const Code &target) const
CallPattern(uword pc, const Code &code)
CodePtr TargetCode() const
void SetTargetCode(const Code &target) const
void SetData(const Object &data) const
ObjectPtr Data() const
CodePtr TargetCode() const
ICCallPattern(uword pc, const Code &caller_code)
void SetTargetCode(const Code &target) const
static uword DecodeLoadWordFromPool(uword end, Register *reg, intptr_t *index)
static uword DecodeLoadDoubleWordFromPool(uword end, Register *reg1, Register *reg2, intptr_t *index)
static void EncodeLoadWordFromPoolFixed(uword end, int32_t offset)
static uword DecodeLoadWordImmediate(uword end, Register *reg, intptr_t *value)
NativeCallPattern(uword pc, const Code &code)
NativeFunction native_function() const
void set_native_function(NativeFunction target) const
void set_target(const Code &target) const
CodePtr target() const
static constexpr intptr_t kUpperCallingRange
static constexpr int kLengthInBytes
static constexpr intptr_t kLowerCallingRange
void set_distance(int32_t distance)
void set_distance(int32_t distance)
PcRelativeTrampolineJumpPattern(uword pattern_start)
bool IsValid() const
static constexpr int kLengthInBytes
int pattern_length_in_bytes() const
ReturnPattern(uword pc)
void SetData(const Object &data) const
SwitchableCallPatternBase(const ObjectPool &object_pool)
void SetTarget(const Code &target) const
SwitchableCallPattern(uword pc, const Code &code)
static int64_t DecodeImm26BranchOffset(int32_t instr)
static int32_t EncodeImm26BranchOffset(int64_t imm, int32_t instr)
uint8_t value
uint32_t * target
Definition: dart_vm.cc:33
uintptr_t uword
Definition: globals.h:501
intptr_t word
Definition: globals.h:500
const Register TMP2
static void USE(T &&)
Definition: globals.h:618
const Register TMP
@ kRdShift
@ kRnShift
static int8_t data[kExtLength]
void(* NativeFunction)(NativeArguments *arguments)
SeparatedVector2 offset