1 // Copyright 2021 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_BASELINE_BASELINE_ASSEMBLER_H_
6 #define V8_BASELINE_BASELINE_ASSEMBLER_H_
7 
8 // TODO(v8:11421): Remove #if once baseline compiler is ported to other
9 // architectures.
10 #include "src/flags/flags.h"
11 #if ENABLE_SPARKPLUG
12 
13 #include "src/codegen/macro-assembler.h"
14 #include "src/objects/tagged-index.h"
15 
16 namespace v8 {
17 namespace internal {
18 namespace baseline {
19 
20 enum class Condition : uint32_t;
21 
22 class BaselineAssembler {
23  public:
24   class ScratchRegisterScope;
25 
BaselineAssembler(MacroAssembler * masm)26   explicit BaselineAssembler(MacroAssembler* masm) : masm_(masm) {}
27   inline static MemOperand RegisterFrameOperand(
28       interpreter::Register interpreter_register);
29   inline MemOperand ContextOperand();
30   inline MemOperand FunctionOperand();
31   inline MemOperand FeedbackVectorOperand();
32 
33   inline void GetCode(Isolate* isolate, CodeDesc* desc);
34   inline int pc_offset() const;
35   inline void CodeEntry() const;
36   inline void ExceptionHandler() const;
37   V8_INLINE void RecordComment(const char* string);
38   inline void Trap();
39   inline void DebugBreak();
40 
41   inline void Bind(Label* label);
42   // Binds the label without marking it as a valid jump target.
43   // This is only useful, when the position is already marked as a valid jump
44   // target (i.e. at the beginning of the bytecode).
45   inline void BindWithoutJumpTarget(Label* label);
46   // Marks the current position as a valid jump target on CFI enabled
47   // architectures.
48   inline void JumpTarget();
49   inline void Jump(Label* target, Label::Distance distance = Label::kFar);
50   inline void JumpIfRoot(Register value, RootIndex index, Label* target,
51                          Label::Distance distance = Label::kFar);
52   inline void JumpIfNotRoot(Register value, RootIndex index, Label* target,
53                             Label ::Distance distance = Label::kFar);
54   inline void JumpIfSmi(Register value, Label* target,
55                         Label::Distance distance = Label::kFar);
56   inline void JumpIfNotSmi(Register value, Label* target,
57                            Label::Distance distance = Label::kFar);
58 
59   inline void TestAndBranch(Register value, int mask, Condition cc,
60                             Label* target,
61                             Label::Distance distance = Label::kFar);
62 
63   inline void JumpIf(Condition cc, Register lhs, const Operand& rhs,
64                      Label* target, Label::Distance distance = Label::kFar);
65   inline void JumpIfObjectType(Condition cc, Register object,
66                                InstanceType instance_type, Register map,
67                                Label* target,
68                                Label::Distance distance = Label::kFar);
69   inline void JumpIfInstanceType(Condition cc, Register map,
70                                  InstanceType instance_type, Label* target,
71                                  Label::Distance distance = Label::kFar);
72   inline void JumpIfPointer(Condition cc, Register value, MemOperand operand,
73                             Label* target,
74                             Label::Distance distance = Label::kFar);
75   inline Condition CheckSmi(Register value);
76   inline void JumpIfSmi(Condition cc, Register value, Smi smi, Label* target,
77                         Label::Distance distance = Label::kFar);
78   inline void JumpIfSmi(Condition cc, Register lhs, Register rhs, Label* target,
79                         Label::Distance distance = Label::kFar);
80   inline void JumpIfTagged(Condition cc, Register value, MemOperand operand,
81                            Label* target,
82                            Label::Distance distance = Label::kFar);
83   inline void JumpIfTagged(Condition cc, MemOperand operand, Register value,
84                            Label* target,
85                            Label::Distance distance = Label::kFar);
86   inline void JumpIfByte(Condition cc, Register value, int32_t byte,
87                          Label* target, Label::Distance distance = Label::kFar);
88 
89   inline void LoadMap(Register output, Register value);
90   inline void LoadRoot(Register output, RootIndex index);
91   inline void LoadNativeContextSlot(Register output, uint32_t index);
92 
93   inline void Move(Register output, Register source);
94   inline void Move(Register output, MemOperand operand);
95   inline void Move(Register output, Smi value);
96   inline void Move(Register output, TaggedIndex value);
97   inline void Move(Register output, interpreter::Register source);
98   inline void Move(interpreter::Register output, Register source);
99   inline void Move(Register output, RootIndex source);
100   inline void Move(MemOperand output, Register source);
101   inline void Move(Register output, ExternalReference reference);
102   inline void Move(Register output, Handle<HeapObject> value);
103   inline void Move(Register output, int32_t immediate);
104   inline void MoveMaybeSmi(Register output, Register source);
105   inline void MoveSmi(Register output, Register source);
106 
107   // Push the given values, in the given order. If the stack needs alignment
108   // (looking at you Arm64), the stack is padded from the front (i.e. before the
109   // first value is pushed).
110   //
111   // This supports pushing a RegisterList as the last value -- the list is
112   // iterated and each interpreter Register is pushed.
113   //
114   // The total number of values pushed is returned. Note that this might be
115   // different from sizeof(T...), specifically if there was a RegisterList.
116   template <typename... T>
117   inline int Push(T... vals);
118 
119   // Like Push(vals...), but pushes in reverse order, to support our reversed
120   // order argument JS calling convention. Doesn't return the number of
121   // arguments pushed though.
122   //
123   // Note that padding is still inserted before the first pushed value (i.e. the
124   // last value).
125   template <typename... T>
126   inline void PushReverse(T... vals);
127 
128   // Pop values off the stack into the given registers.
129   //
130   // Note that this inserts into registers in the given order, i.e. in reverse
131   // order if the registers were pushed. This means that to spill registers,
132   // push and pop have to be in reverse order, e.g.
133   //
134   //     Push(r1, r2, ..., rN);
135   //     ClobberRegisters();
136   //     Pop(rN, ..., r2, r1);
137   //
138   // On stack-alignment architectures, any padding is popped off after the last
139   // register. This the behaviour of Push, which means that the above code still
140   // works even if the number of registers doesn't match stack alignment.
141   template <typename... T>
142   inline void Pop(T... registers);
143 
144   inline void CallBuiltin(Builtin builtin);
145   inline void TailCallBuiltin(Builtin builtin);
146   inline void CallRuntime(Runtime::FunctionId function, int nargs);
147 
148   inline void LoadTaggedPointerField(Register output, Register source,
149                                      int offset);
150   inline void LoadTaggedSignedField(Register output, Register source,
151                                     int offset);
152   inline void LoadTaggedAnyField(Register output, Register source, int offset);
153   inline void LoadByteField(Register output, Register source, int offset);
154   inline void StoreTaggedSignedField(Register target, int offset, Smi value);
155   inline void StoreTaggedFieldWithWriteBarrier(Register target, int offset,
156                                                Register value);
157   inline void StoreTaggedFieldNoWriteBarrier(Register target, int offset,
158                                              Register value);
159   inline void LoadFixedArrayElement(Register output, Register array,
160                                     int32_t index);
161   inline void LoadPrototype(Register prototype, Register object);
162 
163   // Loads the feedback cell from the function, and sets flags on add so that
164   // we can compare afterward.
165   inline void AddToInterruptBudgetAndJumpIfNotExceeded(
166       int32_t weight, Label* skip_interrupt_label);
167   inline void AddToInterruptBudgetAndJumpIfNotExceeded(
168       Register weight, Label* skip_interrupt_label);
169 
170   inline void AddSmi(Register lhs, Smi rhs);
171   inline void SmiUntag(Register value);
172   inline void SmiUntag(Register output, Register value);
173 
174   inline void Switch(Register reg, int case_value_base, Label** labels,
175                      int num_labels);
176 
177   // Register operands.
178   inline void LoadRegister(Register output, interpreter::Register source);
179   inline void StoreRegister(interpreter::Register output, Register value);
180 
181   // Frame values
182   inline void LoadFunction(Register output);
183   inline void LoadContext(Register output);
184   inline void StoreContext(Register context);
185 
186   inline static void EmitReturn(MacroAssembler* masm);
187 
masm()188   MacroAssembler* masm() { return masm_; }
189 
190  private:
191   MacroAssembler* masm_;
192   ScratchRegisterScope* scratch_register_scope_ = nullptr;
193 };
194 
195 class SaveAccumulatorScope final {
196  public:
197   inline explicit SaveAccumulatorScope(BaselineAssembler* assembler);
198 
199   inline ~SaveAccumulatorScope();
200 
201  private:
202   BaselineAssembler* assembler_;
203 };
204 
205 class EnsureAccumulatorPreservedScope final {
206  public:
207   inline explicit EnsureAccumulatorPreservedScope(BaselineAssembler* assembler);
208 
209   inline ~EnsureAccumulatorPreservedScope();
210 
211  private:
212   inline void AssertEqualToAccumulator(Register reg);
213 
214   BaselineAssembler* assembler_;
215 #ifdef V8_CODE_COMMENTS
216   Assembler::CodeComment comment_;
217 #endif
218 };
219 
220 }  // namespace baseline
221 }  // namespace internal
222 }  // namespace v8
223 
224 #endif
225 
226 #endif  // V8_BASELINE_BASELINE_ASSEMBLER_H_
227