Chromium Code Reviews| 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 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 139 already_resolved_(false) { | 139 already_resolved_(false) { |
| 140 SetDefaults(type, outer_scope, Handle<SerializedScopeInfo>::null()); | 140 SetDefaults(type, outer_scope, Handle<SerializedScopeInfo>::null()); |
| 141 // At some point we might want to provide outer scopes to | 141 // At some point we might want to provide outer scopes to |
| 142 // eval scopes (by walking the stack and reading the scope info). | 142 // eval scopes (by walking the stack and reading the scope info). |
| 143 // In that case, the ASSERT below needs to be adjusted. | 143 // In that case, the ASSERT below needs to be adjusted. |
| 144 ASSERT((type == GLOBAL_SCOPE || type == EVAL_SCOPE) == (outer_scope == NULL)); | 144 ASSERT((type == GLOBAL_SCOPE || type == EVAL_SCOPE) == (outer_scope == NULL)); |
| 145 ASSERT(!HasIllegalRedeclaration()); | 145 ASSERT(!HasIllegalRedeclaration()); |
| 146 } | 146 } |
| 147 | 147 |
| 148 | 148 |
| 149 Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info) | 149 Scope::Scope(Scope* inner_scope, Type type, Handle<SerializedScopeInfo> scope_in fo) |
| 150 : isolate_(Isolate::Current()), | 150 : isolate_(Isolate::Current()), |
| 151 inner_scopes_(4), | 151 inner_scopes_(4), |
| 152 variables_(), | 152 variables_(), |
| 153 temps_(4), | 153 temps_(4), |
| 154 params_(4), | 154 params_(4), |
| 155 unresolved_(16), | 155 unresolved_(16), |
| 156 decls_(4), | 156 decls_(4), |
| 157 already_resolved_(true) { | 157 already_resolved_(true) { |
| 158 ASSERT(!scope_info.is_null()); | 158 ASSERT(!scope_info.is_null()); |
| 159 SetDefaults(FUNCTION_SCOPE, NULL, scope_info); | 159 SetDefaults(type, NULL, scope_info); |
| 160 if (scope_info->HasHeapAllocatedLocals()) { | 160 if (scope_info->HasHeapAllocatedLocals()) { |
| 161 num_heap_slots_ = scope_info_->NumberOfContextSlots(); | 161 num_heap_slots_ = scope_info_->NumberOfContextSlots(); |
| 162 } | 162 } |
| 163 AddInnerScope(inner_scope); | 163 AddInnerScope(inner_scope); |
| 164 } | 164 } |
| 165 | 165 |
| 166 | 166 |
| 167 Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name) | 167 Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name) |
| 168 : isolate_(Isolate::Current()), | 168 : isolate_(Isolate::Current()), |
| 169 inner_scopes_(1), | 169 inner_scopes_(1), |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 225 if (context->IsWithContext()) { | 225 if (context->IsWithContext()) { |
| 226 // All the inner scopes are inside a with. | 226 // All the inner scopes are inside a with. |
| 227 contains_with = true; | 227 contains_with = true; |
| 228 for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) { | 228 for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) { |
| 229 s->scope_inside_with_ = true; | 229 s->scope_inside_with_ = true; |
| 230 } | 230 } |
| 231 } else { | 231 } else { |
| 232 if (context->IsFunctionContext()) { | 232 if (context->IsFunctionContext()) { |
| 233 SerializedScopeInfo* scope_info = | 233 SerializedScopeInfo* scope_info = |
| 234 context->closure()->shared()->scope_info(); | 234 context->closure()->shared()->scope_info(); |
| 235 current_scope = | 235 current_scope = new Scope(current_scope, FUNCTION_SCOPE, |
| 236 new Scope(current_scope, Handle<SerializedScopeInfo>(scope_info)); | 236 Handle<SerializedScopeInfo>(scope_info)); |
| 237 } else if (context->IsBlockContext()) { | |
| 238 SerializedScopeInfo* scope_info = | |
| 239 SerializedScopeInfo::cast(context->extension()); | |
| 240 current_scope = new Scope(current_scope, BLOCK_SCOPE, | |
| 241 Handle<SerializedScopeInfo>(scope_info)); | |
| 237 } else { | 242 } else { |
| 238 ASSERT(context->IsCatchContext()); | 243 ASSERT(context->IsCatchContext()); |
| 239 String* name = String::cast(context->extension()); | 244 String* name = String::cast(context->extension()); |
| 240 current_scope = new Scope(current_scope, Handle<String>(name)); | 245 current_scope = new Scope(current_scope, Handle<String>(name)); |
| 241 } | 246 } |
| 242 if (contains_with) current_scope->RecordWithStatement(); | 247 if (contains_with) current_scope->RecordWithStatement(); |
| 243 if (innermost_scope == NULL) innermost_scope = current_scope; | 248 if (innermost_scope == NULL) innermost_scope = current_scope; |
| 244 } | 249 } |
| 245 | 250 |
| 246 // Forget about a with when we move to a context for a different function. | 251 // Forget about a with when we move to a context for a different function. |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 287 } | 292 } |
| 288 | 293 |
| 289 // Declare convenience variables. | 294 // Declare convenience variables. |
| 290 // Declare and allocate receiver (even for the global scope, and even | 295 // Declare and allocate receiver (even for the global scope, and even |
| 291 // if naccesses_ == 0). | 296 // if naccesses_ == 0). |
| 292 // NOTE: When loading parameters in the global scope, we must take | 297 // NOTE: When loading parameters in the global scope, we must take |
| 293 // care not to access them as properties of the global object, but | 298 // care not to access them as properties of the global object, but |
| 294 // instead load them directly from the stack. Currently, the only | 299 // instead load them directly from the stack. Currently, the only |
| 295 // such parameter is 'this' which is passed on the stack when | 300 // such parameter is 'this' which is passed on the stack when |
| 296 // invoking scripts | 301 // invoking scripts |
| 297 if (is_catch_scope()) { | 302 if (is_catch_scope() || is_block_scope()) { |
| 298 ASSERT(outer_scope() != NULL); | 303 ASSERT(outer_scope() != NULL); |
| 299 receiver_ = outer_scope()->receiver(); | 304 receiver_ = outer_scope()->receiver(); |
| 300 } else { | 305 } else { |
| 306 ASSERT(is_function_scope() || | |
| 307 is_global_scope() || | |
| 308 is_eval_scope()); | |
| 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)); |
| 308 receiver_ = var; | 316 receiver_ = var; |
| 309 } | 317 } |
| 310 | 318 |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 552 for (Scope* s = this; s != scope; s = s->outer_scope_) { | 560 for (Scope* s = this; s != scope; s = s->outer_scope_) { |
| 553 ASSERT(s != NULL); // scope must be in the scope chain | 561 ASSERT(s != NULL); // scope must be in the scope chain |
| 554 if (s->num_heap_slots() > 0) n++; | 562 if (s->num_heap_slots() > 0) n++; |
| 555 } | 563 } |
| 556 return n; | 564 return n; |
| 557 } | 565 } |
| 558 | 566 |
| 559 | 567 |
| 560 Scope* Scope::DeclarationScope() { | 568 Scope* Scope::DeclarationScope() { |
| 561 Scope* scope = this; | 569 Scope* scope = this; |
| 562 while (scope->is_catch_scope()) { | 570 while (scope->is_catch_scope() || |
| 571 scope->is_block_scope()) { | |
| 563 scope = scope->outer_scope(); | 572 scope = scope->outer_scope(); |
| 564 } | 573 } |
| 565 return scope; | 574 return scope; |
| 566 } | 575 } |
| 567 | 576 |
| 568 | 577 |
| 578 Handle<SerializedScopeInfo> Scope::GetSerializedScopeInfo() { | |
| 579 if (scope_info_.is_null()) { | |
| 580 scope_info_ = SerializedScopeInfo::Create(this); | |
| 581 } | |
| 582 return scope_info_; | |
| 583 } | |
| 584 | |
| 585 | |
| 569 #ifdef DEBUG | 586 #ifdef DEBUG |
| 570 static const char* Header(Scope::Type type) { | 587 static const char* Header(Scope::Type type) { |
| 571 switch (type) { | 588 switch (type) { |
| 572 case Scope::EVAL_SCOPE: return "eval"; | 589 case Scope::EVAL_SCOPE: return "eval"; |
| 573 case Scope::FUNCTION_SCOPE: return "function"; | 590 case Scope::FUNCTION_SCOPE: return "function"; |
| 574 case Scope::GLOBAL_SCOPE: return "global"; | 591 case Scope::GLOBAL_SCOPE: return "global"; |
| 575 case Scope::CATCH_SCOPE: return "catch"; | 592 case Scope::CATCH_SCOPE: return "catch"; |
| 593 case Scope::BLOCK_SCOPE: return "block"; | |
| 576 } | 594 } |
| 577 UNREACHABLE(); | 595 UNREACHABLE(); |
| 578 return NULL; | 596 return NULL; |
| 579 } | 597 } |
| 580 | 598 |
| 581 | 599 |
| 582 static void Indent(int n, const char* str) { | 600 static void Indent(int n, const char* str) { |
| 583 PrintF("%*s%s", n, "", str); | 601 PrintF("%*s%s", n, "", str); |
| 584 } | 602 } |
| 585 | 603 |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 746 // only present - if at all - for function scopes. | 764 // only present - if at all - for function scopes. |
| 747 // | 765 // |
| 748 // This lookup corresponds to a lookup in the "intermediate" scope sitting | 766 // This lookup corresponds to a lookup in the "intermediate" scope sitting |
| 749 // between this scope and the outer scope. (ECMA-262, 3rd., requires that | 767 // 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 | 768 // the name of named function literal is kept in an intermediate scope |
| 751 // in between this scope and the next outer scope.) | 769 // in between this scope and the next outer scope.) |
| 752 if (function_ != NULL && function_->name().is_identical_to(name)) { | 770 if (function_ != NULL && function_->name().is_identical_to(name)) { |
| 753 var = function_; | 771 var = function_; |
| 754 | 772 |
| 755 } else if (outer_scope_ != NULL) { | 773 } else if (outer_scope_ != NULL) { |
| 756 var = outer_scope_->LookupRecursive(name, true, invalidated_local); | 774 var = outer_scope_->LookupRecursive( |
| 775 name, | |
| 776 is_block_scope() || is_catch_scope() ? inner_lookup : true, | |
|
Kevin Millikin (Chromium)
2011/08/10 11:19:27
This is subtle. I'd probably change all the ident
Steven
2011/08/10 12:21:00
Done.
| |
| 777 invalidated_local); | |
| 757 // We may have found a variable in an outer scope. However, if | 778 // We may have found a variable in an outer scope. However, if |
| 758 // the current scope is inside a 'with', the actual variable may | 779 // the current scope is inside a 'with', the actual variable may |
| 759 // be a property introduced via the 'with' statement. Then, the | 780 // be a property introduced via the 'with' statement. Then, the |
| 760 // variable we may have found is just a guess. | 781 // variable we may have found is just a guess. |
| 761 if (scope_inside_with_) | 782 if (scope_inside_with_) |
| 762 guess = true; | 783 guess = true; |
| 763 } | 784 } |
| 764 | 785 |
| 765 // If we did not find a variable, we are done. | 786 // If we did not find a variable, we are done. |
| 766 if (var == NULL) | 787 if (var == NULL) |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 919 | 940 |
| 920 bool Scope::MustAllocate(Variable* var) { | 941 bool Scope::MustAllocate(Variable* var) { |
| 921 // Give var a read/write use if there is a chance it might be accessed | 942 // Give var a read/write use if there is a chance it might be accessed |
| 922 // via an eval() call. This is only possible if the variable has a | 943 // via an eval() call. This is only possible if the variable has a |
| 923 // visible name. | 944 // visible name. |
| 924 if ((var->is_this() || var->name()->length() > 0) && | 945 if ((var->is_this() || var->name()->length() > 0) && |
| 925 (var->is_accessed_from_inner_scope() || | 946 (var->is_accessed_from_inner_scope() || |
| 926 scope_calls_eval_ || | 947 scope_calls_eval_ || |
| 927 inner_scope_calls_eval_ || | 948 inner_scope_calls_eval_ || |
| 928 scope_contains_with_ || | 949 scope_contains_with_ || |
| 929 is_catch_scope())) { | 950 is_catch_scope() || |
| 951 is_block_scope())) { | |
| 930 var->set_is_used(true); | 952 var->set_is_used(true); |
| 931 } | 953 } |
| 932 // Global variables do not need to be allocated. | 954 // Global variables do not need to be allocated. |
| 933 return !var->is_global() && var->is_used(); | 955 return !var->is_global() && var->is_used(); |
| 934 } | 956 } |
| 935 | 957 |
| 936 | 958 |
| 937 bool Scope::MustAllocateInContext(Variable* var) { | 959 bool Scope::MustAllocateInContext(Variable* var) { |
| 938 // If var is accessed from an inner scope, or if there is a possibility | 960 // 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 | 961 // 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 | 962 // an eval() call or a runtime with lookup), it must be allocated in the |
| 941 // context. | 963 // context. |
| 942 // | 964 // |
| 943 // Exceptions: temporary variables are never allocated in a context; | 965 // Exceptions: temporary variables are never allocated in a context; |
| 944 // catch-bound variables are always allocated in a context. | 966 // catch-bound variables are always allocated in a context. |
| 945 if (var->mode() == Variable::TEMPORARY) return false; | 967 if (var->mode() == Variable::TEMPORARY) return false; |
| 946 if (is_catch_scope()) return true; | 968 if (is_catch_scope() || is_block_scope()) return true; |
| 947 return var->is_accessed_from_inner_scope() || | 969 return var->is_accessed_from_inner_scope() || |
| 948 scope_calls_eval_ || | 970 scope_calls_eval_ || |
| 949 inner_scope_calls_eval_ || | 971 inner_scope_calls_eval_ || |
| 950 scope_contains_with_ || | 972 scope_contains_with_ || |
| 951 var->is_global(); | 973 var->is_global(); |
| 952 } | 974 } |
| 953 | 975 |
| 954 | 976 |
| 955 bool Scope::HasArgumentsParameter() { | 977 bool Scope::HasArgumentsParameter() { |
| 956 for (int i = 0; i < params_.length(); i++) { | 978 for (int i = 0; i < params_.length(); i++) { |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1103 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && | 1125 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && |
| 1104 !must_have_local_context) { | 1126 !must_have_local_context) { |
| 1105 num_heap_slots_ = 0; | 1127 num_heap_slots_ = 0; |
| 1106 } | 1128 } |
| 1107 | 1129 |
| 1108 // Allocation done. | 1130 // Allocation done. |
| 1109 ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS); | 1131 ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS); |
| 1110 } | 1132 } |
| 1111 | 1133 |
| 1112 } } // namespace v8::internal | 1134 } } // namespace v8::internal |
| OLD | NEW |