Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: src/scopes.cc

Issue 8508052: Static resolution of outer variables in eval code. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« src/runtime.cc ('K') | « src/scopes.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 inner_scopes_(4), 141 inner_scopes_(4),
142 variables_(), 142 variables_(),
143 temps_(4), 143 temps_(4),
144 params_(4), 144 params_(4),
145 unresolved_(16), 145 unresolved_(16),
146 decls_(4), 146 decls_(4),
147 already_resolved_(true) { 147 already_resolved_(true) {
148 SetDefaults(type, NULL, scope_info); 148 SetDefaults(type, NULL, scope_info);
149 if (!scope_info.is_null()) { 149 if (!scope_info.is_null()) {
150 num_heap_slots_ = scope_info_->ContextLength(); 150 num_heap_slots_ = scope_info_->ContextLength();
151 } else if (is_with_scope()) {
152 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
151 } 153 }
152 AddInnerScope(inner_scope); 154 AddInnerScope(inner_scope);
153 } 155 }
154 156
155 157
156 Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name) 158 Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name)
157 : isolate_(Isolate::Current()), 159 : isolate_(Isolate::Current()),
158 inner_scopes_(1), 160 inner_scopes_(1),
159 variables_(), 161 variables_(),
160 temps_(0), 162 temps_(0),
161 params_(0), 163 params_(0),
162 unresolved_(0), 164 unresolved_(0),
163 decls_(0), 165 decls_(0),
164 already_resolved_(true) { 166 already_resolved_(true) {
165 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null()); 167 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null());
166 AddInnerScope(inner_scope); 168 AddInnerScope(inner_scope);
167 ++num_var_or_const_; 169 ++num_var_or_const_;
170 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
168 Variable* variable = variables_.Declare(this, 171 Variable* variable = variables_.Declare(this,
169 catch_variable_name, 172 catch_variable_name,
170 VAR, 173 VAR,
171 true, // Valid left-hand side. 174 true, // Valid left-hand side.
172 Variable::NORMAL, 175 Variable::NORMAL,
173 kCreatedInitialized); 176 kCreatedInitialized);
174 AllocateHeapSlot(variable); 177 AllocateHeapSlot(variable);
175 } 178 }
176 179
177 180
(...skipping 16 matching lines...) Expand all
194 ? outer_scope->strict_mode_flag_ : kNonStrictMode; 197 ? outer_scope->strict_mode_flag_ : kNonStrictMode;
195 outer_scope_calls_non_strict_eval_ = false; 198 outer_scope_calls_non_strict_eval_ = false;
196 inner_scope_calls_eval_ = false; 199 inner_scope_calls_eval_ = false;
197 force_eager_compilation_ = false; 200 force_eager_compilation_ = false;
198 num_var_or_const_ = 0; 201 num_var_or_const_ = 0;
199 num_stack_slots_ = 0; 202 num_stack_slots_ = 0;
200 num_heap_slots_ = 0; 203 num_heap_slots_ = 0;
201 scope_info_ = scope_info; 204 scope_info_ = scope_info;
202 start_position_ = RelocInfo::kNoPosition; 205 start_position_ = RelocInfo::kNoPosition;
203 end_position_ = RelocInfo::kNoPosition; 206 end_position_ = RelocInfo::kNoPosition;
207 if (!scope_info.is_null()) {
208 scope_calls_eval_ = scope_info->CallsEval();
209 strict_mode_flag_ =
210 scope_info->IsStrictMode() ? kStrictMode : kNonStrictMode;
211 }
204 } 212 }
205 213
206 214
207 Scope* Scope::DeserializeScopeChain(CompilationInfo* info, 215 Scope* Scope::DeserializeScopeChain(Context* context, Scope* global_scope) {
208 Scope* global_scope) {
209 // Reconstruct the outer scope chain from a closure's context chain. 216 // Reconstruct the outer scope chain from a closure's context chain.
210 ASSERT(!info->closure().is_null());
211 Context* context = info->closure()->context();
212 Scope* current_scope = NULL; 217 Scope* current_scope = NULL;
213 Scope* innermost_scope = NULL; 218 Scope* innermost_scope = NULL;
214 bool contains_with = false; 219 bool contains_with = false;
215 while (!context->IsGlobalContext()) { 220 while (!context->IsGlobalContext()) {
216 if (context->IsWithContext()) { 221 if (context->IsWithContext()) {
217 Scope* with_scope = new Scope(current_scope, 222 Scope* with_scope = new Scope(current_scope,
218 WITH_SCOPE, 223 WITH_SCOPE,
219 Handle<ScopeInfo>::null()); 224 Handle<ScopeInfo>::null());
220 current_scope = with_scope; 225 current_scope = with_scope;
221 // All the inner scopes are inside a with. 226 // All the inner scopes are inside a with.
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 return NULL; 354 return NULL;
350 } 355 }
351 356
352 357
353 Variable* Scope::LocalLookup(Handle<String> name) { 358 Variable* Scope::LocalLookup(Handle<String> name) {
354 Variable* result = variables_.Lookup(name); 359 Variable* result = variables_.Lookup(name);
355 if (result != NULL || scope_info_.is_null()) { 360 if (result != NULL || scope_info_.is_null()) {
356 return result; 361 return result;
357 } 362 }
358 // If we have a serialized scope info, we might find the variable there. 363 // If we have a serialized scope info, we might find the variable there.
359 //
360 // We should never lookup 'arguments' in this scope as it is implicitly
361 // present in every scope.
362 ASSERT(*name != *isolate_->factory()->arguments_symbol());
363 // There should be no local slot with the given name. 364 // There should be no local slot with the given name.
364 ASSERT(scope_info_->StackSlotIndex(*name) < 0); 365 ASSERT(scope_info_->StackSlotIndex(*name) < 0);
365 366
366 // Check context slot lookup. 367 // Check context slot lookup.
367 VariableMode mode; 368 VariableMode mode;
368 InitializationFlag init_flag; 369 InitializationFlag init_flag;
369 int index = scope_info_->ContextSlotIndex(*name, &mode, &init_flag); 370 int index = scope_info_->ContextSlotIndex(*name, &mode, &init_flag);
370 if (index < 0) { 371 if (index < 0) {
371 // Check parameters. 372 // Check parameters.
372 mode = VAR; 373 mode = VAR;
373 init_flag = kCreatedInitialized; 374 init_flag = kCreatedInitialized;
374 index = scope_info_->ParameterIndex(*name); 375 index = scope_info_->ParameterIndex(*name);
375 if (index < 0) { 376 if (index < 0) return NULL;
376 // Check the function name.
377 index = scope_info_->FunctionContextSlotIndex(*name, &mode);
378 if (index < 0) return NULL;
379 }
380 } 377 }
381 378
382 Variable* var = 379 Variable* var =
383 variables_.Declare(this, 380 variables_.Declare(this,
384 name, 381 name,
385 mode, 382 mode,
386 true, 383 true,
387 Variable::NORMAL, 384 Variable::NORMAL,
388 init_flag); 385 init_flag);
389 var->AllocateTo(Variable::CONTEXT, index); 386 var->AllocateTo(Variable::CONTEXT, index);
390 return var; 387 return var;
391 } 388 }
392 389
393 390
391 Variable* Scope::LookupFunctionVar(Handle<String> name) {
392 if (function_ != NULL && function_->name().is_identical_to(name)) {
393 return function_->var();
394 } else if (!scope_info_.is_null()) {
395 // If we are backed by a scope info, try to lookup the variable there.
396 VariableMode mode;
397 int index = scope_info_->FunctionContextSlotIndex(*name, &mode);
398 if (index < 0) return NULL;
399 Variable* var = DeclareFunctionVar(name, mode);
400 var->AllocateTo(Variable::CONTEXT, index);
401 return var;
402 } else {
403 return NULL;
404 }
405 }
406
407
394 Variable* Scope::Lookup(Handle<String> name) { 408 Variable* Scope::Lookup(Handle<String> name) {
395 for (Scope* scope = this; 409 for (Scope* scope = this;
396 scope != NULL; 410 scope != NULL;
397 scope = scope->outer_scope()) { 411 scope = scope->outer_scope()) {
398 Variable* var = scope->LocalLookup(name); 412 Variable* var = scope->LocalLookup(name);
399 if (var != NULL) return var; 413 if (var != NULL) return var;
400 } 414 }
401 return NULL; 415 return NULL;
402 } 416 }
403 417
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
552 if (var->IsStackLocal()) { 566 if (var->IsStackLocal()) {
553 stack_locals->Add(var); 567 stack_locals->Add(var);
554 } else if (var->IsContextSlot()) { 568 } else if (var->IsContextSlot()) {
555 context_locals->Add(var); 569 context_locals->Add(var);
556 } 570 }
557 } 571 }
558 } 572 }
559 } 573 }
560 574
561 575
562 void Scope::AllocateVariables(Handle<Context> context) { 576 void Scope::AllocateVariables(Handle<Context> calling_context) {
563 ASSERT(outer_scope_ == NULL); // eval or global scopes only 577 ASSERT(outer_scope_ == NULL); // eval or global scopes only
564 578
565 // 1) Propagate scope information. 579 // 1) Propagate scope information.
566 // If we are in an eval scope, we may have other outer scopes about 580 // If we are in an eval scope, we may have other outer scopes about
567 // which we don't know anything at this point. Thus we must be conservative 581 // which we don't know anything at this point. Thus we must be conservative
568 // and assume they may invoke eval themselves. Eventually we could capture 582 // and assume they may invoke eval themselves. Eventually we could capture
569 // this information in the ScopeInfo and then use it here (by traversing 583 // this information in the ScopeInfo and then use it here (by traversing
570 // the call chain stack, at compile time). 584 // the call chain stack, at compile time).
571 585
572 bool outer_scope_calls_non_strict_eval = false; 586 Scope* global_scope;
573 if (!is_global_scope()) { 587 if (is_global_scope()) {
574 context->ComputeEvalScopeInfo(&outer_scope_calls_non_strict_eval); 588 global_scope = this;
589 } else {
590 global_scope = new Scope(NULL, GLOBAL_SCOPE);
591 Scope* calling_scope =
592 DeserializeScopeChain(*calling_context, global_scope);
Kevin Millikin (Chromium) 2011/11/10 12:55:21 I don't like this. It doesn't seem consistent. F
Steven 2011/11/11 08:35:04 Done.
593 calling_scope->AddInnerScope(this);
575 } 594 }
576 PropagateScopeInfo(outer_scope_calls_non_strict_eval); 595 global_scope->PropagateScopeInfo(false);
577 596
578 // 2) Resolve variables. 597 // 2) Resolve variables.
579 Scope* global_scope = NULL; 598 ResolveVariablesRecursively(global_scope);
580 if (is_global_scope()) global_scope = this;
581 ResolveVariablesRecursively(global_scope, context);
582 599
583 // 3) Allocate variables. 600 // 3) Allocate variables.
584 AllocateVariablesRecursively(); 601 AllocateVariablesRecursively();
585 } 602 }
586 603
587 604
588 bool Scope::AllowsLazyCompilation() const { 605 bool Scope::AllowsLazyCompilation() const {
589 return !force_eager_compilation_ && HasTrivialOuterContext(); 606 return !force_eager_compilation_ && HasTrivialOuterContext();
590 } 607 }
591 608
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
825 Variable::NORMAL, 842 Variable::NORMAL,
826 init_flag); 843 init_flag);
827 // Allocate it by giving it a dynamic lookup. 844 // Allocate it by giving it a dynamic lookup.
828 var->AllocateTo(Variable::LOOKUP, -1); 845 var->AllocateTo(Variable::LOOKUP, -1);
829 } 846 }
830 return var; 847 return var;
831 } 848 }
832 849
833 850
834 Variable* Scope::LookupRecursive(Handle<String> name, 851 Variable* Scope::LookupRecursive(Handle<String> name,
835 Handle<Context> context,
836 BindingKind* binding_kind) { 852 BindingKind* binding_kind) {
837 ASSERT(binding_kind != NULL); 853 ASSERT(binding_kind != NULL);
838 // Try to find the variable in this scope. 854 // Try to find the variable in this scope.
839 Variable* var = LocalLookup(name); 855 Variable* var = LocalLookup(name);
840 856
841 // We found a variable and we are done. (Even if there is an 'eval' in 857 // We found a variable and we are done. (Even if there is an 'eval' in
842 // this scope which introduces the same variable again, the resulting 858 // this scope which introduces the same variable again, the resulting
843 // variable remains the same.) 859 // variable remains the same.)
844 if (var != NULL) { 860 if (var != NULL) {
845 *binding_kind = BOUND; 861 *binding_kind = BOUND;
846 return var; 862 return var;
847 } 863 }
848 864
849 // We did not find a variable locally. Check against the function variable, 865 // We did not find a variable locally. Check against the function variable,
850 // if any. We can do this for all scopes, since the function variable is 866 // if any. We can do this for all scopes, since the function variable is
851 // only present - if at all - for function scopes. 867 // only present - if at all - for function scopes.
852 //
853 // This lookup corresponds to a lookup in the "intermediate" scope sitting
854 // between this scope and the outer scope. (ECMA-262, 3rd., requires that
855 // the name of named function literal is kept in an intermediate scope
856 // in between this scope and the next outer scope.)
857 *binding_kind = UNBOUND; 868 *binding_kind = UNBOUND;
858 if (function_ != NULL && function_->name().is_identical_to(name)) { 869 var = LookupFunctionVar(name);
859 var = function_->var(); 870 if (var != NULL) {
860 *binding_kind = BOUND; 871 *binding_kind = BOUND;
861 } else if (outer_scope_ != NULL) { 872 } else if (outer_scope_ != NULL) {
862 var = outer_scope_->LookupRecursive(name, context, binding_kind); 873 var = outer_scope_->LookupRecursive(name, binding_kind);
863 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) { 874 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) {
864 var->ForceContextAllocation(); 875 var->ForceContextAllocation();
865 } 876 }
877 } else {
878 ASSERT(is_global_scope());
866 } 879 }
867 880
868 if (is_with_scope()) { 881 if (is_with_scope()) {
869 // The current scope is a with scope, so the variable binding can not be 882 // The current scope is a with scope, so the variable binding can not be
870 // statically resolved. However, note that it was necessary to do a lookup 883 // statically resolved. However, note that it was necessary to do a lookup
871 // in the outer scope anyway, because if a binding exists in an outer scope, 884 // in the outer scope anyway, because if a binding exists in an outer scope,
872 // the associated variable has to be marked as potentially being accessed 885 // the associated variable has to be marked as potentially being accessed
873 // from inside of an inner with scope (the property may not be in the 'with' 886 // from inside of an inner with scope (the property may not be in the 'with'
874 // object). 887 // object).
875 *binding_kind = DYNAMIC_LOOKUP; 888 *binding_kind = DYNAMIC_LOOKUP;
876 return NULL; 889 return NULL;
877 } else if (is_eval_scope()) {
878 // No local binding was found, no 'with' statements have been encountered
879 // and the code is executed as part of a call to 'eval'. The calling context
880 // contains scope information that we can use to determine if the variable
881 // is global, i.e. the calling context chain does not contain a binding and
882 // no 'with' contexts.
883 ASSERT(*binding_kind == UNBOUND);
884 *binding_kind = context->GlobalIfNotShadowedByEval(name)
885 ? UNBOUND_EVAL_SHADOWED : DYNAMIC_LOOKUP;
886 return NULL;
887 } else if (calls_non_strict_eval()) { 890 } else if (calls_non_strict_eval()) {
888 // A variable binding may have been found in an outer scope, but the current 891 // A variable binding may have been found in an outer scope, but the current
889 // scope makes a non-strict 'eval' call, so the found variable may not be 892 // scope makes a non-strict 'eval' call, so the found variable may not be
890 // the correct one (the 'eval' may introduce a binding with the same name). 893 // the correct one (the 'eval' may introduce a binding with the same name).
891 // In that case, change the lookup result to reflect this situation. 894 // In that case, change the lookup result to reflect this situation.
892 if (*binding_kind == BOUND) { 895 if (*binding_kind == BOUND) {
893 *binding_kind = BOUND_EVAL_SHADOWED; 896 *binding_kind = BOUND_EVAL_SHADOWED;
894 } else if (*binding_kind == UNBOUND) { 897 } else if (*binding_kind == UNBOUND) {
895 *binding_kind = UNBOUND_EVAL_SHADOWED; 898 *binding_kind = UNBOUND_EVAL_SHADOWED;
896 } 899 }
897 } 900 }
898 return var; 901 return var;
899 } 902 }
900 903
901 904
902 void Scope::ResolveVariable(Scope* global_scope, 905 void Scope::ResolveVariable(Scope* global_scope,
903 Handle<Context> context,
904 VariableProxy* proxy) { 906 VariableProxy* proxy) {
905 ASSERT(global_scope == NULL || global_scope->is_global_scope()); 907 ASSERT(global_scope == NULL || global_scope->is_global_scope());
906 908
907 // If the proxy is already resolved there's nothing to do 909 // If the proxy is already resolved there's nothing to do
908 // (functions and consts may be resolved by the parser). 910 // (functions and consts may be resolved by the parser).
909 if (proxy->var() != NULL) return; 911 if (proxy->var() != NULL) return;
910 912
911 // Otherwise, try to resolve the variable. 913 // Otherwise, try to resolve the variable.
912 BindingKind binding_kind; 914 BindingKind binding_kind;
913 Variable* var = LookupRecursive(proxy->name(), context, &binding_kind); 915 Variable* var = LookupRecursive(proxy->name(), &binding_kind);
914 switch (binding_kind) { 916 switch (binding_kind) {
915 case BOUND: 917 case BOUND:
916 // We found a variable binding. 918 // We found a variable binding.
917 break; 919 break;
918 920
919 case BOUND_EVAL_SHADOWED: 921 case BOUND_EVAL_SHADOWED:
920 // We found a variable variable binding that might be shadowed 922 // We found a variable variable binding that might be shadowed
921 // by 'eval' introduced variable bindings. 923 // by 'eval' introduced variable bindings.
922 if (var->is_global()) { 924 if (var->is_global()) {
923 var = NonLocal(proxy->name(), DYNAMIC_GLOBAL); 925 var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
(...skipping 20 matching lines...) Expand all
944 // The variable could not be resolved statically. 946 // The variable could not be resolved statically.
945 var = NonLocal(proxy->name(), DYNAMIC); 947 var = NonLocal(proxy->name(), DYNAMIC);
946 break; 948 break;
947 } 949 }
948 950
949 ASSERT(var != NULL); 951 ASSERT(var != NULL);
950 proxy->BindTo(var); 952 proxy->BindTo(var);
951 } 953 }
952 954
953 955
954 void Scope::ResolveVariablesRecursively(Scope* global_scope, 956 void Scope::ResolveVariablesRecursively(Scope* global_scope) {
955 Handle<Context> context) {
956 ASSERT(global_scope == NULL || global_scope->is_global_scope()); 957 ASSERT(global_scope == NULL || global_scope->is_global_scope());
957 958
958 // Resolve unresolved variables for this scope. 959 // Resolve unresolved variables for this scope.
959 for (int i = 0; i < unresolved_.length(); i++) { 960 for (int i = 0; i < unresolved_.length(); i++) {
960 ResolveVariable(global_scope, context, unresolved_[i]); 961 ResolveVariable(global_scope, unresolved_[i]);
961 } 962 }
962 963
963 // Resolve unresolved variables for inner scopes. 964 // Resolve unresolved variables for inner scopes.
964 for (int i = 0; i < inner_scopes_.length(); i++) { 965 for (int i = 0; i < inner_scopes_.length(); i++) {
965 inner_scopes_[i]->ResolveVariablesRecursively(global_scope, context); 966 inner_scopes_[i]->ResolveVariablesRecursively(global_scope);
966 } 967 }
967 } 968 }
968 969
969 970
970 bool Scope::PropagateScopeInfo(bool outer_scope_calls_non_strict_eval ) { 971 bool Scope::PropagateScopeInfo(bool outer_scope_calls_non_strict_eval ) {
971 if (outer_scope_calls_non_strict_eval) { 972 if (outer_scope_calls_non_strict_eval) {
972 outer_scope_calls_non_strict_eval_ = true; 973 outer_scope_calls_non_strict_eval_ = true;
973 } 974 }
974 975
975 bool calls_non_strict_eval = 976 bool calls_non_strict_eval =
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
1180 } 1181 }
1181 1182
1182 1183
1183 int Scope::ContextLocalCount() const { 1184 int Scope::ContextLocalCount() const {
1184 if (num_heap_slots() == 0) return 0; 1185 if (num_heap_slots() == 0) return 0;
1185 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS - 1186 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS -
1186 (function_ != NULL && function_->var()->IsContextSlot() ? 1 : 0); 1187 (function_ != NULL && function_->var()->IsContextSlot() ? 1 : 0);
1187 } 1188 }
1188 1189
1189 } } // namespace v8::internal 1190 } } // namespace v8::internal
OLDNEW
« src/runtime.cc ('K') | « src/scopes.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698