// 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/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/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/compiler-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/runtime-profiler.h" #include "src/execution/vm-state-inl.h" #include "src/handles/maybe-handles.h" #include "src/heap/heap-inl.h" #include "src/heap/local-factory-inl.h" #include "src/heap/local-heap-inl.h" #include "src/init/bootstrapper.h" #include "src/interpreter/interpreter.h" #include "src/logging/log-inl.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/zone/zone-list-inl.h" // crbug.com/v8/8816 namespace v8 { namespace internal { namespace { bool IsForNativeContextIndependentCachingOnly(CodeKind kind) { // NCI code is only cached (and not installed on the JSFunction upon // successful compilation), unless the testing-only // FLAG_turbo_nci_as_midtier is enabled. return CodeKindIsNativeContextIndependentJSFunction(kind) && !FLAG_turbo_nci_as_midtier; } // This predicate is currently needed only because the nci-as-midtier testing // configuration is special. A quick summary of compilation configurations: // // - Turbofan (and currently Turboprop) uses both the optimization marker and // the optimized code cache (underneath, the marker and the cache share the same // slot on the feedback vector). // - Native context independent (NCI) code uses neither the marker nor the // cache. // - The NCI-as-midtier testing configuration uses the marker, but not the // cache. // // This predicate supports that last case. In the near future, this last case is // expected to change s.t. code kinds use the marker iff they use the optimized // code cache (details still TBD). In that case, the existing // CodeKindIsStoredInOptimizedCodeCache is sufficient and this extra predicate // can be removed. // TODO(jgruber,rmcilroy,v8:8888): Remove this predicate once that has happened. bool UsesOptimizationMarker(CodeKind kind) { return !IsForNativeContextIndependentCachingOnly(kind); } class CompilerTracer : public AllStatic { public: static void PrintTracePrefix(const CodeTracer::Scope& scope, const char* header, OptimizedCompilationInfo* info) { PrintF(scope.file(), "[%s ", header); info->closure()->ShortPrint(scope.file()); PrintF(scope.file(), " (target %s)", CodeKindToString(info->code_kind())); } static void PrintTracePrefix(const CodeTracer::Scope& scope, const char* header, Handle function) { PrintF(scope.file(), "[%s ", header); function->ShortPrint(scope.file()); } static void PrintTraceSuffix(const CodeTracer::Scope& scope) { PrintF(scope.file(), "]\n"); } 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 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 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, BailoutId osr_offset) { if (!FLAG_trace_opt) return; CodeTracer::Scope scope(isolate->GetCodeTracer()); PrintTracePrefix(scope, "found optimized code for", function); if (!osr_offset.IsNone()) { PrintF(scope.file(), " at OSR AST id %d", osr_offset.ToInt()); } PrintTraceSuffix(scope); } static void TraceOptimizeForAlwaysOpt(Isolate* isolate, Handle function) { if (!FLAG_trace_opt) return; CodeTracer::Scope scope(isolate->GetCodeTracer()); PrintTracePrefix(scope, "optimizing", function); PrintF(scope.file(), " because --always-opt"); PrintTraceSuffix(scope); } }; } // namespace // Helper that times a scoped region and records the elapsed time. struct ScopedTimer { explicit ScopedTimer(base::TimeDelta* location) : location_(location) { DCHECK_NOT_NULL(location_); timer_.Start(); } ~ScopedTimer() { *location_ += timer_.Elapsed(); } base::ElapsedTimer timer_; base::TimeDelta* location_; }; namespace { void LogFunctionCompilation(CodeEventListener::LogEventsAndTags tag, Handle shared, Handle