LCOV - code coverage report
Current view: top level - src/parsing - pattern-rewriter.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 54 107 50.5 %
Date: 2019-01-20 Functions: 11 62 17.7 %

          Line data    Source code
       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/ast/ast.h"
       6             : #include "src/message-template.h"
       7             : #include "src/objects-inl.h"
       8             : #include "src/parsing/expression-scope-reparenter.h"
       9             : #include "src/parsing/parser.h"
      10             : 
      11             : namespace v8 {
      12             : 
      13             : namespace internal {
      14             : 
      15             : // An AST visitor which performs declaration and assignment related tasks,
      16             : // particularly for destructuring patterns:
      17             : //
      18             : //   1. Declares variables from variable proxies (particularly for destructuring
      19             : //      declarations),
      20             : //   2. Marks destructuring-assigned variable proxies as assigned, and
      21             : //   3. Rewrites scopes for parameters containing a sloppy eval.
      22             : //
      23             : // Historically this also rewrote destructuring assignments/declarations as a
      24             : // block of multiple assignments, hence the named, however this is now done
      25             : // during bytecode generation.
      26             : //
      27             : // TODO(leszeks): Rename or remove this class
      28             : class PatternRewriter final : public AstVisitor<PatternRewriter> {
      29             :  public:
      30             :   // Limit the allowed number of local variables in a function. The hard limit
      31             :   // is that offsets computed by FullCodeGenerator::StackOperand and similar
      32             :   // functions are ints, and they should not overflow. In addition, accessing
      33             :   // local variables creates user-controlled constants in the generated code,
      34             :   // and we don't want too much user-controlled memory inside the code (this was
      35             :   // the reason why this limit was introduced in the first place; see
      36             :   // https://codereview.chromium.org/7003030/ ).
      37             :   static const int kMaxNumFunctionLocals = 4194303;  // 2^22-1
      38             : 
      39             :   typedef Parser::DeclarationDescriptor DeclarationDescriptor;
      40             : 
      41             :   static void InitializeVariables(
      42             :       Parser* parser, const DeclarationDescriptor* declaration_descriptor,
      43             :       const Parser::DeclarationParsingResult::Declaration* declaration,
      44             :       ZonePtrList<const AstRawString>* names);
      45             : 
      46             :  private:
      47             :   PatternRewriter(Parser* parser, const DeclarationDescriptor* descriptor,
      48             :                   ZonePtrList<const AstRawString>* names, bool has_initializer,
      49             :                   int initializer_position = kNoSourcePosition,
      50             :                   bool declares_parameter_containing_sloppy_eval = false)
      51             :       : parser_(parser),
      52             :         descriptor_(descriptor),
      53             :         names_(names),
      54             :         initializer_position_(initializer_position),
      55             :         has_initializer_(has_initializer),
      56             :         declares_parameter_containing_sloppy_eval_(
      57     9316654 :             declares_parameter_containing_sloppy_eval) {}
      58             : 
      59             : #define DECLARE_VISIT(type) void Visit##type(v8::internal::type* node);
      60             :   // Visiting functions for AST nodes make this an AstVisitor.
      61             :   AST_NODE_LIST(DECLARE_VISIT)
      62             : #undef DECLARE_VISIT
      63             : 
      64     9441268 :   void RecurseIntoSubpattern(AstNode* pattern) { Visit(pattern); }
      65             : 
      66             :   Expression* Visit(Assignment* assign) {
      67             :     if (parser_->has_error()) return parser_->FailureExpression();
      68             :     DCHECK_EQ(Token::ASSIGN, assign->op());
      69             : 
      70             :     Expression* pattern = assign->target();
      71             :     if (pattern->IsObjectLiteral()) {
      72             :       VisitObjectLiteral(pattern->AsObjectLiteral());
      73             :     } else {
      74             :       DCHECK(pattern->IsArrayLiteral());
      75             :       VisitArrayLiteral(pattern->AsArrayLiteral());
      76             :     }
      77             :     return assign;
      78             :   }
      79             : 
      80             :   void RewriteParameterScopes(Expression* expr);
      81             : 
      82             :   AstNodeFactory* factory() const { return parser_->factory(); }
      83             :   AstValueFactory* ast_value_factory() const {
      84             :     return parser_->ast_value_factory();
      85             :   }
      86             : 
      87             :   std::vector<void*>* pointer_buffer() { return parser_->pointer_buffer(); }
      88             : 
      89      194993 :   Zone* zone() const { return parser_->zone(); }
      90     9349014 :   Scope* scope() const { return parser_->scope(); }
      91             : 
      92             :   Parser* const parser_;
      93             :   const DeclarationDescriptor* descriptor_;
      94             :   ZonePtrList<const AstRawString>* names_;
      95             :   const int initializer_position_;
      96             :   const bool has_initializer_;
      97             :   const bool declares_parameter_containing_sloppy_eval_;
      98             : 
      99    18882786 :   DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()
     100             : };
     101             : 
     102     9370762 : void Parser::InitializeVariables(
     103     7362705 :     ScopedPtrList<Statement>* statements,
     104             :     const DeclarationDescriptor* declaration_descriptor,
     105             :     const DeclarationParsingResult::Declaration* declaration,
     106             :     ZonePtrList<const AstRawString>* names) {
     107    18741513 :   if (has_error()) return;
     108             :   PatternRewriter::InitializeVariables(this, declaration_descriptor,
     109     9316678 :                                        declaration, names);
     110             : 
     111     9316795 :   if (declaration->initializer) {
     112     7362879 :     int pos = declaration->value_beg_position;
     113     7362879 :     if (pos == kNoSourcePosition) {
     114      353599 :       pos = declaration->initializer_position;
     115             :     }
     116             :     Assignment* assignment = factory()->NewAssignment(
     117     7362879 :         Token::INIT, declaration->pattern, declaration->initializer, pos);
     118     7362762 :     statements->Add(factory()->NewExpressionStatement(assignment, pos));
     119             :   }
     120             : }
     121             : 
     122     9316654 : void PatternRewriter::InitializeVariables(
     123             :     Parser* parser, const DeclarationDescriptor* declaration_descriptor,
     124             :     const Parser::DeclarationParsingResult::Declaration* declaration,
     125             :     ZonePtrList<const AstRawString>* names) {
     126             :   PatternRewriter rewriter(parser, declaration_descriptor, names,
     127             :                            declaration->initializer != nullptr,
     128             :                            declaration->initializer_position,
     129     9372423 :                            declaration_descriptor->kind == PARAMETER_VARIABLE &&
     130     9372423 :                                parser->scope()->is_block_scope());
     131             : 
     132     9316654 :   rewriter.RecurseIntoSubpattern(declaration->pattern);
     133     9316814 : }
     134             : 
     135    19216913 : void PatternRewriter::VisitVariableProxy(VariableProxy* proxy) {
     136             :   DCHECK_NOT_NULL(descriptor_);
     137             : 
     138        1265 :   Scope* target_scope = scope();
     139     9348559 :   if (declares_parameter_containing_sloppy_eval_) {
     140             :     // When an extra declaration scope needs to be inserted to account for
     141             :     // a sloppy eval in a default parameter or function body, the parameter
     142             :     // needs to be declared in the function's scope, not in the varblock
     143             :     // scope which will be used for the initializer expression.
     144             :     DCHECK_EQ(descriptor_->mode, VariableMode::kLet);
     145             :     target_scope = target_scope->outer_scope();
     146             :   }
     147             :   Scope* var_init_scope = scope();
     148             : 
     149             : #ifdef DEBUG
     150             :   // Calculate the scope we expect the variable to be declared in, for DCHECKs.
     151             :   Scope* expected_declaration_scope =
     152             :       declares_parameter_containing_sloppy_eval_
     153             :           ? scope()->outer_scope()
     154             :           : (IsLexicalVariableMode(descriptor_->mode)
     155             :                  ? scope()
     156             :                  : scope()->GetDeclarationScope());
     157             : #endif
     158             : 
     159             :   // Declare variable.
     160             :   // Note that we *always* must treat the initial value via a separate init
     161             :   // assignment for variables and constants because the value must be assigned
     162             :   // when the variable is encountered in the source. But the variable/constant
     163             :   // is declared (and set to 'undefined') upon entering the function within
     164             :   // which the variable or constant is declared. Only function variables have
     165             :   // an initial value in the declaration (because they are initialized upon
     166             :   // entering the function).
     167             : 
     168             :   // A declaration of the form:
     169             :   //
     170             :   //    var v = x;
     171             :   //
     172             :   // is syntactic sugar for:
     173             :   //
     174             :   //    var v; v = x;
     175             :   //
     176             :   // In particular, we need to re-lookup 'v' if it may be a different 'v' than
     177             :   // the 'v' in the declaration (e.g., if we are inside a 'with' statement or
     178             :   // 'catch' block).
     179             :   //
     180             :   // For 'let' and 'const' declared variables the initialization always assigns
     181             :   // to the declared variable. But for var initializations that are declared in
     182             :   // a different scope we need to do a new lookup, so clone the variable for the
     183             :   // declaration and don't consider the original variable resolved.
     184    15372672 :   if (has_initializer_ && descriptor_->mode == VariableMode::kVar &&
     185             :       !var_init_scope->is_declaration_scope()) {
     186             :     DCHECK_EQ(target_scope->GetDeclarationScope(), expected_declaration_scope);
     187             :     // The cloned variable is not added to the unresolved list of the target
     188             :     // scope, as it is about to be resolved by the declaration. The original
     189             :     // variable will be left unresolved for now.
     190      382296 :     var_init_scope->AddUnresolved(proxy);
     191             :     proxy = factory()->NewVariableProxy(proxy->raw_name(), NORMAL_VARIABLE,
     192      764594 :                                         proxy->position());
     193             :   }
     194             : 
     195             :   parser_->DeclareVariable(
     196             :       proxy, descriptor_->kind, descriptor_->mode,
     197     9348603 :       Variable::DefaultInitializationFlag(descriptor_->mode), target_scope,
     198    18697206 :       descriptor_->declaration_pos);
     199             : 
     200    18697308 :   if (parser_->has_error()) return;
     201     9291064 :   Variable* var = proxy->var();
     202             :   DCHECK_NOT_NULL(var);
     203             :   DCHECK(proxy->is_resolved());
     204             :   DCHECK_EQ(var->scope(), expected_declaration_scope);
     205             :   DCHECK_NE(initializer_position_, kNoSourcePosition);
     206     9291064 :   var->set_initializer_position(initializer_position_);
     207             : 
     208     9291064 :   if (var->scope()->num_var() > kMaxNumFunctionLocals) {
     209           0 :     parser_->ReportMessage(MessageTemplate::kTooManyVariables);
     210           0 :     return;
     211             :   }
     212     9291064 :   if (names_) {
     213      194993 :     names_->Add(proxy->raw_name(), zone());
     214             :   }
     215             : }
     216             : 
     217             : // When an extra declaration scope needs to be inserted to account for
     218             : // a sloppy eval in a default parameter or function body, the expressions
     219             : // needs to be in that new inner scope which was added after initial
     220             : // parsing.
     221       22899 : void PatternRewriter::RewriteParameterScopes(Expression* expr) {
     222       22444 :   if (declares_parameter_containing_sloppy_eval_) {
     223         455 :     ReparentExpressionScope(parser_->stack_limit(), expr, scope());
     224             :   }
     225       22444 : }
     226             : 
     227       47535 : void PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) {
     228      161609 :   for (ObjectLiteralProperty* property : *pattern->properties()) {
     229       66538 :     Expression* key = property->key();
     230       66538 :     if (!key->IsLiteral()) {
     231             :       // Computed property names contain expressions which might require
     232             :       // scope rewriting.
     233        2638 :       RewriteParameterScopes(key);
     234             :     }
     235             :     RecurseIntoSubpattern(property->value());
     236             :   }
     237       47536 : }
     238             : 
     239       22749 : void PatternRewriter::VisitArrayLiteral(ArrayLiteral* node) {
     240       81434 :   for (Expression* value : *node->values()) {
     241       35936 :     if (value->IsTheHoleLiteral()) continue;
     242             :     RecurseIntoSubpattern(value);
     243             :   }
     244       22749 : }
     245             : 
     246       39612 : void PatternRewriter::VisitAssignment(Assignment* node) {
     247             :   DCHECK_EQ(Token::ASSIGN, node->op());
     248             : 
     249             :   // Initializer may have been parsed in the wrong scope.
     250       19806 :   RewriteParameterScopes(node->value());
     251             : 
     252             :   RecurseIntoSubpattern(node->target());
     253       19807 : }
     254             : 
     255        2684 : void PatternRewriter::VisitSpread(Spread* node) {
     256             :   RecurseIntoSubpattern(node->expression());
     257        2684 : }
     258             : 
     259             : // =============== UNREACHABLE =============================
     260             : 
     261             : #define NOT_A_PATTERN(Node) \
     262             :   void PatternRewriter::Visit##Node(v8::internal::Node*) { UNREACHABLE(); }
     263             : 
     264           0 : NOT_A_PATTERN(BinaryOperation)
     265           0 : NOT_A_PATTERN(NaryOperation)
     266           0 : NOT_A_PATTERN(Block)
     267           0 : NOT_A_PATTERN(BreakStatement)
     268           0 : NOT_A_PATTERN(Call)
     269           0 : NOT_A_PATTERN(CallNew)
     270           0 : NOT_A_PATTERN(CallRuntime)
     271           0 : NOT_A_PATTERN(ClassLiteral)
     272           0 : NOT_A_PATTERN(CompareOperation)
     273           0 : NOT_A_PATTERN(CompoundAssignment)
     274           0 : NOT_A_PATTERN(Conditional)
     275           0 : NOT_A_PATTERN(ContinueStatement)
     276           0 : NOT_A_PATTERN(CountOperation)
     277           0 : NOT_A_PATTERN(DebuggerStatement)
     278           0 : NOT_A_PATTERN(DoExpression)
     279           0 : NOT_A_PATTERN(DoWhileStatement)
     280           0 : NOT_A_PATTERN(EmptyStatement)
     281           0 : NOT_A_PATTERN(EmptyParentheses)
     282           0 : NOT_A_PATTERN(ExpressionStatement)
     283           0 : NOT_A_PATTERN(ForInStatement)
     284           0 : NOT_A_PATTERN(ForOfStatement)
     285           0 : NOT_A_PATTERN(ForStatement)
     286           0 : NOT_A_PATTERN(FunctionDeclaration)
     287           0 : NOT_A_PATTERN(FunctionLiteral)
     288           0 : NOT_A_PATTERN(GetTemplateObject)
     289           0 : NOT_A_PATTERN(IfStatement)
     290           0 : NOT_A_PATTERN(ImportCallExpression)
     291           0 : NOT_A_PATTERN(Literal)
     292           0 : NOT_A_PATTERN(NativeFunctionLiteral)
     293           0 : NOT_A_PATTERN(Property)
     294           0 : NOT_A_PATTERN(RegExpLiteral)
     295           0 : NOT_A_PATTERN(ResolvedProperty)
     296           0 : NOT_A_PATTERN(ReturnStatement)
     297           0 : NOT_A_PATTERN(SloppyBlockFunctionStatement)
     298           0 : NOT_A_PATTERN(StoreInArrayLiteral)
     299           0 : NOT_A_PATTERN(SuperPropertyReference)
     300           0 : NOT_A_PATTERN(SuperCallReference)
     301           0 : NOT_A_PATTERN(SwitchStatement)
     302           0 : NOT_A_PATTERN(TemplateLiteral)
     303           0 : NOT_A_PATTERN(ThisFunction)
     304           0 : NOT_A_PATTERN(Throw)
     305           0 : NOT_A_PATTERN(TryCatchStatement)
     306           0 : NOT_A_PATTERN(TryFinallyStatement)
     307           0 : NOT_A_PATTERN(UnaryOperation)
     308           0 : NOT_A_PATTERN(VariableDeclaration)
     309           0 : NOT_A_PATTERN(WhileStatement)
     310           0 : NOT_A_PATTERN(WithStatement)
     311           0 : NOT_A_PATTERN(Yield)
     312           0 : NOT_A_PATTERN(YieldStar)
     313           0 : NOT_A_PATTERN(Await)
     314           0 : NOT_A_PATTERN(InitializeClassMembersStatement)
     315             : 
     316             : #undef NOT_A_PATTERN
     317             : }  // namespace internal
     318      183867 : }  // namespace v8

Generated by: LCOV version 1.10