Line data Source code
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
3 : // found in the LICENSE file.
4 :
5 : #include "src/parsing/rewriter.h"
6 :
7 : #include "src/ast/ast.h"
8 : #include "src/ast/scopes.h"
9 : #include "src/objects-inl.h"
10 : #include "src/parsing/parse-info.h"
11 : #include "src/parsing/parser.h"
12 :
13 : namespace v8 {
14 : namespace internal {
15 :
16 : class Processor final : public AstVisitor<Processor> {
17 : public:
18 : Processor(uintptr_t stack_limit, DeclarationScope* closure_scope,
19 1558670 : Variable* result, AstValueFactory* ast_value_factory)
20 : : result_(result),
21 : result_assigned_(false),
22 : replacement_(nullptr),
23 : is_set_(false),
24 : breakable_(false),
25 : zone_(ast_value_factory->zone()),
26 : closure_scope_(closure_scope),
27 3117340 : factory_(ast_value_factory) {
28 : DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
29 : InitializeAstVisitor(stack_limit);
30 : }
31 :
32 : Processor(Parser* parser, DeclarationScope* closure_scope, Variable* result,
33 3322 : AstValueFactory* ast_value_factory)
34 : : result_(result),
35 : result_assigned_(false),
36 : replacement_(nullptr),
37 : is_set_(false),
38 : breakable_(false),
39 : zone_(ast_value_factory->zone()),
40 : closure_scope_(closure_scope),
41 6644 : factory_(ast_value_factory) {
42 : DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
43 3322 : InitializeAstVisitor(parser->stack_limit());
44 : }
45 :
46 : void Process(ZoneList<Statement*>* statements);
47 : bool result_assigned() const { return result_assigned_; }
48 :
49 : Zone* zone() { return zone_; }
50 : DeclarationScope* closure_scope() { return closure_scope_; }
51 : AstNodeFactory* factory() { return &factory_; }
52 :
53 : // Returns ".result = value"
54 1578600 : Expression* SetResult(Expression* value) {
55 1578600 : result_assigned_ = true;
56 1578600 : VariableProxy* result_proxy = factory()->NewVariableProxy(result_);
57 : return factory()->NewAssignment(Token::ASSIGN, result_proxy, value,
58 1578600 : kNoSourcePosition);
59 : }
60 :
61 : // Inserts '.result = undefined' in front of the given statement.
62 : Statement* AssignUndefinedBefore(Statement* s);
63 :
64 : private:
65 : Variable* result_;
66 :
67 : // We are not tracking result usage via the result_'s use
68 : // counts (we leave the accurate computation to the
69 : // usage analyzer). Instead we simple remember if
70 : // there was ever an assignment to result_.
71 : bool result_assigned_;
72 :
73 : // When visiting a node, we "return" a replacement for that node in
74 : // [replacement_]. In many cases this will just be the original node.
75 : Statement* replacement_;
76 :
77 : // To avoid storing to .result all the time, we eliminate some of
78 : // the stores by keeping track of whether or not we're sure .result
79 : // will be overwritten anyway. This is a bit more tricky than what I
80 : // was hoping for.
81 : bool is_set_;
82 :
83 : bool breakable_;
84 :
85 : class BreakableScope final {
86 : public:
87 : explicit BreakableScope(Processor* processor, bool breakable = true)
88 272955 : : processor_(processor), previous_(processor->breakable_) {
89 272955 : processor->breakable_ = processor->breakable_ || breakable;
90 : }
91 :
92 272955 : ~BreakableScope() { processor_->breakable_ = previous_; }
93 :
94 : private:
95 : Processor* processor_;
96 : bool previous_;
97 : };
98 :
99 : Zone* zone_;
100 : DeclarationScope* closure_scope_;
101 : AstNodeFactory factory_;
102 :
103 : // Node visitors.
104 : #define DEF_VISIT(type) void Visit##type(type* node);
105 : AST_NODE_LIST(DEF_VISIT)
106 : #undef DEF_VISIT
107 :
108 : void VisitIterationStatement(IterationStatement* stmt);
109 :
110 13631402 : DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
111 : };
112 :
113 :
114 257064 : Statement* Processor::AssignUndefinedBefore(Statement* s) {
115 85688 : Expression* undef = factory()->NewUndefinedLiteral(kNoSourcePosition);
116 85688 : Expression* assignment = SetResult(undef);
117 85688 : Block* b = factory()->NewBlock(NULL, 2, false, kNoSourcePosition);
118 : b->statements()->Add(
119 85688 : factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone());
120 : b->statements()->Add(s, zone());
121 85688 : return b;
122 : }
123 :
124 :
125 1754909 : void Processor::Process(ZoneList<Statement*>* statements) {
126 : // If we're in a breakable scope (named block, iteration, or switch), we walk
127 : // all statements. The last value producing statement before the break needs
128 : // to assign to .result. If we're not in a breakable scope, only the last
129 : // value producing statement in the block assigns to .result, so we can stop
130 : // early.
131 7554901 : for (int i = statements->length() - 1; i >= 0 && (breakable_ || !is_set_);
132 : --i) {
133 2899997 : Visit(statements->at(i));
134 2899996 : statements->Set(i, replacement_);
135 : }
136 1754908 : }
137 :
138 :
139 1398392 : void Processor::VisitBlock(Block* node) {
140 : // An initializer block is the rewritten form of a variable declaration
141 : // with initialization expressions. The initializer block contains the
142 : // list of assignments corresponding to the initialization expressions.
143 : // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of
144 : // a variable declaration with initialization expression is 'undefined'
145 : // with some JS VMs: For instance, using smjs, print(eval('var x = 7'))
146 : // returns 'undefined'. To obtain the same behavior with v8, we need
147 : // to prevent rewriting in that case.
148 1398392 : if (!node->ignore_completion_value()) {
149 192338 : BreakableScope scope(this, node->labels() != nullptr);
150 192338 : Process(node->statements());
151 : }
152 1398392 : replacement_ = node;
153 1398392 : }
154 :
155 :
156 2997346 : void Processor::VisitExpressionStatement(ExpressionStatement* node) {
157 : // Rewrite : <x>; -> .result = <x>;
158 1504517 : if (!is_set_) {
159 1492829 : node->set_expression(SetResult(node->expression()));
160 1492824 : is_set_ = true;
161 : }
162 1504512 : replacement_ = node;
163 1504512 : }
164 :
165 :
166 10590 : void Processor::VisitIfStatement(IfStatement* node) {
167 : // Rewrite both branches.
168 3530 : bool set_after = is_set_;
169 :
170 3530 : Visit(node->then_statement());
171 3530 : node->set_then_statement(replacement_);
172 3530 : bool set_in_then = is_set_;
173 :
174 3530 : is_set_ = set_after;
175 3530 : Visit(node->else_statement());
176 3530 : node->set_else_statement(replacement_);
177 :
178 3530 : replacement_ = set_in_then && is_set_ ? node : AssignUndefinedBefore(node);
179 3530 : is_set_ = true;
180 3530 : }
181 :
182 :
183 160536 : void Processor::VisitIterationStatement(IterationStatement* node) {
184 : // The statement may have to produce a value, so always assign undefined
185 : // before.
186 : // TODO(verwaest): Omit it if we know that there's no break/continue leaving
187 : // it early.
188 : DCHECK(breakable_ || !is_set_);
189 : BreakableScope scope(this);
190 :
191 80268 : Visit(node->body());
192 80268 : node->set_body(replacement_);
193 :
194 80268 : replacement_ = AssignUndefinedBefore(node);
195 80268 : is_set_ = true;
196 80268 : }
197 :
198 :
199 429 : void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
200 429 : VisitIterationStatement(node);
201 429 : }
202 :
203 :
204 686 : void Processor::VisitWhileStatement(WhileStatement* node) {
205 686 : VisitIterationStatement(node);
206 686 : }
207 :
208 :
209 71554 : void Processor::VisitForStatement(ForStatement* node) {
210 71554 : VisitIterationStatement(node);
211 71554 : }
212 :
213 :
214 3820 : void Processor::VisitForInStatement(ForInStatement* node) {
215 3820 : VisitIterationStatement(node);
216 3820 : }
217 :
218 :
219 3779 : void Processor::VisitForOfStatement(ForOfStatement* node) {
220 3779 : VisitIterationStatement(node);
221 3779 : }
222 :
223 :
224 16714 : void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
225 : // Rewrite both try and catch block.
226 8357 : bool set_after = is_set_;
227 :
228 8357 : Visit(node->try_block());
229 8357 : node->set_try_block(static_cast<Block*>(replacement_));
230 8357 : bool set_in_try = is_set_;
231 :
232 8357 : is_set_ = set_after;
233 8357 : Visit(node->catch_block());
234 8357 : node->set_catch_block(static_cast<Block*>(replacement_));
235 :
236 8357 : replacement_ = is_set_ && set_in_try ? node : AssignUndefinedBefore(node);
237 8357 : is_set_ = true;
238 8357 : }
239 :
240 :
241 5878 : void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
242 : // Only rewrite finally if it could contain 'break' or 'continue'. Always
243 : // rewrite try.
244 4072 : if (breakable_) {
245 : // Only set result before a 'break' or 'continue'.
246 301 : is_set_ = true;
247 301 : Visit(node->finally_block());
248 301 : node->set_finally_block(replacement_->AsBlock());
249 : // Save .result value at the beginning of the finally block and restore it
250 : // at the end again: ".backup = .result; ...; .result = .backup"
251 : // This is necessary because the finally block does not normally contribute
252 : // to the completion value.
253 301 : CHECK_NOT_NULL(closure_scope());
254 : Variable* backup = closure_scope()->NewTemporary(
255 602 : factory()->ast_value_factory()->dot_result_string());
256 301 : Expression* backup_proxy = factory()->NewVariableProxy(backup);
257 301 : Expression* result_proxy = factory()->NewVariableProxy(result_);
258 : Expression* save = factory()->NewAssignment(
259 301 : Token::ASSIGN, backup_proxy, result_proxy, kNoSourcePosition);
260 : Expression* restore = factory()->NewAssignment(
261 301 : Token::ASSIGN, result_proxy, backup_proxy, kNoSourcePosition);
262 : node->finally_block()->statements()->InsertAt(
263 903 : 0, factory()->NewExpressionStatement(save, kNoSourcePosition), zone());
264 : node->finally_block()->statements()->Add(
265 301 : factory()->NewExpressionStatement(restore, kNoSourcePosition), zone());
266 : }
267 4072 : Visit(node->try_block());
268 4072 : node->set_try_block(replacement_->AsBlock());
269 :
270 4072 : replacement_ = is_set_ ? node : AssignUndefinedBefore(node);
271 4072 : is_set_ = true;
272 4072 : }
273 :
274 :
275 698 : void Processor::VisitSwitchStatement(SwitchStatement* node) {
276 : // The statement may have to produce a value, so always assign undefined
277 : // before.
278 : // TODO(verwaest): Omit it if we know that there's no break/continue leaving
279 : // it early.
280 : DCHECK(breakable_ || !is_set_);
281 : BreakableScope scope(this);
282 : // Rewrite statements in all case clauses.
283 : ZoneList<CaseClause*>* clauses = node->cases();
284 934 : for (int i = clauses->length() - 1; i >= 0; --i) {
285 585 : CaseClause* clause = clauses->at(i);
286 585 : Process(clause->statements());
287 : }
288 :
289 349 : replacement_ = AssignUndefinedBefore(node);
290 349 : is_set_ = true;
291 349 : }
292 :
293 :
294 0 : void Processor::VisitContinueStatement(ContinueStatement* node) {
295 335 : is_set_ = false;
296 335 : replacement_ = node;
297 0 : }
298 :
299 :
300 0 : void Processor::VisitBreakStatement(BreakStatement* node) {
301 1617 : is_set_ = false;
302 1617 : replacement_ = node;
303 0 : }
304 :
305 :
306 4821 : void Processor::VisitWithStatement(WithStatement* node) {
307 4821 : Visit(node->statement());
308 4821 : node->set_statement(replacement_);
309 :
310 4821 : replacement_ = is_set_ ? node : AssignUndefinedBefore(node);
311 4821 : is_set_ = true;
312 4821 : }
313 :
314 :
315 2330 : void Processor::VisitSloppyBlockFunctionStatement(
316 2330 : SloppyBlockFunctionStatement* node) {
317 2330 : Visit(node->statement());
318 2330 : node->set_statement(replacement_);
319 2330 : replacement_ = node;
320 2330 : }
321 :
322 :
323 0 : void Processor::VisitEmptyStatement(EmptyStatement* node) {
324 4024 : replacement_ = node;
325 0 : }
326 :
327 :
328 0 : void Processor::VisitReturnStatement(ReturnStatement* node) {
329 12 : is_set_ = true;
330 12 : replacement_ = node;
331 0 : }
332 :
333 :
334 0 : void Processor::VisitDebuggerStatement(DebuggerStatement* node) {
335 2936 : replacement_ = node;
336 0 : }
337 :
338 :
339 : // Expressions are never visited.
340 : #define DEF_VISIT(type) \
341 : void Processor::Visit##type(type* expr) { UNREACHABLE(); }
342 0 : EXPRESSION_NODE_LIST(DEF_VISIT)
343 : #undef DEF_VISIT
344 :
345 :
346 : // Declarations are never visited.
347 : #define DEF_VISIT(type) \
348 : void Processor::Visit##type(type* expr) { UNREACHABLE(); }
349 0 : DECLARATION_NODE_LIST(DEF_VISIT)
350 : #undef DEF_VISIT
351 :
352 :
353 : // Assumes code has been parsed. Mutates the AST, so the AST should not
354 : // continue to be used in the case of failure.
355 11989175 : bool Rewriter::Rewrite(ParseInfo* info, Isolate* isolate) {
356 : DisallowHeapAllocation no_allocation;
357 : DisallowHandleAllocation no_handles;
358 : DisallowHandleDereference no_deref;
359 :
360 : RuntimeCallTimerScope runtimeTimer(
361 : info->runtime_call_stats(),
362 2877249 : &RuntimeCallStats::CompileRewriteReturnResult);
363 :
364 4462936 : FunctionLiteral* function = info->literal();
365 : DCHECK_NOT_NULL(function);
366 4389506 : Scope* scope = function->scope();
367 : DCHECK_NOT_NULL(scope);
368 : DCHECK_EQ(scope, scope->GetClosureScope());
369 :
370 5413079 : if (!(scope->is_script_scope() || scope->is_eval_scope() ||
371 4175278 : scope->is_module_scope())) {
372 : return true;
373 : }
374 :
375 : ZoneList<Statement*>* body = function->body();
376 : DCHECK_IMPLIES(scope->is_module_scope(), !body->is_empty());
377 1585686 : if (!body->is_empty()) {
378 1558671 : Variable* result = scope->AsDeclarationScope()->NewTemporary(
379 3117337 : info->ast_value_factory()->dot_result_string());
380 : Processor processor(info->stack_limit(), scope->AsDeclarationScope(),
381 1558670 : result, info->ast_value_factory());
382 1558670 : processor.Process(body);
383 :
384 : DCHECK_IMPLIES(scope->is_module_scope(), processor.result_assigned());
385 1558669 : if (processor.result_assigned()) {
386 : int pos = kNoSourcePosition;
387 : Expression* result_value =
388 1512253 : processor.factory()->NewVariableProxy(result, pos);
389 1512256 : if (scope->is_module_scope()) {
390 6456 : auto args = new (info->zone()) ZoneList<Expression*>(2, info->zone());
391 : args->Add(result_value, info->zone());
392 6456 : args->Add(processor.factory()->NewBooleanLiteral(true, pos),
393 : info->zone());
394 : result_value = processor.factory()->NewCallRuntime(
395 6456 : Runtime::kInlineCreateIterResultObject, args, pos);
396 : }
397 : Statement* result_statement =
398 1512256 : processor.factory()->NewReturnStatement(result_value, pos);
399 : body->Add(result_statement, info->zone());
400 : }
401 :
402 : // TODO(leszeks): Remove this check and releases once internalization is
403 : // moved out of parsing/analysis. Also remove the parameter once done.
404 : DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
405 : no_deref.Release();
406 : no_handles.Release();
407 : no_allocation.Release();
408 :
409 : // Internalize any values created during rewriting.
410 1558665 : info->ast_value_factory()->Internalize(isolate);
411 1558668 : if (processor.HasStackOverflow()) return false;
412 : }
413 :
414 : return true;
415 : }
416 :
417 3359 : bool Rewriter::Rewrite(Parser* parser, DeclarationScope* closure_scope,
418 6803 : DoExpression* expr, AstValueFactory* factory) {
419 : DisallowHeapAllocation no_allocation;
420 : DisallowHandleAllocation no_handles;
421 : DisallowHandleDereference no_deref;
422 :
423 : Block* block = expr->block();
424 : DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
425 : DCHECK(block->scope() == nullptr ||
426 : block->scope()->GetClosureScope() == closure_scope);
427 3359 : ZoneList<Statement*>* body = block->statements();
428 3359 : VariableProxy* result = expr->result();
429 : Variable* result_var = result->var();
430 :
431 3359 : if (!body->is_empty()) {
432 : Processor processor(parser, closure_scope, result_var, factory);
433 3322 : processor.Process(body);
434 3322 : if (processor.HasStackOverflow()) return false;
435 :
436 3322 : if (!processor.result_assigned()) {
437 85 : AstNodeFactory* node_factory = processor.factory();
438 85 : Expression* undef = node_factory->NewUndefinedLiteral(kNoSourcePosition);
439 : Statement* completion = node_factory->NewExpressionStatement(
440 85 : processor.SetResult(undef), expr->position());
441 : body->Add(completion, factory->zone());
442 : }
443 : }
444 : return true;
445 : }
446 :
447 :
448 : } // namespace internal
449 : } // namespace v8
|