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 "src/ast/ast-traversal-visitor.h"
8 #include "src/ast/ast.h"
9 #include "src/ast/scopes.h"
10 #include "src/objects-inl.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 namespace {
16 
17 
18 class Rewriter final : public AstTraversalVisitor<Rewriter> {
19  public:
Rewriter(uintptr_t stack_limit,Expression * initializer,Scope * param_scope)20   Rewriter(uintptr_t stack_limit, Expression* initializer, Scope* param_scope)
21       : AstTraversalVisitor(stack_limit, initializer),
22         param_scope_(param_scope) {}
23 
24  private:
25   // This is required so that the overriden Visit* methods can be
26   // called by the base class (template).
27   friend class AstTraversalVisitor<Rewriter>;
28 
29   void VisitFunctionLiteral(FunctionLiteral* expr);
30   void VisitClassLiteral(ClassLiteral* expr);
31   void VisitVariableProxy(VariableProxy* expr);
32 
33   void VisitBlock(Block* stmt);
34   void VisitTryCatchStatement(TryCatchStatement* stmt);
35   void VisitWithStatement(WithStatement* stmt);
36 
37   Scope* param_scope_;
38 };
39 
VisitFunctionLiteral(FunctionLiteral * function_literal)40 void Rewriter::VisitFunctionLiteral(FunctionLiteral* function_literal) {
41   function_literal->scope()->ReplaceOuterScope(param_scope_);
42 }
43 
44 
VisitClassLiteral(ClassLiteral * class_literal)45 void Rewriter::VisitClassLiteral(ClassLiteral* class_literal) {
46   if (class_literal->extends() != nullptr) {
47     Visit(class_literal->extends());
48   }
49   // No need to visit the constructor since it will have the class
50   // scope on its scope chain.
51   ZoneList<ClassLiteralProperty*>* props = class_literal->properties();
52   for (int i = 0; i < props->length(); ++i) {
53     ClassLiteralProperty* prop = props->at(i);
54     if (!prop->key()->IsLiteral()) {
55       Visit(prop->key());
56     }
57     // No need to visit the values, since all values are functions with
58     // the class scope on their scope chain.
59     DCHECK(prop->value()->IsFunctionLiteral());
60   }
61 }
62 
63 
VisitVariableProxy(VariableProxy * proxy)64 void Rewriter::VisitVariableProxy(VariableProxy* proxy) {
65   if (!proxy->is_resolved()) {
66     if (param_scope_->outer_scope()->RemoveUnresolved(proxy)) {
67       param_scope_->AddUnresolved(proxy);
68     }
69   } else {
70     // Ensure that temporaries we find are already in the correct scope.
71     DCHECK(proxy->var()->mode() != TEMPORARY ||
72            proxy->var()->scope() == param_scope_->GetClosureScope());
73   }
74 }
75 
76 
VisitBlock(Block * stmt)77 void Rewriter::VisitBlock(Block* stmt) {
78   if (stmt->scope() != nullptr)
79     stmt->scope()->ReplaceOuterScope(param_scope_);
80   else
81     VisitStatements(stmt->statements());
82 }
83 
84 
VisitTryCatchStatement(TryCatchStatement * stmt)85 void Rewriter::VisitTryCatchStatement(TryCatchStatement* stmt) {
86   Visit(stmt->try_block());
87   stmt->scope()->ReplaceOuterScope(param_scope_);
88 }
89 
90 
VisitWithStatement(WithStatement * stmt)91 void Rewriter::VisitWithStatement(WithStatement* stmt) {
92   Visit(stmt->expression());
93   stmt->scope()->ReplaceOuterScope(param_scope_);
94 }
95 
96 
97 }  // anonymous namespace
98 
ReparentParameterExpressionScope(uintptr_t stack_limit,Expression * expr,Scope * param_scope)99 void ReparentParameterExpressionScope(uintptr_t stack_limit, Expression* expr,
100                                       Scope* param_scope) {
101   // The only case that uses this code is block scopes for parameters containing
102   // sloppy eval.
103   DCHECK(param_scope->is_block_scope());
104   DCHECK(param_scope->is_declaration_scope());
105   DCHECK(param_scope->calls_sloppy_eval());
106   DCHECK(param_scope->outer_scope()->is_function_scope());
107 
108   Rewriter rewriter(stack_limit, expr, param_scope);
109   rewriter.Run();
110 }
111 
112 
113 }  // namespace internal
114 }  // namespace v8
115