Commit ebccde15 authored by lrn@chromium.org's avatar lrn@chromium.org

Don't preparse large files to find boundaries of lazy functions.

Instead use the preparser inline to parse only the lazy function
bodies.

This is still disabled for small files.
More measurements are needed to determine if lazy-compiling small
sources is worth it.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10066 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 50e5aaa7
...@@ -377,8 +377,14 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { ...@@ -377,8 +377,14 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
// Only allow non-global compiles for eval. // Only allow non-global compiles for eval.
ASSERT(info->is_eval() || info->is_global()); ASSERT(info->is_eval() || info->is_global());
ParsingFlags flags = kNoParsingFlags;
if (!ParserApi::Parse(info)) return Handle<SharedFunctionInfo>::null(); if (info->pre_parse_data() != NULL ||
String::cast(script->source())->length() > FLAG_min_preparse_length) {
flags = kAllowLazy;
}
if (!ParserApi::Parse(info, flags)) {
return Handle<SharedFunctionInfo>::null();
}
// 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
...@@ -453,7 +459,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, ...@@ -453,7 +459,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
int line_offset, int line_offset,
int column_offset, int column_offset,
v8::Extension* extension, v8::Extension* extension,
ScriptDataImpl* input_pre_data, ScriptDataImpl* pre_data,
Handle<Object> script_data, Handle<Object> script_data,
NativesFlag natives) { NativesFlag natives) {
Isolate* isolate = source->GetIsolate(); Isolate* isolate = source->GetIsolate();
...@@ -484,24 +490,12 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, ...@@ -484,24 +490,12 @@ 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.
ScriptDataImpl* pre_data = input_pre_data;
int flags = kNoParsingFlags; int flags = kNoParsingFlags;
if ((natives == NATIVES_CODE) || FLAG_allow_natives_syntax) { if ((natives == NATIVES_CODE) || FLAG_allow_natives_syntax) {
flags |= kAllowNativesSyntax; flags |= kAllowNativesSyntax;
} }
if (natives != NATIVES_CODE && FLAG_harmony_scoping) { if (natives != NATIVES_CODE && FLAG_harmony_scoping) {
flags |= kHarmonyScoping; flags |= EXTENDED_MODE;
}
if (pre_data == NULL
&& source_length >= FLAG_min_preparse_length) {
if (source->IsExternalTwoByteString()) {
ExternalTwoByteStringUC16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length());
pre_data = ParserApi::PartialPreParse(&stream, extension, flags);
} else {
GenericStringUC16CharacterStream stream(source, 0, source->length());
pre_data = ParserApi::PartialPreParse(&stream, extension, flags);
}
} }
// Create a script object describing the script to be compiled. // Create a script object describing the script to be compiled.
...@@ -527,11 +521,6 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, ...@@ -527,11 +521,6 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
if (extension == NULL && !result.is_null()) { if (extension == NULL && !result.is_null()) {
compilation_cache->PutScript(source, result); compilation_cache->PutScript(source, result);
} }
// Get rid of the pre-parsing data (if necessary).
if (input_pre_data == NULL && pre_data != NULL) {
delete pre_data;
}
} }
if (result.is_null()) isolate->ReportPendingMessages(); if (result.is_null()) isolate->ReportPendingMessages();
...@@ -604,7 +593,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) { ...@@ -604,7 +593,7 @@ bool Compiler::CompileLazy(CompilationInfo* info) {
isolate->counters()->total_compile_size()->Increment(compiled_size); isolate->counters()->total_compile_size()->Increment(compiled_size);
// Generate the AST for the lazily compiled function. // Generate the AST for the lazily compiled function.
if (ParserApi::Parse(info)) { if (ParserApi::Parse(info, kNoParsingFlags)) {
// Measure how long it takes to do the lazy compilation; only take the // Measure how long it takes to do the lazy compilation; only take the
// rest of the function into account to avoid overlap with the lazy // rest of the function into account to avoid overlap with the lazy
// parsing statistics. // parsing statistics.
......
...@@ -4763,7 +4763,7 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) { ...@@ -4763,7 +4763,7 @@ bool HGraphBuilder::TryInline(Call* expr, bool drop_extra) {
// Parse and allocate variables. // Parse and allocate variables.
CompilationInfo target_info(target); CompilationInfo target_info(target);
if (!ParserApi::Parse(&target_info) || if (!ParserApi::Parse(&target_info, kNoParsingFlags) ||
!Scope::Analyze(&target_info)) { !Scope::Analyze(&target_info)) {
if (target_info.isolate()->has_pending_exception()) { if (target_info.isolate()->has_pending_exception()) {
// Parse or scope error, never optimize this function. // Parse or scope error, never optimize this function.
......
...@@ -602,7 +602,8 @@ static void CompileScriptForTracker(Isolate* isolate, Handle<Script> script) { ...@@ -602,7 +602,8 @@ static void CompileScriptForTracker(Isolate* isolate, Handle<Script> script) {
// Build AST. // Build AST.
CompilationInfo info(script); CompilationInfo info(script);
info.MarkAsGlobal(); info.MarkAsGlobal();
if (ParserApi::Parse(&info)) { // Parse and don't allow skipping lazy functions.
if (ParserApi::Parse(&info, kNoParsingFlags)) {
// Compile the code. // Compile the code.
LiveEditFunctionTracker tracker(info.isolate(), info.function()); LiveEditFunctionTracker tracker(info.isolate(), info.function());
if (Compiler::MakeCodeForLiveEdit(&info)) { if (Compiler::MakeCodeForLiveEdit(&info)) {
......
This diff is collapsed.
...@@ -76,8 +76,10 @@ class FunctionEntry BASE_EMBEDDED { ...@@ -76,8 +76,10 @@ class FunctionEntry BASE_EMBEDDED {
kSize kSize
}; };
explicit FunctionEntry(Vector<unsigned> backing) : backing_(backing) { } explicit FunctionEntry(Vector<unsigned> backing)
FunctionEntry() { } : backing_(backing) { }
FunctionEntry() : backing_() { }
int start_pos() { return backing_[kStartPositionIndex]; } int start_pos() { return backing_[kStartPositionIndex]; }
int end_pos() { return backing_[kEndPositionIndex]; } int end_pos() { return backing_[kEndPositionIndex]; }
...@@ -94,6 +96,7 @@ class FunctionEntry BASE_EMBEDDED { ...@@ -94,6 +96,7 @@ class FunctionEntry BASE_EMBEDDED {
private: private:
Vector<unsigned> backing_; Vector<unsigned> backing_;
bool owns_data_;
}; };
...@@ -166,7 +169,7 @@ class ParserApi { ...@@ -166,7 +169,7 @@ class ParserApi {
// Parses the source code represented by the compilation info and sets its // Parses the source code represented by the compilation info and sets its
// function literal. Returns false (and deallocates any allocated AST // function literal. Returns false (and deallocates any allocated AST
// nodes) if parsing failed. // nodes) if parsing failed.
static bool Parse(CompilationInfo* info); static bool Parse(CompilationInfo* info, int flags);
// Generic preparser generating full preparse data. // Generic preparser generating full preparse data.
static ScriptDataImpl* PreParse(UC16CharacterStream* source, static ScriptDataImpl* PreParse(UC16CharacterStream* source,
...@@ -422,13 +425,20 @@ class RegExpParser { ...@@ -422,13 +425,20 @@ class RegExpParser {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// JAVASCRIPT PARSING // JAVASCRIPT PARSING
// Forward declaration.
class SingletonLogger;
class Parser { class Parser {
public: public:
Parser(Handle<Script> script, Parser(Handle<Script> script,
bool allow_natives_syntax, int parsing_flags, // Combination of ParsingFlags
v8::Extension* extension, v8::Extension* extension,
ScriptDataImpl* pre_data); ScriptDataImpl* pre_data);
virtual ~Parser() { } virtual ~Parser() {
if (reusable_preparser_ != NULL) {
delete reusable_preparser_;
}
}
// Returns NULL if parsing failed. // Returns NULL if parsing failed.
FunctionLiteral* ParseProgram(CompilationInfo* info); FunctionLiteral* ParseProgram(CompilationInfo* info);
...@@ -728,12 +738,15 @@ class Parser { ...@@ -728,12 +738,15 @@ class Parser {
Handle<String> type, Handle<String> type,
Vector< Handle<Object> > arguments); Vector< Handle<Object> > arguments);
preparser::PreParser::PreParseResult LazyParseFunctionLiteral(
SingletonLogger* logger);
Isolate* isolate_; Isolate* isolate_;
ZoneList<Handle<String> > symbol_cache_; ZoneList<Handle<String> > symbol_cache_;
Handle<Script> script_; Handle<Script> script_;
Scanner scanner_; Scanner scanner_;
preparser::PreParser* reusable_preparser_;
Scope* top_scope_; Scope* top_scope_;
FunctionState* current_function_state_; FunctionState* current_function_state_;
Target* target_stack_; // for break, continue statements Target* target_stack_; // for break, continue statements
...@@ -743,6 +756,7 @@ class Parser { ...@@ -743,6 +756,7 @@ class Parser {
Mode mode_; Mode mode_;
bool allow_natives_syntax_; bool allow_natives_syntax_;
bool allow_lazy_;
bool stack_overflow_; bool stack_overflow_;
// If true, the next (and immediately following) function literal is // If true, the next (and immediately following) function literal is
// preceded by a parenthesis. // preceded by a parenthesis.
......
...@@ -52,6 +52,34 @@ int isfinite(double value); ...@@ -52,6 +52,34 @@ int isfinite(double value);
namespace preparser { namespace preparser {
PreParser::PreParseResult PreParser::PreParseLazyFunction(
i::LanguageMode mode, i::ParserRecorder* log) {
log_ = log;
// Lazy functions always have trivial outer scopes (no with/catch scopes).
Scope top_scope(&scope_, kTopLevelScope);
set_language_mode(mode);
Scope function_scope(&scope_, kFunctionScope);
ASSERT_EQ(i::Token::LBRACE, scanner_->current_token());
bool ok = true;
int start_position = scanner_->peek_location().beg_pos;
ParseLazyFunctionLiteralBody(&ok);
if (stack_overflow_) return kPreParseStackOverflow;
if (!ok) {
ReportUnexpectedToken(scanner_->current_token());
} else {
ASSERT_EQ(i::Token::RBRACE, scanner_->peek());
if (!is_classic_mode()) {
int end_pos = scanner_->location().end_pos;
CheckOctalLiteral(start_position, end_pos, &ok);
if (ok) {
CheckDelayedStrictModeViolation(start_position, end_pos, &ok);
}
}
}
return kPreParseSuccess;
}
// Preparsing checks a JavaScript program and emits preparse-data that helps // Preparsing checks a JavaScript program and emits preparse-data that helps
// a later parsing to be faster. // a later parsing to be faster.
// See preparser-data.h for the data. // See preparser-data.h for the data.
...@@ -1350,9 +1378,6 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) { ...@@ -1350,9 +1378,6 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
} }
Expect(i::Token::RPAREN, CHECK_OK); Expect(i::Token::RPAREN, CHECK_OK);
Expect(i::Token::LBRACE, CHECK_OK);
int function_block_pos = scanner_->location().beg_pos;
// Determine if the function will be lazily compiled. // Determine if the function will be lazily compiled.
// Currently only happens to top-level functions. // Currently only happens to top-level functions.
// Optimistically assume that all top-level functions are lazily compiled. // Optimistically assume that all top-level functions are lazily compiled.
...@@ -1361,24 +1386,13 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) { ...@@ -1361,24 +1386,13 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
!parenthesized_function_); !parenthesized_function_);
parenthesized_function_ = false; parenthesized_function_ = false;
Expect(i::Token::LBRACE, CHECK_OK);
if (is_lazily_compiled) { if (is_lazily_compiled) {
log_->PauseRecording(); ParseLazyFunctionLiteralBody(CHECK_OK);
ParseSourceElements(i::Token::RBRACE, ok);
log_->ResumeRecording();
if (!*ok) Expression::Default();
Expect(i::Token::RBRACE, CHECK_OK);
// Position right after terminal '}'.
int end_pos = scanner_->location().end_pos;
log_->LogFunction(function_block_pos, end_pos,
function_scope.materialized_literal_count(),
function_scope.expected_properties(),
language_mode());
} else { } else {
ParseSourceElements(i::Token::RBRACE, CHECK_OK); ParseSourceElements(i::Token::RBRACE, ok);
Expect(i::Token::RBRACE, CHECK_OK);
} }
Expect(i::Token::RBRACE, CHECK_OK);
if (!is_classic_mode()) { if (!is_classic_mode()) {
int end_position = scanner_->location().end_pos; int end_position = scanner_->location().end_pos;
...@@ -1391,6 +1405,23 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) { ...@@ -1391,6 +1405,23 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool* ok) {
} }
void PreParser::ParseLazyFunctionLiteralBody(bool* ok) {
int body_start = scanner_->location().beg_pos;
log_->PauseRecording();
ParseSourceElements(i::Token::RBRACE, ok);
log_->ResumeRecording();
if (!*ok) return;
// Position right after terminal '}'.
ASSERT_EQ(i::Token::RBRACE, scanner_->peek());
int body_end = scanner_->peek_location().end_pos;
log_->LogFunction(body_start, body_end,
scope_->materialized_literal_count(),
scope_->expected_properties(),
language_mode());
}
PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) { PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
// CallRuntime :: // CallRuntime ::
// '%' Identifier Arguments // '%' Identifier Arguments
......
...@@ -110,6 +110,24 @@ class PreParser { ...@@ -110,6 +110,24 @@ class PreParser {
kPreParseSuccess kPreParseSuccess
}; };
PreParser(i::Scanner* scanner,
i::ParserRecorder* log,
uintptr_t stack_limit,
bool allow_lazy,
bool allow_natives_syntax)
: scanner_(scanner),
log_(log),
scope_(NULL),
stack_limit_(stack_limit),
strict_mode_violation_location_(i::Scanner::Location::invalid()),
strict_mode_violation_type_(NULL),
stack_overflow_(false),
allow_lazy_(allow_lazy),
allow_natives_syntax_(allow_natives_syntax),
parenthesized_function_(false),
harmony_scoping_(scanner->HarmonyScoping()) { }
~PreParser() {} ~PreParser() {}
// Pre-parse the program from the character stream; returns true on // Pre-parse the program from the character stream; returns true on
...@@ -126,6 +144,17 @@ class PreParser { ...@@ -126,6 +144,17 @@ class PreParser {
allow_lazy, allow_natives_syntax).PreParse(); allow_lazy, allow_natives_syntax).PreParse();
} }
// Parses a single function literal, from the opening parentheses before
// parameters to the closing brace after the body.
// Returns a FunctionEntry describing the body of the funciton in enough
// detail that it can be lazily compiled.
// The scanner is expected to have matched the "function" keyword and
// parameters, and have consumed the initial '{'.
// At return, unless an error occured, the scanner is positioned before the
// the final '}'.
PreParseResult PreParseLazyFunction(i::LanguageMode mode,
i::ParserRecorder* log);
private: private:
// Used to detect duplicates in object literals. Each of the values // Used to detect duplicates in object literals. Each of the values
// kGetterProperty, kSetterProperty and kValueProperty represents // kGetterProperty, kSetterProperty and kValueProperty represents
...@@ -450,24 +479,6 @@ class PreParser { ...@@ -450,24 +479,6 @@ class PreParser {
i::LanguageMode language_mode_; i::LanguageMode language_mode_;
}; };
// Private constructor only used in PreParseProgram.
PreParser(i::Scanner* scanner,
i::ParserRecorder* log,
uintptr_t stack_limit,
bool allow_lazy,
bool allow_natives_syntax)
: scanner_(scanner),
log_(log),
scope_(NULL),
stack_limit_(stack_limit),
strict_mode_violation_location_(i::Scanner::Location::invalid()),
strict_mode_violation_type_(NULL),
stack_overflow_(false),
allow_lazy_(allow_lazy),
allow_natives_syntax_(allow_natives_syntax),
parenthesized_function_(false),
harmony_scoping_(scanner->HarmonyScoping()) { }
// Preparse the program. Only called in PreParseProgram after creating // Preparse the program. Only called in PreParseProgram after creating
// the instance. // the instance.
PreParseResult PreParse() { PreParseResult PreParse() {
...@@ -547,6 +558,7 @@ class PreParser { ...@@ -547,6 +558,7 @@ class PreParser {
Arguments ParseArguments(bool* ok); Arguments ParseArguments(bool* ok);
Expression ParseFunctionLiteral(bool* ok); Expression ParseFunctionLiteral(bool* ok);
void ParseLazyFunctionLiteralBody(bool* ok);
Identifier ParseIdentifier(bool* ok); Identifier ParseIdentifier(bool* ok);
Identifier ParseIdentifierName(bool* ok); Identifier ParseIdentifierName(bool* ok);
......
...@@ -42,15 +42,23 @@ namespace v8 { ...@@ -42,15 +42,23 @@ namespace v8 {
namespace internal { namespace internal {
// General collection of bit-flags that can be passed to scanners and // General collection of (multi-)bit-flags that can be passed to scanners and
// parsers to signify their (initial) mode of operation. // parsers to signify their (initial) mode of operation.
enum ParsingFlags { enum ParsingFlags {
kNoParsingFlags = 0, kNoParsingFlags = 0,
kAllowLazy = 1, // Embed LanguageMode values in parsing flags, i.e., equivalent to:
kAllowNativesSyntax = 2, // CLASSIC_MODE = 0,
kHarmonyScoping = 4 // STRICT_MODE,
// EXTENDED_MODE,
kLanguageModeMask = 0x03,
kAllowLazy = 4,
kAllowNativesSyntax = 8
}; };
STATIC_ASSERT((kLanguageModeMask & CLASSIC_MODE) == CLASSIC_MODE);
STATIC_ASSERT((kLanguageModeMask & STRICT_MODE) == STRICT_MODE);
STATIC_ASSERT((kLanguageModeMask & EXTENDED_MODE) == EXTENDED_MODE);
// Returns the value (0 .. 15) of a hexadecimal character c. // Returns the value (0 .. 15) of a hexadecimal character c.
// If c is not a legal hexadecimal character, returns a value < 0. // If c is not a legal hexadecimal character, returns a value < 0.
......
...@@ -862,7 +862,7 @@ TEST(ScopePositions) { ...@@ -862,7 +862,7 @@ TEST(ScopePositions) {
i::Handle<i::String> source( i::Handle<i::String> source(
FACTORY->NewStringFromAscii(i::CStrVector(program.start()))); FACTORY->NewStringFromAscii(i::CStrVector(program.start())));
i::Handle<i::Script> script = FACTORY->NewScript(source); i::Handle<i::Script> script = FACTORY->NewScript(source);
i::Parser parser(script, false, NULL, NULL); i::Parser parser(script, i::kAllowLazy | i::EXTENDED_MODE, NULL, NULL);
i::CompilationInfo info(script); i::CompilationInfo info(script);
info.MarkAsGlobal(); info.MarkAsGlobal();
info.SetLanguageMode(source_data[i].language_mode); info.SetLanguageMode(source_data[i].language_mode);
......
...@@ -28,10 +28,9 @@ ...@@ -28,10 +28,9 @@
// Test that the illegal continue is thrown at parse time. // Test that the illegal continue is thrown at parse time.
try { try {
function Crash() { continue;if (Crash) { eval("function Crash() { assertUnreachable(); continue;if (Crash) { } }");
} }
Crash(); Crash();
assertTrue(false); assertUnreachable();
} catch (e) { } catch (e) {
assertTrue(e instanceof SyntaxError); assertTrue(e instanceof SyntaxError);
assertTrue(/continue/.test(e.message)); assertTrue(/continue/.test(e.message));
......
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