summaryrefslogtreecommitdiff
path: root/deps/v8/src/baseline/baseline-assembler.h
blob: 3540cb65b54f0e8d11a339aba55cd16ab369045a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_BASELINE_BASELINE_ASSEMBLER_H_
#define V8_BASELINE_BASELINE_ASSEMBLER_H_

// TODO(v8:11421): Remove #if once baseline compiler is ported to other
// architectures.
#include "src/flags/flags.h"
#if ENABLE_SPARKPLUG

#include "src/codegen/macro-assembler.h"
#include "src/objects/tagged-index.h"

namespace v8 {
namespace internal {
namespace baseline {

enum class Condition : uint32_t;

class BaselineAssembler {
 public:
  class ScratchRegisterScope;

  explicit BaselineAssembler(MacroAssembler* masm) : masm_(masm) {}
  inline static MemOperand RegisterFrameOperand(
      interpreter::Register interpreter_register);
  inline void RegisterFrameAddress(interpreter::Register interpreter_register,
                                   Register rscratch);
  inline MemOperand ContextOperand();
  inline MemOperand FunctionOperand();
  inline MemOperand FeedbackVectorOperand();

  inline void GetCode(Isolate* isolate, CodeDesc* desc);
  inline int pc_offset() const;
  inline void CodeEntry() const;
  inline void ExceptionHandler() const;
  V8_INLINE void RecordComment(const char* string);
  inline void Trap();
  inline void DebugBreak();

  template <typename Field>
  inline void DecodeField(Register reg);

  inline void Bind(Label* label);
  // Marks the current position as a valid jump target on CFI enabled
  // architectures.
  inline void JumpTarget();
  inline void Jump(Label* target, Label::Distance distance = Label::kFar);
  inline void JumpIfRoot(Register value, RootIndex index, Label* target,
                         Label::Distance distance = Label::kFar);
  inline void JumpIfNotRoot(Register value, RootIndex index, Label* target,
                            Label ::Distance distance = Label::kFar);
  inline void JumpIfSmi(Register value, Label* target,
                        Label::Distance distance = Label::kFar);
  inline void JumpIfNotSmi(Register value, Label* target,
                           Label::Distance distance = Label::kFar);

  inline void TestAndBranch(Register value, int mask, Condition cc,
                            Label* target,
                            Label::Distance distance = Label::kFar);

  inline void JumpIf(Condition cc, Register lhs, const Operand& rhs,
                     Label* target, Label::Distance distance = Label::kFar);
  inline void JumpIfObjectType(Condition cc, Register object,
                               InstanceType instance_type, Register map,
                               Label* target,
                               Label::Distance distance = Label::kFar);
  inline void JumpIfInstanceType(Condition cc, Register map,
                                 InstanceType instance_type, Label* target,
                                 Label::Distance distance = Label::kFar);
  inline void JumpIfPointer(Condition cc, Register value, MemOperand operand,
                            Label* target,
                            Label::Distance distance = Label::kFar);
  inline Condition CheckSmi(Register value);
  inline void JumpIfSmi(Condition cc, Register value, Smi smi, Label* target,
                        Label::Distance distance = Label::kFar);
  inline void JumpIfSmi(Condition cc, Register lhs, Register rhs, Label* target,
                        Label::Distance distance = Label::kFar);
  inline void JumpIfImmediate(Condition cc, Register left, int right,
                              Label* target,
                              Label::Distance distance = Label::kFar);
  inline void JumpIfTagged(Condition cc, Register value, MemOperand operand,
                           Label* target,
                           Label::Distance distance = Label::kFar);
  inline void JumpIfTagged(Condition cc, MemOperand operand, Register value,
                           Label* target,
                           Label::Distance distance = Label::kFar);
  inline void JumpIfByte(Condition cc, Register value, int32_t byte,
                         Label* target, Label::Distance distance = Label::kFar);

  inline void LoadMap(Register output, Register value);
  inline void LoadRoot(Register output, RootIndex index);
  inline void LoadNativeContextSlot(Register output, uint32_t index);

  inline void Move(Register output, Register source);
  inline void Move(Register output, MemOperand operand);
  inline void Move(Register output, Smi value);
  inline void Move(Register output, TaggedIndex value);
  inline void Move(Register output, interpreter::Register source);
  inline void Move(interpreter::Register output, Register source);
  inline void Move(Register output, RootIndex source);
  inline void Move(MemOperand output, Register source);
  inline void Move(Register output, ExternalReference reference);
  inline void Move(Register output, Handle<HeapObject> value);
  inline void Move(Register output, int32_t immediate);
  inline void MoveMaybeSmi(Register output, Register source);
  inline void MoveSmi(Register output, Register source);

  // Push the given values, in the given order. If the stack needs alignment
  // (looking at you Arm64), the stack is padded from the front (i.e. before the
  // first value is pushed).
  //
  // This supports pushing a RegisterList as the last value -- the list is
  // iterated and each interpreter Register is pushed.
  //
  // The total number of values pushed is returned. Note that this might be
  // different from sizeof(T...), specifically if there was a RegisterList.
  template <typename... T>
  inline int Push(T... vals);

  // Like Push(vals...), but pushes in reverse order, to support our reversed
  // order argument JS calling convention. Doesn't return the number of
  // arguments pushed though.
  //
  // Note that padding is still inserted before the first pushed value (i.e. the
  // last value).
  template <typename... T>
  inline void PushReverse(T... vals);

  // Pop values off the stack into the given registers.
  //
  // Note that this inserts into registers in the given order, i.e. in reverse
  // order if the registers were pushed. This means that to spill registers,
  // push and pop have to be in reverse order, e.g.
  //
  //     Push(r1, r2, ..., rN);
  //     ClobberRegisters();
  //     Pop(rN, ..., r2, r1);
  //
  // On stack-alignment architectures, any padding is popped off after the last
  // register. This the behaviour of Push, which means that the above code still
  // works even if the number of registers doesn't match stack alignment.
  template <typename... T>
  inline void Pop(T... registers);

  inline void CallBuiltin(Builtin builtin);
  inline void TailCallBuiltin(Builtin builtin);
  inline void CallRuntime(Runtime::FunctionId function, int nargs);

  inline void LoadTaggedPointerField(Register output, Register source,
                                     int offset);
  inline void LoadTaggedSignedField(Register output, Register source,
                                    int offset);
  inline void LoadTaggedSignedFieldAndUntag(Register output, Register source,
                                            int offset);
  inline void LoadTaggedAnyField(Register output, Register source, int offset);
  inline void LoadWord16FieldZeroExtend(Register output, Register source,
                                        int offset);
  inline void LoadWord8Field(Register output, Register source, int offset);
  inline void StoreTaggedSignedField(Register target, int offset, Smi value);
  inline void StoreTaggedFieldWithWriteBarrier(Register target, int offset,
                                               Register value);
  inline void StoreTaggedFieldNoWriteBarrier(Register target, int offset,
                                             Register value);
  inline void LoadFixedArrayElement(Register output, Register array,
                                    int32_t index);
  inline void LoadPrototype(Register prototype, Register object);

// Loads compressed pointer or loads from compressed pointer. This is because
// X64 supports complex addressing mode, pointer decompression can be done by
// [%compressed_base + %r1 + K].
#if V8_TARGET_ARCH_X64
  inline void LoadTaggedPointerField(TaggedRegister output, Register source,
                                     int offset);
  inline void LoadTaggedPointerField(TaggedRegister output,
                                     TaggedRegister source, int offset);
  inline void LoadTaggedPointerField(Register output, TaggedRegister source,
                                     int offset);
  inline void LoadTaggedAnyField(Register output, TaggedRegister source,
                                 int offset);
  inline void LoadTaggedAnyField(TaggedRegister output, TaggedRegister source,
                                 int offset);
  inline void LoadFixedArrayElement(Register output, TaggedRegister array,
                                    int32_t index);
  inline void LoadFixedArrayElement(TaggedRegister output, TaggedRegister array,
                                    int32_t index);
#endif

  // Falls through and sets scratch_and_result to 0 on failure, jumps to
  // on_result on success.
  inline void TryLoadOptimizedOsrCode(Register scratch_and_result,
                                      Register feedback_vector,
                                      FeedbackSlot slot, Label* on_result,
                                      Label::Distance distance);

  // Loads the feedback cell from the function, and sets flags on add so that
  // we can compare afterward.
  inline void AddToInterruptBudgetAndJumpIfNotExceeded(
      int32_t weight, Label* skip_interrupt_label);
  inline void AddToInterruptBudgetAndJumpIfNotExceeded(
      Register weight, Label* skip_interrupt_label);

  inline void LdaContextSlot(Register context, uint32_t index, uint32_t depth);
  inline void StaContextSlot(Register context, Register value, uint32_t index,
                             uint32_t depth);
  inline void LdaModuleVariable(Register context, int cell_index,
                                uint32_t depth);
  inline void StaModuleVariable(Register context, Register value,
                                int cell_index, uint32_t depth);

  inline void AddSmi(Register lhs, Smi rhs);
  inline void SmiUntag(Register value);
  inline void SmiUntag(Register output, Register value);

  inline void Word32And(Register output, Register lhs, int rhs);

  inline void Switch(Register reg, int case_value_base, Label** labels,
                     int num_labels);

  // Register operands.
  inline void LoadRegister(Register output, interpreter::Register source);
  inline void StoreRegister(interpreter::Register output, Register value);

  // Frame values
  inline void LoadFunction(Register output);
  inline void LoadContext(Register output);
  inline void StoreContext(Register context);

  inline static void EmitReturn(MacroAssembler* masm);

  MacroAssembler* masm() { return masm_; }

 private:
  MacroAssembler* masm_;
  ScratchRegisterScope* scratch_register_scope_ = nullptr;
};

class SaveAccumulatorScope final {
 public:
  inline explicit SaveAccumulatorScope(BaselineAssembler* assembler);

  inline ~SaveAccumulatorScope();

 private:
  BaselineAssembler* assembler_;
};

class EnsureAccumulatorPreservedScope final {
 public:
  inline explicit EnsureAccumulatorPreservedScope(BaselineAssembler* assembler);

  inline ~EnsureAccumulatorPreservedScope();

 private:
  inline void AssertEqualToAccumulator(Register reg);

  BaselineAssembler* assembler_;
#ifdef V8_CODE_COMMENTS
  Assembler::CodeComment comment_;
#endif
};

}  // namespace baseline
}  // namespace internal
}  // namespace v8

#endif

#endif  // V8_BASELINE_BASELINE_ASSEMBLER_H_