diff options
author | Michaël Zasso <targos@protonmail.com> | 2017-02-14 11:27:26 +0100 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2017-02-22 15:55:42 +0100 |
commit | 7a77daf24344db7942e34c962b0f1ee729ab7af5 (patch) | |
tree | e7cbe7bf4e2f4b802a8f5bc18336c546cd6a0d7f /deps/v8/src/compiler.cc | |
parent | 5f08871ee93ea739148cc49e0f7679e33c70295a (diff) | |
download | android-node-v8-7a77daf24344db7942e34c962b0f1ee729ab7af5.tar.gz android-node-v8-7a77daf24344db7942e34c962b0f1ee729ab7af5.tar.bz2 android-node-v8-7a77daf24344db7942e34c962b0f1ee729ab7af5.zip |
deps: update V8 to 5.6.326.55
PR-URL: https://github.com/nodejs/node/pull/10992
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'deps/v8/src/compiler.cc')
-rw-r--r-- | deps/v8/src/compiler.cc | 590 |
1 files changed, 199 insertions, 391 deletions
diff --git a/deps/v8/src/compiler.cc b/deps/v8/src/compiler.cc index ec402fa822..3435f530c2 100644 --- a/deps/v8/src/compiler.cc +++ b/deps/v8/src/compiler.cc @@ -20,7 +20,6 @@ #include "src/crankshaft/hydrogen.h" #include "src/debug/debug.h" #include "src/debug/liveedit.h" -#include "src/deoptimizer.h" #include "src/frames-inl.h" #include "src/full-codegen/full-codegen.h" #include "src/globals.h" @@ -251,22 +250,6 @@ void CompilationJob::RegisterWeakObjectsInOptimizedCode(Handle<Code> code) { namespace { -bool IsEvalToplevel(Handle<SharedFunctionInfo> shared) { - return shared->is_toplevel() && shared->script()->IsScript() && - Script::cast(shared->script())->compilation_type() == - Script::COMPILATION_TYPE_EVAL; -} - -bool Parse(ParseInfo* info) { - // Create a canonical handle scope if compiling ignition bytecode. This is - // required by the constant array builder to de-duplicate objects without - // dereferencing handles. - std::unique_ptr<CanonicalHandleScope> canonical; - if (FLAG_ignition) canonical.reset(new CanonicalHandleScope(info->isolate())); - - return Parser::ParseStatic(info); -} - void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag, CompilationInfo* info) { // Log the code generation. If source information is available include @@ -320,21 +303,46 @@ void EnsureFeedbackMetadata(CompilationInfo* info) { info->literal()->feedback_vector_spec())); } -bool ShouldUseIgnition(CompilationInfo* info) { - if (!FLAG_ignition) return false; +bool UseTurboFan(Handle<SharedFunctionInfo> shared) { + bool optimization_disabled = shared->optimization_disabled(); + bool dont_crankshaft = shared->dont_crankshaft(); + + // Check the enabling conditions for Turbofan. + // 1. "use asm" code. + bool is_turbofanable_asm = + FLAG_turbo_asm && shared->asm_function() && !optimization_disabled; + // 2. Fallback for features unsupported by Crankshaft. + bool is_unsupported_by_crankshaft_but_turbofanable = + dont_crankshaft && strcmp(FLAG_turbo_filter, "~~") == 0 && + !optimization_disabled; + + // 3. Explicitly enabled by the command-line filter. + bool passes_turbo_filter = shared->PassesFilter(FLAG_turbo_filter); + + return is_turbofanable_asm || is_unsupported_by_crankshaft_but_turbofanable || + passes_turbo_filter; +} + +bool ShouldUseIgnition(CompilationInfo* info) { DCHECK(info->has_shared_info()); + // Skip Ignition for asm.js functions. + if (info->shared_info()->asm_function()) { + return false; + } + // When requesting debug code as a replacement for existing code, we provide // the same kind as the existing code (to prevent implicit tier-change). if (info->is_debug() && info->shared_info()->is_compiled()) { return !info->shared_info()->HasBaselineCode(); } - // Since we can't OSR from Ignition, skip Ignition for asm.js functions. - if (info->shared_info()->asm_function()) { - return false; - } + // Code destined for TurboFan should be compiled with Ignition first. + if (UseTurboFan(info->shared_info())) return true; + + // Only use Ignition for any other function if FLAG_ignition is true. + if (!FLAG_ignition) return false; // Checks whether top level functions should be passed by the filter. if (info->shared_info()->is_toplevel()) { @@ -360,38 +368,6 @@ CompilationJob* GetUnoptimizedCompilationJob(CompilationInfo* info) { } } -bool GenerateUnoptimizedCode(CompilationInfo* info) { - if (FLAG_validate_asm && info->scope()->asm_module() && - !info->shared_info()->is_asm_wasm_broken()) { - EnsureFeedbackMetadata(info); - MaybeHandle<FixedArray> wasm_data; - wasm_data = AsmJs::ConvertAsmToWasm(info->parse_info()); - if (!wasm_data.is_null()) { - info->shared_info()->set_asm_wasm_data(*wasm_data.ToHandleChecked()); - info->SetCode(info->isolate()->builtins()->InstantiateAsmJs()); - return true; - } - } - - std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info)); - if (job->PrepareJob() != CompilationJob::SUCCEEDED) return false; - if (job->ExecuteJob() != CompilationJob::SUCCEEDED) return false; - if (job->FinalizeJob() != CompilationJob::SUCCEEDED) return false; - job->RecordUnoptimizedCompilationStats(); - return true; -} - -bool CompileUnoptimizedCode(CompilationInfo* info) { - DCHECK(AllowCompilation::IsAllowed(info->isolate())); - if (!Compiler::Analyze(info->parse_info()) || - !GenerateUnoptimizedCode(info)) { - Isolate* isolate = info->isolate(); - if (!isolate->has_pending_exception()) isolate->StackOverflow(); - return false; - } - return true; -} - void InstallSharedScopeInfo(CompilationInfo* info, Handle<SharedFunctionInfo> shared) { Handle<ScopeInfo> scope_info = info->scope()->scope_info(); @@ -426,9 +402,50 @@ void InstallUnoptimizedCode(CompilationInfo* info) { // Install compilation result on the shared function info InstallSharedCompilationResult(info, shared); +} - // Record the function compilation event. - RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, info); +CompilationJob::Status FinalizeUnoptimizedCompilationJob(CompilationJob* job) { + CompilationJob::Status status = job->FinalizeJob(); + if (status == CompilationJob::SUCCEEDED) { + InstallUnoptimizedCode(job->info()); + job->RecordUnoptimizedCompilationStats(); + } + return status; +} + +bool GenerateUnoptimizedCode(CompilationInfo* info) { + if (FLAG_validate_asm && info->scope()->asm_module() && + !info->shared_info()->is_asm_wasm_broken() && !info->is_debug()) { + EnsureFeedbackMetadata(info); + MaybeHandle<FixedArray> wasm_data; + wasm_data = AsmJs::ConvertAsmToWasm(info->parse_info()); + if (!wasm_data.is_null()) { + info->shared_info()->set_asm_wasm_data(*wasm_data.ToHandleChecked()); + info->SetCode(info->isolate()->builtins()->InstantiateAsmJs()); + InstallUnoptimizedCode(info); + return true; + } + } + + std::unique_ptr<CompilationJob> job(GetUnoptimizedCompilationJob(info)); + if (job->PrepareJob() != CompilationJob::SUCCEEDED) return false; + if (job->ExecuteJob() != CompilationJob::SUCCEEDED) return false; + if (FinalizeUnoptimizedCompilationJob(job.get()) != + CompilationJob::SUCCEEDED) { + return false; + } + return true; +} + +bool CompileUnoptimizedCode(CompilationInfo* info) { + DCHECK(AllowCompilation::IsAllowed(info->isolate())); + if (!Compiler::Analyze(info->parse_info()) || + !GenerateUnoptimizedCode(info)) { + Isolate* isolate = info->isolate(); + if (!isolate->has_pending_exception()) isolate->StackOverflow(); + return false; + } + return true; } MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(CompilationInfo* info) { @@ -436,28 +453,19 @@ MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(CompilationInfo* info) { PostponeInterruptsScope postpone(info->isolate()); // Parse and update CompilationInfo with the results. - if (!Parse(info->parse_info())) return MaybeHandle<Code>(); + if (!Parser::ParseStatic(info->parse_info())) return MaybeHandle<Code>(); DCHECK_EQ(info->shared_info()->language_mode(), info->literal()->language_mode()); // Compile either unoptimized code or bytecode for the interpreter. if (!CompileUnoptimizedCode(info)) return MaybeHandle<Code>(); - InstallUnoptimizedCode(info); + // Record the function compilation event. + RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, info); return info->code(); } -CompilationJob::Status FinalizeUnoptimizedCompilationJob(CompilationJob* job) { - CompilationJob::Status status = job->FinalizeJob(); - if (status == CompilationJob::SUCCEEDED) { - DCHECK(!job->info()->shared_info()->is_compiled()); - InstallUnoptimizedCode(job->info()); - job->RecordUnoptimizedCompilationStats(); - } - return status; -} - MUST_USE_RESULT MaybeHandle<Code> GetCodeFromOptimizedCodeMap( Handle<JSFunction> function, BailoutId osr_ast_id) { Handle<SharedFunctionInfo> shared(function->shared()); @@ -495,29 +503,9 @@ void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) { Handle<Context> native_context(function->context()->native_context()); SharedFunctionInfo::AddToOptimizedCodeMap(shared, native_context, code, literals, info->osr_ast_id()); - - // Do not cache (native) context-independent code compiled for OSR. - if (code->is_turbofanned() && info->is_osr()) return; - - // Cache optimized (native) context-independent code. - if (FLAG_turbo_cache_shared_code && code->is_turbofanned() && - !info->is_native_context_specializing()) { - DCHECK(!info->is_function_context_specializing()); - DCHECK(info->osr_ast_id().IsNone()); - Handle<SharedFunctionInfo> shared(function->shared()); - SharedFunctionInfo::AddSharedCodeToOptimizedCodeMap(shared, code); - } } bool Renumber(ParseInfo* parse_info) { - // Create a canonical handle scope if compiling ignition bytecode. This is - // required by the constant array builder to de-duplicate objects without - // dereferencing handles. - std::unique_ptr<CanonicalHandleScope> canonical; - if (FLAG_ignition) { - canonical.reset(new CanonicalHandleScope(parse_info->isolate())); - } - if (!AstNumbering::Renumber(parse_info->isolate(), parse_info->zone(), parse_info->literal())) { return false; @@ -536,27 +524,6 @@ bool Renumber(ParseInfo* parse_info) { return true; } -bool UseTurboFan(Handle<SharedFunctionInfo> shared) { - bool optimization_disabled = shared->optimization_disabled(); - bool dont_crankshaft = shared->dont_crankshaft(); - - // Check the enabling conditions for Turbofan. - // 1. "use asm" code. - bool is_turbofanable_asm = - FLAG_turbo_asm && shared->asm_function() && !optimization_disabled; - - // 2. Fallback for features unsupported by Crankshaft. - bool is_unsupported_by_crankshaft_but_turbofanable = - dont_crankshaft && strcmp(FLAG_turbo_filter, "~~") == 0 && - !optimization_disabled; - - // 3. Explicitly enabled by the command-line filter. - bool passes_turbo_filter = shared->PassesFilter(FLAG_turbo_filter); - - return is_turbofanable_asm || is_unsupported_by_crankshaft_but_turbofanable || - passes_turbo_filter; -} - bool GetOptimizedCodeNow(CompilationJob* job) { CompilationInfo* info = job->info(); Isolate* isolate = info->isolate(); @@ -652,8 +619,8 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function, DCHECK_IMPLIES(ignition_osr, !osr_ast_id.IsNone()); DCHECK_IMPLIES(ignition_osr, FLAG_ignition_osr); - // Flag combination --ignition-osr --no-turbo-from-bytecode is unsupported. - if (ignition_osr && !FLAG_turbo_from_bytecode) return MaybeHandle<Code>(); + // Shared function no longer needs to be tiered up + shared->set_marked_for_tier_up(false); Handle<Code> cached_code; // TODO(4764): When compiling for OSR from bytecode, BailoutId might derive @@ -673,8 +640,10 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function, } // Reset profiler ticks, function is no longer considered hot. - if (shared->is_compiled()) { + if (shared->HasBaselineCode()) { shared->code()->set_profiler_ticks(0); + } else if (shared->HasBytecodeArray()) { + shared->set_profiler_ticks(0); } VMState<COMPILER> state(isolate); @@ -708,7 +677,7 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function, TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.OptimizeCode"); // TurboFan can optimize directly from existing bytecode. - if (FLAG_turbo_from_bytecode && use_turbofan && ShouldUseIgnition(info)) { + if (use_turbofan && ShouldUseIgnition(info)) { if (info->is_osr() && !ignition_osr) return MaybeHandle<Code>(); if (!Compiler::EnsureBytecode(info)) { if (isolate->has_pending_exception()) isolate->clear_pending_exception(); @@ -717,14 +686,6 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function, info->MarkAsOptimizeFromBytecode(); } - if (IsEvalToplevel(shared)) { - parse_info->set_eval(); - if (function->context()->IsNativeContext()) parse_info->set_global(); - parse_info->set_toplevel(); - parse_info->set_allow_lazy_parsing(false); - parse_info->set_lazy(false); - } - // Verify that OSR compilations are delegated to the correct graph builder. // Depending on the underlying frame the semantics of the {BailoutId} differ // and the various graph builders hard-code a certain semantic: @@ -775,7 +736,13 @@ CompilationJob::Status FinalizeOptimizedCompilationJob(CompilationJob* job) { "V8.RecompileSynchronous"); Handle<SharedFunctionInfo> shared = info->shared_info(); - shared->code()->set_profiler_ticks(0); + + // Reset profiler ticks, function is no longer considered hot. + if (shared->HasBaselineCode()) { + shared->code()->set_profiler_ticks(0); + } else if (shared->HasBytecodeArray()) { + shared->set_profiler_ticks(0); + } DCHECK(!shared->HasDebugInfo()); @@ -818,84 +785,17 @@ CompilationJob::Status FinalizeOptimizedCompilationJob(CompilationJob* job) { return CompilationJob::FAILED; } -class InterpreterActivationsFinder : public ThreadVisitor, - public OptimizedFunctionVisitor { - public: - explicit InterpreterActivationsFinder(SharedFunctionInfo* shared) - : shared_(shared), has_activations_(false) {} - - void VisitThread(Isolate* isolate, ThreadLocalTop* top) { - Address* activation_pc_address = nullptr; - JavaScriptFrameIterator it(isolate, top); - for (; !it.done(); it.Advance()) { - JavaScriptFrame* frame = it.frame(); - if (FLAG_turbo_from_bytecode && FLAG_ignition_osr && - frame->is_optimized() && frame->function()->shared() == shared_) { - // If we are able to optimize functions directly from bytecode, then - // there might be optimized OSR code active on the stack that is not - // reachable through a function. We count this as an activation. - has_activations_ = true; - } - if (frame->is_interpreted() && frame->function()->shared() == shared_) { - has_activations_ = true; - activation_pc_address = frame->pc_address(); - } - } - - if (activation_pc_address) { - activation_pc_addresses_.push_back(activation_pc_address); - } - } - - void VisitFunction(JSFunction* function) { - if (function->Inlines(shared_)) has_activations_ = true; - } - - void EnterContext(Context* context) {} - void LeaveContext(Context* context) {} - - bool MarkActivationsForBaselineOnReturn(Isolate* isolate) { - if (activation_pc_addresses_.empty()) return false; - - for (Address* activation_pc_address : activation_pc_addresses_) { - DCHECK(isolate->inner_pointer_to_code_cache() - ->GetCacheEntry(*activation_pc_address) - ->code->is_interpreter_trampoline_builtin()); - *activation_pc_address = - isolate->builtins()->InterpreterMarkBaselineOnReturn()->entry(); - } - return true; - } - - bool has_activations() { return has_activations_; } - - private: - SharedFunctionInfo* shared_; - bool has_activations_; - std::vector<Address*> activation_pc_addresses_; -}; - -bool HasInterpreterActivations( - Isolate* isolate, InterpreterActivationsFinder* activations_finder) { - activations_finder->VisitThread(isolate, isolate->thread_local_top()); - isolate->thread_manager()->IterateArchivedThreads(activations_finder); - if (FLAG_turbo_from_bytecode) { - // If we are able to optimize functions directly from bytecode, then there - // might be optimized functions that rely on bytecode being around. We need - // to prevent switching the given function to baseline code in those cases. - Deoptimizer::VisitAllOptimizedFunctions(isolate, activations_finder); - } - return activations_finder->has_activations(); -} - MaybeHandle<Code> GetBaselineCode(Handle<JSFunction> function) { Isolate* isolate = function->GetIsolate(); VMState<COMPILER> state(isolate); PostponeInterruptsScope postpone(isolate); - Zone zone(isolate->allocator()); - ParseInfo parse_info(&zone, function); + Zone zone(isolate->allocator(), ZONE_NAME); + ParseInfo parse_info(&zone, handle(function->shared())); CompilationInfo info(&parse_info, function); + // Function no longer needs to be tiered up + function->shared()->set_marked_for_tier_up(false); + // Reset profiler ticks, function is no longer considered hot. if (function->shared()->HasBytecodeArray()) { function->shared()->set_profiler_ticks(0); @@ -920,31 +820,6 @@ MaybeHandle<Code> GetBaselineCode(Handle<JSFunction> function) { return MaybeHandle<Code>(); } - // TODO(4280): For now we disable switching to baseline code in the presence - // of interpreter activations of the given function. The reasons is that the - // underlying bytecode is cleared below. Note that this only applies in case - // the --ignition-preserve-bytecode flag is not passed. - if (!FLAG_ignition_preserve_bytecode) { - InterpreterActivationsFinder activations_finder(function->shared()); - if (HasInterpreterActivations(isolate, &activations_finder)) { - if (FLAG_trace_opt) { - OFStream os(stdout); - os << "[unable to switch " << Brief(*function) << " due to activations]" - << std::endl; - } - - if (activations_finder.MarkActivationsForBaselineOnReturn(isolate)) { - if (FLAG_trace_opt) { - OFStream os(stdout); - os << "[marking " << Brief(function->shared()) - << " for baseline recompilation on return]" << std::endl; - } - } - - return MaybeHandle<Code>(); - } - } - if (FLAG_trace_opt) { OFStream os(stdout); os << "[switching method " << Brief(*function) << " to baseline code]" @@ -952,7 +827,7 @@ MaybeHandle<Code> GetBaselineCode(Handle<JSFunction> function) { } // Parse and update CompilationInfo with the results. - if (!Parse(info.parse_info())) return MaybeHandle<Code>(); + if (!Parser::ParseStatic(info.parse_info())) return MaybeHandle<Code>(); Handle<SharedFunctionInfo> shared = info.shared_info(); DCHECK_EQ(shared->language_mode(), info.literal()->language_mode()); @@ -963,12 +838,6 @@ MaybeHandle<Code> GetBaselineCode(Handle<JSFunction> function) { return MaybeHandle<Code>(); } - // TODO(4280): For now we play it safe and remove the bytecode array when we - // switch to baseline code. We might consider keeping around the bytecode so - // that it can be used as the "source of truth" eventually. Note that this - // only applies in case the --ignition-preserve-bytecode flag is not passed. - if (!FLAG_ignition_preserve_bytecode) shared->ClearBytecodeArray(); - // Update the shared function info with the scope info. InstallSharedScopeInfo(&info, shared); @@ -1003,6 +872,46 @@ MaybeHandle<Code> GetLazyCode(Handle<JSFunction> function) { return cached_code; } + if (function->shared()->marked_for_tier_up()) { + DCHECK(FLAG_mark_shared_functions_for_tier_up); + + function->shared()->set_marked_for_tier_up(false); + + switch (Compiler::NextCompilationTier(*function)) { + case Compiler::BASELINE: { + if (FLAG_trace_opt) { + PrintF("[recompiling function "); + function->ShortPrint(); + PrintF( + " to baseline eagerly (shared function marked for tier up)]\n"); + } + + Handle<Code> code; + if (GetBaselineCode(function).ToHandle(&code)) { + return code; + } + break; + } + case Compiler::OPTIMIZED: { + if (FLAG_trace_opt) { + PrintF("[optimizing method "); + function->ShortPrint(); + PrintF(" eagerly (shared function marked for tier up)]\n"); + } + + Handle<Code> code; + // TODO(leszeks): Look into performing this compilation concurrently. + if (GetOptimizedCode(function, Compiler::NOT_CONCURRENT) + .ToHandle(&code)) { + return code; + } + break; + } + default: + UNREACHABLE(); + } + } + if (function->shared()->is_compiled()) { return Handle<Code>(function->shared()->code()); } @@ -1013,8 +922,8 @@ MaybeHandle<Code> GetLazyCode(Handle<JSFunction> function) { return entry; } - Zone zone(isolate->allocator()); - ParseInfo parse_info(&zone, function); + Zone zone(isolate->allocator(), ZONE_NAME); + ParseInfo parse_info(&zone, handle(function->shared())); CompilationInfo info(&parse_info, function); Handle<Code> result; ASSIGN_RETURN_ON_EXCEPTION(isolate, result, GetUnoptimizedCode(&info), Code); @@ -1059,50 +968,13 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) { isolate->debug()->OnBeforeCompile(script); - DCHECK(parse_info->is_eval() || parse_info->is_global() || - parse_info->is_module()); - - parse_info->set_toplevel(); - Handle<SharedFunctionInfo> result; { VMState<COMPILER> state(info->isolate()); - if (parse_info->literal() == NULL) { - // Parse the script if needed (if it's already parsed, literal() is - // non-NULL). If compiling for debugging, we may eagerly compile inner - // functions, so do not parse lazily in that case. - ScriptCompiler::CompileOptions options = parse_info->compile_options(); - bool parse_allow_lazy = (options == ScriptCompiler::kConsumeParserCache || - String::cast(script->source())->length() > - FLAG_min_preparse_length) && - !info->is_debug(); - - // Consider parsing eagerly when targeting the code cache. - parse_allow_lazy &= !(FLAG_serialize_eager && info->will_serialize()); - - // Consider parsing eagerly when targeting Ignition. - parse_allow_lazy &= !(FLAG_ignition && FLAG_ignition_eager && - !isolate->serializer_enabled()); - - parse_info->set_allow_lazy_parsing(parse_allow_lazy); - if (!parse_allow_lazy && - (options == ScriptCompiler::kProduceParserCache || - options == ScriptCompiler::kConsumeParserCache)) { - // We are going to parse eagerly, but we either 1) have cached data - // produced by lazy parsing or 2) are asked to generate cached data. - // Eager parsing cannot benefit from cached data, and producing cached - // data while parsing eagerly is not implemented. - parse_info->set_cached_data(nullptr); - parse_info->set_compile_options(ScriptCompiler::kNoCompileOptions); - } - - if (!Parse(parse_info)) { - return Handle<SharedFunctionInfo>::null(); - } + if (parse_info->literal() == nullptr && !Parser::ParseStatic(parse_info)) { + return Handle<SharedFunctionInfo>::null(); } - DCHECK(!info->is_debug() || !parse_info->allow_lazy_parsing()); - FunctionLiteral* lit = parse_info->literal(); // Measure how long it takes to do the compilation; only take the @@ -1122,10 +994,6 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) { DCHECK_EQ(kNoSourcePosition, lit->function_token_position()); result = NewSharedFunctionInfoForLiteral(isolate, lit, script); result->set_is_toplevel(true); - if (parse_info->is_eval()) { - // Eval scripts cannot be (re-)compiled without context. - result->set_allows_lazy_compilation_without_context(false); - } parse_info->set_shared_info(result); // Compile the code. @@ -1133,12 +1001,6 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) { return Handle<SharedFunctionInfo>::null(); } - // Update the shared function info with the scope info. - InstallSharedScopeInfo(info, result); - - // Install compilation result on the shared function info - InstallSharedCompilationResult(info, result); - Handle<String> script_name = script->name()->IsString() ? Handle<String>(String::cast(script->name())) @@ -1173,7 +1035,7 @@ bool Compiler::Analyze(ParseInfo* info) { } bool Compiler::ParseAndAnalyze(ParseInfo* info) { - if (!Parse(info)) return false; + if (!Parser::ParseStatic(info)) return false; if (!Compiler::Analyze(info)) return false; DCHECK_NOT_NULL(info->literal()); DCHECK_NOT_NULL(info->scope()); @@ -1246,8 +1108,8 @@ bool Compiler::CompileOptimized(Handle<JSFunction> function, code = isolate->builtins()->InterpreterEntryTrampoline(); function->shared()->ReplaceCode(*code); } else { - Zone zone(isolate->allocator()); - ParseInfo parse_info(&zone, function); + Zone zone(isolate->allocator(), ZONE_NAME); + ParseInfo parse_info(&zone, handle(function->shared())); CompilationInfo info(&parse_info, function); if (!GetUnoptimizedCode(&info).ToHandle(&code)) { return false; @@ -1266,44 +1128,14 @@ bool Compiler::CompileOptimized(Handle<JSFunction> function, return true; } -bool Compiler::CompileDebugCode(Handle<JSFunction> function) { - Isolate* isolate = function->GetIsolate(); - DCHECK(AllowCompilation::IsAllowed(isolate)); - - // Start a compilation. - Zone zone(isolate->allocator()); - ParseInfo parse_info(&zone, function); - CompilationInfo info(&parse_info, Handle<JSFunction>::null()); - if (IsEvalToplevel(handle(function->shared()))) { - parse_info.set_eval(); - if (function->context()->IsNativeContext()) parse_info.set_global(); - parse_info.set_toplevel(); - parse_info.set_allow_lazy_parsing(false); - parse_info.set_lazy(false); - } - info.MarkAsDebug(); - if (GetUnoptimizedCode(&info).is_null()) { - isolate->clear_pending_exception(); - return false; - } - - // Check postconditions on success. - DCHECK(!isolate->has_pending_exception()); - DCHECK(function->shared()->is_compiled()); - DCHECK(function->shared()->HasDebugCode()); - return true; -} - bool Compiler::CompileDebugCode(Handle<SharedFunctionInfo> shared) { Isolate* isolate = shared->GetIsolate(); DCHECK(AllowCompilation::IsAllowed(isolate)); // Start a compilation. - Zone zone(isolate->allocator()); + Zone zone(isolate->allocator(), ZONE_NAME); ParseInfo parse_info(&zone, shared); CompilationInfo info(&parse_info, Handle<JSFunction>::null()); - DCHECK(shared->allows_lazy_compilation_without_context()); - DCHECK(!IsEvalToplevel(shared)); info.MarkAsDebug(); if (GetUnoptimizedCode(&info).is_null()) { isolate->clear_pending_exception(); @@ -1325,13 +1157,12 @@ MaybeHandle<JSArray> Compiler::CompileForLiveEdit(Handle<Script> script) { // generated shared function infos, clear the script's list temporarily // and restore it at the end of this method. Handle<Object> old_function_infos(script->shared_function_infos(), isolate); - script->set_shared_function_infos(Smi::FromInt(0)); + script->set_shared_function_infos(Smi::kZero); // Start a compilation. - Zone zone(isolate->allocator()); + Zone zone(isolate->allocator(), ZONE_NAME); ParseInfo parse_info(&zone, script); CompilationInfo info(&parse_info, Handle<JSFunction>::null()); - parse_info.set_global(); info.MarkAsDebug(); // TODO(635): support extensions. @@ -1377,7 +1208,7 @@ bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) { DCHECK_NOT_NULL(info->scope()); Handle<SharedFunctionInfo> shared = info->shared_info(); if (!shared->has_deoptimization_support()) { - Zone zone(info->isolate()->allocator()); + Zone zone(info->isolate()->allocator(), ZONE_NAME); CompilationInfo unoptimized(info->parse_info(), info->closure()); unoptimized.EnableDeoptimizationSupport(); @@ -1387,18 +1218,9 @@ bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) { // TurboFan in this case. if (IsResumableFunction(shared->kind())) return false; - // TODO(4280): For now we disable switching to baseline code in the presence - // of interpreter activations of the given function. The reasons is that the - // underlying bytecode is cleared below. The expensive check for activations - // only needs to be done when the given function has bytecode, otherwise we - // can be sure there are no activations. Note that this only applies in case - // the --ignition-preserve-bytecode flag is not passed. - if (!FLAG_ignition_preserve_bytecode && shared->HasBytecodeArray()) { - InterpreterActivationsFinder activations_finder(*shared); - if (HasInterpreterActivations(info->isolate(), &activations_finder)) { - return false; - } - } + // When we call PrepareForSerializing below, we will change the shared + // ParseInfo. Make sure to reset it. + bool old_will_serialize_value = info->parse_info()->will_serialize(); // If the current code has reloc info for serialization, also include // reloc info for serialization for the new code, so that deopt support @@ -1410,13 +1232,7 @@ bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) { EnsureFeedbackMetadata(&unoptimized); if (!FullCodeGenerator::MakeCode(&unoptimized)) return false; - // TODO(4280): For now we play it safe and remove the bytecode array when we - // switch to baseline code. We might consider keeping around the bytecode so - // that it can be used as the "source of truth" eventually. Note that this - // only applies in case the --ignition-preserve-bytecode flag is not passed. - if (!FLAG_ignition_preserve_bytecode && shared->HasBytecodeArray()) { - shared->ClearBytecodeArray(); - } + info->parse_info()->set_will_serialize(old_will_serialize_value); // The scope info might not have been set if a lazily compiled // function is inlined before being called for the first time. @@ -1437,8 +1253,8 @@ bool Compiler::EnsureDeoptimizationSupport(CompilationInfo* info) { // static Compiler::CompilationTier Compiler::NextCompilationTier(JSFunction* function) { Handle<SharedFunctionInfo> shared(function->shared(), function->GetIsolate()); - if (shared->code()->is_interpreter_trampoline_builtin()) { - if (FLAG_turbo_from_bytecode && UseTurboFan(shared)) { + if (shared->IsInterpreted()) { + if (UseTurboFan(shared)) { return OPTIMIZED; } else { return BASELINE; @@ -1468,6 +1284,7 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval( Handle<Script> script; if (!maybe_shared_info.ToHandle(&shared_info)) { script = isolate->factory()->NewScript(source); + if (FLAG_trace_deopt) Script::InitLineEnds(script); if (!script_name.is_null()) { script->set_name(*script_name); script->set_line_offset(line_offset); @@ -1477,11 +1294,10 @@ MaybeHandle<JSFunction> Compiler::GetFunctionFromEval( script->set_compilation_type(Script::COMPILATION_TYPE_EVAL); Script::SetEvalOrigin(script, outer_info, eval_position); - Zone zone(isolate->allocator()); + Zone zone(isolate->allocator(), ZONE_NAME); ParseInfo parse_info(&zone, script); CompilationInfo info(&parse_info, Handle<JSFunction>::null()); parse_info.set_eval(); - if (context->IsNativeContext()) parse_info.set_global(); parse_info.set_language_mode(language_mode); parse_info.set_parse_restriction(restriction); if (!context->IsNativeContext()) { @@ -1628,6 +1444,7 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript( // Create a script object describing the script to be compiled. Handle<Script> script = isolate->factory()->NewScript(source); + if (FLAG_trace_deopt) Script::InitLineEnds(script); if (natives == NATIVES_CODE) { script->set_type(Script::TYPE_NATIVE); script->set_hide_source(true); @@ -1646,14 +1463,10 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForScript( } // Compile the function and add it to the cache. - Zone zone(isolate->allocator()); + Zone zone(isolate->allocator(), ZONE_NAME); ParseInfo parse_info(&zone, script); CompilationInfo info(&parse_info, Handle<JSFunction>::null()); - if (is_module) { - parse_info.set_module(); - } else { - parse_info.set_global(); - } + if (is_module) parse_info.set_module(); if (compile_options != ScriptCompiler::kNoCompileOptions) { parse_info.set_cached_data(cached_data); } @@ -1766,59 +1579,49 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo( result->set_never_compiled(outer_info->shared_info()->never_compiled()); } - Zone zone(isolate->allocator()); + Zone zone(isolate->allocator(), ZONE_NAME); ParseInfo parse_info(&zone, script); CompilationInfo info(&parse_info, Handle<JSFunction>::null()); parse_info.set_literal(literal); parse_info.set_shared_info(result); parse_info.set_language_mode(literal->scope()->language_mode()); + parse_info.set_ast_value_factory( + outer_info->parse_info()->ast_value_factory()); + parse_info.set_ast_value_factory_owned(false); + if (outer_info->will_serialize()) info.PrepareForSerializing(); if (outer_info->is_debug()) info.MarkAsDebug(); - // Determine if the function can be lazily compiled. This is necessary to - // allow some of our builtin JS files to be lazily compiled. These - // builtins cannot be handled lazily by the parser, since we have to know - // if a function uses the special natives syntax, which is something the - // parser records. - // If the debugger requests compilation for break points, we cannot be - // aggressive about lazy compilation, because it might trigger compilation - // of functions without an outer context when setting a breakpoint through - // Debug::FindSharedFunctionInfoInScript. - bool allow_lazy = literal->AllowsLazyCompilation() && !info.is_debug(); - bool lazy = FLAG_lazy && allow_lazy && !literal->should_eager_compile(); - - // Consider compiling eagerly when targeting the code cache. - lazy &= !(FLAG_serialize_eager && info.will_serialize()); - - // Consider compiling eagerly when compiling bytecode for Ignition. - lazy &= - !(FLAG_ignition && FLAG_ignition_eager && !isolate->serializer_enabled()); - - // Generate code - TimerEventScope<TimerEventCompileCode> timer(isolate); - RuntimeCallTimerScope runtimeTimer(isolate, &RuntimeCallStats::CompileCode); - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode"); - - if (lazy) { - info.SetCode(isolate->builtins()->CompileLazy()); - Scope* outer_scope = literal->scope()->GetOuterScopeWithContext(); - if (outer_scope) { - result->set_outer_scope_info(*outer_scope->scope_info()); - } - } else if (Renumber(info.parse_info()) && GenerateUnoptimizedCode(&info)) { - // Code generation will ensure that the feedback vector is present and - // appropriately sized. - DCHECK(!info.code().is_null()); - if (literal->should_eager_compile() && - literal->should_be_used_once_hint()) { - info.code()->MarkToBeExecutedOnce(isolate); + // If this inner function is already compiled, we don't need to compile + // again. When compiling for debug, we are not interested in having debug + // break slots in inner functions, neither for setting break points nor + // for revealing inner functions. + // This is especially important for generators. We must not replace the + // code for generators, as there may be suspended generator objects. + if (!result->is_compiled()) { + if (!literal->ShouldEagerCompile()) { + info.SetCode(isolate->builtins()->CompileLazy()); + Scope* outer_scope = literal->scope()->GetOuterScopeWithContext(); + if (outer_scope) { + result->set_outer_scope_info(*outer_scope->scope_info()); + } + } else { + // Generate code + TimerEventScope<TimerEventCompileCode> timer(isolate); + RuntimeCallTimerScope runtimeTimer(isolate, + &RuntimeCallStats::CompileCode); + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileCode"); + if (Renumber(info.parse_info()) && GenerateUnoptimizedCode(&info)) { + // Code generation will ensure that the feedback vector is present and + // appropriately sized. + DCHECK(!info.code().is_null()); + if (literal->should_be_used_once_hint()) { + info.code()->MarkToBeExecutedOnce(isolate); + } + } else { + return Handle<SharedFunctionInfo>::null(); + } } - // Update the shared function info with the scope info. - InstallSharedScopeInfo(&info, result); - // Install compilation result on the shared function info. - InstallSharedCompilationResult(&info, result); - } else { - return Handle<SharedFunctionInfo>::null(); } if (maybe_existing.is_null()) { @@ -1887,8 +1690,13 @@ bool Compiler::FinalizeCompilationJob(CompilationJob* raw_job) { return FinalizeOptimizedCompilationJob(job.get()) == CompilationJob::SUCCEEDED; } else { - return FinalizeUnoptimizedCompilationJob(job.get()) == - CompilationJob::SUCCEEDED; + if (FinalizeUnoptimizedCompilationJob(job.get()) == + CompilationJob::SUCCEEDED) { + RecordFunctionCompilation(CodeEventListener::LAZY_COMPILE_TAG, + job->info()); + return true; + } + return false; } } |