| 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 // If we're in a breakable scope (named block, iteration, or switch), we walk |
| 128 // all statements. The last value producing statement before the break needs |
| 129 // to assign to .result. If we're not in a breakable scope, only the last |
| 130 // value producing statement in the block assigns to .result, so we can stop |
| 131 // early. |
| 132 for (int i = statements->length() - 1; i >= 0 && (breakable_ || !is_set_); |
| 133 --i) { |
| 110 Visit(statements->at(i)); | 134 Visit(statements->at(i)); |
| 111 statements->Set(i, replacement_); | 135 statements->Set(i, replacement_); |
| 112 } | 136 } |
| 113 } | 137 } |
| 114 | 138 |
| 115 | 139 |
| 116 void Processor::VisitBlock(Block* node) { | 140 void Processor::VisitBlock(Block* node) { |
| 117 // An initializer block is the rewritten form of a variable declaration | 141 // An initializer block is the rewritten form of a variable declaration |
| 118 // with initialization expressions. The initializer block contains the | 142 // with initialization expressions. The initializer block contains the |
| 119 // list of assignments corresponding to the initialization expressions. | 143 // list of assignments corresponding to the initialization expressions. |
| 120 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of | 144 // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of |
| 121 // a variable declaration with initialization expression is 'undefined' | 145 // a variable declaration with initialization expression is 'undefined' |
| 122 // with some JS VMs: For instance, using smjs, print(eval('var x = 7')) | 146 // 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 | 147 // returns 'undefined'. To obtain the same behavior with v8, we need |
| 124 // to prevent rewriting in that case. | 148 // to prevent rewriting in that case. |
| 125 if (!node->ignore_completion_value()) Process(node->statements()); | 149 if (!node->ignore_completion_value()) { |
| 150 BreakableScope scope(this, node->labels() != nullptr); |
| 151 Process(node->statements()); |
| 152 } |
| 126 replacement_ = node; | 153 replacement_ = node; |
| 127 } | 154 } |
| 128 | 155 |
| 129 | 156 |
| 130 void Processor::VisitExpressionStatement(ExpressionStatement* node) { | 157 void Processor::VisitExpressionStatement(ExpressionStatement* node) { |
| 131 // Rewrite : <x>; -> .result = <x>; | 158 // Rewrite : <x>; -> .result = <x>; |
| 132 if (!is_set_) { | 159 if (!is_set_) { |
| 133 node->set_expression(SetResult(node->expression())); | 160 node->set_expression(SetResult(node->expression())); |
| 134 is_set_ = true; | 161 is_set_ = true; |
| 135 } | 162 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 150 replacement_ = node; | 177 replacement_ = node; |
| 151 | 178 |
| 152 if (!is_set_) { | 179 if (!is_set_) { |
| 153 is_set_ = true; | 180 is_set_ = true; |
| 154 replacement_ = AssignUndefinedBefore(node); | 181 replacement_ = AssignUndefinedBefore(node); |
| 155 } | 182 } |
| 156 } | 183 } |
| 157 | 184 |
| 158 | 185 |
| 159 void Processor::VisitIterationStatement(IterationStatement* node) { | 186 void Processor::VisitIterationStatement(IterationStatement* node) { |
| 187 BreakableScope scope(this); |
| 160 // Rewrite the body. | 188 // Rewrite the body. |
| 161 bool set_after = is_set_; | 189 bool set_after = is_set_; |
| 162 is_set_ = false; // We are in a loop, so we can't rely on [set_after]. | 190 is_set_ = false; // We are in a loop, so we can't rely on [set_after]. |
| 163 Visit(node->body()); | 191 Visit(node->body()); |
| 164 node->set_body(replacement_); | 192 node->set_body(replacement_); |
| 165 is_set_ = is_set_ && set_after; | 193 is_set_ = is_set_ && set_after; |
| 166 replacement_ = node; | 194 replacement_ = node; |
| 167 | 195 |
| 168 if (!is_set_) { | 196 if (!is_set_) { |
| 169 is_set_ = true; | 197 is_set_ = true; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 replacement_ = node; | 274 replacement_ = node; |
| 247 | 275 |
| 248 if (!is_set_) { | 276 if (!is_set_) { |
| 249 is_set_ = true; | 277 is_set_ = true; |
| 250 replacement_ = AssignUndefinedBefore(node); | 278 replacement_ = AssignUndefinedBefore(node); |
| 251 } | 279 } |
| 252 } | 280 } |
| 253 | 281 |
| 254 | 282 |
| 255 void Processor::VisitSwitchStatement(SwitchStatement* node) { | 283 void Processor::VisitSwitchStatement(SwitchStatement* node) { |
| 284 BreakableScope scope(this); |
| 256 // Rewrite statements in all case clauses (in reverse order). | 285 // Rewrite statements in all case clauses (in reverse order). |
| 257 ZoneList<CaseClause*>* clauses = node->cases(); | 286 ZoneList<CaseClause*>* clauses = node->cases(); |
| 258 bool set_after = is_set_; | 287 bool set_after = is_set_; |
| 259 for (int i = clauses->length() - 1; i >= 0; --i) { | 288 for (int i = clauses->length() - 1; i >= 0; --i) { |
| 260 CaseClause* clause = clauses->at(i); | 289 CaseClause* clause = clauses->at(i); |
| 261 Process(clause->statements()); | 290 Process(clause->statements()); |
| 262 } | 291 } |
| 263 is_set_ = is_set_ && set_after; | 292 is_set_ = is_set_ && set_after; |
| 264 replacement_ = node; | 293 replacement_ = node; |
| 265 | 294 |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 processor.SetResult(undef), expr->position()); | 420 processor.SetResult(undef), expr->position()); |
| 392 body->Add(completion, factory->zone()); | 421 body->Add(completion, factory->zone()); |
| 393 } | 422 } |
| 394 } | 423 } |
| 395 return true; | 424 return true; |
| 396 } | 425 } |
| 397 | 426 |
| 398 | 427 |
| 399 } // namespace internal | 428 } // namespace internal |
| 400 } // namespace v8 | 429 } // namespace v8 |
| OLD | NEW |