• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/expression-scope-reparenter.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 class Reparenter final : public AstTraversalVisitor<Reparenter> {
18  public:
Reparenter(uintptr_t stack_limit,Expression * initializer,Scope * scope)19   Reparenter(uintptr_t stack_limit, Expression* initializer, Scope* scope)
20       : AstTraversalVisitor(stack_limit, initializer), scope_(scope) {}
21 
22  private:
23   // This is required so that the overriden Visit* methods can be
24   // called by the base class (template).
25   friend class AstTraversalVisitor<Reparenter>;
26 
27   void VisitFunctionLiteral(FunctionLiteral* expr);
28   void VisitClassLiteral(ClassLiteral* expr);
29   void VisitVariableProxy(VariableProxy* expr);
30   void VisitRewritableExpression(RewritableExpression* expr);
31 
32   void VisitBlock(Block* stmt);
33   void VisitTryCatchStatement(TryCatchStatement* stmt);
34   void VisitWithStatement(WithStatement* stmt);
35 
36   Scope* scope_;
37 };
38 
VisitFunctionLiteral(FunctionLiteral * function_literal)39 void Reparenter::VisitFunctionLiteral(FunctionLiteral* function_literal) {
40   function_literal->scope()->ReplaceOuterScope(scope_);
41 }
42 
VisitClassLiteral(ClassLiteral * class_literal)43 void Reparenter::VisitClassLiteral(ClassLiteral* class_literal) {
44   class_literal->scope()->ReplaceOuterScope(scope_);
45   // No need to visit the constructor since it will have the class
46   // scope on its scope chain.
47   DCHECK_EQ(class_literal->constructor()->scope()->outer_scope(),
48             class_literal->scope());
49 
50   if (class_literal->static_fields_initializer() != nullptr) {
51     DCHECK_EQ(
52         class_literal->static_fields_initializer()->scope()->outer_scope(),
53         class_literal->scope());
54   }
55 #if DEBUG
56   // The same goes for the rest of the class, but we do some
57   // sanity checking in debug mode.
58   ZonePtrList<ClassLiteralProperty>* props = class_literal->properties();
59   for (int i = 0; i < props->length(); ++i) {
60     ClassLiteralProperty* prop = props->at(i);
61     // No need to visit the values, since all values are functions with
62     // the class scope on their scope chain.
63     DCHECK(prop->value()->IsFunctionLiteral());
64     DCHECK_EQ(prop->value()->AsFunctionLiteral()->scope()->outer_scope(),
65               class_literal->scope());
66   }
67 #endif
68 }
69 
VisitVariableProxy(VariableProxy * proxy)70 void Reparenter::VisitVariableProxy(VariableProxy* proxy) {
71   if (!proxy->is_resolved()) {
72     if (scope_->outer_scope()->RemoveUnresolved(proxy)) {
73       scope_->AddUnresolved(proxy);
74     }
75   } else {
76     // Ensure that temporaries we find are already in the correct scope.
77     DCHECK(proxy->var()->mode() != VariableMode::kTemporary ||
78            proxy->var()->scope() == scope_->GetClosureScope());
79   }
80 }
81 
VisitRewritableExpression(RewritableExpression * expr)82 void Reparenter::VisitRewritableExpression(RewritableExpression* expr) {
83   Visit(expr->expression());
84   expr->set_scope(scope_);
85 }
86 
VisitBlock(Block * stmt)87 void Reparenter::VisitBlock(Block* stmt) {
88   if (stmt->scope())
89     stmt->scope()->ReplaceOuterScope(scope_);
90   else
91     VisitStatements(stmt->statements());
92 }
93 
VisitTryCatchStatement(TryCatchStatement * stmt)94 void Reparenter::VisitTryCatchStatement(TryCatchStatement* stmt) {
95   Visit(stmt->try_block());
96   if (stmt->scope()) {
97     stmt->scope()->ReplaceOuterScope(scope_);
98   } else {
99     Visit(stmt->catch_block());
100   }
101 }
102 
VisitWithStatement(WithStatement * stmt)103 void Reparenter::VisitWithStatement(WithStatement* stmt) {
104   Visit(stmt->expression());
105   stmt->scope()->ReplaceOuterScope(scope_);
106 }
107 
108 }  // anonymous namespace
109 
ReparentExpressionScope(uintptr_t stack_limit,Expression * expr,Scope * scope)110 void ReparentExpressionScope(uintptr_t stack_limit, Expression* expr,
111                              Scope* scope) {
112   // The only case that uses this code is block scopes for parameters containing
113   // sloppy eval.
114   DCHECK(scope->is_block_scope());
115   DCHECK(scope->is_declaration_scope());
116   DCHECK(scope->AsDeclarationScope()->calls_sloppy_eval());
117   DCHECK(scope->outer_scope()->is_function_scope());
118 
119   Reparenter r(stack_limit, expr, scope);
120   r.Run();
121 }
122 
123 }  // namespace internal
124 }  // namespace v8
125