// Copyright 2012 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/codegen/compiler.h" #include #include #include "src/api/api-inl.h" #include "src/asmjs/asm-js.h" #include "src/ast/prettyprinter.h" #include "src/ast/scopes.h" #include "src/base/logging.h" #include "src/base/optional.h" #include "src/base/platform/time.h" #include "src/baseline/baseline.h" #include "src/codegen/assembler-inl.h" #include "src/codegen/compilation-cache.h" #include "src/codegen/optimized-compilation-info.h" #include "src/codegen/pending-optimization-table.h" #include "src/codegen/script-details.h" #include "src/codegen/unoptimized-compilation-info.h" #include "src/common/assert-scope.h" #include "src/common/globals.h" #include "src/common/message-template.h" #include "src/compiler-dispatcher/lazy-compile-dispatcher.h" #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h" #include "src/compiler/pipeline.h" #include "src/debug/debug.h" #include "src/debug/liveedit.h" #include "src/diagnostics/code-tracer.h" #include "src/execution/frames-inl.h" #include "src/execution/isolate-inl.h" #include "src/execution/isolate.h" #include "src/execution/local-isolate.h" #include "src/execution/vm-state-inl.h" #include "src/handles/handles.h" #include "src/handles/maybe-handles.h" #include "src/handles/persistent-handles.h" #include "src/heap/heap-inl.h" #include "src/heap/local-factory-inl.h" #include "src/heap/local-heap-inl.h" #include "src/heap/local-heap.h" #include "src/heap/parked-scope.h" #include "src/init/bootstrapper.h" #include "src/interpreter/interpreter.h" #include "src/logging/counters-scopes.h" #include "src/logging/log-inl.h" #include "src/logging/runtime-call-stats-scope.h" #include "src/objects/feedback-cell-inl.h" #include "src/objects/js-function-inl.h" #include "src/objects/map.h" #include "src/objects/object-list-macros.h" #include "src/objects/shared-function-info.h" #include "src/objects/string.h" #include "src/parsing/parse-info.h" #include "src/parsing/parser.h" #include "src/parsing/parsing.h" #include "src/parsing/pending-compilation-error-handler.h" #include "src/parsing/scanner-character-streams.h" #include "src/snapshot/code-serializer.h" #include "src/utils/ostreams.h" #include "src/web-snapshot/web-snapshot.h" #include "src/zone/zone-list-inl.h" // crbug.com/v8/8816 #ifdef V8_ENABLE_MAGLEV #include "src/maglev/maglev-concurrent-dispatcher.h" #include "src/maglev/maglev.h" #endif // V8_ENABLE_MAGLEV namespace v8 { namespace internal { namespace { constexpr bool IsOSR(BytecodeOffset osr_offset) { return !osr_offset.IsNone(); } void SetTieringState(JSFunction function, BytecodeOffset osr_offset, TieringState value) { if (IsOSR(osr_offset)) { function.set_osr_tiering_state(value); } else { function.set_tiering_state(value); } } void ResetTieringState(JSFunction function, BytecodeOffset osr_offset) { if (function.has_feedback_vector()) { SetTieringState(function, osr_offset, TieringState::kNone); } } void ResetProfilerTicks(JSFunction function, BytecodeOffset osr_offset) { if (!IsOSR(osr_offset)) { // Reset profiler ticks, the function is no longer considered hot. // TODO(v8:7700): Update for Maglev tiering. function.feedback_vector().set_profiler_ticks(0); } } class CompilerTracer : public AllStatic { public: static void TracePrepareJob(Isolate* isolate, OptimizedCompilationInfo* info, const char* compiler_name) { if (!FLAG_trace_opt || !info->IsOptimizing()) return; CodeTracer::Scope scope(isolate->GetCodeTracer()); PrintTracePrefix(scope, "compiling method", info); PrintF(scope.file(), " using %s%s", compiler_name, info->is_osr() ? " OSR" : ""); PrintTraceSuffix(scope); } static void TraceStartBaselineCompile(Isolate* isolate, Handle shared) { if (!FLAG_trace_baseline) return; CodeTracer::Scope scope(isolate->GetCodeTracer()); PrintTracePrefix(scope, "compiling method", shared, CodeKind::BASELINE); PrintF(scope.file(), " using Sparkplug"); PrintTraceSuffix(scope); } static void TraceOptimizeOSR(Isolate* isolate, Handle function, BytecodeOffset osr_offset, ConcurrencyMode mode) { if (!FLAG_trace_osr) return; CodeTracer::Scope scope(isolate->GetCodeTracer()); PrintF(scope.file(), "[OSR - started. function: %s, osr offset: %d, mode: %s]\n", function->DebugNameCStr().get(), osr_offset.ToInt(), ToString(mode)); } static void TraceOptimizeOSRUnavailable(Isolate* isolate, Handle function, BytecodeOffset osr_offset, ConcurrencyMode mode) { if (!FLAG_trace_osr) return; CodeTracer::Scope scope(isolate->GetCodeTracer()); PrintF(scope.file(), "[OSR - unavailable (failed or in progress). function: %s, osr " "offset: %d, mode: %s]\n", function->DebugNameCStr().get(), osr_offset.ToInt(), ToString(mode)); } static void TraceCompilationStats(Isolate* isolate, OptimizedCompilationInfo* info, double ms_creategraph, double ms_optimize, double ms_codegen) { if (!FLAG_trace_opt || !info->IsOptimizing()) return; CodeTracer::Scope scope(isolate->GetCodeTracer()); PrintTracePrefix(scope, "optimizing", info); PrintF(scope.file(), " - took %0.3f, %0.3f, %0.3f ms", ms_creategraph, ms_optimize, ms_codegen); PrintTraceSuffix(scope); } static void TraceFinishBaselineCompile(Isolate* isolate, Handle shared, double ms_timetaken) { if (!FLAG_trace_baseline) return; CodeTracer::Scope scope(isolate->GetCodeTracer()); PrintTracePrefix(scope, "compiling", shared, CodeKind::BASELINE); PrintF(scope.file(), " - took %0.3f ms", ms_timetaken); PrintTraceSuffix(scope); } static void TraceCompletedJob(Isolate* isolate, OptimizedCompilationInfo* info) { if (!FLAG_trace_opt) return; CodeTracer::Scope scope(isolate->GetCodeTracer()); PrintTracePrefix(scope, "completed optimizing", info); PrintTraceSuffix(scope); } static void TraceAbortedJob(Isolate* isolate, OptimizedCompilationInfo* info) { if (!FLAG_trace_opt) return; CodeTracer::Scope scope(isolate->GetCodeTracer()); PrintTracePrefix(scope, "aborted optimizing", info); PrintF(scope.file(), " because: %s", GetBailoutReason(info->bailout_reason())); PrintTraceSuffix(scope); } static void TraceOptimizedCodeCacheHit(Isolate* isolate, Handle function, BytecodeOffset osr_offset, CodeKind code_kind) { if (!FLAG_trace_opt) return; CodeTracer::Scope scope(isolate->GetCodeTracer()); PrintTracePrefix(scope, "found optimized code for", function, code_kind); if (IsOSR(osr_offset)) { PrintF(scope.file(), " at OSR bytecode offset %d", osr_offset.ToInt()); } PrintTraceSuffix(scope); } static void TraceOptimizeForAlwaysOpt(Isolate* isolate, Handle function, CodeKind code_kind) { if (!FLAG_trace_opt) return; CodeTracer::Scope scope(isolate->GetCodeTracer()); PrintTracePrefix(scope, "optimizing", function, code_kind); PrintF(scope.file(), " because --always-opt"); PrintTraceSuffix(scope); } static void TraceMarkForAlwaysOpt(Isolate* isolate, Handle function) { if (!FLAG_trace_opt) return; CodeTracer::Scope scope(isolate->GetCodeTracer()); PrintF(scope.file(), "[marking "); function->ShortPrint(scope.file()); PrintF(scope.file(), " for optimized recompilation because --always-opt"); PrintF(scope.file(), "]\n"); } private: static void PrintTracePrefix(const CodeTracer::Scope& scope, const char* header, OptimizedCompilationInfo* info) { PrintTracePrefix(scope, header, info->closure(), info->code_kind()); } static void PrintTracePrefix(const CodeTracer::Scope& scope, const char* header, Handle function, CodeKind code_kind) { PrintF(scope.file(), "[%s ", header); function->ShortPrint(scope.file()); PrintF(scope.file(), " (target %s)", CodeKindToString(code_kind)); } static void PrintTracePrefix(const CodeTracer::Scope& scope, const char* header, Handle shared, CodeKind code_kind) { PrintF(scope.file(), "[%s ", header); shared->ShortPrint(scope.file()); PrintF(scope.file(), " (target %s)", CodeKindToString(code_kind)); } static void PrintTraceSuffix(const CodeTracer::Scope& scope) { PrintF(scope.file(), "]\n"); } }; void LogFunctionCompilation(Isolate* isolate, CodeEventListener::LogEventsAndTags tag, Handle