blob: 4ac9d0e6a463047319ef43317ebd6551b798e110 [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);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000055 ASSERT(name1->IsInternalizedString());
56 ASSERT(name2->IsInternalizedString());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057 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)
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000108 : isolate_(zone->isolate()),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000109 inner_scopes_(4, zone),
110 variables_(zone),
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000111 internals_(4, zone),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000112 temps_(4, zone),
113 params_(4, zone),
114 unresolved_(16, zone),
115 decls_(4, zone),
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000116 interface_(FLAG_harmony_modules &&
117 (type == MODULE_SCOPE || type == GLOBAL_SCOPE)
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000118 ? Interface::NewModule(zone) : NULL),
119 already_resolved_(false),
120 zone_(zone) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000121 SetDefaults(type, outer_scope, Handle<ScopeInfo>::null());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000122 // The outermost scope must be a global scope.
123 ASSERT(type == GLOBAL_SCOPE || outer_scope != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000124 ASSERT(!HasIllegalRedeclaration());
125}
126
127
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000128Scope::Scope(Scope* inner_scope,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000129 ScopeType type,
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000130 Handle<ScopeInfo> scope_info,
131 Zone* zone)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000132 : isolate_(Isolate::Current()),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000133 inner_scopes_(4, zone),
134 variables_(zone),
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000135 internals_(4, zone),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000136 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),
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000158 internals_(0, zone),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000159 temps_(0, zone),
160 params_(0, zone),
161 unresolved_(0, zone),
162 decls_(0, zone),
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000163 interface_(NULL),
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000164 already_resolved_(true),
165 zone_(zone) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000166 SetDefaults(CATCH_SCOPE, NULL, Handle<ScopeInfo>::null());
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000167 AddInnerScope(inner_scope);
168 ++num_var_or_const_;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000169 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000170 Variable* variable = variables_.Declare(this,
171 catch_variable_name,
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000172 VAR,
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000173 true, // Valid left-hand side.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000174 Variable::NORMAL,
175 kCreatedInitialized);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000176 AllocateHeapSlot(variable);
177}
178
179
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000180void Scope::SetDefaults(ScopeType type,
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000181 Scope* outer_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000182 Handle<ScopeInfo> scope_info) {
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000183 outer_scope_ = outer_scope;
184 type_ = type;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000185 scope_name_ = isolate_->factory()->empty_string();
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000186 dynamics_ = NULL;
187 receiver_ = NULL;
188 function_ = NULL;
189 arguments_ = NULL;
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000190 illegal_redecl_ = NULL;
191 scope_inside_with_ = false;
192 scope_contains_with_ = false;
193 scope_calls_eval_ = false;
194 // Inherit the strict mode from the parent scope.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000195 language_mode_ = (outer_scope != NULL)
196 ? outer_scope->language_mode_ : CLASSIC_MODE;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000197 outer_scope_calls_non_strict_eval_ = false;
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000198 inner_scope_calls_eval_ = false;
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000199 force_eager_compilation_ = false;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000200 num_var_or_const_ = 0;
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000201 num_stack_slots_ = 0;
202 num_heap_slots_ = 0;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000203 num_modules_ = 0;
204 module_var_ = NULL,
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000205 scope_info_ = scope_info;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000206 start_position_ = RelocInfo::kNoPosition;
207 end_position_ = RelocInfo::kNoPosition;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000208 if (!scope_info.is_null()) {
209 scope_calls_eval_ = scope_info->CallsEval();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000210 language_mode_ = scope_info->language_mode();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000211 }
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000212}
213
214
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000215Scope* Scope::DeserializeScopeChain(Context* context, Scope* global_scope,
216 Zone* zone) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000217 // Reconstruct the outer scope chain from a closure's context chain.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000218 Scope* current_scope = NULL;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000219 Scope* innermost_scope = NULL;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000220 bool contains_with = false;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000221 while (!context->IsNativeContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000222 if (context->IsWithContext()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000223 Scope* with_scope = new(zone) Scope(current_scope,
224 WITH_SCOPE,
225 Handle<ScopeInfo>::null(),
226 zone);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000227 current_scope = with_scope;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000228 // 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;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000232 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000233 } else if (context->IsGlobalContext()) {
234 ScopeInfo* scope_info = ScopeInfo::cast(context->extension());
235 current_scope = new(zone) Scope(current_scope,
236 GLOBAL_SCOPE,
237 Handle<ScopeInfo>(scope_info),
238 zone);
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000239 } else if (context->IsModuleContext()) {
240 ScopeInfo* scope_info = ScopeInfo::cast(context->module()->scope_info());
241 current_scope = new(zone) Scope(current_scope,
242 MODULE_SCOPE,
243 Handle<ScopeInfo>(scope_info),
244 zone);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000245 } else if (context->IsFunctionContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000246 ScopeInfo* scope_info = context->closure()->shared()->scope_info();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000247 current_scope = new(zone) Scope(current_scope,
248 FUNCTION_SCOPE,
249 Handle<ScopeInfo>(scope_info),
250 zone);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000251 } else if (context->IsBlockContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000252 ScopeInfo* scope_info = ScopeInfo::cast(context->extension());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000253 current_scope = new(zone) Scope(current_scope,
254 BLOCK_SCOPE,
255 Handle<ScopeInfo>(scope_info),
256 zone);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000257 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000258 ASSERT(context->IsCatchContext());
259 String* name = String::cast(context->extension());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000260 current_scope = new(zone) Scope(
261 current_scope, Handle<String>(name), zone);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000262 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000263 if (contains_with) current_scope->RecordWithStatement();
264 if (innermost_scope == NULL) innermost_scope = current_scope;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000265
266 // Forget about a with when we move to a context for a different function.
267 if (context->previous()->closure() != context->closure()) {
268 contains_with = false;
269 }
270 context = context->previous();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000271 }
272
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000273 global_scope->AddInnerScope(current_scope);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000274 global_scope->PropagateScopeInfo(false);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000275 return (innermost_scope == NULL) ? global_scope : innermost_scope;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000276}
277
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000278
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000279bool Scope::Analyze(CompilationInfo* info) {
280 ASSERT(info->function() != NULL);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000281 Scope* scope = info->function()->scope();
282 Scope* top = scope;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000283
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000284 // Traverse the scope tree up to the first unresolved scope or the global
285 // scope and start scope resolution and variable allocation from that scope.
286 while (!top->is_global_scope() &&
287 !top->outer_scope()->already_resolved()) {
288 top = top->outer_scope();
289 }
290
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000291 // Allocate the variables.
292 {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000293 AstNodeFactory<AstNullVisitor> ast_node_factory(info->isolate(),
294 info->zone());
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000295 if (!top->AllocateVariables(info, &ast_node_factory)) return false;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000296 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000297
298#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000299 if (info->isolate()->bootstrapper()->IsActive()
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000300 ? FLAG_print_builtin_scopes
301 : FLAG_print_scopes) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000302 scope->Print();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000303 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000304
305 if (FLAG_harmony_modules && FLAG_print_interfaces && top->is_global_scope()) {
306 PrintF("global : ");
307 top->interface()->Print();
308 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000309#endif
310
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000311 info->SetScope(scope);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000312 return true;
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000313}
314
315
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000316void Scope::Initialize() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000317 ASSERT(!already_resolved());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319 // Add this scope as a new inner scope of the outer scope.
320 if (outer_scope_ != NULL) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000321 outer_scope_->inner_scopes_.Add(this, zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000322 scope_inside_with_ = outer_scope_->scope_inside_with_ || is_with_scope();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000324 scope_inside_with_ = is_with_scope();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325 }
326
327 // Declare convenience variables.
328 // Declare and allocate receiver (even for the global scope, and even
329 // if naccesses_ == 0).
330 // NOTE: When loading parameters in the global scope, we must take
331 // care not to access them as properties of the global object, but
332 // instead load them directly from the stack. Currently, the only
333 // such parameter is 'this' which is passed on the stack when
334 // invoking scripts
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000335 if (is_declaration_scope()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000336 Variable* var =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000337 variables_.Declare(this,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000338 isolate_->factory()->this_string(),
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000339 VAR,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000340 false,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000341 Variable::THIS,
342 kCreatedInitialized);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000343 var->AllocateTo(Variable::PARAMETER, -1);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000344 receiver_ = var;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000345 } else {
346 ASSERT(outer_scope() != NULL);
347 receiver_ = outer_scope()->receiver();
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000348 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349
350 if (is_function_scope()) {
351 // Declare 'arguments' variable which exists in all functions.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000352 // Note that it might never be accessed, in which case it won't be
353 // allocated during variable allocation.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000354 variables_.Declare(this,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000355 isolate_->factory()->arguments_string(),
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000356 VAR,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000357 true,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000358 Variable::ARGUMENTS,
359 kCreatedInitialized);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 }
361}
362
363
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000364Scope* Scope::FinalizeBlockScope() {
365 ASSERT(is_block_scope());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000366 ASSERT(internals_.is_empty());
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000367 ASSERT(temps_.is_empty());
368 ASSERT(params_.is_empty());
369
370 if (num_var_or_const() > 0) return this;
371
372 // Remove this scope from outer scope.
373 for (int i = 0; i < outer_scope_->inner_scopes_.length(); i++) {
374 if (outer_scope_->inner_scopes_[i] == this) {
375 outer_scope_->inner_scopes_.Remove(i);
376 break;
377 }
378 }
379
380 // Reparent inner scopes.
381 for (int i = 0; i < inner_scopes_.length(); i++) {
382 outer_scope()->AddInnerScope(inner_scopes_[i]);
383 }
384
385 // Move unresolved variables
386 for (int i = 0; i < unresolved_.length(); i++) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000387 outer_scope()->unresolved_.Add(unresolved_[i], zone());
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000388 }
389
390 return NULL;
391}
392
393
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000394Variable* Scope::LocalLookup(Handle<String> name) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000395 Variable* result = variables_.Lookup(name);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000396 if (result != NULL || scope_info_.is_null()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000397 return result;
398 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000399 // If we have a serialized scope info, we might find the variable there.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000400 // There should be no local slot with the given name.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000401 ASSERT(scope_info_->StackSlotIndex(*name) < 0);
402
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000403 // Check context slot lookup.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000404 VariableMode mode;
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000405 Variable::Location location = Variable::CONTEXT;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000406 InitializationFlag init_flag;
407 int index = scope_info_->ContextSlotIndex(*name, &mode, &init_flag);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000408 if (index < 0) {
409 // Check parameters.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000410 index = scope_info_->ParameterIndex(*name);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000411 if (index < 0) return NULL;
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000412
413 mode = DYNAMIC;
414 location = Variable::LOOKUP;
415 init_flag = kCreatedInitialized;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000416 }
417
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000418 Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL,
419 init_flag);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000420 var->AllocateTo(location, index);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000421 return var;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000422}
423
424
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000425Variable* Scope::LookupFunctionVar(Handle<String> name,
426 AstNodeFactory<AstNullVisitor>* factory) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000427 if (function_ != NULL && function_->proxy()->name().is_identical_to(name)) {
428 return function_->proxy()->var();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000429 } else if (!scope_info_.is_null()) {
430 // If we are backed by a scope info, try to lookup the variable there.
431 VariableMode mode;
432 int index = scope_info_->FunctionContextSlotIndex(*name, &mode);
433 if (index < 0) return NULL;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000434 Variable* var = new(zone()) Variable(
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000435 this, name, mode, true /* is valid LHS */,
436 Variable::NORMAL, kCreatedInitialized);
437 VariableProxy* proxy = factory->NewVariableProxy(var);
438 VariableDeclaration* declaration =
439 factory->NewVariableDeclaration(proxy, mode, this);
440 DeclareFunctionVar(declaration);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000441 var->AllocateTo(Variable::CONTEXT, index);
442 return var;
443 } else {
444 return NULL;
445 }
446}
447
448
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000449Variable* Scope::Lookup(Handle<String> name) {
450 for (Scope* scope = this;
451 scope != NULL;
452 scope = scope->outer_scope()) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000453 Variable* var = scope->LocalLookup(name);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000454 if (var != NULL) return var;
455 }
456 return NULL;
457}
458
459
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000460void Scope::DeclareParameter(Handle<String> name, VariableMode mode) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000461 ASSERT(!already_resolved());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000462 ASSERT(is_function_scope());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000463 Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL,
464 kCreatedInitialized);
465 params_.Add(var, zone());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000466}
467
468
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000469Variable* Scope::DeclareLocal(Handle<String> name,
470 VariableMode mode,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000471 InitializationFlag init_flag,
472 Interface* interface) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000473 ASSERT(!already_resolved());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000474 // This function handles VAR and CONST modes. DYNAMIC variables are
475 // introduces during variable allocation, INTERNAL variables are allocated
476 // explicitly, and TEMPORARY variables are allocated via NewTemporary().
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000477 ASSERT(IsDeclaredVariableMode(mode));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000478 ++num_var_or_const_;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000479 return variables_.Declare(
480 this, name, mode, true, Variable::NORMAL, init_flag, interface);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000481}
482
483
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000484Variable* Scope::DeclareDynamicGlobal(Handle<String> name) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000485 ASSERT(is_global_scope());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000486 return variables_.Declare(this,
487 name,
488 DYNAMIC_GLOBAL,
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000489 true,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000490 Variable::NORMAL,
491 kCreatedInitialized);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492}
493
494
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495void Scope::RemoveUnresolved(VariableProxy* var) {
496 // Most likely (always?) any variable we want to remove
497 // was just added before, so we search backwards.
498 for (int i = unresolved_.length(); i-- > 0;) {
499 if (unresolved_[i] == var) {
500 unresolved_.Remove(i);
501 return;
502 }
503 }
504}
505
506
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000507Variable* Scope::NewInternal(Handle<String> name) {
508 ASSERT(!already_resolved());
509 Variable* var = new(zone()) Variable(this,
510 name,
511 INTERNAL,
512 false,
513 Variable::NORMAL,
514 kCreatedInitialized);
515 internals_.Add(var, zone());
516 return var;
517}
518
519
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000520Variable* Scope::NewTemporary(Handle<String> name) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000521 ASSERT(!already_resolved());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000522 Variable* var = new(zone()) Variable(this,
523 name,
524 TEMPORARY,
525 true,
526 Variable::NORMAL,
527 kCreatedInitialized);
528 temps_.Add(var, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000529 return var;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530}
531
532
533void Scope::AddDeclaration(Declaration* declaration) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000534 decls_.Add(declaration, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000535}
536
537
538void Scope::SetIllegalRedeclaration(Expression* expression) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000539 // Record only the first illegal redeclaration.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540 if (!HasIllegalRedeclaration()) {
541 illegal_redecl_ = expression;
542 }
543 ASSERT(HasIllegalRedeclaration());
544}
545
546
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000547void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 ASSERT(HasIllegalRedeclaration());
549 illegal_redecl_->Accept(visitor);
550}
551
552
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000553Declaration* Scope::CheckConflictingVarDeclarations() {
554 int length = decls_.length();
555 for (int i = 0; i < length; i++) {
556 Declaration* decl = decls_[i];
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000557 if (decl->mode() != VAR) continue;
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000558 Handle<String> name = decl->proxy()->name();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000559
560 // Iterate through all scopes until and including the declaration scope.
561 Scope* previous = NULL;
562 Scope* current = decl->scope();
563 do {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000564 // There is a conflict if there exists a non-VAR binding.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000565 Variable* other_var = current->variables_.Lookup(name);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000566 if (other_var != NULL && other_var->mode() != VAR) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000567 return decl;
568 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000569 previous = current;
570 current = current->outer_scope_;
571 } while (!previous->is_declaration_scope());
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000572 }
573 return NULL;
574}
575
576
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000577class VarAndOrder {
578 public:
579 VarAndOrder(Variable* var, int order) : var_(var), order_(order) { }
580 Variable* var() const { return var_; }
581 int order() const { return order_; }
582 static int Compare(const VarAndOrder* a, const VarAndOrder* b) {
583 return a->order_ - b->order_;
584 }
585
586 private:
587 Variable* var_;
588 int order_;
589};
590
591
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000592void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
593 ZoneList<Variable*>* context_locals) {
594 ASSERT(stack_locals != NULL);
595 ASSERT(context_locals != NULL);
596
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000597 // Collect internals which are always allocated on the heap.
598 for (int i = 0; i < internals_.length(); i++) {
599 Variable* var = internals_[i];
600 if (var->is_used()) {
601 ASSERT(var->IsContextSlot());
602 context_locals->Add(var, zone());
603 }
604 }
605
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000606 // Collect temporaries which are always allocated on the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000607 for (int i = 0; i < temps_.length(); i++) {
608 Variable* var = temps_[i];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000609 if (var->is_used()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000610 ASSERT(var->IsStackLocal());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000611 stack_locals->Add(var, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000612 }
613 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000614
615 // Collect declared local variables.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000616 ZoneList<VarAndOrder> vars(variables_.occupancy(), zone());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000617 for (VariableMap::Entry* p = variables_.Start();
618 p != NULL;
619 p = variables_.Next(p)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 Variable* var = reinterpret_cast<Variable*>(p->value);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000621 if (var->is_used()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000622 vars.Add(VarAndOrder(var, p->order), zone());
623 }
624 }
625 vars.Sort(VarAndOrder::Compare);
626 int var_count = vars.length();
627 for (int i = 0; i < var_count; i++) {
628 Variable* var = vars[i].var();
629 if (var->IsStackLocal()) {
630 stack_locals->Add(var, zone());
631 } else if (var->IsContextSlot()) {
632 context_locals->Add(var, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 }
634 }
635}
636
637
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000638bool Scope::AllocateVariables(CompilationInfo* info,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000639 AstNodeFactory<AstNullVisitor>* factory) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640 // 1) Propagate scope information.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000641 bool outer_scope_calls_non_strict_eval = false;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000642 if (outer_scope_ != NULL) {
643 outer_scope_calls_non_strict_eval =
644 outer_scope_->outer_scope_calls_non_strict_eval() |
645 outer_scope_->calls_non_strict_eval();
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000646 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000647 PropagateScopeInfo(outer_scope_calls_non_strict_eval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000649 // 2) Allocate module instances.
650 if (FLAG_harmony_modules && (is_global_scope() || is_module_scope())) {
651 ASSERT(num_modules_ == 0);
652 AllocateModulesRecursively(this);
653 }
654
655 // 3) Resolve variables.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000656 if (!ResolveVariablesRecursively(info, factory)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000658 // 4) Allocate variables.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000659 AllocateVariablesRecursively();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000660
661 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000662}
663
664
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665bool Scope::HasTrivialContext() const {
666 // A function scope has a trivial context if it always is the global
667 // context. We iteratively scan out the context chain to see if
668 // there is anything that makes this scope non-trivial; otherwise we
669 // return true.
670 for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
671 if (scope->is_eval_scope()) return false;
672 if (scope->scope_inside_with_) return false;
673 if (scope->num_heap_slots_ > 0) return false;
674 }
675 return true;
676}
677
678
679bool Scope::HasTrivialOuterContext() const {
680 Scope* outer = outer_scope_;
681 if (outer == NULL) return true;
682 // Note that the outer context may be trivial in general, but the current
683 // scope may be inside a 'with' statement in which case the outer context
684 // for this scope is not trivial.
685 return !scope_inside_with_ && outer->HasTrivialContext();
686}
687
688
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +0000689bool Scope::HasLazyCompilableOuterContext() const {
690 Scope* outer = outer_scope_;
691 if (outer == NULL) return true;
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000692 // We have to prevent lazy compilation if this scope is inside a with scope
693 // and all declaration scopes between them have empty contexts. Such
694 // declaration scopes may become invisible during scope info deserialization.
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +0000695 outer = outer->DeclarationScope();
696 bool found_non_trivial_declarations = false;
697 for (const Scope* scope = outer; scope != NULL; scope = scope->outer_scope_) {
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +0000698 if (scope->is_with_scope() && !found_non_trivial_declarations) return false;
699 if (scope->is_declaration_scope() && scope->num_heap_slots() > 0) {
700 found_non_trivial_declarations = true;
701 }
702 }
703 return true;
704}
705
706
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000707bool Scope::AllowsLazyCompilation() const {
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +0000708 return !force_eager_compilation_ && HasLazyCompilableOuterContext();
ulan@chromium.orgd6899c32012-05-18 14:12:25 +0000709}
710
711
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000712bool Scope::AllowsLazyCompilationWithoutContext() const {
713 return !force_eager_compilation_ && HasTrivialOuterContext();
714}
715
716
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000717int Scope::ContextChainLength(Scope* scope) {
718 int n = 0;
719 for (Scope* s = this; s != scope; s = s->outer_scope_) {
720 ASSERT(s != NULL); // scope must be in the scope chain
721 if (s->num_heap_slots() > 0) n++;
722 }
723 return n;
724}
725
726
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000727Scope* Scope::GlobalScope() {
728 Scope* scope = this;
729 while (!scope->is_global_scope()) {
730 scope = scope->outer_scope();
731 }
732 return scope;
733}
734
735
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000736Scope* Scope::DeclarationScope() {
737 Scope* scope = this;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000738 while (!scope->is_declaration_scope()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000739 scope = scope->outer_scope();
740 }
741 return scope;
742}
743
744
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000745Handle<ScopeInfo> Scope::GetScopeInfo() {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000746 if (scope_info_.is_null()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000747 scope_info_ = ScopeInfo::Create(this, zone());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000748 }
749 return scope_info_;
750}
751
752
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000753void Scope::GetNestedScopeChain(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000754 List<Handle<ScopeInfo> >* chain,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000755 int position) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000756 if (!is_eval_scope()) chain->Add(Handle<ScopeInfo>(GetScopeInfo()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000757
758 for (int i = 0; i < inner_scopes_.length(); i++) {
759 Scope* scope = inner_scopes_[i];
760 int beg_pos = scope->start_position();
761 int end_pos = scope->end_position();
762 ASSERT(beg_pos >= 0 && end_pos >= 0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000763 if (beg_pos <= position && position < end_pos) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000764 scope->GetNestedScopeChain(chain, position);
765 return;
766 }
767 }
768}
769
770
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000772static const char* Header(ScopeType type) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773 switch (type) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000774 case EVAL_SCOPE: return "eval";
775 case FUNCTION_SCOPE: return "function";
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000776 case MODULE_SCOPE: return "module";
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000777 case GLOBAL_SCOPE: return "global";
778 case CATCH_SCOPE: return "catch";
779 case BLOCK_SCOPE: return "block";
780 case WITH_SCOPE: return "with";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000781 }
782 UNREACHABLE();
783 return NULL;
784}
785
786
787static void Indent(int n, const char* str) {
788 PrintF("%*s%s", n, "", str);
789}
790
791
792static void PrintName(Handle<String> name) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000793 SmartArrayPointer<char> s = name->ToCString(DISALLOW_NULLS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000794 PrintF("%s", *s);
795}
796
797
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000798static void PrintLocation(Variable* var) {
799 switch (var->location()) {
800 case Variable::UNALLOCATED:
801 break;
802 case Variable::PARAMETER:
803 PrintF("parameter[%d]", var->index());
804 break;
805 case Variable::LOCAL:
806 PrintF("local[%d]", var->index());
807 break;
808 case Variable::CONTEXT:
809 PrintF("context[%d]", var->index());
810 break;
811 case Variable::LOOKUP:
812 PrintF("lookup");
813 break;
814 }
815}
816
817
818static void PrintVar(int indent, Variable* var) {
819 if (var->is_used() || !var->IsUnallocated()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000820 Indent(indent, Variable::Mode2String(var->mode()));
821 PrintF(" ");
822 PrintName(var->name());
823 PrintF("; // ");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000824 PrintLocation(var);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000825 if (var->has_forced_context_allocation()) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000826 if (!var->IsUnallocated()) PrintF(", ");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000827 PrintF("forced context allocation");
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000828 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000829 PrintF("\n");
830 }
831}
832
833
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000834static void PrintMap(int indent, VariableMap* map) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000835 for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000836 Variable* var = reinterpret_cast<Variable*>(p->value);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000837 PrintVar(indent, var);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000838 }
839}
840
841
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842void Scope::Print(int n) {
843 int n0 = (n > 0 ? n : 0);
844 int n1 = n0 + 2; // indentation
845
846 // Print header.
847 Indent(n0, Header(type_));
848 if (scope_name_->length() > 0) {
849 PrintF(" ");
850 PrintName(scope_name_);
851 }
852
853 // Print parameters, if any.
854 if (is_function_scope()) {
855 PrintF(" (");
856 for (int i = 0; i < params_.length(); i++) {
857 if (i > 0) PrintF(", ");
858 PrintName(params_[i]->name());
859 }
860 PrintF(")");
861 }
862
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000863 PrintF(" { // (%d, %d)\n", start_position(), end_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864
865 // Function name, if any (named function literals, only).
866 if (function_ != NULL) {
867 Indent(n1, "// (local) function name: ");
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000868 PrintName(function_->proxy()->name());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000869 PrintF("\n");
870 }
871
872 // Scope info.
873 if (HasTrivialOuterContext()) {
874 Indent(n1, "// scope has trivial outer context\n");
875 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000876 switch (language_mode()) {
877 case CLASSIC_MODE:
878 break;
879 case STRICT_MODE:
880 Indent(n1, "// strict mode scope\n");
881 break;
882 case EXTENDED_MODE:
883 Indent(n1, "// extended mode scope\n");
884 break;
885 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886 if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
887 if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
888 if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000889 if (outer_scope_calls_non_strict_eval_) {
890 Indent(n1, "// outer scope calls 'eval' in non-strict context\n");
891 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000892 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
893 if (num_stack_slots_ > 0) { Indent(n1, "// ");
894 PrintF("%d stack slots\n", num_stack_slots_); }
895 if (num_heap_slots_ > 0) { Indent(n1, "// ");
896 PrintF("%d heap slots\n", num_heap_slots_); }
897
898 // Print locals.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899 Indent(n1, "// function var\n");
900 if (function_ != NULL) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000901 PrintVar(n1, function_->proxy()->var());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902 }
903
904 Indent(n1, "// temporary vars\n");
905 for (int i = 0; i < temps_.length(); i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000906 PrintVar(n1, temps_[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000907 }
908
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000909 Indent(n1, "// internal vars\n");
910 for (int i = 0; i < internals_.length(); i++) {
911 PrintVar(n1, internals_[i]);
912 }
913
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914 Indent(n1, "// local vars\n");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000915 PrintMap(n1, &variables_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000917 Indent(n1, "// dynamic vars\n");
918 if (dynamics_ != NULL) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000919 PrintMap(n1, dynamics_->GetMap(DYNAMIC));
920 PrintMap(n1, dynamics_->GetMap(DYNAMIC_LOCAL));
921 PrintMap(n1, dynamics_->GetMap(DYNAMIC_GLOBAL));
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000922 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923
924 // Print inner scopes (disable by providing negative n).
925 if (n >= 0) {
926 for (int i = 0; i < inner_scopes_.length(); i++) {
927 PrintF("\n");
928 inner_scopes_[i]->Print(n1);
929 }
930 }
931
932 Indent(n0, "}\n");
933}
934#endif // DEBUG
935
936
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000937Variable* Scope::NonLocal(Handle<String> name, VariableMode mode) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000938 if (dynamics_ == NULL) dynamics_ = new(zone()) DynamicScopePart(zone());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000939 VariableMap* map = dynamics_->GetMap(mode);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000940 Variable* var = map->Lookup(name);
941 if (var == NULL) {
942 // Declare a new non-local.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000943 InitializationFlag init_flag = (mode == VAR)
944 ? kCreatedInitialized : kNeedsInitialization;
945 var = map->Declare(NULL,
946 name,
947 mode,
948 true,
949 Variable::NORMAL,
950 init_flag);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000951 // Allocate it by giving it a dynamic lookup.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000952 var->AllocateTo(Variable::LOOKUP, -1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000953 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000954 return var;
955}
956
957
ager@chromium.org381abbb2009-02-25 13:23:22 +0000958Variable* Scope::LookupRecursive(Handle<String> name,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000959 BindingKind* binding_kind,
960 AstNodeFactory<AstNullVisitor>* factory) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000961 ASSERT(binding_kind != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000962 // Try to find the variable in this scope.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000963 Variable* var = LocalLookup(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000964
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000965 // We found a variable and we are done. (Even if there is an 'eval' in
966 // this scope which introduces the same variable again, the resulting
967 // variable remains the same.)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000968 if (var != NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000969 *binding_kind = BOUND;
970 return var;
971 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000972
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000973 // We did not find a variable locally. Check against the function variable,
974 // if any. We can do this for all scopes, since the function variable is
975 // only present - if at all - for function scopes.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000976 *binding_kind = UNBOUND;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000977 var = LookupFunctionVar(name, factory);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000978 if (var != NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000979 *binding_kind = BOUND;
980 } else if (outer_scope_ != NULL) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000981 var = outer_scope_->LookupRecursive(name, binding_kind, factory);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000982 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) {
983 var->ForceContextAllocation();
984 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000985 } else {
986 ASSERT(is_global_scope());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000987 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000989 if (is_with_scope()) {
990 // The current scope is a with scope, so the variable binding can not be
991 // statically resolved. However, note that it was necessary to do a lookup
992 // in the outer scope anyway, because if a binding exists in an outer scope,
993 // the associated variable has to be marked as potentially being accessed
994 // from inside of an inner with scope (the property may not be in the 'with'
995 // object).
996 *binding_kind = DYNAMIC_LOOKUP;
997 return NULL;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000998 } else if (calls_non_strict_eval()) {
999 // A variable binding may have been found in an outer scope, but the current
1000 // scope makes a non-strict 'eval' call, so the found variable may not be
1001 // the correct one (the 'eval' may introduce a binding with the same name).
1002 // In that case, change the lookup result to reflect this situation.
1003 if (*binding_kind == BOUND) {
1004 *binding_kind = BOUND_EVAL_SHADOWED;
1005 } else if (*binding_kind == UNBOUND) {
1006 *binding_kind = UNBOUND_EVAL_SHADOWED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009 return var;
1010}
1011
1012
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001013bool Scope::ResolveVariable(CompilationInfo* info,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001014 VariableProxy* proxy,
1015 AstNodeFactory<AstNullVisitor>* factory) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001016 ASSERT(info->global_scope()->is_global_scope());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017
1018 // If the proxy is already resolved there's nothing to do
1019 // (functions and consts may be resolved by the parser).
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001020 if (proxy->var() != NULL) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021
1022 // Otherwise, try to resolve the variable.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001023 BindingKind binding_kind;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001024 Variable* var = LookupRecursive(proxy->name(), &binding_kind, factory);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001025 switch (binding_kind) {
1026 case BOUND:
1027 // We found a variable binding.
1028 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001029
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001030 case BOUND_EVAL_SHADOWED:
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001031 // We either found a variable binding that might be shadowed by eval or
1032 // gave up on it (e.g. by encountering a local with the same in the outer
1033 // scope which was not promoted to a context, this can happen if we use
1034 // debugger to evaluate arbitrary expressions at a break point).
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001035 if (var->IsGlobalObjectProperty()) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001036 var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001037 } else if (var->is_dynamic()) {
1038 var = NonLocal(proxy->name(), DYNAMIC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001039 } else {
1040 Variable* invalidated = var;
1041 var = NonLocal(proxy->name(), DYNAMIC_LOCAL);
1042 var->set_local_if_not_shadowed(invalidated);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001043 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001044 break;
1045
1046 case UNBOUND:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001047 // No binding has been found. Declare a variable on the global object.
1048 var = info->global_scope()->DeclareDynamicGlobal(proxy->name());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001049 break;
1050
1051 case UNBOUND_EVAL_SHADOWED:
1052 // No binding has been found. But some scope makes a
1053 // non-strict 'eval' call.
1054 var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
1055 break;
1056
1057 case DYNAMIC_LOOKUP:
1058 // The variable could not be resolved statically.
1059 var = NonLocal(proxy->name(), DYNAMIC);
1060 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001061 }
1062
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001063 ASSERT(var != NULL);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001064
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001065 if (FLAG_harmony_scoping && is_extended_mode() &&
1066 var->is_const_mode() && proxy->IsLValue()) {
1067 // Assignment to const. Throw a syntax error.
1068 MessageLocation location(
1069 info->script(), proxy->position(), proxy->position());
1070 Isolate* isolate = Isolate::Current();
1071 Factory* factory = isolate->factory();
1072 Handle<JSArray> array = factory->NewJSArray(0);
1073 Handle<Object> result =
1074 factory->NewSyntaxError("harmony_const_assign", array);
1075 isolate->Throw(*result, &location);
1076 return false;
1077 }
1078
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001079 if (FLAG_harmony_modules) {
1080 bool ok;
1081#ifdef DEBUG
1082 if (FLAG_print_interface_details)
1083 PrintF("# Resolve %s:\n", var->name()->ToAsciiArray());
1084#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001085 proxy->interface()->Unify(var->interface(), zone(), &ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001086 if (!ok) {
1087#ifdef DEBUG
1088 if (FLAG_print_interfaces) {
1089 PrintF("SCOPES TYPE ERROR\n");
1090 PrintF("proxy: ");
1091 proxy->interface()->Print();
1092 PrintF("var: ");
1093 var->interface()->Print();
1094 }
1095#endif
1096
1097 // Inconsistent use of module. Throw a syntax error.
1098 // TODO(rossberg): generate more helpful error message.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001099 MessageLocation location(
1100 info->script(), proxy->position(), proxy->position());
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001101 Isolate* isolate = Isolate::Current();
1102 Factory* factory = isolate->factory();
1103 Handle<JSArray> array = factory->NewJSArray(1);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001104 USE(JSObject::SetElement(array, 0, var->name(), NONE, kStrictMode));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001105 Handle<Object> result =
1106 factory->NewSyntaxError("module_type_error", array);
1107 isolate->Throw(*result, &location);
1108 return false;
1109 }
1110 }
1111
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001112 proxy->BindTo(var);
1113
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001114 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001115}
1116
1117
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001118bool Scope::ResolveVariablesRecursively(
1119 CompilationInfo* info,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001120 AstNodeFactory<AstNullVisitor>* factory) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001121 ASSERT(info->global_scope()->is_global_scope());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001122
1123 // Resolve unresolved variables for this scope.
1124 for (int i = 0; i < unresolved_.length(); i++) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001125 if (!ResolveVariable(info, unresolved_[i], factory)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001126 }
1127
1128 // Resolve unresolved variables for inner scopes.
1129 for (int i = 0; i < inner_scopes_.length(); i++) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001130 if (!inner_scopes_[i]->ResolveVariablesRecursively(info, factory))
1131 return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001132 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001133
1134 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001135}
1136
1137
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001138bool Scope::PropagateScopeInfo(bool outer_scope_calls_non_strict_eval ) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001139 if (outer_scope_calls_non_strict_eval) {
1140 outer_scope_calls_non_strict_eval_ = true;
1141 }
1142
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001143 bool calls_non_strict_eval =
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001144 this->calls_non_strict_eval() || outer_scope_calls_non_strict_eval_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001145 for (int i = 0; i < inner_scopes_.length(); i++) {
1146 Scope* inner_scope = inner_scopes_[i];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001147 if (inner_scope->PropagateScopeInfo(calls_non_strict_eval)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 inner_scope_calls_eval_ = true;
1149 }
1150 if (inner_scope->force_eager_compilation_) {
1151 force_eager_compilation_ = true;
1152 }
1153 }
1154
1155 return scope_calls_eval_ || inner_scope_calls_eval_;
1156}
1157
1158
1159bool Scope::MustAllocate(Variable* var) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001160 // Give var a read/write use if there is a chance it might be accessed
1161 // via an eval() call. This is only possible if the variable has a
1162 // visible name.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 if ((var->is_this() || var->name()->length() > 0) &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001164 (var->has_forced_context_allocation() ||
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001165 scope_calls_eval_ ||
1166 inner_scope_calls_eval_ ||
1167 scope_contains_with_ ||
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001168 is_catch_scope() ||
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001169 is_block_scope() ||
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001170 is_module_scope() ||
1171 is_global_scope())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001172 var->set_is_used(true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001173 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001174 // Global variables do not need to be allocated.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001175 return !var->IsGlobalObjectProperty() && var->is_used();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176}
1177
1178
1179bool Scope::MustAllocateInContext(Variable* var) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001180 // If var is accessed from an inner scope, or if there is a possibility
1181 // that it might be accessed from the current or an inner scope (through
1182 // an eval() call or a runtime with lookup), it must be allocated in the
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001183 // context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001184 //
1185 // Exceptions: temporary variables are never allocated in a context;
1186 // catch-bound variables are always allocated in a context.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001187 if (var->mode() == TEMPORARY) return false;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001188 if (var->mode() == INTERNAL) return true;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001189 if (is_catch_scope() || is_block_scope() || is_module_scope()) return true;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001190 if (is_global_scope() && IsLexicalVariableMode(var->mode())) return true;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001191 return var->has_forced_context_allocation() ||
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001192 scope_calls_eval_ ||
1193 inner_scope_calls_eval_ ||
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001194 scope_contains_with_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195}
1196
1197
1198bool Scope::HasArgumentsParameter() {
1199 for (int i = 0; i < params_.length(); i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001200 if (params_[i]->name().is_identical_to(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001201 isolate_->factory()->arguments_string())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001202 return true;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001203 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001204 }
1205 return false;
1206}
1207
1208
1209void Scope::AllocateStackSlot(Variable* var) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001210 var->AllocateTo(Variable::LOCAL, num_stack_slots_++);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211}
1212
1213
1214void Scope::AllocateHeapSlot(Variable* var) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001215 var->AllocateTo(Variable::CONTEXT, num_heap_slots_++);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001216}
1217
1218
1219void Scope::AllocateParameterLocals() {
1220 ASSERT(is_function_scope());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001221 Variable* arguments = LocalLookup(isolate_->factory()->arguments_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001223
whesse@chromium.org7b260152011-06-20 15:33:18 +00001224 bool uses_nonstrict_arguments = false;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001225
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 if (MustAllocate(arguments) && !HasArgumentsParameter()) {
1227 // 'arguments' is used. Unless there is also a parameter called
whesse@chromium.org7b260152011-06-20 15:33:18 +00001228 // 'arguments', we must be conservative and allocate all parameters to
1229 // the context assuming they will be captured by the arguments object.
1230 // If we have a parameter named 'arguments', a (new) value is always
1231 // assigned to it via the function invocation. Then 'arguments' denotes
1232 // that specific parameter value and cannot be used to access the
1233 // parameters, which is why we don't need to allocate an arguments
1234 // object in that case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001235
1236 // We are using 'arguments'. Tell the code generator that is needs to
1237 // allocate the arguments object by setting 'arguments_'.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001238 arguments_ = arguments;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001239
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001240 // In strict mode 'arguments' does not alias formal parameters.
1241 // Therefore in strict mode we allocate parameters as if 'arguments'
1242 // were not used.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001243 uses_nonstrict_arguments = is_classic_mode();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001244 }
1245
whesse@chromium.org7b260152011-06-20 15:33:18 +00001246 // The same parameter may occur multiple times in the parameters_ list.
1247 // If it does, and if it is not copied into the context object, it must
1248 // receive the highest parameter index for that parameter; thus iteration
1249 // order is relevant!
1250 for (int i = params_.length() - 1; i >= 0; --i) {
1251 Variable* var = params_[i];
1252 ASSERT(var->scope() == this);
1253 if (uses_nonstrict_arguments) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001254 // Force context allocation of the parameter.
1255 var->ForceContextAllocation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256 }
1257
whesse@chromium.org7b260152011-06-20 15:33:18 +00001258 if (MustAllocate(var)) {
1259 if (MustAllocateInContext(var)) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001260 ASSERT(var->IsUnallocated() || var->IsContextSlot());
1261 if (var->IsUnallocated()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001262 AllocateHeapSlot(var);
1263 }
1264 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001265 ASSERT(var->IsUnallocated() || var->IsParameter());
1266 if (var->IsUnallocated()) {
1267 var->AllocateTo(Variable::PARAMETER, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268 }
1269 }
1270 }
1271 }
1272}
1273
1274
1275void Scope::AllocateNonParameterLocal(Variable* var) {
1276 ASSERT(var->scope() == this);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001277 ASSERT(!var->IsVariable(isolate_->factory()->result_string()) ||
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001278 !var->IsStackLocal());
1279 if (var->IsUnallocated() && MustAllocate(var)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280 if (MustAllocateInContext(var)) {
1281 AllocateHeapSlot(var);
1282 } else {
1283 AllocateStackSlot(var);
1284 }
1285 }
1286}
1287
1288
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001289void Scope::AllocateNonParameterLocals() {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001290 // All variables that have no rewrite yet are non-parameter locals.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291 for (int i = 0; i < temps_.length(); i++) {
1292 AllocateNonParameterLocal(temps_[i]);
1293 }
1294
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001295 for (int i = 0; i < internals_.length(); i++) {
1296 AllocateNonParameterLocal(internals_[i]);
1297 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001298
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001299 ZoneList<VarAndOrder> vars(variables_.occupancy(), zone());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001300 for (VariableMap::Entry* p = variables_.Start();
1301 p != NULL;
1302 p = variables_.Next(p)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 Variable* var = reinterpret_cast<Variable*>(p->value);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001304 vars.Add(VarAndOrder(var, p->order), zone());
1305 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001306 vars.Sort(VarAndOrder::Compare);
1307 int var_count = vars.length();
1308 for (int i = 0; i < var_count; i++) {
1309 AllocateNonParameterLocal(vars[i].var());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 }
1311
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001312 // For now, function_ must be allocated at the very end. If it gets
1313 // allocated in the context, it must be the last slot in the context,
1314 // because of the current ScopeInfo implementation (see
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
1316 if (function_ != NULL) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001317 AllocateNonParameterLocal(function_->proxy()->var());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001318 }
1319}
1320
1321
1322void Scope::AllocateVariablesRecursively() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323 // Allocate variables for inner scopes.
1324 for (int i = 0; i < inner_scopes_.length(); i++) {
1325 inner_scopes_[i]->AllocateVariablesRecursively();
1326 }
1327
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001328 // If scope is already resolved, we still need to allocate
1329 // variables in inner scopes which might not had been resolved yet.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001330 if (already_resolved()) return;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001331 // The number of slots required for variables.
1332 num_stack_slots_ = 0;
1333 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
1334
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335 // Allocate variables for this scope.
1336 // Parameters must be allocated first, if any.
1337 if (is_function_scope()) AllocateParameterLocals();
1338 AllocateNonParameterLocals();
1339
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001340 // Force allocation of a context for this scope if necessary. For a 'with'
1341 // scope and for a function scope that makes an 'eval' call we need a context,
1342 // even if no local variables were statically allocated in the scope.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001343 // Likewise for modules.
1344 bool must_have_context = is_with_scope() || is_module_scope() ||
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001345 (is_function_scope() && calls_eval());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001346
1347 // If we didn't allocate any locals in the local context, then we only
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001348 // need the minimal number of slots if we must have a context.
1349 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && !must_have_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001350 num_heap_slots_ = 0;
1351 }
1352
1353 // Allocation done.
1354 ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
1355}
1356
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001357
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001358void Scope::AllocateModulesRecursively(Scope* host_scope) {
1359 if (already_resolved()) return;
1360 if (is_module_scope()) {
1361 ASSERT(interface_->IsFrozen());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001362 Handle<String> name = isolate_->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001363 STATIC_ASCII_VECTOR(".module"));
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001364 ASSERT(module_var_ == NULL);
1365 module_var_ = host_scope->NewInternal(name);
1366 ++host_scope->num_modules_;
1367 }
1368
1369 for (int i = 0; i < inner_scopes_.length(); i++) {
1370 Scope* inner_scope = inner_scopes_.at(i);
1371 inner_scope->AllocateModulesRecursively(host_scope);
1372 }
1373}
1374
1375
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001376int Scope::StackLocalCount() const {
1377 return num_stack_slots() -
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001378 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001379}
1380
1381
1382int Scope::ContextLocalCount() const {
1383 if (num_heap_slots() == 0) return 0;
1384 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS -
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001385 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001386}
1387
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388} } // namespace v8::internal