Commit 8f7bfea2 authored by lrn@chromium.org's avatar lrn@chromium.org

Avoid logging preparse-data inside lazily compiled functions.

Reduces size of preparser data significantly when there are nested functions.
Also allows us to drop the "skip" fields of function entries,
that tells us how much preparse-data to skip when skipping the function source.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5541 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 1982f9d2
...@@ -877,12 +877,30 @@ class ParserLog BASE_EMBEDDED { ...@@ -877,12 +877,30 @@ class ParserLog BASE_EMBEDDED {
virtual int function_position() { return 0; } virtual int function_position() { return 0; }
virtual int symbol_position() { return 0; } virtual int symbol_position() { return 0; }
virtual int symbol_ids() { return 0; } virtual int symbol_ids() { return 0; }
virtual void PauseRecording() {}
virtual void ResumeRecording() {}
virtual Vector<unsigned> ExtractData() { virtual Vector<unsigned> ExtractData() {
return Vector<unsigned>(); return Vector<unsigned>();
}; };
}; };
class ConditionalLogPauseScope {
public:
ConditionalLogPauseScope(bool pause, ParserLog* log)
: log_(log), pause_(pause) {
if (pause) log->PauseRecording();
}
~ConditionalLogPauseScope() {
if (pause_) log_->ResumeRecording();
}
private:
ParserLog* log_;
bool pause_;
};
class AstBuildingParserFactory : public ParserFactory { class AstBuildingParserFactory : public ParserFactory {
public: public:
explicit AstBuildingParserFactory(int expected_symbols) explicit AstBuildingParserFactory(int expected_symbols)
...@@ -970,15 +988,31 @@ class PartialParserRecorder: public ParserLog { ...@@ -970,15 +988,31 @@ class PartialParserRecorder: public ParserLog {
return data; return data;
} }
virtual void PauseRecording() {
pause_count_++;
is_recording_ = false;
}
virtual void ResumeRecording() {
ASSERT(pause_count_ > 0);
if (--pause_count_ == 0) is_recording_ = !has_error();
}
protected: protected:
bool has_error() { bool has_error() {
return static_cast<bool>(preamble_[ScriptDataImpl::kHasErrorOffset]); return static_cast<bool>(preamble_[ScriptDataImpl::kHasErrorOffset]);
} }
bool is_recording() {
return is_recording_;
}
void WriteString(Vector<const char> str); void WriteString(Vector<const char> str);
Collector<unsigned> function_store_; Collector<unsigned> function_store_;
unsigned preamble_[ScriptDataImpl::kHeaderSize]; unsigned preamble_[ScriptDataImpl::kHeaderSize];
bool is_recording_;
int pause_count_;
#ifdef DEBUG #ifdef DEBUG
int prev_start; int prev_start;
#endif #endif
...@@ -991,6 +1025,7 @@ class CompleteParserRecorder: public PartialParserRecorder { ...@@ -991,6 +1025,7 @@ class CompleteParserRecorder: public PartialParserRecorder {
CompleteParserRecorder(); CompleteParserRecorder();
virtual void LogSymbol(int start, Vector<const char> literal) { virtual void LogSymbol(int start, Vector<const char> literal) {
if (!is_recording_) return;
int hash = vector_hash(literal); int hash = vector_hash(literal);
HashMap::Entry* entry = symbol_table_.Lookup(&literal, hash, true); HashMap::Entry* entry = symbol_table_.Lookup(&literal, hash, true);
int id = static_cast<int>(reinterpret_cast<intptr_t>(entry->value)); int id = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
...@@ -1061,13 +1096,6 @@ class CompleteParserRecorder: public PartialParserRecorder { ...@@ -1061,13 +1096,6 @@ class CompleteParserRecorder: public PartialParserRecorder {
}; };
void ScriptDataImpl::SkipFunctionEntry(int start) {
ASSERT(function_index_ + FunctionEntry::kSize <= store_.length());
ASSERT(static_cast<int>(store_[function_index_]) == start);
function_index_ += FunctionEntry::kSize;
}
FunctionEntry ScriptDataImpl::GetFunctionEntry(int start) { FunctionEntry ScriptDataImpl::GetFunctionEntry(int start) {
// The current pre-data entry must be a FunctionEntry with the given // The current pre-data entry must be a FunctionEntry with the given
// start position. // start position.
...@@ -1126,7 +1154,10 @@ bool ScriptDataImpl::SanityCheck() { ...@@ -1126,7 +1154,10 @@ bool ScriptDataImpl::SanityCheck() {
PartialParserRecorder::PartialParserRecorder() : function_store_(0) { PartialParserRecorder::PartialParserRecorder()
: function_store_(0),
is_recording_(true),
pause_count_(0) {
preamble_[ScriptDataImpl::kMagicOffset] = ScriptDataImpl::kMagicNumber; preamble_[ScriptDataImpl::kMagicOffset] = ScriptDataImpl::kMagicNumber;
preamble_[ScriptDataImpl::kVersionOffset] = ScriptDataImpl::kCurrentVersion; preamble_[ScriptDataImpl::kVersionOffset] = ScriptDataImpl::kCurrentVersion;
preamble_[ScriptDataImpl::kHasErrorOffset] = false; preamble_[ScriptDataImpl::kHasErrorOffset] = false;
...@@ -1202,6 +1233,7 @@ void PartialParserRecorder::LogMessage(Scanner::Location loc, ...@@ -1202,6 +1233,7 @@ void PartialParserRecorder::LogMessage(Scanner::Location loc,
for (int i = 0; i < args.length(); i++) { for (int i = 0; i < args.length(); i++) {
WriteString(CStrVector(args[i])); WriteString(CStrVector(args[i]));
} }
is_recording_ = false;
} }
...@@ -1248,7 +1280,7 @@ FunctionEntry PartialParserRecorder::LogFunction(int start) { ...@@ -1248,7 +1280,7 @@ FunctionEntry PartialParserRecorder::LogFunction(int start) {
ASSERT(start > prev_start); ASSERT(start > prev_start);
prev_start = start; prev_start = start;
#endif #endif
if (has_error()) return FunctionEntry(); if (!is_recording_) return FunctionEntry();
FunctionEntry result(function_store_.AddBlock(FunctionEntry::kSize, 0)); FunctionEntry result(function_store_.AddBlock(FunctionEntry::kSize, 0));
result.set_start_pos(start); result.set_start_pos(start);
return result; return result;
...@@ -1343,6 +1375,8 @@ Scope* ParserFactory::NewScope(Scope* parent, Scope::Type type, ...@@ -1343,6 +1375,8 @@ Scope* ParserFactory::NewScope(Scope* parent, Scope::Type type,
bool inside_with) { bool inside_with) {
ASSERT(parent != NULL); ASSERT(parent != NULL);
parent->type_ = type; parent->type_ = type;
// Initialize function is hijacked by DummyScope to increment scope depth.
parent->Initialize(inside_with);
return parent; return parent;
} }
...@@ -1415,6 +1449,7 @@ class LexicalScope BASE_EMBEDDED { ...@@ -1415,6 +1449,7 @@ class LexicalScope BASE_EMBEDDED {
} }
~LexicalScope() { ~LexicalScope() {
parser_->top_scope_->Leave();
parser_->top_scope_ = prev_scope_; parser_->top_scope_ = prev_scope_;
parser_->with_nesting_level_ = prev_level_; parser_->with_nesting_level_ = prev_level_;
} }
...@@ -1480,7 +1515,8 @@ bool Parser::PreParseProgram(Handle<String> source, ...@@ -1480,7 +1515,8 @@ bool Parser::PreParseProgram(Handle<String> source,
NoHandleAllocation no_handle_allocation; NoHandleAllocation no_handle_allocation;
scanner_.Initialize(source, stream, JAVASCRIPT); scanner_.Initialize(source, stream, JAVASCRIPT);
ASSERT(target_stack_ == NULL); ASSERT(target_stack_ == NULL);
mode_ = PARSE_EAGERLY; mode_ = FLAG_lazy ? PARSE_LAZILY : PARSE_EAGERLY;
if (allow_natives_syntax_ || extension_ != NULL) mode_ = PARSE_EAGERLY;
DummyScope top_scope; DummyScope top_scope;
LexicalScope scope(this, &top_scope); LexicalScope scope(this, &top_scope);
TemporaryScope temp_scope(this); TemporaryScope temp_scope(this);
...@@ -1658,7 +1694,10 @@ void Parser::ReportMessage(const char* type, Vector<const char*> args) { ...@@ -1658,7 +1694,10 @@ void Parser::ReportMessage(const char* type, Vector<const char*> args) {
Handle<String> Parser::GetSymbol(bool* ok) { Handle<String> Parser::GetSymbol(bool* ok) {
log()->LogSymbol(scanner_.location().beg_pos, scanner_.literal()); if (is_pre_parsing_) {
log()->LogSymbol(scanner_.location().beg_pos, scanner_.literal());
return Handle<String>::null();
}
int symbol_id = -1; int symbol_id = -1;
if (pre_data() != NULL) { if (pre_data() != NULL) {
symbol_id = pre_data()->GetSymbolIdentifier(); symbol_id = pre_data()->GetSymbolIdentifier();
...@@ -1971,7 +2010,7 @@ void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor, ...@@ -1971,7 +2010,7 @@ void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor,
} }
// Propagate the collected information on this property assignments. // Propagate the collected information on this property assignments.
if (top_scope_->is_function_scope()) { if (!is_pre_parsing_ && top_scope_->is_function_scope()) {
bool only_simple_this_property_assignments = bool only_simple_this_property_assignments =
this_property_assignment_finder.only_simple_this_property_assignments() this_property_assignment_finder.only_simple_this_property_assignments()
&& top_scope_->declarations()->length() == 0; && top_scope_->declarations()->length() == 0;
...@@ -4123,8 +4162,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, ...@@ -4123,8 +4162,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
int num_parameters = 0; int num_parameters = 0;
// Parse function body. // Parse function body.
{ Scope::Type type = Scope::FUNCTION_SCOPE; { Scope* scope =
Scope* scope = factory()->NewScope(top_scope_, type, inside_with()); factory()->NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
LexicalScope lexical_scope(this, scope); LexicalScope lexical_scope(this, scope);
TemporaryScope temp_scope(this); TemporaryScope temp_scope(this);
top_scope_->SetScopeName(name); top_scope_->SetScopeName(name);
...@@ -4155,7 +4194,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, ...@@ -4155,7 +4194,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
// NOTE: We create a proxy and resolve it here so that in the // NOTE: We create a proxy and resolve it here so that in the
// future we can change the AST to only refer to VariableProxies // future we can change the AST to only refer to VariableProxies
// instead of Variables and Proxis as is the case now. // instead of Variables and Proxis as is the case now.
if (!function_name.is_null() && function_name->length() > 0) { if (!is_pre_parsing_
&& !function_name.is_null()
&& function_name->length() > 0) {
Variable* fvar = top_scope_->DeclareFunctionVar(function_name); Variable* fvar = top_scope_->DeclareFunctionVar(function_name);
VariableProxy* fproxy = VariableProxy* fproxy =
top_scope_->NewUnresolved(function_name, inside_with()); top_scope_->NewUnresolved(function_name, inside_with());
...@@ -4189,22 +4230,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, ...@@ -4189,22 +4230,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
} }
Counters::total_preparse_skipped.Increment(end_pos - function_block_pos); Counters::total_preparse_skipped.Increment(end_pos - function_block_pos);
scanner_.SeekForward(end_pos); scanner_.SeekForward(end_pos);
pre_data()->Skip(entry.predata_function_skip(),
entry.predata_symbol_skip());
materialized_literal_count = entry.literal_count(); materialized_literal_count = entry.literal_count();
expected_property_count = entry.property_count(); expected_property_count = entry.property_count();
only_simple_this_property_assignments = false; only_simple_this_property_assignments = false;
this_property_assignments = Factory::empty_fixed_array(); this_property_assignments = Factory::empty_fixed_array();
Expect(Token::RBRACE, CHECK_OK); Expect(Token::RBRACE, CHECK_OK);
} else { } else {
if (pre_data() != NULL) { FunctionEntry entry;
// Skip pre-data entry for non-lazily compiled function. if (is_lazily_compiled) entry = log()->LogFunction(function_block_pos);
pre_data()->SkipFunctionEntry(function_block_pos); {
ConditionalLogPauseScope pause_if(is_lazily_compiled, log());
ParseSourceElements(&body, Token::RBRACE, CHECK_OK);
} }
FunctionEntry entry = log()->LogFunction(function_block_pos);
int predata_function_position_before = log()->function_position();
int predata_symbol_position_before = log()->symbol_position();
ParseSourceElements(&body, Token::RBRACE, CHECK_OK);
materialized_literal_count = temp_scope.materialized_literal_count(); materialized_literal_count = temp_scope.materialized_literal_count();
expected_property_count = temp_scope.expected_property_count(); expected_property_count = temp_scope.expected_property_count();
only_simple_this_property_assignments = only_simple_this_property_assignments =
...@@ -4214,13 +4251,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name, ...@@ -4214,13 +4251,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
Expect(Token::RBRACE, CHECK_OK); Expect(Token::RBRACE, CHECK_OK);
end_pos = scanner_.location().end_pos; end_pos = scanner_.location().end_pos;
if (entry.is_valid()) { if (entry.is_valid()) {
ASSERT(is_lazily_compiled);
ASSERT(is_pre_parsing_);
entry.set_end_pos(end_pos); entry.set_end_pos(end_pos);
entry.set_literal_count(materialized_literal_count); entry.set_literal_count(materialized_literal_count);
entry.set_property_count(expected_property_count); entry.set_property_count(expected_property_count);
entry.set_predata_function_skip(
log()->function_position() - predata_function_position_before);
entry.set_predata_symbol_skip(
log()->symbol_position() - predata_symbol_position_before);
} }
} }
...@@ -5625,8 +5660,6 @@ FunctionLiteral* MakeLazyAST(Handle<Script> script, ...@@ -5625,8 +5660,6 @@ FunctionLiteral* MakeLazyAST(Handle<Script> script,
return result; return result;
} }
#undef NEW #undef NEW
} } // namespace v8::internal } } // namespace v8::internal
...@@ -72,19 +72,9 @@ class FunctionEntry BASE_EMBEDDED { ...@@ -72,19 +72,9 @@ class FunctionEntry BASE_EMBEDDED {
backing_[kPropertyCountOffset] = value; backing_[kPropertyCountOffset] = value;
} }
int predata_function_skip() { return backing_[kPredataFunctionSkipOffset]; }
void set_predata_function_skip(int value) {
backing_[kPredataFunctionSkipOffset] = value;
}
int predata_symbol_skip() { return backing_[kPredataSymbolSkipOffset]; }
void set_predata_symbol_skip(int value) {
backing_[kPredataSymbolSkipOffset] = value;
}
bool is_valid() { return backing_.length() > 0; } bool is_valid() { return backing_.length() > 0; }
static const int kSize = 6; static const int kSize = 4;
private: private:
Vector<unsigned> backing_; Vector<unsigned> backing_;
...@@ -92,8 +82,6 @@ class FunctionEntry BASE_EMBEDDED { ...@@ -92,8 +82,6 @@ class FunctionEntry BASE_EMBEDDED {
static const int kEndPosOffset = 1; static const int kEndPosOffset = 1;
static const int kLiteralCountOffset = 2; static const int kLiteralCountOffset = 2;
static const int kPropertyCountOffset = 3; static const int kPropertyCountOffset = 3;
static const int kPredataFunctionSkipOffset = 4;
static const int kPredataSymbolSkipOffset = 5;
}; };
...@@ -117,7 +105,6 @@ class ScriptDataImpl : public ScriptData { ...@@ -117,7 +105,6 @@ class ScriptDataImpl : public ScriptData {
FunctionEntry GetFunctionEntry(int start); FunctionEntry GetFunctionEntry(int start);
int GetSymbolIdentifier(); int GetSymbolIdentifier();
void SkipFunctionEntry(int start);
bool SanityCheck(); bool SanityCheck();
Scanner::Location MessageLocation(); Scanner::Location MessageLocation();
...@@ -133,28 +120,8 @@ class ScriptDataImpl : public ScriptData { ...@@ -133,28 +120,8 @@ class ScriptDataImpl : public ScriptData {
unsigned magic() { return store_[kMagicOffset]; } unsigned magic() { return store_[kMagicOffset]; }
unsigned version() { return store_[kVersionOffset]; } unsigned version() { return store_[kVersionOffset]; }
// Skip forward in the preparser data by the given number
// of unsigned ints of function entries and the given number of bytes of
// symbol id encoding.
void Skip(int function_entries, int symbol_entries) {
ASSERT(function_entries >= 0);
ASSERT(function_entries
<= (static_cast<int>(store_[kFunctionsSizeOffset])
- (function_index_ - kHeaderSize)));
ASSERT(symbol_entries >= 0);
ASSERT(symbol_entries <= symbol_data_end_ - symbol_data_);
unsigned max_function_skip = store_[kFunctionsSizeOffset] -
static_cast<unsigned>(function_index_ - kHeaderSize);
function_index_ +=
Min(static_cast<unsigned>(function_entries), max_function_skip);
symbol_data_ +=
Min(static_cast<unsigned>(symbol_entries),
static_cast<unsigned>(symbol_data_end_ - symbol_data_));
}
static const unsigned kMagicNumber = 0xBadDead; static const unsigned kMagicNumber = 0xBadDead;
static const unsigned kCurrentVersion = 3; static const unsigned kCurrentVersion = 4;
static const int kMagicOffset = 0; static const int kMagicOffset = 0;
static const int kVersionOffset = 1; static const int kVersionOffset = 1;
......
...@@ -201,7 +201,6 @@ void Scope::Initialize(bool inside_with) { ...@@ -201,7 +201,6 @@ void Scope::Initialize(bool inside_with) {
} }
Variable* Scope::LocalLookup(Handle<String> name) { Variable* Scope::LocalLookup(Handle<String> name) {
return variables_.Lookup(name); return variables_.Lookup(name);
} }
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// A hash map to support fast variable declaration and lookup. // A hash map to support fast variable declaration and lookup.
class VariableMap: public HashMap { class VariableMap: public HashMap {
public: public:
...@@ -100,8 +99,12 @@ class Scope: public ZoneObject { ...@@ -100,8 +99,12 @@ class Scope: public ZoneObject {
// The scope name is only used for printing/debugging. // The scope name is only used for printing/debugging.
void SetScopeName(Handle<String> scope_name) { scope_name_ = scope_name; } void SetScopeName(Handle<String> scope_name) { scope_name_ = scope_name; }
void Initialize(bool inside_with); virtual void Initialize(bool inside_with);
// Called just before leaving a scope.
virtual void Leave() {
// No cleanup or fixup necessary.
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Declarations // Declarations
...@@ -272,7 +275,7 @@ class Scope: public ZoneObject { ...@@ -272,7 +275,7 @@ class Scope: public ZoneObject {
bool AllowsLazyCompilation() const; bool AllowsLazyCompilation() const;
// True if the outer context of this scope is always the global context. // True if the outer context of this scope is always the global context.
bool HasTrivialOuterContext() const; virtual bool HasTrivialOuterContext() const;
// The number of contexts between this and scope; zero if this == scope. // The number of contexts between this and scope; zero if this == scope.
int ContextChainLength(Scope* scope); int ContextChainLength(Scope* scope);
...@@ -378,20 +381,53 @@ class Scope: public ZoneObject { ...@@ -378,20 +381,53 @@ class Scope: public ZoneObject {
}; };
// Scope used during pre-parsing.
class DummyScope : public Scope { class DummyScope : public Scope {
public: public:
DummyScope() : Scope(GLOBAL_SCOPE) { DummyScope()
: Scope(GLOBAL_SCOPE),
nesting_level_(1), // Allows us to Leave the initial scope.
inside_with_level_(kNotInsideWith) {
outer_scope_ = this; outer_scope_ = this;
scope_inside_with_ = false;
} }
virtual Variable* Lookup(Handle<String> name) { return NULL; } virtual void Initialize(bool inside_with) {
virtual Variable* Declare(Handle<String> name, Variable::Mode mode) { nesting_level_++;
return NULL; if (inside_with && inside_with_level_ == kNotInsideWith) {
inside_with_level_ = nesting_level_;
}
ASSERT(inside_with_level_ <= nesting_level_);
} }
virtual void Leave() {
nesting_level_--;
ASSERT(nesting_level_ >= 0);
if (nesting_level_ < inside_with_level_) {
inside_with_level_ = kNotInsideWith;
}
ASSERT(inside_with_level_ <= nesting_level_);
}
virtual Variable* Lookup(Handle<String> name) { return NULL; }
virtual VariableProxy* NewUnresolved(Handle<String> name, bool inside_with) { virtual VariableProxy* NewUnresolved(Handle<String> name, bool inside_with) {
return NULL; return NULL;
} }
virtual VariableProxy* NewTemporary(Handle<String> name) { return NULL; } virtual VariableProxy* NewTemporary(Handle<String> name) { return NULL; }
virtual bool HasTrivialOuterContext() const {
return (nesting_level_ == 0 || inside_with_level_ <= 0);
}
private:
static const int kNotInsideWith = -1;
// Number of surrounding scopes of the current scope.
int nesting_level_;
// Nesting level of outermost scope that is contained in a with statement,
// or kNotInsideWith if there are no with's around the current scope.
int inside_with_level_;
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment