| 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()));
|
| }
|
|
|