blob: 6ae7cc0691ae2e36fc194856d535e27383d458ee [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
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000107Scope::Scope(Scope* outer_scope, ScopeType scope_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 &&
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000117 (scope_type == MODULE_SCOPE || scope_type == GLOBAL_SCOPE)
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000118 ? Interface::NewModule(zone) : NULL),
119 already_resolved_(false),
120 zone_(zone) {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000121 SetDefaults(scope_type, outer_scope, Handle<ScopeInfo>::null());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000122 // The outermost scope must be a global scope.
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000123 ASSERT(scope_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,
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000129 ScopeType scope_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) {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000143 SetDefaults(scope_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
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000180void Scope::SetDefaults(ScopeType scope_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;
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000184 scope_type_ = scope_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;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000200 force_context_allocation_ = (outer_scope != NULL && !is_function_scope())
201 ? outer_scope->has_forced_context_allocation() : false;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000202 num_var_or_const_ = 0;
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000203 num_stack_slots_ = 0;
204 num_heap_slots_ = 0;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000205 num_modules_ = 0;
206 module_var_ = NULL,
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000207 scope_info_ = scope_info;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000208 start_position_ = RelocInfo::kNoPosition;
209 end_position_ = RelocInfo::kNoPosition;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000210 if (!scope_info.is_null()) {
211 scope_calls_eval_ = scope_info->CallsEval();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000212 language_mode_ = scope_info->language_mode();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000213 }
sgjesse@chromium.org34755092011-04-07 08:41:03 +0000214}
215
216
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000217Scope* Scope::DeserializeScopeChain(Context* context, Scope* global_scope,
218 Zone* zone) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000219 // Reconstruct the outer scope chain from a closure's context chain.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000220 Scope* current_scope = NULL;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000221 Scope* innermost_scope = NULL;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000222 bool contains_with = false;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000223 while (!context->IsNativeContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000224 if (context->IsWithContext()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000225 Scope* with_scope = new(zone) Scope(current_scope,
226 WITH_SCOPE,
227 Handle<ScopeInfo>::null(),
228 zone);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000229 current_scope = with_scope;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000230 // All the inner scopes are inside a with.
231 contains_with = true;
232 for (Scope* s = innermost_scope; s != NULL; s = s->outer_scope()) {
233 s->scope_inside_with_ = true;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000234 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000235 } else if (context->IsGlobalContext()) {
236 ScopeInfo* scope_info = ScopeInfo::cast(context->extension());
237 current_scope = new(zone) Scope(current_scope,
238 GLOBAL_SCOPE,
239 Handle<ScopeInfo>(scope_info),
240 zone);
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000241 } else if (context->IsModuleContext()) {
242 ScopeInfo* scope_info = ScopeInfo::cast(context->module()->scope_info());
243 current_scope = new(zone) Scope(current_scope,
244 MODULE_SCOPE,
245 Handle<ScopeInfo>(scope_info),
246 zone);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000247 } else if (context->IsFunctionContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000248 ScopeInfo* scope_info = context->closure()->shared()->scope_info();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000249 current_scope = new(zone) Scope(current_scope,
250 FUNCTION_SCOPE,
251 Handle<ScopeInfo>(scope_info),
252 zone);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000253 } else if (context->IsBlockContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000254 ScopeInfo* scope_info = ScopeInfo::cast(context->extension());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000255 current_scope = new(zone) Scope(current_scope,
256 BLOCK_SCOPE,
257 Handle<ScopeInfo>(scope_info),
258 zone);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000259 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000260 ASSERT(context->IsCatchContext());
261 String* name = String::cast(context->extension());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000262 current_scope = new(zone) Scope(
263 current_scope, Handle<String>(name), zone);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000264 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000265 if (contains_with) current_scope->RecordWithStatement();
266 if (innermost_scope == NULL) innermost_scope = current_scope;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000267
268 // Forget about a with when we move to a context for a different function.
269 if (context->previous()->closure() != context->closure()) {
270 contains_with = false;
271 }
272 context = context->previous();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000273 }
274
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000275 global_scope->AddInnerScope(current_scope);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000276 global_scope->PropagateScopeInfo(false);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000277 return (innermost_scope == NULL) ? global_scope : innermost_scope;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000278}
279
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000280
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000281bool Scope::Analyze(CompilationInfo* info) {
282 ASSERT(info->function() != NULL);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000283 Scope* scope = info->function()->scope();
284 Scope* top = scope;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000285
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000286 // Traverse the scope tree up to the first unresolved scope or the global
287 // scope and start scope resolution and variable allocation from that scope.
288 while (!top->is_global_scope() &&
289 !top->outer_scope()->already_resolved()) {
290 top = top->outer_scope();
291 }
292
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000293 // Allocate the variables.
294 {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000295 AstNodeFactory<AstNullVisitor> ast_node_factory(info->isolate(),
296 info->zone());
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000297 if (!top->AllocateVariables(info, &ast_node_factory)) return false;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000298 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000299
300#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 if (info->isolate()->bootstrapper()->IsActive()
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000302 ? FLAG_print_builtin_scopes
303 : FLAG_print_scopes) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000304 scope->Print();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000305 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000306
307 if (FLAG_harmony_modules && FLAG_print_interfaces && top->is_global_scope()) {
308 PrintF("global : ");
309 top->interface()->Print();
310 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000311#endif
312
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000313 info->SetScope(scope);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000314 return true;
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000315}
316
317
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000318void Scope::Initialize() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000319 ASSERT(!already_resolved());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000320
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000321 // Add this scope as a new inner scope of the outer scope.
322 if (outer_scope_ != NULL) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000323 outer_scope_->inner_scopes_.Add(this, zone());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000324 scope_inside_with_ = outer_scope_->scope_inside_with_ || is_with_scope();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000326 scope_inside_with_ = is_with_scope();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327 }
328
329 // Declare convenience variables.
330 // Declare and allocate receiver (even for the global scope, and even
331 // if naccesses_ == 0).
332 // NOTE: When loading parameters in the global scope, we must take
333 // care not to access them as properties of the global object, but
334 // instead load them directly from the stack. Currently, the only
335 // such parameter is 'this' which is passed on the stack when
336 // invoking scripts
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000337 if (is_declaration_scope()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000338 Variable* var =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000339 variables_.Declare(this,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000340 isolate_->factory()->this_string(),
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000341 VAR,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000342 false,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000343 Variable::THIS,
344 kCreatedInitialized);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000345 var->AllocateTo(Variable::PARAMETER, -1);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000346 receiver_ = var;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000347 } else {
348 ASSERT(outer_scope() != NULL);
349 receiver_ = outer_scope()->receiver();
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000350 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000351
352 if (is_function_scope()) {
353 // Declare 'arguments' variable which exists in all functions.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000354 // Note that it might never be accessed, in which case it won't be
355 // allocated during variable allocation.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000356 variables_.Declare(this,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000357 isolate_->factory()->arguments_string(),
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000358 VAR,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000359 true,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000360 Variable::ARGUMENTS,
361 kCreatedInitialized);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 }
363}
364
365
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000366Scope* Scope::FinalizeBlockScope() {
367 ASSERT(is_block_scope());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000368 ASSERT(internals_.is_empty());
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000369 ASSERT(temps_.is_empty());
370 ASSERT(params_.is_empty());
371
372 if (num_var_or_const() > 0) return this;
373
374 // Remove this scope from outer scope.
375 for (int i = 0; i < outer_scope_->inner_scopes_.length(); i++) {
376 if (outer_scope_->inner_scopes_[i] == this) {
377 outer_scope_->inner_scopes_.Remove(i);
378 break;
379 }
380 }
381
382 // Reparent inner scopes.
383 for (int i = 0; i < inner_scopes_.length(); i++) {
384 outer_scope()->AddInnerScope(inner_scopes_[i]);
385 }
386
387 // Move unresolved variables
388 for (int i = 0; i < unresolved_.length(); i++) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000389 outer_scope()->unresolved_.Add(unresolved_[i], zone());
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000390 }
391
392 return NULL;
393}
394
395
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000396Variable* Scope::LocalLookup(Handle<String> name) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000397 Variable* result = variables_.Lookup(name);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000398 if (result != NULL || scope_info_.is_null()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000399 return result;
400 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000401 // If we have a serialized scope info, we might find the variable there.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000402 // There should be no local slot with the given name.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000403 ASSERT(scope_info_->StackSlotIndex(*name) < 0);
404
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000405 // Check context slot lookup.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000406 VariableMode mode;
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000407 Variable::Location location = Variable::CONTEXT;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000408 InitializationFlag init_flag;
409 int index = scope_info_->ContextSlotIndex(*name, &mode, &init_flag);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000410 if (index < 0) {
411 // Check parameters.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000412 index = scope_info_->ParameterIndex(*name);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000413 if (index < 0) return NULL;
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000414
415 mode = DYNAMIC;
416 location = Variable::LOOKUP;
417 init_flag = kCreatedInitialized;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000418 }
419
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000420 Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL,
421 init_flag);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000422 var->AllocateTo(location, index);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000423 return var;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000424}
425
426
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000427Variable* Scope::LookupFunctionVar(Handle<String> name,
428 AstNodeFactory<AstNullVisitor>* factory) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000429 if (function_ != NULL && function_->proxy()->name().is_identical_to(name)) {
430 return function_->proxy()->var();
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000431 } else if (!scope_info_.is_null()) {
432 // If we are backed by a scope info, try to lookup the variable there.
433 VariableMode mode;
434 int index = scope_info_->FunctionContextSlotIndex(*name, &mode);
435 if (index < 0) return NULL;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000436 Variable* var = new(zone()) Variable(
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000437 this, name, mode, true /* is valid LHS */,
438 Variable::NORMAL, kCreatedInitialized);
439 VariableProxy* proxy = factory->NewVariableProxy(var);
440 VariableDeclaration* declaration =
441 factory->NewVariableDeclaration(proxy, mode, this);
442 DeclareFunctionVar(declaration);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000443 var->AllocateTo(Variable::CONTEXT, index);
444 return var;
445 } else {
446 return NULL;
447 }
448}
449
450
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000451Variable* Scope::Lookup(Handle<String> name) {
452 for (Scope* scope = this;
453 scope != NULL;
454 scope = scope->outer_scope()) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000455 Variable* var = scope->LocalLookup(name);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000456 if (var != NULL) return var;
457 }
458 return NULL;
459}
460
461
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000462void Scope::DeclareParameter(Handle<String> name, VariableMode mode) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000463 ASSERT(!already_resolved());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000464 ASSERT(is_function_scope());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000465 Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL,
466 kCreatedInitialized);
467 params_.Add(var, zone());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000468}
469
470
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000471Variable* Scope::DeclareLocal(Handle<String> name,
472 VariableMode mode,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000473 InitializationFlag init_flag,
474 Interface* interface) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000475 ASSERT(!already_resolved());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000476 // This function handles VAR and CONST modes. DYNAMIC variables are
477 // introduces during variable allocation, INTERNAL variables are allocated
478 // explicitly, and TEMPORARY variables are allocated via NewTemporary().
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000479 ASSERT(IsDeclaredVariableMode(mode));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +0000480 ++num_var_or_const_;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000481 return variables_.Declare(
482 this, name, mode, true, Variable::NORMAL, init_flag, interface);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000483}
484
485
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000486Variable* Scope::DeclareDynamicGlobal(Handle<String> name) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000487 ASSERT(is_global_scope());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000488 return variables_.Declare(this,
489 name,
490 DYNAMIC_GLOBAL,
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000491 true,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000492 Variable::NORMAL,
493 kCreatedInitialized);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000494}
495
496
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497void Scope::RemoveUnresolved(VariableProxy* var) {
498 // Most likely (always?) any variable we want to remove
499 // was just added before, so we search backwards.
500 for (int i = unresolved_.length(); i-- > 0;) {
501 if (unresolved_[i] == var) {
502 unresolved_.Remove(i);
503 return;
504 }
505 }
506}
507
508
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000509Variable* Scope::NewInternal(Handle<String> name) {
510 ASSERT(!already_resolved());
511 Variable* var = new(zone()) Variable(this,
512 name,
513 INTERNAL,
514 false,
515 Variable::NORMAL,
516 kCreatedInitialized);
517 internals_.Add(var, zone());
518 return var;
519}
520
521
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000522Variable* Scope::NewTemporary(Handle<String> name) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000523 ASSERT(!already_resolved());
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000524 Variable* var = new(zone()) Variable(this,
525 name,
526 TEMPORARY,
527 true,
528 Variable::NORMAL,
529 kCreatedInitialized);
530 temps_.Add(var, zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000531 return var;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532}
533
534
535void Scope::AddDeclaration(Declaration* declaration) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000536 decls_.Add(declaration, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537}
538
539
540void Scope::SetIllegalRedeclaration(Expression* expression) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000541 // Record only the first illegal redeclaration.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542 if (!HasIllegalRedeclaration()) {
543 illegal_redecl_ = expression;
544 }
545 ASSERT(HasIllegalRedeclaration());
546}
547
548
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000549void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550 ASSERT(HasIllegalRedeclaration());
551 illegal_redecl_->Accept(visitor);
552}
553
554
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000555Declaration* Scope::CheckConflictingVarDeclarations() {
556 int length = decls_.length();
557 for (int i = 0; i < length; i++) {
558 Declaration* decl = decls_[i];
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000559 if (decl->mode() != VAR) continue;
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000560 Handle<String> name = decl->proxy()->name();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000561
562 // Iterate through all scopes until and including the declaration scope.
563 Scope* previous = NULL;
564 Scope* current = decl->scope();
565 do {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000566 // There is a conflict if there exists a non-VAR binding.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000567 Variable* other_var = current->variables_.Lookup(name);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000568 if (other_var != NULL && other_var->mode() != VAR) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000569 return decl;
570 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000571 previous = current;
572 current = current->outer_scope_;
573 } while (!previous->is_declaration_scope());
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000574 }
575 return NULL;
576}
577
578
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000579class VarAndOrder {
580 public:
581 VarAndOrder(Variable* var, int order) : var_(var), order_(order) { }
582 Variable* var() const { return var_; }
583 int order() const { return order_; }
584 static int Compare(const VarAndOrder* a, const VarAndOrder* b) {
585 return a->order_ - b->order_;
586 }
587
588 private:
589 Variable* var_;
590 int order_;
591};
592
593
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000594void Scope::CollectStackAndContextLocals(ZoneList<Variable*>* stack_locals,
595 ZoneList<Variable*>* context_locals) {
596 ASSERT(stack_locals != NULL);
597 ASSERT(context_locals != NULL);
598
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000599 // Collect internals which are always allocated on the heap.
600 for (int i = 0; i < internals_.length(); i++) {
601 Variable* var = internals_[i];
602 if (var->is_used()) {
603 ASSERT(var->IsContextSlot());
604 context_locals->Add(var, zone());
605 }
606 }
607
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000608 // Collect temporaries which are always allocated on the stack, unless the
609 // context as a whole has forced context allocation.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000610 for (int i = 0; i < temps_.length(); i++) {
611 Variable* var = temps_[i];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000612 if (var->is_used()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000613 if (var->IsContextSlot()) {
614 ASSERT(has_forced_context_allocation());
615 context_locals->Add(var, zone());
616 } else {
617 ASSERT(var->IsStackLocal());
618 stack_locals->Add(var, zone());
619 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 }
621 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000622
623 // Collect declared local variables.
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000624 ZoneList<VarAndOrder> vars(variables_.occupancy(), zone());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000625 for (VariableMap::Entry* p = variables_.Start();
626 p != NULL;
627 p = variables_.Next(p)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000628 Variable* var = reinterpret_cast<Variable*>(p->value);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000629 if (var->is_used()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000630 vars.Add(VarAndOrder(var, p->order), zone());
631 }
632 }
633 vars.Sort(VarAndOrder::Compare);
634 int var_count = vars.length();
635 for (int i = 0; i < var_count; i++) {
636 Variable* var = vars[i].var();
637 if (var->IsStackLocal()) {
638 stack_locals->Add(var, zone());
639 } else if (var->IsContextSlot()) {
640 context_locals->Add(var, zone());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641 }
642 }
643}
644
645
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000646bool Scope::AllocateVariables(CompilationInfo* info,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000647 AstNodeFactory<AstNullVisitor>* factory) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648 // 1) Propagate scope information.
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000649 bool outer_scope_calls_non_strict_eval = false;
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000650 if (outer_scope_ != NULL) {
651 outer_scope_calls_non_strict_eval =
652 outer_scope_->outer_scope_calls_non_strict_eval() |
653 outer_scope_->calls_non_strict_eval();
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000654 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000655 PropagateScopeInfo(outer_scope_calls_non_strict_eval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000656
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000657 // 2) Allocate module instances.
658 if (FLAG_harmony_modules && (is_global_scope() || is_module_scope())) {
659 ASSERT(num_modules_ == 0);
660 AllocateModulesRecursively(this);
661 }
662
663 // 3) Resolve variables.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000664 if (!ResolveVariablesRecursively(info, factory)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000666 // 4) Allocate variables.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000667 AllocateVariablesRecursively();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000668
669 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000670}
671
672
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000673bool Scope::HasTrivialContext() const {
674 // A function scope has a trivial context if it always is the global
675 // context. We iteratively scan out the context chain to see if
676 // there is anything that makes this scope non-trivial; otherwise we
677 // return true.
678 for (const Scope* scope = this; scope != NULL; scope = scope->outer_scope_) {
679 if (scope->is_eval_scope()) return false;
680 if (scope->scope_inside_with_) return false;
681 if (scope->num_heap_slots_ > 0) return false;
682 }
683 return true;
684}
685
686
687bool Scope::HasTrivialOuterContext() const {
688 Scope* outer = outer_scope_;
689 if (outer == NULL) return true;
690 // Note that the outer context may be trivial in general, but the current
691 // scope may be inside a 'with' statement in which case the outer context
692 // for this scope is not trivial.
693 return !scope_inside_with_ && outer->HasTrivialContext();
694}
695
696
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +0000697bool Scope::HasLazyCompilableOuterContext() const {
698 Scope* outer = outer_scope_;
699 if (outer == NULL) return true;
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000700 // We have to prevent lazy compilation if this scope is inside a with scope
701 // and all declaration scopes between them have empty contexts. Such
702 // declaration scopes may become invisible during scope info deserialization.
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +0000703 outer = outer->DeclarationScope();
704 bool found_non_trivial_declarations = false;
705 for (const Scope* scope = outer; scope != NULL; scope = scope->outer_scope_) {
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +0000706 if (scope->is_with_scope() && !found_non_trivial_declarations) return false;
707 if (scope->is_declaration_scope() && scope->num_heap_slots() > 0) {
708 found_non_trivial_declarations = true;
709 }
710 }
711 return true;
712}
713
714
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000715bool Scope::AllowsLazyCompilation() const {
mstarzinger@chromium.orgc6d9cee2012-07-03 10:03:19 +0000716 return !force_eager_compilation_ && HasLazyCompilableOuterContext();
ulan@chromium.orgd6899c32012-05-18 14:12:25 +0000717}
718
719
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000720bool Scope::AllowsLazyCompilationWithoutContext() const {
721 return !force_eager_compilation_ && HasTrivialOuterContext();
722}
723
724
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000725int Scope::ContextChainLength(Scope* scope) {
726 int n = 0;
727 for (Scope* s = this; s != scope; s = s->outer_scope_) {
728 ASSERT(s != NULL); // scope must be in the scope chain
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000729 if (s->is_with_scope() || s->num_heap_slots() > 0) n++;
danno@chromium.orgf005df62013-04-30 16:36:45 +0000730 // Catch and module scopes always have heap slots.
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000731 ASSERT(!s->is_catch_scope() || s->num_heap_slots() > 0);
danno@chromium.orgf005df62013-04-30 16:36:45 +0000732 ASSERT(!s->is_module_scope() || s->num_heap_slots() > 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000733 }
734 return n;
735}
736
737
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000738Scope* Scope::GlobalScope() {
739 Scope* scope = this;
740 while (!scope->is_global_scope()) {
741 scope = scope->outer_scope();
742 }
743 return scope;
744}
745
746
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000747Scope* Scope::DeclarationScope() {
748 Scope* scope = this;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000749 while (!scope->is_declaration_scope()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000750 scope = scope->outer_scope();
751 }
752 return scope;
753}
754
755
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000756Handle<ScopeInfo> Scope::GetScopeInfo() {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000757 if (scope_info_.is_null()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000758 scope_info_ = ScopeInfo::Create(this, zone());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000759 }
760 return scope_info_;
761}
762
763
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000764void Scope::GetNestedScopeChain(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000765 List<Handle<ScopeInfo> >* chain,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000766 int position) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000767 if (!is_eval_scope()) chain->Add(Handle<ScopeInfo>(GetScopeInfo()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000768
769 for (int i = 0; i < inner_scopes_.length(); i++) {
770 Scope* scope = inner_scopes_[i];
771 int beg_pos = scope->start_position();
772 int end_pos = scope->end_position();
773 ASSERT(beg_pos >= 0 && end_pos >= 0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000774 if (beg_pos <= position && position < end_pos) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000775 scope->GetNestedScopeChain(chain, position);
776 return;
777 }
778 }
779}
780
781
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000782#ifdef DEBUG
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000783static const char* Header(ScopeType scope_type) {
784 switch (scope_type) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000785 case EVAL_SCOPE: return "eval";
786 case FUNCTION_SCOPE: return "function";
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000787 case MODULE_SCOPE: return "module";
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000788 case GLOBAL_SCOPE: return "global";
789 case CATCH_SCOPE: return "catch";
790 case BLOCK_SCOPE: return "block";
791 case WITH_SCOPE: return "with";
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000792 }
793 UNREACHABLE();
794 return NULL;
795}
796
797
798static void Indent(int n, const char* str) {
799 PrintF("%*s%s", n, "", str);
800}
801
802
803static void PrintName(Handle<String> name) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000804 SmartArrayPointer<char> s = name->ToCString(DISALLOW_NULLS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000805 PrintF("%s", *s);
806}
807
808
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000809static void PrintLocation(Variable* var) {
810 switch (var->location()) {
811 case Variable::UNALLOCATED:
812 break;
813 case Variable::PARAMETER:
814 PrintF("parameter[%d]", var->index());
815 break;
816 case Variable::LOCAL:
817 PrintF("local[%d]", var->index());
818 break;
819 case Variable::CONTEXT:
820 PrintF("context[%d]", var->index());
821 break;
822 case Variable::LOOKUP:
823 PrintF("lookup");
824 break;
825 }
826}
827
828
829static void PrintVar(int indent, Variable* var) {
830 if (var->is_used() || !var->IsUnallocated()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000831 Indent(indent, Variable::Mode2String(var->mode()));
832 PrintF(" ");
833 PrintName(var->name());
834 PrintF("; // ");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000835 PrintLocation(var);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000836 if (var->has_forced_context_allocation()) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000837 if (!var->IsUnallocated()) PrintF(", ");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000838 PrintF("forced context allocation");
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000839 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 PrintF("\n");
841 }
842}
843
844
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000845static void PrintMap(int indent, VariableMap* map) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000846 for (VariableMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000847 Variable* var = reinterpret_cast<Variable*>(p->value);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000848 PrintVar(indent, var);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000849 }
850}
851
852
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000853void Scope::Print(int n) {
854 int n0 = (n > 0 ? n : 0);
855 int n1 = n0 + 2; // indentation
856
857 // Print header.
ulan@chromium.orgdfe53072013-06-06 14:14:51 +0000858 Indent(n0, Header(scope_type_));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000859 if (scope_name_->length() > 0) {
860 PrintF(" ");
861 PrintName(scope_name_);
862 }
863
864 // Print parameters, if any.
865 if (is_function_scope()) {
866 PrintF(" (");
867 for (int i = 0; i < params_.length(); i++) {
868 if (i > 0) PrintF(", ");
869 PrintName(params_[i]->name());
870 }
871 PrintF(")");
872 }
873
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000874 PrintF(" { // (%d, %d)\n", start_position(), end_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000875
876 // Function name, if any (named function literals, only).
877 if (function_ != NULL) {
878 Indent(n1, "// (local) function name: ");
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000879 PrintName(function_->proxy()->name());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 PrintF("\n");
881 }
882
883 // Scope info.
884 if (HasTrivialOuterContext()) {
885 Indent(n1, "// scope has trivial outer context\n");
886 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000887 switch (language_mode()) {
888 case CLASSIC_MODE:
889 break;
890 case STRICT_MODE:
891 Indent(n1, "// strict mode scope\n");
892 break;
893 case EXTENDED_MODE:
894 Indent(n1, "// extended mode scope\n");
895 break;
896 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000897 if (scope_inside_with_) Indent(n1, "// scope inside 'with'\n");
898 if (scope_contains_with_) Indent(n1, "// scope contains 'with'\n");
899 if (scope_calls_eval_) Indent(n1, "// scope calls 'eval'\n");
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000900 if (outer_scope_calls_non_strict_eval_) {
901 Indent(n1, "// outer scope calls 'eval' in non-strict context\n");
902 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000903 if (inner_scope_calls_eval_) Indent(n1, "// inner scope calls 'eval'\n");
904 if (num_stack_slots_ > 0) { Indent(n1, "// ");
905 PrintF("%d stack slots\n", num_stack_slots_); }
906 if (num_heap_slots_ > 0) { Indent(n1, "// ");
907 PrintF("%d heap slots\n", num_heap_slots_); }
908
909 // Print locals.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000910 Indent(n1, "// function var\n");
911 if (function_ != NULL) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000912 PrintVar(n1, function_->proxy()->var());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000913 }
914
915 Indent(n1, "// temporary vars\n");
916 for (int i = 0; i < temps_.length(); i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000917 PrintVar(n1, temps_[i]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000918 }
919
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000920 Indent(n1, "// internal vars\n");
921 for (int i = 0; i < internals_.length(); i++) {
922 PrintVar(n1, internals_[i]);
923 }
924
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 Indent(n1, "// local vars\n");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000926 PrintMap(n1, &variables_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000928 Indent(n1, "// dynamic vars\n");
929 if (dynamics_ != NULL) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000930 PrintMap(n1, dynamics_->GetMap(DYNAMIC));
931 PrintMap(n1, dynamics_->GetMap(DYNAMIC_LOCAL));
932 PrintMap(n1, dynamics_->GetMap(DYNAMIC_GLOBAL));
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000933 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934
935 // Print inner scopes (disable by providing negative n).
936 if (n >= 0) {
937 for (int i = 0; i < inner_scopes_.length(); i++) {
938 PrintF("\n");
939 inner_scopes_[i]->Print(n1);
940 }
941 }
942
943 Indent(n0, "}\n");
944}
945#endif // DEBUG
946
947
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000948Variable* Scope::NonLocal(Handle<String> name, VariableMode mode) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000949 if (dynamics_ == NULL) dynamics_ = new(zone()) DynamicScopePart(zone());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000950 VariableMap* map = dynamics_->GetMap(mode);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000951 Variable* var = map->Lookup(name);
952 if (var == NULL) {
953 // Declare a new non-local.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000954 InitializationFlag init_flag = (mode == VAR)
955 ? kCreatedInitialized : kNeedsInitialization;
956 var = map->Declare(NULL,
957 name,
958 mode,
959 true,
960 Variable::NORMAL,
961 init_flag);
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000962 // Allocate it by giving it a dynamic lookup.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000963 var->AllocateTo(Variable::LOOKUP, -1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000964 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000965 return var;
966}
967
968
ager@chromium.org381abbb2009-02-25 13:23:22 +0000969Variable* Scope::LookupRecursive(Handle<String> name,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000970 BindingKind* binding_kind,
971 AstNodeFactory<AstNullVisitor>* factory) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000972 ASSERT(binding_kind != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000973 // Try to find the variable in this scope.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000974 Variable* var = LocalLookup(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000975
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000976 // We found a variable and we are done. (Even if there is an 'eval' in
977 // this scope which introduces the same variable again, the resulting
978 // variable remains the same.)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000979 if (var != NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000980 *binding_kind = BOUND;
981 return var;
982 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000983
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000984 // We did not find a variable locally. Check against the function variable,
985 // if any. We can do this for all scopes, since the function variable is
986 // only present - if at all - for function scopes.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000987 *binding_kind = UNBOUND;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000988 var = LookupFunctionVar(name, factory);
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000989 if (var != NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000990 *binding_kind = BOUND;
991 } else if (outer_scope_ != NULL) {
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +0000992 var = outer_scope_->LookupRecursive(name, binding_kind, factory);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000993 if (*binding_kind == BOUND && (is_function_scope() || is_with_scope())) {
994 var->ForceContextAllocation();
995 }
ricow@chromium.org27bf2882011-11-17 08:34:43 +0000996 } else {
997 ASSERT(is_global_scope());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000998 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001000 if (is_with_scope()) {
1001 // The current scope is a with scope, so the variable binding can not be
1002 // statically resolved. However, note that it was necessary to do a lookup
1003 // in the outer scope anyway, because if a binding exists in an outer scope,
1004 // the associated variable has to be marked as potentially being accessed
1005 // from inside of an inner with scope (the property may not be in the 'with'
1006 // object).
1007 *binding_kind = DYNAMIC_LOOKUP;
1008 return NULL;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001009 } else if (calls_non_strict_eval()) {
1010 // A variable binding may have been found in an outer scope, but the current
1011 // scope makes a non-strict 'eval' call, so the found variable may not be
1012 // the correct one (the 'eval' may introduce a binding with the same name).
1013 // In that case, change the lookup result to reflect this situation.
1014 if (*binding_kind == BOUND) {
1015 *binding_kind = BOUND_EVAL_SHADOWED;
1016 } else if (*binding_kind == UNBOUND) {
1017 *binding_kind = UNBOUND_EVAL_SHADOWED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020 return var;
1021}
1022
1023
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001024bool Scope::ResolveVariable(CompilationInfo* info,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001025 VariableProxy* proxy,
1026 AstNodeFactory<AstNullVisitor>* factory) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001027 ASSERT(info->global_scope()->is_global_scope());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001028
1029 // If the proxy is already resolved there's nothing to do
1030 // (functions and consts may be resolved by the parser).
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001031 if (proxy->var() != NULL) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001032
1033 // Otherwise, try to resolve the variable.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001034 BindingKind binding_kind;
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001035 Variable* var = LookupRecursive(proxy->name(), &binding_kind, factory);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001036 switch (binding_kind) {
1037 case BOUND:
1038 // We found a variable binding.
1039 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001040
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001041 case BOUND_EVAL_SHADOWED:
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001042 // We either found a variable binding that might be shadowed by eval or
1043 // gave up on it (e.g. by encountering a local with the same in the outer
1044 // scope which was not promoted to a context, this can happen if we use
1045 // debugger to evaluate arbitrary expressions at a break point).
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001046 if (var->IsGlobalObjectProperty()) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001047 var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001048 } else if (var->is_dynamic()) {
1049 var = NonLocal(proxy->name(), DYNAMIC);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001050 } else {
1051 Variable* invalidated = var;
1052 var = NonLocal(proxy->name(), DYNAMIC_LOCAL);
1053 var->set_local_if_not_shadowed(invalidated);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001055 break;
1056
1057 case UNBOUND:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001058 // No binding has been found. Declare a variable on the global object.
1059 var = info->global_scope()->DeclareDynamicGlobal(proxy->name());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001060 break;
1061
1062 case UNBOUND_EVAL_SHADOWED:
1063 // No binding has been found. But some scope makes a
1064 // non-strict 'eval' call.
1065 var = NonLocal(proxy->name(), DYNAMIC_GLOBAL);
1066 break;
1067
1068 case DYNAMIC_LOOKUP:
1069 // The variable could not be resolved statically.
1070 var = NonLocal(proxy->name(), DYNAMIC);
1071 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072 }
1073
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001074 ASSERT(var != NULL);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001075
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001076 if (FLAG_harmony_scoping && is_extended_mode() &&
1077 var->is_const_mode() && proxy->IsLValue()) {
1078 // Assignment to const. Throw a syntax error.
1079 MessageLocation location(
1080 info->script(), proxy->position(), proxy->position());
1081 Isolate* isolate = Isolate::Current();
1082 Factory* factory = isolate->factory();
1083 Handle<JSArray> array = factory->NewJSArray(0);
1084 Handle<Object> result =
1085 factory->NewSyntaxError("harmony_const_assign", array);
1086 isolate->Throw(*result, &location);
1087 return false;
1088 }
1089
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001090 if (FLAG_harmony_modules) {
1091 bool ok;
1092#ifdef DEBUG
1093 if (FLAG_print_interface_details)
1094 PrintF("# Resolve %s:\n", var->name()->ToAsciiArray());
1095#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001096 proxy->interface()->Unify(var->interface(), zone(), &ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001097 if (!ok) {
1098#ifdef DEBUG
1099 if (FLAG_print_interfaces) {
1100 PrintF("SCOPES TYPE ERROR\n");
1101 PrintF("proxy: ");
1102 proxy->interface()->Print();
1103 PrintF("var: ");
1104 var->interface()->Print();
1105 }
1106#endif
1107
1108 // Inconsistent use of module. Throw a syntax error.
1109 // TODO(rossberg): generate more helpful error message.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001110 MessageLocation location(
1111 info->script(), proxy->position(), proxy->position());
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001112 Isolate* isolate = Isolate::Current();
1113 Factory* factory = isolate->factory();
1114 Handle<JSArray> array = factory->NewJSArray(1);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001115 USE(JSObject::SetElement(array, 0, var->name(), NONE, kStrictMode));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001116 Handle<Object> result =
1117 factory->NewSyntaxError("module_type_error", array);
1118 isolate->Throw(*result, &location);
1119 return false;
1120 }
1121 }
1122
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001123 proxy->BindTo(var);
1124
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001125 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001126}
1127
1128
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001129bool Scope::ResolveVariablesRecursively(
1130 CompilationInfo* info,
svenpanne@chromium.orgb1df11d2012-02-08 10:26:21 +00001131 AstNodeFactory<AstNullVisitor>* factory) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001132 ASSERT(info->global_scope()->is_global_scope());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001133
1134 // Resolve unresolved variables for this scope.
1135 for (int i = 0; i < unresolved_.length(); i++) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001136 if (!ResolveVariable(info, unresolved_[i], factory)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 }
1138
1139 // Resolve unresolved variables for inner scopes.
1140 for (int i = 0; i < inner_scopes_.length(); i++) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001141 if (!inner_scopes_[i]->ResolveVariablesRecursively(info, factory))
1142 return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001143 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001144
1145 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146}
1147
1148
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001149bool Scope::PropagateScopeInfo(bool outer_scope_calls_non_strict_eval ) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001150 if (outer_scope_calls_non_strict_eval) {
1151 outer_scope_calls_non_strict_eval_ = true;
1152 }
1153
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001154 bool calls_non_strict_eval =
ricow@chromium.org27bf2882011-11-17 08:34:43 +00001155 this->calls_non_strict_eval() || outer_scope_calls_non_strict_eval_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001156 for (int i = 0; i < inner_scopes_.length(); i++) {
1157 Scope* inner_scope = inner_scopes_[i];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001158 if (inner_scope->PropagateScopeInfo(calls_non_strict_eval)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001159 inner_scope_calls_eval_ = true;
1160 }
1161 if (inner_scope->force_eager_compilation_) {
1162 force_eager_compilation_ = true;
1163 }
1164 }
1165
1166 return scope_calls_eval_ || inner_scope_calls_eval_;
1167}
1168
1169
1170bool Scope::MustAllocate(Variable* var) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001171 // Give var a read/write use if there is a chance it might be accessed
1172 // via an eval() call. This is only possible if the variable has a
1173 // visible name.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174 if ((var->is_this() || var->name()->length() > 0) &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001175 (var->has_forced_context_allocation() ||
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001176 scope_calls_eval_ ||
1177 inner_scope_calls_eval_ ||
1178 scope_contains_with_ ||
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001179 is_catch_scope() ||
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001180 is_block_scope() ||
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001181 is_module_scope() ||
1182 is_global_scope())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001183 var->set_is_used(true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001185 // Global variables do not need to be allocated.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001186 return !var->IsGlobalObjectProperty() && var->is_used();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001187}
1188
1189
1190bool Scope::MustAllocateInContext(Variable* var) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001191 // If var is accessed from an inner scope, or if there is a possibility
1192 // that it might be accessed from the current or an inner scope (through
1193 // an eval() call or a runtime with lookup), it must be allocated in the
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001194 // context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001195 //
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001196 // Exceptions: If the scope as a whole has forced context allocation, all
1197 // variables will have context allocation, even temporaries. Otherwise
1198 // temporary variables are always stack-allocated. Catch-bound variables are
1199 // always context-allocated.
1200 if (has_forced_context_allocation()) return true;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001201 if (var->mode() == TEMPORARY) return false;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001202 if (var->mode() == INTERNAL) return true;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001203 if (is_catch_scope() || is_block_scope() || is_module_scope()) return true;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001204 if (is_global_scope() && IsLexicalVariableMode(var->mode())) return true;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001205 return var->has_forced_context_allocation() ||
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001206 scope_calls_eval_ ||
1207 inner_scope_calls_eval_ ||
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001208 scope_contains_with_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001209}
1210
1211
1212bool Scope::HasArgumentsParameter() {
1213 for (int i = 0; i < params_.length(); i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001214 if (params_[i]->name().is_identical_to(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001215 isolate_->factory()->arguments_string())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001216 return true;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001217 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218 }
1219 return false;
1220}
1221
1222
1223void Scope::AllocateStackSlot(Variable* var) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001224 var->AllocateTo(Variable::LOCAL, num_stack_slots_++);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001225}
1226
1227
1228void Scope::AllocateHeapSlot(Variable* var) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001229 var->AllocateTo(Variable::CONTEXT, num_heap_slots_++);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230}
1231
1232
1233void Scope::AllocateParameterLocals() {
1234 ASSERT(is_function_scope());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001235 Variable* arguments = LocalLookup(isolate_->factory()->arguments_string());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236 ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001237
whesse@chromium.org7b260152011-06-20 15:33:18 +00001238 bool uses_nonstrict_arguments = false;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001239
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240 if (MustAllocate(arguments) && !HasArgumentsParameter()) {
1241 // 'arguments' is used. Unless there is also a parameter called
whesse@chromium.org7b260152011-06-20 15:33:18 +00001242 // 'arguments', we must be conservative and allocate all parameters to
1243 // the context assuming they will be captured by the arguments object.
1244 // If we have a parameter named 'arguments', a (new) value is always
1245 // assigned to it via the function invocation. Then 'arguments' denotes
1246 // that specific parameter value and cannot be used to access the
1247 // parameters, which is why we don't need to allocate an arguments
1248 // object in that case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249
1250 // We are using 'arguments'. Tell the code generator that is needs to
1251 // allocate the arguments object by setting 'arguments_'.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001252 arguments_ = arguments;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001254 // In strict mode 'arguments' does not alias formal parameters.
1255 // Therefore in strict mode we allocate parameters as if 'arguments'
1256 // were not used.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001257 uses_nonstrict_arguments = is_classic_mode();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001258 }
1259
whesse@chromium.org7b260152011-06-20 15:33:18 +00001260 // The same parameter may occur multiple times in the parameters_ list.
1261 // If it does, and if it is not copied into the context object, it must
1262 // receive the highest parameter index for that parameter; thus iteration
1263 // order is relevant!
1264 for (int i = params_.length() - 1; i >= 0; --i) {
1265 Variable* var = params_[i];
1266 ASSERT(var->scope() == this);
1267 if (uses_nonstrict_arguments) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001268 // Force context allocation of the parameter.
1269 var->ForceContextAllocation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270 }
1271
whesse@chromium.org7b260152011-06-20 15:33:18 +00001272 if (MustAllocate(var)) {
1273 if (MustAllocateInContext(var)) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001274 ASSERT(var->IsUnallocated() || var->IsContextSlot());
1275 if (var->IsUnallocated()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001276 AllocateHeapSlot(var);
1277 }
1278 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001279 ASSERT(var->IsUnallocated() || var->IsParameter());
1280 if (var->IsUnallocated()) {
1281 var->AllocateTo(Variable::PARAMETER, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 }
1283 }
1284 }
1285 }
1286}
1287
1288
1289void Scope::AllocateNonParameterLocal(Variable* var) {
1290 ASSERT(var->scope() == this);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001291 ASSERT(!var->IsVariable(isolate_->factory()->result_string()) ||
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001292 !var->IsStackLocal());
1293 if (var->IsUnallocated() && MustAllocate(var)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 if (MustAllocateInContext(var)) {
1295 AllocateHeapSlot(var);
1296 } else {
1297 AllocateStackSlot(var);
1298 }
1299 }
1300}
1301
1302
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303void Scope::AllocateNonParameterLocals() {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001304 // All variables that have no rewrite yet are non-parameter locals.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 for (int i = 0; i < temps_.length(); i++) {
1306 AllocateNonParameterLocal(temps_[i]);
1307 }
1308
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001309 for (int i = 0; i < internals_.length(); i++) {
1310 AllocateNonParameterLocal(internals_[i]);
1311 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001312
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001313 ZoneList<VarAndOrder> vars(variables_.occupancy(), zone());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001314 for (VariableMap::Entry* p = variables_.Start();
1315 p != NULL;
1316 p = variables_.Next(p)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 Variable* var = reinterpret_cast<Variable*>(p->value);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001318 vars.Add(VarAndOrder(var, p->order), zone());
1319 }
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001320 vars.Sort(VarAndOrder::Compare);
1321 int var_count = vars.length();
1322 for (int i = 0; i < var_count; i++) {
1323 AllocateNonParameterLocal(vars[i].var());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324 }
1325
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001326 // For now, function_ must be allocated at the very end. If it gets
1327 // allocated in the context, it must be the last slot in the context,
1328 // because of the current ScopeInfo implementation (see
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 // ScopeInfo::ScopeInfo(FunctionScope* scope) constructor).
1330 if (function_ != NULL) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001331 AllocateNonParameterLocal(function_->proxy()->var());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332 }
1333}
1334
1335
1336void Scope::AllocateVariablesRecursively() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001337 // Allocate variables for inner scopes.
1338 for (int i = 0; i < inner_scopes_.length(); i++) {
1339 inner_scopes_[i]->AllocateVariablesRecursively();
1340 }
1341
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001342 // If scope is already resolved, we still need to allocate
1343 // variables in inner scopes which might not had been resolved yet.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001344 if (already_resolved()) return;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001345 // The number of slots required for variables.
1346 num_stack_slots_ = 0;
1347 num_heap_slots_ = Context::MIN_CONTEXT_SLOTS;
1348
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001349 // Allocate variables for this scope.
1350 // Parameters must be allocated first, if any.
1351 if (is_function_scope()) AllocateParameterLocals();
1352 AllocateNonParameterLocals();
1353
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001354 // Force allocation of a context for this scope if necessary. For a 'with'
1355 // scope and for a function scope that makes an 'eval' call we need a context,
1356 // even if no local variables were statically allocated in the scope.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001357 // Likewise for modules.
1358 bool must_have_context = is_with_scope() || is_module_scope() ||
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001359 (is_function_scope() && calls_eval());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360
1361 // If we didn't allocate any locals in the local context, then we only
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001362 // need the minimal number of slots if we must have a context.
1363 if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && !must_have_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364 num_heap_slots_ = 0;
1365 }
1366
1367 // Allocation done.
1368 ASSERT(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
1369}
1370
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001371
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001372void Scope::AllocateModulesRecursively(Scope* host_scope) {
1373 if (already_resolved()) return;
1374 if (is_module_scope()) {
1375 ASSERT(interface_->IsFrozen());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001376 Handle<String> name = isolate_->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001377 STATIC_ASCII_VECTOR(".module"));
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001378 ASSERT(module_var_ == NULL);
1379 module_var_ = host_scope->NewInternal(name);
1380 ++host_scope->num_modules_;
1381 }
1382
1383 for (int i = 0; i < inner_scopes_.length(); i++) {
1384 Scope* inner_scope = inner_scopes_.at(i);
1385 inner_scope->AllocateModulesRecursively(host_scope);
1386 }
1387}
1388
1389
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001390int Scope::StackLocalCount() const {
1391 return num_stack_slots() -
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001392 (function_ != NULL && function_->proxy()->var()->IsStackLocal() ? 1 : 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001393}
1394
1395
1396int Scope::ContextLocalCount() const {
1397 if (num_heap_slots() == 0) return 0;
1398 return num_heap_slots() - Context::MIN_CONTEXT_SLOTS -
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001399 (function_ != NULL && function_->proxy()->var()->IsContextSlot() ? 1 : 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001400}
1401
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402} } // namespace v8::internal