| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 scope_contains_with_ = false; | 200 scope_contains_with_ = false; |
| 201 scope_calls_eval_ = false; | 201 scope_calls_eval_ = false; |
| 202 // Inherit the strict mode from the parent scope. | 202 // Inherit the strict mode from the parent scope. |
| 203 strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_; | 203 strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_; |
| 204 outer_scope_calls_eval_ = false; | 204 outer_scope_calls_eval_ = false; |
| 205 outer_scope_calls_non_strict_eval_ = false; | 205 outer_scope_calls_non_strict_eval_ = false; |
| 206 inner_scope_calls_eval_ = false; | 206 inner_scope_calls_eval_ = false; |
| 207 outer_scope_is_eval_scope_ = false; | 207 outer_scope_is_eval_scope_ = false; |
| 208 force_eager_compilation_ = false; | 208 force_eager_compilation_ = false; |
| 209 num_var_or_const_ = 0; | 209 num_var_or_const_ = 0; |
| 210 num_stack_allocs_ = 0; |
| 210 num_stack_slots_ = 0; | 211 num_stack_slots_ = 0; |
| 211 num_heap_slots_ = 0; | 212 num_heap_slots_ = 0; |
| 212 scope_info_ = scope_info; | 213 scope_info_ = scope_info; |
| 214 if (!scope_info_.is_null()) { |
| 215 source_beg_statement_pos_ = scope_info_->SourceBegStatementPos(); |
| 216 source_end_statement_pos_ = scope_info_->SourceEndStatementPos(); |
| 217 } else { |
| 218 source_beg_statement_pos_ = -1; |
| 219 source_end_statement_pos_ = -1; |
| 220 } |
| 213 } | 221 } |
| 214 | 222 |
| 215 | 223 |
| 216 Scope* Scope::DeserializeScopeChain(CompilationInfo* info, | 224 Scope* Scope::DeserializeScopeChain(CompilationInfo* info, |
| 217 Scope* global_scope) { | 225 Scope* global_scope) { |
| 218 // Reconstruct the outer scope chain from a closure's context chain. | 226 // Reconstruct the outer scope chain from a closure's context chain. |
| 219 ASSERT(!info->closure().is_null()); | 227 ASSERT(!info->closure().is_null()); |
| 220 Context* context = info->closure()->context(); | 228 Context* context = info->closure()->context(); |
| 221 Scope* current_scope = NULL; | 229 Scope* current_scope = NULL; |
| 222 Scope* innermost_scope = NULL; | 230 Scope* innermost_scope = NULL; |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 287 } | 295 } |
| 288 | 296 |
| 289 // Declare convenience variables. | 297 // Declare convenience variables. |
| 290 // Declare and allocate receiver (even for the global scope, and even | 298 // Declare and allocate receiver (even for the global scope, and even |
| 291 // if naccesses_ == 0). | 299 // if naccesses_ == 0). |
| 292 // NOTE: When loading parameters in the global scope, we must take | 300 // NOTE: When loading parameters in the global scope, we must take |
| 293 // care not to access them as properties of the global object, but | 301 // care not to access them as properties of the global object, but |
| 294 // instead load them directly from the stack. Currently, the only | 302 // instead load them directly from the stack. Currently, the only |
| 295 // such parameter is 'this' which is passed on the stack when | 303 // such parameter is 'this' which is passed on the stack when |
| 296 // invoking scripts | 304 // invoking scripts |
| 297 if (is_catch_scope()) { | 305 if (is_catch_scope() || is_with_scope()) { |
| 298 ASSERT(outer_scope() != NULL); | 306 ASSERT(outer_scope() != NULL); |
| 299 receiver_ = outer_scope()->receiver(); | 307 receiver_ = outer_scope()->receiver(); |
| 300 } else { | 308 } else { |
| 301 Variable* var = | 309 Variable* var = |
| 302 variables_.Declare(this, | 310 variables_.Declare(this, |
| 303 isolate_->factory()->this_symbol(), | 311 isolate_->factory()->this_symbol(), |
| 304 Variable::VAR, | 312 Variable::VAR, |
| 305 false, | 313 false, |
| 306 Variable::THIS); | 314 Variable::THIS); |
| 307 var->set_rewrite(NewSlot(var, Slot::PARAMETER, -1)); | 315 var->set_rewrite(NewSlot(var, Slot::PARAMETER, -1)); |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 bool Scope::HasTrivialOuterContext() const { | 548 bool Scope::HasTrivialOuterContext() const { |
| 541 Scope* outer = outer_scope_; | 549 Scope* outer = outer_scope_; |
| 542 if (outer == NULL) return true; | 550 if (outer == NULL) return true; |
| 543 // Note that the outer context may be trivial in general, but the current | 551 // Note that the outer context may be trivial in general, but the current |
| 544 // scope may be inside a 'with' statement in which case the outer context | 552 // scope may be inside a 'with' statement in which case the outer context |
| 545 // for this scope is not trivial. | 553 // for this scope is not trivial. |
| 546 return !scope_inside_with_ && outer->HasTrivialContext(); | 554 return !scope_inside_with_ && outer->HasTrivialContext(); |
| 547 } | 555 } |
| 548 | 556 |
| 549 | 557 |
| 558 bool Scope::HasContext() const { |
| 559 return num_heap_slots() > 0 || is_with_scope(); |
| 560 } |
| 561 |
| 562 |
| 550 int Scope::ContextChainLength(Scope* scope) { | 563 int Scope::ContextChainLength(Scope* scope) { |
| 551 int n = 0; | 564 int n = 0; |
| 552 for (Scope* s = this; s != scope; s = s->outer_scope_) { | 565 for (Scope* s = this; s != scope; s = s->outer_scope_) { |
| 553 ASSERT(s != NULL); // scope must be in the scope chain | 566 ASSERT(s != NULL); // scope must be in the scope chain |
| 554 if (s->num_heap_slots() > 0) n++; | 567 if (s->HasContext()) n++; |
| 555 } | 568 } |
| 556 return n; | 569 return n; |
| 557 } | 570 } |
| 558 | 571 |
| 559 | 572 |
| 560 Scope* Scope::DeclarationScope() { | 573 Scope* Scope::DeclarationScope() { |
| 561 Scope* scope = this; | 574 Scope* scope = this; |
| 562 while (scope->is_catch_scope()) { | 575 while (scope->is_catch_scope() || scope->is_with_scope()) { |
| 563 scope = scope->outer_scope(); | 576 scope = scope->outer_scope(); |
| 564 } | 577 } |
| 565 return scope; | 578 return scope; |
| 566 } | 579 } |
| 567 | 580 |
| 568 | 581 |
| 569 #ifdef DEBUG | 582 #ifdef DEBUG |
| 570 static const char* Header(Scope::Type type) { | 583 static const char* Header(Scope::Type type) { |
| 571 switch (type) { | 584 switch (type) { |
| 572 case Scope::EVAL_SCOPE: return "eval"; | 585 case Scope::EVAL_SCOPE: return "eval"; |
| 573 case Scope::FUNCTION_SCOPE: return "function"; | 586 case Scope::FUNCTION_SCOPE: return "function"; |
| 574 case Scope::GLOBAL_SCOPE: return "global"; | 587 case Scope::GLOBAL_SCOPE: return "global"; |
| 575 case Scope::CATCH_SCOPE: return "catch"; | 588 case Scope::CATCH_SCOPE: return "catch"; |
| 589 case Scope::WITH_SCOPE: return "with"; |
| 576 } | 590 } |
| 577 UNREACHABLE(); | 591 UNREACHABLE(); |
| 578 return NULL; | 592 return NULL; |
| 579 } | 593 } |
| 580 | 594 |
| 581 | 595 |
| 582 static void Indent(int n, const char* str) { | 596 static void Indent(int n, const char* str) { |
| 583 PrintF("%*s%s", n, "", str); | 597 PrintF("%*s%s", n, "", str); |
| 584 } | 598 } |
| 585 | 599 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 657 Indent(n1, "// outer scope calls 'eval' in non-strict context\n"); | 671 Indent(n1, "// outer scope calls 'eval' in non-strict context\n"); |
| 658 } | 672 } |
| 659 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n"); | 673 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n"); |
| 660 if (outer_scope_is_eval_scope_) { | 674 if (outer_scope_is_eval_scope_) { |
| 661 Indent(n1, "// outer scope is 'eval' scope\n"); | 675 Indent(n1, "// outer scope is 'eval' scope\n"); |
| 662 } | 676 } |
| 663 if (num_stack_slots_ > 0) { Indent(n1, "// "); | 677 if (num_stack_slots_ > 0) { Indent(n1, "// "); |
| 664 PrintF("%d stack slots\n", num_stack_slots_); } | 678 PrintF("%d stack slots\n", num_stack_slots_); } |
| 665 if (num_heap_slots_ > 0) { Indent(n1, "// "); | 679 if (num_heap_slots_ > 0) { Indent(n1, "// "); |
| 666 PrintF("%d heap slots\n", num_heap_slots_); } | 680 PrintF("%d heap slots\n", num_heap_slots_); } |
| 681 if (num_stack_allocs_ > 0) { Indent(n1, "// "); |
| 682 PrintF("%d stack allocs\n", num_stack_allocs_); } |
| 667 | 683 |
| 668 // Print locals. | 684 // Print locals. |
| 669 PrettyPrinter printer; | 685 PrettyPrinter printer; |
| 670 Indent(n1, "// function var\n"); | 686 Indent(n1, "// function var\n"); |
| 671 if (function_ != NULL) { | 687 if (function_ != NULL) { |
| 672 PrintVar(&printer, n1, function_); | 688 PrintVar(&printer, n1, function_); |
| 673 } | 689 } |
| 674 | 690 |
| 675 Indent(n1, "// temporary vars\n"); | 691 Indent(n1, "// temporary vars\n"); |
| 676 for (int i = 0; i < temps_.length(); i++) { | 692 for (int i = 0; i < temps_.length(); i++) { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 746 // only present - if at all - for function scopes. | 762 // only present - if at all - for function scopes. |
| 747 // | 763 // |
| 748 // This lookup corresponds to a lookup in the "intermediate" scope sitting | 764 // This lookup corresponds to a lookup in the "intermediate" scope sitting |
| 749 // between this scope and the outer scope. (ECMA-262, 3rd., requires that | 765 // between this scope and the outer scope. (ECMA-262, 3rd., requires that |
| 750 // the name of named function literal is kept in an intermediate scope | 766 // the name of named function literal is kept in an intermediate scope |
| 751 // in between this scope and the next outer scope.) | 767 // in between this scope and the next outer scope.) |
| 752 if (function_ != NULL && function_->name().is_identical_to(name)) { | 768 if (function_ != NULL && function_->name().is_identical_to(name)) { |
| 753 var = function_; | 769 var = function_; |
| 754 | 770 |
| 755 } else if (outer_scope_ != NULL) { | 771 } else if (outer_scope_ != NULL) { |
| 756 var = outer_scope_->LookupRecursive(name, true, invalidated_local); | 772 var = outer_scope_->LookupRecursive(name, |
| 773 inner_lookup || is_function_scope(), |
| 774 invalidated_local); |
| 757 // We may have found a variable in an outer scope. However, if | 775 // We may have found a variable in an outer scope. However, if |
| 758 // the current scope is inside a 'with', the actual variable may | 776 // the current scope is inside a 'with', the actual variable may |
| 759 // be a property introduced via the 'with' statement. Then, the | 777 // be a property introduced via the 'with' statement. Then, the |
| 760 // variable we may have found is just a guess. | 778 // variable we may have found is just a guess. |
| 761 if (scope_inside_with_) | 779 if (scope_inside_with_) |
| 762 guess = true; | 780 guess = true; |
| 763 } | 781 } |
| 764 | 782 |
| 765 // If we did not find a variable, we are done. | 783 // If we did not find a variable, we are done. |
| 766 if (var == NULL) | 784 if (var == NULL) |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 936 | 954 |
| 937 bool Scope::MustAllocateInContext(Variable* var) { | 955 bool Scope::MustAllocateInContext(Variable* var) { |
| 938 // If var is accessed from an inner scope, or if there is a possibility | 956 // If var is accessed from an inner scope, or if there is a possibility |
| 939 // that it might be accessed from the current or an inner scope (through | 957 // that it might be accessed from the current or an inner scope (through |
| 940 // an eval() call or a runtime with lookup), it must be allocated in the | 958 // an eval() call or a runtime with lookup), it must be allocated in the |
| 941 // context. | 959 // context. |
| 942 // | 960 // |
| 943 // Exceptions: temporary variables are never allocated in a context; | 961 // Exceptions: temporary variables are never allocated in a context; |
| 944 // catch-bound variables are always allocated in a context. | 962 // catch-bound variables are always allocated in a context. |
| 945 if (var->mode() == Variable::TEMPORARY) return false; | 963 if (var->mode() == Variable::TEMPORARY) return false; |
| 946 if (is_catch_scope()) return true; | 964 if (is_catch_scope() && !DeclarationScope()->is_function_scope()) return true; |
| 947 return var->is_accessed_from_inner_scope() || | 965 return var->is_accessed_from_inner_scope() || |
| 948 scope_calls_eval_ || | 966 scope_calls_eval_ || |
| 949 inner_scope_calls_eval_ || | 967 inner_scope_calls_eval_ || |
| 950 scope_contains_with_ || | 968 scope_contains_with_ || |
| 951 var->is_global(); | 969 var->is_global(); |
| 952 } | 970 } |
| 953 | 971 |
| 954 | 972 |
| 955 bool Scope::HasArgumentsParameter() { | 973 bool Scope::HasArgumentsParameter() { |
| 956 for (int i = 0; i < params_.length(); i++) { | 974 for (int i = 0; i < params_.length(); i++) { |
| 957 if (params_[i]->name().is_identical_to( | 975 if (params_[i]->name().is_identical_to( |
| 958 isolate_->factory()->arguments_symbol())) { | 976 isolate_->factory()->arguments_symbol())) { |
| 959 return true; | 977 return true; |
| 960 } | 978 } |
| 961 } | 979 } |
| 962 return false; | 980 return false; |
| 963 } | 981 } |
| 964 | 982 |
| 965 | 983 |
| 966 void Scope::AllocateStackSlot(Variable* var) { | 984 void Scope::AllocateStackSlot(Variable* var) { |
| 967 var->set_rewrite(NewSlot(var, Slot::LOCAL, num_stack_slots_++)); | 985 Scope* scope = DeclarationScope(); |
| 986 var->set_rewrite(NewSlot(var, Slot::LOCAL, scope->num_stack_allocs_++)); |
| 987 num_stack_slots_++; |
| 968 } | 988 } |
| 969 | 989 |
| 970 | 990 |
| 971 void Scope::AllocateHeapSlot(Variable* var) { | 991 void Scope::AllocateHeapSlot(Variable* var) { |
| 972 var->set_rewrite(NewSlot(var, Slot::CONTEXT, num_heap_slots_++)); | 992 var->set_rewrite(NewSlot(var, Slot::CONTEXT, num_heap_slots_++)); |
| 973 } | 993 } |
| 974 | 994 |
| 975 | 995 |
| 976 void Scope::AllocateParameterLocals() { | 996 void Scope::AllocateParameterLocals() { |
| 977 ASSERT(is_function_scope()); | 997 ASSERT(is_function_scope()); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1063 // allocated in the context, it must be the last slot in the context, | 1083 // allocated in the context, it must be the last slot in the context, |
| 1064 // because of the current ScopeInfo implementation (see | 1084 // because of the current ScopeInfo implementation (see |
| 1065 // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor). | 1085 // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor). |
| 1066 if (function_ != NULL) { | 1086 if (function_ != NULL) { |
| 1067 AllocateNonParameterLocal(function_); | 1087 AllocateNonParameterLocal(function_); |
| 1068 } | 1088 } |
| 1069 } | 1089 } |
| 1070 | 1090 |
| 1071 | 1091 |
| 1072 void Scope::AllocateVariablesRecursively() { | 1092 void Scope::AllocateVariablesRecursively() { |
| 1073 // Allocate variables for inner scopes. | 1093 // If scope is already resolved, we still need to allocate |
| 1094 // variables in inner scopes which might not had been resolved yet. |
| 1095 if (!already_resolved()) { |
| 1096 // The number of slots required for variables. |
| 1097 num_stack_slots_ = 0; |
| 1098 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; |
| 1099 |
| 1100 // Allocate variables for this scope. |
| 1101 // Parameters must be allocated first, if any. |
| 1102 if (is_function_scope()) AllocateParameterLocals(); |
| 1103 AllocateNonParameterLocals(); |
| 1104 |
| 1105 // Allocate context if necessary. |
| 1106 bool must_have_local_context = false; |
| 1107 if (scope_calls_eval_ || scope_contains_with_) { |
| 1108 // The context for the eval() call or 'with' statement in this scope. |
| 1109 // Unless we are in the global or an eval scope, we need a local |
| 1110 // context even if we didn't statically allocate any locals in it, |
| 1111 // and the compiler will access the context variable. If we are |
| 1112 // not in an inner scope, the scope is provided from the outside. |
| 1113 must_have_local_context = is_function_scope(); |
| 1114 } |
| 1115 |
| 1116 // If we didn't allocate any locals in the local context, then we only |
| 1117 // need the minimal number of slots if we must have a local context. |
| 1118 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && |
| 1119 !must_have_local_context) { |
| 1120 num_heap_slots_ = 0; |
| 1121 } |
| 1122 |
| 1123 // Allocation done. |
| 1124 ASSERT(num_heap_slots_ == 0 || |
| 1125 num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS); |
| 1126 } |
| 1127 |
| 1128 // Allocate variables for inner scopes. Must be done after parameters and |
| 1129 // local variables to allow reservation of stack slots for variables from |
| 1130 // nested blocks. |
| 1074 for (int i = 0; i < inner_scopes_.length(); i++) { | 1131 for (int i = 0; i < inner_scopes_.length(); i++) { |
| 1075 inner_scopes_[i]->AllocateVariablesRecursively(); | 1132 inner_scopes_[i]->AllocateVariablesRecursively(); |
| 1076 } | 1133 } |
| 1077 | |
| 1078 // If scope is already resolved, we still need to allocate | |
| 1079 // variables in inner scopes which might not had been resolved yet. | |
| 1080 if (already_resolved()) return; | |
| 1081 // The number of slots required for variables. | |
| 1082 num_stack_slots_ = 0; | |
| 1083 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS; | |
| 1084 | |
| 1085 // Allocate variables for this scope. | |
| 1086 // Parameters must be allocated first, if any. | |
| 1087 if (is_function_scope()) AllocateParameterLocals(); | |
| 1088 AllocateNonParameterLocals(); | |
| 1089 | |
| 1090 // Allocate context if necessary. | |
| 1091 bool must_have_local_context = false; | |
| 1092 if (scope_calls_eval_ || scope_contains_with_) { | |
| 1093 // The context for the eval() call or 'with' statement in this scope. | |
| 1094 // Unless we are in the global or an eval scope, we need a local | |
| 1095 // context even if we didn't statically allocate any locals in it, | |
| 1096 // and the compiler will access the context variable. If we are | |
| 1097 // not in an inner scope, the scope is provided from the outside. | |
| 1098 must_have_local_context = is_function_scope(); | |
| 1099 } | |
| 1100 | |
| 1101 // If we didn't allocate any locals in the local context, then we only | |
| 1102 // need the minimal number of slots if we must have a local context. | |
| 1103 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && | |
| 1104 !must_have_local_context) { | |
| 1105 num_heap_slots_ = 0; | |
| 1106 } | |
| 1107 | |
| 1108 // Allocation done. | |
| 1109 ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS); | |
| 1110 } | 1134 } |
| 1111 | 1135 |
| 1112 } } // namespace v8::internal | 1136 } } // namespace v8::internal |
| OLD | NEW |