Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / v8 / src / contexts.cc
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #include "src/bootstrapper.h"
8 #include "src/debug.h"
9 #include "src/scopeinfo.h"
10
11 namespace v8 {
12 namespace internal {
13
14 Context* Context::declaration_context() {
15   Context* current = this;
16   while (!current->IsFunctionContext() && !current->IsNativeContext()) {
17     current = current->previous();
18     ASSERT(current->closure() == closure());
19   }
20   return current;
21 }
22
23
24 JSBuiltinsObject* Context::builtins() {
25   GlobalObject* object = global_object();
26   if (object->IsJSGlobalObject()) {
27     return JSGlobalObject::cast(object)->builtins();
28   } else {
29     ASSERT(object->IsJSBuiltinsObject());
30     return JSBuiltinsObject::cast(object);
31   }
32 }
33
34
35 Context* Context::global_context() {
36   Context* current = this;
37   while (!current->IsGlobalContext()) {
38     current = current->previous();
39   }
40   return current;
41 }
42
43
44 Context* Context::native_context() {
45   // Fast case: the global object for this context has been set.  In
46   // that case, the global object has a direct pointer to the global
47   // context.
48   if (global_object()->IsGlobalObject()) {
49     return global_object()->native_context();
50   }
51
52   // During bootstrapping, the global object might not be set and we
53   // have to search the context chain to find the native context.
54   ASSERT(this->GetIsolate()->bootstrapper()->IsActive());
55   Context* current = this;
56   while (!current->IsNativeContext()) {
57     JSFunction* closure = JSFunction::cast(current->closure());
58     current = Context::cast(closure->context());
59   }
60   return current;
61 }
62
63
64 JSObject* Context::global_proxy() {
65   return native_context()->global_proxy_object();
66 }
67
68
69 void Context::set_global_proxy(JSObject* object) {
70   native_context()->set_global_proxy_object(object);
71 }
72
73
74 Handle<Object> Context::Lookup(Handle<String> name,
75                                ContextLookupFlags flags,
76                                int* index,
77                                PropertyAttributes* attributes,
78                                BindingFlags* binding_flags) {
79   Isolate* isolate = GetIsolate();
80   Handle<Context> context(this, isolate);
81
82   bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
83   *index = -1;
84   *attributes = ABSENT;
85   *binding_flags = MISSING_BINDING;
86
87   if (FLAG_trace_contexts) {
88     PrintF("Context::Lookup(");
89     name->ShortPrint();
90     PrintF(")\n");
91   }
92
93   do {
94     if (FLAG_trace_contexts) {
95       PrintF(" - looking in context %p", reinterpret_cast<void*>(*context));
96       if (context->IsNativeContext()) PrintF(" (native context)");
97       PrintF("\n");
98     }
99
100     // 1. Check global objects, subjects of with, and extension objects.
101     if (context->IsNativeContext() ||
102         context->IsWithContext() ||
103         (context->IsFunctionContext() && context->has_extension())) {
104       Handle<JSReceiver> object(
105           JSReceiver::cast(context->extension()), isolate);
106       // Context extension objects needs to behave as if they have no
107       // prototype.  So even if we want to follow prototype chains, we need
108       // to only do a local lookup for context extension objects.
109       if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
110           object->IsJSContextExtensionObject()) {
111         *attributes = JSReceiver::GetOwnPropertyAttributes(object, name);
112       } else {
113         *attributes = JSReceiver::GetPropertyAttributes(object, name);
114       }
115       if (isolate->has_pending_exception()) return Handle<Object>();
116
117       if (*attributes != ABSENT) {
118         if (FLAG_trace_contexts) {
119           PrintF("=> found property in context object %p\n",
120                  reinterpret_cast<void*>(*object));
121         }
122         return object;
123       }
124     }
125
126     // 2. Check the context proper if it has slots.
127     if (context->IsFunctionContext() || context->IsBlockContext()) {
128       // Use serialized scope information of functions and blocks to search
129       // for the context index.
130       Handle<ScopeInfo> scope_info;
131       if (context->IsFunctionContext()) {
132         scope_info = Handle<ScopeInfo>(
133             context->closure()->shared()->scope_info(), isolate);
134       } else {
135         scope_info = Handle<ScopeInfo>(
136             ScopeInfo::cast(context->extension()), isolate);
137       }
138       VariableMode mode;
139       InitializationFlag init_flag;
140       int slot_index =
141           ScopeInfo::ContextSlotIndex(scope_info, name, &mode, &init_flag);
142       ASSERT(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
143       if (slot_index >= 0) {
144         if (FLAG_trace_contexts) {
145           PrintF("=> found local in context slot %d (mode = %d)\n",
146                  slot_index, mode);
147         }
148         *index = slot_index;
149         // Note: Fixed context slots are statically allocated by the compiler.
150         // Statically allocated variables always have a statically known mode,
151         // which is the mode with which they were declared when added to the
152         // scope. Thus, the DYNAMIC mode (which corresponds to dynamically
153         // declared variables that were introduced through declaration nodes)
154         // must not appear here.
155         switch (mode) {
156           case INTERNAL:  // Fall through.
157           case VAR:
158             *attributes = NONE;
159             *binding_flags = MUTABLE_IS_INITIALIZED;
160             break;
161           case LET:
162             *attributes = NONE;
163             *binding_flags = (init_flag == kNeedsInitialization)
164                 ? MUTABLE_CHECK_INITIALIZED : MUTABLE_IS_INITIALIZED;
165             break;
166           case CONST_LEGACY:
167             *attributes = READ_ONLY;
168             *binding_flags = (init_flag == kNeedsInitialization)
169                 ? IMMUTABLE_CHECK_INITIALIZED : IMMUTABLE_IS_INITIALIZED;
170             break;
171           case CONST:
172             *attributes = READ_ONLY;
173             *binding_flags = (init_flag == kNeedsInitialization)
174                 ? IMMUTABLE_CHECK_INITIALIZED_HARMONY :
175                 IMMUTABLE_IS_INITIALIZED_HARMONY;
176             break;
177           case MODULE:
178             *attributes = READ_ONLY;
179             *binding_flags = IMMUTABLE_IS_INITIALIZED_HARMONY;
180             break;
181           case DYNAMIC:
182           case DYNAMIC_GLOBAL:
183           case DYNAMIC_LOCAL:
184           case TEMPORARY:
185             UNREACHABLE();
186             break;
187         }
188         return context;
189       }
190
191       // Check the slot corresponding to the intermediate context holding
192       // only the function name variable.
193       if (follow_context_chain && context->IsFunctionContext()) {
194         VariableMode mode;
195         int function_index = scope_info->FunctionContextSlotIndex(*name, &mode);
196         if (function_index >= 0) {
197           if (FLAG_trace_contexts) {
198             PrintF("=> found intermediate function in context slot %d\n",
199                    function_index);
200           }
201           *index = function_index;
202           *attributes = READ_ONLY;
203           ASSERT(mode == CONST_LEGACY || mode == CONST);
204           *binding_flags = (mode == CONST_LEGACY)
205               ? IMMUTABLE_IS_INITIALIZED : IMMUTABLE_IS_INITIALIZED_HARMONY;
206           return context;
207         }
208       }
209
210     } else if (context->IsCatchContext()) {
211       // Catch contexts have the variable name in the extension slot.
212       if (String::Equals(name, handle(String::cast(context->extension())))) {
213         if (FLAG_trace_contexts) {
214           PrintF("=> found in catch context\n");
215         }
216         *index = Context::THROWN_OBJECT_INDEX;
217         *attributes = NONE;
218         *binding_flags = MUTABLE_IS_INITIALIZED;
219         return context;
220       }
221     }
222
223     // 3. Prepare to continue with the previous (next outermost) context.
224     if (context->IsNativeContext()) {
225       follow_context_chain = false;
226     } else {
227       context = Handle<Context>(context->previous(), isolate);
228     }
229   } while (follow_context_chain);
230
231   if (FLAG_trace_contexts) {
232     PrintF("=> no property/slot found\n");
233   }
234   return Handle<Object>::null();
235 }
236
237
238 void Context::AddOptimizedFunction(JSFunction* function) {
239   ASSERT(IsNativeContext());
240 #ifdef ENABLE_SLOW_ASSERTS
241   if (FLAG_enable_slow_asserts) {
242     Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
243     while (!element->IsUndefined()) {
244       CHECK(element != function);
245       element = JSFunction::cast(element)->next_function_link();
246     }
247   }
248
249   // Check that the context belongs to the weak native contexts list.
250   bool found = false;
251   Object* context = GetHeap()->native_contexts_list();
252   while (!context->IsUndefined()) {
253     if (context == this) {
254       found = true;
255       break;
256     }
257     context = Context::cast(context)->get(Context::NEXT_CONTEXT_LINK);
258   }
259   CHECK(found);
260 #endif
261
262   // If the function link field is already used then the function was
263   // enqueued as a code flushing candidate and we remove it now.
264   if (!function->next_function_link()->IsUndefined()) {
265     CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher();
266     flusher->EvictCandidate(function);
267   }
268
269   ASSERT(function->next_function_link()->IsUndefined());
270
271   function->set_next_function_link(get(OPTIMIZED_FUNCTIONS_LIST));
272   set(OPTIMIZED_FUNCTIONS_LIST, function);
273 }
274
275
276 void Context::RemoveOptimizedFunction(JSFunction* function) {
277   ASSERT(IsNativeContext());
278   Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
279   JSFunction* prev = NULL;
280   while (!element->IsUndefined()) {
281     JSFunction* element_function = JSFunction::cast(element);
282     ASSERT(element_function->next_function_link()->IsUndefined() ||
283            element_function->next_function_link()->IsJSFunction());
284     if (element_function == function) {
285       if (prev == NULL) {
286         set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link());
287       } else {
288         prev->set_next_function_link(element_function->next_function_link());
289       }
290       element_function->set_next_function_link(GetHeap()->undefined_value());
291       return;
292     }
293     prev = element_function;
294     element = element_function->next_function_link();
295   }
296   UNREACHABLE();
297 }
298
299
300 void Context::SetOptimizedFunctionsListHead(Object* head) {
301   ASSERT(IsNativeContext());
302   set(OPTIMIZED_FUNCTIONS_LIST, head);
303 }
304
305
306 Object* Context::OptimizedFunctionsListHead() {
307   ASSERT(IsNativeContext());
308   return get(OPTIMIZED_FUNCTIONS_LIST);
309 }
310
311
312 void Context::AddOptimizedCode(Code* code) {
313   ASSERT(IsNativeContext());
314   ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
315   ASSERT(code->next_code_link()->IsUndefined());
316   code->set_next_code_link(get(OPTIMIZED_CODE_LIST));
317   set(OPTIMIZED_CODE_LIST, code);
318 }
319
320
321 void Context::SetOptimizedCodeListHead(Object* head) {
322   ASSERT(IsNativeContext());
323   set(OPTIMIZED_CODE_LIST, head);
324 }
325
326
327 Object* Context::OptimizedCodeListHead() {
328   ASSERT(IsNativeContext());
329   return get(OPTIMIZED_CODE_LIST);
330 }
331
332
333 void Context::SetDeoptimizedCodeListHead(Object* head) {
334   ASSERT(IsNativeContext());
335   set(DEOPTIMIZED_CODE_LIST, head);
336 }
337
338
339 Object* Context::DeoptimizedCodeListHead() {
340   ASSERT(IsNativeContext());
341   return get(DEOPTIMIZED_CODE_LIST);
342 }
343
344
345 Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() {
346   Isolate* isolate = GetIsolate();
347   Handle<Object> result(error_message_for_code_gen_from_strings(), isolate);
348   if (!result->IsUndefined()) return result;
349   return isolate->factory()->NewStringFromStaticAscii(
350       "Code generation from strings disallowed for this context");
351 }
352
353
354 #ifdef DEBUG
355 bool Context::IsBootstrappingOrValidParentContext(
356     Object* object, Context* child) {
357   // During bootstrapping we allow all objects to pass as
358   // contexts. This is necessary to fix circular dependencies.
359   if (child->GetIsolate()->bootstrapper()->IsActive()) return true;
360   if (!object->IsContext()) return false;
361   Context* context = Context::cast(object);
362   return context->IsNativeContext() || context->IsGlobalContext() ||
363          context->IsModuleContext() || !child->IsModuleContext();
364 }
365
366
367 bool Context::IsBootstrappingOrGlobalObject(Isolate* isolate, Object* object) {
368   // During bootstrapping we allow all objects to pass as global
369   // objects. This is necessary to fix circular dependencies.
370   return isolate->heap()->gc_state() != Heap::NOT_IN_GC ||
371       isolate->bootstrapper()->IsActive() ||
372       object->IsGlobalObject();
373 }
374 #endif
375
376 } }  // namespace v8::internal