LCOV - code coverage report
Current view: top level - src/parsing - rewriter.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 141 156 90.4 %
Date: 2019-01-20 Functions: 22 65 33.8 %

          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     1086088 :             Variable* result, AstValueFactory* ast_value_factory)
      20             :       : result_(result),
      21             :         replacement_(nullptr),
      22             :         zone_(ast_value_factory->zone()),
      23             :         closure_scope_(closure_scope),
      24             :         factory_(ast_value_factory, ast_value_factory->zone()),
      25             :         result_assigned_(false),
      26             :         is_set_(false),
      27     2172176 :         breakable_(false) {
      28             :     DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
      29             :     InitializeAstVisitor(stack_limit);
      30             :   }
      31             : 
      32             :   Processor(Parser* parser, DeclarationScope* closure_scope, Variable* result,
      33             :             AstValueFactory* ast_value_factory)
      34             :       : result_(result),
      35             :         replacement_(nullptr),
      36             :         zone_(ast_value_factory->zone()),
      37             :         closure_scope_(closure_scope),
      38             :         factory_(ast_value_factory, zone_),
      39             :         result_assigned_(false),
      40             :         is_set_(false),
      41             :         breakable_(false) {
      42             :     DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
      43             :     InitializeAstVisitor(parser->stack_limit());
      44             :   }
      45             : 
      46             :   void Process(ZonePtrList<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     1094162 :   Expression* SetResult(Expression* value) {
      55     1094162 :     result_assigned_ = true;
      56     1094162 :     VariableProxy* result_proxy = factory()->NewVariableProxy(result_);
      57             :     return factory()->NewAssignment(Token::ASSIGN, result_proxy, value,
      58     1094155 :                                     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             :   // When visiting a node, we "return" a replacement for that node in
      68             :   // [replacement_].  In many cases this will just be the original node.
      69             :   Statement* replacement_;
      70             : 
      71             :   class BreakableScope final {
      72             :    public:
      73             :     explicit BreakableScope(Processor* processor, bool breakable = true)
      74      191923 :         : processor_(processor), previous_(processor->breakable_) {
      75      191923 :       processor->breakable_ = processor->breakable_ || breakable;
      76             :     }
      77             : 
      78      191925 :     ~BreakableScope() { processor_->breakable_ = previous_; }
      79             : 
      80             :    private:
      81             :     Processor* processor_;
      82             :     bool previous_;
      83             :   };
      84             : 
      85             :   Zone* zone_;
      86             :   DeclarationScope* closure_scope_;
      87             :   AstNodeFactory factory_;
      88             : 
      89             :   // Node visitors.
      90             : #define DEF_VISIT(type) void Visit##type(type* node);
      91             :   AST_NODE_LIST(DEF_VISIT)
      92             : #undef DEF_VISIT
      93             : 
      94             :   void VisitIterationStatement(IterationStatement* stmt);
      95             : 
      96     9072095 :   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
      97             : 
      98             :   // We are not tracking result usage via the result_'s use
      99             :   // counts (we leave the accurate computation to the
     100             :   // usage analyzer). Instead we simple remember if
     101             :   // there was ever an assignment to result_.
     102             :   bool result_assigned_;
     103             : 
     104             :   // To avoid storing to .result all the time, we eliminate some of
     105             :   // the stores by keeping track of whether or not we're sure .result
     106             :   // will be overwritten anyway. This is a bit more tricky than what I
     107             :   // was hoping for.
     108             :   bool is_set_;
     109             : 
     110             :   bool breakable_;
     111             : };
     112             : 
     113             : 
     114      193010 : Statement* Processor::AssignUndefinedBefore(Statement* s) {
     115       64336 :   Expression* undef = factory()->NewUndefinedLiteral(kNoSourcePosition);
     116       64337 :   Expression* assignment = SetResult(undef);
     117       64336 :   Block* b = factory()->NewBlock(2, false);
     118             :   b->statements()->Add(
     119      128673 :       factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone());
     120       64337 :   b->statements()->Add(s, zone());
     121       64337 :   return b;
     122             : }
     123             : 
     124     3799270 : void Processor::Process(ZonePtrList<Statement>* statements) {
     125             :   // If we're in a breakable scope (named block, iteration, or switch), we walk
     126             :   // all statements. The last value producing statement before the break needs
     127             :   // to assign to .result. If we're not in a breakable scope, only the last
     128             :   // value producing statement in the block assigns to .result, so we can stop
     129             :   // early.
     130     3799270 :   for (int i = statements->length() - 1; i >= 0 && (breakable_ || !is_set_);
     131             :        --i) {
     132     2581435 :     Visit(statements->at(i));
     133     2581442 :     statements->Set(i, replacement_);
     134             :   }
     135     1217835 : }
     136             : 
     137             : 
     138     1541704 : void Processor::VisitBlock(Block* node) {
     139             :   // An initializer block is the rewritten form of a variable declaration
     140             :   // with initialization expressions. The initializer block contains the
     141             :   // list of assignments corresponding to the initialization expressions.
     142             :   // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of
     143             :   // a variable declaration with initialization expression is 'undefined'
     144             :   // with some JS VMs: For instance, using smjs, print(eval('var x = 7'))
     145             :   // returns 'undefined'. To obtain the same behavior with v8, we need
     146             :   // to prevent rewriting in that case.
     147     1541704 :   if (!node->ignore_completion_value()) {
     148             :     BreakableScope scope(this, node->labels() != nullptr);
     149      131450 :     Process(node->statements());
     150             :   }
     151     1541705 :   replacement_ = node;
     152     1541705 : }
     153             : 
     154             : 
     155     2069379 : void Processor::VisitExpressionStatement(ExpressionStatement* node) {
     156             :   // Rewrite : <x>; -> .result = <x>;
     157     1039554 :   if (!is_set_) {
     158     1029825 :     node->set_expression(SetResult(node->expression()));
     159     1029820 :     is_set_ = true;
     160             :   }
     161     1039549 :   replacement_ = node;
     162     1039549 : }
     163             : 
     164             : 
     165        8106 : void Processor::VisitIfStatement(IfStatement* node) {
     166             :   // Rewrite both branches.
     167        2702 :   bool set_after = is_set_;
     168             : 
     169        2702 :   Visit(node->then_statement());
     170        2702 :   node->set_then_statement(replacement_);
     171        2702 :   bool set_in_then = is_set_;
     172             : 
     173        2702 :   is_set_ = set_after;
     174        2702 :   Visit(node->else_statement());
     175        2702 :   node->set_else_statement(replacement_);
     176             : 
     177        2702 :   replacement_ = set_in_then && is_set_ ? node : AssignUndefinedBefore(node);
     178        2702 :   is_set_ = true;
     179        2702 : }
     180             : 
     181             : 
     182      120478 : void Processor::VisitIterationStatement(IterationStatement* node) {
     183             :   // The statement may have to produce a value, so always assign undefined
     184             :   // before.
     185             :   // TODO(verwaest): Omit it if we know that there's no break/continue leaving
     186             :   // it early.
     187             :   DCHECK(breakable_ || !is_set_);
     188             :   BreakableScope scope(this);
     189             : 
     190       60239 :   Visit(node->body());
     191       60238 :   node->set_body(replacement_);
     192             : 
     193       60238 :   replacement_ = AssignUndefinedBefore(node);
     194       60240 :   is_set_ = true;
     195       60240 : }
     196             : 
     197             : 
     198         523 : void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
     199         523 :   VisitIterationStatement(node);
     200         523 : }
     201             : 
     202             : 
     203         744 : void Processor::VisitWhileStatement(WhileStatement* node) {
     204         744 :   VisitIterationStatement(node);
     205         745 : }
     206             : 
     207             : 
     208       50339 : void Processor::VisitForStatement(ForStatement* node) {
     209       50339 :   VisitIterationStatement(node);
     210       50339 : }
     211             : 
     212             : 
     213        4152 : void Processor::VisitForInStatement(ForInStatement* node) {
     214        4152 :   VisitIterationStatement(node);
     215        4152 : }
     216             : 
     217             : 
     218        4480 : void Processor::VisitForOfStatement(ForOfStatement* node) {
     219        4480 :   VisitIterationStatement(node);
     220        4481 : }
     221             : 
     222             : 
     223        7589 : void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
     224             :   // Rewrite both try and catch block.
     225        3795 :   bool set_after = is_set_;
     226             : 
     227        3795 :   Visit(node->try_block());
     228        3794 :   node->set_try_block(static_cast<Block*>(replacement_));
     229        3794 :   bool set_in_try = is_set_;
     230             : 
     231        3794 :   is_set_ = set_after;
     232        3794 :   Visit(node->catch_block());
     233        3794 :   node->set_catch_block(static_cast<Block*>(replacement_));
     234             : 
     235        3794 :   replacement_ = is_set_ && set_in_try ? node : AssignUndefinedBefore(node);
     236        3794 :   is_set_ = true;
     237        3794 : }
     238             : 
     239             : 
     240         867 : void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
     241             :   // Only rewrite finally if it could contain 'break' or 'continue'. Always
     242             :   // rewrite try.
     243         255 :   if (breakable_) {
     244             :     // Only set result before a 'break' or 'continue'.
     245         102 :     is_set_ = true;
     246         102 :     Visit(node->finally_block());
     247         102 :     node->set_finally_block(replacement_->AsBlock());
     248             :     // Save .result value at the beginning of the finally block and restore it
     249             :     // at the end again: ".backup = .result; ...; .result = .backup"
     250             :     // This is necessary because the finally block does not normally contribute
     251             :     // to the completion value.
     252         102 :     CHECK_NOT_NULL(closure_scope());
     253             :     Variable* backup = closure_scope()->NewTemporary(
     254         204 :         factory()->ast_value_factory()->dot_result_string());
     255         102 :     Expression* backup_proxy = factory()->NewVariableProxy(backup);
     256         102 :     Expression* result_proxy = factory()->NewVariableProxy(result_);
     257             :     Expression* save = factory()->NewAssignment(
     258         102 :         Token::ASSIGN, backup_proxy, result_proxy, kNoSourcePosition);
     259             :     Expression* restore = factory()->NewAssignment(
     260         102 :         Token::ASSIGN, result_proxy, backup_proxy, kNoSourcePosition);
     261             :     node->finally_block()->statements()->InsertAt(
     262         306 :         0, factory()->NewExpressionStatement(save, kNoSourcePosition), zone());
     263             :     node->finally_block()->statements()->Add(
     264         306 :         factory()->NewExpressionStatement(restore, kNoSourcePosition), zone());
     265             :     // We can't tell whether the finally-block is guaranteed to set .result, so
     266             :     // reset is_set_ before visiting the try-block.
     267         102 :     is_set_ = false;
     268             :   }
     269         255 :   Visit(node->try_block());
     270         255 :   node->set_try_block(replacement_->AsBlock());
     271             : 
     272         255 :   replacement_ = is_set_ ? node : AssignUndefinedBefore(node);
     273         255 :   is_set_ = true;
     274         255 : }
     275             : 
     276             : 
     277         234 : void Processor::VisitSwitchStatement(SwitchStatement* node) {
     278             :   // The statement may have to produce a value, so always assign undefined
     279             :   // before.
     280             :   // TODO(verwaest): Omit it if we know that there's no break/continue leaving
     281             :   // it early.
     282             :   DCHECK(breakable_ || !is_set_);
     283             :   BreakableScope scope(this);
     284             :   // Rewrite statements in all case clauses.
     285         234 :   ZonePtrList<CaseClause>* clauses = node->cases();
     286         534 :   for (int i = clauses->length() - 1; i >= 0; --i) {
     287         300 :     CaseClause* clause = clauses->at(i);
     288         300 :     Process(clause->statements());
     289             :   }
     290             : 
     291         234 :   replacement_ = AssignUndefinedBefore(node);
     292         234 :   is_set_ = true;
     293         234 : }
     294             : 
     295             : 
     296           0 : void Processor::VisitContinueStatement(ContinueStatement* node) {
     297         235 :   is_set_ = false;
     298         235 :   replacement_ = node;
     299           0 : }
     300             : 
     301             : 
     302           0 : void Processor::VisitBreakStatement(BreakStatement* node) {
     303        1152 :   is_set_ = false;
     304        1152 :   replacement_ = node;
     305           0 : }
     306             : 
     307             : 
     308        3486 : void Processor::VisitWithStatement(WithStatement* node) {
     309        3486 :   Visit(node->statement());
     310        3486 :   node->set_statement(replacement_);
     311             : 
     312        3486 :   replacement_ = is_set_ ? node : AssignUndefinedBefore(node);
     313        3486 :   is_set_ = true;
     314        3486 : }
     315             : 
     316             : 
     317        1742 : void Processor::VisitSloppyBlockFunctionStatement(
     318        1742 :     SloppyBlockFunctionStatement* node) {
     319        1742 :   Visit(node->statement());
     320        1742 :   node->set_statement(replacement_);
     321        1742 :   replacement_ = node;
     322        1742 : }
     323             : 
     324             : 
     325           0 : void Processor::VisitEmptyStatement(EmptyStatement* node) {
     326        2939 :   replacement_ = node;
     327           0 : }
     328             : 
     329             : 
     330           0 : void Processor::VisitReturnStatement(ReturnStatement* node) {
     331          64 :   is_set_ = true;
     332          64 :   replacement_ = node;
     333           0 : }
     334             : 
     335             : 
     336           0 : void Processor::VisitDebuggerStatement(DebuggerStatement* node) {
     337        2147 :   replacement_ = node;
     338           0 : }
     339             : 
     340           0 : void Processor::VisitInitializeClassMembersStatement(
     341             :     InitializeClassMembersStatement* node) {
     342           0 :   replacement_ = node;
     343           0 : }
     344             : 
     345             : // Expressions are never visited.
     346             : #define DEF_VISIT(type)                                         \
     347             :   void Processor::Visit##type(type* expr) { UNREACHABLE(); }
     348           0 : EXPRESSION_NODE_LIST(DEF_VISIT)
     349             : #undef DEF_VISIT
     350             : 
     351             : 
     352             : // Declarations are never visited.
     353             : #define DEF_VISIT(type) \
     354             :   void Processor::Visit##type(type* expr) { UNREACHABLE(); }
     355           0 : DECLARATION_NODE_LIST(DEF_VISIT)
     356             : #undef DEF_VISIT
     357             : 
     358             : 
     359             : // Assumes code has been parsed.  Mutates the AST, so the AST should not
     360             : // continue to be used in the case of failure.
     361     6418526 : bool Rewriter::Rewrite(ParseInfo* info) {
     362             :   DisallowHeapAllocation no_allocation;
     363             :   DisallowHandleAllocation no_handles;
     364             :   DisallowHandleDereference no_deref;
     365             : 
     366             :   RuntimeCallTimerScope runtimeTimer(
     367             :       info->runtime_call_stats(),
     368             :       info->on_background_thread()
     369             :           ? RuntimeCallCounterId::kCompileBackgroundRewriteReturnResult
     370     3554956 :           : RuntimeCallCounterId::kCompileRewriteReturnResult);
     371             : 
     372     1777482 :   FunctionLiteral* function = info->literal();
     373             :   DCHECK_NOT_NULL(function);
     374     1777482 :   Scope* scope = function->scope();
     375             :   DCHECK_NOT_NULL(scope);
     376             :   DCHECK_EQ(scope, scope->GetClosureScope());
     377             : 
     378     3315643 :   if (!(scope->is_script_scope() || scope->is_eval_scope() ||
     379     2459137 :         scope->is_module_scope())) {
     380             :     return true;
     381             :   }
     382             : 
     383     1104578 :   ZonePtrList<Statement>* body = function->body();
     384             :   DCHECK_IMPLIES(scope->is_module_scope(), !body->is_empty());
     385     1104578 :   if (!body->is_empty()) {
     386     1086092 :     Variable* result = scope->AsDeclarationScope()->NewTemporary(
     387     2172185 :         info->ast_value_factory()->dot_result_string());
     388             :     Processor processor(info->stack_limit(), scope->AsDeclarationScope(),
     389     1086088 :                         result, info->ast_value_factory());
     390     1086083 :     processor.Process(body);
     391             : 
     392             :     DCHECK_IMPLIES(scope->is_module_scope(), processor.result_assigned());
     393     1086078 :     if (processor.result_assigned()) {
     394             :       int pos = kNoSourcePosition;
     395             :       Expression* result_value =
     396     1049155 :           processor.factory()->NewVariableProxy(result, pos);
     397             :       Statement* result_statement =
     398     2098309 :           processor.factory()->NewReturnStatement(result_value, pos);
     399     1049154 :       body->Add(result_statement, info->zone());
     400             :     }
     401             : 
     402     1086075 :     if (processor.HasStackOverflow()) return false;
     403             :   }
     404             : 
     405             :   return true;
     406             : }
     407             : 
     408             : }  // namespace internal
     409      183867 : }  // namespace v8

Generated by: LCOV version 1.10