| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/api.h" | 7 #include "src/api.h" |
| 8 #include "src/ast.h" | 8 #include "src/ast.h" |
| 9 #include "src/bailout-reason.h" | 9 #include "src/bailout-reason.h" |
| 10 #include "src/base/platform/platform.h" | 10 #include "src/base/platform/platform.h" |
| (...skipping 2138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2149 // We mark the block as initializer block because we don't want the | 2149 // We mark the block as initializer block because we don't want the |
| 2150 // rewriter to add a '.result' assignment to such a block (to get compliant | 2150 // rewriter to add a '.result' assignment to such a block (to get compliant |
| 2151 // behavior for code such as print(eval('var x = 7')), and for cosmetic | 2151 // behavior for code such as print(eval('var x = 7')), and for cosmetic |
| 2152 // reasons when pretty-printing. Also, unless an assignment (initialization) | 2152 // reasons when pretty-printing. Also, unless an assignment (initialization) |
| 2153 // is inside an initializer block, it is ignored. | 2153 // is inside an initializer block, it is ignored. |
| 2154 // | 2154 // |
| 2155 // Create new block with one expected declaration. | 2155 // Create new block with one expected declaration. |
| 2156 Block* block = factory()->NewBlock(NULL, 1, true, pos); | 2156 Block* block = factory()->NewBlock(NULL, 1, true, pos); |
| 2157 int nvars = 0; // the number of variables declared | 2157 int nvars = 0; // the number of variables declared |
| 2158 const AstRawString* name = NULL; | 2158 const AstRawString* name = NULL; |
| 2159 bool is_for_iteration_variable; | |
| 2160 do { | 2159 do { |
| 2161 if (fni_ != NULL) fni_->Enter(); | 2160 if (fni_ != NULL) fni_->Enter(); |
| 2162 | 2161 |
| 2163 // Parse variable name. | 2162 // Parse variable name. |
| 2164 if (nvars > 0) Consume(Token::COMMA); | 2163 if (nvars > 0) Consume(Token::COMMA); |
| 2165 name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); | 2164 name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); |
| 2166 if (fni_ != NULL) fni_->PushVariableName(name); | 2165 if (fni_ != NULL) fni_->PushVariableName(name); |
| 2167 | 2166 |
| 2168 // Declare variable. | 2167 // Declare variable. |
| 2169 // Note that we *always* must treat the initial value via a separate init | 2168 // Note that we *always* must treat the initial value via a separate init |
| 2170 // assignment for variables and constants because the value must be assigned | 2169 // assignment for variables and constants because the value must be assigned |
| 2171 // when the variable is encountered in the source. But the variable/constant | 2170 // when the variable is encountered in the source. But the variable/constant |
| 2172 // is declared (and set to 'undefined') upon entering the function within | 2171 // is declared (and set to 'undefined') upon entering the function within |
| 2173 // which the variable or constant is declared. Only function variables have | 2172 // which the variable or constant is declared. Only function variables have |
| 2174 // an initial value in the declaration (because they are initialized upon | 2173 // an initial value in the declaration (because they are initialized upon |
| 2175 // entering the function). | 2174 // entering the function). |
| 2176 // | 2175 // |
| 2177 // If we have a const declaration, in an inner scope, the proxy is always | 2176 // If we have a const declaration, in an inner scope, the proxy is always |
| 2178 // bound to the declared variable (independent of possibly surrounding with | 2177 // bound to the declared variable (independent of possibly surrounding with |
| 2179 // statements). | 2178 // statements). |
| 2180 // For let/const declarations in harmony mode, we can also immediately | 2179 // For let/const declarations in harmony mode, we can also immediately |
| 2181 // pre-resolve the proxy because it resides in the same scope as the | 2180 // pre-resolve the proxy because it resides in the same scope as the |
| 2182 // declaration. | 2181 // declaration. |
| 2183 is_for_iteration_variable = | |
| 2184 var_context == kForStatement && | |
| 2185 (peek() == Token::IN || PeekContextualKeyword(CStrVector("of"))); | |
| 2186 if (is_for_iteration_variable && mode == CONST) { | |
| 2187 needs_init = false; | |
| 2188 } | |
| 2189 | |
| 2190 Interface* interface = | 2182 Interface* interface = |
| 2191 is_const ? Interface::NewConst() : Interface::NewValue(); | 2183 is_const ? Interface::NewConst() : Interface::NewValue(); |
| 2192 VariableProxy* proxy = NewUnresolved(name, mode, interface); | 2184 VariableProxy* proxy = NewUnresolved(name, mode, interface); |
| 2193 Declaration* declaration = | 2185 Declaration* declaration = |
| 2194 factory()->NewVariableDeclaration(proxy, mode, scope_, pos); | 2186 factory()->NewVariableDeclaration(proxy, mode, scope_, pos); |
| 2195 Declare(declaration, mode != VAR, CHECK_OK); | 2187 Declare(declaration, mode != VAR, CHECK_OK); |
| 2196 nvars++; | 2188 nvars++; |
| 2197 if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) { | 2189 if (declaration_scope->num_var_or_const() > kMaxNumFunctionLocals) { |
| 2198 ReportMessage("too_many_variables"); | 2190 ReportMessage("too_many_variables"); |
| 2199 *ok = false; | 2191 *ok = false; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2225 // const c; c = x; | 2217 // const c; c = x; |
| 2226 // | 2218 // |
| 2227 // The "variable" c initialized to x is the same as the declared | 2219 // The "variable" c initialized to x is the same as the declared |
| 2228 // one - there is no re-lookup (see the last parameter of the | 2220 // one - there is no re-lookup (see the last parameter of the |
| 2229 // Declare() call above). | 2221 // Declare() call above). |
| 2230 | 2222 |
| 2231 Scope* initialization_scope = is_const ? declaration_scope : scope_; | 2223 Scope* initialization_scope = is_const ? declaration_scope : scope_; |
| 2232 Expression* value = NULL; | 2224 Expression* value = NULL; |
| 2233 int pos = -1; | 2225 int pos = -1; |
| 2234 // Harmony consts have non-optional initializers. | 2226 // Harmony consts have non-optional initializers. |
| 2235 if (peek() == Token::ASSIGN || | 2227 if (peek() == Token::ASSIGN || mode == CONST) { |
| 2236 (mode == CONST && !is_for_iteration_variable)) { | |
| 2237 Expect(Token::ASSIGN, CHECK_OK); | 2228 Expect(Token::ASSIGN, CHECK_OK); |
| 2238 pos = position(); | 2229 pos = position(); |
| 2239 value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK); | 2230 value = ParseAssignmentExpression(var_context != kForStatement, CHECK_OK); |
| 2240 // Don't infer if it is "a = function(){...}();"-like expression. | 2231 // Don't infer if it is "a = function(){...}();"-like expression. |
| 2241 if (fni_ != NULL && | 2232 if (fni_ != NULL && |
| 2242 value->AsCall() == NULL && | 2233 value->AsCall() == NULL && |
| 2243 value->AsCallNew() == NULL) { | 2234 value->AsCallNew() == NULL) { |
| 2244 fni_->Infer(); | 2235 fni_->Infer(); |
| 2245 } else { | 2236 } else { |
| 2246 fni_->RemoveLastFunction(); | 2237 fni_->RemoveLastFunction(); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2359 block->AddStatement( | 2350 block->AddStatement( |
| 2360 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), | 2351 factory()->NewExpressionStatement(assignment, RelocInfo::kNoPosition), |
| 2361 zone()); | 2352 zone()); |
| 2362 } | 2353 } |
| 2363 | 2354 |
| 2364 if (fni_ != NULL) fni_->Leave(); | 2355 if (fni_ != NULL) fni_->Leave(); |
| 2365 } while (peek() == Token::COMMA); | 2356 } while (peek() == Token::COMMA); |
| 2366 | 2357 |
| 2367 // If there was a single non-const declaration, return it in the output | 2358 // If there was a single non-const declaration, return it in the output |
| 2368 // parameter for possible use by for/in. | 2359 // parameter for possible use by for/in. |
| 2369 if (nvars == 1 && (!is_const || is_for_iteration_variable)) { | 2360 if (nvars == 1 && !is_const) { |
| 2370 *out = name; | 2361 *out = name; |
| 2371 } | 2362 } |
| 2372 | 2363 |
| 2373 return block; | 2364 return block; |
| 2374 } | 2365 } |
| 2375 | 2366 |
| 2376 | 2367 |
| 2377 static bool ContainsLabel(ZoneList<const AstRawString*>* labels, | 2368 static bool ContainsLabel(ZoneList<const AstRawString*>* labels, |
| 2378 const AstRawString* label) { | 2369 const AstRawString* label) { |
| 2379 DCHECK(label != NULL); | 2370 DCHECK(label != NULL); |
| (...skipping 716 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3096 | 3087 |
| 3097 // Create an in-between scope for let-bound iteration variables. | 3088 // Create an in-between scope for let-bound iteration variables. |
| 3098 Scope* saved_scope = scope_; | 3089 Scope* saved_scope = scope_; |
| 3099 Scope* for_scope = NewScope(scope_, BLOCK_SCOPE); | 3090 Scope* for_scope = NewScope(scope_, BLOCK_SCOPE); |
| 3100 scope_ = for_scope; | 3091 scope_ = for_scope; |
| 3101 | 3092 |
| 3102 Expect(Token::FOR, CHECK_OK); | 3093 Expect(Token::FOR, CHECK_OK); |
| 3103 Expect(Token::LPAREN, CHECK_OK); | 3094 Expect(Token::LPAREN, CHECK_OK); |
| 3104 for_scope->set_start_position(scanner()->location().beg_pos); | 3095 for_scope->set_start_position(scanner()->location().beg_pos); |
| 3105 if (peek() != Token::SEMICOLON) { | 3096 if (peek() != Token::SEMICOLON) { |
| 3106 if (peek() == Token::VAR || | 3097 if (peek() == Token::VAR || peek() == Token::CONST) { |
| 3107 (peek() == Token::CONST && strict_mode() == SLOPPY)) { | |
| 3108 bool is_const = peek() == Token::CONST; | 3098 bool is_const = peek() == Token::CONST; |
| 3109 const AstRawString* name = NULL; | 3099 const AstRawString* name = NULL; |
| 3110 VariableDeclarationProperties decl_props = kHasNoInitializers; | 3100 VariableDeclarationProperties decl_props = kHasNoInitializers; |
| 3111 Block* variable_statement = | 3101 Block* variable_statement = |
| 3112 ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name, | 3102 ParseVariableDeclarations(kForStatement, &decl_props, NULL, &name, |
| 3113 CHECK_OK); | 3103 CHECK_OK); |
| 3114 bool accept_OF = decl_props == kHasNoInitializers; | 3104 bool accept_OF = decl_props == kHasNoInitializers; |
| 3115 ForEachStatement::VisitMode mode; | 3105 ForEachStatement::VisitMode mode; |
| 3116 | 3106 |
| 3117 if (name != NULL && CheckInOrOf(accept_OF, &mode)) { | 3107 if (name != NULL && CheckInOrOf(accept_OF, &mode)) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3134 result->AddStatement(loop, zone()); | 3124 result->AddStatement(loop, zone()); |
| 3135 scope_ = saved_scope; | 3125 scope_ = saved_scope; |
| 3136 for_scope->set_end_position(scanner()->location().end_pos); | 3126 for_scope->set_end_position(scanner()->location().end_pos); |
| 3137 for_scope = for_scope->FinalizeBlockScope(); | 3127 for_scope = for_scope->FinalizeBlockScope(); |
| 3138 DCHECK(for_scope == NULL); | 3128 DCHECK(for_scope == NULL); |
| 3139 // Parsed for-in loop w/ variable/const declaration. | 3129 // Parsed for-in loop w/ variable/const declaration. |
| 3140 return result; | 3130 return result; |
| 3141 } else { | 3131 } else { |
| 3142 init = variable_statement; | 3132 init = variable_statement; |
| 3143 } | 3133 } |
| 3144 } else if ((peek() == Token::LET || peek() == Token::CONST) && | 3134 } else if (peek() == Token::LET && strict_mode() == STRICT) { |
| 3145 strict_mode() == STRICT) { | |
| 3146 DCHECK(allow_harmony_scoping()); | 3135 DCHECK(allow_harmony_scoping()); |
| 3147 bool is_const = peek() == Token::CONST; | |
| 3148 const AstRawString* name = NULL; | 3136 const AstRawString* name = NULL; |
| 3149 VariableDeclarationProperties decl_props = kHasNoInitializers; | 3137 VariableDeclarationProperties decl_props = kHasNoInitializers; |
| 3150 Block* variable_statement = | 3138 Block* variable_statement = |
| 3151 ParseVariableDeclarations(kForStatement, &decl_props, &let_bindings, | 3139 ParseVariableDeclarations(kForStatement, &decl_props, &let_bindings, |
| 3152 &name, CHECK_OK); | 3140 &name, CHECK_OK); |
| 3153 bool accept_IN = name != NULL && decl_props != kHasInitializers; | 3141 bool accept_IN = name != NULL && decl_props != kHasInitializers; |
| 3154 bool accept_OF = decl_props == kHasNoInitializers; | 3142 bool accept_OF = decl_props == kHasNoInitializers; |
| 3155 ForEachStatement::VisitMode mode; | 3143 ForEachStatement::VisitMode mode; |
| 3156 | 3144 |
| 3157 if (accept_IN && CheckInOrOf(accept_OF, &mode)) { | 3145 if (accept_IN && CheckInOrOf(accept_OF, &mode)) { |
| 3158 // Rewrite a for-in statement of the form | 3146 // Rewrite a for-in statement of the form |
| 3159 // | 3147 // |
| 3160 // for (let/const x in e) b | 3148 // for (let x in e) b |
| 3161 // | 3149 // |
| 3162 // into | 3150 // into |
| 3163 // | 3151 // |
| 3164 // <let x' be a temporary variable> | 3152 // <let x' be a temporary variable> |
| 3165 // for (x' in e) { | 3153 // for (x' in e) { |
| 3166 // let/const x; | 3154 // let x; |
| 3167 // x = x'; | 3155 // x = x'; |
| 3168 // b; | 3156 // b; |
| 3169 // } | 3157 // } |
| 3170 | 3158 |
| 3171 // TODO(keuchel): Move the temporary variable to the block scope, after | 3159 // TODO(keuchel): Move the temporary variable to the block scope, after |
| 3172 // implementing stack allocated block scoped variables. | 3160 // implementing stack allocated block scoped variables. |
| 3173 Variable* temp = scope_->DeclarationScope()->NewTemporary( | 3161 Variable* temp = scope_->DeclarationScope()->NewTemporary( |
| 3174 ast_value_factory()->dot_for_string()); | 3162 ast_value_factory()->dot_for_string()); |
| 3175 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); | 3163 VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); |
| 3176 ForEachStatement* loop = | 3164 ForEachStatement* loop = |
| 3177 factory()->NewForEachStatement(mode, labels, pos); | 3165 factory()->NewForEachStatement(mode, labels, pos); |
| 3178 Target target(&this->target_stack_, loop); | 3166 Target target(&this->target_stack_, loop); |
| 3179 | 3167 |
| 3180 // The expression does not see the loop variable. | 3168 // The expression does not see the loop variable. |
| 3181 scope_ = saved_scope; | 3169 scope_ = saved_scope; |
| 3182 Expression* enumerable = ParseExpression(true, CHECK_OK); | 3170 Expression* enumerable = ParseExpression(true, CHECK_OK); |
| 3183 scope_ = for_scope; | 3171 scope_ = for_scope; |
| 3184 Expect(Token::RPAREN, CHECK_OK); | 3172 Expect(Token::RPAREN, CHECK_OK); |
| 3185 | 3173 |
| 3186 VariableProxy* each = scope_->NewUnresolved(factory(), name); | 3174 VariableProxy* each = |
| 3175 scope_->NewUnresolved(factory(), name, Interface::NewValue()); |
| 3187 Statement* body = ParseStatement(NULL, CHECK_OK); | 3176 Statement* body = ParseStatement(NULL, CHECK_OK); |
| 3188 Block* body_block = | 3177 Block* body_block = |
| 3189 factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); | 3178 factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); |
| 3190 Token::Value init_op = is_const ? Token::INIT_CONST : Token::ASSIGN; | |
| 3191 Assignment* assignment = factory()->NewAssignment( | 3179 Assignment* assignment = factory()->NewAssignment( |
| 3192 init_op, each, temp_proxy, RelocInfo::kNoPosition); | 3180 Token::ASSIGN, each, temp_proxy, RelocInfo::kNoPosition); |
| 3193 Statement* assignment_statement = factory()->NewExpressionStatement( | 3181 Statement* assignment_statement = factory()->NewExpressionStatement( |
| 3194 assignment, RelocInfo::kNoPosition); | 3182 assignment, RelocInfo::kNoPosition); |
| 3195 body_block->AddStatement(variable_statement, zone()); | 3183 body_block->AddStatement(variable_statement, zone()); |
| 3196 body_block->AddStatement(assignment_statement, zone()); | 3184 body_block->AddStatement(assignment_statement, zone()); |
| 3197 body_block->AddStatement(body, zone()); | 3185 body_block->AddStatement(body, zone()); |
| 3198 InitializeForEachStatement(loop, temp_proxy, enumerable, body_block); | 3186 InitializeForEachStatement(loop, temp_proxy, enumerable, body_block); |
| 3199 scope_ = saved_scope; | 3187 scope_ = saved_scope; |
| 3200 for_scope->set_end_position(scanner()->location().end_pos); | 3188 for_scope->set_end_position(scanner()->location().end_pos); |
| 3201 for_scope = for_scope->FinalizeBlockScope(); | 3189 for_scope = for_scope->FinalizeBlockScope(); |
| 3202 body_block->set_scope(for_scope); | 3190 body_block->set_scope(for_scope); |
| (...skipping 1759 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4962 | 4950 |
| 4963 // We cannot internalize on a background thread; a foreground task will take | 4951 // We cannot internalize on a background thread; a foreground task will take |
| 4964 // care of calling Parser::Internalize just before compilation. | 4952 // care of calling Parser::Internalize just before compilation. |
| 4965 | 4953 |
| 4966 if (compile_options() == ScriptCompiler::kProduceParserCache) { | 4954 if (compile_options() == ScriptCompiler::kProduceParserCache) { |
| 4967 if (result != NULL) *info_->cached_data() = recorder.GetScriptData(); | 4955 if (result != NULL) *info_->cached_data() = recorder.GetScriptData(); |
| 4968 log_ = NULL; | 4956 log_ = NULL; |
| 4969 } | 4957 } |
| 4970 } | 4958 } |
| 4971 } } // namespace v8::internal | 4959 } } // namespace v8::internal |
| OLD | NEW |