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 {
virtual int function_position() { return 0; }
virtual int symbol_position() { return 0; }
virtual int symbol_ids() { return 0; }
virtual void PauseRecording() {}
virtual void ResumeRecording() {}
virtual Vector<unsigned> ExtractData() {
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 {
public:
explicit AstBuildingParserFactory(int expected_symbols)
......@@ -970,15 +988,31 @@ class PartialParserRecorder: public ParserLog {
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:
bool has_error() {
return static_cast<bool>(preamble_[ScriptDataImpl::kHasErrorOffset]);
}
bool is_recording() {
return is_recording_;
}
void WriteString(Vector<const char> str);
Collector<unsigned> function_store_;
unsigned preamble_[ScriptDataImpl::kHeaderSize];
bool is_recording_;
int pause_count_;
#ifdef DEBUG
int prev_start;
#endif
......@@ -991,6 +1025,7 @@ class CompleteParserRecorder: public PartialParserRecorder {
CompleteParserRecorder();
virtual void LogSymbol(int start, Vector<const char> literal) {
if (!is_recording_) return;
int hash = vector_hash(literal);
HashMap::Entry* entry = symbol_table_.Lookup(&literal, hash, true);
int id = static_cast<int>(reinterpret_cast<intptr_t>(entry->value));
......@@ -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) {
// The current pre-data entry must be a FunctionEntry with the given
// start position.
......@@ -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::kVersionOffset] = ScriptDataImpl::kCurrentVersion;
preamble_[ScriptDataImpl::kHasErrorOffset] = false;
......@@ -1202,6 +1233,7 @@ void PartialParserRecorder::LogMessage(Scanner::Location loc,
for (int i = 0; i < args.length(); i++) {
WriteString(CStrVector(args[i]));
}
is_recording_ = false;
}
......@@ -1248,7 +1280,7 @@ FunctionEntry PartialParserRecorder::LogFunction(int start) {
ASSERT(start > prev_start);
prev_start = start;
#endif
if (has_error()) return FunctionEntry();
if (!is_recording_) return FunctionEntry();
FunctionEntry result(function_store_.AddBlock(FunctionEntry::kSize, 0));
result.set_start_pos(start);
return result;
......@@ -1343,6 +1375,8 @@ Scope* ParserFactory::NewScope(Scope* parent, Scope::Type type,
bool inside_with) {
ASSERT(parent != NULL);
parent->type_ = type;
// Initialize function is hijacked by DummyScope to increment scope depth.
parent->Initialize(inside_with);
return parent;
}
......@@ -1415,6 +1449,7 @@ class LexicalScope BASE_EMBEDDED {
}
~LexicalScope() {
parser_->top_scope_->Leave();
parser_->top_scope_ = prev_scope_;
parser_->with_nesting_level_ = prev_level_;
}
......@@ -1480,7 +1515,8 @@ bool Parser::PreParseProgram(Handle<String> source,
NoHandleAllocation no_handle_allocation;
scanner_.Initialize(source, stream, JAVASCRIPT);
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;
LexicalScope scope(this, &top_scope);
TemporaryScope temp_scope(this);
......@@ -1658,7 +1694,10 @@ void Parser::ReportMessage(const char* type, Vector<const char*> args) {
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;
if (pre_data() != NULL) {
symbol_id = pre_data()->GetSymbolIdentifier();
......@@ -1971,7 +2010,7 @@ void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor,
}
// 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 =
this_property_assignment_finder.only_simple_this_property_assignments()
&& top_scope_->declarations()->length() == 0;
......@@ -4123,8 +4162,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
int num_parameters = 0;
// Parse function body.
{ Scope::Type type = Scope::FUNCTION_SCOPE;
Scope* scope = factory()->NewScope(top_scope_, type, inside_with());
{ Scope* scope =
factory()->NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with());
LexicalScope lexical_scope(this, scope);
TemporaryScope temp_scope(this);
top_scope_->SetScopeName(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
// future we can change the AST to only refer to VariableProxies
// 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);
VariableProxy* fproxy =
top_scope_->NewUnresolved(function_name, inside_with());
......@@ -4189,22 +4230,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
}
Counters::total_preparse_skipped.Increment(end_pos - function_block_pos);
scanner_.SeekForward(end_pos);
pre_data()->Skip(entry.predata_function_skip(),
entry.predata_symbol_skip());
materialized_literal_count = entry.literal_count();
expected_property_count = entry.property_count();
only_simple_this_property_assignments = false;
this_property_assignments = Factory::empty_fixed_array();
Expect(Token::RBRACE, CHECK_OK);
} else {
if (pre_data() != NULL) {
// Skip pre-data entry for non-lazily compiled function.
pre_data()->SkipFunctionEntry(function_block_pos);
FunctionEntry entry;
if (is_lazily_compiled) entry = log()->LogFunction(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();
expected_property_count = temp_scope.expected_property_count();
only_simple_this_property_assignments =
......@@ -4214,13 +4251,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
Expect(Token::RBRACE, CHECK_OK);
end_pos = scanner_.location().end_pos;
if (entry.is_valid()) {
ASSERT(is_lazily_compiled);
ASSERT(is_pre_parsing_);
entry.set_end_pos(end_pos);
entry.set_literal_count(materialized_literal_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,
return result;
}
#undef NEW
} } // namespace v8::internal
......@@ -72,19 +72,9 @@ class FunctionEntry BASE_EMBEDDED {
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; }
static const int kSize = 6;
static const int kSize = 4;
private:
Vector<unsigned> backing_;
......@@ -92,8 +82,6 @@ class FunctionEntry BASE_EMBEDDED {
static const int kEndPosOffset = 1;
static const int kLiteralCountOffset = 2;
static const int kPropertyCountOffset = 3;
static const int kPredataFunctionSkipOffset = 4;
static const int kPredataSymbolSkipOffset = 5;
};
......@@ -117,7 +105,6 @@ class ScriptDataImpl : public ScriptData {
FunctionEntry GetFunctionEntry(int start);
int GetSymbolIdentifier();
void SkipFunctionEntry(int start);
bool SanityCheck();
Scanner::Location MessageLocation();
......@@ -133,28 +120,8 @@ class ScriptDataImpl : public ScriptData {
unsigned magic() { return store_[kMagicOffset]; }
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 kCurrentVersion = 3;
static const unsigned kCurrentVersion = 4;
static const int kMagicOffset = 0;
static const int kVersionOffset = 1;
......
......@@ -201,7 +201,6 @@ void Scope::Initialize(bool inside_with) {
}
Variable* Scope::LocalLookup(Handle<String> name) {
return variables_.Lookup(name);
}
......
......@@ -34,7 +34,6 @@
namespace v8 {
namespace internal {
// A hash map to support fast variable declaration and lookup.
class VariableMap: public HashMap {
public:
......@@ -100,8 +99,12 @@ class Scope: public ZoneObject {
// The scope name is only used for printing/debugging.
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
......@@ -272,7 +275,7 @@ class Scope: public ZoneObject {
bool AllowsLazyCompilation() const;
// 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.
int ContextChainLength(Scope* scope);
......@@ -378,20 +381,53 @@ class Scope: public ZoneObject {
};
// Scope used during pre-parsing.
class DummyScope : public Scope {
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;
scope_inside_with_ = false;
}
virtual Variable* Lookup(Handle<String> name) { return NULL; }
virtual Variable* Declare(Handle<String> name, Variable::Mode mode) {
return NULL;
virtual void Initialize(bool inside_with) {
nesting_level_++;
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) {
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