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

Side by Side Diff: src/scopes.cc

Issue 7904008: Introduce with scope and rework variable resolution. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Removed tracking of 'with' from parser and variable proxies. Created 9 years, 3 months 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/scopes.h ('K') | « src/scopes.h ('k') | src/variables.h » ('j') | 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 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 Type type, 149 Type type,
150 Handle<SerializedScopeInfo> scope_info) 150 Handle<SerializedScopeInfo> scope_info)
151 : isolate_(Isolate::Current()), 151 : isolate_(Isolate::Current()),
152 inner_scopes_(4), 152 inner_scopes_(4),
153 variables_(), 153 variables_(),
154 temps_(4), 154 temps_(4),
155 params_(4), 155 params_(4),
156 unresolved_(16), 156 unresolved_(16),
157 decls_(4), 157 decls_(4),
158 already_resolved_(true) { 158 already_resolved_(true) {
159 ASSERT(!scope_info.is_null());
160 SetDefaults(type, NULL, scope_info); 159 SetDefaults(type, NULL, scope_info);
161 if (scope_info->HasHeapAllocatedLocals()) { 160 if (!scope_info.is_null() && scope_info->HasHeapAllocatedLocals()) {
162 num_heap_slots_ = scope_info_->NumberOfContextSlots(); 161 num_heap_slots_ = scope_info_->NumberOfContextSlots();
163 } 162 }
164 AddInnerScope(inner_scope); 163 AddInnerScope(inner_scope);
165 } 164 }
166 165
167 166
168 Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name) 167 Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name)
169 : isolate_(Isolate::Current()), 168 : isolate_(Isolate::Current()),
170 inner_scopes_(1), 169 inner_scopes_(1),
171 variables_(), 170 variables_(),
(...skipping 23 matching lines...) Expand all
195 dynamics_ = NULL; 194 dynamics_ = NULL;
196 receiver_ = NULL; 195 receiver_ = NULL;
197 function_ = NULL; 196 function_ = NULL;
198 arguments_ = NULL; 197 arguments_ = NULL;
199 illegal_redecl_ = NULL; 198 illegal_redecl_ = NULL;
200 scope_inside_with_ = false; 199 scope_inside_with_ = false;
201 scope_contains_with_ = false; 200 scope_contains_with_ = false;
202 scope_calls_eval_ = false; 201 scope_calls_eval_ = false;
203 // Inherit the strict mode from the parent scope. 202 // Inherit the strict mode from the parent scope.
204 strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_; 203 strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_;
205 outer_scope_calls_eval_ = false;
206 outer_scope_calls_non_strict_eval_ = false; 204 outer_scope_calls_non_strict_eval_ = false;
207 inner_scope_calls_eval_ = false; 205 inner_scope_calls_eval_ = false;
208 outer_scope_is_eval_scope_ = false;
209 force_eager_compilation_ = false; 206 force_eager_compilation_ = false;
210 num_var_or_const_ = 0; 207 num_var_or_const_ = 0;
211 num_stack_slots_ = 0; 208 num_stack_slots_ = 0;
212 num_heap_slots_ = 0; 209 num_heap_slots_ = 0;
213 scope_info_ = scope_info; 210 scope_info_ = scope_info;
214 } 211 }
215 212
216 213
217 Scope* Scope::DeserializeScopeChain(CompilationInfo* info, 214 Scope* Scope::DeserializeScopeChain(CompilationInfo* info,
218 Scope* global_scope) { 215 Scope* global_scope) {
219 // Reconstruct the outer scope chain from a closure's context chain. 216 // Reconstruct the outer scope chain from a closure's context chain.
220 ASSERT(!info->closure().is_null()); 217 ASSERT(!info->closure().is_null());
221 Context* context = info->closure()->context(); 218 Context* context = info->closure()->context();
222 Scope* current_scope = NULL; 219 Scope* current_scope = NULL;
223 Scope* innermost_scope = NULL; 220 Scope* innermost_scope = NULL;
224 bool contains_with = false; 221 bool contains_with = false;
225 while (!context->IsGlobalContext()) { 222 while (!context->IsGlobalContext()) {
226 if (context->IsWithContext()) { 223 if (context->IsWithContext()) {
224 Scope* with_scope = new Scope(current_scope, WITH_SCOPE,
225 Handle<SerializedScopeInfo>::null());
226 current_scope = with_scope;
227 // All the inner scopes are inside a with. 227 // All the inner scopes are inside a with.
228 contains_with = true; 228 contains_with = true;
229 for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) { 229 for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) {
230 s->scope_inside_with_ = true; 230 s->scope_inside_with_ = true;
231 } 231 }
232 } else if (context->IsFunctionContext()) {
233 SerializedScopeInfo* scope_info =
234 context->closure()->shared()->scope_info();
235 current_scope = new Scope(current_scope, FUNCTION_SCOPE,
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));
232 } else { 242 } else {
233 if (context->IsFunctionContext()) { 243 ASSERT(context->IsCatchContext());
234 SerializedScopeInfo* scope_info = 244 String* name = String::cast(context->extension());
235 context->closure()->shared()->scope_info(); 245 current_scope = new Scope(current_scope, Handle<String>(name));
236 current_scope = new Scope(current_scope, FUNCTION_SCOPE,
237 Handle<SerializedScopeInfo>(scope_info));
238 } else if (context->IsBlockContext()) {
239 SerializedScopeInfo* scope_info =
240 SerializedScopeInfo::cast(context->extension());
241 current_scope = new Scope(current_scope, BLOCK_SCOPE,
242 Handle<SerializedScopeInfo>(scope_info));
243 } else {
244 ASSERT(context->IsCatchContext());
245 String* name = String::cast(context->extension());
246 current_scope = new Scope(current_scope, Handle<String>(name));
247 }
248 if (contains_with) current_scope->RecordWithStatement();
249 if (innermost_scope == NULL) innermost_scope = current_scope;
250 } 246 }
247 if (contains_with) current_scope->RecordWithStatement();
248 if (innermost_scope == NULL) innermost_scope = current_scope;
251 249
252 // Forget about a with when we move to a context for a different function. 250 // Forget about a with when we move to a context for a different function.
253 if (context->previous()->closure() != context->closure()) { 251 if (context->previous()->closure() != context->closure()) {
254 contains_with = false; 252 contains_with = false;
255 } 253 }
256 context = context->previous(); 254 context = context->previous();
257 } 255 }
258 256
259 global_scope->AddInnerScope(current_scope); 257 global_scope->AddInnerScope(current_scope);
260 return (innermost_scope == NULL) ? global_scope : innermost_scope; 258 return (innermost_scope == NULL) ? global_scope : innermost_scope;
(...skipping 13 matching lines...) Expand all
274 : FLAG_print_scopes) { 272 : FLAG_print_scopes) {
275 info->function()->scope()->Print(); 273 info->function()->scope()->Print();
276 } 274 }
277 #endif 275 #endif
278 276
279 info->SetScope(info->function()->scope()); 277 info->SetScope(info->function()->scope());
280 return true; // Can not fail. 278 return true; // Can not fail.
281 } 279 }
282 280
283 281
284 void Scope::Initialize(bool inside_with) { 282 void Scope::Initialize() {
285 ASSERT(!already_resolved()); 283 ASSERT(!already_resolved());
286 284
287 // Add this scope as a new inner scope of the outer scope. 285 // Add this scope as a new inner scope of the outer scope.
288 if (outer_scope_ != NULL) { 286 if (outer_scope_ != NULL) {
289 outer_scope_->inner_scopes_.Add(this); 287 outer_scope_->inner_scopes_.Add(this);
290 scope_inside_with_ = outer_scope_->scope_inside_with_ || inside_with; 288 scope_inside_with_ = outer_scope_->scope_inside_with_ || is_with_scope();
291 } else { 289 } else {
292 scope_inside_with_ = inside_with; 290 scope_inside_with_ = is_with_scope();
293 } 291 }
294 292
295 // Declare convenience variables. 293 // Declare convenience variables.
296 // Declare and allocate receiver (even for the global scope, and even 294 // Declare and allocate receiver (even for the global scope, and even
297 // if naccesses_ == 0). 295 // if naccesses_ == 0).
298 // NOTE: When loading parameters in the global scope, we must take 296 // NOTE: When loading parameters in the global scope, we must take
299 // care not to access them as properties of the global object, but 297 // care not to access them as properties of the global object, but
300 // instead load them directly from the stack. Currently, the only 298 // instead load them directly from the stack. Currently, the only
301 // such parameter is 'this' which is passed on the stack when 299 // such parameter is 'this' which is passed on the stack when
302 // invoking scripts 300 // invoking scripts
303 if (is_catch_scope() || is_block_scope()) { 301 if (is_declaration_scope()) {
304 ASSERT(outer_scope() != NULL);
305 receiver_ = outer_scope()->receiver();
306 } else {
307 ASSERT(is_function_scope() || 302 ASSERT(is_function_scope() ||
Kevin Millikin (Chromium) 2011/09/16 12:58:19 I don't think this ASSERT is necessary any more.
Steven 2011/09/16 18:29:52 Done.
308 is_global_scope() || 303 is_global_scope() ||
309 is_eval_scope()); 304 is_eval_scope());
310 Variable* var = 305 Variable* var =
311 variables_.Declare(this, 306 variables_.Declare(this,
312 isolate_->factory()->this_symbol(), 307 isolate_->factory()->this_symbol(),
313 Variable::VAR, 308 Variable::VAR,
314 false, 309 false,
315 Variable::THIS); 310 Variable::THIS);
316 var->AllocateTo(Variable::PARAMETER, -1); 311 var->AllocateTo(Variable::PARAMETER, -1);
317 receiver_ = var; 312 receiver_ = var;
313 } else {
314 ASSERT(outer_scope() != NULL);
315 receiver_ = outer_scope()->receiver();
318 } 316 }
319 317
320 if (is_function_scope()) { 318 if (is_function_scope()) {
321 // Declare 'arguments' variable which exists in all functions. 319 // Declare 'arguments' variable which exists in all functions.
322 // Note that it might never be accessed, in which case it won't be 320 // Note that it might never be accessed, in which case it won't be
323 // allocated during variable allocation. 321 // allocated during variable allocation.
324 variables_.Declare(this, 322 variables_.Declare(this,
325 isolate_->factory()->arguments_symbol(), 323 isolate_->factory()->arguments_symbol(),
326 Variable::VAR, 324 Variable::VAR,
327 true, 325 true,
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
436 434
437 435
438 Variable* Scope::DeclareGlobal(Handle<String> name) { 436 Variable* Scope::DeclareGlobal(Handle<String> name) {
439 ASSERT(is_global_scope()); 437 ASSERT(is_global_scope());
440 return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL, 438 return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL,
441 true, 439 true,
442 Variable::NORMAL); 440 Variable::NORMAL);
443 } 441 }
444 442
445 443
446 VariableProxy* Scope::NewUnresolved(Handle<String> name, 444 VariableProxy* Scope::NewUnresolved(Handle<String> name, int position) {
447 bool inside_with,
448 int position) {
449 // Note that we must not share the unresolved variables with 445 // Note that we must not share the unresolved variables with
450 // the same name because they may be removed selectively via 446 // the same name because they may be removed selectively via
451 // RemoveUnresolved(). 447 // RemoveUnresolved().
452 ASSERT(!already_resolved()); 448 ASSERT(!already_resolved());
453 VariableProxy* proxy = new(isolate_->zone()) VariableProxy( 449 VariableProxy* proxy = new(isolate_->zone()) VariableProxy(
454 isolate_, name, false, inside_with, position); 450 isolate_, name, false, position);
455 unresolved_.Add(proxy); 451 unresolved_.Add(proxy);
456 return proxy; 452 return proxy;
457 } 453 }
458 454
459 455
460 void Scope::RemoveUnresolved(VariableProxy* var) { 456 void Scope::RemoveUnresolved(VariableProxy* var) {
461 // Most likely (always?) any variable we want to remove 457 // Most likely (always?) any variable we want to remove
462 // was just added before, so we search backwards. 458 // was just added before, so we search backwards.
463 for (int i = unresolved_.length(); i-- > 0;) { 459 for (int i = unresolved_.length(); i-- > 0;) {
464 if (unresolved_[i] == var) { 460 if (unresolved_[i] == var) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
500 illegal_redecl_->Accept(visitor); 496 illegal_redecl_->Accept(visitor);
501 } 497 }
502 498
503 499
504 Declaration* Scope::CheckConflictingVarDeclarations() { 500 Declaration* Scope::CheckConflictingVarDeclarations() {
505 int length = decls_.length(); 501 int length = decls_.length();
506 for (int i = 0; i < length; i++) { 502 for (int i = 0; i < length; i++) {
507 Declaration* decl = decls_[i]; 503 Declaration* decl = decls_[i];
508 if (decl->mode() != Variable::VAR) continue; 504 if (decl->mode() != Variable::VAR) continue;
509 Handle<String> name = decl->proxy()->name(); 505 Handle<String> name = decl->proxy()->name();
510 bool cond = true; 506
511 for (Scope* scope = decl->scope(); cond ; scope = scope->outer_scope_) { 507 // Iterate through all scopes until and including the declaration scope.
508 Scope* previous = NULL;
509 Scope* current = decl->scope();
510 do {
512 // There is a conflict if there exists a non-VAR binding. 511 // There is a conflict if there exists a non-VAR binding.
513 Variable* other_var = scope->variables_.Lookup(name); 512 Variable* other_var = current->variables_.Lookup(name);
514 if (other_var != NULL && other_var->mode() != Variable::VAR) { 513 if (other_var != NULL && other_var->mode() != Variable::VAR) {
515 return decl; 514 return decl;
516 } 515 }
517 516 previous = current;
518 // Include declaration scope in the iteration but stop after. 517 current = current->outer_scope_;
519 if (!scope->is_block_scope() && !scope->is_catch_scope()) cond = false; 518 } while (!previous->is_declaration_scope());
520 }
521 } 519 }
522 return NULL; 520 return NULL;
523 } 521 }
524 522
525 523
526 template<class Allocator> 524 template<class Allocator>
527 void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) { 525 void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) {
528 // Collect variables in this scope. 526 // Collect variables in this scope.
529 // Note that the function_ variable - if present - is not 527 // Note that the function_ variable - if present - is not
530 // collected here but handled separately in ScopeInfo 528 // collected here but handled separately in ScopeInfo
(...skipping 27 matching lines...) Expand all
558 void Scope::AllocateVariables(Handle<Context> context) { 556 void Scope::AllocateVariables(Handle<Context> context) {
559 ASSERT(outer_scope_ == NULL); // eval or global scopes only 557 ASSERT(outer_scope_ == NULL); // eval or global scopes only
560 558
561 // 1) Propagate scope information. 559 // 1) Propagate scope information.
562 // If we are in an eval scope, we may have other outer scopes about 560 // If we are in an eval scope, we may have other outer scopes about
563 // which we don't know anything at this point. Thus we must be conservative 561 // which we don't know anything at this point. Thus we must be conservative
564 // and assume they may invoke eval themselves. Eventually we could capture 562 // and assume they may invoke eval themselves. Eventually we could capture
565 // this information in the ScopeInfo and then use it here (by traversing 563 // this information in the ScopeInfo and then use it here (by traversing
566 // the call chain stack, at compile time). 564 // the call chain stack, at compile time).
567 565
568 bool eval_scope = is_eval_scope();
569 bool outer_scope_calls_eval = false;
570 bool outer_scope_calls_non_strict_eval = false; 566 bool outer_scope_calls_non_strict_eval = false;
571 if (!is_global_scope()) { 567 if (!is_global_scope()) {
572 context->ComputeEvalScopeInfo(&outer_scope_calls_eval, 568 context->ComputeEvalScopeInfo(&outer_scope_calls_non_strict_eval);
573 &outer_scope_calls_non_strict_eval);
574 } 569 }
575 PropagateScopeInfo(outer_scope_calls_eval, 570 PropagateScopeInfo(outer_scope_calls_non_strict_eval);
576 outer_scope_calls_non_strict_eval,
577 eval_scope);
578 571
579 // 2) Resolve variables. 572 // 2) Resolve variables.
580 Scope* global_scope = NULL; 573 Scope* global_scope = NULL;
581 if (is_global_scope()) global_scope = this; 574 if (is_global_scope()) global_scope = this;
582 ResolveVariablesRecursively(global_scope, context); 575 ResolveVariablesRecursively(global_scope, context);
583 576
584 // 3) Allocate variables. 577 // 3) Allocate variables.
585 AllocateVariablesRecursively(); 578 AllocateVariablesRecursively();
586 } 579 }
587 580
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 for (Scope* s = this; s != scope; s = s->outer_scope_) { 613 for (Scope* s = this; s != scope; s = s->outer_scope_) {
621 ASSERT(s != NULL); // scope must be in the scope chain 614 ASSERT(s != NULL); // scope must be in the scope chain
622 if (s->num_heap_slots() > 0) n++; 615 if (s->num_heap_slots() > 0) n++;
623 } 616 }
624 return n; 617 return n;
625 } 618 }
626 619
627 620
628 Scope* Scope::DeclarationScope() { 621 Scope* Scope::DeclarationScope() {
629 Scope* scope = this; 622 Scope* scope = this;
630 while (scope->is_catch_scope() || 623 while (!scope->is_declaration_scope()) {
631 scope->is_block_scope()) {
632 scope = scope->outer_scope(); 624 scope = scope->outer_scope();
633 } 625 }
634 return scope; 626 return scope;
635 } 627 }
636 628
637 629
638 Handle<SerializedScopeInfo> Scope::GetSerializedScopeInfo() { 630 Handle<SerializedScopeInfo> Scope::GetSerializedScopeInfo() {
639 if (scope_info_.is_null()) { 631 if (scope_info_.is_null()) {
640 scope_info_ = SerializedScopeInfo::Create(this); 632 scope_info_ = SerializedScopeInfo::Create(this);
641 } 633 }
642 return scope_info_; 634 return scope_info_;
643 } 635 }
644 636
645 637
646 #ifdef DEBUG 638 #ifdef DEBUG
647 static const char* Header(Scope::Type type) { 639 static const char* Header(Scope::Type type) {
648 switch (type) { 640 switch (type) {
649 case Scope::EVAL_SCOPE: return "eval"; 641 case Scope::EVAL_SCOPE: return "eval";
650 case Scope::FUNCTION_SCOPE: return "function"; 642 case Scope::FUNCTION_SCOPE: return "function";
651 case Scope::GLOBAL_SCOPE: return "global"; 643 case Scope::GLOBAL_SCOPE: return "global";
652 case Scope::CATCH_SCOPE: return "catch"; 644 case Scope::CATCH_SCOPE: return "catch";
653 case Scope::BLOCK_SCOPE: return "block"; 645 case Scope::BLOCK_SCOPE: return "block";
646 case Scope::WITH_SCOPE: return "with";
654 } 647 }
655 UNREACHABLE(); 648 UNREACHABLE();
656 return NULL; 649 return NULL;
657 } 650 }
658 651
659 652
660 static void Indent(int n, const char* str) { 653 static void Indent(int n, const char* str) {
661 PrintF("%*s%s", n, "", str); 654 PrintF("%*s%s", n, "", str);
662 } 655 }
663 656
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 } 736 }
744 737
745 // Scope info. 738 // Scope info.
746 if (HasTrivialOuterContext()) { 739 if (HasTrivialOuterContext()) {
747 Indent(n1, "// scope has trivial outer context\n"); 740 Indent(n1, "// scope has trivial outer context\n");
748 } 741 }
749 if (is_strict_mode()) Indent(n1, "// strict mode scope\n"); 742 if (is_strict_mode()) Indent(n1, "// strict mode scope\n");
750 if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n"); 743 if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
751 if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n"); 744 if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
752 if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n"); 745 if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
753 if (outer_scope_calls_eval_) Indent(n1, "// outer scope calls 'eval'\n");
754 if (outer_scope_calls_non_strict_eval_) { 746 if (outer_scope_calls_non_strict_eval_) {
755 Indent(n1, "// outer scope calls 'eval' in non-strict context\n"); 747 Indent(n1, "// outer scope calls 'eval' in non-strict context\n");
756 } 748 }
757 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n"); 749 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
758 if (outer_scope_is_eval_scope_) {
759 Indent(n1, "// outer scope is 'eval' scope\n");
760 }
761 if (num_stack_slots_ > 0) { Indent(n1, "// "); 750 if (num_stack_slots_ > 0) { Indent(n1, "// ");
762 PrintF("%d stack slots\n", num_stack_slots_); } 751 PrintF("%d stack slots\n", num_stack_slots_); }
763 if (num_heap_slots_ > 0) { Indent(n1, "// "); 752 if (num_heap_slots_ > 0) { Indent(n1, "// ");
764 PrintF("%d heap slots\n", num_heap_slots_); } 753 PrintF("%d heap slots\n", num_heap_slots_); }
765 754
766 // Print locals. 755 // Print locals.
767 Indent(n1, "// function var\n"); 756 Indent(n1, "// function var\n");
768 if (function_ != NULL) { 757 if (function_ != NULL) {
769 PrintVar(n1, function_->var()); 758 PrintVar(n1, function_->var());
770 } 759 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
804 if (var == NULL) { 793 if (var == NULL) {
805 // Declare a new non-local. 794 // Declare a new non-local.
806 var = map->Declare(NULL, name, mode, true, Variable::NORMAL); 795 var = map->Declare(NULL, name, mode, true, Variable::NORMAL);
807 // Allocate it by giving it a dynamic lookup. 796 // Allocate it by giving it a dynamic lookup.
808 var->AllocateTo(Variable::LOOKUP, -1); 797 var->AllocateTo(Variable::LOOKUP, -1);
809 } 798 }
810 return var; 799 return var;
811 } 800 }
812 801
813 802
814 // Lookup a variable starting with this scope. The result is either 803 Scope::LookupResult Scope::LookupRecursive(Handle<String> name,
815 // the statically resolved variable belonging to an outer scope, or 804 Handle<Context> context,
816 // NULL. It may be NULL because a) we couldn't find a variable, or b) 805 Variable** var) {
817 // because the variable is just a guess (and may be shadowed by 806 // Try to find the variable in this scope.
818 // another variable that is introduced dynamically via an 'eval' call 807 *var = LocalLookup(name);
Kevin Millikin (Chromium) 2011/09/16 12:58:19 For some reason I prefer returning the variable an
Steven 2011/09/16 18:29:52 Yeah, after all me too. On 2011/09/16 12:58:19, Ke
819 // or a 'with' statement).
820 Variable* Scope::LookupRecursive(Handle<String> name,
821 bool from_inner_scope,
822 Variable** invalidated_local) {
823 // If we find a variable, but the current scope calls 'eval', the found
824 // variable may not be the correct one (the 'eval' may introduce a
825 // property with the same name). In that case, remember that the variable
826 // found is just a guess.
827 bool guess = scope_calls_eval_;
828 808
829 // Try to find the variable in this scope. 809 // We found a variable and we are done. (Even if there is an 'eval' in
830 Variable* var = LocalLookup(name); 810 // this scope which introduces the same variable again, the resulting
811 // variable remains the same.)
812 if (*var != NULL) return BOUND;
831 813
832 if (var != NULL) { 814 // We did not find a variable locally. Check against the function variable,
833 // We found a variable. If this is not an inner lookup, we are done. 815 // if any. We can do this for all scopes, since the function variable is
834 // (Even if there is an 'eval' in this scope which introduces the 816 // only present - if at all - for function scopes.
835 // same variable again, the resulting variable remains the same. 817 //
836 // Note that enclosing 'with' statements are handled at the call site.) 818 // This lookup corresponds to a lookup in the "intermediate" scope sitting
837 if (!from_inner_scope) 819 // between this scope and the outer scope. (ECMA-262, 3rd., requires that
838 return var; 820 // the name of named function literal is kept in an intermediate scope
839 821 // in between this scope and the next outer scope.)
840 } else { 822 LookupResult result = UNBOUND;
841 // We did not find a variable locally. Check against the function variable, 823 if (function_ != NULL && function_->name().is_identical_to(name)) {
Kevin Millikin (Chromium) 2011/09/16 12:58:19 I wonder if we could make Scope::LocalLookup check
Steven 2011/09/16 18:29:52 Unfortunately we can't. The function name is still
842 // if any. We can do this for all scopes, since the function variable is 824 *var = function_->var();
843 // only present - if at all - for function scopes. 825 result = BOUND;
844 // 826 } else if (outer_scope_ != NULL) {
845 // This lookup corresponds to a lookup in the "intermediate" scope sitting 827 result = outer_scope_->LookupRecursive(name, context, var);
846 // between this scope and the outer scope. (ECMA-262, 3rd., requires that 828 if (result == BOUND) (*var)->MarkAsAccessedFromInnerScope();
847 // the name of named function literal is kept in an intermediate scope
848 // in between this scope and the next outer scope.)
849 if (function_ != NULL && function_->name().is_identical_to(name)) {
850 var = function_->var();
851
852 } else if (outer_scope_ != NULL) {
853 var = outer_scope_->LookupRecursive(name, true, invalidated_local);
854 // We may have found a variable in an outer scope. However, if
855 // the current scope is inside a 'with', the actual variable may
856 // be a property introduced via the 'with' statement. Then, the
857 // variable we may have found is just a guess.
858 if (scope_inside_with_)
859 guess = true;
860 }
861
862 // If we did not find a variable, we are done.
863 if (var == NULL)
864 return NULL;
865 } 829 }
866 830
867 ASSERT(var != NULL); 831 if (is_with_scope()) {
868 832 // The current scope is a with scope, so the variable binding can not be
869 // If this is a lookup from an inner scope, mark the variable. 833 // statically resolved. However, note that it was necessary to do a lookup
870 if (from_inner_scope) { 834 // in the outer scope anyway, because if a binding exists in an outer scope,
871 var->MarkAsAccessedFromInnerScope(); 835 // the associated variable has to be marked as potentially being accessed
836 // from inside of an inner with scope (the property may not be in the 'with'
837 // object).
838 return DYNAMIC_LOOKUP;
Kevin Millikin (Chromium) 2011/09/16 12:58:19 And I'd prefer setting var to NULL (or returning N
Steven 2011/09/16 18:29:52 Done.
839 } else if (is_eval_scope()) {
840 // No local binding was found, no 'with' statements have been encountered
841 // and the code is executed as part of a call to 'eval'. The calling context
842 // contains scope information that we can use to determine if the variable
843 // is global, i.e. the calling context chain does not contain a binding and
844 // no 'with' contexts.
845 ASSERT(result == UNBOUND);
846 return context->GlobalIfNotShadowedByEval(name)
847 ? UNBOUND_EVAL_SHADOWED : DYNAMIC_LOOKUP;
848 } else if (calls_non_strict_eval()) {
849 // A variable binding may have been found in an outer scope, but the current
850 // scope makes a non-strict 'eval' call, so the found variable may not be
851 // the correct one (the 'eval' may introduce a binding with the same name).
852 // In that case, change the lookup result to reflect this situation.
853 if (result == BOUND) return BOUND_EVAL_SHADOWED;
854 if (result == UNBOUND) return UNBOUND_EVAL_SHADOWED;
872 } 855 }
873 856 return result;
874 // If the variable we have found is just a guess, invalidate the
875 // result. If the found variable is local, record that fact so we
876 // can generate fast code to get it if it is not shadowed by eval.
877 if (guess) {
878 if (!var->is_global()) *invalidated_local = var;
879 var = NULL;
880 }
881
882 return var;
883 } 857 }
884 858
885 859
886 void Scope::ResolveVariable(Scope* global_scope, 860 void Scope::ResolveVariable(Scope* global_scope,
887 Handle<Context> context, 861 Handle<Context> context,
888 VariableProxy* proxy) { 862 VariableProxy* proxy) {
889 ASSERT(global_scope == NULL || global_scope->is_global_scope()); 863 ASSERT(global_scope == NULL || global_scope->is_global_scope());
890 864
891 // If the proxy is already resolved there's nothing to do 865 // If the proxy is already resolved there's nothing to do
892 // (functions and consts may be resolved by the parser). 866 // (functions and consts may be resolved by the parser).
893 if (proxy->var() != NULL) return; 867 if (proxy->var() != NULL) return;
894 868
895 // Otherwise, try to resolve the variable. 869 // Otherwise, try to resolve the variable.
896 Variable* invalidated_local = NULL; 870 Variable* var = NULL;
897 Variable* var = LookupRecursive(proxy->name(), false, &invalidated_local); 871 switch (LookupRecursive(proxy->name(), context, &var)) {
872 case BOUND:
873 // We found a variable binding.
874 break;
898 875
899 if (proxy->inside_with()) { 876 case BOUND_EVAL_SHADOWED:
900 // If we are inside a local 'with' statement, all bets are off 877 // We found a variable variable binding that might be shadowed
901 // and we cannot resolve the proxy to a local variable even if 878 // by 'eval' introduced variable bindings.
902 // we found an outer matching variable. 879 if (var->is_global()) {
903 // Note that we must do a lookup anyway, because if we find one, 880 var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
904 // we must mark that variable as potentially accessed from this 881 } else {
905 // inner scope (the property may not be in the 'with' object). 882 Variable* invalidated = var;
906 var = NonLocal(proxy->name(), Variable::DYNAMIC); 883 var = NonLocal(proxy->name(), Variable::DYNAMIC_LOCAL);
884 var->set_local_if_not_shadowed(invalidated);
885 }
886 break;
907 887
908 } else { 888 case UNBOUND:
909 // We are not inside a local 'with' statement. 889 // No binding has been found. Declare a variable in global scope.
890 ASSERT(global_scope != NULL);
891 var = global_scope->DeclareGlobal(proxy->name());
892 break;
910 893
911 if (var == NULL) { 894 case UNBOUND_EVAL_SHADOWED:
912 // We did not find the variable. We have a global variable 895 // No binding has been found. But some scope makes a
913 // if we are in the global scope (we know already that we 896 // non-strict 'eval' call.
914 // are outside a 'with' statement) or if there is no way 897 var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
915 // that the variable might be introduced dynamically (through 898 break;
916 // a local or outer eval() call, or an outer 'with' statement),
917 // or we don't know about the outer scope (because we are
918 // in an eval scope).
919 if (is_global_scope() ||
920 !(scope_inside_with_ || outer_scope_is_eval_scope_ ||
921 scope_calls_eval_ || outer_scope_calls_eval_)) {
922 // We must have a global variable.
923 ASSERT(global_scope != NULL);
924 var = global_scope->DeclareGlobal(proxy->name());
925 899
926 } else if (scope_inside_with_) { 900 case DYNAMIC_LOOKUP:
927 // If we are inside a with statement we give up and look up 901 // The variable could not be resolved statically.
928 // the variable at runtime. 902 var = NonLocal(proxy->name(), Variable::DYNAMIC);
929 var = NonLocal(proxy->name(), Variable::DYNAMIC); 903 break;
930
931 } else if (invalidated_local != NULL) {
932 // No with statements are involved and we found a local
933 // variable that might be shadowed by eval introduced
934 // variables.
935 var = NonLocal(proxy->name(), Variable::DYNAMIC_LOCAL);
936 var->set_local_if_not_shadowed(invalidated_local);
937
938 } else if (outer_scope_is_eval_scope_) {
939 // No with statements and we did not find a local and the code
940 // is executed with a call to eval. The context contains
941 // scope information that we can use to determine if the
942 // variable is global if it is not shadowed by eval-introduced
943 // variables.
944 if (context->GlobalIfNotShadowedByEval(proxy->name())) {
945 var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
946
947 } else {
948 var = NonLocal(proxy->name(), Variable::DYNAMIC);
949 }
950
951 } else {
952 // No with statements and we did not find a local and the code
953 // is not executed with a call to eval. We know that this
954 // variable is global unless it is shadowed by eval-introduced
955 // variables.
956 var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
957 }
958 }
959 } 904 }
960 905
906 ASSERT(var != NULL);
961 proxy->BindTo(var); 907 proxy->BindTo(var);
962 } 908 }
963 909
964 910
965 void Scope::ResolveVariablesRecursively(Scope* global_scope, 911 void Scope::ResolveVariablesRecursively(Scope* global_scope,
966 Handle<Context> context) { 912 Handle<Context> context) {
967 ASSERT(global_scope == NULL || global_scope->is_global_scope()); 913 ASSERT(global_scope == NULL || global_scope->is_global_scope());
968 914
969 // Resolve unresolved variables for this scope. 915 // Resolve unresolved variables for this scope.
970 for (int i = 0; i < unresolved_.length(); i++) { 916 for (int i = 0; i < unresolved_.length(); i++) {
971 ResolveVariable(global_scope, context, unresolved_[i]); 917 ResolveVariable(global_scope, context, unresolved_[i]);
972 } 918 }
973 919
974 // Resolve unresolved variables for inner scopes. 920 // Resolve unresolved variables for inner scopes.
975 for (int i = 0; i < inner_scopes_.length(); i++) { 921 for (int i = 0; i < inner_scopes_.length(); i++) {
976 inner_scopes_[i]->ResolveVariablesRecursively(global_scope, context); 922 inner_scopes_[i]->ResolveVariablesRecursively(global_scope, context);
977 } 923 }
978 } 924 }
979 925
980 926
981 bool Scope::PropagateScopeInfo(bool outer_scope_calls_eval, 927 bool Scope::PropagateScopeInfo(bool outer_scope_calls_non_strict_eval ) {
982 bool outer_scope_calls_non_strict_eval,
983 bool outer_scope_is_eval_scope) {
984 if (outer_scope_calls_eval) {
985 outer_scope_calls_eval_ = true;
986 }
987
988 if (outer_scope_calls_non_strict_eval) { 928 if (outer_scope_calls_non_strict_eval) {
989 outer_scope_calls_non_strict_eval_ = true; 929 outer_scope_calls_non_strict_eval_ = true;
990 } 930 }
991 931
992 if (outer_scope_is_eval_scope) {
993 outer_scope_is_eval_scope_ = true;
994 }
995
996 bool calls_eval = scope_calls_eval_ || outer_scope_calls_eval_;
997 bool is_eval = is_eval_scope() || outer_scope_is_eval_scope_;
998 bool calls_non_strict_eval = 932 bool calls_non_strict_eval =
999 (scope_calls_eval_ && !is_strict_mode()) || 933 (scope_calls_eval_ && !is_strict_mode()) ||
1000 outer_scope_calls_non_strict_eval_; 934 outer_scope_calls_non_strict_eval_;
1001 for (int i = 0; i < inner_scopes_.length(); i++) { 935 for (int i = 0; i < inner_scopes_.length(); i++) {
1002 Scope* inner_scope = inner_scopes_[i]; 936 Scope* inner_scope = inner_scopes_[i];
1003 if (inner_scope->PropagateScopeInfo(calls_eval, 937 if (inner_scope->PropagateScopeInfo(calls_non_strict_eval)) {
1004 calls_non_strict_eval,
1005 is_eval)) {
1006 inner_scope_calls_eval_ = true; 938 inner_scope_calls_eval_ = true;
1007 } 939 }
1008 if (inner_scope->force_eager_compilation_) { 940 if (inner_scope->force_eager_compilation_) {
1009 force_eager_compilation_ = true; 941 force_eager_compilation_ = true;
1010 } 942 }
1011 } 943 }
1012 944
1013 return scope_calls_eval_ || inner_scope_calls_eval_; 945 return scope_calls_eval_ || inner_scope_calls_eval_;
1014 } 946 }
1015 947
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
1199 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && 1131 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS &&
1200 !must_have_local_context) { 1132 !must_have_local_context) {
1201 num_heap_slots_ = 0; 1133 num_heap_slots_ = 0;
1202 } 1134 }
1203 1135
1204 // Allocation done. 1136 // Allocation done.
1205 ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS); 1137 ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
1206 } 1138 }
1207 1139
1208 } } // namespace v8::internal 1140 } } // namespace v8::internal
OLDNEW
« src/scopes.h ('K') | « src/scopes.h ('k') | src/variables.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698