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:
parent
26163835a7
commit
bef3ae07db
@ -175,7 +175,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
|
||||
|
||||
// Adjust for function-level loop nesting.
|
||||
ASSERT_EQ(0, loop_nesting_);
|
||||
loop_nesting_ = info->loop_nesting();
|
||||
loop_nesting_ = info->is_in_loop() ? 1 : 0;
|
||||
|
||||
{
|
||||
CodeGenState state(this);
|
||||
@ -339,7 +339,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
|
||||
}
|
||||
|
||||
// Adjust for function-level loop nesting.
|
||||
ASSERT(loop_nesting_ == info->loop_nesting());
|
||||
ASSERT(loop_nesting_ == info->is_in_loop()? 1 : 0);
|
||||
loop_nesting_ = 0;
|
||||
|
||||
// Code generation state must be reset.
|
||||
|
155
src/compiler.cc
155
src/compiler.cc
@ -45,6 +45,40 @@
|
||||
namespace v8 {
|
||||
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
|
||||
// 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
|
||||
@ -131,30 +165,25 @@ Handle<Code> MakeCodeForLiveEdit(CompilationInfo* info) {
|
||||
#endif
|
||||
|
||||
|
||||
static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global,
|
||||
bool is_eval,
|
||||
Compiler::ValidationState validate,
|
||||
Handle<Script> script,
|
||||
Handle<Context> context,
|
||||
v8::Extension* extension,
|
||||
ScriptDataImpl* pre_data) {
|
||||
static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info,
|
||||
Handle<Context> context) {
|
||||
CompilationZoneScope zone_scope(DELETE_ON_EXIT);
|
||||
|
||||
PostponeInterruptsScope postpone;
|
||||
|
||||
ASSERT(!i::Top::global_context().is_null());
|
||||
Handle<Script> script = info->script();
|
||||
script->set_context_data((*i::Top::global_context())->data());
|
||||
|
||||
bool is_json = (validate == Compiler::VALIDATE_JSON);
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
if (is_eval || is_json) {
|
||||
Script::CompilationType compilation_type = is_json
|
||||
if (info->is_eval() || info->is_json()) {
|
||||
Script::CompilationType compilation_type = info->is_json()
|
||||
? Script::COMPILATION_TYPE_JSON
|
||||
: Script::COMPILATION_TYPE_EVAL;
|
||||
script->set_compilation_type(Smi::FromInt(compilation_type));
|
||||
// For eval scripts add information on the function from which eval was
|
||||
// called.
|
||||
if (is_eval) {
|
||||
if (info->is_eval()) {
|
||||
StackTraceFrameIterator it;
|
||||
if (!it.done()) {
|
||||
script->set_eval_from_shared(
|
||||
@ -171,31 +200,22 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global,
|
||||
#endif
|
||||
|
||||
// Only allow non-global compiles for eval.
|
||||
ASSERT(is_eval || is_global);
|
||||
ASSERT(info->is_eval() || info->is_global());
|
||||
|
||||
// Build AST.
|
||||
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);
|
||||
if (!Parser::Parse(info)) return Handle<SharedFunctionInfo>::null();
|
||||
|
||||
// Measure how long it takes to do the compilation; only take the
|
||||
// rest of the function into account to avoid overlap with the
|
||||
// parsing statistics.
|
||||
HistogramTimer* rate = is_eval
|
||||
HistogramTimer* rate = info->is_eval()
|
||||
? &Counters::compile_eval
|
||||
: &Counters::compile;
|
||||
HistogramTimerScope timer(rate);
|
||||
|
||||
// Compile the code.
|
||||
FunctionLiteral* lit = info->function();
|
||||
LiveEditFunctionTracker live_edit_tracker(lit);
|
||||
Handle<Code> code = MakeCode(context, &info);
|
||||
Handle<Code> code = MakeCode(context, info);
|
||||
|
||||
// Check for stack-overflow exceptions.
|
||||
if (code.is_null()) {
|
||||
@ -205,18 +225,22 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global,
|
||||
|
||||
if (script->name()->IsString()) {
|
||||
PROFILE(CodeCreateEvent(
|
||||
is_eval ? Logger::EVAL_TAG :
|
||||
Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
|
||||
*code, String::cast(script->name())));
|
||||
info->is_eval()
|
||||
? Logger::EVAL_TAG
|
||||
: Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
|
||||
*code,
|
||||
String::cast(script->name())));
|
||||
OPROFILE(CreateNativeCodeRegion(String::cast(script->name()),
|
||||
code->instruction_start(),
|
||||
code->instruction_size()));
|
||||
} else {
|
||||
PROFILE(CodeCreateEvent(
|
||||
is_eval ? Logger::EVAL_TAG :
|
||||
Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
|
||||
*code, ""));
|
||||
OPROFILE(CreateNativeCodeRegion(is_eval ? "Eval" : "Script",
|
||||
info->is_eval()
|
||||
? Logger::EVAL_TAG
|
||||
: Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
|
||||
*code,
|
||||
""));
|
||||
OPROFILE(CreateNativeCodeRegion(info->is_eval() ? "Eval" : "Script",
|
||||
code->instruction_start(),
|
||||
code->instruction_size()));
|
||||
}
|
||||
@ -227,7 +251,7 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(bool is_global,
|
||||
lit->name(),
|
||||
lit->materialized_literal_count(),
|
||||
code,
|
||||
SerializedScopeInfo::Create(info.scope()));
|
||||
SerializedScopeInfo::Create(info->scope()));
|
||||
|
||||
ASSERT_EQ(RelocInfo::kNoPosition, lit->function_token_position());
|
||||
Compiler::SetFunctionInfo(result, lit, true, script);
|
||||
@ -303,13 +327,11 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
|
||||
: *script_data);
|
||||
|
||||
// Compile the function and add it to the cache.
|
||||
result = MakeFunctionInfo(true,
|
||||
false,
|
||||
DONT_VALIDATE_JSON,
|
||||
script,
|
||||
Handle<Context>::null(),
|
||||
extension,
|
||||
pre_data);
|
||||
CompilationInfo info(script);
|
||||
info.MarkAsGlobal();
|
||||
info.SetExtension(extension);
|
||||
info.SetPreParseData(pre_data);
|
||||
result = MakeFunctionInfo(&info, Handle<Context>::null());
|
||||
if (extension == NULL && !result.is_null()) {
|
||||
CompilationCache::PutScript(source, result);
|
||||
}
|
||||
@ -329,9 +351,10 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
|
||||
Handle<Context> context,
|
||||
bool is_global,
|
||||
ValidationState validate) {
|
||||
// Note that if validation is required then no path through this
|
||||
// function is allowed to return a value without validating that
|
||||
// the input is legal json.
|
||||
// Note that if validation is required then no path through this function
|
||||
// is allowed to return a value without validating that the input is legal
|
||||
// json.
|
||||
bool is_json = (validate == VALIDATE_JSON);
|
||||
|
||||
int source_length = 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.
|
||||
VMState state(COMPILER);
|
||||
|
||||
// Do a lookup in the compilation cache; if the entry is not there,
|
||||
// invoke the compiler and add the result to the cache. If we're
|
||||
// evaluating json we bypass the cache since we can't be sure a
|
||||
// potential value in the cache has been validated.
|
||||
// Do a lookup in the compilation cache; if the entry is not there, invoke
|
||||
// the compiler and add the result to the cache. If we're evaluating json
|
||||
// we bypass the cache since we can't be sure a potential value in the
|
||||
// cache has been validated.
|
||||
Handle<SharedFunctionInfo> result;
|
||||
if (validate == DONT_VALIDATE_JSON)
|
||||
if (!is_json) {
|
||||
result = CompilationCache::LookupEval(source, context, is_global);
|
||||
}
|
||||
|
||||
if (result.is_null()) {
|
||||
// Create a script object describing the script to be compiled.
|
||||
Handle<Script> script = Factory::NewScript(source);
|
||||
result = MakeFunctionInfo(is_global,
|
||||
true,
|
||||
validate,
|
||||
script,
|
||||
context,
|
||||
NULL,
|
||||
NULL);
|
||||
if (!result.is_null() && validate != VALIDATE_JSON) {
|
||||
// For json it's unlikely that we'll ever see exactly the same
|
||||
// string again so we don't use the compilation cache.
|
||||
CompilationInfo info(script);
|
||||
info.MarkAsEval();
|
||||
if (is_global) info.MarkAsGlobal();
|
||||
if (is_json) info.MarkAsJson();
|
||||
result = MakeFunctionInfo(&info, context);
|
||||
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.
|
||||
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();
|
||||
Counters::total_compile_size.Increment(compiled_size);
|
||||
|
||||
// Generate the AST for the lazily compiled function. The AST may be
|
||||
// NULL in case of parser stack overflow.
|
||||
FunctionLiteral* lit = Parser::MakeLazyAST(shared);
|
||||
|
||||
// Check for parse errors.
|
||||
if (lit == NULL) {
|
||||
ASSERT(Top::has_pending_exception());
|
||||
return false;
|
||||
}
|
||||
info->set_function(lit);
|
||||
// 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
|
||||
@ -428,6 +442,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -477,8 +492,8 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(FunctionLiteral* literal,
|
||||
// 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.
|
||||
EagerCompilationInfo info(script, false);
|
||||
info.set_function(literal);
|
||||
CompilationInfo info(script);
|
||||
info.SetFunction(literal);
|
||||
|
||||
bool is_run_once = literal->try_full_codegen();
|
||||
bool use_full = FLAG_full_compiler && !literal->contains_loops();
|
||||
|
162
src/compiler.h
162
src/compiler.h
@ -42,112 +42,84 @@ class ScriptDataImpl;
|
||||
// is constructed based on the resources available at compile-time.
|
||||
class CompilationInfo BASE_EMBEDDED {
|
||||
public:
|
||||
virtual ~CompilationInfo() {}
|
||||
explicit CompilationInfo(Handle<Script> script);
|
||||
explicit CompilationInfo(Handle<SharedFunctionInfo> shared_info);
|
||||
explicit CompilationInfo(Handle<JSFunction> closure);
|
||||
|
||||
// Dispatched behavior.
|
||||
virtual Handle<SharedFunctionInfo> shared_info() const = 0;
|
||||
bool is_lazy() const { return (flags_ & IsLazy::mask()) != 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 {
|
||||
return Handle<Script>(Script::cast(shared_info()->script()));
|
||||
void MarkAsEval() {
|
||||
ASSERT(!is_lazy());
|
||||
flags_ |= IsEval::encode(true);
|
||||
}
|
||||
|
||||
virtual Handle<JSFunction> closure() const {
|
||||
return Handle<JSFunction>::null();
|
||||
void MarkAsGlobal() {
|
||||
ASSERT(!is_lazy());
|
||||
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:
|
||||
// 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_;
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
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
|
||||
//
|
||||
// General strategy: Source code is translated into an anonymous function w/o
|
||||
@ -161,7 +133,7 @@ class LazyFunctionCompilationInfo: public CompilationInfo {
|
||||
|
||||
class Compiler : public AllStatic {
|
||||
public:
|
||||
enum ValidationState { VALIDATE_JSON, DONT_VALIDATE_JSON };
|
||||
enum ValidationState { DONT_VALIDATE_JSON, VALIDATE_JSON };
|
||||
|
||||
// All routines return a JSFunction.
|
||||
// If an error occurs an exception is raised and
|
||||
|
@ -779,7 +779,7 @@ static bool CompileLazyHelper(CompilationInfo* info,
|
||||
|
||||
bool CompileLazyShared(Handle<SharedFunctionInfo> shared,
|
||||
ClearExceptionFlag flag) {
|
||||
LazySharedCompilationInfo info(shared);
|
||||
CompilationInfo info(shared);
|
||||
return CompileLazyHelper(&info, flag);
|
||||
}
|
||||
|
||||
@ -791,7 +791,7 @@ bool CompileLazy(Handle<JSFunction> function,
|
||||
function->shared()->set_code_age(0);
|
||||
return true;
|
||||
} else {
|
||||
LazyFunctionCompilationInfo info(function, 0);
|
||||
CompilationInfo info(function);
|
||||
bool result = CompileLazyHelper(&info, flag);
|
||||
PROFILE(FunctionCreateEvent(*function));
|
||||
return result;
|
||||
@ -806,7 +806,8 @@ bool CompileLazyInLoop(Handle<JSFunction> function,
|
||||
function->shared()->set_code_age(0);
|
||||
return true;
|
||||
} else {
|
||||
LazyFunctionCompilationInfo info(function, 1);
|
||||
CompilationInfo info(function);
|
||||
info.MarkAsInLoop();
|
||||
bool result = CompileLazyHelper(&info, flag);
|
||||
PROFILE(FunctionCreateEvent(*function));
|
||||
return result;
|
||||
|
@ -179,7 +179,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
|
||||
|
||||
// Adjust for function-level 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);
|
||||
|
||||
@ -358,7 +358,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// Code generation state must be reset.
|
||||
|
@ -398,31 +398,16 @@ Handle<JSArray> LiveEdit::CompareStringsLinewise(Handle<String> s1,
|
||||
|
||||
|
||||
static void CompileScriptForTracker(Handle<Script> script) {
|
||||
const bool is_eval = false;
|
||||
const bool is_global = true;
|
||||
// TODO(635): support extensions.
|
||||
Extension* extension = NULL;
|
||||
|
||||
PostponeInterruptsScope postpone;
|
||||
|
||||
// Only allow non-global compiles for eval.
|
||||
ASSERT(is_eval || is_global);
|
||||
|
||||
// Build AST.
|
||||
ScriptDataImpl* pre_data = NULL;
|
||||
EagerCompilationInfo info(script, is_eval);
|
||||
FunctionLiteral* lit =
|
||||
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);
|
||||
CompilationInfo info(script);
|
||||
info.MarkAsGlobal();
|
||||
if (!Parser::Parse(&info)) return;
|
||||
|
||||
// Compile the code.
|
||||
LiveEditFunctionTracker tracker(lit);
|
||||
LiveEditFunctionTracker tracker(info.function());
|
||||
Handle<Code> code = MakeCodeForLiveEdit(&info);
|
||||
|
||||
// Check for stack-overflow exceptions.
|
||||
@ -433,11 +418,13 @@ static void CompileScriptForTracker(Handle<Script> script) {
|
||||
tracker.RecordRootFunctionInfo(code);
|
||||
}
|
||||
|
||||
|
||||
// Unwraps JSValue object, returning its field "value"
|
||||
static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) {
|
||||
return Handle<Object>(jsValue->value());
|
||||
}
|
||||
|
||||
|
||||
// Wraps any object into a OpaqueReference, that will hide the object
|
||||
// from JavaScript.
|
||||
static Handle<JSValue> WrapInJSValue(Object* object) {
|
||||
@ -448,6 +435,7 @@ static Handle<JSValue> WrapInJSValue(Object* object) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Simple helper class that creates more or less typed structures over
|
||||
// JSArray object. This is an adhoc method of passing structures from C++
|
||||
// to JavaScript.
|
||||
@ -468,6 +456,7 @@ class JSArrayBasedStruct {
|
||||
Handle<JSArray> GetJSArray() {
|
||||
return array_;
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetField(int field_position, Handle<Object> value) {
|
||||
SetElement(array_, field_position, value);
|
||||
@ -482,6 +471,7 @@ class JSArrayBasedStruct {
|
||||
Object* res = GetField(field_position);
|
||||
return Smi::cast(res)->value();
|
||||
}
|
||||
|
||||
private:
|
||||
Handle<JSArray> array_;
|
||||
};
|
||||
@ -554,6 +544,7 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
|
||||
friend class JSArrayBasedStruct<FunctionInfoWrapper>;
|
||||
};
|
||||
|
||||
|
||||
// Wraps SharedFunctionInfo along with some of its fields for passing it
|
||||
// back to JavaScript. SharedFunctionInfo object itself is additionally
|
||||
// wrapped into BlindReference for sanitizing reasons.
|
||||
@ -594,6 +585,7 @@ class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> {
|
||||
friend class JSArrayBasedStruct<SharedInfoWrapper>;
|
||||
};
|
||||
|
||||
|
||||
class FunctionInfoListener {
|
||||
public:
|
||||
FunctionInfoListener() {
|
||||
@ -620,7 +612,6 @@ class FunctionInfoListener {
|
||||
current_parent_index_ = info.GetParentIndex();
|
||||
}
|
||||
|
||||
public:
|
||||
// Saves only function code, because for a script function we
|
||||
// may never create a SharedFunctionInfo object.
|
||||
void FunctionCode(Handle<Code> function_code) {
|
||||
@ -708,6 +699,7 @@ class FunctionInfoListener {
|
||||
int current_parent_index_;
|
||||
};
|
||||
|
||||
|
||||
static FunctionInfoListener* active_function_info_listener = NULL;
|
||||
|
||||
JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script,
|
||||
|
@ -5344,43 +5344,42 @@ bool Parser::ParseRegExp(FlatStringReader* input,
|
||||
}
|
||||
|
||||
|
||||
FunctionLiteral* Parser::MakeAST(bool compile_in_global_context,
|
||||
Handle<Script> script,
|
||||
v8::Extension* extension,
|
||||
ScriptDataImpl* pre_data,
|
||||
bool is_json) {
|
||||
bool allow_natives_syntax =
|
||||
FLAG_allow_natives_syntax || Bootstrapper::IsActive();
|
||||
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);
|
||||
bool Parser::Parse(CompilationInfo* info) {
|
||||
ASSERT(info->function() == NULL);
|
||||
FunctionLiteral* result = NULL;
|
||||
Handle<Script> script = info->script();
|
||||
if (info->is_lazy()) {
|
||||
AstBuildingParser parser(script, true, NULL, NULL);
|
||||
result = parser.ParseLazy(info->shared_info());
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
||||
FunctionLiteral* Parser::MakeLazyAST(Handle<SharedFunctionInfo> info) {
|
||||
Handle<Script> script(Script::cast(info->script()));
|
||||
AstBuildingParser parser(script, true, NULL, NULL);
|
||||
FunctionLiteral* result = parser.ParseLazy(info);
|
||||
return result;
|
||||
info->SetFunction(result);
|
||||
return (result != NULL);
|
||||
}
|
||||
|
||||
#undef NEW
|
||||
|
16
src/parser.h
16
src/parser.h
@ -35,6 +35,7 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class CompilationInfo;
|
||||
class FuncNameInferrer;
|
||||
class ParserFactory;
|
||||
class ParserLog;
|
||||
@ -183,17 +184,10 @@ class Parser {
|
||||
ParserFactory* factory, ParserLog* log, ScriptDataImpl* pre_data);
|
||||
virtual ~Parser() { }
|
||||
|
||||
// Takes a script and and context information, and builds a
|
||||
// FunctionLiteral AST node. Returns NULL and deallocates any allocated
|
||||
// AST nodes if parsing failed.
|
||||
static FunctionLiteral* MakeAST(bool compile_in_global_context,
|
||||
Handle<Script> script,
|
||||
v8::Extension* extension,
|
||||
ScriptDataImpl* pre_data,
|
||||
bool is_json = false);
|
||||
|
||||
// Support for doing lazy compilation.
|
||||
static FunctionLiteral* MakeLazyAST(Handle<SharedFunctionInfo> info);
|
||||
// Parses the source code represented by the compilation info and sets its
|
||||
// function literal. Returns false (and deallocates any allocated AST
|
||||
// nodes) if parsing failed.
|
||||
static bool Parse(CompilationInfo* info);
|
||||
|
||||
// Generic preparser generating full preparse data.
|
||||
static ScriptDataImpl* PreParse(Handle<String> source,
|
||||
|
@ -178,7 +178,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
|
||||
|
||||
// Adjust for function-level 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);
|
||||
|
||||
@ -356,7 +356,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// Code generation state must be reset.
|
||||
|
Loading…
Reference in New Issue
Block a user