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

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: comment Created 4 years, 1 month 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 // 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
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
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
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
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