Index: src/rewriter.cc |
diff --git a/src/rewriter.cc b/src/rewriter.cc |
deleted file mode 100644 |
index 1f19739331e09feefcf5b75f352f8fa5729a31e4..0000000000000000000000000000000000000000 |
--- a/src/rewriter.cc |
+++ /dev/null |
@@ -1,403 +0,0 @@ |
-// Copyright 2012 the V8 project authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "src/rewriter.h" |
- |
-#include "src/ast.h" |
-#include "src/parser.h" |
-#include "src/scopes.h" |
- |
-namespace v8 { |
-namespace internal { |
- |
-class Processor: public AstVisitor { |
- public: |
- Processor(Isolate* isolate, Scope* scope, Variable* result, |
- AstValueFactory* ast_value_factory) |
- : result_(result), |
- result_assigned_(false), |
- replacement_(nullptr), |
- is_set_(false), |
- zone_(ast_value_factory->zone()), |
- scope_(scope), |
- factory_(ast_value_factory) { |
- InitializeAstVisitor(isolate); |
- } |
- |
- Processor(Parser* parser, Scope* scope, Variable* result, |
- AstValueFactory* ast_value_factory) |
- : result_(result), |
- result_assigned_(false), |
- replacement_(nullptr), |
- is_set_(false), |
- scope_(scope), |
- factory_(ast_value_factory) { |
- InitializeAstVisitor(parser->stack_limit()); |
- } |
- |
- ~Processor() override {} |
- |
- void Process(ZoneList<Statement*>* statements); |
- bool result_assigned() const { return result_assigned_; } |
- |
- Zone* zone() { return zone_; } |
- Scope* scope() { return scope_; } |
- AstNodeFactory* factory() { return &factory_; } |
- |
- // Returns ".result = value" |
- Expression* SetResult(Expression* value) { |
- result_assigned_ = true; |
- VariableProxy* result_proxy = factory()->NewVariableProxy(result_); |
- return factory()->NewAssignment(Token::ASSIGN, result_proxy, value, |
- RelocInfo::kNoPosition); |
- } |
- |
- // Inserts '.result = undefined' in front of the given statement. |
- Statement* AssignUndefinedBefore(Statement* s); |
- |
- private: |
- Variable* result_; |
- |
- // We are not tracking result usage via the result_'s use |
- // counts (we leave the accurate computation to the |
- // usage analyzer). Instead we simple remember if |
- // there was ever an assignment to result_. |
- bool result_assigned_; |
- |
- // When visiting a node, we "return" a replacement for that node in |
- // [replacement_]. In many cases this will just be the original node. |
- Statement* replacement_; |
- |
- // To avoid storing to .result all the time, we eliminate some of |
- // the stores by keeping track of whether or not we're sure .result |
- // will be overwritten anyway. This is a bit more tricky than what I |
- // was hoping for. |
- bool is_set_; |
- |
- Zone* zone_; |
- Scope* scope_; |
- AstNodeFactory factory_; |
- |
- // Node visitors. |
-#define DEF_VISIT(type) void Visit##type(type* node) override; |
- AST_NODE_LIST(DEF_VISIT) |
-#undef DEF_VISIT |
- |
- void VisitIterationStatement(IterationStatement* stmt); |
- |
- DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); |
-}; |
- |
- |
-Statement* Processor::AssignUndefinedBefore(Statement* s) { |
- Expression* result_proxy = factory()->NewVariableProxy(result_); |
- Expression* undef = factory()->NewUndefinedLiteral(RelocInfo::kNoPosition); |
- Expression* assignment = factory()->NewAssignment( |
- Token::ASSIGN, result_proxy, undef, RelocInfo::kNoPosition); |
- Block* b = factory()->NewBlock(NULL, 2, false, RelocInfo::kNoPosition); |
- b->statements()->Add( |
- factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), |
- zone()); |
- b->statements()->Add(s, zone()); |
- return b; |
-} |
- |
- |
-void Processor::Process(ZoneList<Statement*>* statements) { |
- for (int i = statements->length() - 1; i >= 0; --i) { |
- Visit(statements->at(i)); |
- statements->Set(i, replacement_); |
- } |
-} |
- |
- |
-void Processor::VisitBlock(Block* node) { |
- // An initializer block is the rewritten form of a variable declaration |
- // with initialization expressions. The initializer block contains the |
- // list of assignments corresponding to the initialization expressions. |
- // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of |
- // a variable declaration with initialization expression is 'undefined' |
- // with some JS VMs: For instance, using smjs, print(eval('var x = 7')) |
- // returns 'undefined'. To obtain the same behavior with v8, we need |
- // to prevent rewriting in that case. |
- if (!node->ignore_completion_value()) Process(node->statements()); |
- replacement_ = node; |
-} |
- |
- |
-void Processor::VisitExpressionStatement(ExpressionStatement* node) { |
- // Rewrite : <x>; -> .result = <x>; |
- if (!is_set_) { |
- node->set_expression(SetResult(node->expression())); |
- is_set_ = true; |
- } |
- replacement_ = node; |
-} |
- |
- |
-void Processor::VisitIfStatement(IfStatement* node) { |
- // Rewrite both branches. |
- bool set_after = is_set_; |
- Visit(node->then_statement()); |
- node->set_then_statement(replacement_); |
- bool set_in_then = is_set_; |
- is_set_ = set_after; |
- Visit(node->else_statement()); |
- node->set_else_statement(replacement_); |
- is_set_ = is_set_ && set_in_then; |
- replacement_ = node; |
- |
- if (FLAG_harmony_completion && !is_set_) { |
- is_set_ = true; |
- replacement_ = AssignUndefinedBefore(node); |
- } |
-} |
- |
- |
-void Processor::VisitIterationStatement(IterationStatement* node) { |
- // Rewrite the body. |
- bool set_after = is_set_; |
- is_set_ = false; // We are in a loop, so we can't rely on [set_after]. |
- Visit(node->body()); |
- node->set_body(replacement_); |
- is_set_ = is_set_ && set_after; |
- replacement_ = node; |
- |
- if (FLAG_harmony_completion && !is_set_) { |
- is_set_ = true; |
- replacement_ = AssignUndefinedBefore(node); |
- } |
-} |
- |
- |
-void Processor::VisitDoWhileStatement(DoWhileStatement* node) { |
- VisitIterationStatement(node); |
-} |
- |
- |
-void Processor::VisitWhileStatement(WhileStatement* node) { |
- VisitIterationStatement(node); |
-} |
- |
- |
-void Processor::VisitForStatement(ForStatement* node) { |
- VisitIterationStatement(node); |
-} |
- |
- |
-void Processor::VisitForInStatement(ForInStatement* node) { |
- VisitIterationStatement(node); |
-} |
- |
- |
-void Processor::VisitForOfStatement(ForOfStatement* node) { |
- VisitIterationStatement(node); |
-} |
- |
- |
-void Processor::VisitTryCatchStatement(TryCatchStatement* node) { |
- // Rewrite both try and catch block. |
- bool set_after = is_set_; |
- Visit(node->try_block()); |
- node->set_try_block(static_cast<Block*>(replacement_)); |
- bool set_in_try = is_set_; |
- is_set_ = set_after; |
- Visit(node->catch_block()); |
- node->set_catch_block(static_cast<Block*>(replacement_)); |
- is_set_ = is_set_ && set_in_try; |
- replacement_ = node; |
- |
- if (FLAG_harmony_completion && !is_set_) { |
- is_set_ = true; |
- replacement_ = AssignUndefinedBefore(node); |
- } |
-} |
- |
- |
-void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) { |
- // Rewrite both try and finally block (in reverse order). |
- bool set_after = is_set_; |
- is_set_ = true; // Don't normally need to assign in finally block. |
- Visit(node->finally_block()); |
- node->set_finally_block(replacement_->AsBlock()); |
- { // Save .result value at the beginning of the finally block and restore it |
- // at the end again: ".backup = .result; ...; .result = .backup" |
- // This is necessary because the finally block does not normally contribute |
- // to the completion value. |
- Variable* backup = scope()->NewTemporary( |
- factory()->ast_value_factory()->dot_result_string()); |
- Expression* backup_proxy = factory()->NewVariableProxy(backup); |
- Expression* result_proxy = factory()->NewVariableProxy(result_); |
- Expression* save = factory()->NewAssignment( |
- Token::ASSIGN, backup_proxy, result_proxy, RelocInfo::kNoPosition); |
- Expression* restore = factory()->NewAssignment( |
- Token::ASSIGN, result_proxy, backup_proxy, RelocInfo::kNoPosition); |
- node->finally_block()->statements()->InsertAt( |
- 0, factory()->NewExpressionStatement(save, RelocInfo::kNoPosition), |
- zone()); |
- node->finally_block()->statements()->Add( |
- factory()->NewExpressionStatement(restore, RelocInfo::kNoPosition), |
- zone()); |
- } |
- is_set_ = set_after; |
- Visit(node->try_block()); |
- node->set_try_block(replacement_->AsBlock()); |
- replacement_ = node; |
- |
- if (FLAG_harmony_completion && !is_set_) { |
- is_set_ = true; |
- replacement_ = AssignUndefinedBefore(node); |
- } |
-} |
- |
- |
-void Processor::VisitSwitchStatement(SwitchStatement* node) { |
- // Rewrite statements in all case clauses (in reverse order). |
- ZoneList<CaseClause*>* clauses = node->cases(); |
- bool set_after = is_set_; |
- for (int i = clauses->length() - 1; i >= 0; --i) { |
- CaseClause* clause = clauses->at(i); |
- Process(clause->statements()); |
- } |
- is_set_ = is_set_ && set_after; |
- replacement_ = node; |
- |
- if (FLAG_harmony_completion && !is_set_) { |
- is_set_ = true; |
- replacement_ = AssignUndefinedBefore(node); |
- } |
-} |
- |
- |
-void Processor::VisitContinueStatement(ContinueStatement* node) { |
- is_set_ = false; |
- replacement_ = node; |
-} |
- |
- |
-void Processor::VisitBreakStatement(BreakStatement* node) { |
- is_set_ = false; |
- replacement_ = node; |
-} |
- |
- |
-void Processor::VisitWithStatement(WithStatement* node) { |
- Visit(node->statement()); |
- node->set_statement(replacement_); |
- replacement_ = node; |
- |
- if (FLAG_harmony_completion && !is_set_) { |
- is_set_ = true; |
- replacement_ = AssignUndefinedBefore(node); |
- } |
-} |
- |
- |
-void Processor::VisitSloppyBlockFunctionStatement( |
- SloppyBlockFunctionStatement* node) { |
- Visit(node->statement()); |
- node->set_statement(replacement_); |
- replacement_ = node; |
-} |
- |
- |
-void Processor::VisitEmptyStatement(EmptyStatement* node) { |
- replacement_ = node; |
-} |
- |
- |
-void Processor::VisitReturnStatement(ReturnStatement* node) { |
- is_set_ = true; |
- replacement_ = node; |
-} |
- |
- |
-void Processor::VisitDebuggerStatement(DebuggerStatement* node) { |
- replacement_ = node; |
-} |
- |
- |
-// Expressions are never visited. |
-#define DEF_VISIT(type) \ |
- void Processor::Visit##type(type* expr) { UNREACHABLE(); } |
-EXPRESSION_NODE_LIST(DEF_VISIT) |
-#undef DEF_VISIT |
- |
- |
-// Declarations are never visited. |
-#define DEF_VISIT(type) \ |
- void Processor::Visit##type(type* expr) { UNREACHABLE(); } |
-DECLARATION_NODE_LIST(DEF_VISIT) |
-#undef DEF_VISIT |
- |
- |
-// Assumes code has been parsed. Mutates the AST, so the AST should not |
-// continue to be used in the case of failure. |
-bool Rewriter::Rewrite(ParseInfo* info) { |
- FunctionLiteral* function = info->literal(); |
- DCHECK(function != NULL); |
- Scope* scope = function->scope(); |
- DCHECK(scope != NULL); |
- if (!scope->is_script_scope() && !scope->is_eval_scope()) return true; |
- |
- ZoneList<Statement*>* body = function->body(); |
- if (!body->is_empty()) { |
- Variable* result = |
- scope->NewTemporary(info->ast_value_factory()->dot_result_string()); |
- // The name string must be internalized at this point. |
- DCHECK(!result->name().is_null()); |
- Processor processor(info->isolate(), scope, result, |
- info->ast_value_factory()); |
- processor.Process(body); |
- if (processor.HasStackOverflow()) return false; |
- |
- if (processor.result_assigned()) { |
- DCHECK(function->end_position() != RelocInfo::kNoPosition); |
- // Set the position of the assignment statement one character past the |
- // source code, such that it definitely is not in the source code range |
- // of an immediate inner scope. For example in |
- // eval('with ({x:1}) x = 1'); |
- // the end position of the function generated for executing the eval code |
- // coincides with the end of the with scope which is the position of '1'. |
- int pos = function->end_position(); |
- VariableProxy* result_proxy = |
- processor.factory()->NewVariableProxy(result, pos); |
- Statement* result_statement = |
- processor.factory()->NewReturnStatement(result_proxy, pos); |
- body->Add(result_statement, info->zone()); |
- } |
- } |
- |
- return true; |
-} |
- |
- |
-bool Rewriter::Rewrite(Parser* parser, DoExpression* expr, |
- AstValueFactory* factory) { |
- Block* block = expr->block(); |
- Scope* scope = block->scope(); |
- ZoneList<Statement*>* body = block->statements(); |
- VariableProxy* result = expr->result(); |
- Variable* result_var = result->var(); |
- |
- if (!body->is_empty()) { |
- Processor processor(parser, scope, result_var, factory); |
- processor.Process(body); |
- if (processor.HasStackOverflow()) return false; |
- |
- if (!processor.result_assigned()) { |
- AstNodeFactory* node_factory = processor.factory(); |
- Expression* undef = |
- node_factory->NewUndefinedLiteral(RelocInfo::kNoPosition); |
- Statement* completion = node_factory->NewExpressionStatement( |
- processor.SetResult(undef), expr->position()); |
- body->Add(completion, factory->zone()); |
- } |
- } |
- return true; |
-} |
- |
- |
-} // namespace internal |
-} // namespace v8 |