Begin a more aggressive refactoring of the Compiler interface.

The plan is to use the CompilationInfo class to communicate inputs and
outputs to compilation pipeline phases, which each return a boolean
success/failure flag.

The intent is to make it easier to compose small pieces of the
pipeline without having to grow a custom function each time, each
taking a half dozen arguments.

This change modifies the very front end (the parser).

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5581 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2010-10-04 11:35:46 +00:00
parent 26163835a7
commit bef3ae07db
9 changed files with 212 additions and 239 deletions

View File

@ -175,7 +175,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
// Adjust for function-level loop nesting. // Adjust for function-level loop nesting.
ASSERT_EQ(0, loop_nesting_); ASSERT_EQ(0, loop_nesting_);
loop_nesting_ = info->loop_nesting(); loop_nesting_ = info->is_in_loop() ? 1 : 0;
{ {
CodeGenState state(this); CodeGenState state(this);
@ -339,7 +339,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
} }
// Adjust for function-level loop nesting. // Adjust for function-level loop nesting.
ASSERT(loop_nesting_ == info->loop_nesting()); ASSERT(loop_nesting_ == info->is_in_loop()? 1 : 0);
loop_nesting_ = 0; loop_nesting_ = 0;
// Code generation state must be reset. // Code generation state must be reset.

View File

@ -45,6 +45,40 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
CompilationInfo::CompilationInfo(Handle<Script> script)
: flags_(0),
function_(NULL),
scope_(NULL),
script_(script),
extension_(NULL),
pre_parse_data_(NULL) {
}
CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info)
: flags_(IsLazy::encode(true)),
function_(NULL),
scope_(NULL),
shared_info_(shared_info),
script_(Handle<Script>(Script::cast(shared_info->script()))),
extension_(NULL),
pre_parse_data_(NULL) {
}
CompilationInfo::CompilationInfo(Handle<JSFunction> closure)
: flags_(IsLazy::encode(true)),
function_(NULL),
scope_(NULL),
closure_(closure),
shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
script_(Handle<Script>(Script::cast(shared_info_->script()))),
extension_(NULL),
pre_parse_data_(NULL) {
}
// For normal operation the syntax checker is used to determine whether to // For normal operation the syntax checker is used to determine whether to
// use the full compiler for top level code or not. However if the flag // use the full compiler for top level code or not. However if the flag
// --always-full-compiler is specified or debugging is active the full // --always-full-compiler is specified or debugging is active the full
@ -131,30 +165,25 @@ Handle<Code> MakeCodeForLiveEdit(CompilationInfo* info) {
#endif #endif
static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global, static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info,
bool is_eval, Handle<Context> context) {
Compiler::ValidationState validate,
Handle<Script> script,
Handle<Context> context,
v8::Extension* extension,
ScriptDataImpl* pre_data) {
CompilationZoneScope zone_scope(DELETE_ON_EXIT); CompilationZoneScope zone_scope(DELETE_ON_EXIT);
PostponeInterruptsScope postpone; PostponeInterruptsScope postpone;
ASSERT(!i::Top::global_context().is_null()); ASSERT(!i::Top::global_context().is_null());
Handle<Script> script = info->script();
script->set_context_data((*i::Top::global_context())->data()); script->set_context_data((*i::Top::global_context())->data());
bool is_json = (validate == Compiler::VALIDATE_JSON);
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
if (is_eval || is_json) { if (info->is_eval() || info->is_json()) {
Script::CompilationType compilation_type = is_json Script::CompilationType compilation_type = info->is_json()
? Script::COMPILATION_TYPE_JSON ? Script::COMPILATION_TYPE_JSON
: Script::COMPILATION_TYPE_EVAL; : Script::COMPILATION_TYPE_EVAL;
script->set_compilation_type(Smi::FromInt(compilation_type)); script->set_compilation_type(Smi::FromInt(compilation_type));
// For eval scripts add information on the function from which eval was // For eval scripts add information on the function from which eval was
// called. // called.
if (is_eval) { if (info->is_eval()) {
StackTraceFrameIterator it; StackTraceFrameIterator it;
if (!it.done()) { if (!it.done()) {
script->set_eval_from_shared( script->set_eval_from_shared(
@ -171,31 +200,22 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global,
#endif #endif
// Only allow non-global compiles for eval. // Only allow non-global compiles for eval.
ASSERT(is_eval || is_global); ASSERT(info->is_eval() || info->is_global());
// Build AST. if (!Parser::Parse(info)) return Handle<SharedFunctionInfo>::null();
EagerCompilationInfo info(script, is_eval);
FunctionLiteral* lit =
Parser::MakeAST(is_global, script, extension, pre_data, is_json);
// Check for parse errors.
if (lit == NULL) {
ASSERT(Top::has_pending_exception());
return Handle<SharedFunctionInfo>::null();
}
info.set_function(lit);
// Measure how long it takes to do the compilation; only take the // Measure how long it takes to do the compilation; only take the
// rest of the function into account to avoid overlap with the // rest of the function into account to avoid overlap with the
// parsing statistics. // parsing statistics.
HistogramTimer* rate = is_eval HistogramTimer* rate = info->is_eval()
? &Counters::compile_eval ? &Counters::compile_eval
: &Counters::compile; : &Counters::compile;
HistogramTimerScope timer(rate); HistogramTimerScope timer(rate);
// Compile the code. // Compile the code.
FunctionLiteral* lit = info->function();
LiveEditFunctionTracker live_edit_tracker(lit); LiveEditFunctionTracker live_edit_tracker(lit);
Handle<Code> code = MakeCode(context, &info); Handle<Code> code = MakeCode(context, info);
// Check for stack-overflow exceptions. // Check for stack-overflow exceptions.
if (code.is_null()) { if (code.is_null()) {
@ -205,18 +225,22 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global,
if (script->name()->IsString()) { if (script->name()->IsString()) {
PROFILE(CodeCreateEvent( PROFILE(CodeCreateEvent(
is_eval ? Logger::EVAL_TAG : info->is_eval()
Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), ? Logger::EVAL_TAG
*code, String::cast(script->name()))); : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
*code,
String::cast(script->name())));
OPROFILE(CreateNativeCodeRegion(String::cast(script->name()), OPROFILE(CreateNativeCodeRegion(String::cast(script->name()),
code->instruction_start(), code->instruction_start(),
code->instruction_size())); code->instruction_size()));
} else { } else {
PROFILE(CodeCreateEvent( PROFILE(CodeCreateEvent(
is_eval ? Logger::EVAL_TAG : info->is_eval()
Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script), ? Logger::EVAL_TAG
*code, "")); : Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
OPROFILE(CreateNativeCodeRegion(is_eval ? "Eval" : "Script", *code,
""));
OPROFILE(CreateNativeCodeRegion(info->is_eval() ? "Eval" : "Script",
code->instruction_start(), code->instruction_start(),
code->instruction_size())); code->instruction_size()));
} }
@ -227,7 +251,7 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global,
lit->name(), lit->name(),
lit->materialized_literal_count(), lit->materialized_literal_count(),
code, code,
SerializedScopeInfo::Create(info.scope())); SerializedScopeInfo::Create(info->scope()));
ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position()); ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
Compiler::SetFunctionInfo(result, lit, true, script); Compiler::SetFunctionInfo(result, lit, true, script);
@ -303,13 +327,11 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
: *script_data); : *script_data);
// Compile the function and add it to the cache. // Compile the function and add it to the cache.
result = MakeFunctionInfo(true, CompilationInfo info(script);
false, info.MarkAsGlobal();
DONT_VALIDATE_JSON, info.SetExtension(extension);
script, info.SetPreParseData(pre_data);
Handle<Context>::null(), result = MakeFunctionInfo(&info, Handle<Context>::null());
extension,
pre_data);
if (extension == NULL && !result.is_null()) { if (extension == NULL && !result.is_null()) {
CompilationCache::PutScript(source, result); CompilationCache::PutScript(source, result);
} }
@ -329,9 +351,10 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
Handle<Context> context, Handle<Context> context,
bool is_global, bool is_global,
ValidationState validate) { ValidationState validate) {
// Note that if validation is required then no path through this // Note that if validation is required then no path through this function
// function is allowed to return a value without validating that // is allowed to return a value without validating that the input is legal
// the input is legal json. // json.
bool is_json = (validate == VALIDATE_JSON);
int source_length = source->length(); int source_length = source->length();
Counters::total_eval_size.Increment(source_length); Counters::total_eval_size.Increment(source_length);
@ -340,27 +363,26 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
// The VM is in the COMPILER state until exiting this function. // The VM is in the COMPILER state until exiting this function.
VMState state(COMPILER); VMState state(COMPILER);
// Do a lookup in the compilation cache; if the entry is not there, // Do a lookup in the compilation cache; if the entry is not there, invoke
// invoke the compiler and add the result to the cache. If we're // the compiler and add the result to the cache. If we're evaluating json
// evaluating json we bypass the cache since we can't be sure a // we bypass the cache since we can't be sure a potential value in the
// potential value in the cache has been validated. // cache has been validated.
Handle<SharedFunctionInfo> result; Handle<SharedFunctionInfo> result;
if (validate == DONT_VALIDATE_JSON) if (!is_json) {
result = CompilationCache::LookupEval(source, context, is_global); result = CompilationCache::LookupEval(source, context, is_global);
}
if (result.is_null()) { if (result.is_null()) {
// Create a script object describing the script to be compiled. // Create a script object describing the script to be compiled.
Handle<Script> script = Factory::NewScript(source); Handle<Script> script = Factory::NewScript(source);
result = MakeFunctionInfo(is_global, CompilationInfo info(script);
true, info.MarkAsEval();
validate, if (is_global) info.MarkAsGlobal();
script, if (is_json) info.MarkAsJson();
context, result = MakeFunctionInfo(&info, context);
NULL, if (!result.is_null() && !is_json) {
NULL); // For json it's unlikely that we'll ever see exactly the same string
if (!result.is_null() && validate != VALIDATE_JSON) { // again so we don't use the compilation cache.
// For json it's unlikely that we'll ever see exactly the same
// string again so we don't use the compilation cache.
CompilationCache::PutEval(source, context, is_global, result); CompilationCache::PutEval(source, context, is_global, result);
} }
} }
@ -382,16 +404,8 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
int compiled_size = shared->end_position() - shared->start_position(); int compiled_size = shared->end_position() - shared->start_position();
Counters::total_compile_size.Increment(compiled_size); Counters::total_compile_size.Increment(compiled_size);
// Generate the AST for the lazily compiled function. The AST may be // Generate the AST for the lazily compiled function.
// NULL in case of parser stack overflow. if (!Parser::Parse(info)) return false;
FunctionLiteral* lit = Parser::MakeLazyAST(shared);
// Check for parse errors.
if (lit == NULL) {
ASSERT(Top::has_pending_exception());
return false;
}
info->set_function(lit);
// Measure how long it takes to do the lazy compilation; only take // Measure how long it takes to do the lazy compilation; only take
// the rest of the function into account to avoid overlap with the // the rest of the function into account to avoid overlap with the
@ -428,6 +442,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
} }
// Set the expected number of properties for instances. // Set the expected number of properties for instances.
FunctionLiteral* lit = info->function();
SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count()); SetExpectedNofPropertiesFromEstimate(shared, lit->expected_property_count());
// Set the optimication hints after performing lazy compilation, as these are // Set the optimication hints after performing lazy compilation, as these are
@ -477,8 +492,8 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
// Generate code and return it. The way that the compilation mode // Generate code and return it. The way that the compilation mode
// is controlled by the command-line flags is described in // is controlled by the command-line flags is described in
// the static helper function MakeCode. // the static helper function MakeCode.
EagerCompilationInfo info(script, false); CompilationInfo info(script);
info.set_function(literal); info.SetFunction(literal);
bool is_run_once = literal->try_full_codegen(); bool is_run_once = literal->try_full_codegen();
bool use_full = FLAG_full_compiler && !literal->contains_loops(); bool use_full = FLAG_full_compiler && !literal->contains_loops();

View File

@ -42,112 +42,84 @@ class ScriptDataImpl;
// is constructed based on the resources available at compile-time. // is constructed based on the resources available at compile-time.
class CompilationInfo BASE_EMBEDDED { class CompilationInfo BASE_EMBEDDED {
public: public:
virtual ~CompilationInfo() {} explicit CompilationInfo(Handle<Script> script);
explicit CompilationInfo(Handle<SharedFunctionInfo> shared_info);
explicit CompilationInfo(Handle<JSFunction> closure);
// Dispatched behavior. bool is_lazy() const { return (flags_ & IsLazy::mask()) != 0; }
virtual Handle<SharedFunctionInfo> shared_info() const = 0; bool is_eval() const { return (flags_ & IsEval::mask()) != 0; }
bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; }
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(); }
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_; }
virtual Handle<Script> script() const { void MarkAsEval() {
return Handle<Script>(Script::cast(shared_info()->script())); ASSERT(!is_lazy());
flags_ |= IsEval::encode(true);
} }
void MarkAsGlobal() {
virtual Handle<JSFunction> closure() const { ASSERT(!is_lazy());
return Handle<JSFunction>::null(); flags_ |= IsGlobal::encode(true);
}
void MarkAsJson() {
ASSERT(!is_lazy());
flags_ |= IsJson::encode(true);
}
void MarkAsInLoop() {
ASSERT(is_lazy());
flags_ |= IsInLoop::encode(true);
}
void SetFunction(FunctionLiteral* literal) {
ASSERT(function_ == NULL);
function_ = literal;
}
void SetExtension(v8::Extension* extension) {
ASSERT(!is_lazy());
extension_ = extension;
}
void SetPreParseData(ScriptDataImpl* pre_parse_data) {
ASSERT(!is_lazy());
pre_parse_data_ = pre_parse_data;
} }
virtual bool is_eval() const { return false; }
virtual int loop_nesting() const { return 0; }
virtual bool has_global_object() const { return false; }
virtual GlobalObject* global_object() const { return NULL; }
// There should always be a function literal, but it may be set after
// construction (for lazy compilation).
FunctionLiteral* function() { return function_; }
void set_function(FunctionLiteral* literal) { function_ = literal; }
// Derived accessors.
Scope* scope() { return function()->scope(); }
protected:
CompilationInfo() : function_(NULL) {}
private: private:
// Flags using template class BitField<type, start, length>. All are
// false by default.
//
// Compilation is either eager or lazy.
class IsLazy: public BitField<bool, 0, 1> {};
// Flags that can be set for eager compilation.
class IsEval: public BitField<bool, 1, 1> {};
class IsGlobal: public BitField<bool, 2, 1> {};
class IsJson: public BitField<bool, 3, 1> {};
// Flags that can be set for lazy compilation.
class IsInLoop: public BitField<bool, 4, 1> {};
unsigned flags_;
// Fields filled in by the compilation pipeline.
FunctionLiteral* function_; FunctionLiteral* function_;
Scope* scope_;
// Possible initial inputs to the compilation process.
Handle<JSFunction> closure_;
Handle<SharedFunctionInfo> shared_info_;
Handle<Script> script_;
// Fields possibly needed for eager compilation, NULL by default.
v8::Extension* extension_;
ScriptDataImpl* pre_parse_data_;
DISALLOW_COPY_AND_ASSIGN(CompilationInfo); DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
}; };
class EagerCompilationInfo: public CompilationInfo {
public:
EagerCompilationInfo(Handle<Script> script, bool is_eval)
: script_(script), is_eval_(is_eval) {
ASSERT(!script.is_null());
}
// Overridden functions from the base class.
virtual Handle<SharedFunctionInfo> shared_info() const {
return Handle<SharedFunctionInfo>::null();
}
virtual Handle<Script> script() const { return script_; }
virtual bool is_eval() const { return is_eval_; }
private:
Handle<Script> script_;
bool is_eval_;
};
class LazySharedCompilationInfo: public CompilationInfo {
public:
explicit LazySharedCompilationInfo(Handle<SharedFunctionInfo> shared_info)
: shared_info_(shared_info) {
ASSERT(!shared_info.is_null());
}
// Overridden functions from the base class.
virtual Handle<SharedFunctionInfo> shared_info() const {
return shared_info_;
}
private:
Handle<SharedFunctionInfo> shared_info_;
};
class LazyFunctionCompilationInfo: public CompilationInfo {
public:
LazyFunctionCompilationInfo(Handle<JSFunction> closure,
int loop_nesting)
: closure_(closure), loop_nesting_(loop_nesting) {
ASSERT(!closure.is_null());
}
// Overridden functions from the base class.
virtual Handle<SharedFunctionInfo> shared_info() const {
return Handle<SharedFunctionInfo>(closure_->shared());
}
virtual int loop_nesting() const { return loop_nesting_; }
virtual bool has_global_object() const {
return closure_->context()->global() != NULL;
}
virtual GlobalObject* global_object() const {
return closure_->context()->global();
}
private:
Handle<JSFunction> closure_;
int loop_nesting_;
};
// The V8 compiler // The V8 compiler
// //
// General strategy: Source code is translated into an anonymous function w/o // General strategy: Source code is translated into an anonymous function w/o
@ -161,7 +133,7 @@ class LazyFunctionCompilationInfo: public CompilationInfo {
class Compiler : public AllStatic { class Compiler : public AllStatic {
public: public:
enum ValidationState { VALIDATE_JSON, DONT_VALIDATE_JSON }; enum ValidationState { DONT_VALIDATE_JSON, VALIDATE_JSON };
// All routines return a JSFunction. // All routines return a JSFunction.
// If an error occurs an exception is raised and // If an error occurs an exception is raised and

View File

@ -779,7 +779,7 @@ static bool CompileLazyHelper(CompilationInfo* info,
bool CompileLazyShared(Handle<SharedFunctionInfo> shared, bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
ClearExceptionFlag flag) { ClearExceptionFlag flag) {
LazySharedCompilationInfo info(shared); CompilationInfo info(shared);
return CompileLazyHelper(&info, flag); return CompileLazyHelper(&info, flag);
} }
@ -791,7 +791,7 @@ bool CompileLazy(Handle<JSFunction> function,
function->shared()->set_code_age(0); function->shared()->set_code_age(0);
return true; return true;
} else { } else {
LazyFunctionCompilationInfo info(function, 0); CompilationInfo info(function);
bool result = CompileLazyHelper(&info, flag); bool result = CompileLazyHelper(&info, flag);
PROFILE(FunctionCreateEvent(*function)); PROFILE(FunctionCreateEvent(*function));
return result; return result;
@ -806,7 +806,8 @@ bool CompileLazyInLoop(Handle<JSFunction> function,
function->shared()->set_code_age(0); function->shared()->set_code_age(0);
return true; return true;
} else { } else {
LazyFunctionCompilationInfo info(function, 1); CompilationInfo info(function);
info.MarkAsInLoop();
bool result = CompileLazyHelper(&info, flag); bool result = CompileLazyHelper(&info, flag);
PROFILE(FunctionCreateEvent(*function)); PROFILE(FunctionCreateEvent(*function));
return result; return result;

View File

@ -179,7 +179,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
// Adjust for function-level loop nesting. // Adjust for function-level loop nesting.
ASSERT_EQ(0, loop_nesting_); ASSERT_EQ(0, loop_nesting_);
loop_nesting_ = info->loop_nesting(); loop_nesting_ = info->is_in_loop() ? 1 : 0;
JumpTarget::set_compiling_deferred_code(false); JumpTarget::set_compiling_deferred_code(false);
@ -358,7 +358,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
} }
// Adjust for function-level loop nesting. // Adjust for function-level loop nesting.
ASSERT_EQ(loop_nesting_, info->loop_nesting()); ASSERT_EQ(loop_nesting_, info->is_in_loop() ? 1 : 0);
loop_nesting_ = 0; loop_nesting_ = 0;
// Code generation state must be reset. // Code generation state must be reset.

View File

@ -398,31 +398,16 @@ Handle<JSArray> LiveEdit::CompareStringsLinewise(Handle<String> s1,
static void CompileScriptForTracker(Handle<Script> script) { static void CompileScriptForTracker(Handle<Script> script) {
const bool is_eval = false;
const bool is_global = true;
// TODO(635): support extensions. // TODO(635): support extensions.
Extension* extension = NULL;
PostponeInterruptsScope postpone; PostponeInterruptsScope postpone;
// Only allow non-global compiles for eval.
ASSERT(is_eval || is_global);
// Build AST. // Build AST.
ScriptDataImpl* pre_data = NULL; CompilationInfo info(script);
EagerCompilationInfo info(script, is_eval); info.MarkAsGlobal();
FunctionLiteral* lit = if (!Parser::Parse(&info)) return;
Parser::MakeAST(is_global, script, extension, pre_data);
// Check for parse errors.
if (lit == NULL) {
ASSERT(Top::has_pending_exception());
return;
}
info.set_function(lit);
// Compile the code. // Compile the code.
LiveEditFunctionTracker tracker(lit); LiveEditFunctionTracker tracker(info.function());
Handle<Code> code = MakeCodeForLiveEdit(&info); Handle<Code> code = MakeCodeForLiveEdit(&info);
// Check for stack-overflow exceptions. // Check for stack-overflow exceptions.
@ -433,11 +418,13 @@ static void CompileScriptForTracker(Handle<Script> script) {
tracker.RecordRootFunctionInfo(code); tracker.RecordRootFunctionInfo(code);
} }
// Unwraps JSValue object, returning its field "value" // Unwraps JSValue object, returning its field "value"
static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) { static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) {
return Handle<Object>(jsValue->value()); return Handle<Object>(jsValue->value());
} }
// Wraps any object into a OpaqueReference, that will hide the object // Wraps any object into a OpaqueReference, that will hide the object
// from JavaScript. // from JavaScript.
static Handle<JSValue> WrapInJSValue(Object* object) { static Handle<JSValue> WrapInJSValue(Object* object) {
@ -448,6 +435,7 @@ static Handle<JSValue> WrapInJSValue(Object* object) {
return result; return result;
} }
// Simple helper class that creates more or less typed structures over // Simple helper class that creates more or less typed structures over
// JSArray object. This is an adhoc method of passing structures from C++ // JSArray object. This is an adhoc method of passing structures from C++
// to JavaScript. // to JavaScript.
@ -468,6 +456,7 @@ class JSArrayBasedStruct {
Handle<JSArray> GetJSArray() { Handle<JSArray> GetJSArray() {
return array_; return array_;
} }
protected: protected:
void SetField(int field_position, Handle<Object> value) { void SetField(int field_position, Handle<Object> value) {
SetElement(array_, field_position, value); SetElement(array_, field_position, value);
@ -482,6 +471,7 @@ class JSArrayBasedStruct {
Object* res = GetField(field_position); Object* res = GetField(field_position);
return Smi::cast(res)->value(); return Smi::cast(res)->value();
} }
private: private:
Handle<JSArray> array_; Handle<JSArray> array_;
}; };
@ -554,6 +544,7 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
friend class JSArrayBasedStruct<FunctionInfoWrapper>; friend class JSArrayBasedStruct<FunctionInfoWrapper>;
}; };
// Wraps SharedFunctionInfo along with some of its fields for passing it // Wraps SharedFunctionInfo along with some of its fields for passing it
// back to JavaScript. SharedFunctionInfo object itself is additionally // back to JavaScript. SharedFunctionInfo object itself is additionally
// wrapped into BlindReference for sanitizing reasons. // wrapped into BlindReference for sanitizing reasons.
@ -594,6 +585,7 @@ class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> {
friend class JSArrayBasedStruct<SharedInfoWrapper>; friend class JSArrayBasedStruct<SharedInfoWrapper>;
}; };
class FunctionInfoListener { class FunctionInfoListener {
public: public:
FunctionInfoListener() { FunctionInfoListener() {
@ -620,7 +612,6 @@ class FunctionInfoListener {
current_parent_index_ = info.GetParentIndex(); current_parent_index_ = info.GetParentIndex();
} }
public:
// Saves only function code, because for a script function we // Saves only function code, because for a script function we
// may never create a SharedFunctionInfo object. // may never create a SharedFunctionInfo object.
void FunctionCode(Handle<Code> function_code) { void FunctionCode(Handle<Code> function_code) {
@ -708,6 +699,7 @@ class FunctionInfoListener {
int current_parent_index_; int current_parent_index_;
}; };
static FunctionInfoListener* active_function_info_listener = NULL; static FunctionInfoListener* active_function_info_listener = NULL;
JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script, JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script,

View File

@ -5344,43 +5344,42 @@ bool Parser::ParseRegExp(FlatStringReader* input,
} }
FunctionLiteral* Parser::MakeAST(bool compile_in_global_context, bool Parser::Parse(CompilationInfo* info) {
Handle<Script> script, ASSERT(info->function() == NULL);
v8::Extension* extension, FunctionLiteral* result = NULL;
ScriptDataImpl* pre_data, Handle<Script> script = info->script();
bool is_json) { if (info->is_lazy()) {
bool allow_natives_syntax = AstBuildingParser parser(script, true, NULL, NULL);
FLAG_allow_natives_syntax || Bootstrapper::IsActive(); result = parser.ParseLazy(info->shared_info());
AstBuildingParser parser(script, allow_natives_syntax, extension, pre_data);
if (pre_data != NULL && pre_data->has_error()) {
Scanner::Location loc = pre_data->MessageLocation();
const char* message = pre_data->BuildMessage();
Vector<const char*> args = pre_data->BuildArgs();
parser.ReportMessageAt(loc, message, args);
DeleteArray(message);
for (int i = 0; i < args.length(); i++) {
DeleteArray(args[i]);
}
DeleteArray(args.start());
return NULL;
}
Handle<String> source = Handle<String>(String::cast(script->source()));
FunctionLiteral* result;
if (is_json) {
ASSERT(compile_in_global_context);
result = parser.ParseJson(source);
} else { } else {
result = parser.ParseProgram(source, compile_in_global_context); bool allow_natives_syntax =
FLAG_allow_natives_syntax || Bootstrapper::IsActive();
ScriptDataImpl* pre_data = info->pre_parse_data();
AstBuildingParser parser(script, allow_natives_syntax, info->extension(),
pre_data);
if (pre_data != NULL && pre_data->has_error()) {
Scanner::Location loc = pre_data->MessageLocation();
const char* message = pre_data->BuildMessage();
Vector<const char*> args = pre_data->BuildArgs();
parser.ReportMessageAt(loc, message, args);
DeleteArray(message);
for (int i = 0; i < args.length(); i++) {
DeleteArray(args[i]);
}
DeleteArray(args.start());
ASSERT(Top::has_pending_exception());
} else {
Handle<String> source = Handle<String>(String::cast(script->source()));
// JSON is always global.
ASSERT(!info->is_json() || info->is_global());
result = info->is_json()
? parser.ParseJson(source)
: parser.ParseProgram(source, info->is_global());
}
} }
return result;
}
info->SetFunction(result);
FunctionLiteral* Parser::MakeLazyAST(Handle<SharedFunctionInfo> info) { return (result != NULL);
Handle<Script> script(Script::cast(info->script()));
AstBuildingParser parser(script, true, NULL, NULL);
FunctionLiteral* result = parser.ParseLazy(info);
return result;
} }
#undef NEW #undef NEW

View File

@ -35,6 +35,7 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class CompilationInfo;
class FuncNameInferrer; class FuncNameInferrer;
class ParserFactory; class ParserFactory;
class ParserLog; class ParserLog;
@ -183,17 +184,10 @@ class Parser {
ParserFactory* factory, ParserLog* log, ScriptDataImpl* pre_data); ParserFactory* factory, ParserLog* log, ScriptDataImpl* pre_data);
virtual ~Parser() { } virtual ~Parser() { }
// Takes a script and and context information, and builds a // Parses the source code represented by the compilation info and sets its
// FunctionLiteral AST node. Returns NULL and deallocates any allocated // function literal. Returns false (and deallocates any allocated AST
// AST nodes if parsing failed. // nodes) if parsing failed.
static FunctionLiteral* MakeAST(bool compile_in_global_context, static bool Parse(CompilationInfo* info);
Handle<Script> script,
v8::Extension* extension,
ScriptDataImpl* pre_data,
bool is_json = false);
// Support for doing lazy compilation.
static FunctionLiteral* MakeLazyAST(Handle<SharedFunctionInfo> info);
// Generic preparser generating full preparse data. // Generic preparser generating full preparse data.
static ScriptDataImpl* PreParse(Handle<String> source, static ScriptDataImpl* PreParse(Handle<String> source,

View File

@ -178,7 +178,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
// Adjust for function-level loop nesting. // Adjust for function-level loop nesting.
ASSERT_EQ(0, loop_nesting_); ASSERT_EQ(0, loop_nesting_);
loop_nesting_ = info->loop_nesting(); loop_nesting_ = info->is_in_loop() ? 1 : 0;
JumpTarget::set_compiling_deferred_code(false); JumpTarget::set_compiling_deferred_code(false);
@ -356,7 +356,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
} }
// Adjust for function-level loop nesting. // Adjust for function-level loop nesting.
ASSERT_EQ(loop_nesting_, info->loop_nesting()); ASSERT_EQ(loop_nesting_, info->is_in_loop() ? 1 : 0);
loop_nesting_ = 0; loop_nesting_ = 0;
// Code generation state must be reset. // Code generation state must be reset.