[WTF] Add user-defined literal for ASCIILiteral
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMWindowBase.cpp
1 /*
2  *  Copyright (C) 2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2006 Jon Shier (jshier@iastate.edu)
4  *  Copyright (C) 2003-2017 Apple Inc. All rights reseved.
5  *  Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6  *  Copyright (c) 2015 Canon Inc. All rights reserved.
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Lesser General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public
19  *  License along with this library; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
21  *  USA
22  */
23
24 #include "config.h"
25 #include "JSDOMWindowBase.h"
26
27 #include "ActiveDOMCallbackMicrotask.h"
28 #include "Chrome.h"
29 #include "CommonVM.h"
30 #include "DOMWindow.h"
31 #include "Document.h"
32 #include "FetchResponse.h"
33 #include "Frame.h"
34 #include "InspectorController.h"
35 #include "JSDOMBindingSecurity.h"
36 #include "JSDOMGlobalObjectTask.h"
37 #include "JSDOMWindowCustom.h"
38 #include "JSFetchResponse.h"
39 #include "JSMainThreadExecState.h"
40 #include "JSNode.h"
41 #include "Logging.h"
42 #include "Page.h"
43 #include "RejectedPromiseTracker.h"
44 #include "RuntimeApplicationChecks.h"
45 #include "ScriptController.h"
46 #include "ScriptModuleLoader.h"
47 #include "SecurityOrigin.h"
48 #include "Settings.h"
49 #include "WebCoreJSClientData.h"
50 #include <JavaScriptCore/CodeBlock.h>
51 #include <JavaScriptCore/JSInternalPromise.h>
52 #include <JavaScriptCore/JSInternalPromiseDeferred.h>
53 #include <JavaScriptCore/Microtask.h>
54 #include <JavaScriptCore/PromiseDeferredTimer.h>
55 #include <JavaScriptCore/StrongInlines.h>
56 #include <JavaScriptCore/WebAssemblyPrototype.h>
57 #include <wtf/Language.h>
58 #include <wtf/MainThread.h>
59
60 #if PLATFORM(IOS)
61 #include "ChromeClient.h"
62 #endif
63
64
65 namespace WebCore {
66 using namespace JSC;
67
68 const ClassInfo JSDOMWindowBase::s_info = { "Window", &JSDOMGlobalObject::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDOMWindowBase) };
69
70 const GlobalObjectMethodTable JSDOMWindowBase::s_globalObjectMethodTable = {
71     &supportsRichSourceInfo,
72     &shouldInterruptScript,
73     &javaScriptRuntimeFlags,
74     &queueTaskToEventLoop,
75     &shouldInterruptScriptBeforeTimeout,
76     &moduleLoaderImportModule,
77     &moduleLoaderResolve,
78     &moduleLoaderFetch,
79     &moduleLoaderCreateImportMetaProperties,
80     &moduleLoaderEvaluate,
81     &promiseRejectionTracker,
82     &defaultLanguage,
83 #if ENABLE(WEBASSEMBLY)
84     &compileStreaming,
85     &instantiateStreaming,
86 #else
87     nullptr,
88     nullptr,
89 #endif
90 };
91
92 JSDOMWindowBase::JSDOMWindowBase(VM& vm, Structure* structure, RefPtr<DOMWindow>&& window, JSWindowProxy* proxy)
93     : JSDOMGlobalObject(vm, structure, proxy->world(), &s_globalObjectMethodTable)
94     , m_windowCloseWatchpoints((window && window->frame()) ? IsWatched : IsInvalidated)
95     , m_wrapped(WTFMove(window))
96     , m_proxy(proxy)
97 {
98 }
99
100 void JSDOMWindowBase::finishCreation(VM& vm, JSWindowProxy* proxy)
101 {
102     Base::finishCreation(vm, proxy);
103     ASSERT(inherits(vm, info()));
104
105     auto& builtinNames = static_cast<JSVMClientData*>(vm.clientData)->builtinNames();
106
107     GlobalPropertyInfo staticGlobals[] = {
108         GlobalPropertyInfo(builtinNames.documentPublicName(), jsNull(), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
109         GlobalPropertyInfo(builtinNames.windowPublicName(), m_proxy, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
110     };
111
112     addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals));
113
114     if (m_wrapped && m_wrapped->frame() && m_wrapped->frame()->settings().needsSiteSpecificQuirks())
115         setNeedsSiteSpecificQuirks(true);
116 }
117
118 void JSDOMWindowBase::destroy(JSCell* cell)
119 {
120     static_cast<JSDOMWindowBase*>(cell)->JSDOMWindowBase::~JSDOMWindowBase();
121 }
122
123 void JSDOMWindowBase::updateDocument()
124 {
125     // Since "document" property is defined as { configurable: false, writable: false, enumerable: true },
126     // users cannot change its attributes further.
127     // Reaching here, the attributes of "document" property should be never changed.
128     ASSERT(m_wrapped->document());
129     ExecState* exec = globalExec();
130     bool shouldThrowReadOnlyError = false;
131     bool ignoreReadOnlyErrors = true;
132     bool putResult = false;
133     symbolTablePutTouchWatchpointSet(this, exec, static_cast<JSVMClientData*>(exec->vm().clientData)->builtinNames().documentPublicName(), toJS(exec, this, m_wrapped->document()), shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult);
134 }
135
136 ScriptExecutionContext* JSDOMWindowBase::scriptExecutionContext() const
137 {
138     return m_wrapped->document();
139 }
140
141 void JSDOMWindowBase::printErrorMessage(const String& message) const
142 {
143     printErrorMessageForFrame(wrapped().frame(), message);
144 }
145
146 bool JSDOMWindowBase::supportsRichSourceInfo(const JSGlobalObject* object)
147 {
148     const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
149     Frame* frame = thisObject->wrapped().frame();
150     if (!frame)
151         return false;
152
153     Page* page = frame->page();
154     if (!page)
155         return false;
156
157     bool enabled = page->inspectorController().enabled();
158     ASSERT(enabled || !thisObject->debugger());
159     return enabled;
160 }
161
162 static inline bool shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(Page* page)
163 {
164     // See <rdar://problem/5479443>. We don't think that page can ever be NULL
165     // in this case, but if it is, we've gotten into a state where we may have
166     // hung the UI, with no way to ask the client whether to cancel execution.
167     // For now, our solution is just to cancel execution no matter what,
168     // ensuring that we never hang. We might want to consider other solutions
169     // if we discover problems with this one.
170     ASSERT(page);
171     return !page;
172 }
173
174 bool JSDOMWindowBase::shouldInterruptScript(const JSGlobalObject* object)
175 {
176     const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
177     ASSERT(thisObject->wrapped().frame());
178     Page* page = thisObject->wrapped().frame()->page();
179     return shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(page);
180 }
181
182 bool JSDOMWindowBase::shouldInterruptScriptBeforeTimeout(const JSGlobalObject* object)
183 {
184     const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
185     ASSERT(thisObject->wrapped().frame());
186     Page* page = thisObject->wrapped().frame()->page();
187
188     if (shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(page))
189         return true;
190
191 #if PLATFORM(IOS)
192     if (page->chrome().client().isStopping())
193         return true;
194 #endif
195
196     return JSGlobalObject::shouldInterruptScriptBeforeTimeout(object);
197 }
198
199 RuntimeFlags JSDOMWindowBase::javaScriptRuntimeFlags(const JSGlobalObject* object)
200 {
201     const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object);
202     Frame* frame = thisObject->wrapped().frame();
203     if (!frame)
204         return RuntimeFlags();
205     return frame->settings().javaScriptRuntimeFlags();
206 }
207
208 class JSDOMWindowMicrotaskCallback : public RefCounted<JSDOMWindowMicrotaskCallback> {
209 public:
210     static Ref<JSDOMWindowMicrotaskCallback> create(JSDOMWindowBase& globalObject, Ref<JSC::Microtask>&& task)
211     {
212         return adoptRef(*new JSDOMWindowMicrotaskCallback(globalObject, WTFMove(task)));
213     }
214
215     void call()
216     {
217         Ref<JSDOMWindowMicrotaskCallback> protectedThis(*this);
218         VM& vm = m_globalObject->vm();
219         JSLockHolder lock(vm);
220         auto scope = DECLARE_THROW_SCOPE(vm);
221
222         ExecState* exec = m_globalObject->globalExec();
223
224         JSMainThreadExecState::runTask(exec, m_task);
225
226         scope.assertNoException();
227     }
228
229 private:
230     JSDOMWindowMicrotaskCallback(JSDOMWindowBase& globalObject, Ref<JSC::Microtask>&& task)
231         : m_globalObject { globalObject.vm(), &globalObject }
232         , m_task { WTFMove(task) }
233     {
234     }
235
236     Strong<JSDOMWindowBase> m_globalObject;
237     Ref<JSC::Microtask> m_task;
238 };
239
240 void JSDOMWindowBase::queueTaskToEventLoop(JSGlobalObject& object, Ref<JSC::Microtask>&& task)
241 {
242     JSDOMWindowBase& thisObject = static_cast<JSDOMWindowBase&>(object);
243
244     RefPtr<JSDOMWindowMicrotaskCallback> callback = JSDOMWindowMicrotaskCallback::create(thisObject, WTFMove(task));
245     auto microtask = std::make_unique<ActiveDOMCallbackMicrotask>(MicrotaskQueue::mainThreadQueue(), *thisObject.scriptExecutionContext(), [callback]() mutable {
246         callback->call();
247     });
248
249     MicrotaskQueue::mainThreadQueue().append(WTFMove(microtask));
250 }
251
252 void JSDOMWindowBase::willRemoveFromWindowProxy()
253 {
254     setCurrentEvent(0);
255 }
256
257 JSWindowProxy* JSDOMWindowBase::proxy() const
258 {
259     return m_proxy;
260 }
261
262 JSValue toJS(ExecState* state, DOMWindow& domWindow)
263 {
264     auto* frame = domWindow.frame();
265     if (!frame)
266         return jsNull();
267     return toJS(state, frame->windowProxy());
268 }
269
270 JSDOMWindow* toJSDOMWindow(Frame& frame, DOMWrapperWorld& world)
271 {
272     return frame.script().globalObject(world);
273 }
274
275 JSDOMWindow* toJSDOMWindow(JSC::VM& vm, JSValue value)
276 {
277     if (!value.isObject())
278         return nullptr;
279
280     while (!value.isNull()) {
281         JSObject* object = asObject(value);
282         const ClassInfo* classInfo = object->classInfo(vm);
283         if (classInfo == JSDOMWindow::info())
284             return jsCast<JSDOMWindow*>(object);
285         if (classInfo == JSWindowProxy::info())
286             return jsDynamicCast<JSDOMWindow*>(vm, jsCast<JSWindowProxy*>(object)->window());
287         value = object->getPrototypeDirect(vm);
288     }
289     return nullptr;
290 }
291
292 DOMWindow& incumbentDOMWindow(ExecState& state)
293 {
294     return asJSDOMWindow(&callerGlobalObject(state))->wrapped();
295 }
296
297 DOMWindow& activeDOMWindow(ExecState& state)
298 {
299     return asJSDOMWindow(state.lexicalGlobalObject())->wrapped();
300 }
301
302 DOMWindow& firstDOMWindow(ExecState& state)
303 {
304     return asJSDOMWindow(state.vmEntryGlobalObject())->wrapped();
305 }
306
307 Document* responsibleDocument(ExecState& state)
308 {
309     CallerFunctor functor;
310     state.iterate(functor);
311     auto* callerFrame = functor.callerFrame();
312     if (!callerFrame)
313         return nullptr;
314     return asJSDOMWindow(callerFrame->lexicalGlobalObject())->wrapped().document();
315 }
316
317 void JSDOMWindowBase::fireFrameClearedWatchpointsForWindow(DOMWindow* window)
318 {
319     JSC::VM& vm = commonVM();
320     JSVMClientData* clientData = static_cast<JSVMClientData*>(vm.clientData);
321     Vector<Ref<DOMWrapperWorld>> wrapperWorlds;
322     clientData->getAllWorlds(wrapperWorlds);
323     for (unsigned i = 0; i < wrapperWorlds.size(); ++i) {
324         auto& wrappers = wrapperWorlds[i]->wrappers();
325         auto result = wrappers.find(window);
326         if (result == wrappers.end())
327             continue;
328         JSC::JSObject* wrapper = result->value.get();
329         if (!wrapper)
330             continue;
331         JSDOMWindowBase* jsWindow = JSC::jsCast<JSDOMWindowBase*>(wrapper);
332         jsWindow->m_windowCloseWatchpoints.fireAll(vm, "Frame cleared");
333     }
334 }
335
336 JSC::Identifier JSDOMWindowBase::moduleLoaderResolve(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleName, JSC::JSValue importerModuleKey, JSC::JSValue scriptFetcher)
337 {
338     JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject);
339     if (RefPtr<Document> document = thisObject->wrapped().document())
340         return document->moduleLoader()->resolve(globalObject, exec, moduleLoader, moduleName, importerModuleKey, scriptFetcher);
341     return { };
342 }
343
344 JSC::JSInternalPromise* JSDOMWindowBase::moduleLoaderFetch(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleKey, JSC::JSValue parameters, JSC::JSValue scriptFetcher)
345 {
346     JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject);
347     if (RefPtr<Document> document = thisObject->wrapped().document())
348         return document->moduleLoader()->fetch(globalObject, exec, moduleLoader, moduleKey, parameters, scriptFetcher);
349     JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::create(exec, globalObject);
350     return deferred->reject(exec, jsUndefined());
351 }
352
353 JSC::JSValue JSDOMWindowBase::moduleLoaderEvaluate(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleKey, JSC::JSValue moduleRecord, JSC::JSValue scriptFetcher)
354 {
355     JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject);
356     if (RefPtr<Document> document = thisObject->wrapped().document())
357         return document->moduleLoader()->evaluate(globalObject, exec, moduleLoader, moduleKey, moduleRecord, scriptFetcher);
358     return JSC::jsUndefined();
359 }
360
361 JSC::JSInternalPromise* JSDOMWindowBase::moduleLoaderImportModule(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSString* moduleName, JSC::JSValue parameters, const JSC::SourceOrigin& sourceOrigin)
362 {
363     JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject);
364     if (RefPtr<Document> document = thisObject->wrapped().document())
365         return document->moduleLoader()->importModule(globalObject, exec, moduleLoader, moduleName, parameters, sourceOrigin);
366     JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::create(exec, globalObject);
367     return deferred->reject(exec, jsUndefined());
368 }
369
370 JSC::JSObject* JSDOMWindowBase::moduleLoaderCreateImportMetaProperties(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleKey, JSC::JSModuleRecord* moduleRecord, JSC::JSValue scriptFetcher)
371 {
372     JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject);
373     if (RefPtr<Document> document = thisObject->wrapped().document())
374         return document->moduleLoader()->createImportMetaProperties(globalObject, exec, moduleLoader, moduleKey, moduleRecord, scriptFetcher);
375     return constructEmptyObject(exec, globalObject->nullPrototypeObjectStructure());
376 }
377
378 #if ENABLE(WEBASSEMBLY)
379 static std::optional<Vector<uint8_t>> tryAllocate(JSC::ExecState* exec, JSC::JSPromiseDeferred* promise, const char* data, size_t byteSize)
380 {
381     Vector<uint8_t> arrayBuffer;
382     if (!arrayBuffer.tryReserveCapacity(byteSize)) {
383         promise->reject(exec, createOutOfMemoryError(exec));
384         return std::nullopt;
385     }
386
387     arrayBuffer.grow(byteSize);
388     memcpy(arrayBuffer.data(), data, byteSize);
389
390     return arrayBuffer;
391 }
392
393 static bool isResponseCorrect(JSC::ExecState* exec, FetchResponse* inputResponse, JSC::JSPromiseDeferred* promise)
394 {
395     bool isResponseCorsSameOrigin = inputResponse->type() == ResourceResponse::Type::Basic || inputResponse->type() == ResourceResponse::Type::Cors || inputResponse->type() == ResourceResponse::Type::Default;
396
397     if (!isResponseCorsSameOrigin) {
398         promise->reject(exec, createTypeError(exec, "Response is not CORS-same-origin"_s));
399         return false;
400     }
401
402     if (!inputResponse->ok()) {
403         promise->reject(exec, createTypeError(exec, "Response has not returned OK status"_s));
404         return false;
405     }
406
407     auto contentType = inputResponse->headers().fastGet(HTTPHeaderName::ContentType);
408     if (!equalLettersIgnoringASCIICase(contentType, "application/wasm")) {
409         promise->reject(exec, createTypeError(exec, "Unexpected response MIME type. Expected 'application/wasm'"_s));
410         return false;
411     }
412
413     return true;
414 }
415
416 static void handleResponseOnStreamingAction(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, FetchResponse* inputResponse, JSC::JSPromiseDeferred* promise, Function<void(JSC::ExecState* exec, const char* data, size_t byteSize)>&& actionCallback)
417 {
418     if (!isResponseCorrect(exec, inputResponse, promise))
419         return;
420
421     if (inputResponse->isBodyReceivedByChunk()) {
422         inputResponse->consumeBodyReceivedByChunk([promise, callback = WTFMove(actionCallback), globalObject, data = SharedBuffer::create()] (auto&& result) mutable {
423             ExecState* exec = globalObject->globalExec();
424             if (result.hasException()) {
425                 promise->reject(exec, createTypeError(exec, result.exception().message()));
426                 return;
427             }
428
429             if (auto chunk = result.returnValue())
430                 data->append(reinterpret_cast<const char*>(chunk->data), chunk->size);
431             else {
432                 VM& vm = exec->vm();
433                 JSLockHolder lock(vm);
434
435                 callback(exec, data->data(), data->size());
436             }
437         });
438         return;
439     }
440
441     auto body = inputResponse->consumeBody();
442     WTF::switchOn(body, [&] (Ref<FormData>& formData) {
443         if (auto buffer = formData->asSharedBuffer()) {
444             VM& vm = exec->vm();
445             JSLockHolder lock(vm);
446
447             actionCallback(exec, buffer->data(), buffer->size());
448             return;
449         }
450         // FIXME: http://webkit.org/b/184886> Implement loading for the Blob type
451         promise->reject(exec, createTypeError(exec, "Unexpected Response's Content-type"_s));
452     }, [&] (Ref<SharedBuffer>& buffer) {
453         VM& vm = exec->vm();
454         JSLockHolder lock(vm);
455
456         actionCallback(exec, buffer->data(), buffer->size());
457     }, [&] (std::nullptr_t&) {
458         promise->reject(exec, createTypeError(exec, "Unexpected Response's Content-type"_s));
459     });
460 }
461
462 void JSDOMWindowBase::compileStreaming(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSPromiseDeferred* promise, JSC::JSValue source)
463 {
464     ASSERT(source);
465
466     VM& vm = exec->vm();
467
468     ASSERT(vm.promiseDeferredTimer->hasPendingPromise(promise));
469     ASSERT(vm.promiseDeferredTimer->hasDependancyInPendingPromise(promise, globalObject));
470
471     if (auto inputResponse = JSFetchResponse::toWrapped(vm, source)) {
472         handleResponseOnStreamingAction(globalObject, exec, inputResponse, promise, [promise] (JSC::ExecState* exec, const char* data, size_t byteSize) mutable {
473             if (auto arrayBuffer = tryAllocate(exec, promise, data, byteSize))
474                 JSC::WebAssemblyPrototype::webAssemblyModuleValidateAsync(exec, promise, WTFMove(*arrayBuffer));
475         });
476     } else
477         promise->reject(exec, createTypeError(exec, "first argument must be an Response or Promise for Response"_s));
478 }
479
480 void JSDOMWindowBase::instantiateStreaming(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSPromiseDeferred* promise, JSC::JSValue source, JSC::JSObject* importedObject)
481 {
482     ASSERT(source);
483
484     VM& vm = exec->vm();
485
486     ASSERT(vm.promiseDeferredTimer->hasPendingPromise(promise));
487     ASSERT(vm.promiseDeferredTimer->hasDependancyInPendingPromise(promise, globalObject));
488     ASSERT(vm.promiseDeferredTimer->hasDependancyInPendingPromise(promise, importedObject));
489
490     if (auto inputResponse = JSFetchResponse::toWrapped(vm, source)) {
491         handleResponseOnStreamingAction(globalObject, exec, inputResponse, promise, [promise, importedObject] (JSC::ExecState* exec, const char* data, size_t byteSize) mutable {
492             if (auto arrayBuffer = tryAllocate(exec, promise, data, byteSize))
493                 JSC::WebAssemblyPrototype::webAssemblyModuleInstantinateAsync(exec, promise, WTFMove(*arrayBuffer), importedObject);
494         });
495     } else
496         promise->reject(exec, createTypeError(exec, "first argument must be an Response or Promise for Response"_s));
497 }
498 #endif
499
500 void JSDOMWindowBase::promiseRejectionTracker(JSGlobalObject* jsGlobalObject, ExecState* exec, JSPromise* promise, JSPromiseRejectionOperation operation)
501 {
502     // https://html.spec.whatwg.org/multipage/webappapis.html#the-hostpromiserejectiontracker-implementation
503
504     VM& vm = exec->vm();
505     auto& globalObject = *JSC::jsCast<JSDOMWindowBase*>(jsGlobalObject);
506     auto* context = globalObject.scriptExecutionContext();
507     if (!context)
508         return;
509
510     // InternalPromises should not be exposed to user scripts.
511     if (JSC::jsDynamicCast<JSC::JSInternalPromise*>(vm, promise))
512         return;
513
514     // FIXME: If script has muted errors (cross origin), terminate these steps.
515     // <https://webkit.org/b/171415> Implement the `muted-errors` property of Scripts to avoid onerror/onunhandledrejection for cross-origin scripts
516
517     switch (operation) {
518     case JSPromiseRejectionOperation::Reject:
519         context->ensureRejectedPromiseTracker().promiseRejected(*exec, globalObject, *promise);
520         break;
521     case JSPromiseRejectionOperation::Handle:
522         context->ensureRejectedPromiseTracker().promiseHandled(*exec, globalObject, *promise);
523         break;
524     }
525 }
526
527 } // namespace WebCore