• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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