#include "src/maglev/maglev-compiler.h"
#include <optional>
#include <ostream>
#include "src/base/logging.h"
#include "src/codegen/interface-descriptors-inl.h"
#include "src/common/globals.h"
#include "src/compiler/compilation-dependencies.h"
#include "src/compiler/heap-refs.h"
#include "src/compiler/js-heap-broker.h"
#include "src/execution/frames.h"
#include "src/flags/flags.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.h"
#include "src/maglev/maglev-truncation.h"
#include "src/objects/code-inl.h"
#include "src/objects/js-function.h"
#ifdef OHOS_JS_ENGINE
#include "../../../arkweb/chromium_ext/v8/trace.h"
#endif
#ifdef ALWAYS_MAGLEV_GRAPH_LABELLER
#define ALWAYS_MAGLEV_GRAPH_LABELLER_BOOL true
#else
#define ALWAYS_MAGLEV_GRAPH_LABELLER_BOOL false
#endif
namespace v8 {
namespace internal {
namespace maglev {
namespace {
void PrintGraph(Graph* graph, bool condition, const char* message,
bool has_regalloc_data = false) {
if (V8_UNLIKELY(condition &&
graph->compilation_info()->is_tracing_enabled())) {
UnparkedScopeIfOnBackground unparked_scope(
graph->broker()->local_isolate()->heap());
std::cout << "\n----- " << message << " -----" << std::endl;
PrintGraph(std::cout, graph, has_regalloc_data);
}
}
void VerifyGraph(Graph* graph) {
#ifdef DEBUG
GraphProcessor<MaglevGraphVerifier> verifier(graph->compilation_info());
verifier.ProcessGraph(graph);
#endif
}
}
bool MaglevCompiler::Compile(LocalIsolate* local_isolate,
MaglevCompilationInfo* compilation_info) {
std::optional<MaglevGraphLabellerScope> graph_labeller_scope;
compiler::CurrentHeapBrokerScope current_broker(compilation_info->broker());
Graph* graph = Graph::New(compilation_info);
if (V8_UNLIKELY(ALWAYS_MAGLEV_GRAPH_LABELLER_BOOL ||
compilation_info->is_tracing_enabled() ||
compilation_info->collect_source_positions())) {
compilation_info->set_graph_labeller(new MaglevGraphLabeller());
graph_labeller_scope.emplace(compilation_info->graph_labeller());
}
{
UnparkedScopeIfOnBackground unparked_scope(local_isolate->heap());
if (V8_UNLIKELY(v8_flags.maglev_print_bytecode &&
compilation_info->is_tracing_enabled())) {
MaglevCompilationUnit* top_level_unit =
compilation_info->toplevel_compilation_unit();
std::cout << "Compiling " << Brief(*compilation_info->toplevel_function())
<< " with Maglev";
std::cout << "\n----- Bytecode array -----" << std::endl;
BytecodeArray::Disassemble(top_level_unit->bytecode().object(),
std::cout);
if (v8_flags.maglev_print_feedback) {
Print(*top_level_unit->feedback().object(), std::cout);
}
}
{
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.GraphBuilding");
#ifdef OHOS_JS_ENGINE
auto trace = HiTrace("RCS_v8.compile_V8.Maglev.GraphBuilding");
#endif
MaglevGraphBuilder graph_builder(
local_isolate, compilation_info->toplevel_compilation_unit(), graph);
if (!graph_builder.Build()) return false;
PrintGraph(graph, v8_flags.print_maglev_graphs, "After graph building");
VerifyGraph(graph);
}
if (v8_flags.maglev_non_eager_inlining) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.Inlining");
MaglevInliner inliner(graph);
if (!inliner.Run()) return false;
VerifyGraph(graph);
}
if (v8_flags.maglev_truncation && graph->may_have_truncation()) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.Truncation");
GraphBackwardProcessor<PropagateTruncationProcessor> propagate;
propagate.ProcessGraph(graph);
PrintGraph(graph, v8_flags.print_maglev_graphs,
"After propagating truncation");
GraphProcessor<TruncationProcessor> truncate(graph);
truncate.ProcessGraph(graph);
PrintGraph(graph, v8_flags.print_maglev_graphs, "After truncation");
VerifyGraph(graph);
}
if (v8_flags.maglev_licm) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.LoopOptimizations");
#ifdef OHOS_JS_ENGINE
auto trace = HiTrace("RCS_v8.compile_V8.Maglev.LoopOptimizations");
#endif
GraphProcessor<LoopOptimizationProcessor> loop_optimizations(
compilation_info);
loop_optimizations.ProcessGraph(graph);
PrintGraph(graph, v8_flags.print_maglev_graphs,
"After loop optimizations");
VerifyGraph(graph);
}
if (v8_flags.maglev_untagged_phis) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.PhiUntagging");
#ifdef OHOS_JS_ENGINE
auto trace = HiTrace("RCS_v8.compile_V8.Maglev.PhiUntagging");
#endif
GraphProcessor<MaglevPhiRepresentationSelector> representation_selector(
graph);
representation_selector.ProcessGraph(graph);
PrintGraph(graph, v8_flags.print_maglev_graphs, "After Phi untagging");
VerifyGraph(graph);
}
}
{
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.DeadCodeMarking");
#ifdef OHOS_JS_ENGINE
auto trace = HiTrace("RCS_v8.compile_V8.Maglev.DeadCodeMarking");
#endif
if (graph->may_have_unreachable_blocks()) {
graph->RemoveUnreachableBlocks();
}
GraphMultiProcessor<ReturnedValueRepresentationSelector,
AnyUseMarkingProcessor,
RegallocNodeInfoAllocationProcessor>
processor;
processor.ProcessGraph(graph);
PrintGraph(graph, v8_flags.print_maglev_graphs, "After use marking",
true);
VerifyGraph(graph);
}
{
RegallocBlockInfo regalloc_info;
{
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.NodeProcessing");
#ifdef OHOS_JS_ENGINE
auto trace = HiTrace("RCS_v8.compile_V8.Maglev.NodeProcessing");
#endif
UnparkedScopeIfOnBackground unparked_scope(local_isolate->heap());
GraphMultiProcessor<DeadNodeSweepingProcessor,
ValueLocationConstraintProcessor,
MaxCallDepthProcessor, LiveRangeAndNextUseProcessor,
DecompressedUseMarkingProcessor>
processor(LiveRangeAndNextUseProcessor{compilation_info, graph,
®alloc_info});
processor.ProcessGraph(graph);
PrintGraph(graph, v8_flags.print_maglev_graphs,
"After register allocation pre-processing",
true);
}
{
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.RegisterAllocation");
#ifdef OHOS_JS_ENGINE
auto trace = HiTrace("RCS_v8.compile_V8.Maglev.RegisterAllocation");
#endif
StraightForwardRegisterAllocator allocator(compilation_info, graph,
®alloc_info);
PrintGraph(graph, v8_flags.print_maglev_graph,
"After register allocation", true);
}
}
{
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.CodeAssembly");
#ifdef OHOS_JS_ENGINE
auto trace = HiTrace("RCS_v8.compile_V8.Maglev.CodeAssembly");
#endif
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;
}
compilation_info->set_code_generator(std::move(code_generator));
}
return true;
}
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;
{
std::optional<MaglevGraphLabellerScope> current_thread_graph_labeller;
if (compilation_info->has_graph_labeller()) {
current_thread_graph_labeller.emplace(compilation_info->graph_labeller());
}
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.CodeGeneration");
#ifdef OHOS_JS_ENGINE
auto trace = HiTrace("RCS_v8.compile_V8.Maglev.CodeGeneration");
#endif
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::kMaglevCodeGenerationFailed};
}
}
{
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
"V8.Maglev.CommittingDependencies");
if (!compilation_info->broker()->dependencies()->Commit(code)) {
compilation_info->toplevel_function()->SetTieringInProgress(isolate,
false);
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};
}
}
}
}