blob: 72a5ae4d6077fab4a067c57553f7348eeeb8bfa4 [file] [log] [blame]
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001// Copyright 2011 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
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000030#include "bootstrapper.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000031#include "debug.h"
32#include "scopeinfo.h"
33
kasperl@chromium.org71affb52009-05-26 05:44:31 +000034namespace v8 {
35namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000037Context* Context::declaration_context() {
38 Context* current = this;
39 while (!current->IsFunctionContext() && !current->IsGlobalContext()) {
40 current = current->previous();
41 ASSERT(current->closure() == closure());
42 }
43 return current;
44}
45
46
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047JSBuiltinsObject* Context::builtins() {
48 GlobalObject* object = global();
49 if (object->IsJSGlobalObject()) {
50 return JSGlobalObject::cast(object)->builtins();
51 } else {
52 ASSERT(object->IsJSBuiltinsObject());
53 return JSBuiltinsObject::cast(object);
54 }
55}
56
57
58Context* Context::global_context() {
59 // Fast case: the global object for this context has been set. In
60 // that case, the global object has a direct pointer to the global
61 // context.
62 if (global()->IsGlobalObject()) {
63 return global()->global_context();
64 }
kasperl@chromium.org7b9eafd2009-12-21 15:20:30 +000065
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066 // During bootstrapping, the global object might not be set and we
67 // have to search the context chain to find the global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000068 ASSERT(Isolate::Current()->bootstrapper()->IsActive());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000069 Context* current = this;
70 while (!current->IsGlobalContext()) {
kasperl@chromium.org7b9eafd2009-12-21 15:20:30 +000071 JSFunction* closure = JSFunction::cast(current->closure());
72 current = Context::cast(closure->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073 }
74 return current;
75}
76
77
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000078JSObject* Context::global_proxy() {
79 return global_context()->global_proxy_object();
80}
81
82void Context::set_global_proxy(JSObject* object) {
83 global_context()->set_global_proxy_object(object);
84}
85
86
whesse@chromium.org7b260152011-06-20 15:33:18 +000087Handle<Object> Context::Lookup(Handle<String> name,
88 ContextLookupFlags flags,
89 int* index_,
90 PropertyAttributes* attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000091 Isolate* isolate = GetIsolate();
92 Handle<Context> context(this, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000093
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000094 bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
95 *index_ = -1;
96 *attributes = ABSENT;
97
98 if (FLAG_trace_contexts) {
99 PrintF("Context::Lookup(");
100 name->ShortPrint();
101 PrintF(")\n");
102 }
103
104 do {
105 if (FLAG_trace_contexts) {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000106 PrintF(" - looking in context %p", reinterpret_cast<void*>(*context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107 if (context->IsGlobalContext()) PrintF(" (global context)");
108 PrintF("\n");
109 }
110
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000111 // Check extension/with/global object.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000112 if (!context->IsBlockContext() && context->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000113 if (context->IsCatchContext()) {
114 // Catch contexts have the variable name in the extension slot.
115 if (name->Equals(String::cast(context->extension()))) {
116 if (FLAG_trace_contexts) {
117 PrintF("=> found in catch context\n");
118 }
119 *index_ = Context::THROWN_OBJECT_INDEX;
120 *attributes = NONE;
121 return context;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000123 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000124 ASSERT(context->IsGlobalContext() ||
125 context->IsFunctionContext() ||
126 context->IsWithContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000127 // Global, function, and with contexts may have an object in the
128 // extension slot.
129 Handle<JSObject> extension(JSObject::cast(context->extension()),
130 isolate);
131 // Context extension objects needs to behave as if they have no
132 // prototype. So even if we want to follow prototype chains, we
133 // need to only do a local lookup for context extension objects.
134 if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
135 extension->IsJSContextExtensionObject()) {
136 *attributes = extension->GetLocalPropertyAttribute(*name);
137 } else {
138 *attributes = extension->GetPropertyAttribute(*name);
139 }
140 if (*attributes != ABSENT) {
141 // property found
142 if (FLAG_trace_contexts) {
143 PrintF("=> found property in context object %p\n",
144 reinterpret_cast<void*>(*extension));
145 }
146 return extension;
147 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000148 }
149 }
150
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000151 // Check serialized scope information of functions and blocks. Only
152 // functions can have parameters, and a function name.
153 if (context->IsFunctionContext() || context->IsBlockContext()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +0000154 // We may have context-local slots. Check locals in the context.
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000155 Handle<SerializedScopeInfo> scope_info;
156 if (context->IsFunctionContext()) {
157 scope_info = Handle<SerializedScopeInfo>(
158 context->closure()->shared()->scope_info(), isolate);
159 } else {
160 ASSERT(context->IsBlockContext());
161 scope_info = Handle<SerializedScopeInfo>(
162 SerializedScopeInfo::cast(context->extension()), isolate);
163 }
164
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000165 Variable::Mode mode;
ager@chromium.orgb5737492010-07-15 09:29:43 +0000166 int index = scope_info->ContextSlotIndex(*name, &mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000167 ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
168 if (index >= 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000169 if (FLAG_trace_contexts) {
170 PrintF("=> found local in context slot %d (mode = %d)\n",
171 index, mode);
172 }
173 *index_ = index;
174 // Note: Fixed context slots are statically allocated by the compiler.
175 // Statically allocated variables always have a statically known mode,
176 // which is the mode with which they were declared when added to the
177 // scope. Thus, the DYNAMIC mode (which corresponds to dynamically
178 // declared variables that were introduced through declaration nodes)
179 // must not appear here.
180 switch (mode) {
whesse@chromium.org7b260152011-06-20 15:33:18 +0000181 case Variable::INTERNAL: // Fall through.
182 case Variable::VAR:
183 *attributes = NONE;
184 break;
185 case Variable::CONST:
186 *attributes = READ_ONLY;
187 break;
188 case Variable::DYNAMIC:
189 case Variable::DYNAMIC_GLOBAL:
190 case Variable::DYNAMIC_LOCAL:
191 case Variable::TEMPORARY:
192 UNREACHABLE();
193 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000194 }
195 return context;
196 }
197
whesse@chromium.org7b260152011-06-20 15:33:18 +0000198 // Check the slot corresponding to the intermediate context holding
199 // only the function name variable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000200 if (follow_context_chain) {
ager@chromium.orgb5737492010-07-15 09:29:43 +0000201 int index = scope_info->FunctionContextSlotIndex(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000202 if (index >= 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203 if (FLAG_trace_contexts) {
204 PrintF("=> found intermediate function in context slot %d\n",
205 index);
206 }
207 *index_ = index;
208 *attributes = READ_ONLY;
209 return context;
210 }
211 }
212 }
213
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000214 // Proceed with the previous context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000215 if (context->IsGlobalContext()) {
216 follow_context_chain = false;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000217 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000218 context = Handle<Context>(context->previous(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000219 }
220 } while (follow_context_chain);
221
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 if (FLAG_trace_contexts) {
223 PrintF("=> no property/slot found\n");
224 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000225 return Handle<Object>::null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000226}
227
228
ager@chromium.org381abbb2009-02-25 13:23:22 +0000229bool Context::GlobalIfNotShadowedByEval(Handle<String> name) {
230 Context* context = this;
231
232 // Check that there is no local with the given name in contexts
233 // before the global context and check that there are no context
234 // extension objects (conservative check for with statements).
235 while (!context->IsGlobalContext()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000236 // Check if the context is a catch or with context, or has introduced
237 // bindings by calling non-strict eval.
ager@chromium.org381abbb2009-02-25 13:23:22 +0000238 if (context->has_extension()) return false;
239
240 // Not a with context so it must be a function context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000241 ASSERT(context->IsFunctionContext());
ager@chromium.org381abbb2009-02-25 13:23:22 +0000242
243 // Check non-parameter locals.
ager@chromium.orgb5737492010-07-15 09:29:43 +0000244 Handle<SerializedScopeInfo> scope_info(
245 context->closure()->shared()->scope_info());
ager@chromium.org381abbb2009-02-25 13:23:22 +0000246 Variable::Mode mode;
ager@chromium.orgb5737492010-07-15 09:29:43 +0000247 int index = scope_info->ContextSlotIndex(*name, &mode);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000248 ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
249 if (index >= 0) return false;
250
251 // Check parameter locals.
ager@chromium.orgb5737492010-07-15 09:29:43 +0000252 int param_index = scope_info->ParameterIndex(*name);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000253 if (param_index >= 0) return false;
254
255 // Check context only holding the function name variable.
ager@chromium.orgb5737492010-07-15 09:29:43 +0000256 index = scope_info->FunctionContextSlotIndex(*name);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000257 if (index >= 0) return false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000258 context = context->previous();
ager@chromium.org381abbb2009-02-25 13:23:22 +0000259 }
260
261 // No local or potential with statement found so the variable is
262 // global unless it is shadowed by an eval-introduced variable.
263 return true;
264}
265
266
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000267void Context::ComputeEvalScopeInfo(bool* outer_scope_calls_eval,
268 bool* outer_scope_calls_non_strict_eval) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000269 // Skip up the context chain checking all the function contexts to see
270 // whether they call eval.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000271 Context* context = this;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000272 while (!context->IsGlobalContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000273 if (context->IsFunctionContext()) {
274 Handle<SerializedScopeInfo> scope_info(
275 context->closure()->shared()->scope_info());
276 if (scope_info->CallsEval()) {
277 *outer_scope_calls_eval = true;
278 if (!scope_info->IsStrictMode()) {
279 // No need to go further since the answers will not change from
280 // here.
281 *outer_scope_calls_non_strict_eval = true;
282 return;
283 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000284 }
285 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000286 context = context->previous();
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000287 }
288}
289
290
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000291void Context::AddOptimizedFunction(JSFunction* function) {
292 ASSERT(IsGlobalContext());
293#ifdef DEBUG
294 Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
295 while (!element->IsUndefined()) {
296 CHECK(element != function);
297 element = JSFunction::cast(element)->next_function_link();
298 }
299
300 CHECK(function->next_function_link()->IsUndefined());
301
302 // Check that the context belongs to the weak global contexts list.
303 bool found = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 Object* context = GetHeap()->global_contexts_list();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000305 while (!context->IsUndefined()) {
306 if (context == this) {
307 found = true;
308 break;
309 }
310 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
311 }
312 CHECK(found);
313#endif
314 function->set_next_function_link(get(OPTIMIZED_FUNCTIONS_LIST));
315 set(OPTIMIZED_FUNCTIONS_LIST, function);
316}
317
318
319void Context::RemoveOptimizedFunction(JSFunction* function) {
320 ASSERT(IsGlobalContext());
321 Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
322 JSFunction* prev = NULL;
323 while (!element->IsUndefined()) {
324 JSFunction* element_function = JSFunction::cast(element);
325 ASSERT(element_function->next_function_link()->IsUndefined() ||
326 element_function->next_function_link()->IsJSFunction());
327 if (element_function == function) {
328 if (prev == NULL) {
329 set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link());
330 } else {
331 prev->set_next_function_link(element_function->next_function_link());
332 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000333 element_function->set_next_function_link(GetHeap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000334 return;
335 }
336 prev = element_function;
337 element = element_function->next_function_link();
338 }
339 UNREACHABLE();
340}
341
342
343Object* Context::OptimizedFunctionsListHead() {
344 ASSERT(IsGlobalContext());
345 return get(OPTIMIZED_FUNCTIONS_LIST);
346}
347
348
349void Context::ClearOptimizedFunctions() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000350 set(OPTIMIZED_FUNCTIONS_LIST, GetHeap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000351}
352
353
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000354#ifdef DEBUG
355bool Context::IsBootstrappingOrContext(Object* object) {
356 // During bootstrapping we allow all objects to pass as
357 // contexts. This is necessary to fix circular dependencies.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000358 return Isolate::Current()->bootstrapper()->IsActive() || object->IsContext();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000359}
360
361
362bool Context::IsBootstrappingOrGlobalObject(Object* object) {
363 // During bootstrapping we allow all objects to pass as global
364 // objects. This is necessary to fix circular dependencies.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000365 Isolate* isolate = Isolate::Current();
366 return isolate->heap()->gc_state() != Heap::NOT_IN_GC ||
367 isolate->bootstrapper()->IsActive() ||
368 object->IsGlobalObject();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000369}
370#endif
371
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000372} } // namespace v8::internal