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/contexts.h"
      6 
      7 #include "src/bootstrapper.h"
      8 #include "src/debug/debug.h"
      9 #include "src/isolate-inl.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 
     15 Handle<ScriptContextTable> ScriptContextTable::Extend(
     16     Handle<ScriptContextTable> table, Handle<Context> script_context) {
     17   Handle<ScriptContextTable> result;
     18   int used = table->used();
     19   int length = table->length();
     20   CHECK(used >= 0 && length > 0 && used < length);
     21   if (used + kFirstContextSlot == length) {
     22     CHECK(length < Smi::kMaxValue / 2);
     23     Isolate* isolate = table->GetIsolate();
     24     Handle<FixedArray> copy =
     25         isolate->factory()->CopyFixedArrayAndGrow(table, length);
     26     copy->set_map(isolate->heap()->script_context_table_map());
     27     result = Handle<ScriptContextTable>::cast(copy);
     28   } else {
     29     result = table;
     30   }
     31   result->set_used(used + 1);
     32 
     33   DCHECK(script_context->IsScriptContext());
     34   result->set(used + kFirstContextSlot, *script_context);
     35   return result;
     36 }
     37 
     38 
     39 bool ScriptContextTable::Lookup(Handle<ScriptContextTable> table,
     40                                 Handle<String> name, LookupResult* result) {
     41   for (int i = 0; i < table->used(); i++) {
     42     Handle<Context> context = GetContext(table, i);
     43     DCHECK(context->IsScriptContext());
     44     Handle<ScopeInfo> scope_info(context->scope_info());
     45     int slot_index = ScopeInfo::ContextSlotIndex(
     46         scope_info, name, &result->mode, &result->init_flag,
     47         &result->maybe_assigned_flag);
     48 
     49     if (slot_index >= 0) {
     50       result->context_index = i;
     51       result->slot_index = slot_index;
     52       return true;
     53     }
     54   }
     55   return false;
     56 }
     57 
     58 
     59 bool Context::is_declaration_context() {
     60   if (IsFunctionContext() || IsNativeContext() || IsScriptContext() ||
     61       IsModuleContext()) {
     62     return true;
     63   }
     64   if (IsEvalContext()) return closure()->shared()->language_mode() == STRICT;
     65   if (!IsBlockContext()) return false;
     66   Object* ext = extension();
     67   // If we have the special extension, we immediately know it must be a
     68   // declaration scope. That's just a small performance shortcut.
     69   return ext->IsContextExtension() ||
     70          ScopeInfo::cast(ext)->is_declaration_scope();
     71 }
     72 
     73 
     74 Context* Context::declaration_context() {
     75   Context* current = this;
     76   while (!current->is_declaration_context()) {
     77     current = current->previous();
     78   }
     79   return current;
     80 }
     81 
     82 Context* Context::closure_context() {
     83   Context* current = this;
     84   while (!current->IsFunctionContext() && !current->IsScriptContext() &&
     85          !current->IsModuleContext() && !current->IsNativeContext() &&
     86          !current->IsEvalContext()) {
     87     current = current->previous();
     88     DCHECK(current->closure() == closure());
     89   }
     90   return current;
     91 }
     92 
     93 JSObject* Context::extension_object() {
     94   DCHECK(IsNativeContext() || IsFunctionContext() || IsBlockContext() ||
     95          IsEvalContext());
     96   HeapObject* object = extension();
     97   if (object->IsTheHole(GetIsolate())) return nullptr;
     98   if (IsBlockContext()) {
     99     if (!object->IsContextExtension()) return nullptr;
    100     object = JSObject::cast(ContextExtension::cast(object)->extension());
    101   }
    102   DCHECK(object->IsJSContextExtensionObject() ||
    103          (IsNativeContext() && object->IsJSGlobalObject()));
    104   return JSObject::cast(object);
    105 }
    106 
    107 JSReceiver* Context::extension_receiver() {
    108   DCHECK(IsNativeContext() || IsWithContext() || IsEvalContext() ||
    109          IsFunctionContext() || IsBlockContext());
    110   return IsWithContext() ? JSReceiver::cast(
    111                                ContextExtension::cast(extension())->extension())
    112                          : extension_object();
    113 }
    114 
    115 ScopeInfo* Context::scope_info() {
    116   DCHECK(!IsNativeContext());
    117   if (IsFunctionContext() || IsModuleContext() || IsEvalContext()) {
    118     return closure()->shared()->scope_info();
    119   }
    120   HeapObject* object = extension();
    121   if (object->IsContextExtension()) {
    122     DCHECK(IsBlockContext() || IsCatchContext() || IsWithContext() ||
    123            IsDebugEvaluateContext());
    124     object = ContextExtension::cast(object)->scope_info();
    125   }
    126   return ScopeInfo::cast(object);
    127 }
    128 
    129 Module* Context::module() {
    130   Context* current = this;
    131   while (!current->IsModuleContext()) {
    132     current = current->previous();
    133   }
    134   return Module::cast(current->extension());
    135 }
    136 
    137 String* Context::catch_name() {
    138   DCHECK(IsCatchContext());
    139   return String::cast(ContextExtension::cast(extension())->extension());
    140 }
    141 
    142 
    143 JSGlobalObject* Context::global_object() {
    144   return JSGlobalObject::cast(native_context()->extension());
    145 }
    146 
    147 
    148 Context* Context::script_context() {
    149   Context* current = this;
    150   while (!current->IsScriptContext()) {
    151     current = current->previous();
    152   }
    153   return current;
    154 }
    155 
    156 
    157 JSObject* Context::global_proxy() {
    158   return native_context()->global_proxy_object();
    159 }
    160 
    161 
    162 void Context::set_global_proxy(JSObject* object) {
    163   native_context()->set_global_proxy_object(object);
    164 }
    165 
    166 
    167 /**
    168  * Lookups a property in an object environment, taking the unscopables into
    169  * account. This is used For HasBinding spec algorithms for ObjectEnvironment.
    170  */
    171 static Maybe<bool> UnscopableLookup(LookupIterator* it) {
    172   Isolate* isolate = it->isolate();
    173 
    174   Maybe<bool> found = JSReceiver::HasProperty(it);
    175   if (!found.IsJust() || !found.FromJust()) return found;
    176 
    177   Handle<Object> unscopables;
    178   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
    179       isolate, unscopables,
    180       JSReceiver::GetProperty(Handle<JSReceiver>::cast(it->GetReceiver()),
    181                               isolate->factory()->unscopables_symbol()),
    182       Nothing<bool>());
    183   if (!unscopables->IsJSReceiver()) return Just(true);
    184   Handle<Object> blacklist;
    185   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
    186       isolate, blacklist,
    187       JSReceiver::GetProperty(Handle<JSReceiver>::cast(unscopables),
    188                               it->name()),
    189       Nothing<bool>());
    190   return Just(!blacklist->BooleanValue());
    191 }
    192 
    193 static PropertyAttributes GetAttributesForMode(VariableMode mode) {
    194   DCHECK(IsDeclaredVariableMode(mode));
    195   return mode == CONST ? READ_ONLY : NONE;
    196 }
    197 
    198 Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags,
    199                                int* index, PropertyAttributes* attributes,
    200                                InitializationFlag* init_flag,
    201                                VariableMode* variable_mode) {
    202   DCHECK(!IsModuleContext());
    203   Isolate* isolate = GetIsolate();
    204   Handle<Context> context(this, isolate);
    205 
    206   bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
    207   bool failed_whitelist = false;
    208   *index = kNotFound;
    209   *attributes = ABSENT;
    210   *init_flag = kCreatedInitialized;
    211   *variable_mode = VAR;
    212 
    213   if (FLAG_trace_contexts) {
    214     PrintF("Context::Lookup(");
    215     name->ShortPrint();
    216     PrintF(")\n");
    217   }
    218 
    219   do {
    220     if (FLAG_trace_contexts) {
    221       PrintF(" - looking in context %p", reinterpret_cast<void*>(*context));
    222       if (context->IsScriptContext()) PrintF(" (script context)");
    223       if (context->IsNativeContext()) PrintF(" (native context)");
    224       PrintF("\n");
    225     }
    226 
    227     // 1. Check global objects, subjects of with, and extension objects.
    228     DCHECK_IMPLIES(context->IsEvalContext(),
    229                    context->extension()->IsTheHole(isolate));
    230     if ((context->IsNativeContext() ||
    231          (context->IsWithContext() && ((flags & SKIP_WITH_CONTEXT) == 0)) ||
    232          context->IsFunctionContext() || context->IsBlockContext()) &&
    233         context->extension_receiver() != nullptr) {
    234       Handle<JSReceiver> object(context->extension_receiver());
    235 
    236       if (context->IsNativeContext()) {
    237         if (FLAG_trace_contexts) {
    238           PrintF(" - trying other script contexts\n");
    239         }
    240         // Try other script contexts.
    241         Handle<ScriptContextTable> script_contexts(
    242             context->global_object()->native_context()->script_context_table());
    243         ScriptContextTable::LookupResult r;
    244         if (ScriptContextTable::Lookup(script_contexts, name, &r)) {
    245           if (FLAG_trace_contexts) {
    246             Handle<Context> c = ScriptContextTable::GetContext(script_contexts,
    247                                                                r.context_index);
    248             PrintF("=> found property in script context %d: %p\n",
    249                    r.context_index, reinterpret_cast<void*>(*c));
    250           }
    251           *index = r.slot_index;
    252           *variable_mode = r.mode;
    253           *init_flag = r.init_flag;
    254           *attributes = GetAttributesForMode(r.mode);
    255           return ScriptContextTable::GetContext(script_contexts,
    256                                                 r.context_index);
    257         }
    258       }
    259 
    260       // Context extension objects needs to behave as if they have no
    261       // prototype.  So even if we want to follow prototype chains, we need
    262       // to only do a local lookup for context extension objects.
    263       Maybe<PropertyAttributes> maybe = Nothing<PropertyAttributes>();
    264       if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
    265           object->IsJSContextExtensionObject()) {
    266         maybe = JSReceiver::GetOwnPropertyAttributes(object, name);
    267       } else if (context->IsWithContext()) {
    268         // A with context will never bind "this", but debug-eval may look into
    269         // a with context when resolving "this". Other synthetic variables such
    270         // as new.target may be resolved as DYNAMIC_LOCAL due to bug v8:5405 ,
    271         // skipping them here serves as a workaround until a more thorough
    272         // fix can be applied.
    273         // TODO(v8:5405): Replace this check with a DCHECK when resolution of
    274         // of synthetic variables does not go through this code path.
    275         if (ScopeInfo::VariableIsSynthetic(*name)) {
    276           maybe = Just(ABSENT);
    277         } else {
    278           LookupIterator it(object, name, object);
    279           Maybe<bool> found = UnscopableLookup(&it);
    280           if (found.IsNothing()) {
    281             maybe = Nothing<PropertyAttributes>();
    282           } else {
    283             // Luckily, consumers of |maybe| only care whether the property
    284             // was absent or not, so we can return a dummy |NONE| value
    285             // for its attributes when it was present.
    286             maybe = Just(found.FromJust() ? NONE : ABSENT);
    287           }
    288         }
    289       } else {
    290         maybe = JSReceiver::GetPropertyAttributes(object, name);
    291       }
    292 
    293       if (!maybe.IsJust()) return Handle<Object>();
    294       DCHECK(!isolate->has_pending_exception());
    295       *attributes = maybe.FromJust();
    296 
    297       if (maybe.FromJust() != ABSENT) {
    298         if (FLAG_trace_contexts) {
    299           PrintF("=> found property in context object %p\n",
    300                  reinterpret_cast<void*>(*object));
    301         }
    302         return object;
    303       }
    304     }
    305 
    306     // 2. Check the context proper if it has slots.
    307     if (context->IsFunctionContext() || context->IsBlockContext() ||
    308         context->IsScriptContext() || context->IsEvalContext()) {
    309       // Use serialized scope information of functions and blocks to search
    310       // for the context index.
    311       Handle<ScopeInfo> scope_info(context->scope_info());
    312       VariableMode mode;
    313       InitializationFlag flag;
    314       MaybeAssignedFlag maybe_assigned_flag;
    315       int slot_index = ScopeInfo::ContextSlotIndex(scope_info, name, &mode,
    316                                                    &flag, &maybe_assigned_flag);
    317       DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
    318       if (slot_index >= 0) {
    319         if (FLAG_trace_contexts) {
    320           PrintF("=> found local in context slot %d (mode = %d)\n",
    321                  slot_index, mode);
    322         }
    323         *index = slot_index;
    324         *variable_mode = mode;
    325         *init_flag = flag;
    326         *attributes = GetAttributesForMode(mode);
    327         return context;
    328       }
    329 
    330       // Check the slot corresponding to the intermediate context holding
    331       // only the function name variable. It's conceptually (and spec-wise)
    332       // in an outer scope of the function's declaration scope.
    333       if (follow_context_chain && (flags & STOP_AT_DECLARATION_SCOPE) == 0 &&
    334           context->IsFunctionContext()) {
    335         int function_index = scope_info->FunctionContextSlotIndex(*name);
    336         if (function_index >= 0) {
    337           if (FLAG_trace_contexts) {
    338             PrintF("=> found intermediate function in context slot %d\n",
    339                    function_index);
    340           }
    341           *index = function_index;
    342           *attributes = READ_ONLY;
    343           *init_flag = kCreatedInitialized;
    344           *variable_mode = CONST;
    345           return context;
    346         }
    347       }
    348 
    349     } else if (context->IsCatchContext()) {
    350       // Catch contexts have the variable name in the extension slot.
    351       if (String::Equals(name, handle(context->catch_name()))) {
    352         if (FLAG_trace_contexts) {
    353           PrintF("=> found in catch context\n");
    354         }
    355         *index = Context::THROWN_OBJECT_INDEX;
    356         *attributes = NONE;
    357         *init_flag = kCreatedInitialized;
    358         *variable_mode = VAR;
    359         return context;
    360       }
    361     } else if (context->IsDebugEvaluateContext()) {
    362       // Check materialized locals.
    363       Object* ext = context->get(EXTENSION_INDEX);
    364       if (ext->IsContextExtension()) {
    365         Object* obj = ContextExtension::cast(ext)->extension();
    366         if (obj->IsJSReceiver()) {
    367           Handle<JSReceiver> extension(JSReceiver::cast(obj));
    368           LookupIterator it(extension, name, extension);
    369           Maybe<bool> found = JSReceiver::HasProperty(&it);
    370           if (found.FromMaybe(false)) {
    371             *attributes = NONE;
    372             return extension;
    373           }
    374         }
    375       }
    376       // Check the original context, but do not follow its context chain.
    377       Object* obj = context->get(WRAPPED_CONTEXT_INDEX);
    378       if (obj->IsContext()) {
    379         Handle<Object> result =
    380             Context::cast(obj)->Lookup(name, DONT_FOLLOW_CHAINS, index,
    381                                        attributes, init_flag, variable_mode);
    382         if (!result.is_null()) return result;
    383       }
    384       // Check whitelist. Names that do not pass whitelist shall only resolve
    385       // to with, script or native contexts up the context chain.
    386       obj = context->get(WHITE_LIST_INDEX);
    387       if (obj->IsStringSet()) {
    388         failed_whitelist = failed_whitelist || !StringSet::cast(obj)->Has(name);
    389       }
    390     }
    391 
    392     // 3. Prepare to continue with the previous (next outermost) context.
    393     if (context->IsNativeContext() ||
    394         ((flags & STOP_AT_DECLARATION_SCOPE) != 0 &&
    395          context->is_declaration_context())) {
    396       follow_context_chain = false;
    397     } else {
    398       do {
    399         context = Handle<Context>(context->previous(), isolate);
    400         // If we come across a whitelist context, and the name is not
    401         // whitelisted, then only consider with, script or native contexts.
    402       } while (failed_whitelist && !context->IsScriptContext() &&
    403                !context->IsNativeContext() && !context->IsWithContext());
    404     }
    405   } while (follow_context_chain);
    406 
    407   if (FLAG_trace_contexts) {
    408     PrintF("=> no property/slot found\n");
    409   }
    410   return Handle<Object>::null();
    411 }
    412 
    413 static const int kSharedOffset = 0;
    414 static const int kCachedCodeOffset = 1;
    415 static const int kOsrAstIdOffset = 2;
    416 static const int kEntryLength = 3;
    417 static const int kInitialLength = kEntryLength;
    418 
    419 int Context::SearchOptimizedCodeMapEntry(SharedFunctionInfo* shared,
    420                                          BailoutId osr_ast_id) {
    421   DisallowHeapAllocation no_gc;
    422   DCHECK(this->IsNativeContext());
    423   if (!OptimizedCodeMapIsCleared()) {
    424     FixedArray* optimized_code_map = this->osr_code_table();
    425     int length = optimized_code_map->length();
    426     Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt());
    427     for (int i = 0; i < length; i += kEntryLength) {
    428       if (WeakCell::cast(optimized_code_map->get(i + kSharedOffset))->value() ==
    429               shared &&
    430           optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
    431         return i;
    432       }
    433     }
    434   }
    435   return -1;
    436 }
    437 
    438 Code* Context::SearchOptimizedCodeMap(SharedFunctionInfo* shared,
    439                                       BailoutId osr_ast_id) {
    440   DCHECK(this->IsNativeContext());
    441   int entry = SearchOptimizedCodeMapEntry(shared, osr_ast_id);
    442   if (entry != -1) {
    443     FixedArray* code_map = osr_code_table();
    444     DCHECK_LE(entry + kEntryLength, code_map->length());
    445     WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
    446     return cell->cleared() ? nullptr : Code::cast(cell->value());
    447   }
    448   return nullptr;
    449 }
    450 
    451 void Context::AddToOptimizedCodeMap(Handle<Context> native_context,
    452                                     Handle<SharedFunctionInfo> shared,
    453                                     Handle<Code> code,
    454                                     BailoutId osr_ast_id) {
    455   DCHECK(native_context->IsNativeContext());
    456   Isolate* isolate = native_context->GetIsolate();
    457   if (isolate->serializer_enabled()) return;
    458 
    459   STATIC_ASSERT(kEntryLength == 3);
    460   Handle<FixedArray> new_code_map;
    461   int entry;
    462 
    463   if (native_context->OptimizedCodeMapIsCleared()) {
    464     new_code_map = isolate->factory()->NewFixedArray(kInitialLength, TENURED);
    465     entry = 0;
    466   } else {
    467     Handle<FixedArray> old_code_map(native_context->osr_code_table(), isolate);
    468     entry = native_context->SearchOptimizedCodeMapEntry(*shared, osr_ast_id);
    469     if (entry >= 0) {
    470       // Just set the code of the entry.
    471       Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
    472       old_code_map->set(entry + kCachedCodeOffset, *code_cell);
    473       return;
    474     }
    475 
    476     // Can we reuse an entry?
    477     DCHECK(entry < 0);
    478     int length = old_code_map->length();
    479     for (int i = 0; i < length; i += kEntryLength) {
    480       if (WeakCell::cast(old_code_map->get(i + kSharedOffset))->cleared()) {
    481         new_code_map = old_code_map;
    482         entry = i;
    483         break;
    484       }
    485     }
    486 
    487     if (entry < 0) {
    488       // Copy old optimized code map and append one new entry.
    489       new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
    490           old_code_map, kEntryLength, TENURED);
    491       entry = old_code_map->length();
    492     }
    493   }
    494 
    495   Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
    496   Handle<WeakCell> shared_cell = isolate->factory()->NewWeakCell(shared);
    497 
    498   new_code_map->set(entry + kSharedOffset, *shared_cell);
    499   new_code_map->set(entry + kCachedCodeOffset, *code_cell);
    500   new_code_map->set(entry + kOsrAstIdOffset, Smi::FromInt(osr_ast_id.ToInt()));
    501 
    502 #ifdef DEBUG
    503   for (int i = 0; i < new_code_map->length(); i += kEntryLength) {
    504     WeakCell* cell = WeakCell::cast(new_code_map->get(i + kSharedOffset));
    505     DCHECK(cell->cleared() || cell->value()->IsSharedFunctionInfo());
    506     cell = WeakCell::cast(new_code_map->get(i + kCachedCodeOffset));
    507     DCHECK(cell->cleared() ||
    508            (cell->value()->IsCode() &&
    509             Code::cast(cell->value())->kind() == Code::OPTIMIZED_FUNCTION));
    510     DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
    511   }
    512 #endif
    513 
    514   FixedArray* old_code_map = native_context->osr_code_table();
    515   if (old_code_map != *new_code_map) {
    516     native_context->set_osr_code_table(*new_code_map);
    517   }
    518 }
    519 
    520 void Context::EvictFromOptimizedCodeMap(Code* optimized_code,
    521                                         const char* reason) {
    522   DCHECK(IsNativeContext());
    523   DisallowHeapAllocation no_gc;
    524   if (OptimizedCodeMapIsCleared()) return;
    525 
    526   Heap* heap = GetHeap();
    527   FixedArray* code_map = osr_code_table();
    528   int dst = 0;
    529   int length = code_map->length();
    530   for (int src = 0; src < length; src += kEntryLength) {
    531     if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
    532         optimized_code) {
    533       BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
    534       if (FLAG_trace_opt) {
    535         PrintF(
    536             "[evicting entry from native context optimizing code map (%s) for ",
    537             reason);
    538         ShortPrint();
    539         DCHECK(!osr.IsNone());
    540         PrintF(" (osr ast id %d)]\n", osr.ToInt());
    541       }
    542       // Evict the src entry by not copying it to the dst entry.
    543       continue;
    544     }
    545     // Keep the src entry by copying it to the dst entry.
    546     if (dst != src) {
    547       code_map->set(dst + kSharedOffset, code_map->get(src + kSharedOffset));
    548       code_map->set(dst + kCachedCodeOffset,
    549                     code_map->get(src + kCachedCodeOffset));
    550       code_map->set(dst + kOsrAstIdOffset,
    551                     code_map->get(src + kOsrAstIdOffset));
    552     }
    553     dst += kEntryLength;
    554   }
    555   if (dst != length) {
    556     // Always trim even when array is cleared because of heap verifier.
    557     heap->RightTrimFixedArray(code_map, length - dst);
    558     if (code_map->length() == 0) {
    559       ClearOptimizedCodeMap();
    560     }
    561   }
    562 }
    563 
    564 void Context::ClearOptimizedCodeMap() {
    565   DCHECK(IsNativeContext());
    566   FixedArray* empty_fixed_array = GetHeap()->empty_fixed_array();
    567   set_osr_code_table(empty_fixed_array);
    568 }
    569 
    570 void Context::AddOptimizedFunction(JSFunction* function) {
    571   DCHECK(IsNativeContext());
    572   Isolate* isolate = GetIsolate();
    573 #ifdef ENABLE_SLOW_DCHECKS
    574   if (FLAG_enable_slow_asserts) {
    575     Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
    576     while (!element->IsUndefined(isolate)) {
    577       CHECK(element != function);
    578       element = JSFunction::cast(element)->next_function_link();
    579     }
    580   }
    581 
    582   // Check that the context belongs to the weak native contexts list.
    583   bool found = false;
    584   Object* context = isolate->heap()->native_contexts_list();
    585   while (!context->IsUndefined(isolate)) {
    586     if (context == this) {
    587       found = true;
    588       break;
    589     }
    590     context = Context::cast(context)->next_context_link();
    591   }
    592   CHECK(found);
    593 #endif
    594 
    595   // If the function link field is already used then the function was
    596   // enqueued as a code flushing candidate and we remove it now.
    597   if (!function->next_function_link()->IsUndefined(isolate)) {
    598     CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher();
    599     flusher->EvictCandidate(function);
    600   }
    601 
    602   DCHECK(function->next_function_link()->IsUndefined(isolate));
    603 
    604   function->set_next_function_link(get(OPTIMIZED_FUNCTIONS_LIST),
    605                                    UPDATE_WEAK_WRITE_BARRIER);
    606   set(OPTIMIZED_FUNCTIONS_LIST, function, UPDATE_WEAK_WRITE_BARRIER);
    607 }
    608 
    609 
    610 void Context::RemoveOptimizedFunction(JSFunction* function) {
    611   DCHECK(IsNativeContext());
    612   Object* element = get(OPTIMIZED_FUNCTIONS_LIST);
    613   JSFunction* prev = NULL;
    614   Isolate* isolate = function->GetIsolate();
    615   while (!element->IsUndefined(isolate)) {
    616     JSFunction* element_function = JSFunction::cast(element);
    617     DCHECK(element_function->next_function_link()->IsUndefined(isolate) ||
    618            element_function->next_function_link()->IsJSFunction());
    619     if (element_function == function) {
    620       if (prev == NULL) {
    621         set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link(),
    622             UPDATE_WEAK_WRITE_BARRIER);
    623       } else {
    624         prev->set_next_function_link(element_function->next_function_link(),
    625                                      UPDATE_WEAK_WRITE_BARRIER);
    626       }
    627       element_function->set_next_function_link(GetHeap()->undefined_value(),
    628                                                UPDATE_WEAK_WRITE_BARRIER);
    629       return;
    630     }
    631     prev = element_function;
    632     element = element_function->next_function_link();
    633   }
    634   UNREACHABLE();
    635 }
    636 
    637 
    638 void Context::SetOptimizedFunctionsListHead(Object* head) {
    639   DCHECK(IsNativeContext());
    640   set(OPTIMIZED_FUNCTIONS_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
    641 }
    642 
    643 
    644 Object* Context::OptimizedFunctionsListHead() {
    645   DCHECK(IsNativeContext());
    646   return get(OPTIMIZED_FUNCTIONS_LIST);
    647 }
    648 
    649 
    650 void Context::AddOptimizedCode(Code* code) {
    651   DCHECK(IsNativeContext());
    652   DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
    653   DCHECK(code->next_code_link()->IsUndefined(GetIsolate()));
    654   code->set_next_code_link(get(OPTIMIZED_CODE_LIST));
    655   set(OPTIMIZED_CODE_LIST, code, UPDATE_WEAK_WRITE_BARRIER);
    656 }
    657 
    658 
    659 void Context::SetOptimizedCodeListHead(Object* head) {
    660   DCHECK(IsNativeContext());
    661   set(OPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
    662 }
    663 
    664 
    665 Object* Context::OptimizedCodeListHead() {
    666   DCHECK(IsNativeContext());
    667   return get(OPTIMIZED_CODE_LIST);
    668 }
    669 
    670 
    671 void Context::SetDeoptimizedCodeListHead(Object* head) {
    672   DCHECK(IsNativeContext());
    673   set(DEOPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
    674 }
    675 
    676 
    677 Object* Context::DeoptimizedCodeListHead() {
    678   DCHECK(IsNativeContext());
    679   return get(DEOPTIMIZED_CODE_LIST);
    680 }
    681 
    682 
    683 Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() {
    684   Isolate* isolate = GetIsolate();
    685   Handle<Object> result(error_message_for_code_gen_from_strings(), isolate);
    686   if (!result->IsUndefined(isolate)) return result;
    687   return isolate->factory()->NewStringFromStaticChars(
    688       "Code generation from strings disallowed for this context");
    689 }
    690 
    691 
    692 #define COMPARE_NAME(index, type, name) \
    693   if (string->IsOneByteEqualTo(STATIC_CHAR_VECTOR(#name))) return index;
    694 
    695 int Context::ImportedFieldIndexForName(Handle<String> string) {
    696   NATIVE_CONTEXT_IMPORTED_FIELDS(COMPARE_NAME)
    697   return kNotFound;
    698 }
    699 
    700 
    701 int Context::IntrinsicIndexForName(Handle<String> string) {
    702   NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NAME);
    703   return kNotFound;
    704 }
    705 
    706 #undef COMPARE_NAME
    707 
    708 #define COMPARE_NAME(index, type, name) \
    709   if (strncmp(string, #name, length) == 0) return index;
    710 
    711 int Context::IntrinsicIndexForName(const unsigned char* unsigned_string,
    712                                    int length) {
    713   const char* string = reinterpret_cast<const char*>(unsigned_string);
    714   NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NAME);
    715   return kNotFound;
    716 }
    717 
    718 #undef COMPARE_NAME
    719 
    720 #ifdef DEBUG
    721 
    722 bool Context::IsBootstrappingOrNativeContext(Isolate* isolate, Object* object) {
    723   // During bootstrapping we allow all objects to pass as global
    724   // objects. This is necessary to fix circular dependencies.
    725   return isolate->heap()->gc_state() != Heap::NOT_IN_GC ||
    726          isolate->bootstrapper()->IsActive() || object->IsNativeContext();
    727 }
    728 
    729 
    730 bool Context::IsBootstrappingOrValidParentContext(
    731     Object* object, Context* child) {
    732   // During bootstrapping we allow all objects to pass as
    733   // contexts. This is necessary to fix circular dependencies.
    734   if (child->GetIsolate()->bootstrapper()->IsActive()) return true;
    735   if (!object->IsContext()) return false;
    736   Context* context = Context::cast(object);
    737   return context->IsNativeContext() || context->IsScriptContext() ||
    738          context->IsModuleContext() || !child->IsModuleContext();
    739 }
    740 
    741 #endif
    742 
    743 void Context::ResetErrorsThrown() {
    744   DCHECK(IsNativeContext());
    745   set_errors_thrown(Smi::FromInt(0));
    746 }
    747 
    748 void Context::IncrementErrorsThrown() {
    749   DCHECK(IsNativeContext());
    750 
    751   int previous_value = errors_thrown()->value();
    752   set_errors_thrown(Smi::FromInt(previous_value + 1));
    753 }
    754 
    755 
    756 int Context::GetErrorsThrown() { return errors_thrown()->value(); }
    757 
    758 }  // namespace internal
    759 }  // namespace v8
    760