blob: 4f93abdff1d0c50a9058c2f35b934719cb4f8ef2 [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "bootstrapper.h"
31#include "debug.h"
32#include "scopeinfo.h"
33
34namespace v8 {
35namespace internal {
36
Ben Murdoch3fb3ca82011-12-02 17:19:32 +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
Steve Blocka7e24c12009-10-30 11:49:00 +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 }
Leon Clarkee46be812010-01-19 14:06:41 +000065
Steve Blocka7e24c12009-10-30 11:49:00 +000066 // During bootstrapping, the global object might not be set and we
67 // have to search the context chain to find the global context.
Steve Block44f0eee2011-05-26 01:26:41 +010068 ASSERT(Isolate::Current()->bootstrapper()->IsActive());
Steve Blocka7e24c12009-10-30 11:49:00 +000069 Context* current = this;
70 while (!current->IsGlobalContext()) {
Leon Clarkee46be812010-01-19 14:06:41 +000071 JSFunction* closure = JSFunction::cast(current->closure());
72 current = Context::cast(closure->context());
Steve Blocka7e24c12009-10-30 11:49:00 +000073 }
74 return current;
75}
76
77
78JSObject* 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
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000087Handle<Object> Context::Lookup(Handle<String> name,
88 ContextLookupFlags flags,
89 int* index_,
Ben Murdoch69a99ed2011-11-30 16:03:39 +000090 PropertyAttributes* attributes,
91 BindingFlags* binding_flags) {
Steve Block44f0eee2011-05-26 01:26:41 +010092 Isolate* isolate = GetIsolate();
93 Handle<Context> context(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000094
95 bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
96 *index_ = -1;
97 *attributes = ABSENT;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000098 *binding_flags = MISSING_BINDING;
Steve Blocka7e24c12009-10-30 11:49:00 +000099
100 if (FLAG_trace_contexts) {
101 PrintF("Context::Lookup(");
102 name->ShortPrint();
103 PrintF(")\n");
104 }
105
106 do {
107 if (FLAG_trace_contexts) {
Ben Murdochf87a2032010-10-22 12:50:53 +0100108 PrintF(" - looking in context %p", reinterpret_cast<void*>(*context));
Steve Blocka7e24c12009-10-30 11:49:00 +0000109 if (context->IsGlobalContext()) PrintF(" (global context)");
110 PrintF("\n");
111 }
112
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000113 // Check extension/with/global object.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000114 if (!context->IsBlockContext() && context->has_extension()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000115 if (context->IsCatchContext()) {
116 // Catch contexts have the variable name in the extension slot.
117 if (name->Equals(String::cast(context->extension()))) {
118 if (FLAG_trace_contexts) {
119 PrintF("=> found in catch context\n");
120 }
121 *index_ = Context::THROWN_OBJECT_INDEX;
122 *attributes = NONE;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000123 *binding_flags = MUTABLE_IS_INITIALIZED;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000124 return context;
Steve Blocka7e24c12009-10-30 11:49:00 +0000125 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000126 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000127 ASSERT(context->IsGlobalContext() ||
128 context->IsFunctionContext() ||
129 context->IsWithContext());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000130 // Global, function, and with contexts may have an object in the
131 // extension slot.
132 Handle<JSObject> extension(JSObject::cast(context->extension()),
133 isolate);
134 // Context extension objects needs to behave as if they have no
135 // prototype. So even if we want to follow prototype chains, we
136 // need to only do a local lookup for context extension objects.
137 if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
138 extension->IsJSContextExtensionObject()) {
139 *attributes = extension->GetLocalPropertyAttribute(*name);
140 } else {
141 *attributes = extension->GetPropertyAttribute(*name);
142 }
143 if (*attributes != ABSENT) {
144 // property found
145 if (FLAG_trace_contexts) {
146 PrintF("=> found property in context object %p\n",
147 reinterpret_cast<void*>(*extension));
148 }
149 return extension;
150 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000151 }
152 }
153
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000154 // Check serialized scope information of functions and blocks. Only
155 // functions can have parameters, and a function name.
156 if (context->IsFunctionContext() || context->IsBlockContext()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000157 // We may have context-local slots. Check locals in the context.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000158 Handle<SerializedScopeInfo> scope_info;
159 if (context->IsFunctionContext()) {
160 scope_info = Handle<SerializedScopeInfo>(
161 context->closure()->shared()->scope_info(), isolate);
162 } else {
163 ASSERT(context->IsBlockContext());
164 scope_info = Handle<SerializedScopeInfo>(
165 SerializedScopeInfo::cast(context->extension()), isolate);
166 }
167
Steve Blocka7e24c12009-10-30 11:49:00 +0000168 Variable::Mode mode;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100169 int index = scope_info->ContextSlotIndex(*name, &mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000170 ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
171 if (index >= 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000172 if (FLAG_trace_contexts) {
173 PrintF("=> found local in context slot %d (mode = %d)\n",
174 index, mode);
175 }
176 *index_ = index;
177 // Note: Fixed context slots are statically allocated by the compiler.
178 // Statically allocated variables always have a statically known mode,
179 // which is the mode with which they were declared when added to the
180 // scope. Thus, the DYNAMIC mode (which corresponds to dynamically
181 // declared variables that were introduced through declaration nodes)
182 // must not appear here.
183 switch (mode) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000184 case Variable::INTERNAL: // Fall through.
185 case Variable::VAR:
186 *attributes = NONE;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000187 *binding_flags = MUTABLE_IS_INITIALIZED;
188 break;
189 case Variable::LET:
190 *attributes = NONE;
191 *binding_flags = MUTABLE_CHECK_INITIALIZED;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000192 break;
193 case Variable::CONST:
194 *attributes = READ_ONLY;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000195 *binding_flags = IMMUTABLE_CHECK_INITIALIZED;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000196 break;
197 case Variable::DYNAMIC:
198 case Variable::DYNAMIC_GLOBAL:
199 case Variable::DYNAMIC_LOCAL:
200 case Variable::TEMPORARY:
201 UNREACHABLE();
202 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000203 }
204 return context;
205 }
206
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000207 // Check the slot corresponding to the intermediate context holding
208 // only the function name variable.
Steve Blocka7e24c12009-10-30 11:49:00 +0000209 if (follow_context_chain) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100210 int index = scope_info->FunctionContextSlotIndex(*name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000211 if (index >= 0) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000212 if (FLAG_trace_contexts) {
213 PrintF("=> found intermediate function in context slot %d\n",
214 index);
215 }
216 *index_ = index;
217 *attributes = READ_ONLY;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000218 *binding_flags = IMMUTABLE_IS_INITIALIZED;
Steve Blocka7e24c12009-10-30 11:49:00 +0000219 return context;
220 }
221 }
222 }
223
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000224 // Proceed with the previous context.
Steve Blocka7e24c12009-10-30 11:49:00 +0000225 if (context->IsGlobalContext()) {
226 follow_context_chain = false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000227 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100228 context = Handle<Context>(context->previous(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000229 }
230 } while (follow_context_chain);
231
Steve Blocka7e24c12009-10-30 11:49:00 +0000232 if (FLAG_trace_contexts) {
233 PrintF("=> no property/slot found\n");
234 }
235 return Handle<Object>::null();
236}
237
238
239bool Context::GlobalIfNotShadowedByEval(Handle<String> name) {
240 Context* context = this;
241
242 // Check that there is no local with the given name in contexts
243 // before the global context and check that there are no context
244 // extension objects (conservative check for with statements).
245 while (!context->IsGlobalContext()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000246 // Check if the context is a catch or with context, or has introduced
247 // bindings by calling non-strict eval.
Steve Blocka7e24c12009-10-30 11:49:00 +0000248 if (context->has_extension()) return false;
249
250 // Not a with context so it must be a function context.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000251 ASSERT(context->IsFunctionContext());
Steve Blocka7e24c12009-10-30 11:49:00 +0000252
253 // Check non-parameter locals.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100254 Handle<SerializedScopeInfo> scope_info(
255 context->closure()->shared()->scope_info());
Steve Blocka7e24c12009-10-30 11:49:00 +0000256 Variable::Mode mode;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100257 int index = scope_info->ContextSlotIndex(*name, &mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000258 ASSERT(index < 0 || index >= MIN_CONTEXT_SLOTS);
259 if (index >= 0) return false;
260
261 // Check parameter locals.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100262 int param_index = scope_info->ParameterIndex(*name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000263 if (param_index >= 0) return false;
264
265 // Check context only holding the function name variable.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100266 index = scope_info->FunctionContextSlotIndex(*name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000267 if (index >= 0) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000268 context = context->previous();
Steve Blocka7e24c12009-10-30 11:49:00 +0000269 }
270
271 // No local or potential with statement found so the variable is
272 // global unless it is shadowed by an eval-introduced variable.
273 return true;
274}
275
276
Ben Murdoch257744e2011-11-30 15:57:28 +0000277void Context::ComputeEvalScopeInfo(bool* outer_scope_calls_eval,
278 bool* outer_scope_calls_non_strict_eval) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000279 // Skip up the context chain checking all the function contexts to see
280 // whether they call eval.
Ben Murdoch257744e2011-11-30 15:57:28 +0000281 Context* context = this;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000282 while (!context->IsGlobalContext()) {
283 if (context->IsFunctionContext()) {
284 Handle<SerializedScopeInfo> scope_info(
285 context->closure()->shared()->scope_info());
286 if (scope_info->CallsEval()) {
287 *outer_scope_calls_eval = true;
288 if (!scope_info->IsStrictMode()) {
289 // No need to go further since the answers will not change from
290 // here.
291 *outer_scope_calls_non_strict_eval = true;
292 return;
293 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000294 }
295 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000296 context = context->previous();
Ben Murdoch257744e2011-11-30 15:57:28 +0000297 }
298}
299
300
Ben Murdochb0fe1622011-05-05 13:52:32 +0100301void Context::AddOptimizedFunction(JSFunction* function) {
302 ASSERT(IsGlobalContext());
303#ifdef DEBUG
304 Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
305 while (!element->IsUndefined()) {
306 CHECK(element != function);
307 element = JSFunction::cast(element)->next_function_link();
308 }
309
310 CHECK(function->next_function_link()->IsUndefined());
311
312 // Check that the context belongs to the weak global contexts list.
313 bool found = false;
Steve Block44f0eee2011-05-26 01:26:41 +0100314 Object* context = GetHeap()->global_contexts_list();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100315 while (!context->IsUndefined()) {
316 if (context == this) {
317 found = true;
318 break;
319 }
320 context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
321 }
322 CHECK(found);
323#endif
324 function->set_next_function_link(get(OPTIMIZED_FUNCTIONS_LIST));
325 set(OPTIMIZED_FUNCTIONS_LIST, function);
326}
327
328
329void Context::RemoveOptimizedFunction(JSFunction* function) {
330 ASSERT(IsGlobalContext());
331 Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
332 JSFunction* prev = NULL;
333 while (!element->IsUndefined()) {
334 JSFunction* element_function = JSFunction::cast(element);
335 ASSERT(element_function->next_function_link()->IsUndefined() ||
336 element_function->next_function_link()->IsJSFunction());
337 if (element_function == function) {
338 if (prev == NULL) {
339 set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link());
340 } else {
341 prev->set_next_function_link(element_function->next_function_link());
342 }
Steve Block44f0eee2011-05-26 01:26:41 +0100343 element_function->set_next_function_link(GetHeap()->undefined_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100344 return;
345 }
346 prev = element_function;
347 element = element_function->next_function_link();
348 }
349 UNREACHABLE();
350}
351
352
353Object* Context::OptimizedFunctionsListHead() {
354 ASSERT(IsGlobalContext());
355 return get(OPTIMIZED_FUNCTIONS_LIST);
356}
357
358
359void Context::ClearOptimizedFunctions() {
Steve Block44f0eee2011-05-26 01:26:41 +0100360 set(OPTIMIZED_FUNCTIONS_LIST, GetHeap()->undefined_value());
Ben Murdochb0fe1622011-05-05 13:52:32 +0100361}
362
363
Steve Blocka7e24c12009-10-30 11:49:00 +0000364#ifdef DEBUG
365bool Context::IsBootstrappingOrContext(Object* object) {
366 // During bootstrapping we allow all objects to pass as
367 // contexts. This is necessary to fix circular dependencies.
Steve Block44f0eee2011-05-26 01:26:41 +0100368 return Isolate::Current()->bootstrapper()->IsActive() || object->IsContext();
Steve Blocka7e24c12009-10-30 11:49:00 +0000369}
370
371
372bool Context::IsBootstrappingOrGlobalObject(Object* object) {
373 // During bootstrapping we allow all objects to pass as global
374 // objects. This is necessary to fix circular dependencies.
Steve Block44f0eee2011-05-26 01:26:41 +0100375 Isolate* isolate = Isolate::Current();
376 return isolate->heap()->gc_state() != Heap::NOT_IN_GC ||
377 isolate->bootstrapper()->IsActive() ||
378 object->IsGlobalObject();
Steve Blocka7e24c12009-10-30 11:49:00 +0000379}
380#endif
381
382} } // namespace v8::internal