| 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/parser.h" | 9 #include "src/parsing/parser.h" |
| 10 | 10 |
| 11 namespace v8 { | 11 namespace v8 { |
| 12 namespace internal { | 12 namespace internal { |
| 13 | 13 |
| 14 class Processor final : public AstVisitor<Processor> { | 14 class Processor final : public AstVisitor<Processor> { |
| 15 public: | 15 public: |
| 16 Processor(Isolate* isolate, Scope* scope, Variable* result, | 16 Processor(Isolate* isolate, Scope* closure_scope, Variable* result, |
| 17 AstValueFactory* ast_value_factory) | 17 AstValueFactory* ast_value_factory) |
| 18 : result_(result), | 18 : result_(result), |
| 19 result_assigned_(false), | 19 result_assigned_(false), |
| 20 replacement_(nullptr), | 20 replacement_(nullptr), |
| 21 is_set_(false), | 21 is_set_(false), |
| 22 zone_(ast_value_factory->zone()), | 22 zone_(ast_value_factory->zone()), |
| 23 scope_(scope), | 23 closure_scope_(closure_scope), |
| 24 factory_(ast_value_factory) { | 24 factory_(ast_value_factory) { |
| 25 DCHECK_EQ(closure_scope, closure_scope->ClosureScope()); |
| 25 InitializeAstVisitor(isolate); | 26 InitializeAstVisitor(isolate); |
| 26 } | 27 } |
| 27 | 28 |
| 28 Processor(Parser* parser, Scope* scope, Variable* result, | 29 Processor(Parser* parser, Scope* closure_scope, Variable* result, |
| 29 AstValueFactory* ast_value_factory) | 30 AstValueFactory* ast_value_factory) |
| 30 : result_(result), | 31 : result_(result), |
| 31 result_assigned_(false), | 32 result_assigned_(false), |
| 32 replacement_(nullptr), | 33 replacement_(nullptr), |
| 33 is_set_(false), | 34 is_set_(false), |
| 34 zone_(ast_value_factory->zone()), | 35 zone_(ast_value_factory->zone()), |
| 35 scope_(scope), | 36 closure_scope_(closure_scope), |
| 36 factory_(ast_value_factory) { | 37 factory_(ast_value_factory) { |
| 38 DCHECK_EQ(closure_scope, closure_scope->ClosureScope()); |
| 37 InitializeAstVisitor(parser->stack_limit()); | 39 InitializeAstVisitor(parser->stack_limit()); |
| 38 } | 40 } |
| 39 | 41 |
| 40 void Process(ZoneList<Statement*>* statements); | 42 void Process(ZoneList<Statement*>* statements); |
| 41 bool result_assigned() const { return result_assigned_; } | 43 bool result_assigned() const { return result_assigned_; } |
| 42 | 44 |
| 43 Zone* zone() { return zone_; } | 45 Zone* zone() { return zone_; } |
| 44 Scope* scope() { return scope_; } | 46 Scope* closure_scope() { return closure_scope_; } |
| 45 AstNodeFactory* factory() { return &factory_; } | 47 AstNodeFactory* factory() { return &factory_; } |
| 46 | 48 |
| 47 // Returns ".result = value" | 49 // Returns ".result = value" |
| 48 Expression* SetResult(Expression* value) { | 50 Expression* SetResult(Expression* value) { |
| 49 result_assigned_ = true; | 51 result_assigned_ = true; |
| 50 VariableProxy* result_proxy = factory()->NewVariableProxy(result_); | 52 VariableProxy* result_proxy = factory()->NewVariableProxy(result_); |
| 51 return factory()->NewAssignment(Token::ASSIGN, result_proxy, value, | 53 return factory()->NewAssignment(Token::ASSIGN, result_proxy, value, |
| 52 kNoSourcePosition); | 54 kNoSourcePosition); |
| 53 } | 55 } |
| 54 | 56 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 68 // [replacement_]. In many cases this will just be the original node. | 70 // [replacement_]. In many cases this will just be the original node. |
| 69 Statement* replacement_; | 71 Statement* replacement_; |
| 70 | 72 |
| 71 // To avoid storing to .result all the time, we eliminate some of | 73 // To avoid storing to .result all the time, we eliminate some of |
| 72 // the stores by keeping track of whether or not we're sure .result | 74 // the stores by keeping track of whether or not we're sure .result |
| 73 // will be overwritten anyway. This is a bit more tricky than what I | 75 // will be overwritten anyway. This is a bit more tricky than what I |
| 74 // was hoping for. | 76 // was hoping for. |
| 75 bool is_set_; | 77 bool is_set_; |
| 76 | 78 |
| 77 Zone* zone_; | 79 Zone* zone_; |
| 78 Scope* scope_; | 80 Scope* closure_scope_; |
| 79 AstNodeFactory factory_; | 81 AstNodeFactory factory_; |
| 80 | 82 |
| 81 // Node visitors. | 83 // Node visitors. |
| 82 #define DEF_VISIT(type) void Visit##type(type* node); | 84 #define DEF_VISIT(type) void Visit##type(type* node); |
| 83 AST_NODE_LIST(DEF_VISIT) | 85 AST_NODE_LIST(DEF_VISIT) |
| 84 #undef DEF_VISIT | 86 #undef DEF_VISIT |
| 85 | 87 |
| 86 void VisitIterationStatement(IterationStatement* stmt); | 88 void VisitIterationStatement(IterationStatement* stmt); |
| 87 | 89 |
| 88 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); | 90 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { | 218 void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { |
| 217 // Rewrite both try and finally block (in reverse order). | 219 // Rewrite both try and finally block (in reverse order). |
| 218 bool set_after = is_set_; | 220 bool set_after = is_set_; |
| 219 is_set_ = true; // Don't normally need to assign in finally block. | 221 is_set_ = true; // Don't normally need to assign in finally block. |
| 220 Visit(node->finally_block()); | 222 Visit(node->finally_block()); |
| 221 node->set_finally_block(replacement_->AsBlock()); | 223 node->set_finally_block(replacement_->AsBlock()); |
| 222 { // Save .result value at the beginning of the finally block and restore it | 224 { // Save .result value at the beginning of the finally block and restore it |
| 223 // at the end again: ".backup = .result; ...; .result = .backup" | 225 // at the end again: ".backup = .result; ...; .result = .backup" |
| 224 // This is necessary because the finally block does not normally contribute | 226 // This is necessary because the finally block does not normally contribute |
| 225 // to the completion value. | 227 // to the completion value. |
| 226 CHECK(scope() != nullptr); | 228 CHECK_NOT_NULL(closure_scope()); |
| 227 Variable* backup = scope()->NewTemporary( | 229 Variable* backup = closure_scope()->NewTemporary( |
| 228 factory()->ast_value_factory()->dot_result_string()); | 230 factory()->ast_value_factory()->dot_result_string()); |
| 229 Expression* backup_proxy = factory()->NewVariableProxy(backup); | 231 Expression* backup_proxy = factory()->NewVariableProxy(backup); |
| 230 Expression* result_proxy = factory()->NewVariableProxy(result_); | 232 Expression* result_proxy = factory()->NewVariableProxy(result_); |
| 231 Expression* save = factory()->NewAssignment( | 233 Expression* save = factory()->NewAssignment( |
| 232 Token::ASSIGN, backup_proxy, result_proxy, kNoSourcePosition); | 234 Token::ASSIGN, backup_proxy, result_proxy, kNoSourcePosition); |
| 233 Expression* restore = factory()->NewAssignment( | 235 Expression* restore = factory()->NewAssignment( |
| 234 Token::ASSIGN, result_proxy, backup_proxy, kNoSourcePosition); | 236 Token::ASSIGN, result_proxy, backup_proxy, kNoSourcePosition); |
| 235 node->finally_block()->statements()->InsertAt( | 237 node->finally_block()->statements()->InsertAt( |
| 236 0, factory()->NewExpressionStatement(save, kNoSourcePosition), zone()); | 238 0, factory()->NewExpressionStatement(save, kNoSourcePosition), zone()); |
| 237 node->finally_block()->statements()->Add( | 239 node->finally_block()->statements()->Add( |
| 238 factory()->NewExpressionStatement(restore, kNoSourcePosition), zone()); | 240 factory()->NewExpressionStatement(restore, kNoSourcePosition), zone()); |
| 239 } | 241 } |
| 240 is_set_ = set_after; | 242 is_set_ = set_after; |
| 241 Visit(node->try_block()); | 243 Visit(node->try_block()); |
| 242 node->set_try_block(replacement_->AsBlock()); | 244 node->set_try_block(replacement_->AsBlock()); |
| 243 replacement_ = node; | 245 replacement_ = node; |
| 244 | 246 |
| 245 if (!is_set_) { | 247 if (!is_set_) { |
| 246 is_set_ = true; | 248 is_set_ = true; |
| 247 replacement_ = AssignUndefinedBefore(node); | 249 replacement_ = AssignUndefinedBefore(node); |
| 248 } | 250 } |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 #define DEF_VISIT(type) \ | 328 #define DEF_VISIT(type) \ |
| 327 void Processor::Visit##type(type* expr) { UNREACHABLE(); } | 329 void Processor::Visit##type(type* expr) { UNREACHABLE(); } |
| 328 DECLARATION_NODE_LIST(DEF_VISIT) | 330 DECLARATION_NODE_LIST(DEF_VISIT) |
| 329 #undef DEF_VISIT | 331 #undef DEF_VISIT |
| 330 | 332 |
| 331 | 333 |
| 332 // Assumes code has been parsed. Mutates the AST, so the AST should not | 334 // Assumes code has been parsed. Mutates the AST, so the AST should not |
| 333 // continue to be used in the case of failure. | 335 // continue to be used in the case of failure. |
| 334 bool Rewriter::Rewrite(ParseInfo* info) { | 336 bool Rewriter::Rewrite(ParseInfo* info) { |
| 335 FunctionLiteral* function = info->literal(); | 337 FunctionLiteral* function = info->literal(); |
| 336 DCHECK(function != NULL); | 338 DCHECK_NOT_NULL(function); |
| 337 Scope* scope = function->scope(); | 339 Scope* scope = function->scope(); |
| 338 DCHECK(scope != NULL); | 340 DCHECK_NOT_NULL(scope); |
| 339 if (!scope->is_script_scope() && !scope->is_eval_scope()) return true; | 341 if (!scope->is_script_scope() && !scope->is_eval_scope()) return true; |
| 342 Scope* closure_scope = scope->ClosureScope(); |
| 340 | 343 |
| 341 ZoneList<Statement*>* body = function->body(); | 344 ZoneList<Statement*>* body = function->body(); |
| 342 if (!body->is_empty()) { | 345 if (!body->is_empty()) { |
| 343 Variable* result = | 346 Variable* result = closure_scope->NewTemporary( |
| 344 scope->NewTemporary(info->ast_value_factory()->dot_result_string()); | 347 info->ast_value_factory()->dot_result_string()); |
| 345 // The name string must be internalized at this point. | 348 // The name string must be internalized at this point. |
| 346 DCHECK(!result->name().is_null()); | 349 DCHECK(!result->name().is_null()); |
| 347 Processor processor(info->isolate(), scope, result, | 350 Processor processor(info->isolate(), closure_scope, result, |
| 348 info->ast_value_factory()); | 351 info->ast_value_factory()); |
| 349 processor.Process(body); | 352 processor.Process(body); |
| 350 if (processor.HasStackOverflow()) return false; | 353 if (processor.HasStackOverflow()) return false; |
| 351 | 354 |
| 352 if (processor.result_assigned()) { | 355 if (processor.result_assigned()) { |
| 353 int pos = kNoSourcePosition; | 356 int pos = kNoSourcePosition; |
| 354 VariableProxy* result_proxy = | 357 VariableProxy* result_proxy = |
| 355 processor.factory()->NewVariableProxy(result, pos); | 358 processor.factory()->NewVariableProxy(result, pos); |
| 356 Statement* result_statement = | 359 Statement* result_statement = |
| 357 processor.factory()->NewReturnStatement(result_proxy, pos); | 360 processor.factory()->NewReturnStatement(result_proxy, pos); |
| 358 body->Add(result_statement, info->zone()); | 361 body->Add(result_statement, info->zone()); |
| 359 } | 362 } |
| 360 } | 363 } |
| 361 | 364 |
| 362 return true; | 365 return true; |
| 363 } | 366 } |
| 364 | 367 |
| 365 | 368 bool Rewriter::Rewrite(Parser* parser, Scope* closure_scope, DoExpression* expr, |
| 366 bool Rewriter::Rewrite(Parser* parser, DoExpression* expr, | |
| 367 AstValueFactory* factory) { | 369 AstValueFactory* factory) { |
| 368 Block* block = expr->block(); | 370 Block* block = expr->block(); |
| 369 Scope* scope = block->scope(); | 371 DCHECK_EQ(closure_scope, closure_scope->ClosureScope()); |
| 372 DCHECK(block->scope() == nullptr || |
| 373 block->scope()->ClosureScope() == closure_scope); |
| 370 ZoneList<Statement*>* body = block->statements(); | 374 ZoneList<Statement*>* body = block->statements(); |
| 371 VariableProxy* result = expr->result(); | 375 VariableProxy* result = expr->result(); |
| 372 Variable* result_var = result->var(); | 376 Variable* result_var = result->var(); |
| 373 | 377 |
| 374 if (!body->is_empty()) { | 378 if (!body->is_empty()) { |
| 375 Processor processor(parser, scope, result_var, factory); | 379 Processor processor(parser, closure_scope, result_var, factory); |
| 376 processor.Process(body); | 380 processor.Process(body); |
| 377 if (processor.HasStackOverflow()) return false; | 381 if (processor.HasStackOverflow()) return false; |
| 378 | 382 |
| 379 if (!processor.result_assigned()) { | 383 if (!processor.result_assigned()) { |
| 380 AstNodeFactory* node_factory = processor.factory(); | 384 AstNodeFactory* node_factory = processor.factory(); |
| 381 Expression* undef = node_factory->NewUndefinedLiteral(kNoSourcePosition); | 385 Expression* undef = node_factory->NewUndefinedLiteral(kNoSourcePosition); |
| 382 Statement* completion = node_factory->NewExpressionStatement( | 386 Statement* completion = node_factory->NewExpressionStatement( |
| 383 processor.SetResult(undef), expr->position()); | 387 processor.SetResult(undef), expr->position()); |
| 384 body->Add(completion, factory->zone()); | 388 body->Add(completion, factory->zone()); |
| 385 } | 389 } |
| 386 } | 390 } |
| 387 return true; | 391 return true; |
| 388 } | 392 } |
| 389 | 393 |
| 390 | 394 |
| 391 } // namespace internal | 395 } // namespace internal |
| 392 } // namespace v8 | 396 } // namespace v8 |
| OLD | NEW |