Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/parsing/rewriter.h" | 5 #include "src/parsing/rewriter.h" |
| 6 | 6 |
| 7 #include "src/ast/ast.h" | 7 #include "src/ast/ast.h" |
| 8 #include "src/ast/scopes.h" | 8 #include "src/ast/scopes.h" |
| 9 #include "src/parsing/parse-info.h" | 9 #include "src/parsing/parse-info.h" |
| 10 #include "src/parsing/parser.h" | 10 #include "src/parsing/parser.h" |
| 11 | 11 |
| 12 namespace v8 { | 12 namespace v8 { |
| 13 namespace internal { | 13 namespace internal { |
| 14 | 14 |
| 15 class Processor final : public AstVisitor<Processor> { | 15 class Processor final : public AstVisitor<Processor> { |
| 16 public: | 16 public: |
| 17 Processor(Isolate* isolate, DeclarationScope* closure_scope, Variable* result, | 17 Processor(Isolate* isolate, DeclarationScope* closure_scope, Variable* result, |
| 18 AstValueFactory* ast_value_factory) | 18 AstValueFactory* ast_value_factory) |
| 19 : result_(result), | 19 : result_(result), |
| 20 result_assigned_(false), | 20 result_assigned_(false), |
| 21 replacement_(nullptr), | 21 replacement_(nullptr), |
| 22 is_set_(false), | 22 is_set_(false), |
| 23 breakable_(false), | |
| 23 zone_(ast_value_factory->zone()), | 24 zone_(ast_value_factory->zone()), |
| 24 closure_scope_(closure_scope), | 25 closure_scope_(closure_scope), |
| 25 factory_(ast_value_factory) { | 26 factory_(ast_value_factory) { |
| 26 DCHECK_EQ(closure_scope, closure_scope->GetClosureScope()); | 27 DCHECK_EQ(closure_scope, closure_scope->GetClosureScope()); |
| 27 InitializeAstVisitor(isolate); | 28 InitializeAstVisitor(isolate); |
| 28 } | 29 } |
| 29 | 30 |
| 30 Processor(Parser* parser, DeclarationScope* closure_scope, Variable* result, | 31 Processor(Parser* parser, DeclarationScope* closure_scope, Variable* result, |
| 31 AstValueFactory* ast_value_factory) | 32 AstValueFactory* ast_value_factory) |
| 32 : result_(result), | 33 : result_(result), |
| 33 result_assigned_(false), | 34 result_assigned_(false), |
| 34 replacement_(nullptr), | 35 replacement_(nullptr), |
| 35 is_set_(false), | 36 is_set_(false), |
| 37 breakable_(false), | |
| 36 zone_(ast_value_factory->zone()), | 38 zone_(ast_value_factory->zone()), |
| 37 closure_scope_(closure_scope), | 39 closure_scope_(closure_scope), |
| 38 factory_(ast_value_factory) { | 40 factory_(ast_value_factory) { |
| 39 DCHECK_EQ(closure_scope, closure_scope->GetClosureScope()); | 41 DCHECK_EQ(closure_scope, closure_scope->GetClosureScope()); |
| 40 InitializeAstVisitor(parser->stack_limit()); | 42 InitializeAstVisitor(parser->stack_limit()); |
| 41 } | 43 } |
| 42 | 44 |
| 43 void Process(ZoneList<Statement*>* statements); | 45 void Process(ZoneList<Statement*>* statements); |
| 44 bool result_assigned() const { return result_assigned_; } | 46 bool result_assigned() const { return result_assigned_; } |
| 45 | 47 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 70 // When visiting a node, we "return" a replacement for that node in | 72 // When visiting a node, we "return" a replacement for that node in |
| 71 // [replacement_]. In many cases this will just be the original node. | 73 // [replacement_]. In many cases this will just be the original node. |
| 72 Statement* replacement_; | 74 Statement* replacement_; |
| 73 | 75 |
| 74 // To avoid storing to .result all the time, we eliminate some of | 76 // To avoid storing to .result all the time, we eliminate some of |
| 75 // the stores by keeping track of whether or not we're sure .result | 77 // the stores by keeping track of whether or not we're sure .result |
| 76 // will be overwritten anyway. This is a bit more tricky than what I | 78 // will be overwritten anyway. This is a bit more tricky than what I |
| 77 // was hoping for. | 79 // was hoping for. |
| 78 bool is_set_; | 80 bool is_set_; |
| 79 | 81 |
| 82 bool breakable_; | |
| 83 | |
| 84 class BreakableScope final { | |
| 85 public: | |
| 86 explicit BreakableScope(Processor* processor, bool breakable = true) | |
| 87 : processor_(processor), previous_(processor->breakable_) { | |
| 88 processor->breakable_ = processor->breakable_ || breakable; | |
| 89 } | |
| 90 | |
| 91 ~BreakableScope() { processor_->breakable_ = previous_; } | |
| 92 | |
| 93 private: | |
| 94 Processor* processor_; | |
| 95 bool previous_; | |
| 96 }; | |
| 97 | |
| 80 Zone* zone_; | 98 Zone* zone_; |
| 81 DeclarationScope* closure_scope_; | 99 DeclarationScope* closure_scope_; |
| 82 AstNodeFactory factory_; | 100 AstNodeFactory factory_; |
| 83 | 101 |
| 84 // Node visitors. | 102 // Node visitors. |
| 85 #define DEF_VISIT(type) void Visit##type(type* node); | 103 #define DEF_VISIT(type) void Visit##type(type* node); |
| 86 AST_NODE_LIST(DEF_VISIT) | 104 AST_NODE_LIST(DEF_VISIT) |
| 87 #undef DEF_VISIT | 105 #undef DEF_VISIT |
| 88 | 106 |
| 89 void VisitIterationStatement(IterationStatement* stmt); | 107 void VisitIterationStatement(IterationStatement* stmt); |
| 90 | 108 |
| 91 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); | 109 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); |
| 92 }; | 110 }; |
| 93 | 111 |
| 94 | 112 |
| 95 Statement* Processor::AssignUndefinedBefore(Statement* s) { | 113 Statement* Processor::AssignUndefinedBefore(Statement* s) { |
| 96 Expression* result_proxy = factory()->NewVariableProxy(result_); | 114 Expression* result_proxy = factory()->NewVariableProxy(result_); |
| 97 Expression* undef = factory()->NewUndefinedLiteral(kNoSourcePosition); | 115 Expression* undef = factory()->NewUndefinedLiteral(kNoSourcePosition); |
| 98 Expression* assignment = factory()->NewAssignment(Token::ASSIGN, result_proxy, | 116 Expression* assignment = factory()->NewAssignment(Token::ASSIGN, result_proxy, |
| 99 undef, kNoSourcePosition); | 117 undef, kNoSourcePosition); |
| 100 Block* b = factory()->NewBlock(NULL, 2, false, kNoSourcePosition); | 118 Block* b = factory()->NewBlock(NULL, 2, false, kNoSourcePosition); |
| 101 b->statements()->Add( | 119 b->statements()->Add( |
| 102 factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone()); | 120 factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone()); |
| 103 b->statements()->Add(s, zone()); | 121 b->statements()->Add(s, zone()); |
| 104 return b; | 122 return b; |
| 105 } | 123 } |
| 106 | 124 |
| 107 | 125 |
| 108 void Processor::Process(ZoneList<Statement*>* statements) { | 126 void Processor::Process(ZoneList<Statement*>* statements) { |
| 109 for (int i = statements->length() - 1; i >= 0; --i) { | 127 for (int i = statements->length() - 1; i >= 0 && (breakable_ || !is_set_); |
|
adamk
2016/10/20 15:39:06
That's quite a fancy for loop, please add a commen
| |
| 128 --i) { | |
| 110 Visit(statements->at(i)); | 129 Visit(statements->at(i)); |
| 111 statements->Set(i, replacement_); | 130 statements->Set(i, replacement_); |
| 112 } | 131 } |
| 113 } | 132 } |
| 114 | 133 |
| 115 | 134 |
| 116 void Processor::VisitBlock(Block* node) { | 135 void Processor::VisitBlock(Block* node) { |
| 117 // An initializer block is the rewritten form of a variable declaration | 136 // An initializer block is the rewritten form of a variable declaration |
| 118 // with initialization expressions. The initializer block contains the | 137 // with initialization expressions. The initializer block contains the |
| 119 // list of assignments corresponding to the initialization expressions. | 138 // list of assignments corresponding to the initialization expressions. |
| 120 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of | 139 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of |
| 121 // a variable declaration with initialization expression is 'undefined' | 140 // a variable declaration with initialization expression is 'undefined' |
| 122 // with some JS VMs: For instance, using smjs, print(eval('var x = 7')) | 141 // with some JS VMs: For instance, using smjs, print(eval('var x = 7')) |
| 123 // returns 'undefined'. To obtain the same behavior with v8, we need | 142 // returns 'undefined'. To obtain the same behavior with v8, we need |
| 124 // to prevent rewriting in that case. | 143 // to prevent rewriting in that case. |
| 125 if (!node->ignore_completion_value()) Process(node->statements()); | 144 if (!node->ignore_completion_value()) { |
| 145 BreakableScope scope(this, node->labels() != nullptr); | |
| 146 Process(node->statements()); | |
| 147 } | |
| 126 replacement_ = node; | 148 replacement_ = node; |
| 127 } | 149 } |
| 128 | 150 |
| 129 | 151 |
| 130 void Processor::VisitExpressionStatement(ExpressionStatement* node) { | 152 void Processor::VisitExpressionStatement(ExpressionStatement* node) { |
| 131 // Rewrite : <x>; -> .result = <x>; | 153 // Rewrite : <x>; -> .result = <x>; |
| 132 if (!is_set_) { | 154 if (!is_set_) { |
| 133 node->set_expression(SetResult(node->expression())); | 155 node->set_expression(SetResult(node->expression())); |
| 134 is_set_ = true; | 156 is_set_ = true; |
| 135 } | 157 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 150 replacement_ = node; | 172 replacement_ = node; |
| 151 | 173 |
| 152 if (!is_set_) { | 174 if (!is_set_) { |
| 153 is_set_ = true; | 175 is_set_ = true; |
| 154 replacement_ = AssignUndefinedBefore(node); | 176 replacement_ = AssignUndefinedBefore(node); |
| 155 } | 177 } |
| 156 } | 178 } |
| 157 | 179 |
| 158 | 180 |
| 159 void Processor::VisitIterationStatement(IterationStatement* node) { | 181 void Processor::VisitIterationStatement(IterationStatement* node) { |
| 182 BreakableScope scope(this); | |
| 160 // Rewrite the body. | 183 // Rewrite the body. |
| 161 bool set_after = is_set_; | 184 bool set_after = is_set_; |
| 162 is_set_ = false; // We are in a loop, so we can't rely on [set_after]. | 185 is_set_ = false; // We are in a loop, so we can't rely on [set_after]. |
| 163 Visit(node->body()); | 186 Visit(node->body()); |
| 164 node->set_body(replacement_); | 187 node->set_body(replacement_); |
| 165 is_set_ = is_set_ && set_after; | 188 is_set_ = is_set_ && set_after; |
| 166 replacement_ = node; | 189 replacement_ = node; |
| 167 | 190 |
| 168 if (!is_set_) { | 191 if (!is_set_) { |
| 169 is_set_ = true; | 192 is_set_ = true; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 246 replacement_ = node; | 269 replacement_ = node; |
| 247 | 270 |
| 248 if (!is_set_) { | 271 if (!is_set_) { |
| 249 is_set_ = true; | 272 is_set_ = true; |
| 250 replacement_ = AssignUndefinedBefore(node); | 273 replacement_ = AssignUndefinedBefore(node); |
| 251 } | 274 } |
| 252 } | 275 } |
| 253 | 276 |
| 254 | 277 |
| 255 void Processor::VisitSwitchStatement(SwitchStatement* node) { | 278 void Processor::VisitSwitchStatement(SwitchStatement* node) { |
| 279 BreakableScope scope(this); | |
| 256 // Rewrite statements in all case clauses (in reverse order). | 280 // Rewrite statements in all case clauses (in reverse order). |
| 257 ZoneList<CaseClause*>* clauses = node->cases(); | 281 ZoneList<CaseClause*>* clauses = node->cases(); |
| 258 bool set_after = is_set_; | 282 bool set_after = is_set_; |
| 259 for (int i = clauses->length() - 1; i >= 0; --i) { | 283 for (int i = clauses->length() - 1; i >= 0; --i) { |
| 260 CaseClause* clause = clauses->at(i); | 284 CaseClause* clause = clauses->at(i); |
| 261 Process(clause->statements()); | 285 Process(clause->statements()); |
| 262 } | 286 } |
| 263 is_set_ = is_set_ && set_after; | 287 is_set_ = is_set_ && set_after; |
| 264 replacement_ = node; | 288 replacement_ = node; |
| 265 | 289 |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 391 processor.SetResult(undef), expr->position()); | 415 processor.SetResult(undef), expr->position()); |
| 392 body->Add(completion, factory->zone()); | 416 body->Add(completion, factory->zone()); |
| 393 } | 417 } |
| 394 } | 418 } |
| 395 return true; | 419 return true; |
| 396 } | 420 } |
| 397 | 421 |
| 398 | 422 |
| 399 } // namespace internal | 423 } // namespace internal |
| 400 } // namespace v8 | 424 } // namespace v8 |
| OLD | NEW |