LCOV - code coverage report
Current view: top level - src/parsing - rewriter.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 155 167 92.8 %
Date: 2017-04-26 Functions: 21 58 36.2 %

          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

Generated by: LCOV version 1.10