• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Extend(Handle<ScriptContextTable> table,Handle<Context> script_context)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 
Lookup(Handle<ScriptContextTable> table,Handle<String> name,LookupResult * result)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 
is_declaration_context()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 
declaration_context()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 
closure_context()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 
extension_object()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 
extension_receiver()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 
scope_info()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 
module()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 
catch_name()137 String* Context::catch_name() {
138   DCHECK(IsCatchContext());
139   return String::cast(ContextExtension::cast(extension())->extension());
140 }
141 
142 
global_object()143 JSGlobalObject* Context::global_object() {
144   return JSGlobalObject::cast(native_context()->extension());
145 }
146 
147 
script_context()148 Context* Context::script_context() {
149   Context* current = this;
150   while (!current->IsScriptContext()) {
151     current = current->previous();
152   }
153   return current;
154 }
155 
156 
global_proxy()157 JSObject* Context::global_proxy() {
158   return native_context()->global_proxy_object();
159 }
160 
161 
set_global_proxy(JSObject * object)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  */
UnscopableLookup(LookupIterator * it)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 
GetAttributesForMode(VariableMode mode)193 static PropertyAttributes GetAttributesForMode(VariableMode mode) {
194   DCHECK(IsDeclaredVariableMode(mode));
195   return mode == CONST ? READ_ONLY : NONE;
196 }
197 
Lookup(Handle<String> name,ContextLookupFlags flags,int * index,PropertyAttributes * attributes,InitializationFlag * init_flag,VariableMode * variable_mode)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 
SearchOptimizedCodeMapEntry(SharedFunctionInfo * shared,BailoutId osr_ast_id)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 
SearchOptimizedCodeMap(SharedFunctionInfo * shared,BailoutId osr_ast_id)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 
AddToOptimizedCodeMap(Handle<Context> native_context,Handle<SharedFunctionInfo> shared,Handle<Code> code,BailoutId osr_ast_id)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 
EvictFromOptimizedCodeMap(Code * optimized_code,const char * reason)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 
ClearOptimizedCodeMap()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 
AddOptimizedFunction(JSFunction * function)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 
RemoveOptimizedFunction(JSFunction * function)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 
SetOptimizedFunctionsListHead(Object * head)638 void Context::SetOptimizedFunctionsListHead(Object* head) {
639   DCHECK(IsNativeContext());
640   set(OPTIMIZED_FUNCTIONS_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
641 }
642 
643 
OptimizedFunctionsListHead()644 Object* Context::OptimizedFunctionsListHead() {
645   DCHECK(IsNativeContext());
646   return get(OPTIMIZED_FUNCTIONS_LIST);
647 }
648 
649 
AddOptimizedCode(Code * code)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 
SetOptimizedCodeListHead(Object * head)659 void Context::SetOptimizedCodeListHead(Object* head) {
660   DCHECK(IsNativeContext());
661   set(OPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
662 }
663 
664 
OptimizedCodeListHead()665 Object* Context::OptimizedCodeListHead() {
666   DCHECK(IsNativeContext());
667   return get(OPTIMIZED_CODE_LIST);
668 }
669 
670 
SetDeoptimizedCodeListHead(Object * head)671 void Context::SetDeoptimizedCodeListHead(Object* head) {
672   DCHECK(IsNativeContext());
673   set(DEOPTIMIZED_CODE_LIST, head, UPDATE_WEAK_WRITE_BARRIER);
674 }
675 
676 
DeoptimizedCodeListHead()677 Object* Context::DeoptimizedCodeListHead() {
678   DCHECK(IsNativeContext());
679   return get(DEOPTIMIZED_CODE_LIST);
680 }
681 
682 
ErrorMessageForCodeGenerationFromStrings()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 
ImportedFieldIndexForName(Handle<String> string)695 int Context::ImportedFieldIndexForName(Handle<String> string) {
696   NATIVE_CONTEXT_IMPORTED_FIELDS(COMPARE_NAME)
697   return kNotFound;
698 }
699 
700 
IntrinsicIndexForName(Handle<String> string)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 
IntrinsicIndexForName(const unsigned char * unsigned_string,int length)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 
IsBootstrappingOrNativeContext(Isolate * isolate,Object * object)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 
IsBootstrappingOrValidParentContext(Object * object,Context * child)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 
ResetErrorsThrown()743 void Context::ResetErrorsThrown() {
744   DCHECK(IsNativeContext());
745   set_errors_thrown(Smi::FromInt(0));
746 }
747 
IncrementErrorsThrown()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 
GetErrorsThrown()756 int Context::GetErrorsThrown() { return errors_thrown()->value(); }
757 
758 }  // namespace internal
759 }  // namespace v8
760