Home | History | Annotate | Download | only in parsing
      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             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         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             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         factory_(ast_value_factory) {
     42     DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
     43     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   Expression* SetResult(Expression* value) {
     55     result_assigned_ = true;
     56     VariableProxy* result_proxy = factory()->NewVariableProxy(result_);
     57     return factory()->NewAssignment(Token::ASSIGN, result_proxy, value,
     58                                     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         : processor_(processor), previous_(processor->breakable_) {
     89       processor->breakable_ = processor->breakable_ || breakable;
     90     }
     91 
     92     ~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   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
    111 };
    112 
    113 
    114 Statement* Processor::AssignUndefinedBefore(Statement* s) {
    115   Expression* result_proxy = factory()->NewVariableProxy(result_);
    116   Expression* undef = factory()->NewUndefinedLiteral(kNoSourcePosition);
    117   Expression* assignment = factory()->NewAssignment(Token::ASSIGN, result_proxy,
    118                                                     undef, kNoSourcePosition);
    119   Block* b = factory()->NewBlock(NULL, 2, false, kNoSourcePosition);
    120   b->statements()->Add(
    121       factory()->NewExpressionStatement(assignment, kNoSourcePosition), zone());
    122   b->statements()->Add(s, zone());
    123   return b;
    124 }
    125 
    126 
    127 void Processor::Process(ZoneList<Statement*>* statements) {
    128   // If we're in a breakable scope (named block, iteration, or switch), we walk
    129   // all statements. The last value producing statement before the break needs
    130   // to assign to .result. If we're not in a breakable scope, only the last
    131   // value producing statement in the block assigns to .result, so we can stop
    132   // early.
    133   for (int i = statements->length() - 1; i >= 0 && (breakable_ || !is_set_);
    134        --i) {
    135     Visit(statements->at(i));
    136     statements->Set(i, replacement_);
    137   }
    138 }
    139 
    140 
    141 void Processor::VisitBlock(Block* node) {
    142   // An initializer block is the rewritten form of a variable declaration
    143   // with initialization expressions. The initializer block contains the
    144   // list of assignments corresponding to the initialization expressions.
    145   // While unclear from the spec (ECMA-262, 3rd., 12.2), the value of
    146   // a variable declaration with initialization expression is 'undefined'
    147   // with some JS VMs: For instance, using smjs, print(eval('var x = 7'))
    148   // returns 'undefined'. To obtain the same behavior with v8, we need
    149   // to prevent rewriting in that case.
    150   if (!node->ignore_completion_value()) {
    151     BreakableScope scope(this, node->labels() != nullptr);
    152     Process(node->statements());
    153   }
    154   replacement_ = node;
    155 }
    156 
    157 
    158 void Processor::VisitExpressionStatement(ExpressionStatement* node) {
    159   // Rewrite : <x>; -> .result = <x>;
    160   if (!is_set_) {
    161     node->set_expression(SetResult(node->expression()));
    162     is_set_ = true;
    163   }
    164   replacement_ = node;
    165 }
    166 
    167 
    168 void Processor::VisitIfStatement(IfStatement* node) {
    169   // Rewrite both branches.
    170   bool set_after = is_set_;
    171 
    172   Visit(node->then_statement());
    173   node->set_then_statement(replacement_);
    174   bool set_in_then = is_set_;
    175 
    176   is_set_ = set_after;
    177   Visit(node->else_statement());
    178   node->set_else_statement(replacement_);
    179 
    180   replacement_ = set_in_then && is_set_ ? node : AssignUndefinedBefore(node);
    181   is_set_ = true;
    182 }
    183 
    184 
    185 void Processor::VisitIterationStatement(IterationStatement* node) {
    186   // The statement may have to produce a value, so always assign undefined
    187   // before.
    188   // TODO(verwaest): Omit it if we know that there's no break/continue leaving
    189   // it early.
    190   DCHECK(breakable_ || !is_set_);
    191   BreakableScope scope(this);
    192 
    193   Visit(node->body());
    194   node->set_body(replacement_);
    195 
    196   replacement_ = AssignUndefinedBefore(node);
    197   is_set_ = true;
    198 }
    199 
    200 
    201 void Processor::VisitDoWhileStatement(DoWhileStatement* node) {
    202   VisitIterationStatement(node);
    203 }
    204 
    205 
    206 void Processor::VisitWhileStatement(WhileStatement* node) {
    207   VisitIterationStatement(node);
    208 }
    209 
    210 
    211 void Processor::VisitForStatement(ForStatement* node) {
    212   VisitIterationStatement(node);
    213 }
    214 
    215 
    216 void Processor::VisitForInStatement(ForInStatement* node) {
    217   VisitIterationStatement(node);
    218 }
    219 
    220 
    221 void Processor::VisitForOfStatement(ForOfStatement* node) {
    222   VisitIterationStatement(node);
    223 }
    224 
    225 
    226 void Processor::VisitTryCatchStatement(TryCatchStatement* node) {
    227   // Rewrite both try and catch block.
    228   bool set_after = is_set_;
    229 
    230   Visit(node->try_block());
    231   node->set_try_block(static_cast<Block*>(replacement_));
    232   bool set_in_try = is_set_;
    233 
    234   is_set_ = set_after;
    235   Visit(node->catch_block());
    236   node->set_catch_block(static_cast<Block*>(replacement_));
    237 
    238   replacement_ = is_set_ && set_in_try ? node : AssignUndefinedBefore(node);
    239   is_set_ = true;
    240 }
    241 
    242 
    243 void Processor::VisitTryFinallyStatement(TryFinallyStatement* node) {
    244   // Only rewrite finally if it could contain 'break' or 'continue'. Always
    245   // rewrite try.
    246   if (breakable_) {
    247     // Only set result before a 'break' or 'continue'.
    248     is_set_ = true;
    249     Visit(node->finally_block());
    250     node->set_finally_block(replacement_->AsBlock());
    251     // Save .result value at the beginning of the finally block and restore it
    252     // at the end again: ".backup = .result; ...; .result = .backup"
    253     // This is necessary because the finally block does not normally contribute
    254     // to the completion value.
    255     CHECK_NOT_NULL(closure_scope());
    256     Variable* backup = closure_scope()->NewTemporary(
    257         factory()->ast_value_factory()->dot_result_string());
    258     Expression* backup_proxy = factory()->NewVariableProxy(backup);
    259     Expression* result_proxy = factory()->NewVariableProxy(result_);
    260     Expression* save = factory()->NewAssignment(
    261         Token::ASSIGN, backup_proxy, result_proxy, kNoSourcePosition);
    262     Expression* restore = factory()->NewAssignment(
    263         Token::ASSIGN, result_proxy, backup_proxy, kNoSourcePosition);
    264     node->finally_block()->statements()->InsertAt(
    265         0, factory()->NewExpressionStatement(save, kNoSourcePosition), zone());
    266     node->finally_block()->statements()->Add(
    267         factory()->NewExpressionStatement(restore, kNoSourcePosition), zone());
    268   }
    269   Visit(node->try_block());
    270   node->set_try_block(replacement_->AsBlock());
    271 
    272   replacement_ = is_set_ ? node : AssignUndefinedBefore(node);
    273   is_set_ = true;
    274 }
    275 
    276 
    277 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   ZoneList<CaseClause*>* clauses = node->cases();
    286   for (int i = clauses->length() - 1; i >= 0; --i) {
    287     CaseClause* clause = clauses->at(i);
    288     Process(clause->statements());
    289   }
    290 
    291   replacement_ = AssignUndefinedBefore(node);
    292   is_set_ = true;
    293 }
    294 
    295 
    296 void Processor::VisitContinueStatement(ContinueStatement* node) {
    297   is_set_ = false;
    298   replacement_ = node;
    299 }
    300 
    301 
    302 void Processor::VisitBreakStatement(BreakStatement* node) {
    303   is_set_ = false;
    304   replacement_ = node;
    305 }
    306 
    307 
    308 void Processor::VisitWithStatement(WithStatement* node) {
    309   Visit(node->statement());
    310   node->set_statement(replacement_);
    311 
    312   replacement_ = is_set_ ? node : AssignUndefinedBefore(node);
    313   is_set_ = true;
    314 }
    315 
    316 
    317 void Processor::VisitSloppyBlockFunctionStatement(
    318     SloppyBlockFunctionStatement* node) {
    319   Visit(node->statement());
    320   node->set_statement(replacement_);
    321   replacement_ = node;
    322 }
    323 
    324 
    325 void Processor::VisitEmptyStatement(EmptyStatement* node) {
    326   replacement_ = node;
    327 }
    328 
    329 
    330 void Processor::VisitReturnStatement(ReturnStatement* node) {
    331   is_set_ = true;
    332   replacement_ = node;
    333 }
    334 
    335 
    336 void Processor::VisitDebuggerStatement(DebuggerStatement* node) {
    337   replacement_ = node;
    338 }
    339 
    340 
    341 // Expressions are never visited.
    342 #define DEF_VISIT(type)                                         \
    343   void Processor::Visit##type(type* expr) { UNREACHABLE(); }
    344 EXPRESSION_NODE_LIST(DEF_VISIT)
    345 #undef DEF_VISIT
    346 
    347 
    348 // Declarations are never visited.
    349 #define DEF_VISIT(type) \
    350   void Processor::Visit##type(type* expr) { UNREACHABLE(); }
    351 DECLARATION_NODE_LIST(DEF_VISIT)
    352 #undef DEF_VISIT
    353 
    354 
    355 // Assumes code has been parsed.  Mutates the AST, so the AST should not
    356 // continue to be used in the case of failure.
    357 bool Rewriter::Rewrite(ParseInfo* info) {
    358   DisallowHeapAllocation no_allocation;
    359   DisallowHandleAllocation no_handles;
    360   DisallowHandleDereference no_deref;
    361 
    362   RuntimeCallTimerScope runtimeTimer(
    363       info->isolate(), &RuntimeCallStats::CompileRewriteReturnResult);
    364 
    365   FunctionLiteral* function = info->literal();
    366   DCHECK_NOT_NULL(function);
    367   Scope* scope = function->scope();
    368   DCHECK_NOT_NULL(scope);
    369   if (!scope->is_script_scope() && !scope->is_eval_scope()) return true;
    370 
    371   DeclarationScope* closure_scope = scope->GetClosureScope();
    372 
    373   ZoneList<Statement*>* body = function->body();
    374   if (!body->is_empty()) {
    375     Variable* result = closure_scope->NewTemporary(
    376         info->ast_value_factory()->dot_result_string());
    377     Processor processor(info->isolate()->stack_guard()->real_climit(),
    378                         closure_scope, result, info->ast_value_factory());
    379     processor.Process(body);
    380 
    381     // TODO(leszeks): Remove this check and releases once internalization is
    382     // moved out of parsing/analysis.
    383     DCHECK(ThreadId::Current().Equals(info->isolate()->thread_id()));
    384     no_deref.Release();
    385     no_handles.Release();
    386     no_allocation.Release();
    387 
    388     // Internalize any values created during rewriting.
    389     info->ast_value_factory()->Internalize(info->isolate());
    390     if (processor.HasStackOverflow()) return false;
    391 
    392     if (processor.result_assigned()) {
    393       int pos = kNoSourcePosition;
    394       VariableProxy* result_proxy =
    395           processor.factory()->NewVariableProxy(result, pos);
    396       Statement* result_statement =
    397           processor.factory()->NewReturnStatement(result_proxy, pos);
    398       body->Add(result_statement, info->zone());
    399     }
    400   }
    401 
    402   return true;
    403 }
    404 
    405 bool Rewriter::Rewrite(Parser* parser, DeclarationScope* closure_scope,
    406                        DoExpression* expr, AstValueFactory* factory) {
    407   DisallowHeapAllocation no_allocation;
    408   DisallowHandleAllocation no_handles;
    409   DisallowHandleDereference no_deref;
    410 
    411   Block* block = expr->block();
    412   DCHECK_EQ(closure_scope, closure_scope->GetClosureScope());
    413   DCHECK(block->scope() == nullptr ||
    414          block->scope()->GetClosureScope() == closure_scope);
    415   ZoneList<Statement*>* body = block->statements();
    416   VariableProxy* result = expr->result();
    417   Variable* result_var = result->var();
    418 
    419   if (!body->is_empty()) {
    420     Processor processor(parser, closure_scope, result_var, factory);
    421     processor.Process(body);
    422     if (processor.HasStackOverflow()) return false;
    423 
    424     if (!processor.result_assigned()) {
    425       AstNodeFactory* node_factory = processor.factory();
    426       Expression* undef = node_factory->NewUndefinedLiteral(kNoSourcePosition);
    427       Statement* completion = node_factory->NewExpressionStatement(
    428           processor.SetResult(undef), expr->position());
    429       body->Add(completion, factory->zone());
    430     }
    431   }
    432   return true;
    433 }
    434 
    435 
    436 }  // namespace internal
    437 }  // namespace v8
    438