Chromium Code Reviews| Index: src/parser.cc |
| =================================================================== |
| --- src/parser.cc (revision 1358) |
| +++ src/parser.cc (working copy) |
| @@ -69,6 +69,10 @@ |
| Handle<String> name, |
| int start_position, bool is_expression); |
| + // The minimum number of contiguous assignment that is needed to |
| + // be treated as an initialization block. |
| + static const int kMinInitializationBlock = 3; |
|
Mads Ager (chromium)
2009/02/25 13:11:07
Is this limit based on benchmarking? We should ma
olehougaard
2009/02/26 07:31:44
It's based on benchmarking. I've added a comment t
|
| + |
| protected: |
| enum Mode { |
| @@ -1215,6 +1219,110 @@ |
| } |
| +// An InitializationBlockFinder finds and marks sequences of statements of the |
| +// form x.y.z.a = ...; x.y.z.b = ...; etc. |
| +class InitializationBlockFinder { |
| + public: |
| + InitializationBlockFinder() |
| + : first_in_block_(NULL), last_in_block_(NULL), block_size_(0) {} |
| + |
| + ~InitializationBlockFinder() { |
| + if (InBlock()) EndBlock(); |
| + } |
| + |
| + void Update(Statement* stat) { |
| + Assignment* assignment = AsAssignment(stat); |
| + if (InBlock()) { |
| + if (BlockContinues(assignment)) { |
| + UpdateBlock(assignment); |
| + } else { |
| + EndBlock(); |
| + } |
| + } |
| + if (!InBlock() && (assignment != NULL)) StartBlock(assignment); |
|
Mads Ager (chromium)
2009/02/25 13:11:07
In BlockContinues, you check if the operation is T
olehougaard
2009/02/26 07:31:44
Fixed.
|
| + } |
| + |
| + private: |
| + static Assignment* AsAssignment(Statement* stat) { |
| + if (stat == NULL) return NULL; |
| + ExpressionStatement* exp_stat = stat->AsExpressionStatement(); |
| + if (exp_stat == NULL) return NULL; |
| + return exp_stat->expression()->AsAssignment(); |
| + } |
| + |
| + // Returns true if the expressions appear to denote the same object. |
| + // In the context of initialization blocks, we only consider expressions |
| + // of the form 'x.y.z'. |
| + static bool SameObject(Expression* e1, Expression* e2); |
| + |
| + // Returns true if the expressions appear to denote different properties |
| + // of the same object. |
| + static bool PropertyOfSameObject(Expression* e1, Expression* e2) { |
| + Property* p1 = e1->AsProperty(); |
| + Property* p2 = e2->AsProperty(); |
| + if (p1 == NULL || p2 == NULL) return false; |
| + return SameObject(p1->obj(), p2->obj()); |
| + } |
| + |
| + bool BlockContinues(Assignment* assignment) { |
| + if (assignment == NULL || first_in_block_ == NULL) return false; |
| + if (assignment->op() != Token::ASSIGN) return false; |
|
iposva
2009/02/25 12:54:45
You check here that only ASSIGN statements are add
olehougaard
2009/02/26 07:31:44
Fixed.
|
| + return PropertyOfSameObject(first_in_block_->target(), |
| + assignment->target()); |
| + } |
| + |
| + void StartBlock(Assignment* assignment) { |
| + first_in_block_ = assignment; |
| + last_in_block_ = assignment; |
| + block_size_ = 1; |
| + } |
| + |
| + void UpdateBlock(Assignment* assignment) { |
| + last_in_block_ = assignment; |
| + ++block_size_; |
| + } |
| + |
| + void EndBlock() { |
| + if (block_size_ >= Parser::kMinInitializationBlock) { |
| + first_in_block_->mark_block_start(); |
| + last_in_block_->mark_block_end(); |
| + } |
| + last_in_block_ = first_in_block_ = NULL; |
| + block_size_ = 0; |
| + } |
| + |
| + bool InBlock() { return first_in_block_ != NULL; } |
| + |
| + Assignment* first_in_block_; |
| + Assignment* last_in_block_; |
| + int block_size_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(InitializationBlockFinder); |
| +}; |
| + |
| + |
| +bool InitializationBlockFinder::SameObject(Expression* e1, Expression* e2) { |
|
iposva
2009/02/25 12:54:45
What made you put this method outside the class de
olehougaard
2009/02/26 07:31:44
I've put all the code in the declaration for consi
|
| + VariableProxy* v1 = e1->AsVariableProxy(); |
| + VariableProxy* v2 = e2->AsVariableProxy(); |
| + if (v1 != NULL && v2 != NULL) { |
|
iposva
2009/02/25 12:54:45
In general I find code more readable when () are a
olehougaard
2009/02/26 07:31:44
Fixed where found.
|
| + return v1->name()->Equals(*v2->name()); |
| + } |
| + Property* p1 = e1->AsProperty(); |
| + Property* p2 = e2->AsProperty(); |
| + if (p1 == NULL || p2 == NULL) return false; |
| + Literal* key1 = p1->key()->AsLiteral(); |
| + Literal* key2 = p2->key()->AsLiteral(); |
| + if (key1 == NULL || key2 == NULL) return false; |
| + if (!key1->handle()->IsString() || !key2->handle()->IsString()) { |
| + return false; |
| + } |
| + String* name1 = String::cast(*key1->handle()); |
| + String* name2 = String::cast(*key2->handle()); |
| + if (!name1->Equals(name2)) return false; |
| + return SameObject(p1->obj(), p2->obj()); |
| +} |
| + |
| + |
| void* Parser::ParseSourceElements(ZoneListWrapper<Statement>* processor, |
| int end_token, |
| bool* ok) { |
| @@ -1228,9 +1336,15 @@ |
| TargetScope scope(this); |
| ASSERT(processor != NULL); |
| + InitializationBlockFinder block_finder; |
| while (peek() != end_token) { |
| Statement* stat = ParseStatement(NULL, CHECK_OK); |
| - if (stat && !stat->IsEmpty()) processor->Add(stat); |
| + if (stat == NULL || stat->IsEmpty()) continue; |
| + // We find and mark the initialization blocks on top level code only. |
| + // The optimizations of initialization blocks may result in a performance |
| + // degradation in any other scopes. |
|
Mads Ager (chromium)
2009/02/25 13:11:07
You should write here that the reason for only doi
olehougaard
2009/02/26 07:31:44
Fixed.
|
| + if (top_scope_->is_global_scope()) block_finder.Update(stat); |
| + processor->Add(stat); |
| } |
| return 0; |
| } |