• 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/objects/contexts.h"
6 
7 #include "src/ast/modules.h"
8 #include "src/debug/debug.h"
9 #include "src/execution/isolate-inl.h"
10 #include "src/init/bootstrapper.h"
11 #include "src/objects/module-inl.h"
12 #include "src/objects/string-set-inl.h"
13 
14 namespace v8 {
15 namespace internal {
16 
AddLocalNamesFromContext(Isolate * isolate,Handle<ScriptContextTable> script_context_table,Handle<Context> script_context,bool ignore_duplicates,int script_context_index)17 void ScriptContextTable::AddLocalNamesFromContext(
18     Isolate* isolate, Handle<ScriptContextTable> script_context_table,
19     Handle<Context> script_context, bool ignore_duplicates,
20     int script_context_index) {
21   ReadOnlyRoots roots(isolate);
22   PtrComprCageBase cage_base(isolate);
23   Handle<NameToIndexHashTable> names_table(
24       script_context_table->names_to_context_index(cage_base), isolate);
25   Handle<ScopeInfo> scope_info(script_context->scope_info(cage_base), isolate);
26   int local_count = scope_info->ContextLocalCount();
27   names_table = names_table->EnsureCapacity(isolate, names_table, local_count);
28   for (auto it : ScopeInfo::IterateLocalNames(scope_info)) {
29     Handle<Name> name(it->name(cage_base), isolate);
30     if (ignore_duplicates) {
31       int32_t hash = NameToIndexShape::Hash(roots, name);
32       if (names_table->FindEntry(cage_base, roots, name, hash).is_found()) {
33         continue;
34       }
35     }
36     names_table = NameToIndexHashTable::Add(isolate, names_table, name,
37                                             script_context_index);
38   }
39   script_context_table->set_names_to_context_index(*names_table);
40 }
41 
Extend(Isolate * isolate,Handle<ScriptContextTable> table,Handle<Context> script_context,bool ignore_duplicates)42 Handle<ScriptContextTable> ScriptContextTable::Extend(
43     Isolate* isolate, Handle<ScriptContextTable> table,
44     Handle<Context> script_context, bool ignore_duplicates) {
45   Handle<ScriptContextTable> result;
46   int used = table->used(kAcquireLoad);
47   int length = table->length();
48   CHECK(used >= 0 && length > 0 && used < length);
49   if (used + kFirstContextSlotIndex == length) {
50     CHECK(length < Smi::kMaxValue / 2);
51     Handle<FixedArray> copy =
52         isolate->factory()->CopyFixedArrayAndGrow(table, length);
53     copy->set_map(ReadOnlyRoots(isolate).script_context_table_map());
54     result = Handle<ScriptContextTable>::cast(copy);
55   } else {
56     result = table;
57   }
58   DCHECK(script_context->IsScriptContext());
59   ScriptContextTable::AddLocalNamesFromContext(isolate, result, script_context,
60                                                ignore_duplicates, used);
61   result->set(used + kFirstContextSlotIndex, *script_context, kReleaseStore);
62   result->set_used(used + 1, kReleaseStore);
63   return result;
64 }
65 
Initialize(Isolate * isolate)66 void Context::Initialize(Isolate* isolate) {
67   ScopeInfo scope_info = this->scope_info();
68   int header = scope_info.ContextHeaderLength();
69   for (int var = 0; var < scope_info.ContextLocalCount(); var++) {
70     if (scope_info.ContextLocalInitFlag(var) == kNeedsInitialization) {
71       set(header + var, ReadOnlyRoots(isolate).the_hole_value());
72     }
73   }
74 }
75 
Lookup(Handle<String> name,VariableLookupResult * result)76 bool ScriptContextTable::Lookup(Handle<String> name,
77                                 VariableLookupResult* result) {
78   DisallowGarbageCollection no_gc;
79   int index = names_to_context_index().Lookup(name);
80   if (index == -1) return false;
81   DCHECK_LE(0, index);
82   DCHECK_LT(index, used(kAcquireLoad));
83   Context context = get_context(index);
84   DCHECK(context.IsScriptContext());
85   int slot_index = context.scope_info().ContextSlotIndex(name, result);
86   if (slot_index >= 0) {
87     result->context_index = index;
88     result->slot_index = slot_index;
89     return true;
90   }
91   return false;
92 }
93 
is_declaration_context() const94 bool Context::is_declaration_context() const {
95   if (IsFunctionContext() || IsNativeContext() || IsScriptContext() ||
96       IsModuleContext()) {
97     return true;
98   }
99   if (IsEvalContext()) {
100     return scope_info().language_mode() == LanguageMode::kStrict;
101   }
102   if (!IsBlockContext()) return false;
103   return scope_info().is_declaration_scope();
104 }
105 
declaration_context() const106 Context Context::declaration_context() const {
107   Context current = *this;
108   while (!current.is_declaration_context()) {
109     current = current.previous();
110   }
111   return current;
112 }
113 
closure_context() const114 Context Context::closure_context() const {
115   Context current = *this;
116   while (!current.IsFunctionContext() && !current.IsScriptContext() &&
117          !current.IsModuleContext() && !current.IsNativeContext() &&
118          !current.IsEvalContext()) {
119     current = current.previous();
120   }
121   return current;
122 }
123 
extension_object() const124 JSObject Context::extension_object() const {
125   DCHECK(IsNativeContext() || IsFunctionContext() || IsBlockContext() ||
126          IsEvalContext() || IsCatchContext());
127   HeapObject object = extension();
128   if (object.IsUndefined()) return JSObject();
129   DCHECK(object.IsJSContextExtensionObject() ||
130          (IsNativeContext() && object.IsJSGlobalObject()));
131   return JSObject::cast(object);
132 }
133 
extension_receiver() const134 JSReceiver Context::extension_receiver() const {
135   DCHECK(IsNativeContext() || IsWithContext() || IsEvalContext() ||
136          IsFunctionContext() || IsBlockContext());
137   return IsWithContext() ? JSReceiver::cast(extension()) : extension_object();
138 }
139 
module() const140 SourceTextModule Context::module() const {
141   Context current = *this;
142   while (!current.IsModuleContext()) {
143     current = current.previous();
144   }
145   return SourceTextModule::cast(current.extension());
146 }
147 
global_object() const148 JSGlobalObject Context::global_object() const {
149   return JSGlobalObject::cast(native_context().extension());
150 }
151 
script_context() const152 Context Context::script_context() const {
153   Context current = *this;
154   while (!current.IsScriptContext()) {
155     current = current.previous();
156   }
157   return current;
158 }
159 
global_proxy() const160 JSGlobalProxy Context::global_proxy() const {
161   return native_context().global_proxy_object();
162 }
163 
164 /**
165  * Lookups a property in an object environment, taking the unscopables into
166  * account. This is used For HasBinding spec algorithms for ObjectEnvironment.
167  */
UnscopableLookup(LookupIterator * it,bool is_with_context)168 static Maybe<bool> UnscopableLookup(LookupIterator* it, bool is_with_context) {
169   Isolate* isolate = it->isolate();
170 
171   Maybe<bool> found = JSReceiver::HasProperty(it);
172   if (!is_with_context || found.IsNothing() || !found.FromJust()) return found;
173 
174   Handle<Object> unscopables;
175   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
176       isolate, unscopables,
177       JSReceiver::GetProperty(isolate,
178                               Handle<JSReceiver>::cast(it->GetReceiver()),
179                               isolate->factory()->unscopables_symbol()),
180       Nothing<bool>());
181   if (!unscopables->IsJSReceiver()) return Just(true);
182   Handle<Object> blocklist;
183   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
184       isolate, blocklist,
185       JSReceiver::GetProperty(isolate, Handle<JSReceiver>::cast(unscopables),
186                               it->name()),
187       Nothing<bool>());
188   return Just(!blocklist->BooleanValue(isolate));
189 }
190 
GetAttributesForMode(VariableMode mode)191 static PropertyAttributes GetAttributesForMode(VariableMode mode) {
192   DCHECK(IsSerializableVariableMode(mode));
193   return IsConstVariableMode(mode) ? READ_ONLY : NONE;
194 }
195 
196 // static
Lookup(Handle<Context> context,Handle<String> name,ContextLookupFlags flags,int * index,PropertyAttributes * attributes,InitializationFlag * init_flag,VariableMode * variable_mode,bool * is_sloppy_function_name)197 Handle<Object> Context::Lookup(Handle<Context> context, Handle<String> name,
198                                ContextLookupFlags flags, int* index,
199                                PropertyAttributes* attributes,
200                                InitializationFlag* init_flag,
201                                VariableMode* variable_mode,
202                                bool* is_sloppy_function_name) {
203   Isolate* isolate = context->GetIsolate();
204 
205   bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
206   *index = kNotFound;
207   *attributes = ABSENT;
208   *init_flag = kCreatedInitialized;
209   *variable_mode = VariableMode::kVar;
210   if (is_sloppy_function_name != nullptr) {
211     *is_sloppy_function_name = false;
212   }
213 
214   if (FLAG_trace_contexts) {
215     PrintF("Context::Lookup(");
216     name->ShortPrint();
217     PrintF(")\n");
218   }
219 
220   do {
221     if (FLAG_trace_contexts) {
222       PrintF(" - looking in context %p",
223              reinterpret_cast<void*>(context->ptr()));
224       if (context->IsScriptContext()) PrintF(" (script context)");
225       if (context->IsNativeContext()) PrintF(" (native context)");
226       PrintF("\n");
227     }
228 
229     // 1. Check global objects, subjects of with, and extension objects.
230     DCHECK_IMPLIES(context->IsEvalContext() && context->has_extension(),
231                    context->extension().IsTheHole(isolate));
232     if ((context->IsNativeContext() || context->IsWithContext() ||
233          context->IsFunctionContext() || context->IsBlockContext()) &&
234         context->has_extension() && !context->extension_receiver().is_null()) {
235       Handle<JSReceiver> object(context->extension_receiver(), isolate);
236 
237       if (context->IsNativeContext()) {
238         DisallowGarbageCollection no_gc;
239         if (FLAG_trace_contexts) {
240           PrintF(" - trying other script contexts\n");
241         }
242         // Try other script contexts.
243         ScriptContextTable script_contexts =
244             context->global_object().native_context().script_context_table();
245         VariableLookupResult r;
246         if (script_contexts.Lookup(name, &r)) {
247           Context script_context = script_contexts.get_context(r.context_index);
248           if (FLAG_trace_contexts) {
249             PrintF("=> found property in script context %d: %p\n",
250                    r.context_index,
251                    reinterpret_cast<void*>(script_context.ptr()));
252           }
253           *index = r.slot_index;
254           *variable_mode = r.mode;
255           *init_flag = r.init_flag;
256           *attributes = GetAttributesForMode(r.mode);
257           return handle(script_context, isolate);
258         }
259       }
260 
261       // Context extension objects needs to behave as if they have no
262       // prototype.  So even if we want to follow prototype chains, we need
263       // to only do a local lookup for context extension objects.
264       Maybe<PropertyAttributes> maybe = Nothing<PropertyAttributes>();
265       if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0 ||
266           object->IsJSContextExtensionObject()) {
267         maybe = JSReceiver::GetOwnPropertyAttributes(object, name);
268       } else {
269         // A with context will never bind "this", but debug-eval may look into
270         // a with context when resolving "this". Other synthetic variables such
271         // as new.target may be resolved as VariableMode::kDynamicLocal due to
272         // bug v8:5405 , skipping them here serves as a workaround until a more
273         // thorough fix can be applied.
274         // TODO(v8:5405): Replace this check with a DCHECK when resolution of
275         // of synthetic variables does not go through this code path.
276         if (ScopeInfo::VariableIsSynthetic(*name)) {
277           DCHECK(context->IsWithContext());
278           maybe = Just(ABSENT);
279         } else {
280           LookupIterator it(isolate, object, name, object);
281           Maybe<bool> found = UnscopableLookup(&it, context->IsWithContext());
282           if (found.IsNothing()) {
283             maybe = Nothing<PropertyAttributes>();
284           } else {
285             // Luckily, consumers of |maybe| only care whether the property
286             // was absent or not, so we can return a dummy |NONE| value
287             // for its attributes when it was present.
288             maybe = Just(found.FromJust() ? NONE : ABSENT);
289           }
290         }
291       }
292 
293       if (maybe.IsNothing()) 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->ptr()));
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         context->IsModuleContext() || context->IsCatchContext()) {
310       DisallowGarbageCollection no_gc;
311       // Use serialized scope information of functions and blocks to search
312       // for the context index.
313       ScopeInfo scope_info = context->scope_info();
314       VariableLookupResult lookup_result;
315       int slot_index = scope_info.ContextSlotIndex(name, &lookup_result);
316       DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
317       if (slot_index >= 0) {
318         // Re-direct lookup to the ScriptContextTable in case we find a hole in
319         // a REPL script context. REPL scripts allow re-declaration of
320         // script-level let bindings. The value itself is stored in the script
321         // context of the first script that declared a variable, all other
322         // script contexts will contain 'the hole' for that particular name.
323         if (scope_info.IsReplModeScope() &&
324             context->get(slot_index).IsTheHole(isolate)) {
325           context = Handle<Context>(context->previous(), isolate);
326           continue;
327         }
328 
329         if (FLAG_trace_contexts) {
330           PrintF("=> found local in context slot %d (mode = %hhu)\n",
331                  slot_index, static_cast<uint8_t>(lookup_result.mode));
332         }
333         *index = slot_index;
334         *variable_mode = lookup_result.mode;
335         *init_flag = lookup_result.init_flag;
336         *attributes = GetAttributesForMode(lookup_result.mode);
337         return context;
338       }
339 
340       // Check the slot corresponding to the intermediate context holding
341       // only the function name variable. It's conceptually (and spec-wise)
342       // in an outer scope of the function's declaration scope.
343       if (follow_context_chain && context->IsFunctionContext()) {
344         int function_index = scope_info.FunctionContextSlotIndex(*name);
345         if (function_index >= 0) {
346           if (FLAG_trace_contexts) {
347             PrintF("=> found intermediate function in context slot %d\n",
348                    function_index);
349           }
350           *index = function_index;
351           *attributes = READ_ONLY;
352           *init_flag = kCreatedInitialized;
353           *variable_mode = VariableMode::kConst;
354           if (is_sloppy_function_name != nullptr &&
355               is_sloppy(scope_info.language_mode())) {
356             *is_sloppy_function_name = true;
357           }
358           return context;
359         }
360       }
361 
362       // Lookup variable in module imports and exports.
363       if (context->IsModuleContext()) {
364         VariableMode mode;
365         InitializationFlag flag;
366         MaybeAssignedFlag maybe_assigned_flag;
367         int cell_index =
368             scope_info.ModuleIndex(*name, &mode, &flag, &maybe_assigned_flag);
369         if (cell_index != 0) {
370           if (FLAG_trace_contexts) {
371             PrintF("=> found in module imports or exports\n");
372           }
373           *index = cell_index;
374           *variable_mode = mode;
375           *init_flag = flag;
376           *attributes = SourceTextModuleDescriptor::GetCellIndexKind(
377                             cell_index) == SourceTextModuleDescriptor::kExport
378                             ? GetAttributesForMode(mode)
379                             : READ_ONLY;
380           return handle(context->module(), isolate);
381         }
382       }
383     } else if (context->IsDebugEvaluateContext()) {
384       // Check materialized locals.
385       Object ext = context->get(EXTENSION_INDEX);
386       if (ext.IsJSReceiver()) {
387         Handle<JSReceiver> extension(JSReceiver::cast(ext), isolate);
388         LookupIterator it(isolate, extension, name, extension);
389         Maybe<bool> found = JSReceiver::HasProperty(&it);
390         if (found.FromMaybe(false)) {
391           *attributes = NONE;
392           return extension;
393         }
394       }
395 
396       // Check blocklist. Names that are listed, cannot be resolved further.
397       ScopeInfo scope_info = context->scope_info();
398       if (scope_info.HasLocalsBlockList() &&
399           scope_info.LocalsBlockList().Has(isolate, name)) {
400         if (FLAG_trace_contexts) {
401           PrintF(" - name is blocklisted. Aborting.\n");
402         }
403         break;
404       }
405 
406       // Check the original context, but do not follow its context chain.
407       Object obj = context->get(WRAPPED_CONTEXT_INDEX);
408       if (obj.IsContext()) {
409         Handle<Context> wrapped_context(Context::cast(obj), isolate);
410         Handle<Object> result =
411             Context::Lookup(wrapped_context, name, DONT_FOLLOW_CHAINS, index,
412                             attributes, init_flag, variable_mode);
413         if (!result.is_null()) return result;
414       }
415     }
416 
417     // 3. Prepare to continue with the previous (next outermost) context.
418     if (context->IsNativeContext()) break;
419 
420     context = Handle<Context>(context->previous(), isolate);
421   } while (follow_context_chain);
422 
423   if (FLAG_trace_contexts) {
424     PrintF("=> no property/slot found\n");
425   }
426   return Handle<Object>::null();
427 }
428 
AddOptimizedCode(CodeT code)429 void NativeContext::AddOptimizedCode(CodeT code) {
430   DCHECK(CodeKindCanDeoptimize(code.kind()));
431   DCHECK(code.next_code_link().IsUndefined());
432   code.set_next_code_link(OptimizedCodeListHead());
433   set(OPTIMIZED_CODE_LIST, code, UPDATE_WEAK_WRITE_BARRIER, kReleaseStore);
434 }
435 
ErrorMessageForCodeGenerationFromStrings()436 Handle<Object> Context::ErrorMessageForCodeGenerationFromStrings() {
437   Isolate* isolate = GetIsolate();
438   Handle<Object> result(error_message_for_code_gen_from_strings(), isolate);
439   if (!result->IsUndefined(isolate)) return result;
440   return isolate->factory()->NewStringFromStaticChars(
441       "Code generation from strings disallowed for this context");
442 }
443 
444 #define COMPARE_NAME(index, type, name) \
445   if (string->IsOneByteEqualTo(base::StaticCharVector(#name))) return index;
446 
IntrinsicIndexForName(Handle<String> string)447 int Context::IntrinsicIndexForName(Handle<String> string) {
448   NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NAME);
449   return kNotFound;
450 }
451 
452 #undef COMPARE_NAME
453 
454 #define COMPARE_NAME(index, type, name)                                      \
455   {                                                                          \
456     const int name_length = static_cast<int>(arraysize(#name)) - 1;          \
457     if ((length == name_length) && strncmp(string, #name, name_length) == 0) \
458       return index;                                                          \
459   }
460 
IntrinsicIndexForName(const unsigned char * unsigned_string,int length)461 int Context::IntrinsicIndexForName(const unsigned char* unsigned_string,
462                                    int length) {
463   const char* string = reinterpret_cast<const char*>(unsigned_string);
464   NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(COMPARE_NAME);
465   return kNotFound;
466 }
467 
468 #undef COMPARE_NAME
469 
470 #ifdef VERIFY_HEAP
471 namespace {
472 // TODO(v8:12298): Fix js-context-specialization cctests to set up full
473 // native contexts instead of using dummy internalized strings as
474 // extensions.
IsContexExtensionTestObject(HeapObject extension)475 bool IsContexExtensionTestObject(HeapObject extension) {
476   return extension.IsInternalizedString() &&
477          String::cast(extension).length() == 1;
478 }
479 }  // namespace
480 
VerifyExtensionSlot(HeapObject extension)481 void Context::VerifyExtensionSlot(HeapObject extension) {
482   CHECK(scope_info().HasContextExtensionSlot());
483   // Early exit for potentially uninitialized contexfts.
484   if (extension.IsUndefined()) return;
485   if (extension.IsJSContextExtensionObject()) {
486     CHECK((IsBlockContext() && scope_info().is_declaration_scope()) ||
487           IsFunctionContext());
488   } else if (IsModuleContext()) {
489     CHECK(extension.IsSourceTextModule());
490   } else if (IsDebugEvaluateContext() || IsWithContext()) {
491     CHECK(extension.IsJSReceiver() ||
492           (IsWithContext() && IsContexExtensionTestObject(extension)));
493   } else if (IsNativeContext()) {
494     CHECK(extension.IsJSGlobalObject() ||
495           IsContexExtensionTestObject(extension));
496   } else if (IsScriptContext()) {
497     // Host-defined options can be stored on the context for classic scripts.
498     CHECK(extension.IsFixedArray());
499   }
500 }
501 #endif  // VERIFY_HEAP
502 
set_extension(HeapObject object,WriteBarrierMode mode)503 void Context::set_extension(HeapObject object, WriteBarrierMode mode) {
504   DCHECK(scope_info().HasContextExtensionSlot());
505 #ifdef VERIFY_HEAP
506   VerifyExtensionSlot(object);
507 #endif
508   set(EXTENSION_INDEX, object, mode);
509 }
510 
511 #ifdef DEBUG
512 
IsBootstrappingOrValidParentContext(Object object,Context child)513 bool Context::IsBootstrappingOrValidParentContext(Object object,
514                                                   Context child) {
515   // During bootstrapping we allow all objects to pass as
516   // contexts. This is necessary to fix circular dependencies.
517   if (child.GetIsolate()->bootstrapper()->IsActive()) return true;
518   if (!object.IsContext()) return false;
519   Context context = Context::cast(object);
520   return context.IsNativeContext() || context.IsScriptContext() ||
521          context.IsModuleContext() || !child.IsModuleContext();
522 }
523 
524 #endif
525 
ResetErrorsThrown()526 void NativeContext::ResetErrorsThrown() { set_errors_thrown(Smi::FromInt(0)); }
527 
IncrementErrorsThrown()528 void NativeContext::IncrementErrorsThrown() {
529   int previous_value = errors_thrown().value();
530   set_errors_thrown(Smi::FromInt(previous_value + 1));
531 }
532 
GetErrorsThrown()533 int NativeContext::GetErrorsThrown() { return errors_thrown().value(); }
534 
535 STATIC_ASSERT(Context::MIN_CONTEXT_SLOTS == 2);
536 STATIC_ASSERT(Context::MIN_CONTEXT_EXTENDED_SLOTS == 3);
537 STATIC_ASSERT(NativeContext::kScopeInfoOffset ==
538               Context::OffsetOfElementAt(NativeContext::SCOPE_INFO_INDEX));
539 STATIC_ASSERT(NativeContext::kPreviousOffset ==
540               Context::OffsetOfElementAt(NativeContext::PREVIOUS_INDEX));
541 STATIC_ASSERT(NativeContext::kExtensionOffset ==
542               Context::OffsetOfElementAt(NativeContext::EXTENSION_INDEX));
543 
544 STATIC_ASSERT(NativeContext::kStartOfStrongFieldsOffset ==
545               Context::OffsetOfElementAt(-1));
546 STATIC_ASSERT(NativeContext::kStartOfWeakFieldsOffset ==
547               Context::OffsetOfElementAt(NativeContext::FIRST_WEAK_SLOT));
548 STATIC_ASSERT(NativeContext::kMicrotaskQueueOffset ==
549               Context::SizeFor(NativeContext::NATIVE_CONTEXT_SLOTS));
550 STATIC_ASSERT(NativeContext::kSize ==
551               (Context::SizeFor(NativeContext::NATIVE_CONTEXT_SLOTS) +
552                kSystemPointerSize));
553 
554 #ifdef V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS
RunPromiseHook(PromiseHookType type,Handle<JSPromise> promise,Handle<Object> parent)555 void NativeContext::RunPromiseHook(PromiseHookType type,
556                                    Handle<JSPromise> promise,
557                                    Handle<Object> parent) {
558   Isolate* isolate = promise->GetIsolate();
559   DCHECK(isolate->HasContextPromiseHooks());
560   int contextSlot;
561 
562   switch (type) {
563     case PromiseHookType::kInit:
564       contextSlot = PROMISE_HOOK_INIT_FUNCTION_INDEX;
565       break;
566     case PromiseHookType::kResolve:
567       contextSlot = PROMISE_HOOK_RESOLVE_FUNCTION_INDEX;
568       break;
569     case PromiseHookType::kBefore:
570       contextSlot = PROMISE_HOOK_BEFORE_FUNCTION_INDEX;
571       break;
572     case PromiseHookType::kAfter:
573       contextSlot = PROMISE_HOOK_AFTER_FUNCTION_INDEX;
574       break;
575     default:
576       UNREACHABLE();
577   }
578 
579   Handle<Object> hook(isolate->native_context()->get(contextSlot), isolate);
580   if (hook->IsUndefined()) return;
581 
582   int argc = type == PromiseHookType::kInit ? 2 : 1;
583   Handle<Object> argv[2] = {
584     Handle<Object>::cast(promise),
585     parent
586   };
587 
588   Handle<Object> receiver = isolate->global_proxy();
589 
590   StackLimitCheck check(isolate);
591   bool failed = false;
592   if (check.HasOverflowed()) {
593     isolate->StackOverflow();
594     failed = true;
595   } else {
596     failed = Execution::Call(isolate, hook, receiver, argc, argv).is_null();
597   }
598   if (failed) {
599     DCHECK(isolate->has_pending_exception());
600     Handle<Object> exception(isolate->pending_exception(), isolate);
601 
602     MessageLocation* no_location = nullptr;
603     Handle<JSMessageObject> message =
604         isolate->CreateMessageOrAbort(exception, no_location);
605     MessageHandler::ReportMessage(isolate, no_location, message);
606 
607     isolate->clear_pending_exception();
608   }
609 }
610 #endif
611 
612 }  // namespace internal
613 }  // namespace v8
614