| OLD | NEW | 
|---|
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "src/ast.h" | 5 #include "src/ast.h" | 
| 6 #include "src/parser.h" | 6 #include "src/parser.h" | 
| 7 #include "src/pattern-rewriter.h" |  | 
| 8 | 7 | 
| 9 namespace v8 { | 8 namespace v8 { | 
| 10 | 9 | 
| 11 namespace internal { | 10 namespace internal { | 
| 12 | 11 | 
| 13 | 12 | 
| 14 bool Parser::PatternRewriter::IsSingleVariableBinding() const { | 13 void Parser::PatternRewriter::DeclareAndInitializeVariables( | 
| 15   return pattern_->IsVariableProxy(); | 14     Block* block, const DeclarationDescriptor* declaration_descriptor, | 
| 16 } | 15     const DeclarationParsingResult::Declaration* declaration, | 
|  | 16     ZoneList<const AstRawString*>* names, bool* ok) { | 
|  | 17   PatternRewriter rewriter; | 
| 17 | 18 | 
|  | 19   rewriter.pattern_ = declaration->pattern; | 
|  | 20   rewriter.initializer_position_ = declaration->initializer_position; | 
|  | 21   rewriter.block_ = block; | 
|  | 22   rewriter.descriptor_ = declaration_descriptor; | 
|  | 23   rewriter.names_ = names; | 
|  | 24   rewriter.ok_ = ok; | 
| 18 | 25 | 
| 19 const AstRawString* Parser::PatternRewriter::SingleName() const { | 26   rewriter.RecurseIntoSubpattern(rewriter.pattern_, declaration->initializer); | 
| 20   DCHECK(IsSingleVariableBinding()); |  | 
| 21   return pattern_->AsVariableProxy()->raw_name(); |  | 
| 22 } |  | 
| 23 |  | 
| 24 |  | 
| 25 void Parser::PatternRewriter::DeclareAndInitializeVariables(Expression* value, |  | 
| 26                                                             int* nvars, |  | 
| 27                                                             bool* ok) { |  | 
| 28   ok_ = ok; |  | 
| 29   nvars_ = nvars; |  | 
| 30   RecurseIntoSubpattern(pattern_, value); |  | 
| 31   ok_ = nullptr; |  | 
| 32   nvars_ = nullptr; |  | 
| 33 } | 27 } | 
| 34 | 28 | 
| 35 | 29 | 
| 36 void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { | 30 void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) { | 
| 37   Expression* value = current_value_; | 31   Expression* value = current_value_; | 
| 38   decl_->scope->RemoveUnresolved(pattern->AsVariableProxy()); | 32   descriptor_->scope->RemoveUnresolved(pattern->AsVariableProxy()); | 
| 39 | 33 | 
| 40   // Declare variable. | 34   // Declare variable. | 
| 41   // Note that we *always* must treat the initial value via a separate init | 35   // Note that we *always* must treat the initial value via a separate init | 
| 42   // assignment for variables and constants because the value must be assigned | 36   // assignment for variables and constants because the value must be assigned | 
| 43   // when the variable is encountered in the source. But the variable/constant | 37   // when the variable is encountered in the source. But the variable/constant | 
| 44   // is declared (and set to 'undefined') upon entering the function within | 38   // is declared (and set to 'undefined') upon entering the function within | 
| 45   // which the variable or constant is declared. Only function variables have | 39   // which the variable or constant is declared. Only function variables have | 
| 46   // an initial value in the declaration (because they are initialized upon | 40   // an initial value in the declaration (because they are initialized upon | 
| 47   // entering the function). | 41   // entering the function). | 
| 48   // | 42   // | 
| 49   // If we have a legacy const declaration, in an inner scope, the proxy | 43   // If we have a legacy const declaration, in an inner scope, the proxy | 
| 50   // is always bound to the declared variable (independent of possibly | 44   // is always bound to the declared variable (independent of possibly | 
| 51   // surrounding 'with' statements). | 45   // surrounding 'with' statements). | 
| 52   // For let/const declarations in harmony mode, we can also immediately | 46   // For let/const declarations in harmony mode, we can also immediately | 
| 53   // pre-resolve the proxy because it resides in the same scope as the | 47   // pre-resolve the proxy because it resides in the same scope as the | 
| 54   // declaration. | 48   // declaration. | 
| 55   Parser* parser = decl_->parser; | 49   Parser* parser = descriptor_->parser; | 
| 56   const AstRawString* name = pattern->raw_name(); | 50   const AstRawString* name = pattern->raw_name(); | 
| 57   VariableProxy* proxy = parser->NewUnresolved(name, decl_->mode); | 51   VariableProxy* proxy = parser->NewUnresolved(name, descriptor_->mode); | 
| 58   Declaration* declaration = factory()->NewVariableDeclaration( | 52   Declaration* declaration = factory()->NewVariableDeclaration( | 
| 59       proxy, decl_->mode, decl_->scope, decl_->pos); | 53       proxy, descriptor_->mode, descriptor_->scope, descriptor_->pos); | 
| 60   Variable* var = parser->Declare(declaration, decl_->mode != VAR, ok_); | 54   Variable* var = parser->Declare(declaration, descriptor_->mode != VAR, ok_); | 
| 61   if (!*ok_) return; | 55   if (!*ok_) return; | 
| 62   DCHECK_NOT_NULL(var); | 56   DCHECK_NOT_NULL(var); | 
| 63   DCHECK(!proxy->is_resolved() || proxy->var() == var); | 57   DCHECK(!proxy->is_resolved() || proxy->var() == var); | 
| 64   var->set_initializer_position(decl_->initializer_position); | 58   var->set_initializer_position(initializer_position_); | 
| 65   (*nvars_)++; | 59 | 
| 66   if (decl_->declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) { | 60   DCHECK(initializer_position_ != RelocInfo::kNoPosition); | 
|  | 61 | 
|  | 62   if (descriptor_->declaration_scope->num_var_or_const() > | 
|  | 63       kMaxNumFunctionLocals) { | 
| 67     parser->ReportMessage("too_many_variables"); | 64     parser->ReportMessage("too_many_variables"); | 
| 68     *ok_ = false; | 65     *ok_ = false; | 
| 69     return; | 66     return; | 
| 70   } | 67   } | 
| 71   if (decl_->names) { | 68   if (names_) { | 
| 72     decl_->names->Add(name, zone()); | 69     names_->Add(name, zone()); | 
| 73   } | 70   } | 
| 74 | 71 | 
| 75   // Initialize variables if needed. A | 72   // Initialize variables if needed. A | 
| 76   // declaration of the form: | 73   // declaration of the form: | 
| 77   // | 74   // | 
| 78   //    var v = x; | 75   //    var v = x; | 
| 79   // | 76   // | 
| 80   // is syntactic sugar for: | 77   // is syntactic sugar for: | 
| 81   // | 78   // | 
| 82   //    var v; v = x; | 79   //    var v; v = x; | 
| 83   // | 80   // | 
| 84   // In particular, we need to re-lookup 'v' (in scope_, not | 81   // In particular, we need to re-lookup 'v' (in scope_, not | 
| 85   // declaration_scope) as it may be a different 'v' than the 'v' in the | 82   // declaration_scope) as it may be a different 'v' than the 'v' in the | 
| 86   // declaration (e.g., if we are inside a 'with' statement or 'catch' | 83   // declaration (e.g., if we are inside a 'with' statement or 'catch' | 
| 87   // block). | 84   // block). | 
| 88   // | 85   // | 
| 89   // However, note that const declarations are different! A const | 86   // However, note that const declarations are different! A const | 
| 90   // declaration of the form: | 87   // declaration of the form: | 
| 91   // | 88   // | 
| 92   //   const c = x; | 89   //   const c = x; | 
| 93   // | 90   // | 
| 94   // is *not* syntactic sugar for: | 91   // is *not* syntactic sugar for: | 
| 95   // | 92   // | 
| 96   //   const c; c = x; | 93   //   const c; c = x; | 
| 97   // | 94   // | 
| 98   // The "variable" c initialized to x is the same as the declared | 95   // The "variable" c initialized to x is the same as the declared | 
| 99   // one - there is no re-lookup (see the last parameter of the | 96   // one - there is no re-lookup (see the last parameter of the | 
| 100   // Declare() call above). | 97   // Declare() call above). | 
| 101   Scope* initialization_scope = | 98   Scope* initialization_scope = descriptor_->is_const | 
| 102       decl_->is_const ? decl_->declaration_scope : decl_->scope; | 99                                     ? descriptor_->declaration_scope | 
|  | 100                                     : descriptor_->scope; | 
| 103 | 101 | 
| 104 | 102 | 
| 105   // Global variable declarations must be compiled in a specific | 103   // Global variable declarations must be compiled in a specific | 
| 106   // way. When the script containing the global variable declaration | 104   // way. When the script containing the global variable declaration | 
| 107   // is entered, the global variable must be declared, so that if it | 105   // is entered, the global variable must be declared, so that if it | 
| 108   // doesn't exist (on the global object itself, see ES5 errata) it | 106   // doesn't exist (on the global object itself, see ES5 errata) it | 
| 109   // gets created with an initial undefined value. This is handled | 107   // gets created with an initial undefined value. This is handled | 
| 110   // by the declarations part of the function representing the | 108   // by the declarations part of the function representing the | 
| 111   // top-level global code; see Runtime::DeclareGlobalVariable. If | 109   // top-level global code; see Runtime::DeclareGlobalVariable. If | 
| 112   // it already exists (in the object or in a prototype), it is | 110   // it already exists (in the object or in a prototype), it is | 
| 113   // *not* touched until the variable declaration statement is | 111   // *not* touched until the variable declaration statement is | 
| 114   // executed. | 112   // executed. | 
| 115   // | 113   // | 
| 116   // Executing the variable declaration statement will always | 114   // Executing the variable declaration statement will always | 
| 117   // guarantee to give the global object an own property. | 115   // guarantee to give the global object an own property. | 
| 118   // This way, global variable declarations can shadow | 116   // This way, global variable declarations can shadow | 
| 119   // properties in the prototype chain, but only after the variable | 117   // properties in the prototype chain, but only after the variable | 
| 120   // declaration statement has been executed. This is important in | 118   // declaration statement has been executed. This is important in | 
| 121   // browsers where the global object (window) has lots of | 119   // browsers where the global object (window) has lots of | 
| 122   // properties defined in prototype objects. | 120   // properties defined in prototype objects. | 
| 123   if (initialization_scope->is_script_scope() && | 121   if (initialization_scope->is_script_scope() && | 
| 124       !IsLexicalVariableMode(decl_->mode)) { | 122       !IsLexicalVariableMode(descriptor_->mode)) { | 
| 125     // Compute the arguments for the runtime | 123     // Compute the arguments for the runtime | 
| 126     // call.test-parsing/InitializedDeclarationsInStrictForOfError | 124     // call.test-parsing/InitializedDeclarationsInStrictForOfError | 
| 127     ZoneList<Expression*>* arguments = | 125     ZoneList<Expression*>* arguments = | 
| 128         new (zone()) ZoneList<Expression*>(3, zone()); | 126         new (zone()) ZoneList<Expression*>(3, zone()); | 
| 129     // We have at least 1 parameter. | 127     // We have at least 1 parameter. | 
| 130     arguments->Add(factory()->NewStringLiteral(name, decl_->pos), zone()); | 128     arguments->Add(factory()->NewStringLiteral(name, descriptor_->pos), zone()); | 
| 131     CallRuntime* initialize; | 129     CallRuntime* initialize; | 
| 132 | 130 | 
| 133     if (decl_->is_const) { | 131     if (descriptor_->is_const) { | 
| 134       arguments->Add(value, zone()); | 132       arguments->Add(value, zone()); | 
| 135       value = NULL;  // zap the value to avoid the unnecessary assignment | 133       value = NULL;  // zap the value to avoid the unnecessary assignment | 
| 136 | 134 | 
| 137       // Construct the call to Runtime_InitializeConstGlobal | 135       // Construct the call to Runtime_InitializeConstGlobal | 
| 138       // and add it to the initialization statement block. | 136       // and add it to the initialization statement block. | 
| 139       // Note that the function does different things depending on | 137       // Note that the function does different things depending on | 
| 140       // the number of arguments (1 or 2). | 138       // the number of arguments (1 or 2). | 
| 141       initialize = factory()->NewCallRuntime( | 139       initialize = factory()->NewCallRuntime( | 
| 142           ast_value_factory()->initialize_const_global_string(), | 140           ast_value_factory()->initialize_const_global_string(), | 
| 143           Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments, | 141           Runtime::FunctionForId(Runtime::kInitializeConstGlobal), arguments, | 
| 144           decl_->pos); | 142           descriptor_->pos); | 
| 145     } else { | 143     } else { | 
| 146       // Add language mode. | 144       // Add language mode. | 
| 147       // We may want to pass singleton to avoid Literal allocations. | 145       // We may want to pass singleton to avoid Literal allocations. | 
| 148       LanguageMode language_mode = initialization_scope->language_mode(); | 146       LanguageMode language_mode = initialization_scope->language_mode(); | 
| 149       arguments->Add(factory()->NewNumberLiteral(language_mode, decl_->pos), | 147       arguments->Add( | 
| 150                      zone()); | 148           factory()->NewNumberLiteral(language_mode, descriptor_->pos), zone()); | 
| 151 | 149 | 
| 152       // Be careful not to assign a value to the global variable if | 150       // Be careful not to assign a value to the global variable if | 
| 153       // we're in a with. The initialization value should not | 151       // we're in a with. The initialization value should not | 
| 154       // necessarily be stored in the global object in that case, | 152       // necessarily be stored in the global object in that case, | 
| 155       // which is why we need to generate a separate assignment node. | 153       // which is why we need to generate a separate assignment node. | 
| 156       if (value != NULL && !inside_with()) { | 154       if (value != NULL && !inside_with()) { | 
| 157         arguments->Add(value, zone()); | 155         arguments->Add(value, zone()); | 
| 158         value = NULL;  // zap the value to avoid the unnecessary assignment | 156         value = NULL;  // zap the value to avoid the unnecessary assignment | 
| 159         // Construct the call to Runtime_InitializeVarGlobal | 157         // Construct the call to Runtime_InitializeVarGlobal | 
| 160         // and add it to the initialization statement block. | 158         // and add it to the initialization statement block. | 
| 161         initialize = factory()->NewCallRuntime( | 159         initialize = factory()->NewCallRuntime( | 
| 162             ast_value_factory()->initialize_var_global_string(), | 160             ast_value_factory()->initialize_var_global_string(), | 
| 163             Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments, | 161             Runtime::FunctionForId(Runtime::kInitializeVarGlobal), arguments, | 
| 164             decl_->pos); | 162             descriptor_->pos); | 
| 165       } else { | 163       } else { | 
| 166         initialize = NULL; | 164         initialize = NULL; | 
| 167       } | 165       } | 
| 168     } | 166     } | 
| 169 | 167 | 
| 170     if (initialize != NULL) { | 168     if (initialize != NULL) { | 
| 171       decl_->block->AddStatement( | 169       block_->AddStatement( | 
| 172           factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition), | 170           factory()->NewExpressionStatement(initialize, RelocInfo::kNoPosition), | 
| 173           zone()); | 171           zone()); | 
| 174     } | 172     } | 
| 175   } else if (decl_->needs_init) { | 173   } else if (value != nullptr && (descriptor_->needs_init || | 
|  | 174                                   IsLexicalVariableMode(descriptor_->mode))) { | 
| 176     // Constant initializations always assign to the declared constant which | 175     // Constant initializations always assign to the declared constant which | 
| 177     // is always at the function scope level. This is only relevant for | 176     // is always at the function scope level. This is only relevant for | 
| 178     // dynamically looked-up variables and constants (the | 177     // dynamically looked-up variables and constants (the | 
| 179     // start context for constant lookups is always the function context, | 178     // start context for constant lookups is always the function context, | 
| 180     // while it is the top context for var declared variables). Sigh... | 179     // while it is the top context for var declared variables). Sigh... | 
| 181     // For 'let' and 'const' declared variables in harmony mode the | 180     // For 'let' and 'const' declared variables in harmony mode the | 
| 182     // initialization also always assigns to the declared variable. | 181     // initialization also always assigns to the declared variable. | 
| 183     DCHECK_NOT_NULL(proxy); | 182     DCHECK_NOT_NULL(proxy); | 
| 184     DCHECK_NOT_NULL(proxy->var()); | 183     DCHECK_NOT_NULL(proxy->var()); | 
| 185     DCHECK_NOT_NULL(value); | 184     DCHECK_NOT_NULL(value); | 
| 186     Assignment* assignment = | 185     Assignment* assignment = factory()->NewAssignment( | 
| 187         factory()->NewAssignment(decl_->init_op, proxy, value, decl_->pos); | 186         descriptor_->init_op, proxy, value, descriptor_->pos); | 
| 188     decl_->block->AddStatement( | 187     block_->AddStatement( | 
| 189         factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), | 188         factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), | 
| 190         zone()); | 189         zone()); | 
| 191     value = NULL; | 190     value = NULL; | 
| 192   } | 191   } | 
| 193 | 192 | 
| 194   // Add an assignment node to the initialization statement block if we still | 193   // Add an assignment node to the initialization statement block if we still | 
| 195   // have a pending initialization value. | 194   // have a pending initialization value. | 
| 196   if (value != NULL) { | 195   if (value != NULL) { | 
| 197     DCHECK(decl_->mode == VAR); | 196     DCHECK(descriptor_->mode == VAR); | 
| 198     // 'var' initializations are simply assignments (with all the consequences | 197     // 'var' initializations are simply assignments (with all the consequences | 
| 199     // if they are inside a 'with' statement - they may change a 'with' object | 198     // if they are inside a 'with' statement - they may change a 'with' object | 
| 200     // property). | 199     // property). | 
| 201     VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name); | 200     VariableProxy* proxy = initialization_scope->NewUnresolved(factory(), name); | 
| 202     Assignment* assignment = | 201     Assignment* assignment = factory()->NewAssignment( | 
| 203         factory()->NewAssignment(decl_->init_op, proxy, value, decl_->pos); | 202         descriptor_->init_op, proxy, value, descriptor_->pos); | 
| 204     decl_->block->AddStatement( | 203     block_->AddStatement( | 
| 205         factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), | 204         factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), | 
| 206         zone()); | 205         zone()); | 
| 207   } | 206   } | 
| 208 } | 207 } | 
| 209 | 208 | 
| 210 | 209 | 
| 211 void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) { | 210 void Parser::PatternRewriter::VisitObjectLiteral(ObjectLiteral* pattern) { | 
| 212   auto temp = decl_->declaration_scope->NewTemporary( | 211   auto temp = descriptor_->declaration_scope->NewTemporary( | 
| 213       ast_value_factory()->empty_string()); | 212       ast_value_factory()->empty_string()); | 
| 214   auto assignment = | 213   auto assignment = | 
| 215       factory()->NewAssignment(Token::ASSIGN, factory()->NewVariableProxy(temp), | 214       factory()->NewAssignment(Token::ASSIGN, factory()->NewVariableProxy(temp), | 
| 216                                current_value_, RelocInfo::kNoPosition); | 215                                current_value_, RelocInfo::kNoPosition); | 
| 217   decl_->block->AddStatement( | 216   block_->AddStatement( | 
| 218       factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), | 217       factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), | 
| 219       zone()); | 218       zone()); | 
| 220   for (ObjectLiteralProperty* property : *pattern->properties()) { | 219   for (ObjectLiteralProperty* property : *pattern->properties()) { | 
| 221     // TODO(dslomov): computed property names. | 220     // TODO(dslomov): computed property names. | 
| 222     RecurseIntoSubpattern( | 221     RecurseIntoSubpattern( | 
| 223         property->value(), | 222         property->value(), | 
| 224         factory()->NewProperty(factory()->NewVariableProxy(temp), | 223         factory()->NewProperty(factory()->NewVariableProxy(temp), | 
| 225                                property->key(), RelocInfo::kNoPosition)); | 224                                property->key(), RelocInfo::kNoPosition)); | 
| 226   } | 225   } | 
| 227 } | 226 } | 
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 288 NOT_A_PATTERN(TryFinallyStatement) | 287 NOT_A_PATTERN(TryFinallyStatement) | 
| 289 NOT_A_PATTERN(UnaryOperation) | 288 NOT_A_PATTERN(UnaryOperation) | 
| 290 NOT_A_PATTERN(VariableDeclaration) | 289 NOT_A_PATTERN(VariableDeclaration) | 
| 291 NOT_A_PATTERN(WhileStatement) | 290 NOT_A_PATTERN(WhileStatement) | 
| 292 NOT_A_PATTERN(WithStatement) | 291 NOT_A_PATTERN(WithStatement) | 
| 293 NOT_A_PATTERN(Yield) | 292 NOT_A_PATTERN(Yield) | 
| 294 | 293 | 
| 295 #undef NOT_A_PATTERN | 294 #undef NOT_A_PATTERN | 
| 296 } | 295 } | 
| 297 }  // namespace v8::internal | 296 }  // namespace v8::internal | 
| OLD | NEW | 
|---|