More refactoring of class Compiler's interface.

Change more functions used by the Compiler class to have a uniform
interface: they get passed as argument an input/output pointer to a
CompilationInfo that they mutate if they succeed, and they return a
flag telling whether they succeeded.

Also, remove some unnecessary timers.

Review URL: http://codereview.chromium.org/3561012

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5583 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2010-10-04 14:30:43 +00:00
parent 2f54abf974
commit ea910460bd
22 changed files with 335 additions and 293 deletions

View File

@ -3132,9 +3132,9 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
// Build the function info and instantiate it.
Handle<SharedFunctionInfo> function_info =
Compiler::BuildFunctionInfo(node, script(), this);
// Check for stack-overflow exception.
if (HasStackOverflow()) {
Compiler::BuildFunctionInfo(node, script());
if (function_info.is_null()) {
SetStackOverflow();
ASSERT(frame_->height() == original_height);
return;
}

View File

@ -207,9 +207,7 @@ enum NopMarkerTypes {
class CodeGenerator: public AstVisitor {
public:
// Takes a function literal, generates code for it. This function should only
// be called by compiler.cc.
static Handle<Code> MakeCode(CompilationInfo* info);
static bool MakeCode(CompilationInfo* info);
// Printing of AST, etc. as requested by flags.
static void MakeCodePrologue(CompilationInfo* info);

View File

@ -1436,6 +1436,11 @@ class FunctionLiteral: public Expression {
bool AllowsLazyCompilation();
Handle<String> debug_name() const {
if (name_->length() > 0) return name_;
return inferred_name();
}
Handle<String> inferred_name() const { return inferred_name_; }
void set_inferred_name(Handle<String> inferred_name) {
inferred_name_ = inferred_name;

View File

@ -206,10 +206,9 @@ Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm,
}
// Generate the code. Takes a function literal, generates code for it, assemble
// all the pieces into a Code object. This function is only to be called by
// the compiler.cc code.
Handle<Code> CodeGenerator::MakeCode(CompilationInfo* info) {
// Generate the code. Compile the AST and assemble all the pieces into a
// Code object.
bool CodeGenerator::MakeCode(CompilationInfo* info) {
Handle<Script> script = info->script();
if (!script->IsUndefined() && !script->source()->IsUndefined()) {
int len = String::cast(script->source())->length();
@ -224,12 +223,14 @@ Handle<Code> CodeGenerator::MakeCode(CompilationInfo* info) {
cgen.Generate(info);
if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
return false;
}
InLoopFlag in_loop = (cgen.loop_nesting() != 0) ? IN_LOOP : NOT_IN_LOOP;
InLoopFlag in_loop = info->is_in_loop() ? IN_LOOP : NOT_IN_LOOP;
Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, in_loop);
return MakeCodeEpilogue(cgen.masm(), flags, info);
Handle<Code> code = MakeCodeEpilogue(cgen.masm(), flags, info);
info->SetCode(code); // May be an empty handle.
return !code.is_null();
}
@ -325,9 +326,12 @@ void CodeGenerator::ProcessDeclarations(ZoneList<Declaration*>* declarations) {
}
} else {
Handle<SharedFunctionInfo> function =
Compiler::BuildFunctionInfo(node->fun(), script(), this);
Compiler::BuildFunctionInfo(node->fun(), script());
// Check for stack-overflow exception.
if (HasStackOverflow()) return;
if (function.is_null()) {
SetStackOverflow();
return;
}
array->set(j++, *function);
}
}

View File

@ -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();
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);
}
}
{
// 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);
}
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;
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);
// 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);
// Compile the code.
Handle<Code> code = MakeCode(Handle<Context>::null(), 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());
}
// Check for stack-overflow exception.
if (code.is_null()) {
Top::StackOverflow();
return false;
// 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;
}
}
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 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()));
}

View File

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -52,12 +52,14 @@ class CompilationInfo BASE_EMBEDDED {
bool is_json() const { return (flags_ & IsJson::mask()) != 0; }
bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; }
FunctionLiteral* function() const { return function_; }
Scope* scope() const { return function_->scope(); }
Scope* scope() const { return scope_; }
Handle<Code> code() const { return code_; }
Handle<JSFunction> closure() const { return closure_; }
Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
Handle<Script> script() const { return script_; }
v8::Extension* extension() const { return extension_; }
ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; }
Handle<Context> calling_context() const { return calling_context_; }
void MarkAsEval() {
ASSERT(!is_lazy());
@ -79,6 +81,11 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(function_ == NULL);
function_ = literal;
}
void SetScope(Scope* scope) {
ASSERT(scope_ == NULL);
scope_ = scope;
}
void SetCode(Handle<Code> code) { code_ = code; }
void SetExtension(v8::Extension* extension) {
ASSERT(!is_lazy());
extension_ = extension;
@ -87,6 +94,10 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(!is_lazy());
pre_parse_data_ = pre_parse_data;
}
void SetCallingContext(Handle<Context> context) {
ASSERT(is_eval());
calling_context_ = context;
}
private:
// Flags using template class BitField<type, start, length>. All are
@ -104,8 +115,13 @@ class CompilationInfo BASE_EMBEDDED {
unsigned flags_;
// Fields filled in by the compilation pipeline.
// AST filled in by the parser.
FunctionLiteral* function_;
// The scope of the function literal as a convenience. Set to indidicate
// that scopes have been analyzed.
Scope* scope_;
// The compiled code.
Handle<Code> code_;
// Possible initial inputs to the compilation process.
Handle<JSFunction> closure_;
@ -116,6 +132,10 @@ class CompilationInfo BASE_EMBEDDED {
v8::Extension* extension_;
ScriptDataImpl* pre_parse_data_;
// The context of the caller is needed for eval code, and will be a null
// handle otherwise.
Handle<Context> calling_context_;
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
};
@ -127,9 +147,9 @@ class CompilationInfo BASE_EMBEDDED {
// functions, they will be compiled and allocated as part of the compilation
// of the source code.
// Please note this interface returns shared function infos.
// This means you need to call Factory::NewFunctionFromSharedFunctionInfo
// before you have a real function with a context.
// Please note this interface returns shared function infos. This means you
// need to call Factory::NewFunctionFromSharedFunctionInfo before you have a
// real function with a context.
class Compiler : public AllStatic {
public:
@ -155,17 +175,14 @@ class Compiler : public AllStatic {
bool is_global,
ValidationState validation);
// Compile from function info (used for lazy compilation). Returns
// true on success and false if the compilation resulted in a stack
// overflow.
// Compile from function info (used for lazy compilation). Returns true on
// success and false if the compilation resulted in a stack overflow.
static bool CompileLazy(CompilationInfo* info);
// Compile a shared function info object (the function is possibly
// lazily compiled). Called recursively from a backend code
// generator 'caller' to build the shared function info.
// Compile a shared function info object (the function is possibly lazily
// compiled).
static Handle<SharedFunctionInfo> BuildFunctionInfo(FunctionLiteral* node,
Handle<Script> script,
AstVisitor* caller);
Handle<Script> script);
// Set the function info for a newly compiled function.
static void SetFunctionInfo(Handle<SharedFunctionInfo> function_info,
@ -173,23 +190,18 @@ class Compiler : public AllStatic {
bool is_toplevel,
Handle<Script> script);
#ifdef ENABLE_DEBUGGER_SUPPORT
static bool MakeCodeForLiveEdit(CompilationInfo* info);
#endif
private:
static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
Handle<String> name,
Handle<String> inferred_name,
int start_position,
Handle<Script> script,
Handle<Code> code);
CompilationInfo* info);
};
#ifdef ENABLE_DEBUGGER_SUPPORT
Handle<Code> MakeCodeForLiveEdit(CompilationInfo* info);
#endif
// During compilation we need a global list of handles to constants
// for frame elements. When the zone gets deleted, we make sure to
// clear this list of handles as well.

View File

@ -50,12 +50,13 @@ void BitVector::Print() {
#endif
bool AssignedVariablesAnalyzer::Analyze() {
Scope* scope = fun_->scope();
bool AssignedVariablesAnalyzer::Analyze(CompilationInfo* info) {
info_ = info;
Scope* scope = info->scope();
int variables = scope->num_parameters() + scope->num_stack_slots();
if (variables == 0) return true;
av_.ExpandTo(variables);
VisitStatements(fun_->body());
VisitStatements(info->function()->body());
return !HasStackOverflow();
}
@ -129,7 +130,7 @@ int AssignedVariablesAnalyzer::BitIndex(Variable* var) {
if (slot->type() == Slot::PARAMETER) {
return slot->index();
} else {
return fun_->scope()->num_parameters() + slot->index();
return info_->scope()->num_parameters() + slot->index();
}
}

View File

@ -198,8 +198,8 @@ class WorkList BASE_EMBEDDED {
// is guaranteed to be a smi.
class AssignedVariablesAnalyzer : public AstVisitor {
public:
explicit AssignedVariablesAnalyzer(FunctionLiteral* fun) : fun_(fun) { }
bool Analyze();
explicit AssignedVariablesAnalyzer() : info_(NULL) { }
bool Analyze(CompilationInfo* info);
private:
Variable* FindSmiLoopVariable(ForStatement* stmt);
@ -219,7 +219,7 @@ class AssignedVariablesAnalyzer : public AstVisitor {
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
FunctionLiteral* fun_;
CompilationInfo* info_;
// Accumulator for assigned variables set.
BitVector av_;

View File

@ -277,7 +277,7 @@ void BreakableStatementChecker::VisitThisFunction(ThisFunction* expr) {
#define __ ACCESS_MASM(masm())
Handle<Code> FullCodeGenerator::MakeCode(CompilationInfo* info) {
bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
Handle<Script> script = info->script();
if (!script->IsUndefined() && !script->source()->IsUndefined()) {
int len = String::cast(script->source())->length();
@ -291,10 +291,13 @@ Handle<Code> FullCodeGenerator::MakeCode(CompilationInfo* info) {
cgen.Generate(info);
if (cgen.HasStackOverflow()) {
ASSERT(!Top::has_pending_exception());
return Handle<Code>::null();
return false;
}
Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
return CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
info->SetCode(code); // may be an empty handle.
return !code.is_null();
}
@ -462,9 +465,12 @@ void FullCodeGenerator::VisitDeclarations(
}
} else {
Handle<SharedFunctionInfo> function =
Compiler::BuildFunctionInfo(decl->fun(), script(), this);
Compiler::BuildFunctionInfo(decl->fun(), script());
// Check for stack-overflow exception.
if (HasStackOverflow()) return;
if (function.is_null()) {
SetStackOverflow();
return;
}
array->set(j++, *function);
}
}
@ -1156,8 +1162,11 @@ void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
// Build the function boilerplate and instantiate it.
Handle<SharedFunctionInfo> function_info =
Compiler::BuildFunctionInfo(expr, script(), this);
if (HasStackOverflow()) return;
Compiler::BuildFunctionInfo(expr, script());
if (function_info.is_null()) {
SetStackOverflow();
return;
}
EmitNewClosure(function_info);
}

View File

@ -74,7 +74,7 @@ class FullCodeGenerator: public AstVisitor {
context_(NULL) {
}
static Handle<Code> MakeCode(CompilationInfo* info);
static bool MakeCode(CompilationInfo* info);
void Generate(CompilationInfo* info);

View File

@ -191,10 +191,8 @@ void CodeGenerator::Generate(CompilationInfo* info) {
}
#endif
// New scope to get automatic timing calculation.
{ HistogramTimerScope codegen_timer(&Counters::code_generation);
{
CodeGenState state(this);
// Entry:
// Stack: receiver, arguments, return address.
// ebp: caller's frame pointer
@ -369,7 +367,6 @@ void CodeGenerator::Generate(CompilationInfo* info) {
// Process any deferred code using the register allocator.
if (!HasStackOverflow()) {
HistogramTimerScope deferred_timer(&Counters::deferred_code_generation);
JumpTarget::set_compiling_deferred_code(true);
ProcessDeferred();
JumpTarget::set_compiling_deferred_code(false);
@ -4925,9 +4922,12 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
ASSERT(!in_safe_int32_mode());
// Build the function info and instantiate it.
Handle<SharedFunctionInfo> function_info =
Compiler::BuildFunctionInfo(node, script(), this);
Compiler::BuildFunctionInfo(node, script());
// Check for stack-overflow exception.
if (HasStackOverflow()) return;
if (function_info.is_null()) {
SetStackOverflow();
return;
}
Result result = InstantiateFunction(function_info);
frame()->Push(&result);
}

View File

@ -300,9 +300,7 @@ enum ArgumentsAllocationMode {
class CodeGenerator: public AstVisitor {
public:
// Takes a function literal, generates code for it. This function should only
// be called by compiler.cc.
static Handle<Code> MakeCode(CompilationInfo* info);
static bool MakeCode(CompilationInfo* info);
// Printing of AST, etc. as requested by flags.
static void MakeCodePrologue(CompilationInfo* info);

View File

@ -404,18 +404,16 @@ static void CompileScriptForTracker(Handle<Script> script) {
// Build AST.
CompilationInfo info(script);
info.MarkAsGlobal();
if (!Parser::Parse(&info)) return;
// Compile the code.
LiveEditFunctionTracker tracker(info.function());
Handle<Code> code = MakeCodeForLiveEdit(&info);
// Check for stack-overflow exceptions.
if (code.is_null()) {
Top::StackOverflow();
return;
if (Parser::Parse(&info)) {
// Compile the code.
LiveEditFunctionTracker tracker(info.function());
if (Compiler::MakeCodeForLiveEdit(&info)) {
ASSERT(!info.code().is_null());
tracker.RecordRootFunctionInfo(info.code());
} else {
Top::StackOverflow();
}
}
tracker.RecordRootFunctionInfo(code);
}

View File

@ -1,4 +1,4 @@
// Copyright 2006-2009 the V8 project authors. All rights reserved.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -5227,6 +5227,13 @@ Object* Oddball::Initialize(const char* to_string, Object* to_number) {
}
String* SharedFunctionInfo::DebugName() {
Object* n = name();
if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
return String::cast(n);
}
bool SharedFunctionInfo::HasSourceCode() {
return !script()->IsUndefined() &&
!reinterpret_cast<Script*>(script())->source()->IsUndefined();

View File

@ -1,4 +1,4 @@
// Copyright 2006-2009 the V8 project authors. All rights reserved.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -3621,6 +3621,9 @@ class SharedFunctionInfo: public HeapObject {
// properties.
DECL_ACCESSORS(inferred_name, String)
// The function's name if it is non-empty, otherwise the inferred name.
String* DebugName();
// Position of the 'function' token in the script source.
inline int function_token_position();
inline void set_function_token_position(int function_token_position);

View File

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -27,10 +27,12 @@
#include "v8.h"
#include "ast.h"
#include "scopes.h"
#include "rewriter.h"
#include "ast.h"
#include "compiler.h"
#include "scopes.h"
namespace v8 {
namespace internal {
@ -986,34 +988,40 @@ void Processor::VisitThisFunction(ThisFunction* node) {
}
bool Rewriter::Process(FunctionLiteral* function) {
HistogramTimerScope timer(&Counters::rewriting);
// Assumes code has been parsed and scopes hve been analyzed. Mutates the
// AST, so the AST should not continue to be used in the case of failure.
bool Rewriter::Rewrite(CompilationInfo* info) {
FunctionLiteral* function = info->function();
ASSERT(function != NULL);
Scope* scope = function->scope();
ASSERT(scope != NULL);
if (scope->is_function_scope()) return true;
ZoneList<Statement*>* body = function->body();
if (body->is_empty()) return true;
if (!body->is_empty()) {
VariableProxy* result = scope->NewTemporary(Factory::result_symbol());
Processor processor(result);
processor.Process(body);
if (processor.HasStackOverflow()) return false;
VariableProxy* result = scope->NewTemporary(Factory::result_symbol());
Processor processor(result);
processor.Process(body);
if (processor.HasStackOverflow()) return false;
if (processor.result_assigned()) body->Add(new ReturnStatement(result));
}
if (processor.result_assigned()) body->Add(new ReturnStatement(result));
return true;
}
bool Rewriter::Optimize(FunctionLiteral* function) {
ZoneList<Statement*>* body = function->body();
// Assumes code has been parsed and scopes have been analyzed. Mutates the
// AST, so the AST should not continue to be used in the case of failure.
bool Rewriter::Analyze(CompilationInfo* info) {
FunctionLiteral* function = info->function();
ASSERT(function != NULL && function->scope() != NULL);
ZoneList<Statement*>* body = function->body();
if (FLAG_optimize_ast && !body->is_empty()) {
HistogramTimerScope timer(&Counters::ast_optimization);
AstOptimizer optimizer;
optimizer.Optimize(body);
if (optimizer.HasStackOverflow()) {
return false;
}
if (optimizer.HasStackOverflow()) return false;
}
return true;
}

View File

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -31,21 +31,26 @@
namespace v8 {
namespace internal {
// Currently, the rewriter takes function literals (only top-level)
// and rewrites them to return the value of the last expression in
// them.
//
// The rewriter adds a (hidden) variable, called .result, to the
// activation, and tries to figure out where it needs to store into
// this variable. If the variable is ever used, we conclude by adding
// a return statement that returns the variable to the body of the
// given function.
class CompilationInfo;
class Rewriter {
public:
static bool Process(FunctionLiteral* function);
static bool Optimize(FunctionLiteral* function);
// Rewrite top-level code (ECMA 262 "programs") so as to conservatively
// include an assignment of the value of the last statement in the code to
// a compiler-generated temporary variable wherever needed.
//
// Assumes code has been parsed and scopes have been analyzed. Mutates the
// AST, so the AST should not continue to be used in the case of failure.
static bool Rewrite(CompilationInfo* info);
// Perform a suite of simple non-iterative analyses of the AST. Mark
// expressions that are likely smis, expressions without side effects,
// expressions whose value will be converted to Int32, and expressions in a
// context where +0 and -0 are treated the same.
//
// Assumes code has been parsed and scopes have been analyzed. Mutates the
// AST, so the AST should not continue to be used in the case of failure.
static bool Analyze(CompilationInfo* info);
};

View File

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -27,9 +27,12 @@
#include "v8.h"
#include "scopes.h"
#include "bootstrapper.h"
#include "compiler.h"
#include "prettyprinter.h"
#include "scopeinfo.h"
#include "scopes.h"
namespace v8 {
namespace internal {
@ -168,6 +171,25 @@ Scope::Scope(Scope* outer_scope, Type type)
}
bool Scope::Analyze(CompilationInfo* info) {
ASSERT(info->function() != NULL);
Scope* top = info->function()->scope();
while (top->outer_scope() != NULL) top = top->outer_scope();
top->AllocateVariables(info->calling_context());
#ifdef DEBUG
if (Bootstrapper::IsActive()
? FLAG_print_builtin_scopes
: FLAG_print_scopes) {
info->function()->scope()->Print();
}
#endif
info->SetScope(info->function()->scope());
return true; // Can not fail.
}
void Scope::Initialize(bool inside_with) {
// Add this scope as a new inner scope of the outer scope.
if (outer_scope_ != NULL) {

View File

@ -1,4 +1,4 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -34,6 +34,9 @@
namespace v8 {
namespace internal {
class CompilationInfo;
// A hash map to support fast variable declaration and lookup.
class VariableMap: public HashMap {
public:
@ -96,6 +99,11 @@ class Scope: public ZoneObject {
virtual ~Scope() { }
// 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.
static bool Analyze(CompilationInfo* info);
// The scope name is only used for printing/debugging.
void SetScopeName(Handle<String> scope_name) { scope_name_ = scope_name; }

View File

@ -1,4 +1,4 @@
// Copyright 2007-2008 the V8 project authors. All rights reserved.
// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@ -45,14 +45,7 @@ namespace internal {
/* Total compilation times. */ \
HT(compile, V8.Compile) \
HT(compile_eval, V8.CompileEval) \
HT(compile_lazy, V8.CompileLazy) \
/* Individual compiler passes. */ \
HT(rewriting, V8.Rewriting) \
HT(usage_analysis, V8.UsageAnalysis) \
HT(variable_allocation, V8.VariableAllocation) \
HT(ast_optimization, V8.ASTOptimization) \
HT(code_generation, V8.CodeGeneration) \
HT(deferred_code_generation, V8.DeferredCodeGeneration)
HT(compile_lazy, V8.CompileLazy)
// WARNING: STATS_COUNTER_LIST_* is a very large macro that is causing MSVC

View File

@ -190,10 +190,8 @@ void CodeGenerator::Generate(CompilationInfo* info) {
}
#endif
// New scope to get automatic timing calculation.
{ HistogramTimerScope codegen_timer(&Counters::code_generation);
{
CodeGenState state(this);
// Entry:
// Stack: receiver, arguments, return address.
// rbp: caller's frame pointer
@ -367,7 +365,6 @@ void CodeGenerator::Generate(CompilationInfo* info) {
// Process any deferred code using the register allocator.
if (!HasStackOverflow()) {
HistogramTimerScope deferred_timer(&Counters::deferred_code_generation);
JumpTarget::set_compiling_deferred_code(true);
ProcessDeferred();
JumpTarget::set_compiling_deferred_code(false);
@ -4276,9 +4273,12 @@ void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
// Build the function info and instantiate it.
Handle<SharedFunctionInfo> function_info =
Compiler::BuildFunctionInfo(node, script(), this);
Compiler::BuildFunctionInfo(node, script());
// Check for stack-overflow exception.
if (HasStackOverflow()) return;
if (function_info.is_null()) {
SetStackOverflow();
return;
}
InstantiateFunction(function_info);
}

View File

@ -298,9 +298,7 @@ enum ArgumentsAllocationMode {
class CodeGenerator: public AstVisitor {
public:
// Takes a function literal, generates code for it. This function should only
// be called by compiler.cc.
static Handle<Code> MakeCode(CompilationInfo* info);
static bool MakeCode(CompilationInfo* info);
// Printing of AST, etc. as requested by flags.
static void MakeCodePrologue(CompilationInfo* info);