1 // Copyright 2022 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 #include "src/maglev/maglev-compiler.h"
6
7 #include <iomanip>
8 #include <ostream>
9 #include <type_traits>
10
11 #include "src/base/iterator.h"
12 #include "src/base/logging.h"
13 #include "src/base/threaded-list.h"
14 #include "src/codegen/interface-descriptors-inl.h"
15 #include "src/codegen/machine-type.h"
16 #include "src/codegen/macro-assembler.h"
17 #include "src/codegen/register.h"
18 #include "src/codegen/reglist.h"
19 #include "src/common/globals.h"
20 #include "src/compiler/backend/instruction.h"
21 #include "src/compiler/bytecode-liveness-map.h"
22 #include "src/compiler/compilation-dependencies.h"
23 #include "src/compiler/heap-refs.h"
24 #include "src/compiler/js-heap-broker.h"
25 #include "src/execution/frames.h"
26 #include "src/ic/handler-configuration.h"
27 #include "src/maglev/maglev-basic-block.h"
28 #include "src/maglev/maglev-code-generator.h"
29 #include "src/maglev/maglev-compilation-unit.h"
30 #include "src/maglev/maglev-graph-builder.h"
31 #include "src/maglev/maglev-graph-labeller.h"
32 #include "src/maglev/maglev-graph-printer.h"
33 #include "src/maglev/maglev-graph-processor.h"
34 #include "src/maglev/maglev-graph-verifier.h"
35 #include "src/maglev/maglev-graph.h"
36 #include "src/maglev/maglev-interpreter-frame-state.h"
37 #include "src/maglev/maglev-ir.h"
38 #include "src/maglev/maglev-regalloc.h"
39 #include "src/maglev/maglev-vreg-allocator.h"
40 #include "src/objects/code-inl.h"
41 #include "src/objects/js-function.h"
42 #include "src/zone/zone.h"
43
44 namespace v8 {
45 namespace internal {
46 namespace maglev {
47
48 class NumberingProcessor {
49 public:
PreProcessGraph(MaglevCompilationUnit *,Graph * graph)50 void PreProcessGraph(MaglevCompilationUnit*, Graph* graph) { node_id_ = 1; }
PostProcessGraph(MaglevCompilationUnit *,Graph * graph)51 void PostProcessGraph(MaglevCompilationUnit*, Graph* graph) {}
PreProcessBasicBlock(MaglevCompilationUnit *,BasicBlock * block)52 void PreProcessBasicBlock(MaglevCompilationUnit*, BasicBlock* block) {}
53
Process(NodeBase * node,const ProcessingState & state)54 void Process(NodeBase* node, const ProcessingState& state) {
55 node->set_id(node_id_++);
56 }
57
58 private:
59 uint32_t node_id_;
60 };
61
62 class UseMarkingProcessor {
63 public:
PreProcessGraph(MaglevCompilationUnit *,Graph * graph)64 void PreProcessGraph(MaglevCompilationUnit*, Graph* graph) {}
PostProcessGraph(MaglevCompilationUnit *,Graph * graph)65 void PostProcessGraph(MaglevCompilationUnit*, Graph* graph) {}
PreProcessBasicBlock(MaglevCompilationUnit *,BasicBlock * block)66 void PreProcessBasicBlock(MaglevCompilationUnit*, BasicBlock* block) {}
67
68 template <typename NodeT>
Process(NodeT * node,const ProcessingState & state)69 void Process(NodeT* node, const ProcessingState& state) {
70 if constexpr (NodeT::kProperties.can_eager_deopt()) {
71 MarkCheckpointNodes(node, node->eager_deopt_info(), state);
72 }
73 for (Input& input : *node) {
74 input.node()->mark_use(node->id(), &input);
75 }
76 if constexpr (NodeT::kProperties.can_lazy_deopt()) {
77 MarkCheckpointNodes(node, node->lazy_deopt_info(), state);
78 }
79 }
80
Process(Phi * node,const ProcessingState & state)81 void Process(Phi* node, const ProcessingState& state) {
82 // Don't mark Phi uses when visiting the node, because of loop phis.
83 // Instead, they'll be visited while processing Jump/JumpLoop.
84 }
85
86 // Specialize the two unconditional jumps to extend their Phis' inputs' live
87 // ranges.
88
Process(JumpLoop * node,const ProcessingState & state)89 void Process(JumpLoop* node, const ProcessingState& state) {
90 int i = state.block()->predecessor_id();
91 BasicBlock* target = node->target();
92 if (!target->has_phi()) return;
93 uint32_t use = node->id();
94 for (Phi* phi : *target->phis()) {
95 ValueNode* input = phi->input(i).node();
96 input->mark_use(use, &phi->input(i));
97 }
98 }
Process(Jump * node,const ProcessingState & state)99 void Process(Jump* node, const ProcessingState& state) {
100 int i = state.block()->predecessor_id();
101 BasicBlock* target = node->target();
102 if (!target->has_phi()) return;
103 uint32_t use = node->id();
104 for (Phi* phi : *target->phis()) {
105 ValueNode* input = phi->input(i).node();
106 input->mark_use(use, &phi->input(i));
107 }
108 }
109
110 private:
MarkCheckpointNodes(NodeBase * node,const EagerDeoptInfo * deopt_info,const ProcessingState & state)111 void MarkCheckpointNodes(NodeBase* node, const EagerDeoptInfo* deopt_info,
112 const ProcessingState& state) {
113 const CompactInterpreterFrameState* register_frame =
114 deopt_info->state.register_frame;
115 int use_id = node->id();
116 int index = 0;
117
118 register_frame->ForEachValue(
119 *state.compilation_unit(),
120 [&](ValueNode* node, interpreter::Register reg) {
121 node->mark_use(use_id, &deopt_info->input_locations[index++]);
122 });
123 }
MarkCheckpointNodes(NodeBase * node,const LazyDeoptInfo * deopt_info,const ProcessingState & state)124 void MarkCheckpointNodes(NodeBase* node, const LazyDeoptInfo* deopt_info,
125 const ProcessingState& state) {
126 const CompactInterpreterFrameState* register_frame =
127 deopt_info->state.register_frame;
128 int use_id = node->id();
129 int index = 0;
130
131 register_frame->ForEachValue(
132 *state.compilation_unit(),
133 [&](ValueNode* node, interpreter::Register reg) {
134 // Skip over the result location.
135 if (reg == deopt_info->result_location) return;
136 node->mark_use(use_id, &deopt_info->input_locations[index++]);
137 });
138 }
139 };
140
141 // static
Compile(LocalIsolate * local_isolate,MaglevCompilationUnit * toplevel_compilation_unit)142 void MaglevCompiler::Compile(LocalIsolate* local_isolate,
143 MaglevCompilationUnit* toplevel_compilation_unit) {
144 MaglevCompiler compiler(local_isolate, toplevel_compilation_unit);
145 compiler.Compile();
146 }
147
Compile()148 void MaglevCompiler::Compile() {
149 compiler::UnparkedScopeIfNeeded unparked_scope(broker());
150
151 // Build graph.
152 if (FLAG_print_maglev_code || FLAG_code_comments || FLAG_print_maglev_graph ||
153 FLAG_trace_maglev_regalloc) {
154 toplevel_compilation_unit_->info()->set_graph_labeller(
155 new MaglevGraphLabeller());
156 }
157
158 // TODO(v8:7700): Support exceptions in maglev. We currently bail if exception
159 // handler table is non-empty.
160 if (toplevel_compilation_unit_->bytecode().handler_table_size() > 0) {
161 return;
162 }
163
164 MaglevGraphBuilder graph_builder(local_isolate(), toplevel_compilation_unit_);
165
166 graph_builder.Build();
167
168 // TODO(v8:7700): Clean up after all bytecodes are supported.
169 if (graph_builder.found_unsupported_bytecode()) {
170 return;
171 }
172
173 if (FLAG_print_maglev_graph) {
174 std::cout << "After graph buiding" << std::endl;
175 PrintGraph(std::cout, toplevel_compilation_unit_, graph_builder.graph());
176 }
177
178 #ifdef DEBUG
179 {
180 GraphProcessor<MaglevGraphVerifier> verifier(toplevel_compilation_unit_);
181 verifier.ProcessGraph(graph_builder.graph());
182 }
183 #endif
184
185 {
186 GraphMultiProcessor<NumberingProcessor, UseMarkingProcessor,
187 MaglevVregAllocator>
188 processor(toplevel_compilation_unit_);
189 processor.ProcessGraph(graph_builder.graph());
190 }
191
192 if (FLAG_print_maglev_graph) {
193 std::cout << "After node processor" << std::endl;
194 PrintGraph(std::cout, toplevel_compilation_unit_, graph_builder.graph());
195 }
196
197 StraightForwardRegisterAllocator allocator(toplevel_compilation_unit_,
198 graph_builder.graph());
199
200 if (FLAG_print_maglev_graph) {
201 std::cout << "After register allocation" << std::endl;
202 PrintGraph(std::cout, toplevel_compilation_unit_, graph_builder.graph());
203 }
204
205 // Stash the compiled graph on the compilation info.
206 toplevel_compilation_unit_->info()->set_graph(graph_builder.graph());
207 }
208
209 // static
GenerateCode(MaglevCompilationUnit * toplevel_compilation_unit)210 MaybeHandle<CodeT> MaglevCompiler::GenerateCode(
211 MaglevCompilationUnit* toplevel_compilation_unit) {
212 Graph* const graph = toplevel_compilation_unit->info()->graph();
213 if (graph == nullptr) {
214 // Compilation failed.
215 toplevel_compilation_unit->shared_function_info()
216 .object()
217 ->set_maglev_compilation_failed(true);
218 return {};
219 }
220
221 Handle<Code> code;
222 if (!MaglevCodeGenerator::Generate(toplevel_compilation_unit, graph)
223 .ToHandle(&code)) {
224 toplevel_compilation_unit->shared_function_info()
225 .object()
226 ->set_maglev_compilation_failed(true);
227 return {};
228 }
229
230 compiler::JSHeapBroker* const broker = toplevel_compilation_unit->broker();
231 const bool deps_committed_successfully = broker->dependencies()->Commit(code);
232 CHECK(deps_committed_successfully);
233
234 if (FLAG_print_maglev_code) {
235 code->Print();
236 }
237
238 Isolate* const isolate = toplevel_compilation_unit->isolate();
239 isolate->native_context()->AddOptimizedCode(ToCodeT(*code));
240 return ToCodeT(code, isolate);
241 }
242
243 } // namespace maglev
244 } // namespace internal
245 } // namespace v8
246