• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #include "scopes.h"
31 
32 #include "bootstrapper.h"
33 #include "compiler.h"
34 #include "prettyprinter.h"
35 #include "scopeinfo.h"
36 
37 namespace v8 {
38 namespace internal {
39 
40 // ----------------------------------------------------------------------------
41 // A Zone allocator for use with LocalsMap.
42 
43 // TODO(isolates): It is probably worth it to change the Allocator class to
44 //                 take a pointer to an isolate.
45 class ZoneAllocator: public Allocator {
46  public:
47   /* nothing to do */
~ZoneAllocator()48   virtual ~ZoneAllocator()  {}
49 
New(size_t size)50   virtual void* New(size_t size)  { return ZONE->New(static_cast<int>(size)); }
51 
52   /* ignored - Zone is freed in one fell swoop */
Delete(void * p)53   virtual void Delete(void* p)  {}
54 };
55 
56 
57 static ZoneAllocator LocalsMapAllocator;
58 
59 
60 // ----------------------------------------------------------------------------
61 // Implementation of LocalsMap
62 //
63 // Note: We are storing the handle locations as key values in the hash map.
64 //       When inserting a new variable via Declare(), we rely on the fact that
65 //       the handle location remains alive for the duration of that variable
66 //       use. Because a Variable holding a handle with the same location exists
67 //       this is ensured.
68 
Match(void * key1,void * key2)69 static bool Match(void* key1, void* key2) {
70   String* name1 = *reinterpret_cast<String**>(key1);
71   String* name2 = *reinterpret_cast<String**>(key2);
72   ASSERT(name1->IsSymbol());
73   ASSERT(name2->IsSymbol());
74   return name1 == name2;
75 }
76 
77 
78 // Dummy constructor
VariableMap(bool gotta_love_static_overloading)79 VariableMap::VariableMap(bool gotta_love_static_overloading) : HashMap() {}
80 
VariableMap()81 VariableMap::VariableMap() : HashMap(Match, &LocalsMapAllocator, 8) {}
~VariableMap()82 VariableMap::~VariableMap() {}
83 
84 
Declare(Scope * scope,Handle<String> name,Variable::Mode mode,bool is_valid_lhs,Variable::Kind kind)85 Variable* VariableMap::Declare(Scope* scope,
86                                Handle<String> name,
87                                Variable::Mode mode,
88                                bool is_valid_lhs,
89                                Variable::Kind kind) {
90   HashMap::Entry* p = HashMap::Lookup(name.location(), name->Hash(), true);
91   if (p->value == NULL) {
92     // The variable has not been declared yet -> insert it.
93     ASSERT(p->key == name.location());
94     p->value = new Variable(scope, name, mode, is_valid_lhs, kind);
95   }
96   return reinterpret_cast<Variable*>(p->value);
97 }
98 
99 
Lookup(Handle<String> name)100 Variable* VariableMap::Lookup(Handle<String> name) {
101   HashMap::Entry* p = HashMap::Lookup(name.location(), name->Hash(), false);
102   if (p != NULL) {
103     ASSERT(*reinterpret_cast<String**>(p->key) == *name);
104     ASSERT(p->value != NULL);
105     return reinterpret_cast<Variable*>(p->value);
106   }
107   return NULL;
108 }
109 
110 
111 // ----------------------------------------------------------------------------
112 // Implementation of Scope
113 
114 
115 // Dummy constructor
Scope(Type type)116 Scope::Scope(Type type)
117   : inner_scopes_(0),
118     variables_(false),
119     temps_(0),
120     params_(0),
121     unresolved_(0),
122     decls_(0) {
123   SetDefaults(type, NULL, Handle<SerializedScopeInfo>::null());
124   ASSERT(!resolved());
125 }
126 
127 
Scope(Scope * outer_scope,Type type)128 Scope::Scope(Scope* outer_scope, Type type)
129   : inner_scopes_(4),
130     variables_(),
131     temps_(4),
132     params_(4),
133     unresolved_(16),
134     decls_(4) {
135   SetDefaults(type, outer_scope, Handle<SerializedScopeInfo>::null());
136   // At some point we might want to provide outer scopes to
137   // eval scopes (by walking the stack and reading the scope info).
138   // In that case, the ASSERT below needs to be adjusted.
139   ASSERT((type == GLOBAL_SCOPE || type == EVAL_SCOPE) == (outer_scope == NULL));
140   ASSERT(!HasIllegalRedeclaration());
141   ASSERT(!resolved());
142 }
143 
144 
Scope(Scope * inner_scope,Handle<SerializedScopeInfo> scope_info)145 Scope::Scope(Scope* inner_scope, Handle<SerializedScopeInfo> scope_info)
146   : inner_scopes_(4),
147     variables_(),
148     temps_(4),
149     params_(4),
150     unresolved_(16),
151     decls_(4) {
152   ASSERT(!scope_info.is_null());
153   SetDefaults(FUNCTION_SCOPE, NULL, scope_info);
154   ASSERT(resolved());
155   if (scope_info->HasHeapAllocatedLocals()) {
156     num_heap_slots_ = scope_info_->NumberOfContextSlots();
157   }
158 
159   AddInnerScope(inner_scope);
160 
161   // This scope's arguments shadow (if present) is context-allocated if an inner
162   // scope accesses this one's parameters.  Allocate the arguments_shadow_
163   // variable if necessary.
164   Isolate* isolate = Isolate::Current();
165   Variable::Mode mode;
166   int arguments_shadow_index =
167       scope_info_->ContextSlotIndex(
168           isolate->heap()->arguments_shadow_symbol(), &mode);
169   if (arguments_shadow_index >= 0) {
170     ASSERT(mode == Variable::INTERNAL);
171     arguments_shadow_ = new Variable(
172         this,
173         isolate->factory()->arguments_shadow_symbol(),
174         Variable::INTERNAL,
175         true,
176         Variable::ARGUMENTS);
177     arguments_shadow_->set_rewrite(
178         new Slot(arguments_shadow_, Slot::CONTEXT, arguments_shadow_index));
179     arguments_shadow_->set_is_used(true);
180   }
181 }
182 
183 
SetDefaults(Type type,Scope * outer_scope,Handle<SerializedScopeInfo> scope_info)184 void Scope::SetDefaults(Type type,
185                         Scope* outer_scope,
186                         Handle<SerializedScopeInfo> scope_info) {
187   outer_scope_ = outer_scope;
188   type_ = type;
189   scope_name_ = FACTORY->empty_symbol();
190   dynamics_ = NULL;
191   receiver_ = NULL;
192   function_ = NULL;
193   arguments_ = NULL;
194   arguments_shadow_ = NULL;
195   illegal_redecl_ = NULL;
196   scope_inside_with_ = false;
197   scope_contains_with_ = false;
198   scope_calls_eval_ = false;
199   // Inherit the strict mode from the parent scope.
200   strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_;
201   outer_scope_calls_eval_ = false;
202   inner_scope_calls_eval_ = false;
203   outer_scope_is_eval_scope_ = false;
204   force_eager_compilation_ = false;
205   num_var_or_const_ = 0;
206   num_stack_slots_ = 0;
207   num_heap_slots_ = 0;
208   scope_info_ = scope_info;
209 }
210 
211 
DeserializeScopeChain(CompilationInfo * info,Scope * global_scope)212 Scope* Scope::DeserializeScopeChain(CompilationInfo* info,
213                                     Scope* global_scope) {
214   ASSERT(!info->closure().is_null());
215   // If we have a serialized scope info, reuse it.
216   Scope* innermost_scope = NULL;
217   Scope* scope = NULL;
218 
219   SerializedScopeInfo* scope_info = info->closure()->shared()->scope_info();
220   if (scope_info != SerializedScopeInfo::Empty()) {
221     JSFunction* current = *info->closure();
222     do {
223       current = current->context()->closure();
224       Handle<SerializedScopeInfo> scope_info(current->shared()->scope_info());
225       if (*scope_info != SerializedScopeInfo::Empty()) {
226         scope = new Scope(scope, scope_info);
227         if (innermost_scope == NULL) innermost_scope = scope;
228       } else {
229         ASSERT(current->context()->IsGlobalContext());
230       }
231     } while (!current->context()->IsGlobalContext());
232   }
233 
234   global_scope->AddInnerScope(scope);
235   if (innermost_scope == NULL) innermost_scope = global_scope;
236 
237   return innermost_scope;
238 }
239 
240 
Analyze(CompilationInfo * info)241 bool Scope::Analyze(CompilationInfo* info) {
242   ASSERT(info->function() != NULL);
243   Scope* top = info->function()->scope();
244 
245   while (top->outer_scope() != NULL) top = top->outer_scope();
246   top->AllocateVariables(info->calling_context());
247 
248 #ifdef DEBUG
249   if (info->isolate()->bootstrapper()->IsActive()
250           ? FLAG_print_builtin_scopes
251           : FLAG_print_scopes) {
252     info->function()->scope()->Print();
253   }
254 #endif
255 
256   info->SetScope(info->function()->scope());
257   return true;  // Can not fail.
258 }
259 
260 
Initialize(bool inside_with)261 void Scope::Initialize(bool inside_with) {
262   ASSERT(!resolved());
263 
264   // Add this scope as a new inner scope of the outer scope.
265   if (outer_scope_ != NULL) {
266     outer_scope_->inner_scopes_.Add(this);
267     scope_inside_with_ = outer_scope_->scope_inside_with_ || inside_with;
268   } else {
269     scope_inside_with_ = inside_with;
270   }
271 
272   // Declare convenience variables.
273   // Declare and allocate receiver (even for the global scope, and even
274   // if naccesses_ == 0).
275   // NOTE: When loading parameters in the global scope, we must take
276   // care not to access them as properties of the global object, but
277   // instead load them directly from the stack. Currently, the only
278   // such parameter is 'this' which is passed on the stack when
279   // invoking scripts
280   Variable* var =
281       variables_.Declare(this, FACTORY->this_symbol(), Variable::VAR,
282                          false, Variable::THIS);
283   var->set_rewrite(new Slot(var, Slot::PARAMETER, -1));
284   receiver_ = var;
285 
286   if (is_function_scope()) {
287     // Declare 'arguments' variable which exists in all functions.
288     // Note that it might never be accessed, in which case it won't be
289     // allocated during variable allocation.
290     variables_.Declare(this, FACTORY->arguments_symbol(), Variable::VAR,
291                        true, Variable::ARGUMENTS);
292   }
293 }
294 
295 
LocalLookup(Handle<String> name)296 Variable* Scope::LocalLookup(Handle<String> name) {
297   Variable* result = variables_.Lookup(name);
298   if (result != NULL || !resolved()) {
299     return result;
300   }
301   // If the scope is resolved, we can find a variable in serialized scope info.
302 
303   // We should never lookup 'arguments' in this scope
304   // as it is implicitly present in any scope.
305   ASSERT(*name != *FACTORY->arguments_symbol());
306 
307   // Assert that there is no local slot with the given name.
308   ASSERT(scope_info_->StackSlotIndex(*name) < 0);
309 
310   // Check context slot lookup.
311   Variable::Mode mode;
312   int index = scope_info_->ContextSlotIndex(*name, &mode);
313   if (index >= 0) {
314     Variable* var =
315         variables_.Declare(this, name, mode, true, Variable::NORMAL);
316     var->set_rewrite(new Slot(var, Slot::CONTEXT, index));
317     return var;
318   }
319 
320   index = scope_info_->ParameterIndex(*name);
321   if (index >= 0) {
322     // ".arguments" must be present in context slots.
323     ASSERT(arguments_shadow_ != NULL);
324     Variable* var =
325         variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL);
326     Property* rewrite =
327         new Property(new VariableProxy(arguments_shadow_),
328                      new Literal(Handle<Object>(Smi::FromInt(index))),
329                      RelocInfo::kNoPosition,
330                      Property::SYNTHETIC);
331     rewrite->set_is_arguments_access(true);
332     var->set_rewrite(rewrite);
333     return var;
334   }
335 
336   index = scope_info_->FunctionContextSlotIndex(*name);
337   if (index >= 0) {
338     // Check that there is no local slot with the given name.
339     ASSERT(scope_info_->StackSlotIndex(*name) < 0);
340     Variable* var =
341         variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL);
342     var->set_rewrite(new Slot(var, Slot::CONTEXT, index));
343     return var;
344   }
345 
346   return NULL;
347 }
348 
349 
Lookup(Handle<String> name)350 Variable* Scope::Lookup(Handle<String> name) {
351   for (Scope* scope = this;
352        scope != NULL;
353        scope = scope->outer_scope()) {
354     Variable* var = scope->LocalLookup(name);
355     if (var != NULL) return var;
356   }
357   return NULL;
358 }
359 
360 
DeclareFunctionVar(Handle<String> name)361 Variable* Scope::DeclareFunctionVar(Handle<String> name) {
362   ASSERT(is_function_scope() && function_ == NULL);
363   function_ = new Variable(this, name, Variable::CONST, true, Variable::NORMAL);
364   return function_;
365 }
366 
367 
DeclareLocal(Handle<String> name,Variable::Mode mode,LocalType type)368 Variable* Scope::DeclareLocal(Handle<String> name,
369                               Variable::Mode mode,
370                               LocalType type) {
371   // DYNAMIC variables are introduces during variable allocation,
372   // INTERNAL variables are allocated explicitly, and TEMPORARY
373   // variables are allocated via NewTemporary().
374   ASSERT(!resolved());
375   ASSERT(mode == Variable::VAR || mode == Variable::CONST);
376   if (type == VAR_OR_CONST) {
377     num_var_or_const_++;
378   }
379   return variables_.Declare(this, name, mode, true, Variable::NORMAL);
380 }
381 
382 
DeclareGlobal(Handle<String> name)383 Variable* Scope::DeclareGlobal(Handle<String> name) {
384   ASSERT(is_global_scope());
385   return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL, true,
386                             Variable::NORMAL);
387 }
388 
389 
AddParameter(Variable * var)390 void Scope::AddParameter(Variable* var) {
391   ASSERT(is_function_scope());
392   ASSERT(LocalLookup(var->name()) == var);
393   params_.Add(var);
394 }
395 
396 
NewUnresolved(Handle<String> name,bool inside_with,int position)397 VariableProxy* Scope::NewUnresolved(Handle<String> name,
398                                     bool inside_with,
399                                     int position) {
400   // Note that we must not share the unresolved variables with
401   // the same name because they may be removed selectively via
402   // RemoveUnresolved().
403   ASSERT(!resolved());
404   VariableProxy* proxy = new VariableProxy(name, false, inside_with, position);
405   unresolved_.Add(proxy);
406   return proxy;
407 }
408 
409 
RemoveUnresolved(VariableProxy * var)410 void Scope::RemoveUnresolved(VariableProxy* var) {
411   // Most likely (always?) any variable we want to remove
412   // was just added before, so we search backwards.
413   for (int i = unresolved_.length(); i-- > 0;) {
414     if (unresolved_[i] == var) {
415       unresolved_.Remove(i);
416       return;
417     }
418   }
419 }
420 
421 
NewTemporary(Handle<String> name)422 Variable* Scope::NewTemporary(Handle<String> name) {
423   ASSERT(!resolved());
424   Variable* var =
425       new Variable(this, name, Variable::TEMPORARY, true, Variable::NORMAL);
426   temps_.Add(var);
427   return var;
428 }
429 
430 
AddDeclaration(Declaration * declaration)431 void Scope::AddDeclaration(Declaration* declaration) {
432   decls_.Add(declaration);
433 }
434 
435 
SetIllegalRedeclaration(Expression * expression)436 void Scope::SetIllegalRedeclaration(Expression* expression) {
437   // Record only the first illegal redeclaration.
438   if (!HasIllegalRedeclaration()) {
439     illegal_redecl_ = expression;
440   }
441   ASSERT(HasIllegalRedeclaration());
442 }
443 
444 
VisitIllegalRedeclaration(AstVisitor * visitor)445 void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) {
446   ASSERT(HasIllegalRedeclaration());
447   illegal_redecl_->Accept(visitor);
448 }
449 
450 
451 template<class Allocator>
CollectUsedVariables(List<Variable *,Allocator> * locals)452 void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) {
453   // Collect variables in this scope.
454   // Note that the function_ variable - if present - is not
455   // collected here but handled separately in ScopeInfo
456   // which is the current user of this function).
457   for (int i = 0; i < temps_.length(); i++) {
458     Variable* var = temps_[i];
459     if (var->is_used()) {
460       locals->Add(var);
461     }
462   }
463   for (VariableMap::Entry* p = variables_.Start();
464        p != NULL;
465        p = variables_.Next(p)) {
466     Variable* var = reinterpret_cast<Variable*>(p->value);
467     if (var->is_used()) {
468       locals->Add(var);
469     }
470   }
471 }
472 
473 
474 // Make sure the method gets instantiated by the template system.
475 template void Scope::CollectUsedVariables(
476     List<Variable*, FreeStoreAllocationPolicy>* locals);
477 template void Scope::CollectUsedVariables(
478     List<Variable*, PreallocatedStorage>* locals);
479 template void Scope::CollectUsedVariables(
480     List<Variable*, ZoneListAllocationPolicy>* locals);
481 
482 
AllocateVariables(Handle<Context> context)483 void Scope::AllocateVariables(Handle<Context> context) {
484   ASSERT(outer_scope_ == NULL);  // eval or global scopes only
485 
486   // 1) Propagate scope information.
487   // If we are in an eval scope, we may have other outer scopes about
488   // which we don't know anything at this point. Thus we must be conservative
489   // and assume they may invoke eval themselves. Eventually we could capture
490   // this information in the ScopeInfo and then use it here (by traversing
491   // the call chain stack, at compile time).
492   bool eval_scope = is_eval_scope();
493   PropagateScopeInfo(eval_scope, eval_scope);
494 
495   // 2) Resolve variables.
496   Scope* global_scope = NULL;
497   if (is_global_scope()) global_scope = this;
498   ResolveVariablesRecursively(global_scope, context);
499 
500   // 3) Allocate variables.
501   AllocateVariablesRecursively();
502 }
503 
504 
AllowsLazyCompilation() const505 bool Scope::AllowsLazyCompilation() const {
506   return !force_eager_compilation_ && HasTrivialOuterContext();
507 }
508 
509 
HasTrivialContext() const510 bool Scope::HasTrivialContext() const {
511   // A function scope has a trivial context if it always is the global
512   // context. We iteratively scan out the context chain to see if
513   // there is anything that makes this scope non-trivial; otherwise we
514   // return true.
515   for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
516     if (scope->is_eval_scope()) return false;
517     if (scope->scope_inside_with_) return false;
518     if (scope->num_heap_slots_ > 0) return false;
519   }
520   return true;
521 }
522 
523 
HasTrivialOuterContext() const524 bool Scope::HasTrivialOuterContext() const {
525   Scope* outer = outer_scope_;
526   if (outer == NULL) return true;
527   // Note that the outer context may be trivial in general, but the current
528   // scope may be inside a 'with' statement in which case the outer context
529   // for this scope is not trivial.
530   return !scope_inside_with_ && outer->HasTrivialContext();
531 }
532 
533 
ContextChainLength(Scope * scope)534 int Scope::ContextChainLength(Scope* scope) {
535   int n = 0;
536   for (Scope* s = this; s != scope; s = s->outer_scope_) {
537     ASSERT(s != NULL);  // scope must be in the scope chain
538     if (s->num_heap_slots() > 0) n++;
539   }
540   return n;
541 }
542 
543 
544 #ifdef DEBUG
Header(Scope::Type type)545 static const char* Header(Scope::Type type) {
546   switch (type) {
547     case Scope::EVAL_SCOPE: return "eval";
548     case Scope::FUNCTION_SCOPE: return "function";
549     case Scope::GLOBAL_SCOPE: return "global";
550   }
551   UNREACHABLE();
552   return NULL;
553 }
554 
555 
Indent(int n,const char * str)556 static void Indent(int n, const char* str) {
557   PrintF("%*s%s", n, "", str);
558 }
559 
560 
PrintName(Handle<String> name)561 static void PrintName(Handle<String> name) {
562   SmartPointer<char> s = name->ToCString(DISALLOW_NULLS);
563   PrintF("%s", *s);
564 }
565 
566 
PrintVar(PrettyPrinter * printer,int indent,Variable * var)567 static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
568   if (var->is_used() || var->rewrite() != NULL) {
569     Indent(indent, Variable::Mode2String(var->mode()));
570     PrintF(" ");
571     PrintName(var->name());
572     PrintF(";  // ");
573     if (var->rewrite() != NULL) {
574       PrintF("%s, ", printer->Print(var->rewrite()));
575       if (var->is_accessed_from_inner_scope()) PrintF(", ");
576     }
577     if (var->is_accessed_from_inner_scope()) PrintF("inner scope access");
578     PrintF("\n");
579   }
580 }
581 
582 
PrintMap(PrettyPrinter * printer,int indent,VariableMap * map)583 static void PrintMap(PrettyPrinter* printer, int indent, VariableMap* map) {
584   for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
585     Variable* var = reinterpret_cast<Variable*>(p->value);
586     PrintVar(printer, indent, var);
587   }
588 }
589 
590 
Print(int n)591 void Scope::Print(int n) {
592   int n0 = (n > 0 ? n : 0);
593   int n1 = n0 + 2;  // indentation
594 
595   // Print header.
596   Indent(n0, Header(type_));
597   if (scope_name_->length() > 0) {
598     PrintF(" ");
599     PrintName(scope_name_);
600   }
601 
602   // Print parameters, if any.
603   if (is_function_scope()) {
604     PrintF(" (");
605     for (int i = 0; i < params_.length(); i++) {
606       if (i > 0) PrintF(", ");
607       PrintName(params_[i]->name());
608     }
609     PrintF(")");
610   }
611 
612   PrintF(" {\n");
613 
614   // Function name, if any (named function literals, only).
615   if (function_ != NULL) {
616     Indent(n1, "// (local) function name: ");
617     PrintName(function_->name());
618     PrintF("\n");
619   }
620 
621   // Scope info.
622   if (HasTrivialOuterContext()) {
623     Indent(n1, "// scope has trivial outer context\n");
624   }
625   if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
626   if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
627   if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
628   if (outer_scope_calls_eval_) Indent(n1, "// outer scope calls 'eval'\n");
629   if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
630   if (outer_scope_is_eval_scope_) {
631     Indent(n1, "// outer scope is 'eval' scope\n");
632   }
633   if (num_stack_slots_ > 0) { Indent(n1, "// ");
634   PrintF("%d stack slots\n", num_stack_slots_); }
635   if (num_heap_slots_ > 0) { Indent(n1, "// ");
636   PrintF("%d heap slots\n", num_heap_slots_); }
637 
638   // Print locals.
639   PrettyPrinter printer;
640   Indent(n1, "// function var\n");
641   if (function_ != NULL) {
642     PrintVar(&printer, n1, function_);
643   }
644 
645   Indent(n1, "// temporary vars\n");
646   for (int i = 0; i < temps_.length(); i++) {
647     PrintVar(&printer, n1, temps_[i]);
648   }
649 
650   Indent(n1, "// local vars\n");
651   PrintMap(&printer, n1, &variables_);
652 
653   Indent(n1, "// dynamic vars\n");
654   if (dynamics_ != NULL) {
655     PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC));
656     PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_LOCAL));
657     PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_GLOBAL));
658   }
659 
660   // Print inner scopes (disable by providing negative n).
661   if (n >= 0) {
662     for (int i = 0; i < inner_scopes_.length(); i++) {
663       PrintF("\n");
664       inner_scopes_[i]->Print(n1);
665     }
666   }
667 
668   Indent(n0, "}\n");
669 }
670 #endif  // DEBUG
671 
672 
NonLocal(Handle<String> name,Variable::Mode mode)673 Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) {
674   if (dynamics_ == NULL) dynamics_ = new DynamicScopePart();
675   VariableMap* map = dynamics_->GetMap(mode);
676   Variable* var = map->Lookup(name);
677   if (var == NULL) {
678     // Declare a new non-local.
679     var = map->Declare(NULL, name, mode, true, Variable::NORMAL);
680     // Allocate it by giving it a dynamic lookup.
681     var->set_rewrite(new Slot(var, Slot::LOOKUP, -1));
682   }
683   return var;
684 }
685 
686 
687 // Lookup a variable starting with this scope. The result is either
688 // the statically resolved variable belonging to an outer scope, or
689 // NULL. It may be NULL because a) we couldn't find a variable, or b)
690 // because the variable is just a guess (and may be shadowed by
691 // another variable that is introduced dynamically via an 'eval' call
692 // or a 'with' statement).
LookupRecursive(Handle<String> name,bool inner_lookup,Variable ** invalidated_local)693 Variable* Scope::LookupRecursive(Handle<String> name,
694                                  bool inner_lookup,
695                                  Variable** invalidated_local) {
696   // If we find a variable, but the current scope calls 'eval', the found
697   // variable may not be the correct one (the 'eval' may introduce a
698   // property with the same name). In that case, remember that the variable
699   // found is just a guess.
700   bool guess = scope_calls_eval_;
701 
702   // Try to find the variable in this scope.
703   Variable* var = LocalLookup(name);
704 
705   if (var != NULL) {
706     // We found a variable. If this is not an inner lookup, we are done.
707     // (Even if there is an 'eval' in this scope which introduces the
708     // same variable again, the resulting variable remains the same.
709     // Note that enclosing 'with' statements are handled at the call site.)
710     if (!inner_lookup)
711       return var;
712 
713   } else {
714     // We did not find a variable locally. Check against the function variable,
715     // if any. We can do this for all scopes, since the function variable is
716     // only present - if at all - for function scopes.
717     //
718     // This lookup corresponds to a lookup in the "intermediate" scope sitting
719     // between this scope and the outer scope. (ECMA-262, 3rd., requires that
720     // the name of named function literal is kept in an intermediate scope
721     // in between this scope and the next outer scope.)
722     if (function_ != NULL && function_->name().is_identical_to(name)) {
723       var = function_;
724 
725     } else if (outer_scope_ != NULL) {
726       var = outer_scope_->LookupRecursive(name, true, invalidated_local);
727       // We may have found a variable in an outer scope. However, if
728       // the current scope is inside a 'with', the actual variable may
729       // be a property introduced via the 'with' statement. Then, the
730       // variable we may have found is just a guess.
731       if (scope_inside_with_)
732         guess = true;
733     }
734 
735     // If we did not find a variable, we are done.
736     if (var == NULL)
737       return NULL;
738   }
739 
740   ASSERT(var != NULL);
741 
742   // If this is a lookup from an inner scope, mark the variable.
743   if (inner_lookup) {
744     var->MarkAsAccessedFromInnerScope();
745   }
746 
747   // If the variable we have found is just a guess, invalidate the
748   // result. If the found variable is local, record that fact so we
749   // can generate fast code to get it if it is not shadowed by eval.
750   if (guess) {
751     if (!var->is_global()) *invalidated_local = var;
752     var = NULL;
753   }
754 
755   return var;
756 }
757 
758 
ResolveVariable(Scope * global_scope,Handle<Context> context,VariableProxy * proxy)759 void Scope::ResolveVariable(Scope* global_scope,
760                             Handle<Context> context,
761                             VariableProxy* proxy) {
762   ASSERT(global_scope == NULL || global_scope->is_global_scope());
763 
764   // If the proxy is already resolved there's nothing to do
765   // (functions and consts may be resolved by the parser).
766   if (proxy->var() != NULL) return;
767 
768   // Otherwise, try to resolve the variable.
769   Variable* invalidated_local = NULL;
770   Variable* var = LookupRecursive(proxy->name(), false, &invalidated_local);
771 
772   if (proxy->inside_with()) {
773     // If we are inside a local 'with' statement, all bets are off
774     // and we cannot resolve the proxy to a local variable even if
775     // we found an outer matching variable.
776     // Note that we must do a lookup anyway, because if we find one,
777     // we must mark that variable as potentially accessed from this
778     // inner scope (the property may not be in the 'with' object).
779     var = NonLocal(proxy->name(), Variable::DYNAMIC);
780 
781   } else {
782     // We are not inside a local 'with' statement.
783 
784     if (var == NULL) {
785       // We did not find the variable. We have a global variable
786       // if we are in the global scope (we know already that we
787       // are outside a 'with' statement) or if there is no way
788       // that the variable might be introduced dynamically (through
789       // a local or outer eval() call, or an outer 'with' statement),
790       // or we don't know about the outer scope (because we are
791       // in an eval scope).
792       if (is_global_scope() ||
793           !(scope_inside_with_ || outer_scope_is_eval_scope_ ||
794             scope_calls_eval_ || outer_scope_calls_eval_)) {
795         // We must have a global variable.
796         ASSERT(global_scope != NULL);
797         var = global_scope->DeclareGlobal(proxy->name());
798 
799       } else if (scope_inside_with_) {
800         // If we are inside a with statement we give up and look up
801         // the variable at runtime.
802         var = NonLocal(proxy->name(), Variable::DYNAMIC);
803 
804       } else if (invalidated_local != NULL) {
805         // No with statements are involved and we found a local
806         // variable that might be shadowed by eval introduced
807         // variables.
808         var = NonLocal(proxy->name(), Variable::DYNAMIC_LOCAL);
809         var->set_local_if_not_shadowed(invalidated_local);
810 
811       } else if (outer_scope_is_eval_scope_) {
812         // No with statements and we did not find a local and the code
813         // is executed with a call to eval.  The context contains
814         // scope information that we can use to determine if the
815         // variable is global if it is not shadowed by eval-introduced
816         // variables.
817         if (context->GlobalIfNotShadowedByEval(proxy->name())) {
818           var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
819 
820         } else {
821           var = NonLocal(proxy->name(), Variable::DYNAMIC);
822         }
823 
824       } else {
825         // No with statements and we did not find a local and the code
826         // is not executed with a call to eval.  We know that this
827         // variable is global unless it is shadowed by eval-introduced
828         // variables.
829         var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
830       }
831     }
832   }
833 
834   proxy->BindTo(var);
835 }
836 
837 
ResolveVariablesRecursively(Scope * global_scope,Handle<Context> context)838 void Scope::ResolveVariablesRecursively(Scope* global_scope,
839                                         Handle<Context> context) {
840   ASSERT(global_scope == NULL || global_scope->is_global_scope());
841 
842   // Resolve unresolved variables for this scope.
843   for (int i = 0; i < unresolved_.length(); i++) {
844     ResolveVariable(global_scope, context, unresolved_[i]);
845   }
846 
847   // Resolve unresolved variables for inner scopes.
848   for (int i = 0; i < inner_scopes_.length(); i++) {
849     inner_scopes_[i]->ResolveVariablesRecursively(global_scope, context);
850   }
851 }
852 
853 
PropagateScopeInfo(bool outer_scope_calls_eval,bool outer_scope_is_eval_scope)854 bool Scope::PropagateScopeInfo(bool outer_scope_calls_eval,
855                                bool outer_scope_is_eval_scope) {
856   if (outer_scope_calls_eval) {
857     outer_scope_calls_eval_ = true;
858   }
859 
860   if (outer_scope_is_eval_scope) {
861     outer_scope_is_eval_scope_ = true;
862   }
863 
864   bool calls_eval = scope_calls_eval_ || outer_scope_calls_eval_;
865   bool is_eval = is_eval_scope() || outer_scope_is_eval_scope_;
866   for (int i = 0; i < inner_scopes_.length(); i++) {
867     Scope* inner_scope = inner_scopes_[i];
868     if (inner_scope->PropagateScopeInfo(calls_eval, is_eval)) {
869       inner_scope_calls_eval_ = true;
870     }
871     if (inner_scope->force_eager_compilation_) {
872       force_eager_compilation_ = true;
873     }
874   }
875 
876   return scope_calls_eval_ || inner_scope_calls_eval_;
877 }
878 
879 
MustAllocate(Variable * var)880 bool Scope::MustAllocate(Variable* var) {
881   // Give var a read/write use if there is a chance it might be accessed
882   // via an eval() call.  This is only possible if the variable has a
883   // visible name.
884   if ((var->is_this() || var->name()->length() > 0) &&
885       (var->is_accessed_from_inner_scope() ||
886        scope_calls_eval_ || inner_scope_calls_eval_ ||
887        scope_contains_with_)) {
888     var->set_is_used(true);
889   }
890   // Global variables do not need to be allocated.
891   return !var->is_global() && var->is_used();
892 }
893 
894 
MustAllocateInContext(Variable * var)895 bool Scope::MustAllocateInContext(Variable* var) {
896   // If var is accessed from an inner scope, or if there is a
897   // possibility that it might be accessed from the current or an inner
898   // scope (through an eval() call), it must be allocated in the
899   // context.  Exception: temporary variables are not allocated in the
900   // context.
901   return
902     var->mode() != Variable::TEMPORARY &&
903     (var->is_accessed_from_inner_scope() ||
904      scope_calls_eval_ || inner_scope_calls_eval_ ||
905      scope_contains_with_ || var->is_global());
906 }
907 
908 
HasArgumentsParameter()909 bool Scope::HasArgumentsParameter() {
910   for (int i = 0; i < params_.length(); i++) {
911     if (params_[i]->name().is_identical_to(FACTORY->arguments_symbol()))
912       return true;
913   }
914   return false;
915 }
916 
917 
AllocateStackSlot(Variable * var)918 void Scope::AllocateStackSlot(Variable* var) {
919   var->set_rewrite(new Slot(var, Slot::LOCAL, num_stack_slots_++));
920 }
921 
922 
AllocateHeapSlot(Variable * var)923 void Scope::AllocateHeapSlot(Variable* var) {
924   var->set_rewrite(new Slot(var, Slot::CONTEXT, num_heap_slots_++));
925 }
926 
927 
AllocateParameterLocals()928 void Scope::AllocateParameterLocals() {
929   ASSERT(is_function_scope());
930   Variable* arguments = LocalLookup(FACTORY->arguments_symbol());
931   ASSERT(arguments != NULL);  // functions have 'arguments' declared implicitly
932 
933   // Parameters are rewritten to arguments[i] if 'arguments' is used in
934   // a non-strict mode function. Strict mode code doesn't alias arguments.
935   bool rewrite_parameters = false;
936 
937   if (MustAllocate(arguments) && !HasArgumentsParameter()) {
938     // 'arguments' is used. Unless there is also a parameter called
939     // 'arguments', we must be conservative and access all parameters via
940     // the arguments object: The i'th parameter is rewritten into
941     // '.arguments[i]' (*). If we have a parameter named 'arguments', a
942     // (new) value is always assigned to it via the function
943     // invocation. Then 'arguments' denotes that specific parameter value
944     // and cannot be used to access the parameters, which is why we don't
945     // need to rewrite in that case.
946     //
947     // (*) Instead of having a parameter called 'arguments', we may have an
948     // assignment to 'arguments' in the function body, at some arbitrary
949     // point in time (possibly through an 'eval()' call!). After that
950     // assignment any re-write of parameters would be invalid (was bug
951     // 881452). Thus, we introduce a shadow '.arguments'
952     // variable which also points to the arguments object. For rewrites we
953     // use '.arguments' which remains valid even if we assign to
954     // 'arguments'. To summarize: If we need to rewrite, we allocate an
955     // 'arguments' object dynamically upon function invocation. The compiler
956     // introduces 2 local variables 'arguments' and '.arguments', both of
957     // which originally point to the arguments object that was
958     // allocated. All parameters are rewritten into property accesses via
959     // the '.arguments' variable. Thus, any changes to properties of
960     // 'arguments' are reflected in the variables and vice versa. If the
961     // 'arguments' variable is changed, '.arguments' still points to the
962     // correct arguments object and the rewrites still work.
963 
964     // We are using 'arguments'. Tell the code generator that is needs to
965     // allocate the arguments object by setting 'arguments_'.
966     arguments_ = arguments;
967 
968     // In strict mode 'arguments' does not alias formal parameters.
969     // Therefore in strict mode we allocate parameters as if 'arguments'
970     // were not used.
971     rewrite_parameters = !is_strict_mode();
972   }
973 
974   if (rewrite_parameters) {
975     // We also need the '.arguments' shadow variable. Declare it and create
976     // and bind the corresponding proxy. It's ok to declare it only now
977     // because it's a local variable that is allocated after the parameters
978     // have been allocated.
979     //
980     // Note: This is "almost" at temporary variable but we cannot use
981     // NewTemporary() because the mode needs to be INTERNAL since this
982     // variable may be allocated in the heap-allocated context (temporaries
983     // are never allocated in the context).
984     arguments_shadow_ = new Variable(this,
985                                      FACTORY->arguments_shadow_symbol(),
986                                      Variable::INTERNAL,
987                                      true,
988                                      Variable::ARGUMENTS);
989     arguments_shadow_->set_is_used(true);
990     temps_.Add(arguments_shadow_);
991 
992     // Allocate the parameters by rewriting them into '.arguments[i]' accesses.
993     for (int i = 0; i < params_.length(); i++) {
994       Variable* var = params_[i];
995       ASSERT(var->scope() == this);
996       if (MustAllocate(var)) {
997         if (MustAllocateInContext(var)) {
998           // It is ok to set this only now, because arguments is a local
999           // variable that is allocated after the parameters have been
1000           // allocated.
1001           arguments_shadow_->MarkAsAccessedFromInnerScope();
1002         }
1003         Property* rewrite =
1004             new Property(new VariableProxy(arguments_shadow_),
1005                          new Literal(Handle<Object>(Smi::FromInt(i))),
1006                          RelocInfo::kNoPosition,
1007                          Property::SYNTHETIC);
1008         rewrite->set_is_arguments_access(true);
1009         var->set_rewrite(rewrite);
1010       }
1011     }
1012 
1013   } else {
1014     // The arguments object is not used, so we can access parameters directly.
1015     // The same parameter may occur multiple times in the parameters_ list.
1016     // If it does, and if it is not copied into the context object, it must
1017     // receive the highest parameter index for that parameter; thus iteration
1018     // order is relevant!
1019     for (int i = 0; i < params_.length(); i++) {
1020       Variable* var = params_[i];
1021       ASSERT(var->scope() == this);
1022       if (MustAllocate(var)) {
1023         if (MustAllocateInContext(var)) {
1024           ASSERT(var->rewrite() == NULL ||
1025                  (var->AsSlot() != NULL &&
1026                   var->AsSlot()->type() == Slot::CONTEXT));
1027           if (var->rewrite() == NULL) {
1028             // Only set the heap allocation if the parameter has not
1029             // been allocated yet.
1030             AllocateHeapSlot(var);
1031           }
1032         } else {
1033           ASSERT(var->rewrite() == NULL ||
1034                  (var->AsSlot() != NULL &&
1035                   var->AsSlot()->type() == Slot::PARAMETER));
1036           // Set the parameter index always, even if the parameter
1037           // was seen before! (We need to access the actual parameter
1038           // supplied for the last occurrence of a multiply declared
1039           // parameter.)
1040           var->set_rewrite(new Slot(var, Slot::PARAMETER, i));
1041         }
1042       }
1043     }
1044   }
1045 }
1046 
1047 
AllocateNonParameterLocal(Variable * var)1048 void Scope::AllocateNonParameterLocal(Variable* var) {
1049   ASSERT(var->scope() == this);
1050   ASSERT(var->rewrite() == NULL ||
1051          (!var->IsVariable(FACTORY->result_symbol())) ||
1052          (var->AsSlot() == NULL || var->AsSlot()->type() != Slot::LOCAL));
1053   if (var->rewrite() == NULL && MustAllocate(var)) {
1054     if (MustAllocateInContext(var)) {
1055       AllocateHeapSlot(var);
1056     } else {
1057       AllocateStackSlot(var);
1058     }
1059   }
1060 }
1061 
1062 
AllocateNonParameterLocals()1063 void Scope::AllocateNonParameterLocals() {
1064   // All variables that have no rewrite yet are non-parameter locals.
1065   for (int i = 0; i < temps_.length(); i++) {
1066     AllocateNonParameterLocal(temps_[i]);
1067   }
1068 
1069   for (VariableMap::Entry* p = variables_.Start();
1070        p != NULL;
1071        p = variables_.Next(p)) {
1072     Variable* var = reinterpret_cast<Variable*>(p->value);
1073     AllocateNonParameterLocal(var);
1074   }
1075 
1076   // For now, function_ must be allocated at the very end.  If it gets
1077   // allocated in the context, it must be the last slot in the context,
1078   // because of the current ScopeInfo implementation (see
1079   // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
1080   if (function_ != NULL) {
1081     AllocateNonParameterLocal(function_);
1082   }
1083 }
1084 
1085 
AllocateVariablesRecursively()1086 void Scope::AllocateVariablesRecursively() {
1087   // Allocate variables for inner scopes.
1088   for (int i = 0; i < inner_scopes_.length(); i++) {
1089     inner_scopes_[i]->AllocateVariablesRecursively();
1090   }
1091 
1092   // If scope is already resolved, we still need to allocate
1093   // variables in inner scopes which might not had been resolved yet.
1094   if (resolved()) return;
1095   // The number of slots required for variables.
1096   num_stack_slots_ = 0;
1097   num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
1098 
1099   // Allocate variables for this scope.
1100   // Parameters must be allocated first, if any.
1101   if (is_function_scope()) AllocateParameterLocals();
1102   AllocateNonParameterLocals();
1103 
1104   // Allocate context if necessary.
1105   bool must_have_local_context = false;
1106   if (scope_calls_eval_ || scope_contains_with_) {
1107     // The context for the eval() call or 'with' statement in this scope.
1108     // Unless we are in the global or an eval scope, we need a local
1109     // context even if we didn't statically allocate any locals in it,
1110     // and the compiler will access the context variable. If we are
1111     // not in an inner scope, the scope is provided from the outside.
1112     must_have_local_context = is_function_scope();
1113   }
1114 
1115   // If we didn't allocate any locals in the local context, then we only
1116   // need the minimal number of slots if we must have a local context.
1117   if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS &&
1118       !must_have_local_context) {
1119     num_heap_slots_ = 0;
1120   }
1121 
1122   // Allocation done.
1123   ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
1124 }
1125 
1126 } }  // namespace v8::internal
1127