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