LCOV - code coverage report
Current view: top level - src - contexts.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 238 248 96.0 %
Date: 2017-04-26 Functions: 36 37 97.3 %

          Line data    Source code
       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       11615 : 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       11615 :   CHECK(used >= 0 && length > 0 && used < length);
      21       11615 :   if (used + kFirstContextSlot == length) {
      22        9163 :     CHECK(length < Smi::kMaxValue / 2);
      23             :     Isolate* isolate = table->GetIsolate();
      24             :     Handle<FixedArray> copy =
      25        9163 :         isolate->factory()->CopyFixedArrayAndGrow(table, length);
      26       18326 :     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       11615 :   result->set(used + kFirstContextSlot, *script_context);
      35       11615 :   return result;
      36             : }
      37             : 
      38             : 
      39     9506182 : bool ScriptContextTable::Lookup(Handle<ScriptContextTable> table,
      40             :                                 Handle<String> name, LookupResult* result) {
      41    39567772 :   for (int i = 0; i < table->used(); i++) {
      42    10347324 :     Handle<Context> context = GetContext(table, i);
      43             :     DCHECK(context->IsScriptContext());
      44    10347325 :     Handle<ScopeInfo> scope_info(context->scope_info());
      45             :     int slot_index = ScopeInfo::ContextSlotIndex(
      46             :         scope_info, name, &result->mode, &result->init_flag,
      47    10347325 :         &result->maybe_assigned_flag);
      48             : 
      49    10347325 :     if (slot_index >= 0) {
      50       69621 :       result->context_index = i;
      51       69621 :       result->slot_index = slot_index;
      52       69621 :       return true;
      53             :     }
      54             :   }
      55             :   return false;
      56             : }
      57             : 
      58             : 
      59      819435 : bool Context::is_declaration_context() {
      60      823715 :   if (IsFunctionContext() || IsNativeContext() || IsScriptContext() ||
      61        4280 :       IsModuleContext()) {
      62             :     return true;
      63             :   }
      64        4634 :   if (IsEvalContext()) return closure()->shared()->language_mode() == STRICT;
      65        3926 :   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        5768 :   return ext->IsContextExtension() ||
      70        5768 :          ScopeInfo::cast(ext)->is_declaration_scope();
      71             : }
      72             : 
      73             : 
      74      515538 : Context* Context::declaration_context() {
      75             :   Context* current = this;
      76     1031907 :   while (!current->is_declaration_context()) {
      77             :     current = current->previous();
      78             :   }
      79      515538 :   return current;
      80             : }
      81             : 
      82       37590 : Context* Context::closure_context() {
      83             :   Context* current = this;
      84      131807 :   while (!current->IsFunctionContext() && !current->IsScriptContext() &&
      85       54232 :          !current->IsModuleContext() && !current->IsNativeContext() &&
      86        4048 :          !current->IsEvalContext()) {
      87             :     current = current->previous();
      88             :     DCHECK(current->closure() == closure());
      89             :   }
      90       37590 :   return current;
      91             : }
      92             : 
      93    11252549 : JSObject* Context::extension_object() {
      94             :   DCHECK(IsNativeContext() || IsFunctionContext() || IsBlockContext() ||
      95             :          IsEvalContext());
      96             :   HeapObject* object = extension();
      97    11252549 :   if (object->IsTheHole(GetIsolate())) return nullptr;
      98     6413292 :   if (IsBlockContext()) {
      99       33148 :     if (!object->IsContextExtension()) return nullptr;
     100             :     object = JSObject::cast(ContextExtension::cast(object)->extension());
     101             :   }
     102             :   DCHECK(object->IsJSContextExtensionObject() ||
     103             :          (IsNativeContext() && object->IsJSGlobalObject()));
     104     6383924 :   return JSObject::cast(object);
     105             : }
     106             : 
     107    18293227 : JSReceiver* Context::extension_receiver() {
     108             :   DCHECK(IsNativeContext() || IsWithContext() || IsEvalContext() ||
     109             :          IsFunctionContext() || IsBlockContext());
     110    18293227 :   return IsWithContext() ? JSReceiver::cast(
     111             :                                ContextExtension::cast(extension())->extension())
     112    29241974 :                          : extension_object();
     113             : }
     114             : 
     115    17164715 : ScopeInfo* Context::scope_info() {
     116             :   DCHECK(!IsNativeContext());
     117    17164715 :   if (IsFunctionContext() || IsModuleContext() || IsEvalContext()) {
     118     6190240 :     return closure()->shared()->scope_info();
     119             :   }
     120             :   HeapObject* object = extension();
     121    10974476 :   if (object->IsContextExtension()) {
     122             :     DCHECK(IsBlockContext() || IsCatchContext() || IsWithContext() ||
     123             :            IsDebugEvaluateContext());
     124             :     object = ContextExtension::cast(object)->scope_info();
     125             :   }
     126    10974476 :   return ScopeInfo::cast(object);
     127             : }
     128             : 
     129         353 : Module* Context::module() {
     130             :   Context* current = this;
     131         706 :   while (!current->IsModuleContext()) {
     132             :     current = current->previous();
     133             :   }
     134         353 :   return Module::cast(current->extension());
     135             : }
     136             : 
     137        1794 : String* Context::catch_name() {
     138             :   DCHECK(IsCatchContext());
     139        1794 :   return String::cast(ContextExtension::cast(extension())->extension());
     140             : }
     141             : 
     142             : 
     143    17824470 : JSGlobalObject* Context::global_object() {
     144    17824470 :   return JSGlobalObject::cast(native_context()->extension());
     145             : }
     146             : 
     147             : 
     148           0 : Context* Context::script_context() {
     149             :   Context* current = this;
     150           0 :   while (!current->IsScriptContext()) {
     151             :     current = current->previous();
     152             :   }
     153           0 :   return current;
     154             : }
     155             : 
     156             : 
     157     3934582 : JSObject* Context::global_proxy() {
     158     3934582 :   return native_context()->global_proxy_object();
     159             : }
     160             : 
     161             : 
     162      106897 : void Context::set_global_proxy(JSObject* object) {
     163             :   native_context()->set_global_proxy_object(object);
     164      106897 : }
     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     3667863 : static Maybe<bool> UnscopableLookup(LookupIterator* it) {
     172             :   Isolate* isolate = it->isolate();
     173             : 
     174     3667863 :   Maybe<bool> found = JSReceiver::HasProperty(it);
     175     7335670 :   if (!found.IsJust() || !found.FromJust()) return found;
     176             : 
     177             :   Handle<Object> unscopables;
     178     1427832 :   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      713874 :   if (!unscopables->IsJSReceiver()) return Just(true);
     184             :   Handle<Object> blacklist;
     185      385896 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     186             :       isolate, blacklist,
     187             :       JSReceiver::GetProperty(Handle<JSReceiver>::cast(unscopables),
     188             :                               it->name()),
     189             :       Nothing<bool>());
     190      192934 :   return Just(!blacklist->BooleanValue());
     191             : }
     192             : 
     193             : static PropertyAttributes GetAttributesForMode(VariableMode mode) {
     194             :   DCHECK(IsDeclaredVariableMode(mode));
     195     2814675 :   return mode == CONST ? READ_ONLY : NONE;
     196             : }
     197             : 
     198     6462830 : 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     6462830 :   bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
     207             :   bool failed_whitelist = false;
     208     6462830 :   *index = kNotFound;
     209     6462830 :   *attributes = ABSENT;
     210     6462830 :   *init_flag = kCreatedInitialized;
     211     6462830 :   *variable_mode = VAR;
     212             : 
     213             :   if (FLAG_trace_contexts) {
     214             :     PrintF("Context::Lookup(");
     215             :     name->ShortPrint();
     216             :     PrintF(")\n");
     217             :   }
     218             : 
     219     6271196 :   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    34142978 :     if ((context->IsNativeContext() ||
     231    19790179 :          (context->IsWithContext() && ((flags & SKIP_WITH_CONTEXT) == 0)) ||
     232    30505464 :          context->IsFunctionContext() || context->IsBlockContext()) &&
     233    11559841 :         context->extension_receiver() != nullptr) {
     234     6725702 :       Handle<JSReceiver> object(context->extension_receiver());
     235             : 
     236     6725702 :       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     2229064 :             context->global_object()->native_context()->script_context_table());
     243             :         ScriptContextTable::LookupResult r;
     244     2229064 :         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          53 :           *index = r.slot_index;
     252          53 :           *variable_mode = r.mode;
     253          53 :           *init_flag = r.init_flag;
     254          53 :           *attributes = GetAttributesForMode(r.mode);
     255             :           return ScriptContextTable::GetContext(script_contexts,
     256          53 :                                                 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    12512478 :       if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
     265             :           object->IsJSContextExtensionObject()) {
     266     1218254 :         maybe = JSReceiver::GetOwnPropertyAttributes(object, name);
     267     5507395 :       } 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     3668088 :         if (ScopeInfo::VariableIsSynthetic(*name)) {
     276             :           maybe = Just(ABSENT);
     277             :         } else {
     278     3667863 :           LookupIterator it(object, name, object);
     279     3667863 :           Maybe<bool> found = UnscopableLookup(&it);
     280     3667863 :           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     3667751 :             maybe = Just(found.FromJust() ? NONE : ABSENT);
     287             :           }
     288             :         }
     289             :       } else {
     290     1839307 :         maybe = JSReceiver::GetPropertyAttributes(object, name);
     291             :       }
     292             : 
     293     6725649 :       if (!maybe.IsJust()) return Handle<Object>();
     294             :       DCHECK(!isolate->has_pending_exception());
     295     6725537 :       *attributes = maybe.FromJust();
     296             : 
     297     6725537 :       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     3028101 :         return object;
     303             :       }
     304             :     }
     305             : 
     306             :     // 2. Check the context proper if it has slots.
     307    25459712 :     if (context->IsFunctionContext() || context->IsBlockContext() ||
     308    16152000 :         context->IsScriptContext() || context->IsEvalContext()) {
     309             :       // Use serialized scope information of functions and blocks to search
     310             :       // for the context index.
     311     5659217 :       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     5659217 :                                                    &flag, &maybe_assigned_flag);
     317             :       DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
     318     5659217 :       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     2814622 :         *index = slot_index;
     324     2814622 :         *variable_mode = mode;
     325     2814622 :         *init_flag = flag;
     326     2814622 :         *attributes = GetAttributesForMode(mode);
     327     2814622 :         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     5084009 :       if (follow_context_chain && (flags & STOP_AT_DECLARATION_SCOPE) == 0 &&
     334     2239414 :           context->IsFunctionContext()) {
     335     2064757 :         int function_index = scope_info->FunctionContextSlotIndex(*name);
     336     2064757 :         if (function_index >= 0) {
     337             :           if (FLAG_trace_contexts) {
     338             :             PrintF("=> found intermediate function in context slot %d\n",
     339             :                    function_index);
     340             :           }
     341         236 :           *index = function_index;
     342         236 :           *attributes = READ_ONLY;
     343         236 :           *init_flag = kCreatedInitialized;
     344         236 :           *variable_mode = CONST;
     345         236 :           return context;
     346             :         }
     347             :       }
     348             : 
     349     3436531 :     } else if (context->IsCatchContext()) {
     350             :       // Catch contexts have the variable name in the extension slot.
     351      366169 :       if (String::Equals(name, handle(context->catch_name()))) {
     352             :         if (FLAG_trace_contexts) {
     353             :           PrintF("=> found in catch context\n");
     354             :         }
     355         119 :         *index = Context::THROWN_OBJECT_INDEX;
     356         119 :         *attributes = NONE;
     357         119 :         *init_flag = kCreatedInitialized;
     358         119 :         *variable_mode = VAR;
     359         119 :         return context;
     360             :       }
     361     3070362 :     } else if (context->IsDebugEvaluateContext()) {
     362             :       // Check materialized locals.
     363             :       Object* ext = context->get(EXTENSION_INDEX);
     364       14855 :       if (ext->IsContextExtension()) {
     365             :         Object* obj = ContextExtension::cast(ext)->extension();
     366       14855 :         if (obj->IsJSReceiver()) {
     367             :           Handle<JSReceiver> extension(JSReceiver::cast(obj));
     368       14337 :           LookupIterator it(extension, name, extension);
     369       14337 :           Maybe<bool> found = JSReceiver::HasProperty(&it);
     370       14337 :           if (found.FromMaybe(false)) {
     371        8699 :             *attributes = NONE;
     372        8699 :             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        6156 :       if (obj->IsContext()) {
     379             :         Handle<Object> result =
     380             :             Context::cast(obj)->Lookup(name, DONT_FOLLOW_CHAINS, index,
     381        1464 :                                        attributes, init_flag, variable_mode);
     382        1464 :         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        5280 :       if (obj->IsStringSet()) {
     388        4632 :         failed_whitelist = failed_whitelist || !StringSet::cast(obj)->Has(name);
     389             :       }
     390             :     }
     391             : 
     392             :     // 3. Prepare to continue with the previous (next outermost) context.
     393    18808844 :     if (context->IsNativeContext() ||
     394     6569518 :         ((flags & STOP_AT_DECLARATION_SCOPE) != 0 &&
     395      303066 :          context->is_declaration_context())) {
     396             :       follow_context_chain = false;
     397             :     } else {
     398     5964267 :       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        8598 :       } while (failed_whitelist && !context->IsScriptContext() &&
     403     5968483 :                !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        9552 : int Context::SearchOptimizedCodeMapEntry(SharedFunctionInfo* shared,
     420             :                                          BailoutId osr_ast_id) {
     421             :   DisallowHeapAllocation no_gc;
     422             :   DCHECK(this->IsNativeContext());
     423        9552 :   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       43997 :     for (int i = 0; i < length; i += kEntryLength) {
     428       41845 :       if (WeakCell::cast(optimized_code_map->get(i + kSharedOffset))->value() ==
     429       42112 :               shared &&
     430         267 :           optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
     431             :         return i;
     432             :       }
     433             :     }
     434             :   }
     435             :   return -1;
     436             : }
     437             : 
     438        8477 : Code* Context::SearchOptimizedCodeMap(SharedFunctionInfo* shared,
     439             :                                       BailoutId osr_ast_id) {
     440             :   DCHECK(this->IsNativeContext());
     441        8477 :   int entry = SearchOptimizedCodeMapEntry(shared, osr_ast_id);
     442        8477 :   if (entry != -1) {
     443             :     FixedArray* code_map = osr_code_table();
     444             :     DCHECK_LE(entry + kEntryLength, code_map->length());
     445         211 :     WeakCell* cell = WeakCell::cast(code_map->get(entry + kCachedCodeOffset));
     446         211 :     return cell->cleared() ? nullptr : Code::cast(cell->value());
     447             :   }
     448             :   return nullptr;
     449             : }
     450             : 
     451        2546 : 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        2546 :   Isolate* isolate = native_context->GetIsolate();
     457        2546 :   if (isolate->serializer_enabled()) return;
     458             : 
     459             :   STATIC_ASSERT(kEntryLength == 3);
     460             :   Handle<FixedArray> new_code_map;
     461             :   int entry;
     462             : 
     463        2546 :   if (native_context->OptimizedCodeMapIsCleared()) {
     464        1471 :     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        1075 :     entry = native_context->SearchOptimizedCodeMapEntry(*shared, osr_ast_id);
     469        1075 :     if (entry >= 0) {
     470             :       // Just set the code of the entry.
     471           0 :       Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
     472           0 :       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       21689 :     for (int i = 0; i < length; i += kEntryLength) {
     480       20614 :       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        1075 :     if (entry < 0) {
     488             :       // Copy old optimized code map and append one new entry.
     489             :       new_code_map = isolate->factory()->CopyFixedArrayAndGrow(
     490        1075 :           old_code_map, kEntryLength, TENURED);
     491             :       entry = old_code_map->length();
     492             :     }
     493             :   }
     494             : 
     495        2546 :   Handle<WeakCell> code_cell = isolate->factory()->NewWeakCell(code);
     496        2546 :   Handle<WeakCell> shared_cell = isolate->factory()->NewWeakCell(shared);
     497             : 
     498        2546 :   new_code_map->set(entry + kSharedOffset, *shared_cell);
     499        5092 :   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        2546 :   if (old_code_map != *new_code_map) {
     516             :     native_context->set_osr_code_table(*new_code_map);
     517             :   }
     518             : }
     519             : 
     520     1084953 : void Context::EvictFromOptimizedCodeMap(Code* optimized_code,
     521             :                                         const char* reason) {
     522             :   DCHECK(IsNativeContext());
     523             :   DisallowHeapAllocation no_gc;
     524     2169906 :   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      102208 :   for (int src = 0; src < length; src += kEntryLength) {
     531      188318 :     if (WeakCell::cast(code_map->get(src + kCachedCodeOffset))->value() ==
     532             :         optimized_code) {
     533        2077 :       BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
     534        2077 :       if (FLAG_trace_opt) {
     535             :         PrintF(
     536             :             "[evicting entry from native context optimizing code map (%s) for ",
     537           0 :             reason);
     538           0 :         ShortPrint();
     539             :         DCHECK(!osr.IsNone());
     540           0 :         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       92082 :     if (dst != src) {
     547          10 :       code_map->set(dst + kSharedOffset, code_map->get(src + kSharedOffset));
     548             :       code_map->set(dst + kCachedCodeOffset,
     549          10 :                     code_map->get(src + kCachedCodeOffset));
     550             :       code_map->set(dst + kOsrAstIdOffset,
     551          20 :                     code_map->get(src + kOsrAstIdOffset));
     552             :     }
     553       92082 :     dst += kEntryLength;
     554             :   }
     555        8049 :   if (dst != length) {
     556             :     // Always trim even when array is cleared because of heap verifier.
     557        2077 :     heap->RightTrimFixedArray(code_map, length - dst);
     558        2077 :     if (code_map->length() == 0) {
     559             :       ClearOptimizedCodeMap();
     560             :     }
     561             :   }
     562             : }
     563             : 
     564       23955 : void Context::ClearOptimizedCodeMap() {
     565             :   DCHECK(IsNativeContext());
     566       25159 :   FixedArray* empty_fixed_array = GetHeap()->empty_fixed_array();
     567             :   set_osr_code_table(empty_fixed_array);
     568       23955 : }
     569             : 
     570     1479990 : 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     1479990 :   if (!function->next_function_link()->IsUndefined(isolate)) {
     598           2 :     CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher();
     599           2 :     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     1479990 :                                    UPDATE_WEAK_WRITE_BARRIER);
     606     1479989 :   set(OPTIMIZED_FUNCTIONS_LIST, function, UPDATE_WEAK_WRITE_BARRIER);
     607     1479989 : }
     608             : 
     609             : 
     610         530 : 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        1062 :   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         532 :     if (element_function == function) {
     620         530 :       if (prev == NULL) {
     621             :         set(OPTIMIZED_FUNCTIONS_LIST, element_function->next_function_link(),
     622         528 :             UPDATE_WEAK_WRITE_BARRIER);
     623             :       } else {
     624             :         prev->set_next_function_link(element_function->next_function_link(),
     625           2 :                                      UPDATE_WEAK_WRITE_BARRIER);
     626             :       }
     627         530 :       element_function->set_next_function_link(GetHeap()->undefined_value(),
     628         530 :                                                UPDATE_WEAK_WRITE_BARRIER);
     629         530 :       return;
     630             :     }
     631             :     prev = element_function;
     632             :     element = element_function->next_function_link();
     633             :   }
     634           0 :   UNREACHABLE();
     635             : }
     636             : 
     637             : 
     638      463047 : void Context::SetOptimizedFunctionsListHead(Object* head) {
     639             :   DCHECK(IsNativeContext());
     640      463047 :   set(OPTIMIZED_FUNCTIONS_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
     641      463047 : }
     642             : 
     643             : 
     644       98729 : Object* Context::OptimizedFunctionsListHead() {
     645             :   DCHECK(IsNativeContext());
     646       98729 :   return get(OPTIMIZED_FUNCTIONS_LIST);
     647             : }
     648             : 
     649             : 
     650      642048 : void Context::AddOptimizedCode(Code* code) {
     651             :   DCHECK(IsNativeContext());
     652             :   DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
     653             :   DCHECK(code->next_code_link()->IsUndefined(GetIsolate()));
     654      642048 :   code->set_next_code_link(get(OPTIMIZED_CODE_LIST));
     655      642048 :   set(OPTIMIZED_CODE_LIST, code, UPDATE_WEAK_WRITE_BARRIER);
     656      642049 : }
     657             : 
     658             : 
     659      416434 : void Context::SetOptimizedCodeListHead(Object* head) {
     660             :   DCHECK(IsNativeContext());
     661      416434 :   set(OPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
     662      416434 : }
     663             : 
     664             : 
     665      109382 : Object* Context::OptimizedCodeListHead() {
     666             :   DCHECK(IsNativeContext());
     667      109382 :   return get(OPTIMIZED_CODE_LIST);
     668             : }
     669             : 
     670             : 
     671      422165 : void Context::SetDeoptimizedCodeListHead(Object* head) {
     672             :   DCHECK(IsNativeContext());
     673      422165 :   set(DEOPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
     674      422165 : }
     675             : 
     676             : 
     677      546864 : Object* Context::DeoptimizedCodeListHead() {
     678             :   DCHECK(IsNativeContext());
     679      546864 :   return get(DEOPTIMIZED_CODE_LIST);
     680             : }
     681             : 
     682             : 
     683          48 : Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() {
     684             :   Isolate* isolate = GetIsolate();
     685             :   Handle<Object> result(error_message_for_code_gen_from_strings(), isolate);
     686          48 :   if (!result->IsUndefined(isolate)) return result;
     687             :   return isolate->factory()->NewStringFromStaticChars(
     688          42 :       "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        1501 : int Context::ImportedFieldIndexForName(Handle<String> string) {
     696       26465 :   NATIVE_CONTEXT_IMPORTED_FIELDS(COMPARE_NAME)
     697         237 :   return kNotFound;
     698             : }
     699             : 
     700             : 
     701         237 : int Context::IntrinsicIndexForName(Handle<String> string) {
     702        4898 :   NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NAME);
     703           0 :   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      241926 : int Context::IntrinsicIndexForName(const unsigned char* unsigned_string,
     712             :                                    int length) {
     713             :   const char* string = reinterpret_cast<const char*>(unsigned_string);
     714      241926 :   NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NAME);
     715          75 :   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      105618 : void Context::ResetErrorsThrown() {
     744             :   DCHECK(IsNativeContext());
     745             :   set_errors_thrown(Smi::FromInt(0));
     746      105618 : }
     747             : 
     748     1159401 : void Context::IncrementErrorsThrown() {
     749             :   DCHECK(IsNativeContext());
     750             : 
     751             :   int previous_value = errors_thrown()->value();
     752     1159401 :   set_errors_thrown(Smi::FromInt(previous_value + 1));
     753     1159401 : }
     754             : 
     755             : 
     756         130 : int Context::GetErrorsThrown() { return errors_thrown()->value(); }
     757             : 
     758             : }  // namespace internal
     759             : }  // namespace v8

Generated by: LCOV version 1.10