Home | History | Annotate | Download | only in parsing
      1 // Copyright 2015 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/parameter-initializer-rewriter.h"
      6 
      7 #include <algorithm>
      8 #include <utility>
      9 #include <vector>
     10 
     11 #include "src/ast/ast.h"
     12 #include "src/ast/ast-expression-visitor.h"
     13 #include "src/ast/scopes.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 
     18 namespace {
     19 
     20 
     21 class Rewriter final : public AstExpressionVisitor {
     22  public:
     23   Rewriter(uintptr_t stack_limit, Expression* initializer, Scope* old_scope,
     24            Scope* new_scope)
     25       : AstExpressionVisitor(stack_limit, initializer),
     26         old_scope_(old_scope),
     27         new_scope_(new_scope),
     28         old_scope_closure_(old_scope->ClosureScope()),
     29         new_scope_closure_(new_scope->ClosureScope()) {}
     30   ~Rewriter();
     31 
     32  private:
     33   void VisitExpression(Expression* expr) override {}
     34 
     35   void VisitFunctionLiteral(FunctionLiteral* expr) override;
     36   void VisitClassLiteral(ClassLiteral* expr) override;
     37   void VisitVariableProxy(VariableProxy* expr) override;
     38 
     39   void VisitBlock(Block* stmt) override;
     40   void VisitTryCatchStatement(TryCatchStatement* stmt) override;
     41   void VisitWithStatement(WithStatement* stmt) override;
     42 
     43   Scope* old_scope_;
     44   Scope* new_scope_;
     45   Scope* old_scope_closure_;
     46   Scope* new_scope_closure_;
     47   std::vector<std::pair<Variable*, int>> temps_;
     48 };
     49 
     50 struct LessThanSecond {
     51   bool operator()(const std::pair<Variable*, int>& left,
     52                   const std::pair<Variable*, int>& right) {
     53     return left.second < right.second;
     54   }
     55 };
     56 
     57 Rewriter::~Rewriter() {
     58   if (!temps_.empty()) {
     59     // Ensure that we add temporaries in the order they appeared in old_scope_.
     60     std::sort(temps_.begin(), temps_.end(), LessThanSecond());
     61     for (auto var_and_index : temps_) {
     62       var_and_index.first->set_scope(new_scope_closure_);
     63       new_scope_closure_->AddTemporary(var_and_index.first);
     64     }
     65   }
     66 }
     67 
     68 void Rewriter::VisitFunctionLiteral(FunctionLiteral* function_literal) {
     69   function_literal->scope()->ReplaceOuterScope(new_scope_);
     70 }
     71 
     72 
     73 void Rewriter::VisitClassLiteral(ClassLiteral* class_literal) {
     74   class_literal->scope()->ReplaceOuterScope(new_scope_);
     75   if (class_literal->extends() != nullptr) {
     76     Visit(class_literal->extends());
     77   }
     78   // No need to visit the constructor since it will have the class
     79   // scope on its scope chain.
     80   ZoneList<ObjectLiteralProperty*>* props = class_literal->properties();
     81   for (int i = 0; i < props->length(); ++i) {
     82     ObjectLiteralProperty* prop = props->at(i);
     83     if (!prop->key()->IsLiteral()) {
     84       Visit(prop->key());
     85     }
     86     // No need to visit the values, since all values are functions with
     87     // the class scope on their scope chain.
     88     DCHECK(prop->value()->IsFunctionLiteral());
     89   }
     90 }
     91 
     92 
     93 void Rewriter::VisitVariableProxy(VariableProxy* proxy) {
     94   if (proxy->is_resolved()) {
     95     Variable* var = proxy->var();
     96     if (var->mode() != TEMPORARY) return;
     97     // Temporaries are only placed in ClosureScopes.
     98     DCHECK_EQ(var->scope(), var->scope()->ClosureScope());
     99     // If the temporary is already where it should be, return quickly.
    100     if (var->scope() == new_scope_closure_) return;
    101     int index = old_scope_closure_->RemoveTemporary(var);
    102     if (index >= 0) {
    103       temps_.push_back(std::make_pair(var, index));
    104     }
    105   } else if (old_scope_->RemoveUnresolved(proxy)) {
    106     new_scope_->AddUnresolved(proxy);
    107   }
    108 }
    109 
    110 
    111 void Rewriter::VisitBlock(Block* stmt) {
    112   if (stmt->scope() != nullptr)
    113     stmt->scope()->ReplaceOuterScope(new_scope_);
    114   else
    115     VisitStatements(stmt->statements());
    116 }
    117 
    118 
    119 void Rewriter::VisitTryCatchStatement(TryCatchStatement* stmt) {
    120   Visit(stmt->try_block());
    121   stmt->scope()->ReplaceOuterScope(new_scope_);
    122 }
    123 
    124 
    125 void Rewriter::VisitWithStatement(WithStatement* stmt) {
    126   Visit(stmt->expression());
    127   stmt->scope()->ReplaceOuterScope(new_scope_);
    128 }
    129 
    130 
    131 }  // anonymous namespace
    132 
    133 
    134 void RewriteParameterInitializerScope(uintptr_t stack_limit,
    135                                       Expression* initializer, Scope* old_scope,
    136                                       Scope* new_scope) {
    137   Rewriter rewriter(stack_limit, initializer, old_scope, new_scope);
    138   rewriter.Run();
    139 }
    140 
    141 
    142 }  // namespace internal
    143 }  // namespace v8
    144