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
12namespace v8 {
13namespace internal {
14
15namespace {
16
17class Reparenter final : public AstTraversalVisitor<Reparenter> {
18 public:
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
31 void VisitBlock(Block* stmt);
32 void VisitTryCatchStatement(TryCatchStatement* stmt);
33 void VisitWithStatement(WithStatement* stmt);
34
35 Scope* scope_;
36};
37
38void Reparenter::VisitFunctionLiteral(FunctionLiteral* function_literal) {
39 function_literal->scope()->ReplaceOuterScope(scope_);
40}
41
42void Reparenter::VisitClassLiteral(ClassLiteral* class_literal) {
43 class_literal->scope()->ReplaceOuterScope(scope_);
44 // No need to visit the constructor since it will have the class
45 // scope on its scope chain.
46 DCHECK_EQ(class_literal->constructor()->scope()->outer_scope(),
47 class_literal->scope());
48
49 if (class_literal->static_fields_initializer() != nullptr) {
50 DCHECK_EQ(
51 class_literal->static_fields_initializer()->scope()->outer_scope(),
52 class_literal->scope());
53 }
54#if DEBUG
55 // The same goes for the rest of the class, but we do some
56 // sanity checking in debug mode.
57 for (ClassLiteralProperty* prop : *class_literal->properties()) {
58 // No need to visit the values, since all values are functions with
59 // the class scope on their scope chain.
60 DCHECK(prop->value()->IsFunctionLiteral());
61 DCHECK_EQ(prop->value()->AsFunctionLiteral()->scope()->outer_scope(),
62 class_literal->scope());
63 }
64#endif
65}
66
67void Reparenter::VisitVariableProxy(VariableProxy* proxy) {
68 if (!proxy->is_resolved()) {
69 if (scope_->outer_scope()->RemoveUnresolved(proxy)) {
70 scope_->AddUnresolved(proxy);
71 }
72 } else {
73 // Ensure that temporaries we find are already in the correct scope.
74 DCHECK(proxy->var()->mode() != VariableMode::kTemporary ||
75 proxy->var()->scope() == scope_->GetClosureScope());
76 }
77}
78
79void Reparenter::VisitBlock(Block* stmt) {
80 if (stmt->scope())
81 stmt->scope()->ReplaceOuterScope(scope_);
82 else
83 VisitStatements(stmt->statements());
84}
85
86void Reparenter::VisitTryCatchStatement(TryCatchStatement* stmt) {
87 Visit(stmt->try_block());
88 if (stmt->scope()) {
89 stmt->scope()->ReplaceOuterScope(scope_);
90 } else {
91 Visit(stmt->catch_block());
92 }
93}
94
95void Reparenter::VisitWithStatement(WithStatement* stmt) {
96 Visit(stmt->expression());
97 stmt->scope()->ReplaceOuterScope(scope_);
98}
99
100} // anonymous namespace
101
102void ReparentExpressionScope(uintptr_t stack_limit, Expression* expr,
103 Scope* scope) {
104 // The only case that uses this code is block scopes for parameters containing
105 // sloppy eval.
106 DCHECK(scope->is_block_scope());
107 DCHECK(scope->is_declaration_scope());
108 DCHECK(scope->AsDeclarationScope()->calls_sloppy_eval());
109 DCHECK(scope->outer_scope()->is_function_scope());
110
111 Reparenter r(stack_limit, expr, scope);
112 r.Run();
113}
114
115} // namespace internal
116} // namespace v8
117