blob: a5b12f8144993161d1b0865b9dbb1ceedc82d74b [file] [log] [blame]
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000030#include "scopes.h"
31
danno@chromium.org81cac2b2012-07-10 11:28:27 +000032#include "accessors.h"
ager@chromium.orgb61a0d12010-10-13 08:35:23 +000033#include "bootstrapper.h"
34#include "compiler.h"
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000035#include "messages.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "scopeinfo.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037
whesse@chromium.org030d38e2011-07-13 13:23:34 +000038#include "allocation-inl.h"
39
kasperl@chromium.org71affb52009-05-26 05:44:31 +000040namespace v8 {
41namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042
43// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044// Implementation of LocalsMap
45//
46// Note: We are storing the handle locations as key values in the hash map.
47// When inserting a new variable via Declare(), we rely on the fact that
48// the handle location remains alive for the duration of that variable
49// use. Because a Variable holding a handle with the same location exists
50// this is ensured.
51
52static bool Match(void* key1, void* key2) {
53 String* name1 = *reinterpret_cast<String**>(key1);
54 String* name2 = *reinterpret_cast<String**>(key2);
55 ASSERT(name1->IsSymbol());
56 ASSERT(name2->IsSymbol());
57 return name1 == name2;
58}
59
60
mmassi@chromium.org7028c052012-06-13 11:51:58 +000061VariableMap::VariableMap(Zone* zone)
62 : ZoneHashMap(Match, 8, ZoneAllocationPolicy(zone)),
63 zone_(zone) {}
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000064VariableMap::~VariableMap() {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000067Variable* VariableMap::Declare(
68 Scope* scope,
69 Handle<String> name,
70 VariableMode mode,
71 bool is_valid_lhs,
72 Variable::Kind kind,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000073 InitializationFlag initialization_flag,
74 Interface* interface) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000075 Entry* p = ZoneHashMap::Lookup(name.location(), name->Hash(), true,
76 ZoneAllocationPolicy(zone()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077 if (p->value == NULL) {
78 // The variable has not been declared yet -> insert it.
79 ASSERT(p->key == name.location());
mmassi@chromium.org7028c052012-06-13 11:51:58 +000080 p->value = new(zone()) Variable(scope,
81 name,
82 mode,
83 is_valid_lhs,
84 kind,
85 initialization_flag,
86 interface);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087 }
88 return reinterpret_cast<Variable*>(p->value);
89}
90
91
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000092Variable* VariableMap::Lookup(Handle<String> name) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000093 Entry* p = ZoneHashMap::Lookup(name.location(), name->Hash(), false,
94 ZoneAllocationPolicy(NULL));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095 if (p != NULL) {
96 ASSERT(*reinterpret_cast<String**>(p->key) == *name);
97 ASSERT(p->value != NULL);
98 return reinterpret_cast<Variable*>(p->value);
99 }
100 return NULL;
101}
102
103
104// ----------------------------------------------------------------------------
105// Implementation of Scope
106
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000107Scope::Scope(Scope* outer_scope, ScopeType type, Zone* zone)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000108 : isolate_(Isolate::Current()),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000109 inner_scopes_(4, zone),
110 variables_(zone),
111 temps_(4, zone),
112 params_(4, zone),
113 unresolved_(16, zone),
114 decls_(4, zone),
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000115 interface_(FLAG_harmony_modules &&
116 (type == MODULE_SCOPE || type == GLOBAL_SCOPE)
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000117 ? Interface::NewModule(zone) : NULL),
118 already_resolved_(false),
119 zone_(zone) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000120 SetDefaults(type, outer_scope, Handle<ScopeInfo>::null());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121 // At some point we might want to provide outer scopes to
122 // eval scopes (by walking the stack and reading the scope info).
123 // In that case, the ASSERT below needs to be adjusted.
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000124 ASSERT_EQ(type == GLOBAL_SCOPE, outer_scope == NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000125 ASSERT(!HasIllegalRedeclaration());
126}
127
128
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000129Scope::Scope(Scope* inner_scope,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000130 ScopeType type,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000131 Handle<ScopeInfo> scope_info,
132 Zone* zone)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000133 : isolate_(Isolate::Current()),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000134 inner_scopes_(4, zone),
135 variables_(zone),
136 temps_(4, zone),
137 params_(4, zone),
138 unresolved_(16, zone),
139 decls_(4, zone),
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000140 interface_(NULL),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000141 already_resolved_(true),
142 zone_(zone) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000143 SetDefaults(type, NULL, scope_info);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000144 if (!scope_info.is_null()) {
145 num_heap_slots_ = scope_info_->ContextLength();
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000146 }
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +0000147 // Ensure at least MIN_CONTEXT_SLOTS to indicate a materialized context.
148 num_heap_slots_ = Max(num_heap_slots_,
149 static_cast<int>(Context::MIN_CONTEXT_SLOTS));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000150 AddInnerScope(inner_scope);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000151}
152
153
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000154Scope::Scope(Scope* inner_scope, Handle<String> catch_variable_name, Zone* zone)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000155 : isolate_(Isolate::Current()),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000156 inner_scopes_(1, zone),
157 variables_(zone),
158 temps_(0, zone),
159 params_(0, zone),
160 unresolved_(0, zone),
161 decls_(0, zone),
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000162 interface_(NULL),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000163 already_resolved_(true),
164 zone_(zone) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000165 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null());
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000166 AddInnerScope(inner_scope);
167 ++num_var_or_const_;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000168 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000169 Variable* variable = variables_.Declare(this,
170 catch_variable_name,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000171 VAR,
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000172 true, // Valid left-hand side.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000173 Variable::NORMAL,
174 kCreatedInitialized);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000175 AllocateHeapSlot(variable);
176}
177
178
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000179void Scope::SetDefaults(ScopeType type,
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000180 Scope* outer_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000181 Handle<ScopeInfo> scope_info) {
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000182 outer_scope_ = outer_scope;
183 type_ = type;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000184 scope_name_ = isolate_->factory()->empty_symbol();
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000185 dynamics_ = NULL;
186 receiver_ = NULL;
187 function_ = NULL;
188 arguments_ = NULL;
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000189 illegal_redecl_ = NULL;
190 scope_inside_with_ = false;
191 scope_contains_with_ = false;
192 scope_calls_eval_ = false;
193 // Inherit the strict mode from the parent scope.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000194 language_mode_ = (outer_scope != NULL)
195 ? outer_scope->language_mode_ : CLASSIC_MODE;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000196 outer_scope_calls_non_strict_eval_ = false;
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000197 inner_scope_calls_eval_ = false;
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000198 force_eager_compilation_ = false;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000199 num_var_or_const_ = 0;
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000200 num_stack_slots_ = 0;
201 num_heap_slots_ = 0;
202 scope_info_ = scope_info;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000203 start_position_ = RelocInfo::kNoPosition;
204 end_position_ = RelocInfo::kNoPosition;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000205 if (!scope_info.is_null()) {
206 scope_calls_eval_ = scope_info->CallsEval();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000207 language_mode_ = scope_info->language_mode();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000208 }
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000209}
210
211
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000212Scope* Scope::DeserializeScopeChain(Context* context, Scope* global_scope,
213 Zone* zone) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000214 // Reconstruct the outer scope chain from a closure's context chain.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000215 Scope* current_scope = NULL;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000216 Scope* innermost_scope = NULL;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000217 bool contains_with = false;
218 while (!context->IsGlobalContext()) {
219 if (context->IsWithContext()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000220 Scope* with_scope = new(zone) Scope(current_scope,
221 WITH_SCOPE,
222 Handle<ScopeInfo>::null(),
223 zone);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000224 current_scope = with_scope;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000225 // All the inner scopes are inside a with.
226 contains_with = true;
227 for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) {
228 s->scope_inside_with_ = true;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000229 }
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000230 } else if (context->IsModuleContext()) {
231 ScopeInfo* scope_info = ScopeInfo::cast(context->module()->scope_info());
232 current_scope = new(zone) Scope(current_scope,
233 MODULE_SCOPE,
234 Handle<ScopeInfo>(scope_info),
235 zone);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000236 } else if (context->IsFunctionContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000237 ScopeInfo* scope_info = context->closure()->shared()->scope_info();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000238 current_scope = new(zone) Scope(current_scope,
239 FUNCTION_SCOPE,
240 Handle<ScopeInfo>(scope_info),
241 zone);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000242 } else if (context->IsBlockContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000243 ScopeInfo* scope_info = ScopeInfo::cast(context->extension());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000244 current_scope = new(zone) Scope(current_scope,
245 BLOCK_SCOPE,
246 Handle<ScopeInfo>(scope_info),
247 zone);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000248 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000249 ASSERT(context->IsCatchContext());
250 String* name = String::cast(context->extension());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000251 current_scope = new(zone) Scope(
252 current_scope, Handle<String>(name), zone);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000253 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000254 if (contains_with) current_scope->RecordWithStatement();
255 if (innermost_scope == NULL) innermost_scope = current_scope;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000256
257 // Forget about a with when we move to a context for a different function.
258 if (context->previous()->closure() != context->closure()) {
259 contains_with = false;
260 }
261 context = context->previous();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000262 }
263
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000264 global_scope->AddInnerScope(current_scope);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000265 global_scope->PropagateScopeInfo(false);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000266 return (innermost_scope == NULL) ? global_scope : innermost_scope;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000267}
268
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000269
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000270bool Scope::Analyze(CompilationInfo* info) {
271 ASSERT(info->function() != NULL);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000272 Scope* scope = info->function()->scope();
273 Scope* top = scope;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000274
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000275 // Traverse the scope tree up to the first unresolved scope or the global
276 // scope and start scope resolution and variable allocation from that scope.
277 while (!top->is_global_scope() &&
278 !top->outer_scope()->already_resolved()) {
279 top = top->outer_scope();
280 }
281
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000282 // Allocate the variables.
283 {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000284 AstNodeFactory<AstNullVisitor> ast_node_factory(info->isolate(),
285 info->zone());
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000286 if (!top->AllocateVariables(info, &ast_node_factory)) return false;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000287 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000288
289#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000290 if (info->isolate()->bootstrapper()->IsActive()
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000291 ? FLAG_print_builtin_scopes
292 : FLAG_print_scopes) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000293 scope->Print();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000294 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000295
296 if (FLAG_harmony_modules && FLAG_print_interfaces && top->is_global_scope()) {
297 PrintF("global : ");
298 top->interface()->Print();
299 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000300#endif
301
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000302 if (FLAG_harmony_scoping) {
303 VariableProxy* proxy = scope->CheckAssignmentToConst();
304 if (proxy != NULL) {
305 // Found an assignment to const. Throw a syntax error.
306 MessageLocation location(info->script(),
307 proxy->position(),
308 proxy->position());
309 Isolate* isolate = info->isolate();
310 Factory* factory = isolate->factory();
311 Handle<JSArray> array = factory->NewJSArray(0);
312 Handle<Object> result =
313 factory->NewSyntaxError("harmony_const_assign", array);
314 isolate->Throw(*result, &location);
315 return false;
316 }
317 }
318
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000319 info->SetScope(scope);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000320 return true;
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000321}
322
323
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000324void Scope::Initialize() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000325 ASSERT(!already_resolved());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000326
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327 // Add this scope as a new inner scope of the outer scope.
328 if (outer_scope_ != NULL) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000329 outer_scope_->inner_scopes_.Add(this, zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000330 scope_inside_with_ = outer_scope_->scope_inside_with_ || is_with_scope();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000331 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000332 scope_inside_with_ = is_with_scope();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000333 }
334
335 // Declare convenience variables.
336 // Declare and allocate receiver (even for the global scope, and even
337 // if naccesses_ == 0).
338 // NOTE: When loading parameters in the global scope, we must take
339 // care not to access them as properties of the global object, but
340 // instead load them directly from the stack. Currently, the only
341 // such parameter is 'this' which is passed on the stack when
342 // invoking scripts
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000343 if (is_declaration_scope()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000344 Variable* var =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000345 variables_.Declare(this,
346 isolate_->factory()->this_symbol(),
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000347 VAR,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000348 false,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000349 Variable::THIS,
350 kCreatedInitialized);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000351 var->AllocateTo(Variable::PARAMETER, -1);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000352 receiver_ = var;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000353 } else {
354 ASSERT(outer_scope() != NULL);
355 receiver_ = outer_scope()->receiver();
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000356 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000357
358 if (is_function_scope()) {
359 // Declare 'arguments' variable which exists in all functions.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000360 // Note that it might never be accessed, in which case it won't be
361 // allocated during variable allocation.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000362 variables_.Declare(this,
363 isolate_->factory()->arguments_symbol(),
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000364 VAR,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000365 true,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000366 Variable::ARGUMENTS,
367 kCreatedInitialized);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 }
369}
370
371
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000372Scope* Scope::FinalizeBlockScope() {
373 ASSERT(is_block_scope());
374 ASSERT(temps_.is_empty());
375 ASSERT(params_.is_empty());
376
377 if (num_var_or_const() > 0) return this;
378
379 // Remove this scope from outer scope.
380 for (int i = 0; i < outer_scope_->inner_scopes_.length(); i++) {
381 if (outer_scope_->inner_scopes_[i] == this) {
382 outer_scope_->inner_scopes_.Remove(i);
383 break;
384 }
385 }
386
387 // Reparent inner scopes.
388 for (int i = 0; i < inner_scopes_.length(); i++) {
389 outer_scope()->AddInnerScope(inner_scopes_[i]);
390 }
391
392 // Move unresolved variables
393 for (int i = 0; i < unresolved_.length(); i++) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000394 outer_scope()->unresolved_.Add(unresolved_[i], zone());
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000395 }
396
397 return NULL;
398}
399
400
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000401Variable* Scope::LocalLookup(Handle<String> name) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000402 Variable* result = variables_.Lookup(name);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000403 if (result != NULL || scope_info_.is_null()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000404 return result;
405 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000406 // If we have a serialized scope info, we might find the variable there.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000407 // There should be no local slot with the given name.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000408 ASSERT(scope_info_->StackSlotIndex(*name) < 0);
409
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000410 // Check context slot lookup.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000411 VariableMode mode;
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000412 Variable::Location location = Variable::CONTEXT;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000413 InitializationFlag init_flag;
414 int index = scope_info_->ContextSlotIndex(*name, &mode, &init_flag);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000415 if (index < 0) {
416 // Check parameters.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000417 index = scope_info_->ParameterIndex(*name);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000418 if (index < 0) return NULL;
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000419
420 mode = DYNAMIC;
421 location = Variable::LOOKUP;
422 init_flag = kCreatedInitialized;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000423 }
424
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000425 Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL,
426 init_flag);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000427 var->AllocateTo(location, index);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000428 return var;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429}
430
431
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000432Variable* Scope::LookupFunctionVar(Handle<String> name,
433 AstNodeFactory<AstNullVisitor>* factory) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000434 if (function_ != NULL && function_->proxy()->name().is_identical_to(name)) {
435 return function_->proxy()->var();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000436 } else if (!scope_info_.is_null()) {
437 // If we are backed by a scope info, try to lookup the variable there.
438 VariableMode mode;
439 int index = scope_info_->FunctionContextSlotIndex(*name, &mode);
440 if (index < 0) return NULL;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000441 Variable* var = new(zone()) Variable(
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000442 this, name, mode, true /* is valid LHS */,
443 Variable::NORMAL, kCreatedInitialized);
444 VariableProxy* proxy = factory->NewVariableProxy(var);
445 VariableDeclaration* declaration =
446 factory->NewVariableDeclaration(proxy, mode, this);
447 DeclareFunctionVar(declaration);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000448 var->AllocateTo(Variable::CONTEXT, index);
449 return var;
450 } else {
451 return NULL;
452 }
453}
454
455
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000456Variable* Scope::Lookup(Handle<String> name) {
457 for (Scope* scope = this;
458 scope != NULL;
459 scope = scope->outer_scope()) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000460 Variable* var = scope->LocalLookup(name);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000461 if (var != NULL) return var;
462 }
463 return NULL;
464}
465
466
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000467void Scope::DeclareParameter(Handle<String> name, VariableMode mode) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000468 ASSERT(!already_resolved());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000469 ASSERT(is_function_scope());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000470 Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL,
471 kCreatedInitialized);
472 params_.Add(var, zone());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000473}
474
475
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000476Variable* Scope::DeclareLocal(Handle<String> name,
477 VariableMode mode,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000478 InitializationFlag init_flag,
479 Interface* interface) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000480 ASSERT(!already_resolved());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000481 // This function handles VAR and CONST modes. DYNAMIC variables are
482 // introduces during variable allocation, INTERNAL variables are allocated
483 // explicitly, and TEMPORARY variables are allocated via NewTemporary().
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000484 ASSERT(mode == VAR ||
485 mode == CONST ||
486 mode == CONST_HARMONY ||
487 mode == LET);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000488 ++num_var_or_const_;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000489 return variables_.Declare(
490 this, name, mode, true, Variable::NORMAL, init_flag, interface);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000491}
492
493
494Variable* Scope::DeclareGlobal(Handle<String> name) {
495 ASSERT(is_global_scope());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000496 return variables_.Declare(this,
497 name,
498 DYNAMIC_GLOBAL,
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000499 true,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000500 Variable::NORMAL,
501 kCreatedInitialized);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502}
503
504
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000505void Scope::RemoveUnresolved(VariableProxy* var) {
506 // Most likely (always?) any variable we want to remove
507 // was just added before, so we search backwards.
508 for (int i = unresolved_.length(); i-- > 0;) {
509 if (unresolved_[i] == var) {
510 unresolved_.Remove(i);
511 return;
512 }
513 }
514}
515
516
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000517Variable* Scope::NewTemporary(Handle<String> name) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000518 ASSERT(!already_resolved());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000519 Variable* var = new(zone()) Variable(this,
520 name,
521 TEMPORARY,
522 true,
523 Variable::NORMAL,
524 kCreatedInitialized);
525 temps_.Add(var, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000526 return var;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000527}
528
529
530void Scope::AddDeclaration(Declaration* declaration) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000531 decls_.Add(declaration, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532}
533
534
535void Scope::SetIllegalRedeclaration(Expression* expression) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000536 // Record only the first illegal redeclaration.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537 if (!HasIllegalRedeclaration()) {
538 illegal_redecl_ = expression;
539 }
540 ASSERT(HasIllegalRedeclaration());
541}
542
543
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000544void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000545 ASSERT(HasIllegalRedeclaration());
546 illegal_redecl_->Accept(visitor);
547}
548
549
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000550Declaration* Scope::CheckConflictingVarDeclarations() {
551 int length = decls_.length();
552 for (int i = 0; i < length; i++) {
553 Declaration* decl = decls_[i];
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000554 if (decl->mode() != VAR) continue;
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000555 Handle<String> name = decl->proxy()->name();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000556
557 // Iterate through all scopes until and including the declaration scope.
558 Scope* previous = NULL;
559 Scope* current = decl->scope();
560 do {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000561 // There is a conflict if there exists a non-VAR binding.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000562 Variable* other_var = current->variables_.Lookup(name);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000563 if (other_var != NULL && other_var->mode() != VAR) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000564 return decl;
565 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000566 previous = current;
567 current = current->outer_scope_;
568 } while (!previous->is_declaration_scope());
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000569 }
570 return NULL;
571}
572
573
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000574VariableProxy* Scope::CheckAssignmentToConst() {
575 // Check this scope.
576 if (is_extended_mode()) {
577 for (int i = 0; i < unresolved_.length(); i++) {
578 ASSERT(unresolved_[i]->var() != NULL);
579 if (unresolved_[i]->var()->is_const_mode() &&
580 unresolved_[i]->IsLValue()) {
581 return unresolved_[i];
582 }
583 }
584 }
585
586 // Check inner scopes.
587 for (int i = 0; i < inner_scopes_.length(); i++) {
588 VariableProxy* proxy = inner_scopes_[i]->CheckAssignmentToConst();
589 if (proxy != NULL) return proxy;
590 }
591
592 // No assignments to const found.
593 return NULL;
594}
595
596
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000597void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
598 ZoneList<Variable*>* context_locals) {
599 ASSERT(stack_locals != NULL);
600 ASSERT(context_locals != NULL);
601
602 // Collect temporaries which are always allocated on the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000603 for (int i = 0; i < temps_.length(); i++) {
604 Variable* var = temps_[i];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000605 if (var->is_used()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000606 ASSERT(var->IsStackLocal());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000607 stack_locals->Add(var, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000608 }
609 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000610
611 // Collect declared local variables.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000612 for (VariableMap::Entry* p = variables_.Start();
613 p != NULL;
614 p = variables_.Next(p)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615 Variable* var = reinterpret_cast<Variable*>(p->value);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000616 if (var->is_used()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000617 if (var->IsStackLocal()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000618 stack_locals->Add(var, zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000619 } else if (var->IsContextSlot()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000620 context_locals->Add(var, zone());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000621 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622 }
623 }
624}
625
626
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000627bool Scope::AllocateVariables(CompilationInfo* info,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000628 AstNodeFactory<AstNullVisitor>* factory) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000629 // 1) Propagate scope information.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000630 bool outer_scope_calls_non_strict_eval = false;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000631 if (outer_scope_ != NULL) {
632 outer_scope_calls_non_strict_eval =
633 outer_scope_->outer_scope_calls_non_strict_eval() |
634 outer_scope_->calls_non_strict_eval();
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000635 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000636 PropagateScopeInfo(outer_scope_calls_non_strict_eval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000637
638 // 2) Resolve variables.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000639 if (!ResolveVariablesRecursively(info, factory)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640
641 // 3) Allocate variables.
642 AllocateVariablesRecursively();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000643
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000644 // 4) Allocate and link module instance objects.
645 if (FLAG_harmony_modules && (is_global_scope() || is_module_scope())) {
646 AllocateModules(info);
647 LinkModules(info);
648 }
649
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000650 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000651}
652
653
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000654bool Scope::HasTrivialContext() const {
655 // A function scope has a trivial context if it always is the global
656 // context. We iteratively scan out the context chain to see if
657 // there is anything that makes this scope non-trivial; otherwise we
658 // return true.
659 for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
660 if (scope->is_eval_scope()) return false;
661 if (scope->scope_inside_with_) return false;
662 if (scope->num_heap_slots_ > 0) return false;
663 }
664 return true;
665}
666
667
668bool Scope::HasTrivialOuterContext() const {
669 Scope* outer = outer_scope_;
670 if (outer == NULL) return true;
671 // Note that the outer context may be trivial in general, but the current
672 // scope may be inside a 'with' statement in which case the outer context
673 // for this scope is not trivial.
674 return !scope_inside_with_ && outer->HasTrivialContext();
675}
676
677
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +0000678bool Scope::HasLazyCompilableOuterContext() const {
679 Scope* outer = outer_scope_;
680 if (outer == NULL) return true;
681 // There are several reasons that prevent lazy compilation:
682 // - This scope is inside a with scope and all declaration scopes between
683 // them have empty contexts. Such declaration scopes become invisible
684 // during scope info deserialization.
685 // - This scope is inside a strict eval scope with variables that are
686 // potentially context allocated in an artificial function scope that
687 // is not deserialized correctly.
688 outer = outer->DeclarationScope();
689 bool found_non_trivial_declarations = false;
690 for (const Scope* scope = outer; scope != NULL; scope = scope->outer_scope_) {
691 if (scope->is_eval_scope()) return false;
692 if (scope->is_with_scope() && !found_non_trivial_declarations) return false;
693 if (scope->is_declaration_scope() && scope->num_heap_slots() > 0) {
694 found_non_trivial_declarations = true;
695 }
696 }
697 return true;
698}
699
700
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000701bool Scope::AllowsLazyCompilation() const {
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +0000702 return !force_eager_compilation_ && HasLazyCompilableOuterContext();
ulan@chromium.orgd6899c32012-05-18 14:12:25 +0000703}
704
705
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000706bool Scope::AllowsLazyCompilationWithoutContext() const {
707 return !force_eager_compilation_ && HasTrivialOuterContext();
708}
709
710
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711int Scope::ContextChainLength(Scope* scope) {
712 int n = 0;
713 for (Scope* s = this; s != scope; s = s->outer_scope_) {
714 ASSERT(s != NULL); // scope must be in the scope chain
715 if (s->num_heap_slots() > 0) n++;
716 }
717 return n;
718}
719
720
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000721Scope* Scope::DeclarationScope() {
722 Scope* scope = this;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000723 while (!scope->is_declaration_scope()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000724 scope = scope->outer_scope();
725 }
726 return scope;
727}
728
729
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000730Handle<ScopeInfo> Scope::GetScopeInfo() {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000731 if (scope_info_.is_null()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000732 scope_info_ = ScopeInfo::Create(this, zone());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000733 }
734 return scope_info_;
735}
736
737
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000738void Scope::GetNestedScopeChain(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000739 List<Handle<ScopeInfo> >* chain,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000740 int position) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000741 if (!is_eval_scope()) chain->Add(Handle<ScopeInfo>(GetScopeInfo()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000742
743 for (int i = 0; i < inner_scopes_.length(); i++) {
744 Scope* scope = inner_scopes_[i];
745 int beg_pos = scope->start_position();
746 int end_pos = scope->end_position();
747 ASSERT(beg_pos >= 0 && end_pos >= 0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000748 if (beg_pos <= position && position < end_pos) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000749 scope->GetNestedScopeChain(chain, position);
750 return;
751 }
752 }
753}
754
755
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000756#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000757static const char* Header(ScopeType type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000758 switch (type) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000759 case EVAL_SCOPE: return "eval";
760 case FUNCTION_SCOPE: return "function";
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000761 case MODULE_SCOPE: return "module";
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000762 case GLOBAL_SCOPE: return "global";
763 case CATCH_SCOPE: return "catch";
764 case BLOCK_SCOPE: return "block";
765 case WITH_SCOPE: return "with";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000766 }
767 UNREACHABLE();
768 return NULL;
769}
770
771
772static void Indent(int n, const char* str) {
773 PrintF("%*s%s", n, "", str);
774}
775
776
777static void PrintName(Handle<String> name) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000778 SmartArrayPointer<char> s = name->ToCString(DISALLOW_NULLS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000779 PrintF("%s", *s);
780}
781
782
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000783static void PrintLocation(Variable* var) {
784 switch (var->location()) {
785 case Variable::UNALLOCATED:
786 break;
787 case Variable::PARAMETER:
788 PrintF("parameter[%d]", var->index());
789 break;
790 case Variable::LOCAL:
791 PrintF("local[%d]", var->index());
792 break;
793 case Variable::CONTEXT:
794 PrintF("context[%d]", var->index());
795 break;
796 case Variable::LOOKUP:
797 PrintF("lookup");
798 break;
799 }
800}
801
802
803static void PrintVar(int indent, Variable* var) {
804 if (var->is_used() || !var->IsUnallocated()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000805 Indent(indent, Variable::Mode2String(var->mode()));
806 PrintF(" ");
807 PrintName(var->name());
808 PrintF("; // ");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000809 PrintLocation(var);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000810 if (var->has_forced_context_allocation()) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000811 if (!var->IsUnallocated()) PrintF(", ");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000812 PrintF("forced context allocation");
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000813 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000814 PrintF("\n");
815 }
816}
817
818
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000819static void PrintMap(int indent, VariableMap* map) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000820 for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000821 Variable* var = reinterpret_cast<Variable*>(p->value);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000822 PrintVar(indent, var);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000823 }
824}
825
826
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827void Scope::Print(int n) {
828 int n0 = (n > 0 ? n : 0);
829 int n1 = n0 + 2; // indentation
830
831 // Print header.
832 Indent(n0, Header(type_));
833 if (scope_name_->length() > 0) {
834 PrintF(" ");
835 PrintName(scope_name_);
836 }
837
838 // Print parameters, if any.
839 if (is_function_scope()) {
840 PrintF(" (");
841 for (int i = 0; i < params_.length(); i++) {
842 if (i > 0) PrintF(", ");
843 PrintName(params_[i]->name());
844 }
845 PrintF(")");
846 }
847
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000848 PrintF(" { // (%d, %d)\n", start_position(), end_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000849
850 // Function name, if any (named function literals, only).
851 if (function_ != NULL) {
852 Indent(n1, "// (local) function name: ");
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000853 PrintName(function_->proxy()->name());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000854 PrintF("\n");
855 }
856
857 // Scope info.
858 if (HasTrivialOuterContext()) {
859 Indent(n1, "// scope has trivial outer context\n");
860 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000861 switch (language_mode()) {
862 case CLASSIC_MODE:
863 break;
864 case STRICT_MODE:
865 Indent(n1, "// strict mode scope\n");
866 break;
867 case EXTENDED_MODE:
868 Indent(n1, "// extended mode scope\n");
869 break;
870 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
872 if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
873 if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000874 if (outer_scope_calls_non_strict_eval_) {
875 Indent(n1, "// outer scope calls 'eval' in non-strict context\n");
876 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000877 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
878 if (num_stack_slots_ > 0) { Indent(n1, "// ");
879 PrintF("%d stack slots\n", num_stack_slots_); }
880 if (num_heap_slots_ > 0) { Indent(n1, "// ");
881 PrintF("%d heap slots\n", num_heap_slots_); }
882
883 // Print locals.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000884 Indent(n1, "// function var\n");
885 if (function_ != NULL) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000886 PrintVar(n1, function_->proxy()->var());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000887 }
888
889 Indent(n1, "// temporary vars\n");
890 for (int i = 0; i < temps_.length(); i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000891 PrintVar(n1, temps_[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000892 }
893
894 Indent(n1, "// local vars\n");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000895 PrintMap(n1, &variables_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000896
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000897 Indent(n1, "// dynamic vars\n");
898 if (dynamics_ != NULL) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000899 PrintMap(n1, dynamics_->GetMap(DYNAMIC));
900 PrintMap(n1, dynamics_->GetMap(DYNAMIC_LOCAL));
901 PrintMap(n1, dynamics_->GetMap(DYNAMIC_GLOBAL));
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000902 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000903
904 // Print inner scopes (disable by providing negative n).
905 if (n >= 0) {
906 for (int i = 0; i < inner_scopes_.length(); i++) {
907 PrintF("\n");
908 inner_scopes_[i]->Print(n1);
909 }
910 }
911
912 Indent(n0, "}\n");
913}
914#endif // DEBUG
915
916
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000917Variable* Scope::NonLocal(Handle<String> name, VariableMode mode) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000918 if (dynamics_ == NULL) dynamics_ = new(zone()) DynamicScopePart(zone());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000919 VariableMap* map = dynamics_->GetMap(mode);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000920 Variable* var = map->Lookup(name);
921 if (var == NULL) {
922 // Declare a new non-local.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000923 InitializationFlag init_flag = (mode == VAR)
924 ? kCreatedInitialized : kNeedsInitialization;
925 var = map->Declare(NULL,
926 name,
927 mode,
928 true,
929 Variable::NORMAL,
930 init_flag);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000931 // Allocate it by giving it a dynamic lookup.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000932 var->AllocateTo(Variable::LOOKUP, -1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934 return var;
935}
936
937
ager@chromium.org381abbb2009-02-25 13:23:22 +0000938Variable* Scope::LookupRecursive(Handle<String> name,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000939 BindingKind* binding_kind,
940 AstNodeFactory<AstNullVisitor>* factory) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000941 ASSERT(binding_kind != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942 // Try to find the variable in this scope.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000943 Variable* var = LocalLookup(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000944
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000945 // We found a variable and we are done. (Even if there is an 'eval' in
946 // this scope which introduces the same variable again, the resulting
947 // variable remains the same.)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000948 if (var != NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000949 *binding_kind = BOUND;
950 return var;
951 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000952
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000953 // We did not find a variable locally. Check against the function variable,
954 // if any. We can do this for all scopes, since the function variable is
955 // only present - if at all - for function scopes.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000956 *binding_kind = UNBOUND;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000957 var = LookupFunctionVar(name, factory);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000958 if (var != NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000959 *binding_kind = BOUND;
960 } else if (outer_scope_ != NULL) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000961 var = outer_scope_->LookupRecursive(name, binding_kind, factory);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000962 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) {
963 var->ForceContextAllocation();
964 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000965 } else {
966 ASSERT(is_global_scope());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000967 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000968
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000969 if (is_with_scope()) {
970 // The current scope is a with scope, so the variable binding can not be
971 // statically resolved. However, note that it was necessary to do a lookup
972 // in the outer scope anyway, because if a binding exists in an outer scope,
973 // the associated variable has to be marked as potentially being accessed
974 // from inside of an inner with scope (the property may not be in the 'with'
975 // object).
976 *binding_kind = DYNAMIC_LOOKUP;
977 return NULL;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000978 } else if (calls_non_strict_eval()) {
979 // A variable binding may have been found in an outer scope, but the current
980 // scope makes a non-strict 'eval' call, so the found variable may not be
981 // the correct one (the 'eval' may introduce a binding with the same name).
982 // In that case, change the lookup result to reflect this situation.
983 if (*binding_kind == BOUND) {
984 *binding_kind = BOUND_EVAL_SHADOWED;
985 } else if (*binding_kind == UNBOUND) {
986 *binding_kind = UNBOUND_EVAL_SHADOWED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000987 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000989 return var;
990}
991
992
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000993bool Scope::ResolveVariable(CompilationInfo* info,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000994 VariableProxy* proxy,
995 AstNodeFactory<AstNullVisitor>* factory) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000996 ASSERT(info->global_scope()->is_global_scope());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997
998 // If the proxy is already resolved there's nothing to do
999 // (functions and consts may be resolved by the parser).
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001000 if (proxy->var() != NULL) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001
1002 // Otherwise, try to resolve the variable.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001003 BindingKind binding_kind;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001004 Variable* var = LookupRecursive(proxy->name(), &binding_kind, factory);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001005 switch (binding_kind) {
1006 case BOUND:
1007 // We found a variable binding.
1008 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001010 case BOUND_EVAL_SHADOWED:
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001011 // We either found a variable binding that might be shadowed by eval or
1012 // gave up on it (e.g. by encountering a local with the same in the outer
1013 // scope which was not promoted to a context, this can happen if we use
1014 // debugger to evaluate arbitrary expressions at a break point).
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001015 if (var->is_global()) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001016 var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001017 } else if (var->is_dynamic()) {
1018 var = NonLocal(proxy->name(), DYNAMIC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001019 } else {
1020 Variable* invalidated = var;
1021 var = NonLocal(proxy->name(), DYNAMIC_LOCAL);
1022 var->set_local_if_not_shadowed(invalidated);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001024 break;
1025
1026 case UNBOUND:
1027 // No binding has been found. Declare a variable in global scope.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001028 var = info->global_scope()->DeclareGlobal(proxy->name());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001029 break;
1030
1031 case UNBOUND_EVAL_SHADOWED:
1032 // No binding has been found. But some scope makes a
1033 // non-strict 'eval' call.
1034 var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
1035 break;
1036
1037 case DYNAMIC_LOOKUP:
1038 // The variable could not be resolved statically.
1039 var = NonLocal(proxy->name(), DYNAMIC);
1040 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041 }
1042
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001043 ASSERT(var != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001044 proxy->BindTo(var);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001045
1046 if (FLAG_harmony_modules) {
1047 bool ok;
1048#ifdef DEBUG
1049 if (FLAG_print_interface_details)
1050 PrintF("# Resolve %s:\n", var->name()->ToAsciiArray());
1051#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001052 proxy->interface()->Unify(var->interface(), zone(), &ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001053 if (!ok) {
1054#ifdef DEBUG
1055 if (FLAG_print_interfaces) {
1056 PrintF("SCOPES TYPE ERROR\n");
1057 PrintF("proxy: ");
1058 proxy->interface()->Print();
1059 PrintF("var: ");
1060 var->interface()->Print();
1061 }
1062#endif
1063
1064 // Inconsistent use of module. Throw a syntax error.
1065 // TODO(rossberg): generate more helpful error message.
1066 MessageLocation location(info->script(),
1067 proxy->position(),
1068 proxy->position());
1069 Isolate* isolate = Isolate::Current();
1070 Factory* factory = isolate->factory();
1071 Handle<JSArray> array = factory->NewJSArray(1);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001072 USE(JSObject::SetElement(array, 0, var->name(), NONE, kStrictMode));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001073 Handle<Object> result =
1074 factory->NewSyntaxError("module_type_error", array);
1075 isolate->Throw(*result, &location);
1076 return false;
1077 }
1078 }
1079
1080 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001081}
1082
1083
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001084bool Scope::ResolveVariablesRecursively(
1085 CompilationInfo* info,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001086 AstNodeFactory<AstNullVisitor>* factory) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001087 ASSERT(info->global_scope()->is_global_scope());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088
1089 // Resolve unresolved variables for this scope.
1090 for (int i = 0; i < unresolved_.length(); i++) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001091 if (!ResolveVariable(info, unresolved_[i], factory)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001092 }
1093
1094 // Resolve unresolved variables for inner scopes.
1095 for (int i = 0; i < inner_scopes_.length(); i++) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001096 if (!inner_scopes_[i]->ResolveVariablesRecursively(info, factory))
1097 return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001099
1100 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001101}
1102
1103
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001104bool Scope::PropagateScopeInfo(bool outer_scope_calls_non_strict_eval ) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001105 if (outer_scope_calls_non_strict_eval) {
1106 outer_scope_calls_non_strict_eval_ = true;
1107 }
1108
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001109 bool calls_non_strict_eval =
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001110 this->calls_non_strict_eval() || outer_scope_calls_non_strict_eval_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111 for (int i = 0; i < inner_scopes_.length(); i++) {
1112 Scope* inner_scope = inner_scopes_[i];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001113 if (inner_scope->PropagateScopeInfo(calls_non_strict_eval)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001114 inner_scope_calls_eval_ = true;
1115 }
1116 if (inner_scope->force_eager_compilation_) {
1117 force_eager_compilation_ = true;
1118 }
1119 }
1120
1121 return scope_calls_eval_ || inner_scope_calls_eval_;
1122}
1123
1124
1125bool Scope::MustAllocate(Variable* var) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001126 // Give var a read/write use if there is a chance it might be accessed
1127 // via an eval() call. This is only possible if the variable has a
1128 // visible name.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129 if ((var->is_this() || var->name()->length() > 0) &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001130 (var->has_forced_context_allocation() ||
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001131 scope_calls_eval_ ||
1132 inner_scope_calls_eval_ ||
1133 scope_contains_with_ ||
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001134 is_catch_scope() ||
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001135 is_block_scope() ||
1136 is_module_scope())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001137 var->set_is_used(true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001139 // Global variables do not need to be allocated.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001140 return !var->is_global() && var->is_used();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141}
1142
1143
1144bool Scope::MustAllocateInContext(Variable* var) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001145 // If var is accessed from an inner scope, or if there is a possibility
1146 // that it might be accessed from the current or an inner scope (through
1147 // an eval() call or a runtime with lookup), it must be allocated in the
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001148 // context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001149 //
1150 // Exceptions: temporary variables are never allocated in a context;
1151 // catch-bound variables are always allocated in a context.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001152 if (var->mode() == TEMPORARY) return false;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001153 if (is_catch_scope() || is_block_scope() || is_module_scope()) return true;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001154 return var->has_forced_context_allocation() ||
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001155 scope_calls_eval_ ||
1156 inner_scope_calls_eval_ ||
1157 scope_contains_with_ ||
1158 var->is_global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001159}
1160
1161
1162bool Scope::HasArgumentsParameter() {
1163 for (int i = 0; i < params_.length(); i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001164 if (params_[i]->name().is_identical_to(
1165 isolate_->factory()->arguments_symbol())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166 return true;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001167 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 }
1169 return false;
1170}
1171
1172
1173void Scope::AllocateStackSlot(Variable* var) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001174 var->AllocateTo(Variable::LOCAL, num_stack_slots_++);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175}
1176
1177
1178void Scope::AllocateHeapSlot(Variable* var) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001179 var->AllocateTo(Variable::CONTEXT, num_heap_slots_++);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180}
1181
1182
1183void Scope::AllocateParameterLocals() {
1184 ASSERT(is_function_scope());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001185 Variable* arguments = LocalLookup(isolate_->factory()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001186 ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001187
whesse@chromium.org7b260152011-06-20 15:33:18 +00001188 bool uses_nonstrict_arguments = false;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 if (MustAllocate(arguments) && !HasArgumentsParameter()) {
1191 // 'arguments' is used. Unless there is also a parameter called
whesse@chromium.org7b260152011-06-20 15:33:18 +00001192 // 'arguments', we must be conservative and allocate all parameters to
1193 // the context assuming they will be captured by the arguments object.
1194 // If we have a parameter named 'arguments', a (new) value is always
1195 // assigned to it via the function invocation. Then 'arguments' denotes
1196 // that specific parameter value and cannot be used to access the
1197 // parameters, which is why we don't need to allocate an arguments
1198 // object in that case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001199
1200 // We are using 'arguments'. Tell the code generator that is needs to
1201 // allocate the arguments object by setting 'arguments_'.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001202 arguments_ = arguments;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001203
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001204 // In strict mode 'arguments' does not alias formal parameters.
1205 // Therefore in strict mode we allocate parameters as if 'arguments'
1206 // were not used.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001207 uses_nonstrict_arguments = is_classic_mode();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001208 }
1209
whesse@chromium.org7b260152011-06-20 15:33:18 +00001210 // The same parameter may occur multiple times in the parameters_ list.
1211 // If it does, and if it is not copied into the context object, it must
1212 // receive the highest parameter index for that parameter; thus iteration
1213 // order is relevant!
1214 for (int i = params_.length() - 1; i >= 0; --i) {
1215 Variable* var = params_[i];
1216 ASSERT(var->scope() == this);
1217 if (uses_nonstrict_arguments) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001218 // Force context allocation of the parameter.
1219 var->ForceContextAllocation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001220 }
1221
whesse@chromium.org7b260152011-06-20 15:33:18 +00001222 if (MustAllocate(var)) {
1223 if (MustAllocateInContext(var)) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001224 ASSERT(var->IsUnallocated() || var->IsContextSlot());
1225 if (var->IsUnallocated()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001226 AllocateHeapSlot(var);
1227 }
1228 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001229 ASSERT(var->IsUnallocated() || var->IsParameter());
1230 if (var->IsUnallocated()) {
1231 var->AllocateTo(Variable::PARAMETER, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232 }
1233 }
1234 }
1235 }
1236}
1237
1238
1239void Scope::AllocateNonParameterLocal(Variable* var) {
1240 ASSERT(var->scope() == this);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001241 ASSERT(!var->IsVariable(isolate_->factory()->result_symbol()) ||
1242 !var->IsStackLocal());
1243 if (var->IsUnallocated() && MustAllocate(var)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244 if (MustAllocateInContext(var)) {
1245 AllocateHeapSlot(var);
1246 } else {
1247 AllocateStackSlot(var);
1248 }
1249 }
1250}
1251
1252
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253void Scope::AllocateNonParameterLocals() {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001254 // All variables that have no rewrite yet are non-parameter locals.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001255 for (int i = 0; i < temps_.length(); i++) {
1256 AllocateNonParameterLocal(temps_[i]);
1257 }
1258
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001259 for (VariableMap::Entry* p = variables_.Start();
1260 p != NULL;
1261 p = variables_.Next(p)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262 Variable* var = reinterpret_cast<Variable*>(p->value);
1263 AllocateNonParameterLocal(var);
1264 }
1265
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001266 // For now, function_ must be allocated at the very end. If it gets
1267 // allocated in the context, it must be the last slot in the context,
1268 // because of the current ScopeInfo implementation (see
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269 // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
1270 if (function_ != NULL) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001271 AllocateNonParameterLocal(function_->proxy()->var());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001272 }
1273}
1274
1275
1276void Scope::AllocateVariablesRecursively() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 // Allocate variables for inner scopes.
1278 for (int i = 0; i < inner_scopes_.length(); i++) {
1279 inner_scopes_[i]->AllocateVariablesRecursively();
1280 }
1281
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001282 // If scope is already resolved, we still need to allocate
1283 // variables in inner scopes which might not had been resolved yet.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001284 if (already_resolved()) return;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001285 // The number of slots required for variables.
1286 num_stack_slots_ = 0;
1287 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
1288
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001289 // Allocate variables for this scope.
1290 // Parameters must be allocated first, if any.
1291 if (is_function_scope()) AllocateParameterLocals();
1292 AllocateNonParameterLocals();
1293
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001294 // Force allocation of a context for this scope if necessary. For a 'with'
1295 // scope and for a function scope that makes an 'eval' call we need a context,
1296 // even if no local variables were statically allocated in the scope.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001297 // Likewise for modules.
1298 bool must_have_context = is_with_scope() || is_module_scope() ||
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001299 (is_function_scope() && calls_eval());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300
1301 // If we didn't allocate any locals in the local context, then we only
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001302 // need the minimal number of slots if we must have a context.
1303 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && !must_have_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304 num_heap_slots_ = 0;
1305 }
1306
1307 // Allocation done.
1308 ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
1309}
1310
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001311
1312int Scope::StackLocalCount() const {
1313 return num_stack_slots() -
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001314 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001315}
1316
1317
1318int Scope::ContextLocalCount() const {
1319 if (num_heap_slots() == 0) return 0;
1320 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS -
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001321 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001322}
1323
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001324
1325void Scope::AllocateModules(CompilationInfo* info) {
1326 ASSERT(is_global_scope() || is_module_scope());
1327
1328 if (is_module_scope()) {
1329 ASSERT(interface_->IsFrozen());
1330 ASSERT(scope_info_.is_null());
1331
1332 // TODO(rossberg): This has to be the initial compilation of this code.
1333 // We currently do not allow recompiling any module definitions.
1334 Handle<ScopeInfo> scope_info = GetScopeInfo();
1335 Factory* factory = info->isolate()->factory();
1336 Handle<Context> context = factory->NewModuleContext(scope_info);
1337 Handle<JSModule> instance = factory->NewJSModule(context, scope_info);
1338 context->set_module(*instance);
1339
1340 bool ok;
1341 interface_->MakeSingleton(instance, &ok);
1342 ASSERT(ok);
1343 }
1344
1345 // Allocate nested modules.
1346 for (int i = 0; i < inner_scopes_.length(); i++) {
1347 Scope* inner_scope = inner_scopes_.at(i);
1348 if (inner_scope->is_module_scope()) {
1349 inner_scope->AllocateModules(info);
1350 }
1351 }
1352}
1353
1354
1355void Scope::LinkModules(CompilationInfo* info) {
1356 ASSERT(is_global_scope() || is_module_scope());
1357
1358 if (is_module_scope()) {
1359 Handle<JSModule> instance = interface_->Instance();
1360
1361 // Populate the module instance object.
1362 const PropertyAttributes ro_attr =
1363 static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE | DONT_ENUM);
1364 const PropertyAttributes rw_attr =
1365 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM);
1366 for (Interface::Iterator it = interface_->iterator();
1367 !it.done(); it.Advance()) {
1368 if (it.interface()->IsModule()) {
1369 Handle<Object> value = it.interface()->Instance();
1370 ASSERT(!value.is_null());
1371 JSReceiver::SetProperty(
1372 instance, it.name(), value, ro_attr, kStrictMode);
1373 } else {
1374 Variable* var = LocalLookup(it.name());
1375 ASSERT(var != NULL && var->IsContextSlot());
1376 PropertyAttributes attr = var->is_const_mode() ? ro_attr : rw_attr;
1377 Handle<AccessorInfo> info =
1378 Accessors::MakeModuleExport(it.name(), var->index(), attr);
1379 Handle<Object> result = SetAccessor(instance, info);
1380 ASSERT(!(result.is_null() || result->IsUndefined()));
1381 USE(result);
1382 }
1383 }
1384 USE(JSObject::PreventExtensions(instance));
1385 }
1386
1387 // Link nested modules.
1388 for (int i = 0; i < inner_scopes_.length(); i++) {
1389 Scope* inner_scope = inner_scopes_.at(i);
1390 if (inner_scope->is_module_scope()) {
1391 inner_scope->LinkModules(info);
1392 }
1393 }
1394}
1395
1396
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001397} } // namespace v8::internal