The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / scopes.cc @ 40c0f755

History | View | Annotate | Download (32.4 KB)

1
// Copyright 2006-2008 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 "prettyprinter.h"
31
#include "scopeinfo.h"
32
#include "scopes.h"
33

    
34
namespace v8 { namespace internal {
35

    
36
// ----------------------------------------------------------------------------
37
// A Zone allocator for use with LocalsMap.
38

    
39
class ZoneAllocator: public Allocator {
40
 public:
41
  /* nothing to do */
42
  virtual ~ZoneAllocator()  {}
43

    
44
  virtual void* New(size_t size)  { return Zone::New(size); }
45

    
46
  /* ignored - Zone is freed in one fell swoop */
47
  virtual void Delete(void* p)  {}
48
};
49

    
50

    
51
static ZoneAllocator LocalsMapAllocator;
52

    
53

    
54
// ----------------------------------------------------------------------------
55
// Implementation of LocalsMap
56
//
57
// Note: We are storing the handle locations as key values in the hash map.
58
//       When inserting a new variable via Declare(), we rely on the fact that
59
//       the handle location remains alive for the duration of that variable
60
//       use. Because a Variable holding a handle with the same location exists
61
//       this is ensured.
62

    
63
static bool Match(void* key1, void* key2) {
64
  String* name1 = *reinterpret_cast<String**>(key1);
65
  String* name2 = *reinterpret_cast<String**>(key2);
66
  ASSERT(name1->IsSymbol());
67
  ASSERT(name2->IsSymbol());
68
  return name1 == name2;
69
}
70

    
71

    
72
// Dummy constructor
73
LocalsMap::LocalsMap(bool gotta_love_static_overloading) : HashMap()  {}
74

    
75
LocalsMap::LocalsMap() : HashMap(Match, &LocalsMapAllocator, 8)  {}
76
LocalsMap::~LocalsMap()  {}
77

    
78

    
79
Variable* LocalsMap::Declare(Scope* scope,
80
                             Handle<String> name,
81
                             Variable::Mode mode,
82
                             bool is_valid_LHS,
83
                             bool is_this) {
84
  HashMap::Entry* p = HashMap::Lookup(name.location(), name->Hash(), true);
85
  if (p->value == NULL) {
86
    // The variable has not been declared yet -> insert it.
87
    ASSERT(p->key == name.location());
88
    p->value = new Variable(scope, name, mode, is_valid_LHS, is_this);
89
  }
90
  return reinterpret_cast<Variable*>(p->value);
91
}
92

    
93

    
94
Variable* LocalsMap::Lookup(Handle<String> name) {
95
  HashMap::Entry* p = HashMap::Lookup(name.location(), name->Hash(), false);
96
  if (p != NULL) {
97
    ASSERT(*reinterpret_cast<String**>(p->key) == *name);
98
    ASSERT(p->value != NULL);
99
    return reinterpret_cast<Variable*>(p->value);
100
  }
101
  return NULL;
102
}
103

    
104

    
105
// ----------------------------------------------------------------------------
106
// Implementation of Scope
107

    
108

    
109
// Dummy constructor
110
Scope::Scope()
111
  : inner_scopes_(0),
112
    locals_(false),
113
    temps_(0),
114
    params_(0),
115
    nonlocals_(0),
116
    unresolved_(0),
117
    decls_(0) {
118
}
119

    
120

    
121
Scope::Scope(Scope* outer_scope, Type type)
122
  : outer_scope_(outer_scope),
123
    inner_scopes_(4),
124
    type_(type),
125
    scope_name_(Factory::empty_symbol()),
126
    locals_(),
127
    temps_(4),
128
    params_(4),
129
    nonlocals_(4),
130
    unresolved_(16),
131
    decls_(4),
132
    receiver_(NULL),
133
    function_(NULL),
134
    arguments_(NULL),
135
    arguments_shadow_(NULL),
136
    illegal_redecl_(NULL),
137
    scope_inside_with_(false),
138
    scope_contains_with_(false),
139
    scope_calls_eval_(false),
140
    outer_scope_calls_eval_(false),
141
    inner_scope_calls_eval_(false),
142
    outer_scope_is_eval_scope_(false),
143
    force_eager_compilation_(false),
144
    num_stack_slots_(0),
145
    num_heap_slots_(0) {
146
  // At some point we might want to provide outer scopes to
147
  // eval scopes (by walking the stack and reading the scope info).
148
  // In that case, the ASSERT below needs to be adjusted.
149
  ASSERT((type == GLOBAL_SCOPE || type == EVAL_SCOPE) == (outer_scope == NULL));
150
  ASSERT(!HasIllegalRedeclaration());
151
}
152

    
153

    
154
void Scope::Initialize(bool inside_with) {
155
  // Add this scope as a new inner scope of the outer scope.
156
  if (outer_scope_ != NULL) {
157
    outer_scope_->inner_scopes_.Add(this);
158
    scope_inside_with_ = outer_scope_->scope_inside_with_ || inside_with;
159
  } else {
160
    scope_inside_with_ = inside_with;
161
  }
162

    
163
  // Declare convenience variables.
164
  // Declare and allocate receiver (even for the global scope, and even
165
  // if naccesses_ == 0).
166
  // NOTE: When loading parameters in the global scope, we must take
167
  // care not to access them as properties of the global object, but
168
  // instead load them directly from the stack. Currently, the only
169
  // such parameter is 'this' which is passed on the stack when
170
  // invoking scripts
171
  { Variable* var =
172
      locals_.Declare(this, Factory::this_symbol(), Variable::VAR, false, true);
173
    var->rewrite_ = new Slot(var, Slot::PARAMETER, -1);
174
    receiver_ = new VariableProxy(Factory::this_symbol(), true, false);
175
    receiver_->BindTo(var);
176
  }
177

    
178
  if (is_function_scope()) {
179
    // Declare 'arguments' variable which exists in all functions.
180
    // Note that it may never be accessed, in which case it won't
181
    // be allocated during variable allocation.
182
    Declare(Factory::arguments_symbol(), Variable::VAR);
183
  }
184
}
185

    
186

    
187

    
188
Variable* Scope::LookupLocal(Handle<String> name) {
189
  return locals_.Lookup(name);
190
}
191

    
192

    
193
Variable* Scope::Lookup(Handle<String> name) {
194
  for (Scope* scope = this;
195
       scope != NULL;
196
       scope = scope->outer_scope()) {
197
    Variable* var = scope->LookupLocal(name);
198
    if (var != NULL) return var;
199
  }
200
  return NULL;
201
}
202

    
203

    
204
Variable* Scope::DeclareFunctionVar(Handle<String> name) {
205
  ASSERT(is_function_scope() && function_ == NULL);
206
  function_ = new Variable(this, name, Variable::CONST, true, false);
207
  return function_;
208
}
209

    
210

    
211
Variable* Scope::Declare(Handle<String> name, Variable::Mode mode) {
212
  // DYNAMIC variables are introduces during variable allocation,
213
  // INTERNAL variables are allocated explicitly, and TEMPORARY
214
  // variables are allocated via NewTemporary().
215
  ASSERT(mode == Variable::VAR || mode == Variable::CONST);
216
  return locals_.Declare(this, name, mode, true, false);
217
}
218

    
219

    
220
void Scope::AddParameter(Variable* var) {
221
  ASSERT(is_function_scope());
222
  ASSERT(LookupLocal(var->name()) == var);
223
  params_.Add(var);
224
}
225

    
226

    
227
VariableProxy* Scope::NewUnresolved(Handle<String> name, bool inside_with) {
228
  // Note that we must not share the unresolved variables with
229
  // the same name because they may be removed selectively via
230
  // RemoveUnresolved().
231
  VariableProxy* proxy = new VariableProxy(name, false, inside_with);
232
  unresolved_.Add(proxy);
233
  return proxy;
234
}
235

    
236

    
237
void Scope::RemoveUnresolved(VariableProxy* var) {
238
  // Most likely (always?) any variable we want to remove
239
  // was just added before, so we search backwards.
240
  for (int i = unresolved_.length(); i-- > 0;) {
241
    if (unresolved_[i] == var) {
242
      unresolved_.Remove(i);
243
      return;
244
    }
245
  }
246
}
247

    
248

    
249
VariableProxy* Scope::NewTemporary(Handle<String> name) {
250
  Variable* var = new Variable(this, name, Variable::TEMPORARY, true, false);
251
  VariableProxy* tmp = new VariableProxy(name, false, false);
252
  tmp->BindTo(var);
253
  temps_.Add(var);
254
  return tmp;
255
}
256

    
257

    
258
void Scope::AddDeclaration(Declaration* declaration) {
259
  decls_.Add(declaration);
260
}
261

    
262

    
263
void Scope::SetIllegalRedeclaration(Expression* expression) {
264
  // Only set the illegal redeclaration expression the
265
  // first time the function is called.
266
  if (!HasIllegalRedeclaration()) {
267
    illegal_redecl_ = expression;
268
  }
269
  ASSERT(HasIllegalRedeclaration());
270
}
271

    
272

    
273
void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) {
274
  ASSERT(HasIllegalRedeclaration());
275
  illegal_redecl_->Accept(visitor);
276
}
277

    
278

    
279
template<class Allocator>
280
void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) {
281
  // Collect variables in this scope.
282
  // Note that the function_ variable - if present - is not
283
  // collected here but handled separately in ScopeInfo
284
  // which is the current user of this function).
285
  for (int i = 0; i < temps_.length(); i++) {
286
    Variable* var = temps_[i];
287
    if (var->var_uses()->is_used()) {
288
      locals->Add(var);
289
    }
290
  }
291
  for (LocalsMap::Entry* p = locals_.Start(); p != NULL; p = locals_.Next(p)) {
292
    Variable* var = reinterpret_cast<Variable*>(p->value);
293
    if (var->var_uses()->is_used()) {
294
      locals->Add(var);
295
    }
296
  }
297
}
298

    
299

    
300
// Make sure the method gets instantiated by the template system.
301
template void Scope::CollectUsedVariables(
302
    List<Variable*, FreeStoreAllocationPolicy>* locals);
303
template void Scope::CollectUsedVariables(
304
    List<Variable*, PreallocatedStorage>* locals);
305

    
306

    
307
void Scope::AllocateVariables(Handle<Context> context) {
308
  ASSERT(outer_scope_ == NULL);  // eval or global scopes only
309

    
310
  // 1) Propagate scope information.
311
  // If we are in an eval scope, we may have other outer scopes about
312
  // which we don't know anything at this point. Thus we must be conservative
313
  // and assume they may invoke eval themselves. Eventually we could capture
314
  // this information in the ScopeInfo and then use it here (by traversing
315
  // the call chain stack, at compile time).
316
  bool eval_scope = is_eval_scope();
317
  PropagateScopeInfo(eval_scope, eval_scope);
318

    
319
  // 2) Resolve variables.
320
  Scope* global_scope = NULL;
321
  if (is_global_scope()) global_scope = this;
322
  ResolveVariablesRecursively(global_scope, context);
323

    
324
  // 3) Allocate variables.
325
  AllocateVariablesRecursively();
326
}
327

    
328

    
329
bool Scope::AllowsLazyCompilation() const {
330
  return !force_eager_compilation_ && HasTrivialOuterContext();
331
}
332

    
333

    
334
bool Scope::HasTrivialContext() const {
335
  // A function scope has a trivial context if it always is the global
336
  // context. We iteratively scan out the context chain to see if
337
  // there is anything that makes this scope non-trivial; otherwise we
338
  // return true.
339
  for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
340
    if (scope->is_eval_scope()) return false;
341
    if (scope->scope_inside_with_) return false;
342
    if (scope->num_heap_slots_ > 0) return false;
343
  }
344
  return true;
345
}
346

    
347

    
348
bool Scope::HasTrivialOuterContext() const {
349
  Scope* outer = outer_scope_;
350
  if (outer == NULL) return true;
351
  // Note that the outer context may be trivial in general, but the current
352
  // scope may be inside a 'with' statement in which case the outer context
353
  // for this scope is not trivial.
354
  return !scope_inside_with_ && outer->HasTrivialContext();
355
}
356

    
357

    
358
int Scope::ContextChainLength(Scope* scope) {
359
  int n = 0;
360
  for (Scope* s = this; s != scope; s = s->outer_scope_) {
361
    ASSERT(s != NULL);  // scope must be in the scope chain
362
    if (s->num_heap_slots() > 0) n++;
363
  }
364
  return n;
365
}
366

    
367

    
368
#ifdef DEBUG
369
static const char* Header(Scope::Type type) {
370
  switch (type) {
371
    case Scope::EVAL_SCOPE: return "eval";
372
    case Scope::FUNCTION_SCOPE: return "function";
373
    case Scope::GLOBAL_SCOPE: return "global";
374
  }
375
  UNREACHABLE();
376
  return NULL;
377
}
378

    
379

    
380
static void Indent(int n, const char* str) {
381
  PrintF("%*s%s", n, "", str);
382
}
383

    
384

    
385
static void PrintName(Handle<String> name) {
386
  SmartPointer<char> s = name->ToCString(DISALLOW_NULLS);
387
  PrintF("%s", *s);
388
}
389

    
390

    
391
static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
392
  if (var->var_uses()->is_used() || var->rewrite() != NULL) {
393
    Indent(indent, Variable::Mode2String(var->mode()));
394
    PrintF(" ");
395
    PrintName(var->name());
396
    PrintF(";  // ");
397
    if (var->rewrite() != NULL) PrintF("%s, ", printer->Print(var->rewrite()));
398
    if (var->is_accessed_from_inner_scope()) PrintF("inner scope access, ");
399
    PrintF("var ");
400
    var->var_uses()->Print();
401
    PrintF(", obj ");
402
    var->obj_uses()->Print();
403
    PrintF("\n");
404
  }
405
}
406

    
407

    
408
void Scope::Print(int n) {
409
  int n0 = (n > 0 ? n : 0);
410
  int n1 = n0 + 2;  // indentation
411

    
412
  // Print header.
413
  Indent(n0, Header(type_));
414
  if (scope_name_->length() > 0) {
415
    PrintF(" ");
416
    PrintName(scope_name_);
417
  }
418

    
419
  // Print parameters, if any.
420
  if (is_function_scope()) {
421
    PrintF(" (");
422
    for (int i = 0; i < params_.length(); i++) {
423
      if (i > 0) PrintF(", ");
424
      PrintName(params_[i]->name());
425
    }
426
    PrintF(")");
427
  }
428

    
429
  PrintF(" {\n");
430

    
431
  // Function name, if any (named function literals, only).
432
  if (function_ != NULL) {
433
    Indent(n1, "// (local) function name: ");
434
    PrintName(function_->name());
435
    PrintF("\n");
436
  }
437

    
438
  // Scope info.
439
  if (HasTrivialOuterContext()) {
440
    Indent(n1, "// scope has trivial outer context\n");
441
  }
442
  if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
443
  if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
444
  if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
445
  if (outer_scope_calls_eval_) Indent(n1, "// outer scope calls 'eval'\n");
446
  if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
447
  if (outer_scope_is_eval_scope_) {
448
    Indent(n1, "// outer scope is 'eval' scope\n");
449
  }
450
  if (num_stack_slots_ > 0) { Indent(n1, "// ");
451
  PrintF("%d stack slots\n", num_stack_slots_); }
452
  if (num_heap_slots_ > 0) { Indent(n1, "// ");
453
  PrintF("%d heap slots\n", num_heap_slots_); }
454

    
455
  // Print locals.
456
  PrettyPrinter printer;
457
  Indent(n1, "// function var\n");
458
  if (function_ != NULL) {
459
    PrintVar(&printer, n1, function_);
460
  }
461

    
462
  Indent(n1, "// temporary vars\n");
463
  for (int i = 0; i < temps_.length(); i++) {
464
    PrintVar(&printer, n1, temps_[i]);
465
  }
466

    
467
  Indent(n1, "// local vars\n");
468
  for (LocalsMap::Entry* p = locals_.Start(); p != NULL; p = locals_.Next(p)) {
469
    Variable* var = reinterpret_cast<Variable*>(p->value);
470
    PrintVar(&printer, n1, var);
471
  }
472

    
473
  Indent(n1, "// nonlocal vars\n");
474
  for (int i = 0; i < nonlocals_.length(); i++)
475
    PrintVar(&printer, n1, nonlocals_[i]);
476

    
477
  // Print inner scopes (disable by providing negative n).
478
  if (n >= 0) {
479
    for (int i = 0; i < inner_scopes_.length(); i++) {
480
      PrintF("\n");
481
      inner_scopes_[i]->Print(n1);
482
    }
483
  }
484

    
485
  Indent(n0, "}\n");
486
}
487
#endif  // DEBUG
488

    
489

    
490
Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) {
491
  // Space optimization: reuse existing non-local with the same name
492
  // and mode.
493
  for (int i = 0; i < nonlocals_.length(); i++) {
494
    Variable* var = nonlocals_[i];
495
    if (var->name().is_identical_to(name) && var->mode() == mode) {
496
      return var;
497
    }
498
  }
499

    
500
  // Otherwise create a new non-local and add it to the list.
501
  Variable* var = new Variable(NULL, name, mode, true, false);
502
  nonlocals_.Add(var);
503

    
504
  // Allocate it by giving it a dynamic lookup.
505
  var->rewrite_ = new Slot(var, Slot::LOOKUP, -1);
506

    
507
  return var;
508
}
509

    
510

    
511
// Lookup a variable starting with this scope. The result is either
512
// the statically resolved (local!) variable belonging to an outer scope,
513
// or NULL. It may be NULL because a) we couldn't find a variable, or b)
514
// because the variable is just a guess (and may be shadowed by another
515
// variable that is introduced dynamically via an 'eval' call or a 'with'
516
// statement).
517
Variable* Scope::LookupRecursive(Handle<String> name,
518
                                 bool inner_lookup,
519
                                 Variable** invalidated_local) {
520
  // If we find a variable, but the current scope calls 'eval', the found
521
  // variable may not be the correct one (the 'eval' may introduce a
522
  // property with the same name). In that case, remember that the variable
523
  // found is just a guess.
524
  bool guess = scope_calls_eval_;
525

    
526
  // Try to find the variable in this scope.
527
  Variable* var = LookupLocal(name);
528

    
529
  if (var != NULL) {
530
    // We found a variable. If this is not an inner lookup, we are done.
531
    // (Even if there is an 'eval' in this scope which introduces the
532
    // same variable again, the resulting variable remains the same.
533
    // Note that enclosing 'with' statements are handled at the call site.)
534
    if (!inner_lookup)
535
      return var;
536

    
537
  } else {
538
    // We did not find a variable locally. Check against the function variable,
539
    // if any. We can do this for all scopes, since the function variable is
540
    // only present - if at all - for function scopes.
541
    //
542
    // This lookup corresponds to a lookup in the "intermediate" scope sitting
543
    // between this scope and the outer scope. (ECMA-262, 3rd., requires that
544
    // the name of named function literal is kept in an intermediate scope
545
    // in between this scope and the next outer scope.)
546
    if (function_ != NULL && function_->name().is_identical_to(name)) {
547
      var = function_;
548

    
549
    } else if (outer_scope_ != NULL) {
550
      var = outer_scope_->LookupRecursive(name, true, invalidated_local);
551
      // We may have found a variable in an outer scope. However, if
552
      // the current scope is inside a 'with', the actual variable may
553
      // be a property introduced via the 'with' statement. Then, the
554
      // variable we may have found is just a guess.
555
      if (scope_inside_with_)
556
        guess = true;
557
    }
558

    
559
    // If we did not find a variable, we are done.
560
    if (var == NULL)
561
      return NULL;
562
  }
563

    
564
  ASSERT(var != NULL);
565

    
566
  // If this is a lookup from an inner scope, mark the variable.
567
  if (inner_lookup)
568
    var->is_accessed_from_inner_scope_ = true;
569

    
570
  // If the variable we have found is just a guess, invalidate the result.
571
  if (guess) {
572
    *invalidated_local = var;
573
    var = NULL;
574
  }
575

    
576
  return var;
577
}
578

    
579

    
580
void Scope::ResolveVariable(Scope* global_scope,
581
                            Handle<Context> context,
582
                            VariableProxy* proxy) {
583
  ASSERT(global_scope == NULL || global_scope->is_global_scope());
584

    
585
  // If the proxy is already resolved there's nothing to do
586
  // (functions and consts may be resolved by the parser).
587
  if (proxy->var() != NULL) return;
588

    
589
  // Otherwise, try to resolve the variable.
590
  Variable* invalidated_local = NULL;
591
  Variable* var = LookupRecursive(proxy->name(), false, &invalidated_local);
592

    
593
  if (proxy->inside_with()) {
594
    // If we are inside a local 'with' statement, all bets are off
595
    // and we cannot resolve the proxy to a local variable even if
596
    // we found an outer matching variable.
597
    // Note that we must do a lookup anyway, because if we find one,
598
    // we must mark that variable as potentially accessed from this
599
    // inner scope (the property may not be in the 'with' object).
600
    var = NonLocal(proxy->name(), Variable::DYNAMIC);
601

    
602
  } else {
603
    // We are not inside a local 'with' statement.
604

    
605
    if (var == NULL) {
606
      // We did not find the variable. We have a global variable
607
      // if we are in the global scope (we know already that we
608
      // are outside a 'with' statement) or if there is no way
609
      // that the variable might be introduced dynamically (through
610
      // a local or outer eval() call, or an outer 'with' statement),
611
      // or we don't know about the outer scope (because we are
612
      // in an eval scope).
613
      if (is_global_scope() ||
614
          !(scope_inside_with_ || outer_scope_is_eval_scope_ ||
615
            scope_calls_eval_ || outer_scope_calls_eval_)) {
616
        // We must have a global variable.
617
        ASSERT(global_scope != NULL);
618
        var = new Variable(global_scope, proxy->name(),
619
                           Variable::DYNAMIC, true, false);
620
        // Ideally we simply rewrite these variables into property
621
        // accesses. Unfortunately, we cannot do this here at the
622
        // moment because then we can't differentiate between
623
        // global variable ('x') and global property ('this.x') access.
624
        // If 'x' doesn't exist, the former leads to an error, while the
625
        // latter returns undefined. Sigh...
626
        // var->rewrite_ = new Property(new Literal(env_->global()),
627
        //                              new Literal(proxy->name()));
628

    
629
      } else if (scope_inside_with_) {
630
        // If we are inside a with statement we give up and look up
631
        // the variable at runtime.
632
        var = NonLocal(proxy->name(), Variable::DYNAMIC);
633

    
634
      } else if (invalidated_local != NULL) {
635
        // No with statements are involved and we found a local
636
        // variable that might be shadowed by eval introduced
637
        // variables.
638
        var = NonLocal(proxy->name(), Variable::DYNAMIC_LOCAL);
639
        var->set_local_if_not_shadowed(invalidated_local);
640

    
641
      } else if (outer_scope_is_eval_scope_) {
642
        // No with statements and we did not find a local and the code
643
        // is executed with a call to eval.  The context contains
644
        // scope information that we can use to determine if the
645
        // variable is global if it is not shadowed by eval-introduced
646
        // variables.
647
        if (context->GlobalIfNotShadowedByEval(proxy->name())) {
648
          var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
649

    
650
        } else {
651
          var = NonLocal(proxy->name(), Variable::DYNAMIC);
652
        }
653

    
654
      } else {
655
        // No with statements and we did not find a local and the code
656
        // is not executed with a call to eval.  We know that this
657
        // variable is global unless it is shadowed by eval-introduced
658
        // variables.
659
        var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
660
      }
661
    }
662
  }
663

    
664
  proxy->BindTo(var);
665
}
666

    
667

    
668
void Scope::ResolveVariablesRecursively(Scope* global_scope,
669
                                        Handle<Context> context) {
670
  ASSERT(global_scope == NULL || global_scope->is_global_scope());
671

    
672
  // Resolve unresolved variables for this scope.
673
  for (int i = 0; i < unresolved_.length(); i++) {
674
    ResolveVariable(global_scope, context, unresolved_[i]);
675
  }
676

    
677
  // Resolve unresolved variables for inner scopes.
678
  for (int i = 0; i < inner_scopes_.length(); i++) {
679
    inner_scopes_[i]->ResolveVariablesRecursively(global_scope, context);
680
  }
681
}
682

    
683

    
684
bool Scope::PropagateScopeInfo(bool outer_scope_calls_eval,
685
                               bool outer_scope_is_eval_scope) {
686
  if (outer_scope_calls_eval) {
687
    outer_scope_calls_eval_ = true;
688
  }
689

    
690
  if (outer_scope_is_eval_scope) {
691
    outer_scope_is_eval_scope_ = true;
692
  }
693

    
694
  bool calls_eval = scope_calls_eval_ || outer_scope_calls_eval_;
695
  bool is_eval = is_eval_scope() || outer_scope_is_eval_scope_;
696
  for (int i = 0; i < inner_scopes_.length(); i++) {
697
    Scope* inner_scope = inner_scopes_[i];
698
    if (inner_scope->PropagateScopeInfo(calls_eval, is_eval)) {
699
      inner_scope_calls_eval_ = true;
700
    }
701
    if (inner_scope->force_eager_compilation_) {
702
      force_eager_compilation_ = true;
703
    }
704
  }
705

    
706
  return scope_calls_eval_ || inner_scope_calls_eval_;
707
}
708

    
709

    
710
bool Scope::MustAllocate(Variable* var) {
711
  // Give var a read/write use if there is a chance it might be
712
  // accessed via an eval() call, or if it is a global variable.
713
  // This is only possible if the variable has a visible name.
714
  if ((var->is_this() || var->name()->length() > 0) &&
715
      (var->is_accessed_from_inner_scope_ ||
716
       scope_calls_eval_ || inner_scope_calls_eval_ ||
717
       scope_contains_with_ || var->is_global())) {
718
    var->var_uses()->RecordAccess(1);
719
  }
720
  return var->var_uses()->is_used();
721
}
722

    
723

    
724
bool Scope::MustAllocateInContext(Variable* var) {
725
  // If var is accessed from an inner scope, or if there is a
726
  // possibility that it might be accessed from the current or
727
  // an inner scope (through an eval() call), it must be allocated
728
  // in the context.
729
  // Exceptions: Global variables and temporary variables must
730
  // never be allocated in the (FixedArray part of the) context.
731
  return
732
    var->mode() != Variable::TEMPORARY &&
733
    (var->is_accessed_from_inner_scope_ ||
734
     scope_calls_eval_ || inner_scope_calls_eval_ ||
735
     scope_contains_with_ || var->is_global());
736
}
737

    
738

    
739
bool Scope::HasArgumentsParameter() {
740
  for (int i = 0; i < params_.length(); i++) {
741
    if (params_[i]->name().is_identical_to(Factory::arguments_symbol()))
742
      return true;
743
  }
744
  return false;
745
}
746

    
747

    
748
void Scope::AllocateStackSlot(Variable* var) {
749
  var->rewrite_ = new Slot(var, Slot::LOCAL, num_stack_slots_++);
750
}
751

    
752

    
753
void Scope::AllocateHeapSlot(Variable* var) {
754
  var->rewrite_ = new Slot(var, Slot::CONTEXT, num_heap_slots_++);
755
}
756

    
757

    
758
void Scope::AllocateParameterLocals() {
759
  ASSERT(is_function_scope());
760
  Variable* arguments = LookupLocal(Factory::arguments_symbol());
761
  ASSERT(arguments != NULL);  // functions have 'arguments' declared implicitly
762
  if (MustAllocate(arguments) && !HasArgumentsParameter()) {
763
    // 'arguments' is used. Unless there is also a parameter called
764
    // 'arguments', we must be conservative and access all parameters via
765
    // the arguments object: The i'th parameter is rewritten into
766
    // '.arguments[i]' (*). If we have a parameter named 'arguments', a
767
    // (new) value is always assigned to it via the function
768
    // invocation. Then 'arguments' denotes that specific parameter value
769
    // and cannot be used to access the parameters, which is why we don't
770
    // need to rewrite in that case.
771
    //
772
    // (*) Instead of having a parameter called 'arguments', we may have an
773
    // assignment to 'arguments' in the function body, at some arbitrary
774
    // point in time (possibly through an 'eval()' call!). After that
775
    // assignment any re-write of parameters would be invalid (was bug
776
    // 881452). Thus, we introduce a shadow '.arguments'
777
    // variable which also points to the arguments object. For rewrites we
778
    // use '.arguments' which remains valid even if we assign to
779
    // 'arguments'. To summarize: If we need to rewrite, we allocate an
780
    // 'arguments' object dynamically upon function invocation. The compiler
781
    // introduces 2 local variables 'arguments' and '.arguments', both of
782
    // which originally point to the arguments object that was
783
    // allocated. All parameters are rewritten into property accesses via
784
    // the '.arguments' variable. Thus, any changes to properties of
785
    // 'arguments' are reflected in the variables and vice versa. If the
786
    // 'arguments' variable is changed, '.arguments' still points to the
787
    // correct arguments object and the rewrites still work.
788

    
789
    // We are using 'arguments'. Tell the code generator that is needs to
790
    // allocate the arguments object by setting 'arguments_'.
791
    arguments_ = new VariableProxy(Factory::arguments_symbol(), false, false);
792
    arguments_->BindTo(arguments);
793

    
794
    // We also need the '.arguments' shadow variable. Declare it and create
795
    // and bind the corresponding proxy. It's ok to declare it only now
796
    // because it's a local variable that is allocated after the parameters
797
    // have been allocated.
798
    //
799
    // Note: This is "almost" at temporary variable but we cannot use
800
    // NewTemporary() because the mode needs to be INTERNAL since this
801
    // variable may be allocated in the heap-allocated context (temporaries
802
    // are never allocated in the context).
803
    Variable* arguments_shadow =
804
        new Variable(this, Factory::arguments_shadow_symbol(),
805
                     Variable::INTERNAL, true, false);
806
    arguments_shadow_ =
807
        new VariableProxy(Factory::arguments_shadow_symbol(), false, false);
808
    arguments_shadow_->BindTo(arguments_shadow);
809
    temps_.Add(arguments_shadow);
810

    
811
    // Allocate the parameters by rewriting them into '.arguments[i]' accesses.
812
    for (int i = 0; i < params_.length(); i++) {
813
      Variable* var = params_[i];
814
      ASSERT(var->scope() == this);
815
      if (MustAllocate(var)) {
816
        if (MustAllocateInContext(var)) {
817
          // It is ok to set this only now, because arguments is a local
818
          // variable that is allocated after the parameters have been
819
          // allocated.
820
          arguments_shadow->is_accessed_from_inner_scope_ = true;
821
        }
822
        var->rewrite_ =
823
          new Property(arguments_shadow_,
824
                       new Literal(Handle<Object>(Smi::FromInt(i))),
825
                       RelocInfo::kNoPosition,
826
                       Property::SYNTHETIC);
827
        arguments_shadow->var_uses()->RecordUses(var->var_uses());
828
      }
829
    }
830

    
831
  } else {
832
    // The arguments object is not used, so we can access parameters directly.
833
    // The same parameter may occur multiple times in the parameters_ list.
834
    // If it does, and if it is not copied into the context object, it must
835
    // receive the highest parameter index for that parameter; thus iteration
836
    // order is relevant!
837
    for (int i = 0; i < params_.length(); i++) {
838
      Variable* var = params_[i];
839
      ASSERT(var->scope() == this);
840
      if (MustAllocate(var)) {
841
        if (MustAllocateInContext(var)) {
842
          ASSERT(var->rewrite_ == NULL ||
843
                 (var->slot() != NULL && var->slot()->type() == Slot::CONTEXT));
844
          if (var->rewrite_ == NULL) {
845
            // Only set the heap allocation if the parameter has not
846
            // been allocated yet.
847
            AllocateHeapSlot(var);
848
          }
849
        } else {
850
          ASSERT(var->rewrite_ == NULL ||
851
                 (var->slot() != NULL &&
852
                  var->slot()->type() == Slot::PARAMETER));
853
          // Set the parameter index always, even if the parameter
854
          // was seen before! (We need to access the actual parameter
855
          // supplied for the last occurrence of a multiply declared
856
          // parameter.)
857
          var->rewrite_ = new Slot(var, Slot::PARAMETER, i);
858
        }
859
      }
860
    }
861
  }
862
}
863

    
864

    
865
void Scope::AllocateNonParameterLocal(Variable* var) {
866
  ASSERT(var->scope() == this);
867
  ASSERT(var->rewrite_ == NULL ||
868
         (!var->IsVariable(Factory::result_symbol())) ||
869
         (var->slot() == NULL || var->slot()->type() != Slot::LOCAL));
870
  if (MustAllocate(var) && var->rewrite_ == NULL) {
871
    if (MustAllocateInContext(var)) {
872
      AllocateHeapSlot(var);
873
    } else {
874
      AllocateStackSlot(var);
875
    }
876
  }
877
}
878

    
879

    
880
void Scope::AllocateNonParameterLocals() {
881
  // Each variable occurs exactly once in the locals_ list; all
882
  // variables that have no rewrite yet are non-parameter locals.
883

    
884
  // Sort them according to use such that the locals with more uses
885
  // get allocated first.
886
  if (FLAG_usage_computation) {
887
    // This is currently not implemented.
888
  }
889

    
890
  for (int i = 0; i < temps_.length(); i++) {
891
    AllocateNonParameterLocal(temps_[i]);
892
  }
893

    
894
  for (LocalsMap::Entry* p = locals_.Start(); p != NULL; p = locals_.Next(p)) {
895
    Variable* var = reinterpret_cast<Variable*>(p->value);
896
    AllocateNonParameterLocal(var);
897
  }
898

    
899
  // Note: For now, function_ must be allocated at the very end.  If
900
  // it gets allocated in the context, it must be the last slot in the
901
  // context, because of the current ScopeInfo implementation (see
902
  // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
903
  if (function_ != NULL) {
904
    AllocateNonParameterLocal(function_);
905
  }
906
}
907

    
908

    
909
void Scope::AllocateVariablesRecursively() {
910
  // The number of slots required for variables.
911
  num_stack_slots_ = 0;
912
  num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
913

    
914
  // Allocate variables for inner scopes.
915
  for (int i = 0; i < inner_scopes_.length(); i++) {
916
    inner_scopes_[i]->AllocateVariablesRecursively();
917
  }
918

    
919
  // Allocate variables for this scope.
920
  // Parameters must be allocated first, if any.
921
  if (is_function_scope()) AllocateParameterLocals();
922
  AllocateNonParameterLocals();
923

    
924
  // Allocate context if necessary.
925
  bool must_have_local_context = false;
926
  if (scope_calls_eval_ || scope_contains_with_) {
927
    // The context for the eval() call or 'with' statement in this scope.
928
    // Unless we are in the global or an eval scope, we need a local
929
    // context even if we didn't statically allocate any locals in it,
930
    // and the compiler will access the context variable. If we are
931
    // not in an inner scope, the scope is provided from the outside.
932
    must_have_local_context = is_function_scope();
933
  }
934

    
935
  // If we didn't allocate any locals in the local context, then we only
936
  // need the minimal number of slots if we must have a local context.
937
  if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS &&
938
      !must_have_local_context) {
939
    num_heap_slots_ = 0;
940
  }
941

    
942
  // Allocation done.
943
  ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
944
}
945

    
946
} }  // namespace v8::internal