Chromium Code Reviews| 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/scopes.h" | 7 #include "src/scopes.h" |
| 8 | 8 |
| 9 #include "src/accessors.h" | 9 #include "src/accessors.h" |
| 10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 27 VariableMap::VariableMap(Zone* zone) | 27 VariableMap::VariableMap(Zone* zone) |
| 28 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)), | 28 : ZoneHashMap(ZoneHashMap::PointersMatch, 8, ZoneAllocationPolicy(zone)), |
| 29 zone_(zone) {} | 29 zone_(zone) {} |
| 30 VariableMap::~VariableMap() {} | 30 VariableMap::~VariableMap() {} |
| 31 | 31 |
| 32 | 32 |
| 33 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name, | 33 Variable* VariableMap::Declare(Scope* scope, const AstRawString* name, |
| 34 VariableMode mode, bool is_valid_lhs, | 34 VariableMode mode, bool is_valid_lhs, |
| 35 Variable::Kind kind, | 35 Variable::Kind kind, |
| 36 InitializationFlag initialization_flag, | 36 InitializationFlag initialization_flag, |
| 37 int position, | |
| 37 MaybeAssignedFlag maybe_assigned_flag) { | 38 MaybeAssignedFlag maybe_assigned_flag) { |
| 38 // AstRawStrings are unambiguous, i.e., the same string is always represented | 39 // AstRawStrings are unambiguous, i.e., the same string is always represented |
| 39 // by the same AstRawString*. | 40 // by the same AstRawString*. |
| 40 // FIXME(marja): fix the type of Lookup. | 41 // FIXME(marja): fix the type of Lookup. |
| 41 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(), | 42 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(), |
| 42 true, ZoneAllocationPolicy(zone())); | 43 true, ZoneAllocationPolicy(zone())); |
| 43 if (p->value == NULL) { | 44 if (p->value == NULL) { |
| 44 // The variable has not been declared yet -> insert it. | 45 // The variable has not been declared yet -> insert it. |
| 45 DCHECK(p->key == name); | 46 DCHECK(p->key == name); |
| 46 p->value = new (zone()) Variable(scope, name, mode, is_valid_lhs, kind, | 47 p->value = new (zone()) |
| 47 initialization_flag, maybe_assigned_flag); | 48 Variable(scope, name, mode, is_valid_lhs, kind, initialization_flag, |
| 49 position, maybe_assigned_flag); | |
| 48 } | 50 } |
| 49 return reinterpret_cast<Variable*>(p->value); | 51 return reinterpret_cast<Variable*>(p->value); |
| 50 } | 52 } |
| 51 | 53 |
| 52 | 54 |
| 53 Variable* VariableMap::Lookup(const AstRawString* name) { | 55 Variable* VariableMap::Lookup(const AstRawString* name) { |
| 54 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(), | 56 Entry* p = ZoneHashMap::Lookup(const_cast<AstRawString*>(name), name->hash(), |
| 55 false, ZoneAllocationPolicy(NULL)); | 57 false, ZoneAllocationPolicy(NULL)); |
| 56 if (p != NULL) { | 58 if (p != NULL) { |
| 57 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name); | 59 DCHECK(reinterpret_cast<const AstRawString*>(p->key) == name); |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 256 // Traverse the scope tree up to the first unresolved scope or the global | 258 // Traverse the scope tree up to the first unresolved scope or the global |
| 257 // scope and start scope resolution and variable allocation from that scope. | 259 // scope and start scope resolution and variable allocation from that scope. |
| 258 while (!top->is_script_scope() && | 260 while (!top->is_script_scope() && |
| 259 !top->outer_scope()->already_resolved()) { | 261 !top->outer_scope()->already_resolved()) { |
| 260 top = top->outer_scope(); | 262 top = top->outer_scope(); |
| 261 } | 263 } |
| 262 | 264 |
| 263 // Allocate the variables. | 265 // Allocate the variables. |
| 264 { | 266 { |
| 265 AstNodeFactory ast_node_factory(info->ast_value_factory()); | 267 AstNodeFactory ast_node_factory(info->ast_value_factory()); |
| 266 if (!top->AllocateVariables(info, &ast_node_factory)) return false; | 268 if (!top->AllocateVariables(info, &ast_node_factory)) { |
| 269 DCHECK(top->pending_error_handler_.has_pending_error()); | |
| 270 top->pending_error_handler_.ThrowPendingError(info->isolate(), | |
| 271 info->script()); | |
| 272 return false; | |
| 273 } | |
| 267 } | 274 } |
| 268 | 275 |
| 269 #ifdef DEBUG | 276 #ifdef DEBUG |
| 270 if (info->isolate()->bootstrapper()->IsActive() | 277 if (info->isolate()->bootstrapper()->IsActive() |
| 271 ? FLAG_print_builtin_scopes | 278 ? FLAG_print_builtin_scopes |
| 272 : FLAG_print_scopes) { | 279 : FLAG_print_scopes) { |
| 273 scope->Print(); | 280 scope->Print(); |
| 274 } | 281 } |
| 275 #endif | 282 #endif |
| 276 | 283 |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 395 | 402 |
| 396 mode = DYNAMIC; | 403 mode = DYNAMIC; |
| 397 location = Variable::LOOKUP; | 404 location = Variable::LOOKUP; |
| 398 init_flag = kCreatedInitialized; | 405 init_flag = kCreatedInitialized; |
| 399 // Be conservative and flag parameters as maybe assigned. Better information | 406 // Be conservative and flag parameters as maybe assigned. Better information |
| 400 // would require ScopeInfo to serialize the maybe_assigned bit also for | 407 // would require ScopeInfo to serialize the maybe_assigned bit also for |
| 401 // parameters. | 408 // parameters. |
| 402 maybe_assigned_flag = kMaybeAssigned; | 409 maybe_assigned_flag = kMaybeAssigned; |
| 403 } | 410 } |
| 404 | 411 |
| 405 Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL, | 412 Variable* var = |
| 406 init_flag, maybe_assigned_flag); | 413 variables_.Declare(this, name, mode, true, Variable::NORMAL, init_flag, |
| 414 RelocInfo::kNoPosition, maybe_assigned_flag); | |
| 407 var->AllocateTo(location, index); | 415 var->AllocateTo(location, index); |
| 408 return var; | 416 return var; |
| 409 } | 417 } |
| 410 | 418 |
| 411 | 419 |
| 412 Variable* Scope::LookupFunctionVar(const AstRawString* name, | 420 Variable* Scope::LookupFunctionVar(const AstRawString* name, |
| 413 AstNodeFactory* factory) { | 421 AstNodeFactory* factory) { |
| 414 if (function_ != NULL && function_->proxy()->raw_name() == name) { | 422 if (function_ != NULL && function_->proxy()->raw_name() == name) { |
| 415 return function_->proxy()->var(); | 423 return function_->proxy()->var(); |
| 416 } else if (!scope_info_.is_null()) { | 424 } else if (!scope_info_.is_null()) { |
| 417 // If we are backed by a scope info, try to lookup the variable there. | 425 // If we are backed by a scope info, try to lookup the variable there. |
| 418 VariableMode mode; | 426 VariableMode mode; |
| 419 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); | 427 int index = scope_info_->FunctionContextSlotIndex(*(name->string()), &mode); |
| 420 if (index < 0) return NULL; | 428 if (index < 0) return NULL; |
| 421 Variable* var = new(zone()) Variable( | 429 Variable* var = new (zone()) |
| 422 this, name, mode, true /* is valid LHS */, | 430 Variable(this, name, mode, true /* is valid LHS */, Variable::FUNCTION, |
| 423 Variable::NORMAL, kCreatedInitialized); | 431 kCreatedInitialized, RelocInfo::kNoPosition); |
| 424 VariableProxy* proxy = factory->NewVariableProxy(var); | 432 VariableProxy* proxy = factory->NewVariableProxy(var); |
| 425 VariableDeclaration* declaration = factory->NewVariableDeclaration( | 433 VariableDeclaration* declaration = factory->NewVariableDeclaration( |
| 426 proxy, mode, this, RelocInfo::kNoPosition); | 434 proxy, mode, this, RelocInfo::kNoPosition); |
| 427 DeclareFunctionVar(declaration); | 435 DeclareFunctionVar(declaration); |
| 428 var->AllocateTo(Variable::CONTEXT, index); | 436 var->AllocateTo(Variable::CONTEXT, index); |
| 429 return var; | 437 return var; |
| 430 } else { | 438 } else { |
| 431 return NULL; | 439 return NULL; |
| 432 } | 440 } |
| 433 } | 441 } |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 454 DCHECK_NULL(rest_parameter_); | 462 DCHECK_NULL(rest_parameter_); |
| 455 rest_parameter_ = var; | 463 rest_parameter_ = var; |
| 456 rest_index_ = num_parameters(); | 464 rest_index_ = num_parameters(); |
| 457 } | 465 } |
| 458 params_.Add(var, zone()); | 466 params_.Add(var, zone()); |
| 459 return var; | 467 return var; |
| 460 } | 468 } |
| 461 | 469 |
| 462 | 470 |
| 463 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, | 471 Variable* Scope::DeclareLocal(const AstRawString* name, VariableMode mode, |
| 464 InitializationFlag init_flag, | 472 InitializationFlag init_flag, int position, |
| 473 bool is_function, | |
| 465 MaybeAssignedFlag maybe_assigned_flag) { | 474 MaybeAssignedFlag maybe_assigned_flag) { |
| 466 DCHECK(!already_resolved()); | 475 DCHECK(!already_resolved()); |
| 467 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are | 476 // This function handles VAR, LET, and CONST modes. DYNAMIC variables are |
| 468 // introduces during variable allocation, INTERNAL variables are allocated | 477 // introduces during variable allocation, INTERNAL variables are allocated |
| 469 // explicitly, and TEMPORARY variables are allocated via NewTemporary(). | 478 // explicitly, and TEMPORARY variables are allocated via NewTemporary(). |
| 470 DCHECK(IsDeclaredVariableMode(mode)); | 479 DCHECK(IsDeclaredVariableMode(mode)); |
| 471 ++num_var_or_const_; | 480 ++num_var_or_const_; |
| 472 return variables_.Declare(this, name, mode, true, Variable::NORMAL, init_flag, | 481 return variables_.Declare(this, name, mode, true, |
| 473 maybe_assigned_flag); | 482 is_function ? Variable::FUNCTION : Variable::NORMAL, |
| 483 init_flag, position, maybe_assigned_flag); | |
| 474 } | 484 } |
| 475 | 485 |
| 476 | 486 |
| 477 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) { | 487 Variable* Scope::DeclareDynamicGlobal(const AstRawString* name) { |
| 478 DCHECK(is_script_scope()); | 488 DCHECK(is_script_scope()); |
| 479 return variables_.Declare(this, | 489 return variables_.Declare(this, |
| 480 name, | 490 name, |
| 481 DYNAMIC_GLOBAL, | 491 DYNAMIC_GLOBAL, |
| 482 true, | 492 true, |
| 483 Variable::NORMAL, | 493 Variable::NORMAL, |
| 484 kCreatedInitialized); | 494 kCreatedInitialized); |
| 485 } | 495 } |
| 486 | 496 |
| 487 | 497 |
| 488 void Scope::RemoveUnresolved(VariableProxy* var) { | 498 void Scope::RemoveUnresolved(VariableProxy* var) { |
| 489 // Most likely (always?) any variable we want to remove | 499 // Most likely (always?) any variable we want to remove |
| 490 // was just added before, so we search backwards. | 500 // was just added before, so we search backwards. |
| 491 for (int i = unresolved_.length(); i-- > 0;) { | 501 for (int i = unresolved_.length(); i-- > 0;) { |
| 492 if (unresolved_[i] == var) { | 502 if (unresolved_[i] == var) { |
| 493 unresolved_.Remove(i); | 503 unresolved_.Remove(i); |
| 494 return; | 504 return; |
| 495 } | 505 } |
| 496 } | 506 } |
| 497 } | 507 } |
| 498 | 508 |
| 499 | 509 |
| 500 Variable* Scope::NewInternal(const AstRawString* name) { | 510 Variable* Scope::NewInternal(const AstRawString* name) { |
| 501 DCHECK(!already_resolved()); | 511 DCHECK(!already_resolved()); |
| 502 Variable* var = new(zone()) Variable(this, | 512 Variable* var = |
| 503 name, | 513 new (zone()) Variable(this, name, INTERNAL, false, Variable::NORMAL, |
| 504 INTERNAL, | 514 kCreatedInitialized, RelocInfo::kNoPosition); |
| 505 false, | |
| 506 Variable::NORMAL, | |
| 507 kCreatedInitialized); | |
| 508 internals_.Add(var, zone()); | 515 internals_.Add(var, zone()); |
| 509 return var; | 516 return var; |
| 510 } | 517 } |
| 511 | 518 |
| 512 | 519 |
| 513 Variable* Scope::NewTemporary(const AstRawString* name) { | 520 Variable* Scope::NewTemporary(const AstRawString* name) { |
| 514 DCHECK(!already_resolved()); | 521 DCHECK(!already_resolved()); |
| 515 Variable* var = new(zone()) Variable(this, | 522 Variable* var = |
| 516 name, | 523 new (zone()) Variable(this, name, TEMPORARY, true, Variable::NORMAL, |
| 517 TEMPORARY, | 524 kCreatedInitialized, RelocInfo::kNoPosition); |
| 518 true, | |
| 519 Variable::NORMAL, | |
| 520 kCreatedInitialized); | |
| 521 temps_.Add(var, zone()); | 525 temps_.Add(var, zone()); |
| 522 return var; | 526 return var; |
| 523 } | 527 } |
| 524 | 528 |
| 525 | 529 |
| 526 void Scope::AddDeclaration(Declaration* declaration) { | 530 void Scope::AddDeclaration(Declaration* declaration) { |
| 527 decls_.Add(declaration, zone()); | 531 decls_.Add(declaration, zone()); |
| 528 } | 532 } |
| 529 | 533 |
| 530 | 534 |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 761 int end_pos = scope->end_position(); | 765 int end_pos = scope->end_position(); |
| 762 DCHECK(beg_pos >= 0 && end_pos >= 0); | 766 DCHECK(beg_pos >= 0 && end_pos >= 0); |
| 763 if (beg_pos <= position && position < end_pos) { | 767 if (beg_pos <= position && position < end_pos) { |
| 764 scope->GetNestedScopeChain(isolate, chain, position); | 768 scope->GetNestedScopeChain(isolate, chain, position); |
| 765 return; | 769 return; |
| 766 } | 770 } |
| 767 } | 771 } |
| 768 } | 772 } |
| 769 | 773 |
| 770 | 774 |
| 775 void Scope::ReportMessage(int start_position, int end_position, | |
| 776 const char* message, const AstRawString* arg) { | |
| 777 // Propagate the error to the topmost scope targeted by this scope analysis | |
| 778 // phase. | |
| 779 Scope* top = this; | |
| 780 while (!top->is_script_scope() && !top->outer_scope()->already_resolved()) { | |
| 781 top = top->outer_scope(); | |
| 782 } | |
| 783 | |
| 784 top->pending_error_handler_.ReportMessageAt(start_position, end_position, | |
| 785 message, arg, kReferenceError); | |
| 786 } | |
| 787 | |
| 788 | |
| 771 #ifdef DEBUG | 789 #ifdef DEBUG |
| 772 static const char* Header(ScopeType scope_type) { | 790 static const char* Header(ScopeType scope_type) { |
| 773 switch (scope_type) { | 791 switch (scope_type) { |
| 774 case EVAL_SCOPE: return "eval"; | 792 case EVAL_SCOPE: return "eval"; |
| 775 case FUNCTION_SCOPE: return "function"; | 793 case FUNCTION_SCOPE: return "function"; |
| 776 case MODULE_SCOPE: return "module"; | 794 case MODULE_SCOPE: return "module"; |
| 777 case SCRIPT_SCOPE: return "global"; | 795 case SCRIPT_SCOPE: return "global"; |
| 778 case CATCH_SCOPE: return "catch"; | 796 case CATCH_SCOPE: return "catch"; |
| 779 case BLOCK_SCOPE: return "block"; | 797 case BLOCK_SCOPE: return "block"; |
| 780 case WITH_SCOPE: return "with"; | 798 case WITH_SCOPE: return "with"; |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1043 // If the proxy is already resolved there's nothing to do | 1061 // If the proxy is already resolved there's nothing to do |
| 1044 // (functions and consts may be resolved by the parser). | 1062 // (functions and consts may be resolved by the parser). |
| 1045 if (proxy->is_resolved()) return true; | 1063 if (proxy->is_resolved()) return true; |
| 1046 | 1064 |
| 1047 // Otherwise, try to resolve the variable. | 1065 // Otherwise, try to resolve the variable. |
| 1048 BindingKind binding_kind; | 1066 BindingKind binding_kind; |
| 1049 Variable* var = LookupRecursive(proxy, &binding_kind, factory); | 1067 Variable* var = LookupRecursive(proxy, &binding_kind, factory); |
| 1050 switch (binding_kind) { | 1068 switch (binding_kind) { |
| 1051 case BOUND: | 1069 case BOUND: |
| 1052 // We found a variable binding. | 1070 // We found a variable binding. |
| 1071 if (is_strong(language_mode())) { | |
| 1072 // Check for declaration-after use (for variables) in strong mode. Note | |
| 1073 // that we can only do this in the case where we have seen the | |
| 1074 // declaration. And we always allow referencing functions (for now). | |
| 1075 | |
| 1076 // If both the use and the declaration are inside an eval scope | |
| 1077 // (possibly indirectly), or one of them is, we need to check whether | |
| 1078 // they are inside the same eval scope or different ones. | |
|
rossberg
2015/02/23 13:45:26
Can you add a TODO regarding different evals? I su
marja
2015/02/24 13:29:34
Added a todo.
So one error case is:
This throws:
| |
| 1079 const Scope* eval_for_use = NearestOuterEvalScope(); | |
| 1080 const Scope* eval_for_declaration = | |
| 1081 var->scope()->NearestOuterEvalScope(); | |
| 1082 | |
| 1083 if (proxy->position() != RelocInfo::kNoPosition && | |
| 1084 proxy->position() < var->position() && !var->is_function() && | |
|
rossberg
2015/02/23 13:45:26
I don't believe this is good enough. Consider:
marja
2015/02/24 13:29:35
Fixed this to use initializer_position(), undid th
| |
| 1085 eval_for_use == eval_for_declaration) { | |
| 1086 DCHECK(proxy->end_position() != RelocInfo::kNoPosition); | |
| 1087 ReportMessage(proxy->position(), proxy->end_position(), | |
| 1088 "strong_use_before_declaration", proxy->raw_name()); | |
| 1089 return false; | |
| 1090 } | |
| 1091 } | |
| 1053 break; | 1092 break; |
| 1054 | 1093 |
| 1055 case BOUND_EVAL_SHADOWED: | 1094 case BOUND_EVAL_SHADOWED: |
| 1056 // We either found a variable binding that might be shadowed by eval or | 1095 // We either found a variable binding that might be shadowed by eval or |
| 1057 // gave up on it (e.g. by encountering a local with the same in the outer | 1096 // gave up on it (e.g. by encountering a local with the same in the outer |
| 1058 // scope which was not promoted to a context, this can happen if we use | 1097 // scope which was not promoted to a context, this can happen if we use |
| 1059 // debugger to evaluate arbitrary expressions at a break point). | 1098 // debugger to evaluate arbitrary expressions at a break point). |
| 1060 if (var->IsGlobalObjectProperty()) { | 1099 if (var->IsGlobalObjectProperty()) { |
| 1061 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); | 1100 var = NonLocal(proxy->raw_name(), DYNAMIC_GLOBAL); |
| 1062 } else if (var->is_dynamic()) { | 1101 } else if (var->is_dynamic()) { |
| (...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1381 } | 1420 } |
| 1382 | 1421 |
| 1383 | 1422 |
| 1384 int Scope::ContextLocalCount() const { | 1423 int Scope::ContextLocalCount() const { |
| 1385 if (num_heap_slots() == 0) return 0; | 1424 if (num_heap_slots() == 0) return 0; |
| 1386 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - | 1425 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - |
| 1387 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); | 1426 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0); |
| 1388 } | 1427 } |
| 1389 | 1428 |
| 1390 } } // namespace v8::internal | 1429 } } // namespace v8::internal |
| OLD | NEW |