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