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-02-19 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             : #include "src/zone/zone-list-inl.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : class Processor final : public AstVisitor<Processor> {
      18             :  public:
      19             :   Processor(uintptr_t stack_limit, DeclarationScope* closure_scope,
      20     1078852 :             Variable* result, AstValueFactory* ast_value_factory)
      21             :       : result_(result),
      22             :         replacement_(nullptr),
      23             :         zone_(ast_value_factory->zone()),
      24             :         closure_scope_(closure_scope),
      25             :         factory_(ast_value_factory, ast_value_factory->zone()),
      26             :         result_assigned_(false),
      27             :         is_set_(false),
      28     2157704 :         breakable_(false) {
      29             :     DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
      30             :     InitializeAstVisitor(stack_limit);
      31             :   }
      32             : 
      33             :   Processor(Parser* parser, DeclarationScope* closure_scope, Variable* result,
      34             :             AstValueFactory* ast_value_factory)
      35             :       : result_(result),
      36             :         replacement_(nullptr),
      37             :         zone_(ast_value_factory->zone()),
      38             :         closure_scope_(closure_scope),
      39             :         factory_(ast_value_factory, zone_),
      40             :         result_assigned_(false),
      41             :         is_set_(false),
      42             :         breakable_(false) {
      43             :     DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
      44             :     InitializeAstVisitor(parser->stack_limit());
      45             :   }
      46             : 
      47             :   void Process(ZonePtrList<Statement>* statements);
      48             :   bool result_assigned() const { return result_assigned_; }
      49             : 
      50             :   Zone* zone() { return zone_; }
      51             :   DeclarationScope* closure_scope() { return closure_scope_; }
      52             :   AstNodeFactory* factory() { return &factory_; }
      53             : 
      54             :   // Returns ".result = value"
      55     1088615 :   Expression* SetResult(Expression* value) {
      56     1088615 :     result_assigned_ = true;
      57     1088615 :     VariableProxy* result_proxy = factory()->NewVariableProxy(result_);
      58             :     return factory()->NewAssignment(Token::ASSIGN, result_proxy, value,
      59     1088614 :                                     kNoSourcePosition);
      60             :   }
      61             : 
      62             :   // Inserts '.result = undefined' in front of the given statement.
      63             :   Statement* AssignUndefinedBefore(Statement* s);
      64             : 
      65             :  private:
      66             :   Variable* result_;
      67             : 
      68             :   // When visiting a node, we "return" a replacement for that node in
      69             :   // [replacement_].  In many cases this will just be the original node.
      70             :   Statement* replacement_;
      71             : 
      72             :   class BreakableScope final {
      73             :    public:
      74             :     explicit BreakableScope(Processor* processor, bool breakable = true)
      75      192270 :         : processor_(processor), previous_(processor->breakable_) {
      76      192270 :       processor->breakable_ = processor->breakable_ || breakable;
      77             :     }
      78             : 
      79      192263 :     ~BreakableScope() { processor_->breakable_ = previous_; }
      80             : 
      81             :    private:
      82             :     Processor* processor_;
      83             :     bool previous_;
      84             :   };
      85             : 
      86             :   Zone* zone_;
      87             :   DeclarationScope* closure_scope_;
      88             :   AstNodeFactory factory_;
      89             : 
      90             :   // Node visitors.
      91             : #define DEF_VISIT(type) void Visit##type(type* node);
      92             :   AST_NODE_LIST(DEF_VISIT)
      93             : #undef DEF_VISIT
      94             : 
      95             :   void VisitIterationStatement(IterationStatement* stmt);
      96             : 
      97     8842664 :   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
      98             : 
      99             :   // We are not tracking result usage via the result_'s use
     100             :   // counts (we leave the accurate computation to the
     101             :   // usage analyzer). Instead we simple remember if
     102             :   // there was ever an assignment to result_.
     103             :   bool result_assigned_;
     104             : 
     105             :   // To avoid storing to .result all the time, we eliminate some of
     106             :   // the stores by keeping track of whether or not we're sure .result
     107             :   // will be overwritten anyway. This is a bit more tricky than what I
     108             :   // was hoping for.
     109             :   bool is_set_;
     110             : 
     111             :   bool breakable_;
     112             : };
     113             : 
     114             : 
     115      192549 : Statement* Processor::AssignUndefinedBefore(Statement* s) {
     116       64183 :   Expression* undef = factory()->NewUndefinedLiteral(kNoSourcePosition);
     117       64184 :   Expression* assignment = SetResult(undef);
     118       64183 :   Block* b = factory()->NewBlock(2, false);
     119             :   b->statements()->Add(
     120      128366 :       factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone());
     121       64183 :   b->statements()->Add(s, zone());
     122       64182 :   return b;
     123             : }
     124             : 
     125     3718253 : void Processor::Process(ZonePtrList<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     3718253 :   for (int i = statements->length() - 1; i >= 0 && (breakable_ || !is_set_);
     132             :        --i) {
     133     2507258 :     Visit(statements->at(i));
     134     2507245 :     statements->Set(i, replacement_);
     135             :   }
     136     1210995 : }
     137             : 
     138             : 
     139     1473250 : 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     1473250 :   if (!node->ignore_completion_value()) {
     149             :     BreakableScope scope(this, node->labels() != nullptr);
     150      131857 :     Process(node->statements());
     151             :   }
     152     1473247 :   replacement_ = node;
     153     1473247 : }
     154             : 
     155             : 
     156     2058277 : void Processor::VisitExpressionStatement(ExpressionStatement* node) {
     157             :   // Rewrite : <x>; -> .result = <x>;
     158     1033845 :   if (!is_set_) {
     159     1024432 :     node->set_expression(SetResult(node->expression()));
     160     1024434 :     is_set_ = true;
     161             :   }
     162     1033847 :   replacement_ = node;
     163     1033847 : }
     164             : 
     165             : 
     166        7810 : void Processor::VisitIfStatement(IfStatement* node) {
     167             :   // Rewrite both branches.
     168        2603 :   bool set_after = is_set_;
     169             : 
     170        2603 :   Visit(node->then_statement());
     171        2604 :   node->set_then_statement(replacement_);
     172        2604 :   bool set_in_then = is_set_;
     173             : 
     174        2604 :   is_set_ = set_after;
     175        2604 :   Visit(node->else_statement());
     176        2603 :   node->set_else_statement(replacement_);
     177             : 
     178        2603 :   replacement_ = set_in_then && is_set_ ? node : AssignUndefinedBefore(node);
     179        2603 :   is_set_ = true;
     180        2603 : }
     181             : 
     182             : 
     183      120358 : 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       60179 :   Visit(node->body());
     192       60176 :   node->set_body(replacement_);
     193             : 
     194       60176 :   replacement_ = AssignUndefinedBefore(node);
     195       60175 :   is_set_ = true;
     196       60175 : }
     197             : 
     198             : 
     199         523 : void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
     200         523 :   VisitIterationStatement(node);
     201         523 : }
     202             : 
     203             : 
     204         732 : void Processor::VisitWhileStatement(WhileStatement* node) {
     205         732 :   VisitIterationStatement(node);
     206         732 : }
     207             : 
     208             : 
     209       50228 : void Processor::VisitForStatement(ForStatement* node) {
     210       50228 :   VisitIterationStatement(node);
     211       50226 : }
     212             : 
     213             : 
     214        4151 : void Processor::VisitForInStatement(ForInStatement* node) {
     215        4151 :   VisitIterationStatement(node);
     216        4151 : }
     217             : 
     218             : 
     219        4545 : void Processor::VisitForOfStatement(ForOfStatement* node) {
     220        4545 :   VisitIterationStatement(node);
     221        4544 : }
     222             : 
     223             : 
     224        7932 : void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
     225             :   // Rewrite both try and catch block.
     226        3966 :   bool set_after = is_set_;
     227             : 
     228        3966 :   Visit(node->try_block());
     229        3966 :   node->set_try_block(static_cast<Block*>(replacement_));
     230        3966 :   bool set_in_try = is_set_;
     231             : 
     232        3966 :   is_set_ = set_after;
     233        3966 :   Visit(node->catch_block());
     234        3965 :   node->set_catch_block(static_cast<Block*>(replacement_));
     235             : 
     236        3965 :   replacement_ = is_set_ && set_in_try ? node : AssignUndefinedBefore(node);
     237        3965 :   is_set_ = true;
     238        3965 : }
     239             : 
     240             : 
     241         909 : void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
     242             :   // Only rewrite finally if it could contain 'break' or 'continue'. Always
     243             :   // rewrite try.
     244         297 :   if (breakable_) {
     245             :     // Only set result before a 'break' or 'continue'.
     246         102 :     is_set_ = true;
     247         102 :     Visit(node->finally_block());
     248         102 :     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         102 :     CHECK_NOT_NULL(closure_scope());
     254             :     Variable* backup = closure_scope()->NewTemporary(
     255         204 :         factory()->ast_value_factory()->dot_result_string());
     256         102 :     Expression* backup_proxy = factory()->NewVariableProxy(backup);
     257         102 :     Expression* result_proxy = factory()->NewVariableProxy(result_);
     258             :     Expression* save = factory()->NewAssignment(
     259         102 :         Token::ASSIGN, backup_proxy, result_proxy, kNoSourcePosition);
     260             :     Expression* restore = factory()->NewAssignment(
     261         102 :         Token::ASSIGN, result_proxy, backup_proxy, kNoSourcePosition);
     262             :     node->finally_block()->statements()->InsertAt(
     263         306 :         0, factory()->NewExpressionStatement(save, kNoSourcePosition), zone());
     264             :     node->finally_block()->statements()->Add(
     265         306 :         factory()->NewExpressionStatement(restore, kNoSourcePosition), zone());
     266             :     // We can't tell whether the finally-block is guaranteed to set .result, so
     267             :     // reset is_set_ before visiting the try-block.
     268         102 :     is_set_ = false;
     269             :   }
     270         297 :   Visit(node->try_block());
     271         297 :   node->set_try_block(replacement_->AsBlock());
     272             : 
     273         297 :   replacement_ = is_set_ ? node : AssignUndefinedBefore(node);
     274         297 :   is_set_ = true;
     275         297 : }
     276             : 
     277             : 
     278         234 : void Processor::VisitSwitchStatement(SwitchStatement* node) {
     279             :   // The statement may have to produce a value, so always assign undefined
     280             :   // before.
     281             :   // TODO(verwaest): Omit it if we know that there's no break/continue leaving
     282             :   // it early.
     283             :   DCHECK(breakable_ || !is_set_);
     284             :   BreakableScope scope(this);
     285             :   // Rewrite statements in all case clauses.
     286         234 :   ZonePtrList<CaseClause>* clauses = node->cases();
     287         534 :   for (int i = clauses->length() - 1; i >= 0; --i) {
     288         300 :     CaseClause* clause = clauses->at(i);
     289         300 :     Process(clause->statements());
     290             :   }
     291             : 
     292         234 :   replacement_ = AssignUndefinedBefore(node);
     293         234 :   is_set_ = true;
     294         234 : }
     295             : 
     296             : 
     297           0 : void Processor::VisitContinueStatement(ContinueStatement* node) {
     298         235 :   is_set_ = false;
     299         235 :   replacement_ = node;
     300           0 : }
     301             : 
     302             : 
     303           0 : void Processor::VisitBreakStatement(BreakStatement* node) {
     304        1223 :   is_set_ = false;
     305        1223 :   replacement_ = node;
     306           0 : }
     307             : 
     308             : 
     309        3486 : void Processor::VisitWithStatement(WithStatement* node) {
     310        3486 :   Visit(node->statement());
     311        3486 :   node->set_statement(replacement_);
     312             : 
     313        3486 :   replacement_ = is_set_ ? node : AssignUndefinedBefore(node);
     314        3486 :   is_set_ = true;
     315        3486 : }
     316             : 
     317             : 
     318        1736 : void Processor::VisitSloppyBlockFunctionStatement(
     319        1736 :     SloppyBlockFunctionStatement* node) {
     320        1736 :   Visit(node->statement());
     321        1736 :   node->set_statement(replacement_);
     322        1736 :   replacement_ = node;
     323        1736 : }
     324             : 
     325             : 
     326           0 : void Processor::VisitEmptyStatement(EmptyStatement* node) {
     327        2918 :   replacement_ = node;
     328           0 : }
     329             : 
     330             : 
     331           0 : void Processor::VisitReturnStatement(ReturnStatement* node) {
     332          64 :   is_set_ = true;
     333          64 :   replacement_ = node;
     334           0 : }
     335             : 
     336             : 
     337           0 : void Processor::VisitDebuggerStatement(DebuggerStatement* node) {
     338        2147 :   replacement_ = node;
     339           0 : }
     340             : 
     341           0 : void Processor::VisitInitializeClassMembersStatement(
     342             :     InitializeClassMembersStatement* node) {
     343           0 :   replacement_ = node;
     344           0 : }
     345             : 
     346             : // Expressions are never visited.
     347             : #define DEF_VISIT(type)                                         \
     348             :   void Processor::Visit##type(type* expr) { UNREACHABLE(); }
     349           0 : EXPRESSION_NODE_LIST(DEF_VISIT)
     350             : #undef DEF_VISIT
     351             : 
     352             : 
     353             : // Declarations are never visited.
     354             : #define DEF_VISIT(type) \
     355             :   void Processor::Visit##type(type* expr) { UNREACHABLE(); }
     356           0 : DECLARATION_NODE_LIST(DEF_VISIT)
     357             : #undef DEF_VISIT
     358             : 
     359             : 
     360             : // Assumes code has been parsed.  Mutates the AST, so the AST should not
     361             : // continue to be used in the case of failure.
     362     6356677 : bool Rewriter::Rewrite(ParseInfo* info) {
     363             :   DisallowHeapAllocation no_allocation;
     364             :   DisallowHandleAllocation no_handles;
     365             :   DisallowHandleDereference no_deref;
     366             : 
     367             :   RuntimeCallTimerScope runtimeTimer(
     368             :       info->runtime_call_stats(),
     369             :       info->on_background_thread()
     370             :           ? RuntimeCallCounterId::kCompileBackgroundRewriteReturnResult
     371     3518548 :           : RuntimeCallCounterId::kCompileRewriteReturnResult);
     372             : 
     373     1759277 :   FunctionLiteral* function = info->literal();
     374             :   DCHECK_NOT_NULL(function);
     375     1759277 :   Scope* scope = function->scope();
     376             :   DCHECK_NOT_NULL(scope);
     377             :   DCHECK_EQ(scope, scope->GetClosureScope());
     378             : 
     379     3282746 :   if (!(scope->is_script_scope() || scope->is_eval_scope() ||
     380     2430048 :         scope->is_module_scope())) {
     381             :     return true;
     382             :   }
     383             : 
     384     1097393 :   ZonePtrList<Statement>* body = function->body();
     385             :   DCHECK_IMPLIES(scope->is_module_scope(), !body->is_empty());
     386     1097393 :   if (!body->is_empty()) {
     387     1078855 :     Variable* result = scope->AsDeclarationScope()->NewTemporary(
     388     2157709 :         info->ast_value_factory()->dot_result_string());
     389             :     Processor processor(info->stack_limit(), scope->AsDeclarationScope(),
     390     1078852 :                         result, info->ast_value_factory());
     391     1078852 :     processor.Process(body);
     392             : 
     393             :     DCHECK_IMPLIES(scope->is_module_scope(), processor.result_assigned());
     394     1078846 :     if (processor.result_assigned()) {
     395             :       int pos = kNoSourcePosition;
     396             :       Expression* result_value =
     397     1043677 :           processor.factory()->NewVariableProxy(result, pos);
     398             :       Statement* result_statement =
     399     2087349 :           processor.factory()->NewReturnStatement(result_value, pos);
     400     1043674 :       body->Add(result_statement, info->zone());
     401             :     }
     402             : 
     403     1078849 :     if (processor.HasStackOverflow()) return false;
     404             :   }
     405             : 
     406             :   return true;
     407             : }
     408             : 
     409             : }  // namespace internal
     410      178779 : }  // namespace v8

Generated by: LCOV version 1.10