Home | History | Annotate | Download | only in src
      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
    377