Index: src/compiler.cc |
diff --git a/src/compiler.cc b/src/compiler.cc |
index 127f6d544ee5754e975fb2d4e5b5d0727add106e..6cc09713d61191b3c9f5f826fd14b62fd6b0a398 100755 |
--- a/src/compiler.cc |
+++ b/src/compiler.cc |
@@ -92,81 +92,57 @@ static bool AlwaysFullCompiler() { |
} |
-static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) { |
- FunctionLiteral* function = info->function(); |
- ASSERT(function != NULL); |
- // Rewrite the AST by introducing .result assignments where needed. |
- if (!Rewriter::Process(function)) { |
- // Signal a stack overflow by returning a null handle. The stack |
- // overflow exception will be thrown by the caller. |
- return Handle<Code>::null(); |
- } |
- |
- { |
- // Compute top scope and allocate variables. For lazy compilation |
- // the top scope only contains the single lazily compiled function, |
- // so this doesn't re-allocate variables repeatedly. |
- HistogramTimerScope timer(&Counters::variable_allocation); |
- Scope* top = info->scope(); |
- while (top->outer_scope() != NULL) top = top->outer_scope(); |
- top->AllocateVariables(context); |
- } |
- |
-#ifdef DEBUG |
- if (Bootstrapper::IsActive() ? |
- FLAG_print_builtin_scopes : |
- FLAG_print_scopes) { |
- info->scope()->Print(); |
- } |
-#endif |
- |
- // Optimize the AST. |
- if (!Rewriter::Optimize(function)) { |
- // Signal a stack overflow by returning a null handle. The stack |
- // overflow exception will be thrown by the caller. |
- return Handle<Code>::null(); |
- } |
- |
- // Generate code and return it. Code generator selection is governed by |
- // which backends are enabled and whether the function is considered |
- // run-once code or not: |
- // |
- // --full-compiler enables the dedicated backend for code we expect to be |
- // run once |
- // |
- // The normal choice of backend can be overridden with the flags |
- // --always-full-compiler. |
- Handle<SharedFunctionInfo> shared = info->shared_info(); |
- bool is_run_once = (shared.is_null()) |
- ? info->scope()->is_global_scope() |
- : (shared->is_toplevel() || shared->try_full_codegen()); |
- bool use_full = FLAG_full_compiler && !function->contains_loops(); |
- if (AlwaysFullCompiler() || (use_full && is_run_once)) { |
- return FullCodeGenerator::MakeCode(info); |
+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); |
+ |
+ if (Rewriter::Rewrite(info) && |
+ Scope::Analyze(info) && |
+ Rewriter::Analyze(info)) { |
+ // Generate code and return it. Code generator selection is governed by |
+ // which backends are enabled and whether the function is considered |
+ // run-once code or not. |
+ // |
+ // --full-compiler enables the dedicated backend for code we expect to |
+ // be run once |
+ // |
+ // The normal choice of backend can be overridden with the flags |
+ // --always-full-compiler. |
+ Handle<SharedFunctionInfo> shared = info->shared_info(); |
+ bool is_run_once = (shared.is_null()) |
+ ? info->scope()->is_global_scope() |
+ : (shared->is_toplevel() || shared->try_full_codegen()); |
+ bool can_use_full = |
+ FLAG_full_compiler && !info->function()->contains_loops(); |
+ if (AlwaysFullCompiler() || (is_run_once && can_use_full)) { |
+ return FullCodeGenerator::MakeCode(info); |
+ } else { |
+ AssignedVariablesAnalyzer ava; |
+ return ava.Analyze(info) && CodeGenerator::MakeCode(info); |
+ } |
} |
- AssignedVariablesAnalyzer ava(function); |
- if (!ava.Analyze()) return Handle<Code>::null(); |
- return CodeGenerator::MakeCode(info); |
+ return false; |
} |
#ifdef ENABLE_DEBUGGER_SUPPORT |
-Handle<Code> MakeCodeForLiveEdit(CompilationInfo* info) { |
- Handle<Context> context = Handle<Context>::null(); |
- Handle<Code> code = MakeCode(context, info); |
+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<SerializedScopeInfo> scope_info = |
SerializedScopeInfo::Create(info->scope()); |
info->shared_info()->set_scope_info(*scope_info); |
} |
- return code; |
+ return succeeded; |
} |
#endif |
-static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info, |
- Handle<Context> context) { |
+static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { |
CompilationZoneScope zone_scope(DELETE_ON_EXIT); |
PostponeInterruptsScope postpone; |
@@ -215,34 +191,32 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info, |
// Compile the code. |
FunctionLiteral* lit = info->function(); |
LiveEditFunctionTracker live_edit_tracker(lit); |
- Handle<Code> code = MakeCode(context, info); |
- |
- // Check for stack-overflow exceptions. |
- if (code.is_null()) { |
+ if (!MakeCode(info)) { |
Top::StackOverflow(); |
return Handle<SharedFunctionInfo>::null(); |
} |
+ ASSERT(!info->code().is_null()); |
if (script->name()->IsString()) { |
PROFILE(CodeCreateEvent( |
info->is_eval() |
? Logger::EVAL_TAG |
: Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), |
- *code, |
+ *info->code(), |
String::cast(script->name()))); |
OPROFILE(CreateNativeCodeRegion(String::cast(script->name()), |
- code->instruction_start(), |
- code->instruction_size())); |
+ info->code()->instruction_start(), |
+ info->code()->instruction_size())); |
} else { |
PROFILE(CodeCreateEvent( |
info->is_eval() |
? Logger::EVAL_TAG |
: Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), |
- *code, |
+ *info->code(), |
"")); |
OPROFILE(CreateNativeCodeRegion(info->is_eval() ? "Eval" : "Script", |
- code->instruction_start(), |
- code->instruction_size())); |
+ info->code()->instruction_start(), |
+ info->code()->instruction_size())); |
} |
// Allocate function. |
@@ -250,7 +224,7 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info, |
Factory::NewSharedFunctionInfo( |
lit->name(), |
lit->materialized_literal_count(), |
- code, |
+ info->code(), |
SerializedScopeInfo::Create(info->scope())); |
ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position()); |
@@ -331,7 +305,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, |
info.MarkAsGlobal(); |
info.SetExtension(extension); |
info.SetPreParseData(pre_data); |
- result = MakeFunctionInfo(&info, Handle<Context>::null()); |
+ result = MakeFunctionInfo(&info); |
if (extension == NULL && !result.is_null()) { |
CompilationCache::PutScript(source, result); |
} |
@@ -379,7 +353,8 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, |
info.MarkAsEval(); |
if (is_global) info.MarkAsGlobal(); |
if (is_json) info.MarkAsJson(); |
- result = MakeFunctionInfo(&info, context); |
+ info.SetCallingContext(context); |
+ result = MakeFunctionInfo(&info); |
if (!result.is_null() && !is_json) { |
// For json it's unlikely that we'll ever see exactly the same string |
// again so we don't use the compilation cache. |
@@ -399,126 +374,122 @@ bool Compiler::CompileLazy(CompilationInfo* info) { |
PostponeInterruptsScope postpone; |
- // Compute name, source code and script data. |
Handle<SharedFunctionInfo> shared = info->shared_info(); |
int compiled_size = shared->end_position() - shared->start_position(); |
Counters::total_compile_size.Increment(compiled_size); |
// Generate the AST for the lazily compiled function. |
- if (!Parser::Parse(info)) return false; |
- |
- // 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(&Counters::compile_lazy); |
- |
- // Compile the code. |
- Handle<Code> code = MakeCode(Handle<Context>::null(), info); |
- |
- // Check for stack-overflow exception. |
- if (code.is_null()) { |
- Top::StackOverflow(); |
- return false; |
- } |
+ 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(&Counters::compile_lazy); |
+ |
+ // Compile the code. |
+ if (!MakeCode(info)) { |
+ Top::StackOverflow(); |
+ } else { |
+ ASSERT(!info->code().is_null()); |
+ RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, |
+ Handle<String>(shared->DebugName()), |
+ shared->start_position(), |
+ info); |
+ |
+ // Update the shared function info with the compiled code and the |
+ // scope info. Please note, that the order of the sharedfunction |
+ // initialization is important since SerializedScopeInfo::Create 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<SerializedScopeInfo> scope_info = |
+ SerializedScopeInfo::Create(info->scope()); |
+ shared->set_scope_info(*scope_info); |
+ shared->set_code(*info->code()); |
+ if (!info->closure().is_null()) { |
+ info->closure()->set_code(*info->code()); |
+ } |
- RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, |
- Handle<String>(String::cast(shared->name())), |
- Handle<String>(shared->inferred_name()), |
- shared->start_position(), |
- info->script(), |
- code); |
- |
- // Update the shared function info with the compiled code and the scope info. |
- // Please note, that the order of the sharedfunction initialization is |
- // important since SerializedScopeInfo::Create 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<SerializedScopeInfo> scope_info = |
- SerializedScopeInfo::Create(info->scope()); |
- shared->set_scope_info(*scope_info); |
- shared->set_code(*code); |
- if (!info->closure().is_null()) { |
- info->closure()->set_code(*code); |
+ // Set the expected number of properties for instances. |
+ FunctionLiteral* lit = info->function(); |
+ SetExpectedNofPropertiesFromEstimate(shared, |
+ lit->expected_property_count()); |
+ |
+ // Set the optimization hints after performing lazy compilation, as |
+ // these are not set when the function is set up as a lazily compiled |
+ // function. |
+ shared->SetThisPropertyAssignmentsInfo( |
+ lit->has_only_simple_this_property_assignments(), |
+ *lit->this_property_assignments()); |
+ |
+ // Check the function has compiled code. |
+ ASSERT(shared->is_compiled()); |
+ shared->set_code_age(0); |
+ ASSERT(!info->code().is_null()); |
+ return true; |
+ } |
} |
- // Set the expected number of properties for instances. |
- FunctionLiteral* lit = info->function(); |
- SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count()); |
- |
- // Set the optimication hints after performing lazy compilation, as these are |
- // not set when the function is set up as a lazily compiled function. |
- shared->SetThisPropertyAssignmentsInfo( |
- lit->has_only_simple_this_property_assignments(), |
- *lit->this_property_assignments()); |
- |
- // Check the function has compiled code. |
- ASSERT(shared->is_compiled()); |
- shared->set_code_age(0); |
- return true; |
+ ASSERT(info->code().is_null()); |
+ return false; |
} |
Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, |
- Handle<Script> script, |
- AstVisitor* caller) { |
- LiveEditFunctionTracker live_edit_tracker(literal); |
+ Handle<Script> script) { |
#ifdef DEBUG |
// We should not try to compile the same function literal more than |
// once. |
literal->mark_as_compiled(); |
#endif |
- // 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. |
+ // Precondition: code has been parsed and scopes have been analyzed. |
+ CompilationInfo info(script); |
+ info.SetFunction(literal); |
+ info.SetScope(literal->scope()); |
+ |
+ LiveEditFunctionTracker live_edit_tracker(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. |
bool allow_lazy = literal->AllowsLazyCompilation() && |
!LiveEditFunctionTracker::IsActive(); |
Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty()); |
// Generate code |
- Handle<Code> code; |
if (FLAG_lazy && allow_lazy) { |
- code = Handle<Code>(Builtins::builtin(Builtins::LazyCompile)); |
+ Handle<Code> code(Builtins::builtin(Builtins::LazyCompile)); |
+ info.SetCode(code); |
} else { |
- // The bodies of function literals have not yet been visited by |
- // the AST optimizer/analyzer. |
- if (!Rewriter::Optimize(literal)) { |
- return Handle<SharedFunctionInfo>::null(); |
- } |
- |
// Generate code and return it. The way that the compilation mode |
// is controlled by the command-line flags is described in |
// the static helper function MakeCode. |
- CompilationInfo info(script); |
- info.SetFunction(literal); |
+ // |
+ // The bodies of function literals have not yet been visited by |
+ // the AST analyzer. |
+ if (!Rewriter::Analyze(&info)) return Handle<SharedFunctionInfo>::null(); |
bool is_run_once = literal->try_full_codegen(); |
bool use_full = FLAG_full_compiler && !literal->contains_loops(); |
if (AlwaysFullCompiler() || (use_full && is_run_once)) { |
- code = FullCodeGenerator::MakeCode(&info); |
+ if (!FullCodeGenerator::MakeCode(&info)) { |
+ return Handle<SharedFunctionInfo>::null(); |
+ } |
} else { |
// We fall back to the classic V8 code generator. |
- AssignedVariablesAnalyzer ava(literal); |
- if (!ava.Analyze()) return Handle<SharedFunctionInfo>::null(); |
- code = CodeGenerator::MakeCode(&info); |
- } |
- |
- // Check for stack-overflow exception. |
- if (code.is_null()) { |
- caller->SetStackOverflow(); |
- return Handle<SharedFunctionInfo>::null(); |
+ AssignedVariablesAnalyzer ava; |
+ if (!ava.Analyze(&info)) return Handle<SharedFunctionInfo>::null(); |
+ if (!CodeGenerator::MakeCode(&info)) { |
+ return Handle<SharedFunctionInfo>::null(); |
+ } |
} |
// Function compilation complete. |
RecordFunctionCompilation(Logger::FUNCTION_TAG, |
- literal->name(), |
- literal->inferred_name(), |
+ literal->debug_name(), |
literal->start_position(), |
- script, |
- code); |
+ &info); |
scope_info = SerializedScopeInfo::Create(info.scope()); |
} |
@@ -526,7 +497,7 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal, |
Handle<SharedFunctionInfo> result = |
Factory::NewSharedFunctionInfo(literal->name(), |
literal->materialized_literal_count(), |
- code, |
+ info.code(), |
scope_info); |
SetFunctionInfo(result, literal, false, script); |
@@ -566,32 +537,34 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info, |
void Compiler::RecordFunctionCompilation(Logger::LogEventsAndTags tag, |
Handle<String> name, |
- Handle<String> inferred_name, |
int start_position, |
- Handle<Script> script, |
- Handle<Code> code) { |
- // Log the code generation. If source information is available |
- // include script name and line number. Check explicitly whether |
- // logging is enabled as finding the line number is not free. |
- if (Logger::is_logging() |
- || OProfileAgent::is_enabled() |
- || CpuProfiler::is_profiling()) { |
- Handle<String> func_name(name->length() > 0 ? *name : *inferred_name); |
+ CompilationInfo* info) { |
+ // Log the code generation. If source information is available include |
+ // script name and line number. Check explicitly whether logging is |
+ // enabled as finding the line number is not free. |
+ if (Logger::is_logging() || |
+ OProfileAgent::is_enabled() || |
+ CpuProfiler::is_profiling()) { |
+ Handle<Script> script = info->script(); |
+ Handle<Code> code = info->code(); |
if (script->name()->IsString()) { |
int line_num = GetScriptLineNumber(script, start_position) + 1; |
USE(line_num); |
PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script), |
- *code, *func_name, |
- String::cast(script->name()), line_num)); |
- OPROFILE(CreateNativeCodeRegion(*func_name, |
+ *code, |
+ *name, |
+ String::cast(script->name()), |
+ line_num)); |
+ OPROFILE(CreateNativeCodeRegion(*name, |
String::cast(script->name()), |
line_num, |
code->instruction_start(), |
code->instruction_size())); |
} else { |
PROFILE(CodeCreateEvent(Logger::ToNativeByScript(tag, *script), |
- *code, *func_name)); |
- OPROFILE(CreateNativeCodeRegion(*func_name, |
+ *code, |
+ *name)); |
+ OPROFILE(CreateNativeCodeRegion(*name, |
code->instruction_start(), |
code->instruction_size())); |
} |