blob: 4ea3ed3b8f5a576c2b07d311d3f0f4702e66b41e [file] [log] [blame]
// Copyright 2022 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.
#include "src/maglev/maglev-compiler.h"
#include <algorithm>
#include <iomanip>
#include <ostream>
#include <type_traits>
#include <unordered_map>
#include "src/base/iterator.h"
#include "src/base/logging.h"
#include "src/base/threaded-list.h"
#include "src/codegen/interface-descriptors-inl.h"
#include "src/codegen/machine-type.h"
#include "src/codegen/register-configuration.h"
#include "src/codegen/register.h"
#include "src/codegen/reglist.h"
#include "src/common/globals.h"
#include "src/compiler/backend/instruction.h"
#include "src/compiler/bytecode-liveness-map.h"
#include "src/compiler/compilation-dependencies.h"
#include "src/compiler/heap-refs.h"
#include "src/compiler/js-heap-broker.h"
#include "src/deoptimizer/frame-translation-builder.h"
#include "src/execution/frames.h"
#include "src/flags/flags.h"
#include "src/ic/handler-configuration.h"
#include "src/maglev/maglev-basic-block.h"
#include "src/maglev/maglev-code-generator.h"
#include "src/maglev/maglev-compilation-info.h"
#include "src/maglev/maglev-compilation-unit.h"
#include "src/maglev/maglev-graph-builder.h"
#include "src/maglev/maglev-graph-labeller.h"
#include "src/maglev/maglev-graph-printer.h"
#include "src/maglev/maglev-graph-processor.h"
#include "src/maglev/maglev-graph-verifier.h"
#include "src/maglev/maglev-graph.h"
#include "src/maglev/maglev-inlining.h"
#include "src/maglev/maglev-interpreter-frame-state.h"
#include "src/maglev/maglev-ir-inl.h"
#include "src/maglev/maglev-ir.h"
#include "src/maglev/maglev-phi-representation-selector.h"
#include "src/maglev/maglev-post-hoc-optimizations-processors.h"
#include "src/maglev/maglev-pre-regalloc-codegen-processors.h"
#include "src/maglev/maglev-regalloc-data.h"
#include "src/maglev/maglev-regalloc.h"
#include "src/objects/code-inl.h"
#include "src/objects/js-function.h"
#include "src/utils/identity-map.h"
#include "src/zone/zone.h"
namespace v8 {
namespace internal {
namespace maglev {
// static
bool MaglevCompiler::Compile(LocalIsolate* local_isolate,
MaglevCompilationInfo* compilation_info) {
compiler::CurrentHeapBrokerScope current_broker(compilation_info->broker());
Graph* graph =
Graph::New(compilation_info->zone(),
compilation_info->toplevel_compilation_unit()->is_osr());
bool is_tracing_enabled = false;
{
UnparkedScopeIfOnBackground unparked_scope(local_isolate->heap());
// Build graph.
if (v8_flags.print_maglev_code || v8_flags.code_comments ||
v8_flags.print_maglev_graph || v8_flags.print_maglev_graphs ||
v8_flags.trace_maglev_graph_building ||
v8_flags.trace_maglev_escape_analysis ||
v8_flags.trace_maglev_phi_untagging || v8_flags.trace_maglev_regalloc ||
v8_flags.trace_maglev_object_tracking) {
is_tracing_enabled = compilation_info->toplevel_compilation_unit()
->shared_function_info()
.object()
->PassesFilter(v8_flags.maglev_print_filter);
compilation_info->set_graph_labeller(new MaglevGraphLabeller());
}
if (is_tracing_enabled &&
(v8_flags.print_maglev_code || v8_flags.print_maglev_graph ||
v8_flags.print_maglev_graphs || v8_flags.trace_maglev_graph_building ||
v8_flags.trace_maglev_phi_untagging ||
v8_flags.trace_maglev_regalloc)) {
MaglevCompilationUnit* top_level_unit =
compilation_info->toplevel_compilation_unit();
std::cout << "Compiling " << Brief(*compilation_info->toplevel_function())
<< " with Maglev\n";
BytecodeArray::Disassemble(top_level_unit->bytecode().object(),
std::cout);
if (v8_flags.maglev_print_feedback) {
Print(*top_level_unit->feedback().object(), std::cout);
}
}
MaglevGraphBuilder graph_builder(
local_isolate, compilation_info->toplevel_compilation_unit(), graph);
{
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.GraphBuilding");
graph_builder.Build();
if (is_tracing_enabled && v8_flags.print_maglev_graphs) {
std::cout << "\nAfter graph building" << std::endl;
PrintGraph(std::cout, compilation_info, graph);
}
}
#ifdef DEBUG
{
GraphProcessor<MaglevGraphVerifier, /* visit_identity_nodes */ true>
verifier(compilation_info);
verifier.ProcessGraph(graph);
}
#endif
if (v8_flags.maglev_non_eager_inlining) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.Inlining");
MaglevInliner inliner(compilation_info, graph);
inliner.Run(is_tracing_enabled);
}
#ifdef DEBUG
{
GraphProcessor<MaglevGraphVerifier, /* visit_identity_nodes */ true>
verifier(compilation_info);
verifier.ProcessGraph(graph);
}
#endif
if (v8_flags.maglev_licm) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.LoopOptimizations");
GraphProcessor<LoopOptimizationProcessor> loop_optimizations(
&graph_builder);
loop_optimizations.ProcessGraph(graph);
if (is_tracing_enabled && v8_flags.print_maglev_graphs) {
std::cout << "\nAfter loop optimizations" << std::endl;
PrintGraph(std::cout, compilation_info, graph);
}
}
#ifdef DEBUG
{
GraphProcessor<MaglevGraphVerifier, /* visit_identity_nodes */ true>
verifier(compilation_info);
verifier.ProcessGraph(graph);
}
#endif
if (v8_flags.maglev_untagged_phis) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.PhiUntagging");
GraphProcessor<MaglevPhiRepresentationSelector> representation_selector(
&graph_builder);
representation_selector.ProcessGraph(graph);
if (is_tracing_enabled && v8_flags.print_maglev_graphs) {
std::cout << "\nAfter Phi untagging" << std::endl;
PrintGraph(std::cout, compilation_info, graph);
}
}
}
#ifdef DEBUG
{
GraphProcessor<MaglevGraphVerifier, /* visit_identity_nodes */ true>
verifier(compilation_info);
verifier.ProcessGraph(graph);
}
#endif
{
// Post-hoc optimisation:
// - Dead node marking
// - Cleaning up identity nodes
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.DeadCodeMarking");
GraphMultiProcessor<AnyUseMarkingProcessor> processor;
processor.ProcessGraph(graph);
}
if (is_tracing_enabled && v8_flags.print_maglev_graphs) {
UnparkedScopeIfOnBackground unparked_scope(local_isolate->heap());
std::cout << "After use marking" << std::endl;
PrintGraph(std::cout, compilation_info, graph);
}
#ifdef DEBUG
{
GraphProcessor<MaglevGraphVerifier, /* visit_identity_nodes */ true>
verifier(compilation_info);
verifier.ProcessGraph(graph);
}
#endif
{
// Preprocessing for register allocation and code gen:
// - Remove dead nodes
// - Collect input/output location constraints
// - Find the maximum number of stack arguments passed to calls
// - Collect use information, for SSA liveness and next-use distance.
// - Mark
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.NodeProcessing");
GraphMultiProcessor<DeadNodeSweepingProcessor,
ValueLocationConstraintProcessor, MaxCallDepthProcessor,
LiveRangeAndNextUseProcessor,
DecompressedUseMarkingProcessor>
processor(DeadNodeSweepingProcessor{compilation_info},
LiveRangeAndNextUseProcessor{compilation_info});
processor.ProcessGraph(graph);
}
if (is_tracing_enabled && v8_flags.print_maglev_graphs) {
UnparkedScopeIfOnBackground unparked_scope(local_isolate->heap());
std::cout << "After register allocation pre-processing" << std::endl;
PrintGraph(std::cout, compilation_info, graph);
}
{
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.RegisterAllocation");
StraightForwardRegisterAllocator allocator(compilation_info, graph);
if (is_tracing_enabled &&
(v8_flags.print_maglev_graph || v8_flags.print_maglev_graphs)) {
UnparkedScopeIfOnBackground unparked_scope(local_isolate->heap());
std::cout << "After register allocation" << std::endl;
PrintGraph(std::cout, compilation_info, graph);
}
}
{
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.CodeAssembly");
UnparkedScopeIfOnBackground unparked_scope(local_isolate->heap());
std::unique_ptr<MaglevCodeGenerator> code_generator =
std::make_unique<MaglevCodeGenerator>(local_isolate, compilation_info,
graph);
bool success = code_generator->Assemble();
if (!success) {
return false;
}
// Stash the compiled code_generator on the compilation info.
compilation_info->set_code_generator(std::move(code_generator));
}
return true;
}
// static
std::pair<MaybeHandle<Code>, BailoutReason> MaglevCompiler::GenerateCode(
Isolate* isolate, MaglevCompilationInfo* compilation_info) {
compiler::CurrentHeapBrokerScope current_broker(compilation_info->broker());
MaglevCodeGenerator* const code_generator =
compilation_info->code_generator();
DCHECK_NOT_NULL(code_generator);
Handle<Code> code;
{
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.CodeGeneration");
if (compilation_info->is_detached() ||
!code_generator->Generate(isolate).ToHandle(&code)) {
compilation_info->toplevel_compilation_unit()
->shared_function_info()
.object()
->set_maglev_compilation_failed(true);
return {{}, BailoutReason::kCodeGenerationFailed};
}
}
{
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.CommittingDependencies");
if (!compilation_info->broker()->dependencies()->Commit(code)) {
// Don't `set_maglev_compilation_failed` s.t. we may reattempt
// compilation.
// TODO(v8:7700): Make this more robust, i.e.: don't recompile endlessly.
compilation_info->toplevel_function()->SetInterruptBudget(
isolate, BudgetModification::kReduce);
return {{}, BailoutReason::kBailedOutDueToDependencyChange};
}
}
if (v8_flags.print_maglev_code) {
#ifdef OBJECT_PRINT
std::unique_ptr<char[]> debug_name =
compilation_info->toplevel_function()->shared()->DebugNameCStr();
CodeTracer::StreamScope tracing_scope(isolate->GetCodeTracer());
auto& os = tracing_scope.stream();
code->CodePrint(os, debug_name.get());
#else
Print(*code);
#endif
}
return {code, BailoutReason::kNoReason};
}
} // namespace maglev
} // namespace internal
} // namespace v8