Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Unified Diff: src/compiler.cc

Issue 110203002: Refactor the compiling pipeline. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: addressed comments Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler.h ('k') | src/debug.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler.cc
diff --git a/src/compiler.cc b/src/compiler.cc
index c6dfa045b744a82da959c177e090546488322398..b9fe9870d6750a5383c72b955195bb9b4c2a4bb0 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -59,7 +59,6 @@ CompilationInfo::CompilationInfo(Handle<Script> script,
: flags_(LanguageModeField::encode(CLASSIC_MODE)),
script_(script),
osr_ast_id_(BailoutId::None()),
- osr_pc_offset_(0),
parameter_count_(0) {
Initialize(script->GetIsolate(), BASE, zone);
}
@@ -71,7 +70,6 @@ CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info,
shared_info_(shared_info),
script_(Handle<Script>(Script::cast(shared_info->script()))),
osr_ast_id_(BailoutId::None()),
- osr_pc_offset_(0),
parameter_count_(0) {
Initialize(script_->GetIsolate(), BASE, zone);
}
@@ -85,7 +83,6 @@ CompilationInfo::CompilationInfo(Handle<JSFunction> closure,
script_(Handle<Script>(Script::cast(shared_info_->script()))),
context_(closure->context()),
osr_ast_id_(BailoutId::None()),
- osr_pc_offset_(0),
parameter_count_(0) {
Initialize(script_->GetIsolate(), BASE, zone);
}
@@ -97,7 +94,6 @@ CompilationInfo::CompilationInfo(HydrogenCodeStub* stub,
: flags_(LanguageModeField::encode(CLASSIC_MODE) |
IsLazy::encode(true)),
osr_ast_id_(BailoutId::None()),
- osr_pc_offset_(0),
parameter_count_(0) {
Initialize(isolate, STUB, zone);
code_stub_ = stub;
@@ -243,86 +239,6 @@ bool CompilationInfo::ShouldSelfOptimize() {
}
-// Determine whether to use the full compiler for all code. If the flag
-// --always-full-compiler is specified this is the case. For the virtual frame
-// based compiler the full compiler is also used if a debugger is connected, as
-// the code from the full compiler supports mode precise break points. For the
-// crankshaft adaptive compiler debugging the optimized code is not possible at
-// all. However crankshaft support recompilation of functions, so in this case
-// the full compiler need not be be used if a debugger is attached, but only if
-// break points has actually been set.
-static bool IsDebuggerActive(Isolate* isolate) {
-#ifdef ENABLE_DEBUGGER_SUPPORT
- return isolate->use_crankshaft() ?
- isolate->debug()->has_break_points() :
- isolate->debugger()->IsDebuggerActive();
-#else
- return false;
-#endif
-}
-
-
-static bool AlwaysFullCompiler(Isolate* isolate) {
- return FLAG_always_full_compiler || IsDebuggerActive(isolate);
-}
-
-
-void RecompileJob::RecordOptimizationStats() {
- Handle<JSFunction> function = info()->closure();
- if (!function->IsOptimized()) {
- // Concurrent recompilation and OSR may race. Increment only once.
- int opt_count = function->shared()->opt_count();
- function->shared()->set_opt_count(opt_count + 1);
- }
- double ms_creategraph = time_taken_to_create_graph_.InMillisecondsF();
- double ms_optimize = time_taken_to_optimize_.InMillisecondsF();
- double ms_codegen = time_taken_to_codegen_.InMillisecondsF();
- if (FLAG_trace_opt) {
- PrintF("[optimizing ");
- function->ShortPrint();
- PrintF(" - took %0.3f, %0.3f, %0.3f ms]\n", ms_creategraph, ms_optimize,
- ms_codegen);
- }
- if (FLAG_trace_opt_stats) {
- static double compilation_time = 0.0;
- static int compiled_functions = 0;
- static int code_size = 0;
-
- compilation_time += (ms_creategraph + ms_optimize + ms_codegen);
- compiled_functions++;
- code_size += function->shared()->SourceSize();
- PrintF("Compiled: %d functions with %d byte source size in %fms.\n",
- compiled_functions,
- code_size,
- compilation_time);
- }
- if (FLAG_hydrogen_stats) {
- isolate()->GetHStatistics()->IncrementSubtotals(time_taken_to_create_graph_,
- time_taken_to_optimize_,
- time_taken_to_codegen_);
- }
-}
-
-
-// A return value of true indicates the compilation pipeline is still
-// going, not necessarily that we optimized the code.
-static bool MakeCrankshaftCode(CompilationInfo* info) {
- RecompileJob job(info);
- RecompileJob::Status status = job.CreateGraph();
-
- if (status != RecompileJob::SUCCEEDED) {
- return status != RecompileJob::FAILED;
- }
- status = job.OptimizeGraph();
- if (status != RecompileJob::SUCCEEDED) {
- status = job.AbortOptimization();
- return status != RecompileJob::FAILED;
- }
- status = job.GenerateAndInstallCode();
- return status != RecompileJob::FAILED;
-}
-
-
class HOptimizedGraphBuilderWithPositions: public HOptimizedGraphBuilder {
public:
explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info)
@@ -360,7 +276,26 @@ class HOptimizedGraphBuilderWithPositions: public HOptimizedGraphBuilder {
};
-RecompileJob::Status RecompileJob::CreateGraph() {
+// Determine whether to use the full compiler for all code. If the flag
+// --always-full-compiler is specified this is the case. For the virtual frame
+// based compiler the full compiler is also used if a debugger is connected, as
+// the code from the full compiler supports mode precise break points. For the
+// crankshaft adaptive compiler debugging the optimized code is not possible at
+// all. However crankshaft support recompilation of functions, so in this case
+// the full compiler need not be be used if a debugger is attached, but only if
+// break points has actually been set.
+static bool IsDebuggerActive(Isolate* isolate) {
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ return isolate->use_crankshaft() ?
+ isolate->debug()->has_break_points() :
+ isolate->debugger()->IsDebuggerActive();
+#else
+ return false;
+#endif
+}
+
+
+OptimizedCompileJob::Status OptimizedCompileJob::CreateGraph() {
ASSERT(isolate()->use_crankshaft());
ASSERT(info()->IsOptimizing());
ASSERT(!info()->IsCompilingForDebugging());
@@ -376,18 +311,15 @@ RecompileJob::Status RecompileJob::CreateGraph() {
// Fall back to using the full code generator if it's not possible
// to use the Hydrogen-based optimizing compiler. We already have
// generated code for this from the shared function object.
- if (AlwaysFullCompiler(isolate())) {
- info()->AbortOptimization();
- return SetLastStatus(BAILED_OUT);
- }
+ if (FLAG_always_full_compiler) return AbortOptimization();
+ if (IsDebuggerActive(isolate())) return AbortOptimization(kDebuggerIsActive);
// Limit the number of times we re-compile a functions with
// the optimizing compiler.
const int kMaxOptCount =
FLAG_deopt_every_n_times == 0 ? FLAG_max_opt_count : 1000;
if (info()->opt_count() > kMaxOptCount) {
- info()->set_bailout_reason(kOptimizedTooManyTimes);
- return AbortOptimization();
+ return AbortAndDisableOptimization(kOptimizedTooManyTimes);
}
// Due to an encoding limit on LUnallocated operands in the Lithium
@@ -400,21 +332,18 @@ RecompileJob::Status RecompileJob::CreateGraph() {
const int parameter_limit = -LUnallocated::kMinFixedSlotIndex;
Scope* scope = info()->scope();
if ((scope->num_parameters() + 1) > parameter_limit) {
- info()->set_bailout_reason(kTooManyParameters);
- return AbortOptimization();
+ return AbortAndDisableOptimization(kTooManyParameters);
}
const int locals_limit = LUnallocated::kMaxFixedSlotIndex;
if (info()->is_osr() &&
scope->num_parameters() + 1 + scope->num_stack_slots() > locals_limit) {
- info()->set_bailout_reason(kTooManyParametersLocals);
- return AbortOptimization();
+ return AbortAndDisableOptimization(kTooManyParametersLocals);
}
// Take --hydrogen-filter into account.
if (!info()->closure()->PassesFilter(FLAG_hydrogen_filter)) {
- info()->AbortOptimization();
- return SetLastStatus(BAILED_OUT);
+ return AbortOptimization(kHydrogenFilter);
}
// Recompile the unoptimized version of the code if the current version
@@ -474,7 +403,6 @@ RecompileJob::Status RecompileJob::CreateGraph() {
graph_ = graph_builder_->CreateGraph();
if (isolate()->has_pending_exception()) {
- info()->SetCode(Handle<Code>::null());
return SetLastStatus(FAILED);
}
@@ -484,24 +412,21 @@ RecompileJob::Status RecompileJob::CreateGraph() {
ASSERT(!graph_builder_->inline_bailout() || graph_ == NULL);
if (graph_ == NULL) {
if (graph_builder_->inline_bailout()) {
- info_->AbortOptimization();
- return SetLastStatus(BAILED_OUT);
- } else {
return AbortOptimization();
+ } else {
+ return AbortAndDisableOptimization();
}
}
if (info()->HasAbortedDueToDependencyChange()) {
- info_->set_bailout_reason(kBailedOutDueToDependencyChange);
- info_->AbortOptimization();
- return SetLastStatus(BAILED_OUT);
+ return AbortOptimization(kBailedOutDueToDependencyChange);
}
return SetLastStatus(SUCCEEDED);
}
-RecompileJob::Status RecompileJob::OptimizeGraph() {
+OptimizedCompileJob::Status OptimizedCompileJob::OptimizeGraph() {
DisallowHeapAllocation no_allocation;
DisallowHandleAllocation no_handles;
DisallowHandleDereference no_deref;
@@ -511,20 +436,19 @@ RecompileJob::Status RecompileJob::OptimizeGraph() {
Timer t(this, &time_taken_to_optimize_);
ASSERT(graph_ != NULL);
BailoutReason bailout_reason = kNoReason;
- if (!graph_->Optimize(&bailout_reason)) {
- if (bailout_reason != kNoReason) graph_builder_->Bailout(bailout_reason);
- return SetLastStatus(BAILED_OUT);
- } else {
+
+ if (graph_->Optimize(&bailout_reason)) {
chunk_ = LChunk::NewChunk(graph_);
- if (chunk_ == NULL) {
- return SetLastStatus(BAILED_OUT);
- }
+ if (chunk_ != NULL) return SetLastStatus(SUCCEEDED);
+ } else if (bailout_reason != kNoReason) {
+ graph_builder_->Bailout(bailout_reason);
}
- return SetLastStatus(SUCCEEDED);
+
+ return AbortOptimization();
}
-RecompileJob::Status RecompileJob::GenerateAndInstallCode() {
+OptimizedCompileJob::Status OptimizedCompileJob::GenerateCode() {
ASSERT(last_status() == SUCCEEDED);
ASSERT(!info()->HasAbortedDueToDependencyChange());
DisallowCodeDependencyChange no_dependency_change;
@@ -540,9 +464,9 @@ RecompileJob::Status RecompileJob::GenerateAndInstallCode() {
Handle<Code> optimized_code = chunk_->Codegen();
if (optimized_code.is_null()) {
if (info()->bailout_reason() == kNoReason) {
- info()->set_bailout_reason(kCodeGenerationFailed);
+ info_->set_bailout_reason(kCodeGenerationFailed);
}
- return AbortOptimization();
+ return AbortAndDisableOptimization();
}
info()->SetCode(optimized_code);
}
@@ -553,54 +477,40 @@ RecompileJob::Status RecompileJob::GenerateAndInstallCode() {
}
-static bool GenerateCode(CompilationInfo* info) {
- bool is_optimizing = info->isolate()->use_crankshaft() &&
- !info->IsCompilingForDebugging() &&
- info->IsOptimizing();
- if (is_optimizing) {
- Logger::TimerEventScope timer(
- info->isolate(), Logger::TimerEventScope::v8_recompile_synchronous);
- return MakeCrankshaftCode(info);
- } else {
- if (info->IsOptimizing()) {
- // Have the CompilationInfo decide if the compilation should be
- // BASE or NONOPT.
- info->DisableOptimization();
- }
- Logger::TimerEventScope timer(
- info->isolate(), Logger::TimerEventScope::v8_compile_full_code);
- return FullCodeGenerator::MakeCode(info);
+void OptimizedCompileJob::RecordOptimizationStats() {
+ Handle<JSFunction> function = info()->closure();
+ if (!function->IsOptimized()) {
+ // Concurrent recompilation and OSR may race. Increment only once.
+ int opt_count = function->shared()->opt_count();
+ function->shared()->set_opt_count(opt_count + 1);
}
-}
-
-
-static bool MakeCode(CompilationInfo* info) {
- // Precondition: code has been parsed. Postcondition: the code field in
- // the compilation info is set if compilation succeeded.
- ASSERT(info->function() != NULL);
- return Rewriter::Rewrite(info) && Scope::Analyze(info) && GenerateCode(info);
-}
-
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
-bool Compiler::MakeCodeForLiveEdit(CompilationInfo* info) {
- // Precondition: code has been parsed. Postcondition: the code field in
- // the compilation info is set if compilation succeeded.
- bool succeeded = MakeCode(info);
- if (!info->shared_info().is_null()) {
- Handle<ScopeInfo> scope_info = ScopeInfo::Create(info->scope(),
- info->zone());
- info->shared_info()->set_scope_info(*scope_info);
+ double ms_creategraph = time_taken_to_create_graph_.InMillisecondsF();
+ double ms_optimize = time_taken_to_optimize_.InMillisecondsF();
+ double ms_codegen = time_taken_to_codegen_.InMillisecondsF();
+ if (FLAG_trace_opt) {
+ PrintF("[optimizing ");
+ function->ShortPrint();
+ PrintF(" - took %0.3f, %0.3f, %0.3f ms]\n", ms_creategraph, ms_optimize,
+ ms_codegen);
}
- return succeeded;
-}
-#endif
-
+ if (FLAG_trace_opt_stats) {
+ static double compilation_time = 0.0;
+ static int compiled_functions = 0;
+ static int code_size = 0;
-static bool DebuggerWantsEagerCompilation(CompilationInfo* info,
- bool allow_lazy_without_ctx = false) {
- return LiveEditFunctionTracker::IsActive(info->isolate()) ||
- (info->isolate()->DebuggerHasBreakPoints() && !allow_lazy_without_ctx);
+ compilation_time += (ms_creategraph + ms_optimize + ms_codegen);
+ compiled_functions++;
+ code_size += function->shared()->SourceSize();
+ PrintF("Compiled: %d functions with %d byte source size in %fms.\n",
+ compiled_functions,
+ code_size,
+ compilation_time);
+ }
+ if (FLAG_hydrogen_stats) {
+ isolate()->GetHStatistics()->IncrementSubtotals(time_taken_to_create_graph_,
+ time_taken_to_optimize_,
+ time_taken_to_codegen_);
+ }
}
@@ -631,148 +541,378 @@ void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared,
}
-static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
- Isolate* isolate = info->isolate();
- PostponeInterruptsScope postpone(isolate);
+static void UpdateSharedFunctionInfo(CompilationInfo* info) {
+ // Update the shared function info with the compiled code and the
+ // scope info. Please note, that the order of the shared function
+ // info initialization is important since set_scope_info might
+ // trigger a GC, causing the ASSERT below to be invalid if the code
+ // was flushed. By setting the code object last we avoid this.
+ Handle<SharedFunctionInfo> shared = info->shared_info();
+ Handle<ScopeInfo> scope_info =
+ ScopeInfo::Create(info->scope(), info->zone());
+ shared->set_scope_info(*scope_info);
- ASSERT(!isolate->native_context().is_null());
- Handle<Script> script = info->script();
- // TODO(svenpanne) Obscure place for this, perhaps move to OnBeforeCompile?
- FixedArray* array = isolate->native_context()->embedder_data();
- script->set_context_data(array->get(0));
+ Handle<Code> code = info->code();
+ CHECK(code->kind() == Code::FUNCTION);
+ shared->ReplaceCode(*code);
+ if (shared->optimization_disabled()) code->set_optimizable(false);
-#ifdef ENABLE_DEBUGGER_SUPPORT
- if (info->is_eval()) {
- script->set_compilation_type(Script::COMPILATION_TYPE_EVAL);
- // For eval scripts add information on the function from which eval was
- // called.
- if (info->is_eval()) {
- StackTraceFrameIterator it(isolate);
- if (!it.done()) {
- script->set_eval_from_shared(it.frame()->function()->shared());
- Code* code = it.frame()->LookupCode();
- int offset = static_cast<int>(
- it.frame()->pc() - code->instruction_start());
- script->set_eval_from_instructions_offset(Smi::FromInt(offset));
- }
- }
- }
+ // Set the expected number of properties for instances.
+ FunctionLiteral* lit = info->function();
+ int expected = lit->expected_property_count();
+ SetExpectedNofPropertiesFromEstimate(shared, expected);
- // Notify debugger
- isolate->debugger()->OnBeforeCompile(script);
-#endif
+ // Check the function has compiled code.
+ ASSERT(shared->is_compiled());
+ shared->set_dont_optimize_reason(lit->dont_optimize_reason());
+ shared->set_dont_inline(lit->flags()->Contains(kDontInline));
+ shared->set_ast_node_count(lit->ast_node_count());
+ shared->set_language_mode(lit->language_mode());
+}
- // Only allow non-global compiles for eval.
- ASSERT(info->is_eval() || info->is_global());
- {
- Parser parser(info);
- if ((info->pre_parse_data() != NULL ||
- String::cast(script->source())->length() > FLAG_min_preparse_length) &&
- !DebuggerWantsEagerCompilation(info))
- parser.set_allow_lazy(true);
- if (!parser.Parse()) {
- return Handle<SharedFunctionInfo>::null();
- }
+
+// Sets the function info on a function.
+// The start_position points to the first '(' character after the function name
+// in the full script source. When counting characters in the script source the
+// the first character is number 0 (not 1).
+static void SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
+ FunctionLiteral* lit,
+ bool is_toplevel,
+ Handle<Script> script) {
+ function_info->set_length(lit->parameter_count());
+ function_info->set_formal_parameter_count(lit->parameter_count());
+ function_info->set_script(*script);
+ function_info->set_function_token_position(lit->function_token_position());
+ function_info->set_start_position(lit->start_position());
+ function_info->set_end_position(lit->end_position());
+ function_info->set_is_expression(lit->is_expression());
+ function_info->set_is_anonymous(lit->is_anonymous());
+ function_info->set_is_toplevel(is_toplevel);
+ function_info->set_inferred_name(*lit->inferred_name());
+ function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
+ function_info->set_allows_lazy_compilation_without_context(
+ lit->AllowsLazyCompilationWithoutContext());
+ function_info->set_language_mode(lit->language_mode());
+ function_info->set_uses_arguments(lit->scope()->arguments() != NULL);
+ function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
+ function_info->set_ast_node_count(lit->ast_node_count());
+ function_info->set_is_function(lit->is_function());
+ function_info->set_dont_optimize_reason(lit->dont_optimize_reason());
+ function_info->set_dont_inline(lit->flags()->Contains(kDontInline));
+ function_info->set_dont_cache(lit->flags()->Contains(kDontCache));
+ function_info->set_is_generator(lit->is_generator());
+}
+
+
+static bool CompileUnoptimizedCode(CompilationInfo* info) {
+ ASSERT(info->function() != NULL);
+ if (!Rewriter::Rewrite(info)) return false;
+ if (!Scope::Analyze(info)) return false;
+ ASSERT(info->scope() != NULL);
+
+ if (!FullCodeGenerator::MakeCode(info)) {
+ Isolate* isolate = info->isolate();
+ if (!isolate->has_pending_exception()) isolate->StackOverflow();
+ return false;
}
+ return true;
+}
- FunctionLiteral* lit = info->function();
- LiveEditFunctionTracker live_edit_tracker(isolate, lit);
- Handle<SharedFunctionInfo> result;
- {
- // Measure how long it takes to do the compilation; only take the
- // rest of the function into account to avoid overlap with the
- // parsing statistics.
- HistogramTimer* rate = info->is_eval()
- ? info->isolate()->counters()->compile_eval()
- : info->isolate()->counters()->compile();
- HistogramTimerScope timer(rate);
- // Compile the code.
- if (!MakeCode(info)) {
- if (!isolate->has_pending_exception()) isolate->StackOverflow();
- return Handle<SharedFunctionInfo>::null();
- }
+static Handle<Code> GetUnoptimizedCodeCommon(CompilationInfo* info) {
+ VMState<COMPILER> state(info->isolate());
+ PostponeInterruptsScope postpone(info->isolate());
+ if (!Parser::Parse(info)) return Handle<Code>::null();
+ LanguageMode language_mode = info->function()->language_mode();
+ info->SetLanguageMode(language_mode);
- // Allocate function.
- ASSERT(!info->code().is_null());
- result =
- isolate->factory()->NewSharedFunctionInfo(
- lit->name(),
- lit->materialized_literal_count(),
- lit->is_generator(),
- info->code(),
- ScopeInfo::Create(info->scope(), info->zone()));
+ if (!CompileUnoptimizedCode(info)) return Handle<Code>::null();
+ Compiler::RecordFunctionCompilation(
+ Logger::LAZY_COMPILE_TAG, info, info->shared_info());
+ UpdateSharedFunctionInfo(info);
+ ASSERT_EQ(Code::FUNCTION, info->code()->kind());
+ return info->code();
+}
- ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
- Compiler::SetFunctionInfo(result, lit, true, script);
-
- if (script->name()->IsString()) {
- PROFILE(isolate, CodeCreateEvent(
- info->is_eval()
- ? Logger::EVAL_TAG
- : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
- *info->code(),
- *result,
- info,
- String::cast(script->name())));
- GDBJIT(AddCode(Handle<String>(String::cast(script->name())),
- script,
- info->code(),
- info));
- } else {
- PROFILE(isolate, CodeCreateEvent(
- info->is_eval()
- ? Logger::EVAL_TAG
- : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
- *info->code(),
- *result,
- info,
- isolate->heap()->empty_string()));
- GDBJIT(AddCode(Handle<String>(), script, info->code(), info));
- }
- // Hint to the runtime system used when allocating space for initial
- // property space by setting the expected number of properties for
- // the instances of the function.
- SetExpectedNofPropertiesFromEstimate(result,
- lit->expected_property_count());
+Handle<Code> Compiler::GetUnoptimizedCode(Handle<JSFunction> function) {
+ ASSERT(!function->GetIsolate()->has_pending_exception());
+ ASSERT(!function->is_compiled());
+ if (function->shared()->is_compiled()) {
+ return Handle<Code>(function->shared()->code());
+ }
- script->set_compilation_state(Script::COMPILATION_STATE_COMPILED);
+ CompilationInfoWithZone info(function);
+ Handle<Code> result = GetUnoptimizedCodeCommon(&info);
+ ASSERT_EQ(result.is_null(), info.isolate()->has_pending_exception());
+
+ if (FLAG_always_opt &&
+ info.isolate()->use_crankshaft() &&
+ !info.shared_info()->optimization_disabled() &&
+ !info.isolate()->DebuggerHasBreakPoints()) {
+ Handle<Code> opt_code = Compiler::GetOptimizedCode(
+ function, result, Compiler::NOT_CONCURRENT);
+ if (!opt_code.is_null()) result = opt_code;
}
-#ifdef ENABLE_DEBUGGER_SUPPORT
- // Notify debugger
- isolate->debugger()->OnAfterCompile(
- script, Debugger::NO_AFTER_COMPILE_FLAGS);
-#endif
+ return result;
+}
- live_edit_tracker.RecordFunctionInfo(result, lit, info->zone());
+Handle<Code> Compiler::GetUnoptimizedCode(Handle<SharedFunctionInfo> shared) {
+ ASSERT(!shared->GetIsolate()->has_pending_exception());
+ ASSERT(!shared->is_compiled());
+
+ CompilationInfoWithZone info(shared);
+ Handle<Code> result = GetUnoptimizedCodeCommon(&info);
+ ASSERT_EQ(result.is_null(), info.isolate()->has_pending_exception());
return result;
}
-Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
- Handle<Object> script_name,
- int line_offset,
- int column_offset,
- bool is_shared_cross_origin,
- Handle<Context> context,
- v8::Extension* extension,
- ScriptDataImpl* pre_data,
- Handle<Object> script_data,
- NativesFlag natives) {
- Isolate* isolate = source->GetIsolate();
- int source_length = source->length();
- isolate->counters()->total_load_size()->Increment(source_length);
- isolate->counters()->total_compile_size()->Increment(source_length);
+bool Compiler::EnsureCompiled(Handle<JSFunction> function,
+ ClearExceptionFlag flag) {
+ if (function->is_compiled()) return true;
+ Handle<Code> code = Compiler::GetUnoptimizedCode(function);
+ if (code.is_null()) {
+ if (flag == CLEAR_EXCEPTION) {
+ function->GetIsolate()->clear_pending_exception();
+ }
+ return false;
+ }
+ function->ReplaceCode(*code);
+ ASSERT(function->is_compiled());
+ return true;
+}
- // The VM is in the COMPILER state until exiting this function.
+
+// Compile full code for debugging. This code will have debug break slots
+// and deoptimization information. Deoptimization information is required
+// in case that an optimized version of this function is still activated on
+// the stack. It will also make sure that the full code is compiled with
+// the same flags as the previous version, that is flags which can change
+// the code generated. The current method of mapping from already compiled
+// full code without debug break slots to full code with debug break slots
+// depends on the generated code is otherwise exactly the same.
+// If compilation fails, just keep the existing code.
+Handle<Code> Compiler::GetCodeForDebugging(Handle<JSFunction> function) {
+ CompilationInfoWithZone info(function);
+ Isolate* isolate = info.isolate();
VMState<COMPILER> state(isolate);
- CompilationCache* compilation_cache = isolate->compilation_cache();
+ ASSERT(!isolate->has_pending_exception());
+ Handle<Code> old_code(function->shared()->code());
+ ASSERT(old_code->kind() == Code::FUNCTION);
+ ASSERT(!old_code->has_debug_break_slots());
+
+ info.MarkCompilingForDebugging();
+ if (old_code->is_compiled_optimizable()) {
+ info.EnableDeoptimizationSupport();
+ } else {
+ info.MarkNonOptimizable();
+ }
+ Handle<Code> new_code = GetUnoptimizedCodeCommon(&info);
+ if (new_code.is_null()) {
+ isolate->clear_pending_exception();
+ } else {
+ ASSERT_EQ(old_code->is_compiled_optimizable(),
+ new_code->is_compiled_optimizable());
+ }
+ return new_code;
+}
+
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+void Compiler::CompileForLiveEdit(Handle<Script> script) {
+ // TODO(635): support extensions.
+ CompilationInfoWithZone info(script);
+ VMState<COMPILER> state(info.isolate());
+
+ info.MarkAsGlobal();
+ if (!Parser::Parse(&info)) return;
+ LanguageMode language_mode = info.function()->language_mode();
+ info.SetLanguageMode(language_mode);
+
+ LiveEditFunctionTracker tracker(info.isolate(), info.function());
+ if (!CompileUnoptimizedCode(&info)) return;
+ if (!info.shared_info().is_null()) {
+ Handle<ScopeInfo> scope_info = ScopeInfo::Create(info.scope(),
+ info.zone());
+ info.shared_info()->set_scope_info(*scope_info);
+ }
+ tracker.RecordRootFunctionInfo(info.code());
+}
+#endif
+
+
+static bool DebuggerWantsEagerCompilation(CompilationInfo* info,
+ bool allow_lazy_without_ctx = false) {
+ return LiveEditFunctionTracker::IsActive(info->isolate()) ||
+ (info->isolate()->DebuggerHasBreakPoints() && !allow_lazy_without_ctx);
+}
+
+
+static Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
+ Isolate* isolate = info->isolate();
+ ASSERT(!isolate->native_context().is_null());
+ Handle<Script> script = info->script();
+
+ // TODO(svenpanne) Obscure place for this, perhaps move to OnBeforeCompile?
+ FixedArray* array = isolate->native_context()->embedder_data();
+ script->set_context_data(array->get(0));
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ isolate->debugger()->OnBeforeCompile(script);
+#endif
+
+ ASSERT(info->is_eval() || info->is_global());
+
+ bool parse_allow_lazy =
+ (info->pre_parse_data() != NULL ||
+ String::cast(script->source())->length() > FLAG_min_preparse_length) &&
+ !DebuggerWantsEagerCompilation(info);
- // Do a lookup in the compilation cache but not for extensions.
+ Handle<SharedFunctionInfo> result;
+
+ { VMState<COMPILER> state(info->isolate());
+ if (!Parser::Parse(info, parse_allow_lazy)) {
+ return Handle<SharedFunctionInfo>::null();
+ }
+
+ FunctionLiteral* lit = info->function();
+ LiveEditFunctionTracker live_edit_tracker(isolate, lit);
+
+ // Measure how long it takes to do the compilation; only take the
+ // rest of the function into account to avoid overlap with the
+ // parsing statistics.
+ HistogramTimer* rate = info->is_eval()
+ ? info->isolate()->counters()->compile_eval()
+ : info->isolate()->counters()->compile();
+ HistogramTimerScope timer(rate);
+
+ // Compile the code.
+ if (!CompileUnoptimizedCode(info)) {
+ return Handle<SharedFunctionInfo>::null();
+ }
+
+ // Allocate function.
+ ASSERT(!info->code().is_null());
+ result = isolate->factory()->NewSharedFunctionInfo(
+ lit->name(),
+ lit->materialized_literal_count(),
+ lit->is_generator(),
+ info->code(),
+ ScopeInfo::Create(info->scope(), info->zone()));
+
+ ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
+ SetFunctionInfo(result, lit, true, script);
+
+ Handle<String> script_name = script->name()->IsString()
+ ? Handle<String>(String::cast(script->name()))
+ : isolate->factory()->empty_string();
+ Logger::LogEventsAndTags log_tag = info->is_eval()
+ ? Logger::EVAL_TAG
+ : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script);
+
+ PROFILE(isolate, CodeCreateEvent(
+ log_tag, *info->code(), *result, info, *script_name));
+ GDBJIT(AddCode(script_name, script, info->code(), info));
+
+ // Hint to the runtime system used when allocating space for initial
+ // property space by setting the expected number of properties for
+ // the instances of the function.
+ SetExpectedNofPropertiesFromEstimate(result,
+ lit->expected_property_count());
+
+ script->set_compilation_state(Script::COMPILATION_STATE_COMPILED);
+
+ live_edit_tracker.RecordFunctionInfo(result, lit, info->zone());
+ }
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ isolate->debugger()->OnAfterCompile(script, Debugger::NO_AFTER_COMPILE_FLAGS);
+#endif
+
+ return result;
+}
+
+
+Handle<JSFunction> Compiler::GetFunctionFromEval(Handle<String> source,
+ Handle<Context> context,
+ LanguageMode language_mode,
+ ParseRestriction restriction,
+ int scope_position) {
+ Isolate* isolate = source->GetIsolate();
+ int source_length = source->length();
+ isolate->counters()->total_eval_size()->Increment(source_length);
+ isolate->counters()->total_compile_size()->Increment(source_length);
+
+ CompilationCache* compilation_cache = isolate->compilation_cache();
+ Handle<SharedFunctionInfo> shared_info = compilation_cache->LookupEval(
+ source, context, language_mode, scope_position);
+
+ if (shared_info.is_null()) {
+ Handle<Script> script = isolate->factory()->NewScript(source);
+ CompilationInfoWithZone info(script);
+ info.MarkAsEval();
+ if (context->IsNativeContext()) info.MarkAsGlobal();
+ info.SetLanguageMode(language_mode);
+ info.SetParseRestriction(restriction);
+ info.SetContext(context);
+
+#if ENABLE_DEBUGGER_SUPPORT
+ Debug::RecordEvalCaller(script);
+#endif // ENABLE_DEBUGGER_SUPPORT
+
+ shared_info = CompileToplevel(&info);
+
+ if (shared_info.is_null()) {
+ return Handle<JSFunction>::null();
+ } else {
+ // Explicitly disable optimization for eval code. We're not yet prepared
+ // to handle eval-code in the optimizing compiler.
+ shared_info->DisableOptimization(kEval);
+
+ // If caller is strict mode, the result must be in strict mode or
+ // extended mode as well, but not the other way around. Consider:
+ // eval("'use strict'; ...");
+ ASSERT(language_mode != STRICT_MODE || !shared_info->is_classic_mode());
+ // If caller is in extended mode, the result must also be in
+ // extended mode.
+ ASSERT(language_mode != EXTENDED_MODE ||
+ shared_info->is_extended_mode());
+ if (!shared_info->dont_cache()) {
+ compilation_cache->PutEval(
+ source, context, shared_info, scope_position);
+ }
+ }
+ } else if (shared_info->ic_age() != isolate->heap()->global_ic_age()) {
+ shared_info->ResetForNewContext(isolate->heap()->global_ic_age());
+ }
+
+ return isolate->factory()->NewFunctionFromSharedFunctionInfo(
+ shared_info, context, NOT_TENURED);
+}
+
+
+Handle<SharedFunctionInfo> Compiler::CompileScript(Handle<String> source,
+ Handle<Object> script_name,
+ int line_offset,
+ int column_offset,
+ bool is_shared_cross_origin,
+ Handle<Context> context,
+ v8::Extension* extension,
+ ScriptDataImpl* pre_data,
+ Handle<Object> script_data,
+ NativesFlag natives) {
+ Isolate* isolate = source->GetIsolate();
+ int source_length = source->length();
+ isolate->counters()->total_load_size()->Increment(source_length);
+ isolate->counters()->total_compile_size()->Increment(source_length);
+
+ CompilationCache* compilation_cache = isolate->compilation_cache();
+
+ // Do a lookup in the compilation cache but not for extensions.
Handle<SharedFunctionInfo> result;
if (extension == NULL) {
result = compilation_cache->LookupScript(source,
@@ -817,14 +957,12 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
if (FLAG_use_strict) {
info.SetLanguageMode(FLAG_harmony_scoping ? EXTENDED_MODE : STRICT_MODE);
}
- result = MakeFunctionInfo(&info);
+ result = CompileToplevel(&info);
if (extension == NULL && !result.is_null() && !result->dont_cache()) {
compilation_cache->PutScript(source, context, result);
}
- } else {
- if (result->ic_age() != isolate->heap()->global_ic_age()) {
+ } else if (result->ic_age() != isolate->heap()->global_ic_age()) {
result->ResetForNewContext(isolate->heap()->global_ic_age());
- }
}
if (result.is_null()) isolate->ReportPendingMessages();
@@ -832,130 +970,82 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
}
-Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
- Handle<Context> context,
- bool is_global,
- LanguageMode language_mode,
- ParseRestriction restriction,
- int scope_position) {
- Isolate* isolate = source->GetIsolate();
- int source_length = source->length();
- isolate->counters()->total_eval_size()->Increment(source_length);
- isolate->counters()->total_compile_size()->Increment(source_length);
-
- // The VM is in the COMPILER state until exiting this function.
- VMState<COMPILER> state(isolate);
-
- // Do a lookup in the compilation cache; if the entry is not there, invoke
- // the compiler and add the result to the cache.
- Handle<SharedFunctionInfo> result;
- CompilationCache* compilation_cache = isolate->compilation_cache();
- result = compilation_cache->LookupEval(source,
- context,
- is_global,
- language_mode,
- scope_position);
+Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
+ Handle<Script> script) {
+ // Precondition: code has been parsed and scopes have been analyzed.
+ CompilationInfoWithZone info(script);
+ info.SetFunction(literal);
+ info.SetScope(literal->scope());
+ info.SetLanguageMode(literal->scope()->language_mode());
- if (result.is_null()) {
- // Create a script object describing the script to be compiled.
- Handle<Script> script = isolate->factory()->NewScript(source);
- CompilationInfoWithZone info(script);
- info.MarkAsEval();
- if (is_global) info.MarkAsGlobal();
- info.SetLanguageMode(language_mode);
- info.SetParseRestriction(restriction);
- info.SetContext(context);
- result = MakeFunctionInfo(&info);
- if (!result.is_null()) {
- // Explicitly disable optimization for eval code. We're not yet prepared
- // to handle eval-code in the optimizing compiler.
- result->DisableOptimization(kEval);
+ Isolate* isolate = info.isolate();
+ Factory* factory = isolate->factory();
+ LiveEditFunctionTracker live_edit_tracker(isolate, literal);
+ // 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_without_ctx = literal->AllowsLazyCompilationWithoutContext();
+ bool allow_lazy = literal->AllowsLazyCompilation() &&
+ !DebuggerWantsEagerCompilation(&info, allow_lazy_without_ctx);
- // If caller is strict mode, the result must be in strict mode or
- // extended mode as well, but not the other way around. Consider:
- // eval("'use strict'; ...");
- ASSERT(language_mode != STRICT_MODE || !result->is_classic_mode());
- // If caller is in extended mode, the result must also be in
- // extended mode.
- ASSERT(language_mode != EXTENDED_MODE ||
- result->is_extended_mode());
- if (!result->dont_cache()) {
- compilation_cache->PutEval(
- source, context, is_global, result, scope_position);
- }
- }
+ // Generate code
+ Handle<ScopeInfo> scope_info;
+ if (FLAG_lazy && allow_lazy && !literal->is_parenthesized()) {
+ Handle<Code> code = isolate->builtins()->CompileUnoptimized();
+ info.SetCode(code);
+ scope_info = Handle<ScopeInfo>(ScopeInfo::Empty(isolate));
+ } else if (FullCodeGenerator::MakeCode(&info)) {
+ ASSERT(!info.code().is_null());
+ scope_info = ScopeInfo::Create(info.scope(), info.zone());
} else {
- if (result->ic_age() != isolate->heap()->global_ic_age()) {
- result->ResetForNewContext(isolate->heap()->global_ic_age());
- }
+ return Handle<SharedFunctionInfo>::null();
}
+ // Create a shared function info object.
+ Handle<SharedFunctionInfo> result =
+ factory->NewSharedFunctionInfo(literal->name(),
+ literal->materialized_literal_count(),
+ literal->is_generator(),
+ info.code(),
+ scope_info);
+ SetFunctionInfo(result, literal, false, script);
+ RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result);
+ result->set_allows_lazy_compilation(allow_lazy);
+ result->set_allows_lazy_compilation_without_context(allow_lazy_without_ctx);
+
+ // Set the expected number of properties for instances and return
+ // the resulting function.
+ SetExpectedNofPropertiesFromEstimate(result,
+ literal->expected_property_count());
+ live_edit_tracker.RecordFunctionInfo(result, literal, info.zone());
return result;
}
-static bool InstallFullCode(CompilationInfo* info) {
- // Update the shared function info with the compiled code and the
- // scope info. Please note, that the order of the shared function
- // info initialization is important since set_scope_info might
- // trigger a GC, causing the ASSERT below to be invalid if the code
- // was flushed. By setting the code object last we avoid this.
- Handle<SharedFunctionInfo> shared = info->shared_info();
- Handle<Code> code = info->code();
- CHECK(code->kind() == Code::FUNCTION);
- Handle<JSFunction> function = info->closure();
- Handle<ScopeInfo> scope_info =
- ScopeInfo::Create(info->scope(), info->zone());
- shared->set_scope_info(*scope_info);
- shared->ReplaceCode(*code);
- if (!function.is_null()) {
- function->ReplaceCode(*code);
- ASSERT(!function->IsOptimized());
- }
-
- // Set the expected number of properties for instances.
- FunctionLiteral* lit = info->function();
- int expected = lit->expected_property_count();
- SetExpectedNofPropertiesFromEstimate(shared, expected);
-
- // Check the function has compiled code.
- ASSERT(shared->is_compiled());
- shared->set_dont_optimize_reason(lit->dont_optimize_reason());
- shared->set_dont_inline(lit->flags()->Contains(kDontInline));
- shared->set_ast_node_count(lit->ast_node_count());
-
- if (info->isolate()->use_crankshaft() &&
- !function.is_null() &&
- !shared->optimization_disabled()) {
- // If we're asked to always optimize, we compile the optimized
- // version of the function right away - unless the debugger is
- // active as it makes no sense to compile optimized code then.
- if (FLAG_always_opt &&
- !info->isolate()->DebuggerHasBreakPoints()) {
- CompilationInfoWithZone optimized(function);
- optimized.SetOptimizing(BailoutId::None());
- return Compiler::CompileLazy(&optimized);
+static Handle<Code> GetCodeFromOptimizedCodeMap(Handle<JSFunction> function) {
+ if (FLAG_cache_optimized_code) {
+ Handle<SharedFunctionInfo> shared(function->shared());
+ DisallowHeapAllocation no_gc;
+ int index = shared->SearchOptimizedCodeMap(
+ function->context()->native_context());
+ if (index > 0) {
+ if (FLAG_trace_opt) {
+ PrintF("[found optimized code for ");
+ function->ShortPrint();
+ PrintF("]\n");
+ }
+ FixedArray* literals = shared->GetLiteralsFromOptimizedCodeMap(index);
+ if (literals != NULL) function->set_literals(literals);
+ return Handle<Code>(shared->GetCodeFromOptimizedCodeMap(index));
}
}
- return true;
-}
-
-
-static void InstallCodeCommon(CompilationInfo* info) {
- Handle<SharedFunctionInfo> shared = info->shared_info();
- Handle<Code> code = info->code();
- ASSERT(!code.is_null());
-
- // Set optimizable to false if this is disallowed by the shared
- // function info, e.g., we might have flushed the code and must
- // reset this bit when lazy compiling the code again.
- if (shared->optimization_disabled()) code->set_optimizable(false);
-
- if (shared->code() == *code) {
- // Do not send compilation event for the same code twice.
- return;
- }
- Compiler::RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info, shared);
+ return Handle<Code>::null();
}
@@ -975,317 +1065,162 @@ static void InsertCodeIntoOptimizedCodeMap(CompilationInfo* info) {
}
-static bool InstallCodeFromOptimizedCodeMap(CompilationInfo* info) {
- if (!info->IsOptimizing()) return false; // Nothing to look up.
+static bool CompileOptimizedPrologue(CompilationInfo* info) {
+ if (!Parser::Parse(info)) return false;
+ LanguageMode language_mode = info->function()->language_mode();
+ info->SetLanguageMode(language_mode);
- // Lookup non-OSR optimized code.
- if (FLAG_cache_optimized_code && !info->is_osr()) {
- Handle<SharedFunctionInfo> shared = info->shared_info();
- Handle<JSFunction> function = info->closure();
- ASSERT(!function.is_null());
- Handle<Context> native_context(function->context()->native_context());
- int index = shared->SearchOptimizedCodeMap(*native_context);
- if (index > 0) {
- if (FLAG_trace_opt) {
- PrintF("[found optimized code for ");
- function->ShortPrint();
- PrintF("]\n");
- }
- // Caching of optimized code enabled and optimized code found.
- shared->InstallFromOptimizedCodeMap(*function, index);
- return true;
- }
- }
- return false;
+ if (!Rewriter::Rewrite(info)) return false;
+ if (!Scope::Analyze(info)) return false;
+ ASSERT(info->scope() != NULL);
+ return true;
}
-bool Compiler::CompileLazy(CompilationInfo* info) {
- Isolate* isolate = info->isolate();
-
- // The VM is in the COMPILER state until exiting this function.
- VMState<COMPILER> state(isolate);
-
- PostponeInterruptsScope postpone(isolate);
-
- Handle<SharedFunctionInfo> shared = info->shared_info();
- int compiled_size = shared->end_position() - shared->start_position();
- isolate->counters()->total_compile_size()->Increment(compiled_size);
-
- if (InstallCodeFromOptimizedCodeMap(info)) return true;
-
- // Generate the AST for the lazily compiled function.
- if (Parser::Parse(info)) {
- // Measure how long it takes to do the lazy compilation; only take the
- // rest of the function into account to avoid overlap with the lazy
- // parsing statistics.
- HistogramTimerScope timer(isolate->counters()->compile_lazy());
-
- // After parsing we know the function's language mode. Remember it.
- LanguageMode language_mode = info->function()->language_mode();
- info->SetLanguageMode(language_mode);
- shared->set_language_mode(language_mode);
+static bool GetOptimizedCodeNow(CompilationInfo* info) {
+ if (!CompileOptimizedPrologue(info)) return false;
- // Compile the code.
- if (!MakeCode(info)) {
- if (!isolate->has_pending_exception()) {
- isolate->StackOverflow();
- }
- } else {
- InstallCodeCommon(info);
-
- if (info->IsOptimizing()) {
- // Optimized code successfully created.
- Handle<Code> code = info->code();
- ASSERT(shared->scope_info() != ScopeInfo::Empty(isolate));
- // TODO(titzer): Only replace the code if it was not an OSR compile.
- info->closure()->ReplaceCode(*code);
- InsertCodeIntoOptimizedCodeMap(info);
- return true;
- } else if (!info->is_osr()) {
- // Compilation failed. Replace with full code if not OSR compile.
- return InstallFullCode(info);
- }
- }
- }
-
- ASSERT(info->code().is_null());
- return false;
+ Logger::TimerEventScope timer(
+ info->isolate(), Logger::TimerEventScope::v8_recompile_synchronous);
+
+ OptimizedCompileJob job(info);
+ if (job.CreateGraph() != OptimizedCompileJob::SUCCEEDED) return false;
+ if (job.OptimizeGraph() != OptimizedCompileJob::SUCCEEDED) return false;
+ if (job.GenerateCode() != OptimizedCompileJob::SUCCEEDED) return false;
+
+ // Success!
+ ASSERT(!info->isolate()->has_pending_exception());
+ InsertCodeIntoOptimizedCodeMap(info);
+ Compiler::RecordFunctionCompilation(
+ Logger::LAZY_COMPILE_TAG, info, info->shared_info());
+ return true;
}
-bool Compiler::RecompileConcurrent(Handle<JSFunction> closure,
- Handle<Code> unoptimized,
- uint32_t osr_pc_offset) {
- bool compiling_for_osr = (osr_pc_offset != 0);
-
- Isolate* isolate = closure->GetIsolate();
- // Here we prepare compile data for the concurrent recompilation thread, but
- // this still happens synchronously and interrupts execution.
- Logger::TimerEventScope timer(
- isolate, Logger::TimerEventScope::v8_recompile_synchronous);
-
+static bool GetOptimizedCodeLater(CompilationInfo* info) {
+ Isolate* isolate = info->isolate();
if (!isolate->optimizing_compiler_thread()->IsQueueAvailable()) {
if (FLAG_trace_concurrent_recompilation) {
PrintF(" ** Compilation queue full, will retry optimizing ");
- closure->PrintName();
- PrintF(" on next run.\n");
+ info->closure()->PrintName();
+ PrintF(" later.\n");
}
return false;
}
- SmartPointer<CompilationInfo> info(new CompilationInfoWithZone(closure));
- Handle<SharedFunctionInfo> shared = info->shared_info();
+ CompilationHandleScope handle_scope(info);
+ if (!CompileOptimizedPrologue(info)) return false;
+ info->SaveHandles(); // Copy handles to the compilation handle scope.
+
+ Logger::TimerEventScope timer(
+ isolate, Logger::TimerEventScope::v8_recompile_synchronous);
- if (compiling_for_osr) {
- BailoutId osr_ast_id = unoptimized->TranslatePcOffsetToAstId(osr_pc_offset);
- ASSERT(!osr_ast_id.IsNone());
- info->SetOptimizing(osr_ast_id);
- info->SetOsrInfo(unoptimized, osr_pc_offset);
+ OptimizedCompileJob* job = new(info->zone()) OptimizedCompileJob(info);
+ OptimizedCompileJob::Status status = job->CreateGraph();
+ if (status != OptimizedCompileJob::SUCCEEDED) return false;
+ isolate->optimizing_compiler_thread()->QueueForOptimization(job);
- if (FLAG_trace_osr) {
- PrintF("[COSR - attempt to queue ");
- closure->PrintName();
- PrintF(" at AST id %d]\n", osr_ast_id.ToInt());
+ if (FLAG_trace_concurrent_recompilation) {
+ PrintF(" ** Queued ");
+ info->closure()->PrintName();
+ if (info->is_osr()) {
+ PrintF(" for concurrent OSR at %d.\n", info->osr_ast_id().ToInt());
+ } else {
+ PrintF(" for concurrent optimization.\n");
}
- } else {
- info->SetOptimizing(BailoutId::None());
}
+ return true;
+}
+
+Handle<Code> Compiler::GetOptimizedCode(Handle<JSFunction> function,
+ Handle<Code> current_code,
+ ConcurrencyMode mode,
+ BailoutId osr_ast_id) {
+ if (osr_ast_id.IsNone()) { // No cache for OSR.
+ Handle<Code> cached_code = GetCodeFromOptimizedCodeMap(function);
+ if (!cached_code.is_null()) return cached_code;
+ }
+
+ SmartPointer<CompilationInfo> info(new CompilationInfoWithZone(function));
+ Isolate* isolate = info->isolate();
VMState<COMPILER> state(isolate);
+ ASSERT(!isolate->has_pending_exception());
PostponeInterruptsScope postpone(isolate);
+ Handle<SharedFunctionInfo> shared = info->shared_info();
+ ASSERT_NE(ScopeInfo::Empty(isolate), shared->scope_info());
int compiled_size = shared->end_position() - shared->start_position();
isolate->counters()->total_compile_size()->Increment(compiled_size);
+ current_code->set_profiler_ticks(0);
- {
- CompilationHandleScope handle_scope(info.get());
+ info->SetOptimizing(osr_ast_id, current_code);
- if (!compiling_for_osr && InstallCodeFromOptimizedCodeMap(info.get())) {
- return true;
+ if (mode == CONCURRENT) {
+ if (GetOptimizedCodeLater(info.get())) {
+ info.Detach(); // The background recompile job owns this now.
+ return isolate->builtins()->InOptimizationQueue();
}
+ } else {
+ if (GetOptimizedCodeNow(info.get())) return info->code();
+ }
- if (Parser::Parse(info.get())) {
- LanguageMode language_mode = info->function()->language_mode();
- info->SetLanguageMode(language_mode);
- shared->set_language_mode(language_mode);
- info->SaveHandles();
-
- if (Rewriter::Rewrite(info.get()) && Scope::Analyze(info.get())) {
- RecompileJob* job = new(info->zone()) RecompileJob(info.get());
- RecompileJob::Status status = job->CreateGraph();
- if (status == RecompileJob::SUCCEEDED) {
- info.Detach();
- unoptimized->set_profiler_ticks(0);
- isolate->optimizing_compiler_thread()->QueueForOptimization(job);
- ASSERT(!isolate->has_pending_exception());
- return true;
- } else if (status == RecompileJob::BAILED_OUT) {
- isolate->clear_pending_exception();
- InstallFullCode(info.get());
- }
- }
- }
+ // Failed.
+ if (FLAG_trace_opt) {
+ PrintF("[failed to optimize ");
+ function->PrintName();
+ PrintF("]\n");
}
if (isolate->has_pending_exception()) isolate->clear_pending_exception();
- return false;
+ return Handle<Code>::null();
}
-Handle<Code> Compiler::InstallOptimizedCode(RecompileJob* job) {
+Handle<Code> Compiler::GetConcurrentlyOptimizedCode(OptimizedCompileJob* job) {
+ // Take ownership of compilation info. Deleting compilation info
+ // also tears down the zone and the recompile job.
SmartPointer<CompilationInfo> info(job->info());
- // The function may have already been optimized by OSR. Simply continue.
- // Except when OSR already disabled optimization for some reason.
- if (info->shared_info()->optimization_disabled()) {
- info->AbortOptimization();
- InstallFullCode(info.get());
- if (FLAG_trace_concurrent_recompilation) {
- PrintF(" ** aborting optimization for ");
- info->closure()->PrintName();
- PrintF(" as it has been disabled.\n");
- }
- ASSERT(!info->closure()->IsInRecompileQueue());
- return Handle<Code>::null();
- }
-
Isolate* isolate = info->isolate();
+
VMState<COMPILER> state(isolate);
Logger::TimerEventScope timer(
isolate, Logger::TimerEventScope::v8_recompile_synchronous);
- // If crankshaft succeeded, install the optimized code else install
- // the unoptimized code.
- RecompileJob::Status status = job->last_status();
- if (info->HasAbortedDueToDependencyChange()) {
- info->set_bailout_reason(kBailedOutDueToDependencyChange);
- status = job->AbortOptimization();
- } else if (status != RecompileJob::SUCCEEDED) {
- info->set_bailout_reason(kFailedBailedOutLastTime);
- status = job->AbortOptimization();
- } else if (isolate->DebuggerHasBreakPoints()) {
- info->set_bailout_reason(kDebuggerIsActive);
- status = job->AbortOptimization();
- } else {
- status = job->GenerateAndInstallCode();
- ASSERT(status == RecompileJob::SUCCEEDED ||
- status == RecompileJob::BAILED_OUT);
- }
- InstallCodeCommon(info.get());
- if (status == RecompileJob::SUCCEEDED) {
- Handle<Code> code = info->code();
- ASSERT(info->shared_info()->scope_info() != ScopeInfo::Empty(isolate));
- info->closure()->ReplaceCode(*code);
- if (info->shared_info()->SearchOptimizedCodeMap(
- info->closure()->context()->native_context()) == -1) {
- InsertCodeIntoOptimizedCodeMap(info.get());
- }
- if (FLAG_trace_concurrent_recompilation) {
- PrintF(" ** Optimized code for ");
- info->closure()->PrintName();
- PrintF(" installed.\n");
- }
- } else {
- info->AbortOptimization();
- InstallFullCode(info.get());
+ Handle<SharedFunctionInfo> shared = info->shared_info();
+ shared->code()->set_profiler_ticks(0);
+
+ // 1) Optimization may have failed.
+ // 2) The function may have already been optimized by OSR. Simply continue.
+ // Except when OSR already disabled optimization for some reason.
+ // 3) The code may have already been invalidated due to dependency change.
+ // 4) Debugger may have been activated.
+
+ if (job->last_status() != OptimizedCompileJob::SUCCEEDED ||
+ shared->optimization_disabled() ||
+ info->HasAbortedDueToDependencyChange() ||
+ isolate->DebuggerHasBreakPoints()) {
+ return Handle<Code>::null();
}
- // Optimized code is finally replacing unoptimized code. Reset the latter's
- // profiler ticks to prevent too soon re-opt after a deopt.
- info->shared_info()->code()->set_profiler_ticks(0);
- ASSERT(!info->closure()->IsInRecompileQueue());
- return (status == RecompileJob::SUCCEEDED) ? info->code()
- : Handle<Code>::null();
-}
-
-Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
- Handle<Script> script) {
- // Precondition: code has been parsed and scopes have been analyzed.
- CompilationInfoWithZone info(script);
- info.SetFunction(literal);
- info.SetScope(literal->scope());
- info.SetLanguageMode(literal->scope()->language_mode());
-
- Isolate* isolate = info.isolate();
- Factory* factory = isolate->factory();
- LiveEditFunctionTracker live_edit_tracker(isolate, literal);
- // 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_without_ctx = literal->AllowsLazyCompilationWithoutContext();
- bool allow_lazy = literal->AllowsLazyCompilation() &&
- !DebuggerWantsEagerCompilation(&info, allow_lazy_without_ctx);
-
- Handle<ScopeInfo> scope_info(ScopeInfo::Empty(isolate));
-
- // Generate code
- if (FLAG_lazy && allow_lazy && !literal->is_parenthesized()) {
- Handle<Code> code = isolate->builtins()->LazyCompile();
- info.SetCode(code);
- } else if (GenerateCode(&info)) {
- ASSERT(!info.code().is_null());
- scope_info = ScopeInfo::Create(info.scope(), info.zone());
- } else {
- return Handle<SharedFunctionInfo>::null();
+ if (job->GenerateCode() != OptimizedCompileJob::SUCCEEDED) {
+ return Handle<Code>::null();
}
- // Create a shared function info object.
- Handle<SharedFunctionInfo> result =
- factory->NewSharedFunctionInfo(literal->name(),
- literal->materialized_literal_count(),
- literal->is_generator(),
- info.code(),
- scope_info);
- SetFunctionInfo(result, literal, false, script);
- RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, result);
- result->set_allows_lazy_compilation(allow_lazy);
- result->set_allows_lazy_compilation_without_context(allow_lazy_without_ctx);
-
- // Set the expected number of properties for instances and return
- // the resulting function.
- SetExpectedNofPropertiesFromEstimate(result,
- literal->expected_property_count());
- live_edit_tracker.RecordFunctionInfo(result, literal, info.zone());
- return result;
-}
+ Compiler::RecordFunctionCompilation(
+ Logger::LAZY_COMPILE_TAG, info.get(), shared);
+ if (info->shared_info()->SearchOptimizedCodeMap(
+ info->context()->native_context()) == -1) {
+ InsertCodeIntoOptimizedCodeMap(info.get());
+ }
+ if (FLAG_trace_concurrent_recompilation) {
+ PrintF(" ** Optimized code for ");
+ info->closure()->PrintName();
+ PrintF(" generated.\n");
+ }
-// Sets the function info on a function.
-// The start_position points to the first '(' character after the function name
-// in the full script source. When counting characters in the script source the
-// the first character is number 0 (not 1).
-void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
- FunctionLiteral* lit,
- bool is_toplevel,
- Handle<Script> script) {
- function_info->set_length(lit->parameter_count());
- function_info->set_formal_parameter_count(lit->parameter_count());
- function_info->set_script(*script);
- function_info->set_function_token_position(lit->function_token_position());
- function_info->set_start_position(lit->start_position());
- function_info->set_end_position(lit->end_position());
- function_info->set_is_expression(lit->is_expression());
- function_info->set_is_anonymous(lit->is_anonymous());
- function_info->set_is_toplevel(is_toplevel);
- function_info->set_inferred_name(*lit->inferred_name());
- function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
- function_info->set_allows_lazy_compilation_without_context(
- lit->AllowsLazyCompilationWithoutContext());
- function_info->set_language_mode(lit->language_mode());
- function_info->set_uses_arguments(lit->scope()->arguments() != NULL);
- function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
- function_info->set_ast_node_count(lit->ast_node_count());
- function_info->set_is_function(lit->is_function());
- function_info->set_dont_optimize_reason(lit->dont_optimize_reason());
- function_info->set_dont_inline(lit->flags()->Contains(kDontInline));
- function_info->set_dont_cache(lit->flags()->Contains(kDontCache));
- function_info->set_is_generator(lit->is_generator());
+ return Handle<Code>(*info->code());
}
@@ -1302,31 +1237,18 @@ void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag,
info->isolate()->cpu_profiler()->is_profiling()) {
Handle<Script> script = info->script();
Handle<Code> code = info->code();
- if (*code == info->isolate()->builtins()->builtin(Builtins::kLazyCompile))
+ if (code.is_identical_to(info->isolate()->builtins()->CompileUnoptimized()))
return;
int line_num = GetScriptLineNumber(script, shared->start_position()) + 1;
int column_num =
GetScriptColumnNumber(script, shared->start_position()) + 1;
USE(line_num);
- if (script->name()->IsString()) {
- PROFILE(info->isolate(),
- CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
- *code,
- *shared,
- info,
- String::cast(script->name()),
- line_num,
- column_num));
- } else {
- PROFILE(info->isolate(),
- CodeCreateEvent(Logger::ToNativeByScript(tag, *script),
- *code,
- *shared,
- info,
- info->isolate()->heap()->empty_string(),
- line_num,
- column_num));
- }
+ String* script_name = script->name()->IsString()
+ ? String::cast(script->name())
+ : info->isolate()->heap()->empty_string();
+ Logger::LogEventsAndTags log_tag = Logger::ToNativeByScript(tag, *script);
+ PROFILE(info->isolate(), CodeCreateEvent(
+ log_tag, *code, *shared, info, script_name, line_num, column_num));
}
GDBJIT(AddCode(Handle<String>(shared->DebugName()),
« no previous file with comments | « src/compiler.h ('k') | src/debug.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698