Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: src/parsing/rewriter.cc

Issue 2431273002: Only rewrite all statements in a block if we're in a breakable scope (Closed)
Patch Set: Update test again Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698