Avoid collecting symbol info for one-off preparsing.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5431 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
lrn@chromium.org 2010-09-09 11:49:21 +00:00
parent e5b63e7213
commit 67d8302779
3 changed files with 134 additions and 46 deletions

View File

@ -277,13 +277,11 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
// for small sources, odds are that there aren't many functions // for small sources, odds are that there aren't many functions
// that would be compiled lazily anyway, so we skip the preparse step // that would be compiled lazily anyway, so we skip the preparse step
// in that case too. // in that case too.
// TODO(lrn): Maybe *only* collect function info, not symbol info, in
// this case, since it's just replacing one hash-lookup with another.
ScriptDataImpl* pre_data = input_pre_data; ScriptDataImpl* pre_data = input_pre_data;
if (pre_data == NULL if (pre_data == NULL
&& FLAG_lazy && FLAG_lazy
&& source_length >= FLAG_min_preparse_length) { && source_length >= FLAG_min_preparse_length) {
pre_data = PreParse(source, NULL, extension); pre_data = PartialPreParse(source, NULL, extension);
} }
// Create a script object describing the script to be compiled. // Create a script object describing the script to be compiled.

View File

@ -872,11 +872,14 @@ class ParserLog BASE_EMBEDDED {
// Records the occurrence of a function. // Records the occurrence of a function.
virtual FunctionEntry LogFunction(int start) { return FunctionEntry(); } virtual FunctionEntry LogFunction(int start) { return FunctionEntry(); }
virtual void LogSymbol(int start, Vector<const char> symbol) {} virtual void LogSymbol(int start, Vector<const char> symbol) {}
virtual void LogError() { }
// Return the current position in the function entry log. // Return the current position in the function entry log.
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 LogError() { } virtual Vector<unsigned> ExtractData() {
return Vector<unsigned>();
};
}; };
@ -889,9 +892,14 @@ class AstBuildingParserFactory : public ParserFactory {
virtual Handle<String> LookupSymbol(int symbol_id, virtual Handle<String> LookupSymbol(int symbol_id,
Vector<const char> string) { Vector<const char> string) {
// If there is no preparse data, we have no simpler way to identify similar // Length of symbol cache is the number of identified symbols.
// symbols. // If we are larger than that, or negative, it's not a cached symbol.
if (symbol_id < 0) return Factory::LookupSymbol(string); // This might also happen if there is no preparser symbol data, even
// if there is some preparser data.
if (static_cast<unsigned>(symbol_id)
>= static_cast<unsigned>(symbol_cache_.length())) {
return Factory::LookupSymbol(string);
}
return LookupCachedSymbol(symbol_id, string); return LookupCachedSymbol(symbol_id, string);
} }
@ -933,10 +941,55 @@ class AstBuildingParserFactory : public ParserFactory {
}; };
class ParserRecorder: public ParserLog { // Record only functions.
class PartialParserRecorder: public ParserLog {
public: public:
ParserRecorder(); PartialParserRecorder();
virtual FunctionEntry LogFunction(int start); virtual FunctionEntry LogFunction(int start);
virtual int function_position() { return function_store_.size(); }
virtual void LogError() { }
virtual void LogMessage(Scanner::Location loc,
const char* message,
Vector<const char*> args);
virtual Vector<unsigned> ExtractData() {
int function_size = function_store_.size();
int total_size = ScriptDataImpl::kHeaderSize + function_size;
Vector<unsigned> data = Vector<unsigned>::New(total_size);
preamble_[ScriptDataImpl::kFunctionsSizeOffset] = function_size;
preamble_[ScriptDataImpl::kSymbolCountOffset] = 0;
memcpy(data.start(), preamble_, sizeof(preamble_));
int symbol_start = ScriptDataImpl::kHeaderSize + function_size;
if (function_size > 0) {
function_store_.WriteTo(data.SubVector(ScriptDataImpl::kHeaderSize,
symbol_start));
}
return data;
}
protected:
bool has_error() {
return static_cast<bool>(preamble_[ScriptDataImpl::kHasErrorOffset]);
}
void WriteString(Vector<const char> str);
Collector<unsigned> function_store_;
unsigned preamble_[ScriptDataImpl::kHeaderSize];
#ifdef DEBUG
int prev_start;
#endif
};
// Record both functions and symbols.
class CompleteParserRecorder: public PartialParserRecorder {
public:
CompleteParserRecorder();
virtual void LogSymbol(int start, Vector<const char> literal) { virtual void LogSymbol(int start, Vector<const char> literal) {
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);
@ -953,11 +1006,8 @@ class ParserRecorder: public ParserLog {
symbol_store_.Add(id - 1); symbol_store_.Add(id - 1);
} }
} }
virtual void LogError() { }
virtual void LogMessage(Scanner::Location loc, virtual Vector<unsigned> ExtractData() {
const char* message,
Vector<const char*> args);
Vector<unsigned> ExtractData() {
int function_size = function_store_.size(); int function_size = function_store_.size();
int symbol_size = symbol_store_.size(); int symbol_size = symbol_store_.size();
int total_size = ScriptDataImpl::kHeaderSize + function_size + symbol_size; int total_size = ScriptDataImpl::kHeaderSize + function_size + symbol_size;
@ -976,11 +1026,9 @@ class ParserRecorder: public ParserLog {
return data; return data;
} }
virtual int function_position() { return function_store_.size(); }
virtual int symbol_position() { return symbol_store_.size(); } virtual int symbol_position() { return symbol_store_.size(); }
virtual int symbol_ids() { return symbol_id_; } virtual int symbol_ids() { return symbol_id_; }
private: private:
Collector<unsigned> function_store_;
Collector<unsigned> symbol_store_; Collector<unsigned> symbol_store_;
Collector<Vector<const char> > symbol_entries_; Collector<Vector<const char> > symbol_entries_;
HashMap symbol_table_; HashMap symbol_table_;
@ -1004,16 +1052,6 @@ class ParserRecorder: public ParserLog {
if (string2->length() != length) return false; if (string2->length() != length) return false;
return memcmp(string1->start(), string2->start(), length) == 0; return memcmp(string1->start(), string2->start(), length) == 0;
} }
unsigned preamble_[ScriptDataImpl::kHeaderSize];
#ifdef DEBUG
int prev_start;
#endif
bool has_error() {
return static_cast<bool>(preamble_[ScriptDataImpl::kHasErrorOffset]);
}
void WriteString(Vector<const char> str);
}; };
@ -1088,15 +1126,8 @@ bool ScriptDataImpl::SanityCheck() {
} }
ParserRecorder::ParserRecorder()
: function_store_(0), PartialParserRecorder::PartialParserRecorder() : function_store_(0) {
symbol_store_(0),
symbol_entries_(0),
symbol_table_(vector_compare),
symbol_id_(0) {
#ifdef DEBUG
prev_start = -1;
#endif
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;
@ -1104,10 +1135,22 @@ ParserRecorder::ParserRecorder()
preamble_[ScriptDataImpl::kSymbolCountOffset] = 0; preamble_[ScriptDataImpl::kSymbolCountOffset] = 0;
preamble_[ScriptDataImpl::kSizeOffset] = 0; preamble_[ScriptDataImpl::kSizeOffset] = 0;
ASSERT_EQ(6, ScriptDataImpl::kHeaderSize); ASSERT_EQ(6, ScriptDataImpl::kHeaderSize);
#ifdef DEBUG
prev_start = -1;
#endif
} }
void ParserRecorder::WriteString(Vector<const char> str) { CompleteParserRecorder::CompleteParserRecorder()
: PartialParserRecorder(),
symbol_store_(0),
symbol_entries_(0),
symbol_table_(vector_compare),
symbol_id_(0) {
}
void PartialParserRecorder::WriteString(Vector<const char> str) {
function_store_.Add(str.length()); function_store_.Add(str.length());
for (int i = 0; i < str.length(); i++) { for (int i = 0; i < str.length(); i++) {
function_store_.Add(str[i]); function_store_.Add(str[i]);
@ -1127,8 +1170,9 @@ const char* ScriptDataImpl::ReadString(unsigned* start, int* chars) {
} }
void ParserRecorder::LogMessage(Scanner::Location loc, const char* message, void PartialParserRecorder::LogMessage(Scanner::Location loc,
Vector<const char*> args) { const char* message,
Vector<const char*> args) {
if (has_error()) return; if (has_error()) return;
preamble_[ScriptDataImpl::kHasErrorOffset] = true; preamble_[ScriptDataImpl::kHasErrorOffset] = true;
function_store_.Reset(); function_store_.Reset();
@ -1183,7 +1227,7 @@ unsigned* ScriptDataImpl::ReadAddress(int position) {
} }
FunctionEntry ParserRecorder::LogFunction(int start) { FunctionEntry PartialParserRecorder::LogFunction(int start) {
#ifdef DEBUG #ifdef DEBUG
ASSERT(start > prev_start); ASSERT(start > prev_start);
prev_start = start; prev_start = start;
@ -1206,7 +1250,7 @@ class AstBuildingParser : public Parser {
factory(), factory(),
log(), log(),
pre_data), pre_data),
factory_(pre_data ? pre_data->symbol_count() : 16) { } factory_(pre_data ? pre_data->symbol_count() : 0) { }
virtual void ReportMessageAt(Scanner::Location loc, const char* message, virtual void ReportMessageAt(Scanner::Location loc, const char* message,
Vector<const char*> args); Vector<const char*> args);
virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode, virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
@ -1223,23 +1267,44 @@ class AstBuildingParser : public Parser {
class PreParser : public Parser { class PreParser : public Parser {
public: public:
PreParser(Handle<Script> script, bool allow_natives_syntax, PreParser(Handle<Script> script, bool allow_natives_syntax,
v8::Extension* extension) v8::Extension* extension, ParserLog* recorder)
: Parser(script, allow_natives_syntax, extension, PREPARSE, : Parser(script, allow_natives_syntax, extension, PREPARSE,
factory(), recorder(), NULL), factory(), recorder, NULL),
factory_(true) { } factory_(true) { }
virtual void ReportMessageAt(Scanner::Location loc, const char* message, virtual void ReportMessageAt(Scanner::Location loc, const char* message,
Vector<const char*> args); Vector<const char*> args);
virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode, virtual VariableProxy* Declare(Handle<String> name, Variable::Mode mode,
FunctionLiteral* fun, bool resolve, bool* ok); FunctionLiteral* fun, bool resolve, bool* ok);
ParserFactory* factory() { return &factory_; } ParserFactory* factory() { return &factory_; }
ParserRecorder* recorder() { return &recorder_; } virtual PartialParserRecorder* recorder() = 0;
private: private:
ParserRecorder recorder_;
ParserFactory factory_; ParserFactory factory_;
}; };
class CompletePreParser : public PreParser {
public:
CompletePreParser(Handle<Script> script, bool allow_natives_syntax,
v8::Extension* extension)
: PreParser(script, allow_natives_syntax, extension, &recorder_) { }
virtual PartialParserRecorder* recorder() { return &recorder_; }
private:
CompleteParserRecorder recorder_;
};
class PartialPreParser : public PreParser {
public:
PartialPreParser(Handle<Script> script, bool allow_natives_syntax,
v8::Extension* extension)
: PreParser(script, allow_natives_syntax, extension, &recorder_) { }
virtual PartialParserRecorder* recorder() { return &recorder_; }
private:
PartialParserRecorder recorder_;
};
Scope* AstBuildingParserFactory::NewScope(Scope* parent, Scope::Type type, Scope* AstBuildingParserFactory::NewScope(Scope* parent, Scope::Type type,
bool inside_with) { bool inside_with) {
Scope* result = new Scope(parent, type); Scope* result = new Scope(parent, type);
@ -5413,6 +5478,25 @@ bool ScriptDataImpl::HasError() {
} }
// Preparse, but only collect data that is immediately useful,
// even if the preparser data is only used once.
ScriptDataImpl* PartialPreParse(Handle<String> source,
unibrow::CharacterStream* stream,
v8::Extension* extension) {
Handle<Script> no_script;
bool allow_natives_syntax =
always_allow_natives_syntax ||
FLAG_allow_natives_syntax ||
Bootstrapper::IsActive();
PartialPreParser parser(no_script, allow_natives_syntax, extension);
if (!parser.PreParseProgram(source, stream)) return NULL;
// Extract the accumulated data from the recorder as a single
// contiguous vector that we are responsible for disposing.
Vector<unsigned> store = parser.recorder()->ExtractData();
return new ScriptDataImpl(store);
}
ScriptDataImpl* PreParse(Handle<String> source, ScriptDataImpl* PreParse(Handle<String> source,
unibrow::CharacterStream* stream, unibrow::CharacterStream* stream,
v8::Extension* extension) { v8::Extension* extension) {
@ -5421,7 +5505,7 @@ ScriptDataImpl* PreParse(Handle<String> source,
always_allow_natives_syntax || always_allow_natives_syntax ||
FLAG_allow_natives_syntax || FLAG_allow_natives_syntax ||
Bootstrapper::IsActive(); Bootstrapper::IsActive();
PreParser parser(no_script, allow_natives_syntax, extension); CompletePreParser parser(no_script, allow_natives_syntax, extension);
if (!parser.PreParseProgram(source, stream)) return NULL; if (!parser.PreParseProgram(source, stream)) return NULL;
// Extract the accumulated data from the recorder as a single // Extract the accumulated data from the recorder as a single
// contiguous vector that we are responsible for disposing. // contiguous vector that we are responsible for disposing.

View File

@ -212,11 +212,17 @@ FunctionLiteral* MakeAST(bool compile_in_global_context,
ScriptDataImpl* pre_data, ScriptDataImpl* pre_data,
bool is_json = false); bool is_json = false);
// Generic preparser generating full preparse data.
ScriptDataImpl* PreParse(Handle<String> source, ScriptDataImpl* PreParse(Handle<String> source,
unibrow::CharacterStream* stream, unibrow::CharacterStream* stream,
v8::Extension* extension); v8::Extension* extension);
// Preparser that only does preprocessing that makes sense if only used
// immediately after.
ScriptDataImpl* PartialPreParse(Handle<String> source,
unibrow::CharacterStream* stream,
v8::Extension* extension);
bool ParseRegExp(FlatStringReader* input, bool ParseRegExp(FlatStringReader* input,
bool multiline, bool multiline,