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_COMPILER_H_
6#define V8_BASELINE_BASELINE_COMPILER_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/base/logging.h"
14#include "src/base/threaded-list.h"
15#include "src/base/vlq.h"
16#include "src/baseline/baseline-assembler.h"
17#include "src/execution/local-isolate.h"
18#include "src/handles/handles.h"
19#include "src/interpreter/bytecode-array-iterator.h"
20#include "src/interpreter/bytecode-register.h"
21#include "src/interpreter/interpreter-intrinsics.h"
22#include "src/logging/counters.h"
23#include "src/objects/map.h"
24#include "src/objects/tagged-index.h"
25
26namespace v8 {
27namespace internal {
28
29class BytecodeArray;
30
31namespace baseline {
32
33class BytecodeOffsetTableBuilder {
34 public:
35  void AddPosition(size_t pc_offset) {
36    size_t pc_diff = pc_offset - previous_pc_;
37    DCHECK_GE(pc_diff, 0);
38    DCHECK_LE(pc_diff, std::numeric_limits<uint32_t>::max());
39    base::VLQEncodeUnsigned(&bytes_, static_cast<uint32_t>(pc_diff));
40    previous_pc_ = pc_offset;
41  }
42
43  template <typename IsolateT>
44  Handle<ByteArray> ToBytecodeOffsetTable(IsolateT* isolate);
45
46  void Reserve(size_t size) { bytes_.reserve(size); }
47
48 private:
49  size_t previous_pc_ = 0;
50  std::vector<byte> bytes_;
51};
52
53class BaselineCompiler {
54 public:
55  explicit BaselineCompiler(LocalIsolate* local_isolate,
56                            Handle<SharedFunctionInfo> shared_function_info,
57                            Handle<BytecodeArray> bytecode);
58
59  void GenerateCode();
60  MaybeHandle<Code> Build(LocalIsolate* local_isolate);
61  static int EstimateInstructionSize(BytecodeArray bytecode);
62
63 private:
64  void Prologue();
65  void PrologueFillFrame();
66  void PrologueHandleOptimizationState(Register feedback_vector);
67
68  void PreVisitSingleBytecode();
69  void VisitSingleBytecode();
70
71  void VerifyFrame();
72  void VerifyFrameSize();
73
74  // Register operands.
75  interpreter::Register RegisterOperand(int operand_index);
76  void LoadRegister(Register output, int operand_index);
77  void StoreRegister(int operand_index, Register value);
78  void StoreRegisterPair(int operand_index, Register val0, Register val1);
79
80  // Constant pool operands.
81  template <typename Type>
82  Handle<Type> Constant(int operand_index);
83  Smi ConstantSmi(int operand_index);
84  template <typename Type>
85  void LoadConstant(Register output, int operand_index);
86
87  // Immediate value operands.
88  uint32_t Uint(int operand_index);
89  int32_t Int(int operand_index);
90  uint32_t Index(int operand_index);
91  uint32_t Flag(int operand_index);
92  uint32_t RegisterCount(int operand_index);
93  TaggedIndex IndexAsTagged(int operand_index);
94  TaggedIndex UintAsTagged(int operand_index);
95  Smi IndexAsSmi(int operand_index);
96  Smi IntAsSmi(int operand_index);
97  Smi FlagAsSmi(int operand_index);
98
99  // Jump helpers.
100  Label* NewLabel();
101  Label* BuildForwardJumpLabel();
102  void UpdateInterruptBudgetAndJumpToLabel(int weight, Label* label,
103                                           Label* skip_interrupt_label);
104  void UpdateInterruptBudgetAndDoInterpreterJump();
105  void UpdateInterruptBudgetAndDoInterpreterJumpIfRoot(RootIndex root);
106  void UpdateInterruptBudgetAndDoInterpreterJumpIfNotRoot(RootIndex root);
107
108  // Feedback vector.
109  MemOperand FeedbackVector();
110  void LoadFeedbackVector(Register output);
111  void LoadClosureFeedbackArray(Register output);
112
113  // Position mapping.
114  void AddPosition();
115
116  // Misc. helpers.
117
118  void UpdateMaxCallArgs(int max_call_args) {
119    max_call_args_ = std::max(max_call_args_, max_call_args);
120  }
121
122  // Select the root boolean constant based on the jump in the given
123  // `jump_func` -- the function should jump to the given label if we want to
124  // select "true", otherwise it should fall through.
125  void SelectBooleanConstant(
126      Register output, std::function<void(Label*, Label::Distance)> jump_func);
127
128  // Jumps based on calling ToBoolean on kInterpreterAccumulatorRegister.
129  void JumpIfToBoolean(bool do_jump_if_true, Label* label,
130                       Label::Distance distance = Label::kFar);
131
132  // Call helpers.
133  template <Builtin kBuiltin, typename... Args>
134  void CallBuiltin(Args... args);
135  template <typename... Args>
136  void CallRuntime(Runtime::FunctionId function, Args... args);
137
138  template <Builtin kBuiltin, typename... Args>
139  void TailCallBuiltin(Args... args);
140
141  template <ConvertReceiverMode kMode, typename... Args>
142  void BuildCall(uint32_t slot, uint32_t arg_count, Args... args);
143
144#ifdef V8_TRACE_UNOPTIMIZED
145  void TraceBytecode(Runtime::FunctionId function_id);
146#endif
147
148  // Single bytecode visitors.
149#define DECLARE_VISITOR(name, ...) void Visit##name();
150  BYTECODE_LIST(DECLARE_VISITOR)
151#undef DECLARE_VISITOR
152
153  // Intrinsic call visitors.
154#define DECLARE_VISITOR(name, ...) \
155  void VisitIntrinsic##name(interpreter::RegisterList args);
156  INTRINSICS_LIST(DECLARE_VISITOR)
157#undef DECLARE_VISITOR
158
159  const interpreter::BytecodeArrayIterator& iterator() { return iterator_; }
160
161  LocalIsolate* local_isolate_;
162  RuntimeCallStats* stats_;
163  Handle<SharedFunctionInfo> shared_function_info_;
164  Handle<HeapObject> interpreter_data_;
165  Handle<BytecodeArray> bytecode_;
166  MacroAssembler masm_;
167  BaselineAssembler basm_;
168  interpreter::BytecodeArrayIterator iterator_;
169  BytecodeOffsetTableBuilder bytecode_offset_table_builder_;
170  Zone zone_;
171
172  int max_call_args_ = 0;
173
174  struct ThreadedLabel {
175    Label label;
176    ThreadedLabel* ptr;
177    ThreadedLabel** next() { return &ptr; }
178  };
179
180  struct BaselineLabels {
181    base::ThreadedList<ThreadedLabel> linked;
182    Label unlinked;
183  };
184
185  BaselineLabels* EnsureLabels(int i) {
186    if (labels_[i] == nullptr) {
187      labels_[i] = zone_.New<BaselineLabels>();
188    }
189    return labels_[i];
190  }
191
192  BaselineLabels** labels_;
193};
194
195}  // namespace baseline
196}  // namespace internal
197}  // namespace v8
198
199#endif  // ENABLE_SPARKPLUG
200
201#endif  // V8_BASELINE_BASELINE_COMPILER_H_
202