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/ast/scopes.h" | 5 #include "src/ast/scopes.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "src/accessors.h" | 9 #include "src/accessors.h" |
| 10 #include "src/ast/ast.h" | 10 #include "src/ast/ast.h" |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 300 } | 300 } |
| 301 | 301 |
| 302 bool Scope::IsAsmModule() const { | 302 bool Scope::IsAsmModule() const { |
| 303 return is_function_scope() && AsDeclarationScope()->asm_module(); | 303 return is_function_scope() && AsDeclarationScope()->asm_module(); |
| 304 } | 304 } |
| 305 | 305 |
| 306 bool Scope::IsAsmFunction() const { | 306 bool Scope::IsAsmFunction() const { |
| 307 return is_function_scope() && AsDeclarationScope()->asm_function(); | 307 return is_function_scope() && AsDeclarationScope()->asm_function(); |
| 308 } | 308 } |
| 309 | 309 |
| 310 Scope* Scope::DeserializeScopeChainForTesting( | |
| 311 Isolate* isolate, Zone* zone, Context* context, | |
| 312 DeclarationScope* script_scope, AstValueFactory* ast_value_factory) { | |
| 313 return DeserializeScopeChain(isolate, zone, context, script_scope, | |
| 314 ast_value_factory); | |
| 315 } | |
| 316 | |
| 317 void DeclarationScope::DeserializeScopeChain(ParseInfo* info) { | |
| 318 if (!info->context().is_null() && !info->context()->IsNativeContext()) { | |
|
adamk
2016/09/12 16:57:47
Can you make this an early return instead? I'd fin
jochen (gone - plz use gerrit)
2016/09/12 19:00:43
done
| |
| 319 ReplaceOuterScope(Scope::DeserializeScopeChain( | |
|
adamk
2016/09/12 16:57:47
Nit: You shouldn't need to qualify DeserializeScop
jochen (gone - plz use gerrit)
2016/09/12 19:00:43
done
jochen (gone - plz use gerrit)
2016/09/12 19:02:08
Actually, the compiler disagrees so I reverted thi
| |
| 320 info->isolate(), zone(), *info->context(), info->script_scope(), | |
| 321 info->ast_value_factory())); | |
| 322 } | |
| 323 } | |
| 324 | |
| 310 Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone, | 325 Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone, |
| 311 Context* context, | 326 Context* context, |
| 312 DeclarationScope* script_scope, | 327 DeclarationScope* script_scope, |
| 313 AstValueFactory* ast_value_factory, | 328 AstValueFactory* ast_value_factory) { |
| 314 DeserializationMode deserialization_mode) { | |
| 315 // Reconstruct the outer scope chain from a closure's context chain. | 329 // Reconstruct the outer scope chain from a closure's context chain. |
| 316 Scope* current_scope = nullptr; | 330 Scope* current_scope = nullptr; |
| 317 Scope* innermost_scope = nullptr; | 331 Scope* innermost_scope = nullptr; |
| 318 Scope* outer_scope = nullptr; | 332 Scope* outer_scope = nullptr; |
| 319 while (!context->IsNativeContext()) { | 333 while (!context->IsNativeContext()) { |
| 320 if (context->IsWithContext() || context->IsDebugEvaluateContext()) { | 334 if (context->IsWithContext() || context->IsDebugEvaluateContext()) { |
| 321 // For scope analysis, debug-evaluate is equivalent to a with scope. | 335 // For scope analysis, debug-evaluate is equivalent to a with scope. |
| 322 outer_scope = new (zone) | 336 outer_scope = new (zone) |
| 323 Scope(zone, WITH_SCOPE, Handle<ScopeInfo>(context->scope_info())); | 337 Scope(zone, WITH_SCOPE, Handle<ScopeInfo>(context->scope_info())); |
| 324 | 338 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 365 isolate, Handle<ScopeInfo>(scope_info), ast_value_factory); | 379 isolate, Handle<ScopeInfo>(scope_info), ast_value_factory); |
| 366 } else { | 380 } else { |
| 367 DCHECK(context->IsCatchContext()); | 381 DCHECK(context->IsCatchContext()); |
| 368 String* name = context->catch_name(); | 382 String* name = context->catch_name(); |
| 369 outer_scope = new (zone) | 383 outer_scope = new (zone) |
| 370 Scope(zone, ast_value_factory->GetString(handle(name, isolate)), | 384 Scope(zone, ast_value_factory->GetString(handle(name, isolate)), |
| 371 Handle<ScopeInfo>(context->scope_info())); | 385 Handle<ScopeInfo>(context->scope_info())); |
| 372 } | 386 } |
| 373 if (current_scope != nullptr) { | 387 if (current_scope != nullptr) { |
| 374 outer_scope->AddInnerScope(current_scope); | 388 outer_scope->AddInnerScope(current_scope); |
| 375 DCHECK_IMPLIES( | 389 DCHECK(current_scope->scope_info_->HasOuterScopeInfo()); |
| 376 deserialization_mode == DeserializationMode::kKeepScopeInfo, | 390 DCHECK(outer_scope->scope_info_->Equals( |
| 377 current_scope->scope_info_->HasOuterScopeInfo()); | 391 current_scope->scope_info_->OuterScopeInfo())); |
| 378 DCHECK_IMPLIES( | |
| 379 deserialization_mode == DeserializationMode::kKeepScopeInfo, | |
| 380 outer_scope->scope_info_->Equals( | |
| 381 current_scope->scope_info_->OuterScopeInfo())); | |
| 382 } | 392 } |
| 383 current_scope = outer_scope; | 393 current_scope = outer_scope; |
| 384 if (deserialization_mode == DeserializationMode::kDeserializeOffHeap) { | |
| 385 current_scope->DeserializeScopeInfo(isolate, ast_value_factory); | |
| 386 } | |
| 387 if (innermost_scope == nullptr) innermost_scope = current_scope; | 394 if (innermost_scope == nullptr) innermost_scope = current_scope; |
| 388 context = context->previous(); | 395 context = context->previous(); |
| 389 } | 396 } |
| 390 | 397 |
| 391 if (innermost_scope == nullptr) return script_scope; | 398 if (innermost_scope == nullptr) return script_scope; |
| 392 script_scope->AddInnerScope(current_scope); | 399 script_scope->AddInnerScope(current_scope); |
| 393 #if DEBUG | 400 #if DEBUG |
| 394 if (deserialization_mode == DeserializationMode::kKeepScopeInfo) { | 401 if (script_scope->scope_info_.is_null()) { |
| 395 if (script_scope->scope_info_.is_null()) { | 402 DCHECK(!current_scope->scope_info_->HasOuterScopeInfo()); |
| 396 DCHECK(!current_scope->scope_info_->HasOuterScopeInfo()); | 403 } else { |
| 397 } else { | 404 DCHECK(!script_scope->scope_info_->HasOuterScopeInfo()); |
| 398 DCHECK(!script_scope->scope_info_->HasOuterScopeInfo()); | 405 DCHECK(script_scope->scope_info_->Equals( |
| 399 DCHECK(script_scope->scope_info_->Equals( | 406 current_scope->scope_info_->OuterScopeInfo())); |
| 400 current_scope->scope_info_->OuterScopeInfo())); | |
| 401 } | |
| 402 } | 407 } |
| 403 #endif | 408 #endif |
| 404 return innermost_scope; | 409 return innermost_scope; |
| 405 } | 410 } |
| 406 | 411 |
| 407 void Scope::DeserializeScopeInfo(Isolate* isolate, | |
| 408 AstValueFactory* ast_value_factory) { | |
| 409 if (scope_info_.is_null()) return; | |
| 410 | |
| 411 DCHECK(ThreadId::Current().Equals(isolate->thread_id())); | |
| 412 | |
| 413 // Internalize context local variables. | |
| 414 for (int var = 0; var < scope_info_->ContextLocalCount(); ++var) { | |
| 415 Handle<String> name_handle(scope_info_->ContextLocalName(var), isolate); | |
| 416 const AstRawString* name = ast_value_factory->GetString(name_handle); | |
| 417 int index = Context::MIN_CONTEXT_SLOTS + var; | |
| 418 VariableMode mode = scope_info_->ContextLocalMode(var); | |
| 419 InitializationFlag init_flag = scope_info_->ContextLocalInitFlag(var); | |
| 420 MaybeAssignedFlag maybe_assigned_flag = | |
| 421 scope_info_->ContextLocalMaybeAssignedFlag(var); | |
| 422 VariableLocation location = VariableLocation::CONTEXT; | |
| 423 VariableKind kind = NORMAL_VARIABLE; | |
| 424 if (index == scope_info_->ReceiverContextSlotIndex()) { | |
| 425 kind = THIS_VARIABLE; | |
| 426 } | |
| 427 | |
| 428 Variable* result = variables_.Declare(zone(), this, name, mode, kind, | |
| 429 init_flag, maybe_assigned_flag); | |
| 430 result->AllocateTo(location, index); | |
| 431 } | |
| 432 | |
| 433 // Internalize function proxy for this scope. | |
| 434 if (scope_info_->HasFunctionName()) { | |
| 435 Handle<String> name_handle(scope_info_->FunctionName(), isolate); | |
| 436 const AstRawString* name = ast_value_factory->GetString(name_handle); | |
| 437 int index = scope_info_->FunctionContextSlotIndex(*name_handle); | |
| 438 if (index >= 0) { | |
| 439 Variable* result = AsDeclarationScope()->DeclareFunctionVar(name); | |
| 440 result->AllocateTo(VariableLocation::CONTEXT, index); | |
| 441 } | |
| 442 } | |
| 443 | |
| 444 scope_info_ = Handle<ScopeInfo>::null(); | |
| 445 } | |
| 446 | |
| 447 DeclarationScope* Scope::AsDeclarationScope() { | 412 DeclarationScope* Scope::AsDeclarationScope() { |
| 448 DCHECK(is_declaration_scope()); | 413 DCHECK(is_declaration_scope()); |
| 449 return static_cast<DeclarationScope*>(this); | 414 return static_cast<DeclarationScope*>(this); |
| 450 } | 415 } |
| 451 | 416 |
| 452 const DeclarationScope* Scope::AsDeclarationScope() const { | 417 const DeclarationScope* Scope::AsDeclarationScope() const { |
| 453 DCHECK(is_declaration_scope()); | 418 DCHECK(is_declaration_scope()); |
| 454 return static_cast<const DeclarationScope*>(this); | 419 return static_cast<const DeclarationScope*>(this); |
| 455 } | 420 } |
| 456 | 421 |
| 457 ModuleScope* Scope::AsModuleScope() { | 422 ModuleScope* Scope::AsModuleScope() { |
| 458 DCHECK(is_module_scope()); | 423 DCHECK(is_module_scope()); |
| 459 return static_cast<ModuleScope*>(this); | 424 return static_cast<ModuleScope*>(this); |
| 460 } | 425 } |
| 461 | 426 |
| 462 const ModuleScope* Scope::AsModuleScope() const { | 427 const ModuleScope* Scope::AsModuleScope() const { |
| 463 DCHECK(is_module_scope()); | 428 DCHECK(is_module_scope()); |
| 464 return static_cast<const ModuleScope*>(this); | 429 return static_cast<const ModuleScope*>(this); |
| 465 } | 430 } |
| 466 | 431 |
| 467 int Scope::num_parameters() const { | 432 int Scope::num_parameters() const { |
| 468 return is_declaration_scope() ? AsDeclarationScope()->num_parameters() : 0; | 433 return is_declaration_scope() ? AsDeclarationScope()->num_parameters() : 0; |
| 469 } | 434 } |
| 470 | 435 |
| 471 void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory, | 436 void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory, |
| 472 bool* ok) { | 437 bool* ok) { |
|
adamk
2016/09/12 16:57:47
It doesn't look like this out parameter should eve
jochen (gone - plz use gerrit)
2016/09/12 19:00:43
done
| |
| 438 // For the outer most eval scope (which is inside a script scope), don't | |
| 439 // hoist during parsing, but later during DeclarationScope::Analyze when the | |
| 440 // actual scope chain is available. | |
| 441 if (is_eval_scope() && !outer_scope()->outer_scope()) return; | |
| 442 HoistSloppyBlockFunctionsInternal(factory, ok); | |
| 443 } | |
| 444 | |
| 445 void DeclarationScope::HoistSloppyBlockFunctionsInternal( | |
| 446 AstNodeFactory* factory, bool* ok) { | |
| 473 DCHECK(is_sloppy(language_mode())); | 447 DCHECK(is_sloppy(language_mode())); |
| 474 DCHECK(is_function_scope() || is_eval_scope() || is_script_scope() || | 448 DCHECK(is_function_scope() || is_eval_scope() || is_script_scope() || |
| 475 (is_block_scope() && outer_scope()->is_function_scope())); | 449 (is_block_scope() && outer_scope()->is_function_scope())); |
| 476 DCHECK(HasSimpleParameters() || is_block_scope()); | 450 DCHECK(HasSimpleParameters() || is_block_scope()); |
| 477 bool has_simple_parameters = HasSimpleParameters(); | 451 bool has_simple_parameters = HasSimpleParameters(); |
| 478 // For each variable which is used as a function declaration in a sloppy | 452 // For each variable which is used as a function declaration in a sloppy |
| 479 // block, | 453 // block, |
| 480 SloppyBlockFunctionMap* map = sloppy_block_function_map(); | 454 SloppyBlockFunctionMap* map = sloppy_block_function_map(); |
| 481 for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) { | 455 for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) { |
| 482 AstRawString* name = static_cast<AstRawString*>(p->key); | 456 AstRawString* name = static_cast<AstRawString*>(p->key); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 541 var_created = true; | 515 var_created = true; |
| 542 VariableProxy* proxy = NewUnresolved(factory, name); | 516 VariableProxy* proxy = NewUnresolved(factory, name); |
| 543 Declaration* declaration = | 517 Declaration* declaration = |
| 544 factory->NewVariableDeclaration(proxy, this, kNoSourcePosition); | 518 factory->NewVariableDeclaration(proxy, this, kNoSourcePosition); |
| 545 // Based on the preceding check, it doesn't matter what we pass as | 519 // Based on the preceding check, it doesn't matter what we pass as |
| 546 // allow_harmony_restrictive_generators and | 520 // allow_harmony_restrictive_generators and |
| 547 // sloppy_mode_block_scope_function_redefinition. | 521 // sloppy_mode_block_scope_function_redefinition. |
| 548 DeclareVariable(declaration, VAR, | 522 DeclareVariable(declaration, VAR, |
| 549 Variable::DefaultInitializationFlag(VAR), false, | 523 Variable::DefaultInitializationFlag(VAR), false, |
| 550 nullptr, ok); | 524 nullptr, ok); |
| 551 DCHECK(*ok); // Based on the preceding check, this should not fail | 525 DCHECK(*ok); // Based on the preceding check, this should not fail |
|
adamk
2016/09/12 16:57:47
Let's make this a CHECK instead and remove the out
jochen (gone - plz use gerrit)
2016/09/12 19:00:43
done
| |
| 552 if (!*ok) return; | 526 if (!*ok) return; |
| 553 } | 527 } |
| 554 | 528 |
| 555 // Create VariableProxies for creating an assignment statement | 529 Expression* assignment = factory->NewAssignment( |
| 556 // (later). Read from the local lexical scope and write to the function | 530 Token::ASSIGN, NewUnresolved(factory, name), |
| 557 // scope. | 531 delegate->scope()->NewUnresolved(factory, name), kNoSourcePosition); |
| 558 delegate->set_to(NewUnresolved(factory, name)); | 532 Statement* statement = |
| 559 delegate->set_from(delegate->scope()->NewUnresolved(factory, name)); | 533 factory->NewExpressionStatement(assignment, kNoSourcePosition); |
| 534 delegate->set_statement(statement); | |
| 560 } | 535 } |
| 561 } | 536 } |
| 562 } | 537 } |
| 563 | 538 |
| 564 void DeclarationScope::Analyze(ParseInfo* info, AnalyzeMode mode) { | 539 void DeclarationScope::Analyze(ParseInfo* info, AnalyzeMode mode) { |
| 565 DCHECK(info->literal() != NULL); | 540 DCHECK(info->literal() != NULL); |
| 566 DeclarationScope* scope = info->literal()->scope(); | 541 DeclarationScope* scope = info->literal()->scope(); |
| 567 | 542 |
| 543 scope->DeserializeScopeChain(info); | |
| 544 | |
| 545 if (scope->is_eval_scope() && is_sloppy(scope->language_mode())) { | |
| 546 AstNodeFactory factory(info->ast_value_factory()); | |
| 547 bool ok = true; | |
| 548 scope->HoistSloppyBlockFunctionsInternal(&factory, &ok); | |
| 549 CHECK(ok); | |
| 550 } | |
| 551 | |
| 568 // We are compiling one of three cases: | 552 // We are compiling one of three cases: |
| 569 // 1) top-level code, | 553 // 1) top-level code, |
| 570 // 2) a function/eval/module on the top-level | 554 // 2) a function/eval/module on the top-level |
| 571 // 3) a function/eval in a scope that was already resolved. | 555 // 3) a function/eval in a scope that was already resolved. |
| 572 DCHECK(scope->scope_type() == SCRIPT_SCOPE || | 556 DCHECK(scope->scope_type() == SCRIPT_SCOPE || |
| 573 scope->outer_scope()->scope_type() == SCRIPT_SCOPE || | 557 scope->outer_scope()->scope_type() == SCRIPT_SCOPE || |
| 574 scope->outer_scope()->already_resolved_); | 558 scope->outer_scope()->already_resolved_); |
| 575 | 559 |
| 576 scope->AllocateVariables(info, mode); | 560 scope->AllocateVariables(info, mode); |
| 577 | 561 |
| 578 #ifdef DEBUG | 562 #ifdef DEBUG |
| 563 if (scope->outer_scope()) { | |
| 564 DCHECK(is_sloppy(scope->outer_scope()->language_mode()) || | |
| 565 is_strict(info->language_mode())); | |
| 566 } | |
| 567 | |
| 579 if (info->script_is_native() ? FLAG_print_builtin_scopes | 568 if (info->script_is_native() ? FLAG_print_builtin_scopes |
| 580 : FLAG_print_scopes) { | 569 : FLAG_print_scopes) { |
| 581 scope->Print(); | 570 scope->Print(); |
| 582 } | 571 } |
| 583 scope->CheckScopePositions(); | 572 scope->CheckScopePositions(); |
| 584 scope->CheckZones(); | 573 scope->CheckZones(); |
| 585 #endif | 574 #endif |
| 586 } | 575 } |
| 587 | 576 |
| 588 void DeclarationScope::DeclareThis(AstValueFactory* ast_value_factory) { | 577 void DeclarationScope::DeclareThis(AstValueFactory* ast_value_factory) { |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 740 } | 729 } |
| 741 } | 730 } |
| 742 outer_closure->locals_.Rewind(top_local_); | 731 outer_closure->locals_.Rewind(top_local_); |
| 743 outer_closure->decls_.Rewind(top_decl_); | 732 outer_closure->decls_.Rewind(top_decl_); |
| 744 } | 733 } |
| 745 | 734 |
| 746 void Scope::ReplaceOuterScope(Scope* outer) { | 735 void Scope::ReplaceOuterScope(Scope* outer) { |
| 747 DCHECK_NOT_NULL(outer); | 736 DCHECK_NOT_NULL(outer); |
| 748 DCHECK_NOT_NULL(outer_scope_); | 737 DCHECK_NOT_NULL(outer_scope_); |
| 749 DCHECK(!already_resolved_); | 738 DCHECK(!already_resolved_); |
| 750 DCHECK(!outer->already_resolved_); | |
| 751 DCHECK(!outer_scope_->already_resolved_); | 739 DCHECK(!outer_scope_->already_resolved_); |
| 752 outer_scope_->RemoveInnerScope(this); | 740 outer_scope_->RemoveInnerScope(this); |
| 753 outer->AddInnerScope(this); | 741 outer->AddInnerScope(this); |
| 754 outer_scope_ = outer; | 742 outer_scope_ = outer; |
| 755 } | 743 } |
| 756 | 744 |
| 757 | 745 |
| 758 void Scope::PropagateUsageFlagsToScope(Scope* other) { | 746 void Scope::PropagateUsageFlagsToScope(Scope* other) { |
| 759 DCHECK_NOT_NULL(other); | 747 DCHECK_NOT_NULL(other); |
| 760 DCHECK(!already_resolved_); | 748 DCHECK(!already_resolved_); |
| (...skipping 1084 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1845 Variable* function = | 1833 Variable* function = |
| 1846 is_function_scope() ? AsDeclarationScope()->function_var() : nullptr; | 1834 is_function_scope() ? AsDeclarationScope()->function_var() : nullptr; |
| 1847 bool is_function_var_in_context = | 1835 bool is_function_var_in_context = |
| 1848 function != nullptr && function->IsContextSlot(); | 1836 function != nullptr && function->IsContextSlot(); |
| 1849 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - | 1837 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - |
| 1850 (is_function_var_in_context ? 1 : 0); | 1838 (is_function_var_in_context ? 1 : 0); |
| 1851 } | 1839 } |
| 1852 | 1840 |
| 1853 } // namespace internal | 1841 } // namespace internal |
| 1854 } // namespace v8 | 1842 } // namespace v8 |
| OLD | NEW |