| 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 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 // function scope in which we are evaluating. | 326 // function scope in which we are evaluating. |
| 327 if (context->IsDebugEvaluateContext()) { | 327 if (context->IsDebugEvaluateContext()) { |
| 328 outer_scope->set_is_debug_evaluate_scope(); | 328 outer_scope->set_is_debug_evaluate_scope(); |
| 329 } | 329 } |
| 330 } else if (context->IsScriptContext()) { | 330 } else if (context->IsScriptContext()) { |
| 331 // If we reach a script context, it's the outermost context with scope | 331 // If we reach a script context, it's the outermost context with scope |
| 332 // info. The next context will be the native context. Install the scope | 332 // info. The next context will be the native context. Install the scope |
| 333 // info of this script context onto the existing script scope to avoid | 333 // info of this script context onto the existing script scope to avoid |
| 334 // nesting script scopes. | 334 // nesting script scopes. |
| 335 Handle<ScopeInfo> scope_info(context->scope_info(), isolate); | 335 Handle<ScopeInfo> scope_info(context->scope_info(), isolate); |
| 336 script_scope->SetScriptScopeInfo(scope_info); | 336 if (deserialization_mode == DeserializationMode::kIncludingVariables) { |
| 337 script_scope->SetScriptScopeInfo(scope_info); |
| 338 } |
| 337 DCHECK(context->previous()->IsNativeContext()); | 339 DCHECK(context->previous()->IsNativeContext()); |
| 338 break; | 340 break; |
| 339 } else if (context->IsFunctionContext()) { | 341 } else if (context->IsFunctionContext()) { |
| 340 Handle<ScopeInfo> scope_info(context->scope_info(), isolate); | 342 Handle<ScopeInfo> scope_info(context->scope_info(), isolate); |
| 341 // TODO(neis): For an eval scope, we currently create an ordinary function | 343 // TODO(neis): For an eval scope, we currently create an ordinary function |
| 342 // context. This is wrong and needs to be fixed. | 344 // context. This is wrong and needs to be fixed. |
| 343 // https://bugs.chromium.org/p/v8/issues/detail?id=5295 | 345 // https://bugs.chromium.org/p/v8/issues/detail?id=5295 |
| 344 DCHECK(scope_info->scope_type() == FUNCTION_SCOPE || | 346 DCHECK(scope_info->scope_type() == FUNCTION_SCOPE || |
| 345 scope_info->scope_type() == EVAL_SCOPE); | 347 scope_info->scope_type() == EVAL_SCOPE); |
| 346 outer_scope = | 348 outer_scope = |
| (...skipping 16 matching lines...) Expand all Loading... |
| 363 DCHECK_EQ(scope_info->scope_type(), MODULE_SCOPE); | 365 DCHECK_EQ(scope_info->scope_type(), MODULE_SCOPE); |
| 364 outer_scope = new (zone) ModuleScope( | 366 outer_scope = new (zone) ModuleScope( |
| 365 isolate, Handle<ScopeInfo>(scope_info), ast_value_factory); | 367 isolate, Handle<ScopeInfo>(scope_info), ast_value_factory); |
| 366 } else { | 368 } else { |
| 367 DCHECK(context->IsCatchContext()); | 369 DCHECK(context->IsCatchContext()); |
| 368 String* name = context->catch_name(); | 370 String* name = context->catch_name(); |
| 369 outer_scope = new (zone) | 371 outer_scope = new (zone) |
| 370 Scope(zone, ast_value_factory->GetString(handle(name, isolate)), | 372 Scope(zone, ast_value_factory->GetString(handle(name, isolate)), |
| 371 Handle<ScopeInfo>(context->scope_info())); | 373 Handle<ScopeInfo>(context->scope_info())); |
| 372 } | 374 } |
| 375 if (deserialization_mode == DeserializationMode::kScopesOnly) { |
| 376 outer_scope->scope_info_ = Handle<ScopeInfo>::null(); |
| 377 } |
| 373 if (current_scope != nullptr) { | 378 if (current_scope != nullptr) { |
| 374 outer_scope->AddInnerScope(current_scope); | 379 outer_scope->AddInnerScope(current_scope); |
| 375 DCHECK_IMPLIES( | 380 DCHECK_IMPLIES( |
| 376 deserialization_mode == DeserializationMode::kKeepScopeInfo, | 381 deserialization_mode == DeserializationMode::kIncludingVariables, |
| 377 current_scope->scope_info_->HasOuterScopeInfo()); | 382 current_scope->scope_info_->HasOuterScopeInfo()); |
| 378 DCHECK_IMPLIES( | 383 DCHECK_IMPLIES( |
| 379 deserialization_mode == DeserializationMode::kKeepScopeInfo, | 384 deserialization_mode == DeserializationMode::kIncludingVariables, |
| 380 outer_scope->scope_info_->Equals( | 385 outer_scope->scope_info_->Equals( |
| 381 current_scope->scope_info_->OuterScopeInfo())); | 386 current_scope->scope_info_->OuterScopeInfo())); |
| 382 } | 387 } |
| 383 current_scope = outer_scope; | 388 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; | 389 if (innermost_scope == nullptr) innermost_scope = current_scope; |
| 388 context = context->previous(); | 390 context = context->previous(); |
| 389 } | 391 } |
| 390 | 392 |
| 391 if (innermost_scope == nullptr) return script_scope; | 393 if (innermost_scope == nullptr) return script_scope; |
| 392 script_scope->AddInnerScope(current_scope); | 394 script_scope->AddInnerScope(current_scope); |
| 393 #if DEBUG | 395 #if DEBUG |
| 394 if (deserialization_mode == DeserializationMode::kKeepScopeInfo) { | 396 if (deserialization_mode == DeserializationMode::kIncludingVariables) { |
| 395 if (script_scope->scope_info_.is_null()) { | 397 if (script_scope->scope_info_.is_null()) { |
| 396 DCHECK(!current_scope->scope_info_->HasOuterScopeInfo()); | 398 DCHECK(!current_scope->scope_info_->HasOuterScopeInfo()); |
| 397 } else { | 399 } else { |
| 398 DCHECK(!script_scope->scope_info_->HasOuterScopeInfo()); | 400 DCHECK(!script_scope->scope_info_->HasOuterScopeInfo()); |
| 399 DCHECK(script_scope->scope_info_->Equals( | 401 DCHECK(script_scope->scope_info_->Equals( |
| 400 current_scope->scope_info_->OuterScopeInfo())); | 402 current_scope->scope_info_->OuterScopeInfo())); |
| 401 } | 403 } |
| 402 } | 404 } |
| 403 #endif | 405 #endif |
| 404 return innermost_scope; | 406 return innermost_scope; |
| 405 } | 407 } |
| 406 | 408 |
| 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() { | 409 DeclarationScope* Scope::AsDeclarationScope() { |
| 448 DCHECK(is_declaration_scope()); | 410 DCHECK(is_declaration_scope()); |
| 449 return static_cast<DeclarationScope*>(this); | 411 return static_cast<DeclarationScope*>(this); |
| 450 } | 412 } |
| 451 | 413 |
| 452 const DeclarationScope* Scope::AsDeclarationScope() const { | 414 const DeclarationScope* Scope::AsDeclarationScope() const { |
| 453 DCHECK(is_declaration_scope()); | 415 DCHECK(is_declaration_scope()); |
| 454 return static_cast<const DeclarationScope*>(this); | 416 return static_cast<const DeclarationScope*>(this); |
| 455 } | 417 } |
| 456 | 418 |
| 457 ModuleScope* Scope::AsModuleScope() { | 419 ModuleScope* Scope::AsModuleScope() { |
| 458 DCHECK(is_module_scope()); | 420 DCHECK(is_module_scope()); |
| 459 return static_cast<ModuleScope*>(this); | 421 return static_cast<ModuleScope*>(this); |
| 460 } | 422 } |
| 461 | 423 |
| 462 const ModuleScope* Scope::AsModuleScope() const { | 424 const ModuleScope* Scope::AsModuleScope() const { |
| 463 DCHECK(is_module_scope()); | 425 DCHECK(is_module_scope()); |
| 464 return static_cast<const ModuleScope*>(this); | 426 return static_cast<const ModuleScope*>(this); |
| 465 } | 427 } |
| 466 | 428 |
| 467 int Scope::num_parameters() const { | 429 int Scope::num_parameters() const { |
| 468 return is_declaration_scope() ? AsDeclarationScope()->num_parameters() : 0; | 430 return is_declaration_scope() ? AsDeclarationScope()->num_parameters() : 0; |
| 469 } | 431 } |
| 470 | 432 |
| 471 void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory, | 433 void DeclarationScope::HoistSloppyBlockFunctions(AstNodeFactory* factory) { |
| 472 bool* ok) { | |
| 473 DCHECK(is_sloppy(language_mode())); | 434 DCHECK(is_sloppy(language_mode())); |
| 474 DCHECK(is_function_scope() || is_eval_scope() || is_script_scope() || | 435 DCHECK(is_function_scope() || is_eval_scope() || is_script_scope() || |
| 475 (is_block_scope() && outer_scope()->is_function_scope())); | 436 (is_block_scope() && outer_scope()->is_function_scope())); |
| 476 DCHECK(HasSimpleParameters() || is_block_scope()); | 437 DCHECK(HasSimpleParameters() || is_block_scope()); |
| 477 bool has_simple_parameters = HasSimpleParameters(); | 438 bool has_simple_parameters = HasSimpleParameters(); |
| 478 // For each variable which is used as a function declaration in a sloppy | 439 // For each variable which is used as a function declaration in a sloppy |
| 479 // block, | 440 // block, |
| 480 SloppyBlockFunctionMap* map = sloppy_block_function_map(); | 441 SloppyBlockFunctionMap* map = sloppy_block_function_map(); |
| 481 for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) { | 442 for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) { |
| 482 AstRawString* name = static_cast<AstRawString*>(p->key); | 443 AstRawString* name = static_cast<AstRawString*>(p->key); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 | 499 |
| 539 // Declare a var-style binding for the function in the outer scope | 500 // Declare a var-style binding for the function in the outer scope |
| 540 if (!var_created) { | 501 if (!var_created) { |
| 541 var_created = true; | 502 var_created = true; |
| 542 VariableProxy* proxy = NewUnresolved(factory, name); | 503 VariableProxy* proxy = NewUnresolved(factory, name); |
| 543 Declaration* declaration = | 504 Declaration* declaration = |
| 544 factory->NewVariableDeclaration(proxy, this, kNoSourcePosition); | 505 factory->NewVariableDeclaration(proxy, this, kNoSourcePosition); |
| 545 // Based on the preceding check, it doesn't matter what we pass as | 506 // Based on the preceding check, it doesn't matter what we pass as |
| 546 // allow_harmony_restrictive_generators and | 507 // allow_harmony_restrictive_generators and |
| 547 // sloppy_mode_block_scope_function_redefinition. | 508 // sloppy_mode_block_scope_function_redefinition. |
| 509 bool ok = true; |
| 548 DeclareVariable(declaration, VAR, | 510 DeclareVariable(declaration, VAR, |
| 549 Variable::DefaultInitializationFlag(VAR), false, | 511 Variable::DefaultInitializationFlag(VAR), false, |
| 550 nullptr, ok); | 512 nullptr, &ok); |
| 551 DCHECK(*ok); // Based on the preceding check, this should not fail | 513 CHECK(ok); // Based on the preceding check, this should not fail |
| 552 if (!*ok) return; | |
| 553 } | 514 } |
| 554 | 515 |
| 555 // Create VariableProxies for creating an assignment statement | 516 Expression* assignment = factory->NewAssignment( |
| 556 // (later). Read from the local lexical scope and write to the function | 517 Token::ASSIGN, NewUnresolved(factory, name), |
| 557 // scope. | 518 delegate->scope()->NewUnresolved(factory, name), kNoSourcePosition); |
| 558 delegate->set_to(NewUnresolved(factory, name)); | 519 Statement* statement = |
| 559 delegate->set_from(delegate->scope()->NewUnresolved(factory, name)); | 520 factory->NewExpressionStatement(assignment, kNoSourcePosition); |
| 521 delegate->set_statement(statement); |
| 560 } | 522 } |
| 561 } | 523 } |
| 562 } | 524 } |
| 563 | 525 |
| 564 void DeclarationScope::Analyze(ParseInfo* info, AnalyzeMode mode) { | 526 void DeclarationScope::Analyze(ParseInfo* info, AnalyzeMode mode) { |
| 565 DCHECK(info->literal() != NULL); | 527 DCHECK(info->literal() != NULL); |
| 566 DeclarationScope* scope = info->literal()->scope(); | 528 DeclarationScope* scope = info->literal()->scope(); |
| 567 | 529 |
| 530 if (!info->context().is_null() && !info->context()->IsNativeContext()) { |
| 531 if (scope->outer_scope()) { |
| 532 DeclarationScope* script_scope = new (info->zone()) |
| 533 DeclarationScope(info->zone(), info->ast_value_factory()); |
| 534 info->set_script_scope(script_scope); |
| 535 scope->ReplaceOuterScope(Scope::DeserializeScopeChain( |
| 536 info->isolate(), info->zone(), *info->context(), script_scope, |
| 537 info->ast_value_factory(), |
| 538 Scope::DeserializationMode::kIncludingVariables)); |
| 539 } else { |
| 540 DCHECK(info->context()->IsScriptContext()); |
| 541 Handle<ScopeInfo> scope_info(info->context()->scope_info(), |
| 542 info->isolate()); |
| 543 scope->SetScriptScopeInfo(scope_info); |
| 544 } |
| 545 } |
| 546 |
| 547 if (scope->is_eval_scope() && is_sloppy(scope->language_mode())) { |
| 548 AstNodeFactory factory(info->ast_value_factory()); |
| 549 scope->HoistSloppyBlockFunctions(&factory); |
| 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 |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 740 } | 724 } |
| 741 } | 725 } |
| 742 outer_closure->locals_.Rewind(top_local_); | 726 outer_closure->locals_.Rewind(top_local_); |
| 743 outer_closure->decls_.Rewind(top_decl_); | 727 outer_closure->decls_.Rewind(top_decl_); |
| 744 } | 728 } |
| 745 | 729 |
| 746 void Scope::ReplaceOuterScope(Scope* outer) { | 730 void Scope::ReplaceOuterScope(Scope* outer) { |
| 747 DCHECK_NOT_NULL(outer); | 731 DCHECK_NOT_NULL(outer); |
| 748 DCHECK_NOT_NULL(outer_scope_); | 732 DCHECK_NOT_NULL(outer_scope_); |
| 749 DCHECK(!already_resolved_); | 733 DCHECK(!already_resolved_); |
| 750 DCHECK(!outer->already_resolved_); | |
| 751 DCHECK(!outer_scope_->already_resolved_); | |
| 752 outer_scope_->RemoveInnerScope(this); | 734 outer_scope_->RemoveInnerScope(this); |
| 753 outer->AddInnerScope(this); | 735 outer->AddInnerScope(this); |
| 754 outer_scope_ = outer; | 736 outer_scope_ = outer; |
| 755 } | 737 } |
| 756 | 738 |
| 757 | 739 |
| 758 void Scope::PropagateUsageFlagsToScope(Scope* other) { | 740 void Scope::PropagateUsageFlagsToScope(Scope* other) { |
| 759 DCHECK_NOT_NULL(other); | 741 DCHECK_NOT_NULL(other); |
| 760 DCHECK(!already_resolved_); | 742 DCHECK(!already_resolved_); |
| 761 DCHECK(!other->already_resolved_); | 743 DCHECK(!other->already_resolved_); |
| (...skipping 1093 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1855 Variable* function = | 1837 Variable* function = |
| 1856 is_function_scope() ? AsDeclarationScope()->function_var() : nullptr; | 1838 is_function_scope() ? AsDeclarationScope()->function_var() : nullptr; |
| 1857 bool is_function_var_in_context = | 1839 bool is_function_var_in_context = |
| 1858 function != nullptr && function->IsContextSlot(); | 1840 function != nullptr && function->IsContextSlot(); |
| 1859 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - | 1841 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - |
| 1860 (is_function_var_in_context ? 1 : 0); | 1842 (is_function_var_in_context ? 1 : 0); |
| 1861 } | 1843 } |
| 1862 | 1844 |
| 1863 } // namespace internal | 1845 } // namespace internal |
| 1864 } // namespace v8 | 1846 } // namespace v8 |
| OLD | NEW |