summaryrefslogtreecommitdiff
path: root/chromium/v8/src/baseline/baseline-assembler.h
blob: 38874d556f0f73f3218287f471a7570ef602c160 (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
// 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.
#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_ARM64 || \
    V8_TARGET_ARCH_ARM

#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 MemOperand ContextOperand();
  inline MemOperand FunctionOperand();
  inline MemOperand FeedbackVectorOperand();

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

  inline void Bind(Label* label);
  // Binds the label without marking it as a valid jump target.
  // This is only useful, when the position is already marked as a valid jump
  // target (i.e. at the beginning of the bytecode).
  inline void BindWithoutJumpTarget(Label* label);
  // Marks the current position as a valid jump target on CFI enabled
  // architectures.
  inline void JumpTarget();
  inline void JumpIf(Condition cc, Label* target,
                     Label::Distance distance = Label::kFar);
  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 Test(Register value, int mask);

  inline void CmpObjectType(Register object, InstanceType instance_type,
                            Register map);
  inline void CmpInstanceType(Register map, InstanceType instance_type);
  inline void Cmp(Register value, Smi smi);
  inline void ComparePointer(Register value, MemOperand operand);
  inline Condition CheckSmi(Register value);
  inline void SmiCompare(Register lhs, Register rhs);
  inline void CompareTagged(Register value, MemOperand operand);
  inline void CompareTagged(MemOperand operand, Register value);
  inline void CompareByte(Register value, int32_t byte);

  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(Builtins::Name builtin);
  inline void TailCallBuiltin(Builtins::Name 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 LoadTaggedAnyField(Register output, Register source, int offset);
  inline void LoadByteField(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 the feedback cell from the function, and sets flags on add so that
  // we can compare afterward.
  inline void AddToInterruptBudget(int32_t weight);
  inline void AddToInterruptBudget(Register weight);

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

  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_;
};

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

#endif

#endif  // V8_BASELINE_BASELINE_ASSEMBLER_H_