blob: a76492e03c93bd2cf04baebdce9b559ef9d511bd [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// 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
Ben Murdochf87a2032010-10-22 12:50:53 +010030#include "scopes.h"
31
32#include "bootstrapper.h"
33#include "compiler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034#include "prettyprinter.h"
35#include "scopeinfo.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000036
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000037#include "allocation-inl.h"
38
Steve Blocka7e24c12009-10-30 11:49:00 +000039namespace v8 {
40namespace internal {
41
42// ----------------------------------------------------------------------------
43// A Zone allocator for use with LocalsMap.
44
Steve Block44f0eee2011-05-26 01:26:41 +010045// TODO(isolates): It is probably worth it to change the Allocator class to
46// take a pointer to an isolate.
Steve Blocka7e24c12009-10-30 11:49:00 +000047class ZoneAllocator: public Allocator {
48 public:
49 /* nothing to do */
50 virtual ~ZoneAllocator() {}
51
Steve Block44f0eee2011-05-26 01:26:41 +010052 virtual void* New(size_t size) { return ZONE->New(static_cast<int>(size)); }
Steve Blocka7e24c12009-10-30 11:49:00 +000053
54 /* ignored - Zone is freed in one fell swoop */
55 virtual void Delete(void* p) {}
56};
57
58
59static ZoneAllocator LocalsMapAllocator;
60
61
62// ----------------------------------------------------------------------------
63// Implementation of LocalsMap
64//
65// Note: We are storing the handle locations as key values in the hash map.
66// When inserting a new variable via Declare(), we rely on the fact that
67// the handle location remains alive for the duration of that variable
68// use. Because a Variable holding a handle with the same location exists
69// this is ensured.
70
71static bool Match(void* key1, void* key2) {
72 String* name1 = *reinterpret_cast<String**>(key1);
73 String* name2 = *reinterpret_cast<String**>(key2);
74 ASSERT(name1->IsSymbol());
75 ASSERT(name2->IsSymbol());
76 return name1 == name2;
77}
78
79
80// Dummy constructor
81VariableMap::VariableMap(bool gotta_love_static_overloading) : HashMap() {}
82
83VariableMap::VariableMap() : HashMap(Match, &LocalsMapAllocator, 8) {}
84VariableMap::~VariableMap() {}
85
86
87Variable* VariableMap::Declare(Scope* scope,
88 Handle<String> name,
89 Variable::Mode mode,
90 bool is_valid_lhs,
91 Variable::Kind kind) {
92 HashMap::Entry* p = HashMap::Lookup(name.location(), name->Hash(), true);
93 if (p->value == NULL) {
94 // The variable has not been declared yet -> insert it.
95 ASSERT(p->key == name.location());
96 p->value = new Variable(scope, name, mode, is_valid_lhs, kind);
97 }
98 return reinterpret_cast<Variable*>(p->value);
99}
100
101
102Variable* VariableMap::Lookup(Handle<String> name) {
103 HashMap::Entry* p = HashMap::Lookup(name.location(), name->Hash(), false);
104 if (p != NULL) {
105 ASSERT(*reinterpret_cast<String**>(p->key) == *name);
106 ASSERT(p->value != NULL);
107 return reinterpret_cast<Variable*>(p->value);
108 }
109 return NULL;
110}
111
112
113// ----------------------------------------------------------------------------
114// Implementation of Scope
115
116
117// Dummy constructor
118Scope::Scope(Type type)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000119 : isolate_(Isolate::Current()),
120 inner_scopes_(0),
121 variables_(false),
122 temps_(0),
123 params_(0),
124 unresolved_(0),
125 decls_(0),
126 already_resolved_(false) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100127 SetDefaults(type, NULL, Handle<SerializedScopeInfo>::null());
Steve Blocka7e24c12009-10-30 11:49:00 +0000128}
129
130
131Scope::Scope(Scope* outer_scope, Type type)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000132 : isolate_(Isolate::Current()),
133 inner_scopes_(4),
134 variables_(),
135 temps_(4),
136 params_(4),
137 unresolved_(16),
138 decls_(4),
139 already_resolved_(false) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100140 SetDefaults(type, outer_scope, Handle<SerializedScopeInfo>::null());
Steve Blocka7e24c12009-10-30 11:49:00 +0000141 // At some point we might want to provide outer scopes to
142 // eval scopes (by walking the stack and reading the scope info).
143 // In that case, the ASSERT below needs to be adjusted.
144 ASSERT((type == GLOBAL_SCOPE || type == EVAL_SCOPE) == (outer_scope == NULL));
145 ASSERT(!HasIllegalRedeclaration());
146}
147
148
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000149Scope::Scope(Scope* inner_scope,
150 Type type,
151 Handle<SerializedScopeInfo> scope_info)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000152 : isolate_(Isolate::Current()),
153 inner_scopes_(4),
154 variables_(),
155 temps_(4),
156 params_(4),
157 unresolved_(16),
158 decls_(4),
159 already_resolved_(true) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100160 ASSERT(!scope_info.is_null());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000161 SetDefaults(type, NULL, scope_info);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100162 if (scope_info->HasHeapAllocatedLocals()) {
163 num_heap_slots_ = scope_info_->NumberOfContextSlots();
164 }
Steve Block44f0eee2011-05-26 01:26:41 +0100165 AddInnerScope(inner_scope);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000166}
Steve Block44f0eee2011-05-26 01:26:41 +0100167
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000168
169Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name)
170 : isolate_(Isolate::Current()),
171 inner_scopes_(1),
172 variables_(),
173 temps_(0),
174 params_(0),
175 unresolved_(0),
176 decls_(0),
177 already_resolved_(true) {
178 SetDefaults(CATCH_SCOPE, NULL, Handle<SerializedScopeInfo>::null());
179 AddInnerScope(inner_scope);
180 ++num_var_or_const_;
181 Variable* variable = variables_.Declare(this,
182 catch_variable_name,
183 Variable::VAR,
184 true, // Valid left-hand side.
185 Variable::NORMAL);
186 AllocateHeapSlot(variable);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100187}
188
189
Ben Murdoch8b112d22011-06-08 16:22:53 +0100190void Scope::SetDefaults(Type type,
191 Scope* outer_scope,
192 Handle<SerializedScopeInfo> scope_info) {
193 outer_scope_ = outer_scope;
194 type_ = type;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000195 scope_name_ = isolate_->factory()->empty_symbol();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100196 dynamics_ = NULL;
197 receiver_ = NULL;
198 function_ = NULL;
199 arguments_ = NULL;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100200 illegal_redecl_ = NULL;
201 scope_inside_with_ = false;
202 scope_contains_with_ = false;
203 scope_calls_eval_ = false;
204 // Inherit the strict mode from the parent scope.
205 strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_;
206 outer_scope_calls_eval_ = false;
Ben Murdoch257744e2011-11-30 15:57:28 +0000207 outer_scope_calls_non_strict_eval_ = false;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100208 inner_scope_calls_eval_ = false;
209 outer_scope_is_eval_scope_ = false;
210 force_eager_compilation_ = false;
Steve Block053d10c2011-06-13 19:13:29 +0100211 num_var_or_const_ = 0;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100212 num_stack_slots_ = 0;
213 num_heap_slots_ = 0;
214 scope_info_ = scope_info;
215}
216
217
Steve Block44f0eee2011-05-26 01:26:41 +0100218Scope* Scope::DeserializeScopeChain(CompilationInfo* info,
219 Scope* global_scope) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000220 // Reconstruct the outer scope chain from a closure's context chain.
Steve Block44f0eee2011-05-26 01:26:41 +0100221 ASSERT(!info->closure().is_null());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000222 Context* context = info->closure()->context();
223 Scope* current_scope = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100224 Scope* innermost_scope = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000225 bool contains_with = false;
226 while (!context->IsGlobalContext()) {
227 if (context->IsWithContext()) {
228 // All the inner scopes are inside a with.
229 contains_with = true;
230 for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) {
231 s->scope_inside_with_ = true;
Steve Block44f0eee2011-05-26 01:26:41 +0100232 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000233 } else {
234 if (context->IsFunctionContext()) {
235 SerializedScopeInfo* scope_info =
236 context->closure()->shared()->scope_info();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000237 current_scope = new Scope(current_scope, FUNCTION_SCOPE,
238 Handle<SerializedScopeInfo>(scope_info));
239 } else if (context->IsBlockContext()) {
240 SerializedScopeInfo* scope_info =
241 SerializedScopeInfo::cast(context->extension());
242 current_scope = new Scope(current_scope, BLOCK_SCOPE,
243 Handle<SerializedScopeInfo>(scope_info));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000244 } else {
245 ASSERT(context->IsCatchContext());
246 String* name = String::cast(context->extension());
247 current_scope = new Scope(current_scope, Handle<String>(name));
248 }
249 if (contains_with) current_scope->RecordWithStatement();
250 if (innermost_scope == NULL) innermost_scope = current_scope;
251 }
252
253 // Forget about a with when we move to a context for a different function.
254 if (context->previous()->closure() != context->closure()) {
255 contains_with = false;
256 }
257 context = context->previous();
Steve Block44f0eee2011-05-26 01:26:41 +0100258 }
259
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000260 global_scope->AddInnerScope(current_scope);
261 return (innermost_scope == NULL) ? global_scope : innermost_scope;
Steve Block44f0eee2011-05-26 01:26:41 +0100262}
263
Ben Murdochb8e0da22011-05-16 14:20:40 +0100264
Ben Murdochf87a2032010-10-22 12:50:53 +0100265bool Scope::Analyze(CompilationInfo* info) {
266 ASSERT(info->function() != NULL);
267 Scope* top = info->function()->scope();
Ben Murdochb8e0da22011-05-16 14:20:40 +0100268
Ben Murdochf87a2032010-10-22 12:50:53 +0100269 while (top->outer_scope() != NULL) top = top->outer_scope();
270 top->AllocateVariables(info->calling_context());
271
272#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100273 if (info->isolate()->bootstrapper()->IsActive()
Ben Murdochf87a2032010-10-22 12:50:53 +0100274 ? FLAG_print_builtin_scopes
275 : FLAG_print_scopes) {
276 info->function()->scope()->Print();
277 }
278#endif
279
280 info->SetScope(info->function()->scope());
281 return true; // Can not fail.
282}
283
284
Steve Blocka7e24c12009-10-30 11:49:00 +0000285void Scope::Initialize(bool inside_with) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000286 ASSERT(!already_resolved());
Ben Murdochb8e0da22011-05-16 14:20:40 +0100287
Steve Blocka7e24c12009-10-30 11:49:00 +0000288 // Add this scope as a new inner scope of the outer scope.
289 if (outer_scope_ != NULL) {
290 outer_scope_->inner_scopes_.Add(this);
291 scope_inside_with_ = outer_scope_->scope_inside_with_ || inside_with;
292 } else {
293 scope_inside_with_ = inside_with;
294 }
295
296 // Declare convenience variables.
297 // Declare and allocate receiver (even for the global scope, and even
298 // if naccesses_ == 0).
299 // NOTE: When loading parameters in the global scope, we must take
300 // care not to access them as properties of the global object, but
301 // instead load them directly from the stack. Currently, the only
302 // such parameter is 'this' which is passed on the stack when
303 // invoking scripts
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000304 if (is_catch_scope() || is_block_scope()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000305 ASSERT(outer_scope() != NULL);
306 receiver_ = outer_scope()->receiver();
307 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000308 ASSERT(is_function_scope() ||
309 is_global_scope() ||
310 is_eval_scope());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000311 Variable* var =
312 variables_.Declare(this,
313 isolate_->factory()->this_symbol(),
314 Variable::VAR,
315 false,
316 Variable::THIS);
317 var->set_rewrite(NewSlot(var, Slot::PARAMETER, -1));
318 receiver_ = var;
319 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000320
321 if (is_function_scope()) {
322 // Declare 'arguments' variable which exists in all functions.
323 // Note that it might never be accessed, in which case it won't be
324 // allocated during variable allocation.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000325 variables_.Declare(this,
326 isolate_->factory()->arguments_symbol(),
327 Variable::VAR,
328 true,
329 Variable::ARGUMENTS);
Steve Blocka7e24c12009-10-30 11:49:00 +0000330 }
331}
332
333
Steve Blocka7e24c12009-10-30 11:49:00 +0000334Variable* Scope::LocalLookup(Handle<String> name) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100335 Variable* result = variables_.Lookup(name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000336 if (result != NULL || scope_info_.is_null()) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100337 return result;
338 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000339 // If we have a serialized scope info, we might find the variable there.
340 //
341 // We should never lookup 'arguments' in this scope as it is implicitly
342 // present in every scope.
343 ASSERT(*name != *isolate_->factory()->arguments_symbol());
344 // There should be no local slot with the given name.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100345 ASSERT(scope_info_->StackSlotIndex(*name) < 0);
346
347 // Check context slot lookup.
348 Variable::Mode mode;
349 int index = scope_info_->ContextSlotIndex(*name, &mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000350 if (index < 0) {
351 // Check parameters.
352 mode = Variable::VAR;
353 index = scope_info_->ParameterIndex(*name);
354 if (index < 0) {
355 // Check the function name.
356 index = scope_info_->FunctionContextSlotIndex(*name);
357 if (index < 0) return NULL;
358 }
Ben Murdochb8e0da22011-05-16 14:20:40 +0100359 }
360
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000361 Variable* var =
362 variables_.Declare(this, name, mode, true, Variable::NORMAL);
363 var->set_rewrite(NewSlot(var, Slot::CONTEXT, index));
364 return var;
Steve Blocka7e24c12009-10-30 11:49:00 +0000365}
366
367
368Variable* Scope::Lookup(Handle<String> name) {
369 for (Scope* scope = this;
370 scope != NULL;
371 scope = scope->outer_scope()) {
372 Variable* var = scope->LocalLookup(name);
373 if (var != NULL) return var;
374 }
375 return NULL;
376}
377
378
379Variable* Scope::DeclareFunctionVar(Handle<String> name) {
380 ASSERT(is_function_scope() && function_ == NULL);
381 function_ = new Variable(this, name, Variable::CONST, true, Variable::NORMAL);
382 return function_;
383}
384
385
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000386void Scope::DeclareParameter(Handle<String> name) {
387 ASSERT(!already_resolved());
388 ASSERT(is_function_scope());
389 Variable* var =
390 variables_.Declare(this, name, Variable::VAR, true, Variable::NORMAL);
391 params_.Add(var);
392}
393
394
395Variable* Scope::DeclareLocal(Handle<String> name, Variable::Mode mode) {
396 ASSERT(!already_resolved());
397 // This function handles VAR and CONST modes. DYNAMIC variables are
398 // introduces during variable allocation, INTERNAL variables are allocated
399 // explicitly, and TEMPORARY variables are allocated via NewTemporary().
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000400 ASSERT(mode == Variable::VAR ||
401 mode == Variable::CONST ||
402 mode == Variable::LET);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000403 ++num_var_or_const_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000404 return variables_.Declare(this, name, mode, true, Variable::NORMAL);
405}
406
407
408Variable* Scope::DeclareGlobal(Handle<String> name) {
409 ASSERT(is_global_scope());
Leon Clarkee46be812010-01-19 14:06:41 +0000410 return variables_.Declare(this, name, Variable::DYNAMIC_GLOBAL, true,
Steve Blocka7e24c12009-10-30 11:49:00 +0000411 Variable::NORMAL);
412}
413
414
Ben Murdoch8b112d22011-06-08 16:22:53 +0100415VariableProxy* Scope::NewUnresolved(Handle<String> name,
416 bool inside_with,
417 int position) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000418 // Note that we must not share the unresolved variables with
419 // the same name because they may be removed selectively via
420 // RemoveUnresolved().
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000421 ASSERT(!already_resolved());
422 VariableProxy* proxy = new(isolate_->zone()) VariableProxy(
423 isolate_, name, false, inside_with, position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000424 unresolved_.Add(proxy);
425 return proxy;
426}
427
428
429void Scope::RemoveUnresolved(VariableProxy* var) {
430 // Most likely (always?) any variable we want to remove
431 // was just added before, so we search backwards.
432 for (int i = unresolved_.length(); i-- > 0;) {
433 if (unresolved_[i] == var) {
434 unresolved_.Remove(i);
435 return;
436 }
437 }
438}
439
440
Ben Murdochb0fe1622011-05-05 13:52:32 +0100441Variable* Scope::NewTemporary(Handle<String> name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000442 ASSERT(!already_resolved());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100443 Variable* var =
444 new Variable(this, name, Variable::TEMPORARY, true, Variable::NORMAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000445 temps_.Add(var);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100446 return var;
Steve Blocka7e24c12009-10-30 11:49:00 +0000447}
448
449
450void Scope::AddDeclaration(Declaration* declaration) {
451 decls_.Add(declaration);
452}
453
454
455void Scope::SetIllegalRedeclaration(Expression* expression) {
Steve Block1e0659c2011-05-24 12:43:12 +0100456 // Record only the first illegal redeclaration.
Steve Blocka7e24c12009-10-30 11:49:00 +0000457 if (!HasIllegalRedeclaration()) {
458 illegal_redecl_ = expression;
459 }
460 ASSERT(HasIllegalRedeclaration());
461}
462
463
464void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) {
465 ASSERT(HasIllegalRedeclaration());
466 illegal_redecl_->Accept(visitor);
467}
468
469
470template<class Allocator>
471void Scope::CollectUsedVariables(List<Variable*, Allocator>* locals) {
472 // Collect variables in this scope.
473 // Note that the function_ variable - if present - is not
474 // collected here but handled separately in ScopeInfo
475 // which is the current user of this function).
476 for (int i = 0; i < temps_.length(); i++) {
477 Variable* var = temps_[i];
Steve Block6ded16b2010-05-10 14:33:55 +0100478 if (var->is_used()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000479 locals->Add(var);
480 }
481 }
482 for (VariableMap::Entry* p = variables_.Start();
483 p != NULL;
484 p = variables_.Next(p)) {
485 Variable* var = reinterpret_cast<Variable*>(p->value);
Steve Block6ded16b2010-05-10 14:33:55 +0100486 if (var->is_used()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000487 locals->Add(var);
488 }
489 }
490}
491
492
493// Make sure the method gets instantiated by the template system.
494template void Scope::CollectUsedVariables(
495 List<Variable*, FreeStoreAllocationPolicy>* locals);
496template void Scope::CollectUsedVariables(
497 List<Variable*, PreallocatedStorage>* locals);
498template void Scope::CollectUsedVariables(
499 List<Variable*, ZoneListAllocationPolicy>* locals);
500
501
502void Scope::AllocateVariables(Handle<Context> context) {
503 ASSERT(outer_scope_ == NULL); // eval or global scopes only
504
505 // 1) Propagate scope information.
506 // If we are in an eval scope, we may have other outer scopes about
507 // which we don't know anything at this point. Thus we must be conservative
508 // and assume they may invoke eval themselves. Eventually we could capture
509 // this information in the ScopeInfo and then use it here (by traversing
510 // the call chain stack, at compile time).
Ben Murdoch257744e2011-11-30 15:57:28 +0000511
Steve Blocka7e24c12009-10-30 11:49:00 +0000512 bool eval_scope = is_eval_scope();
Ben Murdoch257744e2011-11-30 15:57:28 +0000513 bool outer_scope_calls_eval = false;
514 bool outer_scope_calls_non_strict_eval = false;
515 if (!is_global_scope()) {
516 context->ComputeEvalScopeInfo(&outer_scope_calls_eval,
517 &outer_scope_calls_non_strict_eval);
518 }
519 PropagateScopeInfo(outer_scope_calls_eval,
520 outer_scope_calls_non_strict_eval,
521 eval_scope);
Steve Blocka7e24c12009-10-30 11:49:00 +0000522
523 // 2) Resolve variables.
524 Scope* global_scope = NULL;
525 if (is_global_scope()) global_scope = this;
526 ResolveVariablesRecursively(global_scope, context);
527
528 // 3) Allocate variables.
529 AllocateVariablesRecursively();
530}
531
532
533bool Scope::AllowsLazyCompilation() const {
534 return !force_eager_compilation_ && HasTrivialOuterContext();
535}
536
537
538bool Scope::HasTrivialContext() const {
539 // A function scope has a trivial context if it always is the global
540 // context. We iteratively scan out the context chain to see if
541 // there is anything that makes this scope non-trivial; otherwise we
542 // return true.
543 for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
544 if (scope->is_eval_scope()) return false;
545 if (scope->scope_inside_with_) return false;
546 if (scope->num_heap_slots_ > 0) return false;
547 }
548 return true;
549}
550
551
552bool Scope::HasTrivialOuterContext() const {
553 Scope* outer = outer_scope_;
554 if (outer == NULL) return true;
555 // Note that the outer context may be trivial in general, but the current
556 // scope may be inside a 'with' statement in which case the outer context
557 // for this scope is not trivial.
558 return !scope_inside_with_ && outer->HasTrivialContext();
559}
560
561
562int Scope::ContextChainLength(Scope* scope) {
563 int n = 0;
564 for (Scope* s = this; s != scope; s = s->outer_scope_) {
565 ASSERT(s != NULL); // scope must be in the scope chain
566 if (s->num_heap_slots() > 0) n++;
567 }
568 return n;
569}
570
571
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000572Scope* Scope::DeclarationScope() {
573 Scope* scope = this;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000574 while (scope->is_catch_scope() ||
575 scope->is_block_scope()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000576 scope = scope->outer_scope();
577 }
578 return scope;
579}
580
581
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000582Handle<SerializedScopeInfo> Scope::GetSerializedScopeInfo() {
583 if (scope_info_.is_null()) {
584 scope_info_ = SerializedScopeInfo::Create(this);
585 }
586 return scope_info_;
587}
588
589
Steve Blocka7e24c12009-10-30 11:49:00 +0000590#ifdef DEBUG
591static const char* Header(Scope::Type type) {
592 switch (type) {
593 case Scope::EVAL_SCOPE: return "eval";
594 case Scope::FUNCTION_SCOPE: return "function";
595 case Scope::GLOBAL_SCOPE: return "global";
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000596 case Scope::CATCH_SCOPE: return "catch";
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000597 case Scope::BLOCK_SCOPE: return "block";
Steve Blocka7e24c12009-10-30 11:49:00 +0000598 }
599 UNREACHABLE();
600 return NULL;
601}
602
603
604static void Indent(int n, const char* str) {
605 PrintF("%*s%s", n, "", str);
606}
607
608
609static void PrintName(Handle<String> name) {
610 SmartPointer<char> s = name->ToCString(DISALLOW_NULLS);
611 PrintF("%s", *s);
612}
613
614
615static void PrintVar(PrettyPrinter* printer, int indent, Variable* var) {
Steve Block6ded16b2010-05-10 14:33:55 +0100616 if (var->is_used() || var->rewrite() != NULL) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000617 Indent(indent, Variable::Mode2String(var->mode()));
618 PrintF(" ");
619 PrintName(var->name());
620 PrintF("; // ");
Steve Block6ded16b2010-05-10 14:33:55 +0100621 if (var->rewrite() != NULL) {
622 PrintF("%s, ", printer->Print(var->rewrite()));
623 if (var->is_accessed_from_inner_scope()) PrintF(", ");
624 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000625 if (var->is_accessed_from_inner_scope()) {
626 PrintF("inner scope access");
627 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000628 PrintF("\n");
629 }
630}
631
632
633static void PrintMap(PrettyPrinter* printer, int indent, VariableMap* map) {
634 for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
635 Variable* var = reinterpret_cast<Variable*>(p->value);
636 PrintVar(printer, indent, var);
637 }
638}
639
640
641void Scope::Print(int n) {
642 int n0 = (n > 0 ? n : 0);
643 int n1 = n0 + 2; // indentation
644
645 // Print header.
646 Indent(n0, Header(type_));
647 if (scope_name_->length() > 0) {
648 PrintF(" ");
649 PrintName(scope_name_);
650 }
651
652 // Print parameters, if any.
653 if (is_function_scope()) {
654 PrintF(" (");
655 for (int i = 0; i < params_.length(); i++) {
656 if (i > 0) PrintF(", ");
657 PrintName(params_[i]->name());
658 }
659 PrintF(")");
660 }
661
662 PrintF(" {\n");
663
664 // Function name, if any (named function literals, only).
665 if (function_ != NULL) {
666 Indent(n1, "// (local) function name: ");
667 PrintName(function_->name());
668 PrintF("\n");
669 }
670
671 // Scope info.
672 if (HasTrivialOuterContext()) {
673 Indent(n1, "// scope has trivial outer context\n");
674 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000675 if (is_strict_mode()) Indent(n1, "// strict mode scope\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000676 if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
677 if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
678 if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
679 if (outer_scope_calls_eval_) Indent(n1, "// outer scope calls 'eval'\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000680 if (outer_scope_calls_non_strict_eval_) {
681 Indent(n1, "// outer scope calls 'eval' in non-strict context\n");
682 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000683 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
684 if (outer_scope_is_eval_scope_) {
685 Indent(n1, "// outer scope is 'eval' scope\n");
686 }
687 if (num_stack_slots_ > 0) { Indent(n1, "// ");
688 PrintF("%d stack slots\n", num_stack_slots_); }
689 if (num_heap_slots_ > 0) { Indent(n1, "// ");
690 PrintF("%d heap slots\n", num_heap_slots_); }
691
692 // Print locals.
693 PrettyPrinter printer;
694 Indent(n1, "// function var\n");
695 if (function_ != NULL) {
696 PrintVar(&printer, n1, function_);
697 }
698
699 Indent(n1, "// temporary vars\n");
700 for (int i = 0; i < temps_.length(); i++) {
701 PrintVar(&printer, n1, temps_[i]);
702 }
703
704 Indent(n1, "// local vars\n");
705 PrintMap(&printer, n1, &variables_);
706
707 Indent(n1, "// dynamic vars\n");
708 if (dynamics_ != NULL) {
709 PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC));
710 PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_LOCAL));
711 PrintMap(&printer, n1, dynamics_->GetMap(Variable::DYNAMIC_GLOBAL));
712 }
713
714 // Print inner scopes (disable by providing negative n).
715 if (n >= 0) {
716 for (int i = 0; i < inner_scopes_.length(); i++) {
717 PrintF("\n");
718 inner_scopes_[i]->Print(n1);
719 }
720 }
721
722 Indent(n0, "}\n");
723}
724#endif // DEBUG
725
726
727Variable* Scope::NonLocal(Handle<String> name, Variable::Mode mode) {
728 if (dynamics_ == NULL) dynamics_ = new DynamicScopePart();
729 VariableMap* map = dynamics_->GetMap(mode);
730 Variable* var = map->Lookup(name);
731 if (var == NULL) {
732 // Declare a new non-local.
733 var = map->Declare(NULL, name, mode, true, Variable::NORMAL);
734 // Allocate it by giving it a dynamic lookup.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000735 var->set_rewrite(NewSlot(var, Slot::LOOKUP, -1));
Steve Blocka7e24c12009-10-30 11:49:00 +0000736 }
737 return var;
738}
739
740
741// Lookup a variable starting with this scope. The result is either
Steve Blockd0582a62009-12-15 09:54:21 +0000742// the statically resolved variable belonging to an outer scope, or
743// NULL. It may be NULL because a) we couldn't find a variable, or b)
744// because the variable is just a guess (and may be shadowed by
745// another variable that is introduced dynamically via an 'eval' call
746// or a 'with' statement).
Steve Blocka7e24c12009-10-30 11:49:00 +0000747Variable* Scope::LookupRecursive(Handle<String> name,
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000748 bool from_inner_scope,
Steve Blocka7e24c12009-10-30 11:49:00 +0000749 Variable** invalidated_local) {
750 // If we find a variable, but the current scope calls 'eval', the found
751 // variable may not be the correct one (the 'eval' may introduce a
752 // property with the same name). In that case, remember that the variable
753 // found is just a guess.
754 bool guess = scope_calls_eval_;
755
756 // Try to find the variable in this scope.
757 Variable* var = LocalLookup(name);
758
759 if (var != NULL) {
760 // We found a variable. If this is not an inner lookup, we are done.
761 // (Even if there is an 'eval' in this scope which introduces the
762 // same variable again, the resulting variable remains the same.
763 // Note that enclosing 'with' statements are handled at the call site.)
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000764 if (!from_inner_scope)
Steve Blocka7e24c12009-10-30 11:49:00 +0000765 return var;
766
767 } else {
768 // We did not find a variable locally. Check against the function variable,
769 // if any. We can do this for all scopes, since the function variable is
770 // only present - if at all - for function scopes.
771 //
772 // This lookup corresponds to a lookup in the "intermediate" scope sitting
773 // between this scope and the outer scope. (ECMA-262, 3rd., requires that
774 // the name of named function literal is kept in an intermediate scope
775 // in between this scope and the next outer scope.)
776 if (function_ != NULL && function_->name().is_identical_to(name)) {
777 var = function_;
778
779 } else if (outer_scope_ != NULL) {
780 var = outer_scope_->LookupRecursive(name, true, invalidated_local);
781 // We may have found a variable in an outer scope. However, if
782 // the current scope is inside a 'with', the actual variable may
783 // be a property introduced via the 'with' statement. Then, the
784 // variable we may have found is just a guess.
785 if (scope_inside_with_)
786 guess = true;
787 }
788
789 // If we did not find a variable, we are done.
790 if (var == NULL)
791 return NULL;
792 }
793
794 ASSERT(var != NULL);
795
796 // If this is a lookup from an inner scope, mark the variable.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000797 if (from_inner_scope) {
Ben Murdochb8e0da22011-05-16 14:20:40 +0100798 var->MarkAsAccessedFromInnerScope();
799 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000800
Steve Blockd0582a62009-12-15 09:54:21 +0000801 // If the variable we have found is just a guess, invalidate the
802 // result. If the found variable is local, record that fact so we
803 // can generate fast code to get it if it is not shadowed by eval.
Steve Blocka7e24c12009-10-30 11:49:00 +0000804 if (guess) {
Steve Blockd0582a62009-12-15 09:54:21 +0000805 if (!var->is_global()) *invalidated_local = var;
Steve Blocka7e24c12009-10-30 11:49:00 +0000806 var = NULL;
807 }
808
809 return var;
810}
811
812
813void Scope::ResolveVariable(Scope* global_scope,
814 Handle<Context> context,
815 VariableProxy* proxy) {
816 ASSERT(global_scope == NULL || global_scope->is_global_scope());
817
818 // If the proxy is already resolved there's nothing to do
819 // (functions and consts may be resolved by the parser).
820 if (proxy->var() != NULL) return;
821
822 // Otherwise, try to resolve the variable.
823 Variable* invalidated_local = NULL;
824 Variable* var = LookupRecursive(proxy->name(), false, &invalidated_local);
825
826 if (proxy->inside_with()) {
827 // If we are inside a local 'with' statement, all bets are off
828 // and we cannot resolve the proxy to a local variable even if
829 // we found an outer matching variable.
830 // Note that we must do a lookup anyway, because if we find one,
831 // we must mark that variable as potentially accessed from this
832 // inner scope (the property may not be in the 'with' object).
833 var = NonLocal(proxy->name(), Variable::DYNAMIC);
834
835 } else {
836 // We are not inside a local 'with' statement.
837
838 if (var == NULL) {
839 // We did not find the variable. We have a global variable
840 // if we are in the global scope (we know already that we
841 // are outside a 'with' statement) or if there is no way
842 // that the variable might be introduced dynamically (through
843 // a local or outer eval() call, or an outer 'with' statement),
844 // or we don't know about the outer scope (because we are
845 // in an eval scope).
846 if (is_global_scope() ||
847 !(scope_inside_with_ || outer_scope_is_eval_scope_ ||
848 scope_calls_eval_ || outer_scope_calls_eval_)) {
849 // We must have a global variable.
850 ASSERT(global_scope != NULL);
851 var = global_scope->DeclareGlobal(proxy->name());
852
853 } else if (scope_inside_with_) {
854 // If we are inside a with statement we give up and look up
855 // the variable at runtime.
856 var = NonLocal(proxy->name(), Variable::DYNAMIC);
857
858 } else if (invalidated_local != NULL) {
859 // No with statements are involved and we found a local
860 // variable that might be shadowed by eval introduced
861 // variables.
862 var = NonLocal(proxy->name(), Variable::DYNAMIC_LOCAL);
863 var->set_local_if_not_shadowed(invalidated_local);
864
865 } else if (outer_scope_is_eval_scope_) {
866 // No with statements and we did not find a local and the code
867 // is executed with a call to eval. The context contains
868 // scope information that we can use to determine if the
869 // variable is global if it is not shadowed by eval-introduced
870 // variables.
871 if (context->GlobalIfNotShadowedByEval(proxy->name())) {
872 var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
873
874 } else {
875 var = NonLocal(proxy->name(), Variable::DYNAMIC);
876 }
877
878 } else {
879 // No with statements and we did not find a local and the code
880 // is not executed with a call to eval. We know that this
881 // variable is global unless it is shadowed by eval-introduced
882 // variables.
883 var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL);
884 }
885 }
886 }
887
888 proxy->BindTo(var);
889}
890
891
892void Scope::ResolveVariablesRecursively(Scope* global_scope,
893 Handle<Context> context) {
894 ASSERT(global_scope == NULL || global_scope->is_global_scope());
895
896 // Resolve unresolved variables for this scope.
897 for (int i = 0; i < unresolved_.length(); i++) {
898 ResolveVariable(global_scope, context, unresolved_[i]);
899 }
900
901 // Resolve unresolved variables for inner scopes.
902 for (int i = 0; i < inner_scopes_.length(); i++) {
903 inner_scopes_[i]->ResolveVariablesRecursively(global_scope, context);
904 }
905}
906
907
908bool Scope::PropagateScopeInfo(bool outer_scope_calls_eval,
Ben Murdoch257744e2011-11-30 15:57:28 +0000909 bool outer_scope_calls_non_strict_eval,
Steve Blocka7e24c12009-10-30 11:49:00 +0000910 bool outer_scope_is_eval_scope) {
911 if (outer_scope_calls_eval) {
912 outer_scope_calls_eval_ = true;
913 }
914
Ben Murdoch257744e2011-11-30 15:57:28 +0000915 if (outer_scope_calls_non_strict_eval) {
916 outer_scope_calls_non_strict_eval_ = true;
917 }
918
Steve Blocka7e24c12009-10-30 11:49:00 +0000919 if (outer_scope_is_eval_scope) {
920 outer_scope_is_eval_scope_ = true;
921 }
922
923 bool calls_eval = scope_calls_eval_ || outer_scope_calls_eval_;
924 bool is_eval = is_eval_scope() || outer_scope_is_eval_scope_;
Ben Murdoch257744e2011-11-30 15:57:28 +0000925 bool calls_non_strict_eval =
926 (scope_calls_eval_ && !is_strict_mode()) ||
927 outer_scope_calls_non_strict_eval_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000928 for (int i = 0; i < inner_scopes_.length(); i++) {
929 Scope* inner_scope = inner_scopes_[i];
Ben Murdoch257744e2011-11-30 15:57:28 +0000930 if (inner_scope->PropagateScopeInfo(calls_eval,
931 calls_non_strict_eval,
932 is_eval)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000933 inner_scope_calls_eval_ = true;
934 }
935 if (inner_scope->force_eager_compilation_) {
936 force_eager_compilation_ = true;
937 }
938 }
939
940 return scope_calls_eval_ || inner_scope_calls_eval_;
941}
942
943
944bool Scope::MustAllocate(Variable* var) {
945 // Give var a read/write use if there is a chance it might be accessed
946 // via an eval() call. This is only possible if the variable has a
947 // visible name.
948 if ((var->is_this() || var->name()->length() > 0) &&
Ben Murdochb8e0da22011-05-16 14:20:40 +0100949 (var->is_accessed_from_inner_scope() ||
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000950 scope_calls_eval_ ||
951 inner_scope_calls_eval_ ||
952 scope_contains_with_ ||
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000953 is_catch_scope() ||
954 is_block_scope())) {
Steve Block6ded16b2010-05-10 14:33:55 +0100955 var->set_is_used(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000956 }
957 // Global variables do not need to be allocated.
Steve Block6ded16b2010-05-10 14:33:55 +0100958 return !var->is_global() && var->is_used();
Steve Blocka7e24c12009-10-30 11:49:00 +0000959}
960
961
962bool Scope::MustAllocateInContext(Variable* var) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000963 // If var is accessed from an inner scope, or if there is a possibility
964 // that it might be accessed from the current or an inner scope (through
965 // an eval() call or a runtime with lookup), it must be allocated in the
Steve Blocka7e24c12009-10-30 11:49:00 +0000966 // context.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000967 //
968 // Exceptions: temporary variables are never allocated in a context;
969 // catch-bound variables are always allocated in a context.
970 if (var->mode() == Variable::TEMPORARY) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000971 if (is_catch_scope() || is_block_scope()) return true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000972 return var->is_accessed_from_inner_scope() ||
973 scope_calls_eval_ ||
974 inner_scope_calls_eval_ ||
975 scope_contains_with_ ||
976 var->is_global();
Steve Blocka7e24c12009-10-30 11:49:00 +0000977}
978
979
980bool Scope::HasArgumentsParameter() {
981 for (int i = 0; i < params_.length(); i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000982 if (params_[i]->name().is_identical_to(
983 isolate_->factory()->arguments_symbol())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000984 return true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000985 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000986 }
987 return false;
988}
989
990
991void Scope::AllocateStackSlot(Variable* var) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000992 var->set_rewrite(NewSlot(var, Slot::LOCAL, num_stack_slots_++));
Steve Blocka7e24c12009-10-30 11:49:00 +0000993}
994
995
996void Scope::AllocateHeapSlot(Variable* var) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000997 var->set_rewrite(NewSlot(var, Slot::CONTEXT, num_heap_slots_++));
Steve Blocka7e24c12009-10-30 11:49:00 +0000998}
999
1000
1001void Scope::AllocateParameterLocals() {
1002 ASSERT(is_function_scope());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001003 Variable* arguments = LocalLookup(isolate_->factory()->arguments_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +00001004 ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly
Steve Block44f0eee2011-05-26 01:26:41 +01001005
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001006 bool uses_nonstrict_arguments = false;
Steve Block44f0eee2011-05-26 01:26:41 +01001007
Steve Blocka7e24c12009-10-30 11:49:00 +00001008 if (MustAllocate(arguments) && !HasArgumentsParameter()) {
1009 // 'arguments' is used. Unless there is also a parameter called
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001010 // 'arguments', we must be conservative and allocate all parameters to
1011 // the context assuming they will be captured by the arguments object.
1012 // If we have a parameter named 'arguments', a (new) value is always
1013 // assigned to it via the function invocation. Then 'arguments' denotes
1014 // that specific parameter value and cannot be used to access the
1015 // parameters, which is why we don't need to allocate an arguments
1016 // object in that case.
Steve Blocka7e24c12009-10-30 11:49:00 +00001017
1018 // We are using 'arguments'. Tell the code generator that is needs to
1019 // allocate the arguments object by setting 'arguments_'.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001020 arguments_ = arguments;
Steve Blocka7e24c12009-10-30 11:49:00 +00001021
Steve Block44f0eee2011-05-26 01:26:41 +01001022 // In strict mode 'arguments' does not alias formal parameters.
1023 // Therefore in strict mode we allocate parameters as if 'arguments'
1024 // were not used.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001025 uses_nonstrict_arguments = !is_strict_mode();
Steve Block44f0eee2011-05-26 01:26:41 +01001026 }
1027
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001028 // The same parameter may occur multiple times in the parameters_ list.
1029 // If it does, and if it is not copied into the context object, it must
1030 // receive the highest parameter index for that parameter; thus iteration
1031 // order is relevant!
1032 for (int i = params_.length() - 1; i >= 0; --i) {
1033 Variable* var = params_[i];
1034 ASSERT(var->scope() == this);
1035 if (uses_nonstrict_arguments) {
1036 // Give the parameter a use from an inner scope, to force allocation
1037 // to the context.
1038 var->MarkAsAccessedFromInnerScope();
Steve Blocka7e24c12009-10-30 11:49:00 +00001039 }
1040
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001041 if (MustAllocate(var)) {
1042 if (MustAllocateInContext(var)) {
1043 ASSERT(var->rewrite() == NULL || var->IsContextSlot());
1044 if (var->rewrite() == NULL) {
1045 AllocateHeapSlot(var);
1046 }
1047 } else {
1048 ASSERT(var->rewrite() == NULL || var->IsParameter());
1049 if (var->rewrite() == NULL) {
1050 var->set_rewrite(NewSlot(var, Slot::PARAMETER, i));
Steve Blocka7e24c12009-10-30 11:49:00 +00001051 }
1052 }
1053 }
1054 }
1055}
1056
1057
1058void Scope::AllocateNonParameterLocal(Variable* var) {
1059 ASSERT(var->scope() == this);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001060 ASSERT(var->rewrite() == NULL ||
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001061 !var->IsVariable(isolate_->factory()->result_symbol()) ||
1062 var->AsSlot() == NULL ||
1063 var->AsSlot()->type() != Slot::LOCAL);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001064 if (var->rewrite() == NULL && MustAllocate(var)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001065 if (MustAllocateInContext(var)) {
1066 AllocateHeapSlot(var);
1067 } else {
1068 AllocateStackSlot(var);
1069 }
1070 }
1071}
1072
1073
1074void Scope::AllocateNonParameterLocals() {
1075 // All variables that have no rewrite yet are non-parameter locals.
1076 for (int i = 0; i < temps_.length(); i++) {
1077 AllocateNonParameterLocal(temps_[i]);
1078 }
1079
1080 for (VariableMap::Entry* p = variables_.Start();
1081 p != NULL;
1082 p = variables_.Next(p)) {
1083 Variable* var = reinterpret_cast<Variable*>(p->value);
1084 AllocateNonParameterLocal(var);
1085 }
1086
1087 // For now, function_ must be allocated at the very end. If it gets
1088 // allocated in the context, it must be the last slot in the context,
1089 // because of the current ScopeInfo implementation (see
1090 // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
1091 if (function_ != NULL) {
1092 AllocateNonParameterLocal(function_);
1093 }
1094}
1095
1096
1097void Scope::AllocateVariablesRecursively() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001098 // Allocate variables for inner scopes.
1099 for (int i = 0; i < inner_scopes_.length(); i++) {
1100 inner_scopes_[i]->AllocateVariablesRecursively();
1101 }
1102
Ben Murdochb8e0da22011-05-16 14:20:40 +01001103 // If scope is already resolved, we still need to allocate
1104 // variables in inner scopes which might not had been resolved yet.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001105 if (already_resolved()) return;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001106 // The number of slots required for variables.
1107 num_stack_slots_ = 0;
1108 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
1109
Steve Blocka7e24c12009-10-30 11:49:00 +00001110 // Allocate variables for this scope.
1111 // Parameters must be allocated first, if any.
1112 if (is_function_scope()) AllocateParameterLocals();
1113 AllocateNonParameterLocals();
1114
1115 // Allocate context if necessary.
1116 bool must_have_local_context = false;
1117 if (scope_calls_eval_ || scope_contains_with_) {
1118 // The context for the eval() call or 'with' statement in this scope.
1119 // Unless we are in the global or an eval scope, we need a local
1120 // context even if we didn't statically allocate any locals in it,
1121 // and the compiler will access the context variable. If we are
1122 // not in an inner scope, the scope is provided from the outside.
1123 must_have_local_context = is_function_scope();
1124 }
1125
1126 // If we didn't allocate any locals in the local context, then we only
1127 // need the minimal number of slots if we must have a local context.
1128 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS &&
1129 !must_have_local_context) {
1130 num_heap_slots_ = 0;
1131 }
1132
1133 // Allocation done.
1134 ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
1135}
1136
1137} } // namespace v8::internal