WebKit Bugzilla
Attachment 346992 Details for
Bug 188265
: Worker should support unhandled promise rejections
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-188265-20180813090542.patch (text/plain), 58.98 KB, created by
Yusuke Suzuki
on 2018-08-12 17:05:44 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Yusuke Suzuki
Created:
2018-08-12 17:05:44 PDT
Size:
58.98 KB
patch
obsolete
>Subversion Revision: 234789 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index f139546d3bdcd461fecc428bf1069744da87c3cd..6ef5b5d2daf8823b04ce8e3f216c5e8fdfed4208 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,66 @@ >+2018-08-12 Yusuke Suzuki <yusukesuzuki@slowstart.org> >+ >+ Worker should support unhandled promise rejections >+ https://bugs.webkit.org/show_bug.cgi?id=188265 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch adds PromiseRejectionEvent support in workers. >+ >+ * Sources.txt: >+ * WebCore.xcodeproj/project.pbxproj: >+ * bindings/js/JSDOMGlobalObject.cpp: >+ (WebCore::JSDOMGlobalObject::promiseRejectionTracker): >+ Move promiseRejectionTracker handler from JSDOMWindowBase to JSDOMGlobalObject >+ to share it with WorkerGlobalScope. >+ >+ * bindings/js/JSDOMGlobalObject.h: >+ * bindings/js/JSDOMWindowBase.cpp: >+ (WebCore::JSDOMWindowBase::promiseRejectionTracker): Deleted. >+ Moved to JSDOMGlobalObject. >+ >+ * bindings/js/JSDOMWindowBase.h: >+ * bindings/js/JSExecState.cpp: >+ (WebCore::JSExecState::didLeaveScriptContext): >+ PromiseRejectionTracker is driven in workers too. >+ >+ * bindings/js/JSPromiseRejectionEventCustom.cpp: Added. >+ (WebCore::JSPromiseRejectionEvent::visitAdditionalChildren): >+ Marking PromiseRejectionEvent::m_reason. >+ >+ * bindings/js/JSWorkerGlobalScopeBase.cpp: >+ Configure promiseRejectionTracker. >+ >+ * dom/Microtasks.cpp: >+ (WebCore::MicrotaskQueue::queueForScriptExecutionContext): >+ * dom/Microtasks.h: >+ * dom/PromiseRejectionEvent.cpp: >+ (WebCore::PromiseRejectionEvent::PromiseRejectionEvent): >+ * dom/PromiseRejectionEvent.h: >+ * dom/PromiseRejectionEvent.idl: >+ Expose it to worker scope. The custom mark function is required since we start >+ using JSValueInWrappedObject. And the constructor no longer requires ExecState. >+ >+ * dom/RejectedPromiseTracker.cpp: >+ (WebCore::RejectedPromiseTracker::reportUnhandledRejections): >+ (WebCore::RejectedPromiseTracker::reportRejectionHandled): >+ Remove state argument for PromiseRejectionEvent::create. >+ >+ * dom/ScriptExecutionContext.cpp: >+ (WebCore::ScriptExecutionContext::removeRejectedPromiseTracker): >+ * dom/ScriptExecutionContext.h: >+ * html/HTMLAttributeNames.in: >+ Add onunhandledrejection and onrejectionhandled event handler attributes. >+ >+ * workers/WorkerGlobalScope.h: >+ * workers/WorkerGlobalScope.idl: >+ Add onunhandledrejection and onrejectionhandled event handler attributes. >+ >+ * workers/WorkerThread.cpp: >+ (WebCore::WorkerThread::stop): >+ In worker thread, we should delete PromiseRejectionTracker before destroying VM. >+ In main thread, we do not need to handle this case since we do not destroy VM. >+ > 2018-08-12 Yusuke Suzuki <yusukesuzuki@slowstart.org> > > Break reference cycle in ErrorEvent by using JSValueInWrappedObject >diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt >index 70a01639b46333b558cc23ae3694aa7c3439fa52..f0ef78610dd046b367272c05aac6744585c938a2 100644 >--- a/Source/WebCore/Sources.txt >+++ b/Source/WebCore/Sources.txt >@@ -433,6 +433,7 @@ bindings/js/JSPerformanceEntryCustom.cpp > bindings/js/JSPerformanceObserverCustom.cpp > bindings/js/JSPluginElementFunctions.cpp > bindings/js/JSPopStateEventCustom.cpp >+bindings/js/JSPromiseRejectionEventCustom.cpp > bindings/js/JSReadableStreamPrivateConstructors.cpp > bindings/js/JSReadableStreamSourceCustom.cpp > bindings/js/JSRemoteDOMWindowBase.cpp >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index 69138ca40697816fcee328073ae789769d0b6dde..d34f8b009380c32c935e8790b7eddad0898df738 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -9256,6 +9256,7 @@ > 71EFCEDA202B388F00D7C411 /* AnimationEffectReadOnly.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnimationEffectReadOnly.cpp; sourceTree = "<group>"; }; > 71EFCEDB202B389000D7C411 /* KeyframeEffectReadOnly.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = KeyframeEffectReadOnly.idl; sourceTree = "<group>"; }; > 71EFCEDE202B39C700D7C411 /* JSAnimationEffectReadOnlyCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSAnimationEffectReadOnlyCustom.cpp; sourceTree = "<group>"; }; >+ A4A69B8BB91B49D0A804C31D /* JSPromiseRejectionEventCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPromiseRejectionEventCustom.cpp; sourceTree = "<group>"; }; > 71EFCEDF202B3AA100D7C411 /* JSKeyframeEffectReadOnly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSKeyframeEffectReadOnly.h; sourceTree = "<group>"; }; > 71EFCEE0202B3AA300D7C411 /* JSKeyframeEffectReadOnly.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSKeyframeEffectReadOnly.cpp; sourceTree = "<group>"; }; > 71F936F71DD4F99B00922CC7 /* tracks-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "tracks-support.js"; sourceTree = "<group>"; }; >@@ -19920,6 +19921,7 @@ > 3140C52B1FE06B4900D2A873 /* JSOffscreenCanvasRenderingContext2DCustom.cpp */, > CB38FD551CD21D5B00592A3F /* JSPerformanceEntryCustom.cpp */, > 833CF70F20DB3F5F00141BCC /* JSPerformanceObserverCustom.cpp */, >+ A4A69B8BB91B49D0A804C31D /* JSPromiseRejectionEventCustom.cpp */, > 83F572941FA1066F003837BE /* JSServiceWorkerClientCustom.cpp */, > 460D19441FCE21DD00C3DB85 /* JSServiceWorkerGlobalScopeCustom.cpp */, > BC98A27C0C0C9950004BEBF7 /* JSStyleSheetCustom.cpp */, >diff --git a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp b/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp >index 720361ea62b9d7c4cc7bc919590e87b9fbaac2f0..c157dbb71dffbb8c57465a39522ee6508e44ae77 100644 >--- a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp >+++ b/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp >@@ -40,12 +40,15 @@ > #include "JSReadableStreamPrivateConstructors.h" > #include "JSRemoteDOMWindow.h" > #include "JSWorkerGlobalScope.h" >+#include "RejectedPromiseTracker.h" > #include "RuntimeEnabledFeatures.h" > #include "StructuredClone.h" > #include "WebCoreJSClientData.h" > #include "WorkerGlobalScope.h" > #include <JavaScriptCore/BuiltinNames.h> > #include <JavaScriptCore/CodeBlock.h> >+#include <JavaScriptCore/JSInternalPromise.h> >+#include <JavaScriptCore/JSInternalPromiseDeferred.h> > > namespace WebCore { > using namespace JSC; >@@ -239,6 +242,33 @@ Event* JSDOMGlobalObject::currentEvent() const > return m_currentEvent; > } > >+void JSDOMGlobalObject::promiseRejectionTracker(JSGlobalObject* jsGlobalObject, ExecState* exec, JSPromise* promise, JSPromiseRejectionOperation operation) >+{ >+ // https://html.spec.whatwg.org/multipage/webappapis.html#the-hostpromiserejectiontracker-implementation >+ >+ VM& vm = exec->vm(); >+ auto& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(jsGlobalObject); >+ auto* context = globalObject.scriptExecutionContext(); >+ if (!context) >+ return; >+ >+ // InternalPromises should not be exposed to user scripts. >+ if (JSC::jsDynamicCast<JSC::JSInternalPromise*>(vm, promise)) >+ return; >+ >+ // FIXME: If script has muted errors (cross origin), terminate these steps. >+ // <https://webkit.org/b/171415> Implement the `muted-errors` property of Scripts to avoid onerror/onunhandledrejection for cross-origin scripts >+ >+ switch (operation) { >+ case JSPromiseRejectionOperation::Reject: >+ context->ensureRejectedPromiseTracker().promiseRejected(*exec, globalObject, *promise); >+ break; >+ case JSPromiseRejectionOperation::Handle: >+ context->ensureRejectedPromiseTracker().promiseHandled(*exec, globalObject, *promise); >+ break; >+ } >+} >+ > JSDOMGlobalObject& callerGlobalObject(ExecState& state) > { > class GetCallerGlobalObjectFunctor { >diff --git a/Source/WebCore/bindings/js/JSDOMGlobalObject.h b/Source/WebCore/bindings/js/JSDOMGlobalObject.h >index 93dc5a0fa4c98f4a785807106ee98818245c6509..9b4164436d5623095c8a495a7f09fafdcac2722e 100644 >--- a/Source/WebCore/bindings/js/JSDOMGlobalObject.h >+++ b/Source/WebCore/bindings/js/JSDOMGlobalObject.h >@@ -91,6 +91,8 @@ class WEBCORE_EXPORT JSDOMGlobalObject : public JSC::JSGlobalObject { > } > > protected: >+ static void promiseRejectionTracker(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSPromise*, JSC::JSPromiseRejectionOperation); >+ > JSDOMStructureMap m_structures; > JSDOMConstructorMap m_constructors; > DOMGuardedObjectSet m_guardedObjects; >diff --git a/Source/WebCore/bindings/js/JSDOMWindowBase.cpp b/Source/WebCore/bindings/js/JSDOMWindowBase.cpp >index 22228224e5818c7cc78f39ad6a94e143488b886f..6764fc2bb57e22718467020538da8bbce2b1d04a 100644 >--- a/Source/WebCore/bindings/js/JSDOMWindowBase.cpp >+++ b/Source/WebCore/bindings/js/JSDOMWindowBase.cpp >@@ -465,31 +465,4 @@ void JSDOMWindowBase::instantiateStreaming(JSC::JSGlobalObject* globalObject, JS > } > #endif > >-void JSDOMWindowBase::promiseRejectionTracker(JSGlobalObject* jsGlobalObject, ExecState* exec, JSPromise* promise, JSPromiseRejectionOperation operation) >-{ >- // https://html.spec.whatwg.org/multipage/webappapis.html#the-hostpromiserejectiontracker-implementation >- >- VM& vm = exec->vm(); >- auto& globalObject = *JSC::jsCast<JSDOMWindowBase*>(jsGlobalObject); >- auto* context = globalObject.scriptExecutionContext(); >- if (!context) >- return; >- >- // InternalPromises should not be exposed to user scripts. >- if (JSC::jsDynamicCast<JSC::JSInternalPromise*>(vm, promise)) >- return; >- >- // FIXME: If script has muted errors (cross origin), terminate these steps. >- // <https://webkit.org/b/171415> Implement the `muted-errors` property of Scripts to avoid onerror/onunhandledrejection for cross-origin scripts >- >- switch (operation) { >- case JSPromiseRejectionOperation::Reject: >- context->ensureRejectedPromiseTracker().promiseRejected(*exec, globalObject, *promise); >- break; >- case JSPromiseRejectionOperation::Handle: >- context->ensureRejectedPromiseTracker().promiseHandled(*exec, globalObject, *promise); >- break; >- } >-} >- > } // namespace WebCore >diff --git a/Source/WebCore/bindings/js/JSDOMWindowBase.h b/Source/WebCore/bindings/js/JSDOMWindowBase.h >index a88aa62ef1155bab9a3c7720a8fe224e52318c61..84f2852208ef1ba97fc091b7085a469242acec7a 100644 >--- a/Source/WebCore/bindings/js/JSDOMWindowBase.h >+++ b/Source/WebCore/bindings/js/JSDOMWindowBase.h >@@ -102,8 +102,6 @@ class WEBCORE_EXPORT JSDOMWindowBase : public JSDOMGlobalObject { > static void instantiateStreaming(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSPromiseDeferred*, JSC::JSValue, JSC::JSObject*); > #endif > >- static void promiseRejectionTracker(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSPromise*, JSC::JSPromiseRejectionOperation); >- > RefPtr<DOMWindow> m_wrapped; > JSWindowProxy* m_proxy; > }; >diff --git a/Source/WebCore/bindings/js/JSExecState.cpp b/Source/WebCore/bindings/js/JSExecState.cpp >index d784c84bab22bb9f681f723f340ad795eab7f08e..19bdbf3213fbca1891ad034ed14c6a5a1d0d3d8c 100644 >--- a/Source/WebCore/bindings/js/JSExecState.cpp >+++ b/Source/WebCore/bindings/js/JSExecState.cpp >@@ -36,20 +36,9 @@ namespace WebCore { > > void JSExecState::didLeaveScriptContext(JSC::ExecState* exec) > { >- // While main thread has many ScriptExecutionContexts, WorkerGlobalScope and worker thread have >- // one on one correspondence. The lifetime of MicrotaskQueue is aligned to this semantics. >- // While main thread MicrotaskQueue is persistently held, worker's MicrotaskQueue is held by >- // WorkerGlobalScope. > ScriptExecutionContext* context = scriptExecutionContextFromExecState(exec); >- if (isMainThread()) { >- MicrotaskQueue::mainThreadQueue().performMicrotaskCheckpoint(); >- // FIXME: Promise rejection tracker is available only in non-worker environment. >- // https://bugs.webkit.org/show_bug.cgi?id=188265 >- context->ensureRejectedPromiseTracker().processQueueSoon(); >- } else { >- ASSERT(context->isWorkerGlobalScope()); >- static_cast<WorkerGlobalScope*>(context)->microtaskQueue().performMicrotaskCheckpoint(); >- } >+ MicrotaskQueue::queueForScriptExecutionContext(context).performMicrotaskCheckpoint(); >+ context->ensureRejectedPromiseTracker().processQueueSoon(); > } > > JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException) >diff --git a/Source/WebCore/bindings/js/JSPromiseRejectionEventCustom.cpp b/Source/WebCore/bindings/js/JSPromiseRejectionEventCustom.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..3df99957bda91277f3074244358a02ee85f872a0 >--- /dev/null >+++ b/Source/WebCore/bindings/js/JSPromiseRejectionEventCustom.cpp >@@ -0,0 +1,40 @@ >+/* >+ * Copyright (C) 2018 Yusuke Suzuki <yusukesuzuki@slowstart.org>. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "JSPromiseRejectionEvent.h" >+ >+#include "PromiseRejectionEvent.h" >+#include <JavaScriptCore/HeapInlines.h> >+#include <JavaScriptCore/JSCJSValueInlines.h> >+ >+namespace WebCore { >+ >+void JSPromiseRejectionEvent::visitAdditionalChildren(JSC::SlotVisitor& visitor) >+{ >+ wrapped().reason().visit(visitor); >+} >+ >+} // namespace WebCore >diff --git a/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp b/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp >index f4c43531858dae4de82b39ac83c0773f190d9fa5..50ff12a9d22a976ba8a2fb9485d2f10548c9780c 100644 >--- a/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp >+++ b/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp >@@ -62,7 +62,7 @@ const GlobalObjectMethodTable JSWorkerGlobalScopeBase::s_globalObjectMethodTable > nullptr, // moduleLoaderFetch > nullptr, // moduleLoaderCreateImportMetaProperties > nullptr, // moduleLoaderEvaluate >- nullptr, // promiseRejectionTracker >+ &promiseRejectionTracker, > &defaultLanguage, > nullptr, // compileStreaming > nullptr, // instantiateStreaming >diff --git a/Source/WebCore/dom/Microtasks.cpp b/Source/WebCore/dom/Microtasks.cpp >index c3ade44c15c42297c8ff8bd3801bbbf1726ef74b..06ec928d77f1827f8644caa40006262c7f608aca 100644 >--- a/Source/WebCore/dom/Microtasks.cpp >+++ b/Source/WebCore/dom/Microtasks.cpp >@@ -47,6 +47,18 @@ MicrotaskQueue& MicrotaskQueue::mainThreadQueue() > return queue; > } > >+MicrotaskQueue& MicrotaskQueue::queueForScriptExecutionContext(ScriptExecutionContext* context) >+{ >+ // While main thread has many ScriptExecutionContexts, WorkerGlobalScope and worker thread have >+ // one on one correspondence. The lifetime of MicrotaskQueue is aligned to this semantics. >+ // While main thread MicrotaskQueue is persistently held, worker's MicrotaskQueue is held by >+ // WorkerGlobalScope. >+ if (isMainThread()) >+ return mainThreadQueue(); >+ ASSERT(context->isWorkerGlobalScope()); >+ return downcast<WorkerGlobalScope>(*context).microtaskQueue(); >+} >+ > void MicrotaskQueue::append(std::unique_ptr<Microtask>&& task) > { > m_microtaskQueue.append(WTFMove(task)); >diff --git a/Source/WebCore/dom/Microtasks.h b/Source/WebCore/dom/Microtasks.h >index 25ec8f85afd40c82bddd302cebafea140579b9a6..88d6fc5bed41086121a2cf49d05bfcd600da3737 100644 >--- a/Source/WebCore/dom/Microtasks.h >+++ b/Source/WebCore/dom/Microtasks.h >@@ -28,6 +28,7 @@ > namespace WebCore { > > class MicrotaskQueue; >+class ScriptExecutionContext; > > class Microtask { > public: >@@ -69,6 +70,7 @@ class MicrotaskQueue { > friend class Microtask; > public: > WEBCORE_EXPORT static MicrotaskQueue& mainThreadQueue(); >+ WEBCORE_EXPORT static MicrotaskQueue& queueForScriptExecutionContext(ScriptExecutionContext*); > > WEBCORE_EXPORT MicrotaskQueue(); > WEBCORE_EXPORT ~MicrotaskQueue(); >diff --git a/Source/WebCore/dom/PromiseRejectionEvent.cpp b/Source/WebCore/dom/PromiseRejectionEvent.cpp >index 11ea1377a967c6a0c7b653a772730998fadda383..451d6288b44110f54488b70f10476835a8223be3 100644 >--- a/Source/WebCore/dom/PromiseRejectionEvent.cpp >+++ b/Source/WebCore/dom/PromiseRejectionEvent.cpp >@@ -34,10 +34,10 @@ > namespace WebCore { > using namespace JSC; > >-PromiseRejectionEvent::PromiseRejectionEvent(ExecState& state, const AtomicString& type, const Init& initializer, IsTrusted isTrusted) >+PromiseRejectionEvent::PromiseRejectionEvent(const AtomicString& type, const Init& initializer, IsTrusted isTrusted) > : Event(type, initializer, isTrusted) > , m_promise(*(initializer.promise)) >- , m_reason(state.vm(), initializer.reason) >+ , m_reason(initializer.reason) > { > } > >diff --git a/Source/WebCore/dom/PromiseRejectionEvent.h b/Source/WebCore/dom/PromiseRejectionEvent.h >index d82625ffca306c82e81696b724be24d427569d08..2dc7d8555dbfce12effc6b9fd7228c35ece758b3 100644 >--- a/Source/WebCore/dom/PromiseRejectionEvent.h >+++ b/Source/WebCore/dom/PromiseRejectionEvent.h >@@ -26,7 +26,7 @@ > #pragma once > > #include "Event.h" >-#include <JavaScriptCore/Strong.h> >+#include "JSValueInWrappedObject.h" > > namespace WebCore { > >@@ -39,25 +39,23 @@ class PromiseRejectionEvent final : public Event { > JSC::JSValue reason; > }; > >- static Ref<PromiseRejectionEvent> create(JSC::ExecState& state, const AtomicString& type, const Init& initializer, IsTrusted isTrusted = IsTrusted::No) >+ static Ref<PromiseRejectionEvent> create(const AtomicString& type, const Init& initializer, IsTrusted isTrusted = IsTrusted::No) > { >- return adoptRef(*new PromiseRejectionEvent(state, type, initializer, isTrusted)); >+ return adoptRef(*new PromiseRejectionEvent(type, initializer, isTrusted)); > } > > virtual ~PromiseRejectionEvent(); > > DOMPromise& promise() const { return m_promise.get(); } >- JSC::JSValue reason() const { return m_reason.get(); } >+ const JSValueInWrappedObject& reason() const { return m_reason; } > > EventInterface eventInterface() const override { return PromiseRejectionEventInterfaceType; } > > private: >- PromiseRejectionEvent(JSC::ExecState&, const AtomicString&, const Init&, IsTrusted); >+ PromiseRejectionEvent(const AtomicString&, const Init&, IsTrusted); > > Ref<DOMPromise> m_promise; >- // FIXME: The following use of JSC::Strong is incorrect and can lead to storage leaks >- // due to reference cycles; we should use JSValueInWrappedObject instead. >- JSC::Strong<JSC::Unknown> m_reason; >+ JSValueInWrappedObject m_reason; > }; > > } // namespace WebCore >diff --git a/Source/WebCore/dom/PromiseRejectionEvent.idl b/Source/WebCore/dom/PromiseRejectionEvent.idl >index 7a6f58fa45014248e9f505ab93f999eccf1148bf..5a20803ea2a1238cb96116e04db53620491c54bf 100644 >--- a/Source/WebCore/dom/PromiseRejectionEvent.idl >+++ b/Source/WebCore/dom/PromiseRejectionEvent.idl >@@ -25,8 +25,8 @@ > > [ > Constructor(DOMString type, PromiseRejectionEventInit eventInitDict), >- ConstructorCallWith=ScriptState, >- Exposed=(Window), >+ Exposed=(Window,Worker), >+ JSCustomMarkFunction, > ] interface PromiseRejectionEvent : Event { > readonly attribute Promise<any> promise; > readonly attribute any reason; >diff --git a/Source/WebCore/dom/RejectedPromiseTracker.cpp b/Source/WebCore/dom/RejectedPromiseTracker.cpp >index c66072a8bfc1c2b6177c1f848d1b975337628fff..ab77306f27f336c7e4e89ff8821e59713ce79805 100644 >--- a/Source/WebCore/dom/RejectedPromiseTracker.cpp >+++ b/Source/WebCore/dom/RejectedPromiseTracker.cpp >@@ -166,7 +166,7 @@ void RejectedPromiseTracker::reportUnhandledRejections(Vector<UnhandledPromise>& > initializer.promise = &domPromise; > initializer.reason = promise.result(vm); > >- auto event = PromiseRejectionEvent::create(state, eventNames().unhandledrejectionEvent, initializer); >+ auto event = PromiseRejectionEvent::create(eventNames().unhandledrejectionEvent, initializer); > auto target = m_context.errorEventTarget(); > target->dispatchEvent(event); > >@@ -188,14 +188,13 @@ void RejectedPromiseTracker::reportRejectionHandled(Ref<DOMPromise>&& rejectedPr > if (rejectedPromise->isSuspended()) > return; > >- auto& state = *rejectedPromise->globalObject()->globalExec(); > auto& promise = *rejectedPromise->promise(); > > PromiseRejectionEvent::Init initializer; > initializer.promise = rejectedPromise.ptr(); > initializer.reason = promise.result(vm); > >- auto event = PromiseRejectionEvent::create(state, eventNames().rejectionhandledEvent, initializer); >+ auto event = PromiseRejectionEvent::create(eventNames().rejectionhandledEvent, initializer); > auto target = m_context.errorEventTarget(); > target->dispatchEvent(event); > } >diff --git a/Source/WebCore/dom/ScriptExecutionContext.cpp b/Source/WebCore/dom/ScriptExecutionContext.cpp >index d8c44d870eec25f12e68c3448aada6666db11536..ca795c991ddec0a62725019187c221284c327f49 100644 >--- a/Source/WebCore/dom/ScriptExecutionContext.cpp >+++ b/Source/WebCore/dom/ScriptExecutionContext.cpp >@@ -497,6 +497,11 @@ RejectedPromiseTracker& ScriptExecutionContext::ensureRejectedPromiseTrackerSlow > return *m_rejectedPromiseTracker.get(); > } > >+void ScriptExecutionContext::removeRejectedPromiseTracker() >+{ >+ m_rejectedPromiseTracker = nullptr; >+} >+ > void ScriptExecutionContext::setDatabaseContext(DatabaseContext* databaseContext) > { > m_databaseContext = databaseContext; >diff --git a/Source/WebCore/dom/ScriptExecutionContext.h b/Source/WebCore/dom/ScriptExecutionContext.h >index 16b6c53cb13d8ea4765d7deb26847bc6ff0d192d..3bdfcc80dbe6e6adad5877d1fee301127376d563 100644 >--- a/Source/WebCore/dom/ScriptExecutionContext.h >+++ b/Source/WebCore/dom/ScriptExecutionContext.h >@@ -283,6 +283,7 @@ class ScriptExecutionContext : public SecurityContext { > > bool hasPendingActivity() const; > void removeFromContextsMap(); >+ void removeRejectedPromiseTracker(); > > private: > // The following addMessage function is deprecated. >diff --git a/Source/WebCore/html/HTMLAttributeNames.in b/Source/WebCore/html/HTMLAttributeNames.in >index 6e665047ed58574616e9bdc6f1c4ca1917f4e224..22b9569fd4e71698961d0ece8ad2b5ed21dad103 100644 >--- a/Source/WebCore/html/HTMLAttributeNames.in >+++ b/Source/WebCore/html/HTMLAttributeNames.in >@@ -270,6 +270,7 @@ onplaying > onpopstate > onprogress > onratechange >+onrejectionhandled > onreset > onresize > onscroll >@@ -296,6 +297,7 @@ ontransitioncancel > ontransitionend > ontransitionrun > ontransitionstart >+onunhandledrejection > onunload > onvolumechange > onwaiting >diff --git a/Source/WebCore/workers/WorkerGlobalScope.h b/Source/WebCore/workers/WorkerGlobalScope.h >index 68c34447702b1c32b64aaf218a2017a7c32a9114..c5db809cc507d9c01dc8906e0d6f551477f49879 100644 >--- a/Source/WebCore/workers/WorkerGlobalScope.h >+++ b/Source/WebCore/workers/WorkerGlobalScope.h >@@ -121,6 +121,8 @@ class WorkerGlobalScope : public RefCounted<WorkerGlobalScope>, public Supplemen > > void removeMicrotaskQueue(); > >+ using ScriptExecutionContext::removeRejectedPromiseTracker; >+ > void createImageBitmap(ImageBitmap::Source&&, ImageBitmapOptions&&, ImageBitmap::Promise&&); > void createImageBitmap(ImageBitmap::Source&&, int sx, int sy, int sw, int sh, ImageBitmapOptions&&, ImageBitmap::Promise&&); > >diff --git a/Source/WebCore/workers/WorkerGlobalScope.idl b/Source/WebCore/workers/WorkerGlobalScope.idl >index cf2ac6bf78856aa472132a1251aa80f1a9675e9d..cc1f1f3dac88bca47fd37f0c1838b988f5b4db9b 100644 >--- a/Source/WebCore/workers/WorkerGlobalScope.idl >+++ b/Source/WebCore/workers/WorkerGlobalScope.idl >@@ -39,6 +39,8 @@ > attribute EventHandler onerror; > attribute EventHandler onoffline; > attribute EventHandler ononline; >+ attribute EventHandler onrejectionhandled; >+ attribute EventHandler onunhandledrejection; > > // WorkerUtils > >diff --git a/Source/WebCore/workers/WorkerThread.cpp b/Source/WebCore/workers/WorkerThread.cpp >index 533d11af64aa977103dc95e8aab0f27c4129f1dd..e3971911f7f694a8cfcbc343f5479f7b8a0d1ce3 100644 >--- a/Source/WebCore/workers/WorkerThread.cpp >+++ b/Source/WebCore/workers/WorkerThread.cpp >@@ -299,8 +299,9 @@ void WorkerThread::stop(WTF::Function<void()>&& stoppedCallback) > // which become dangling once Heap is destroyed. > workerGlobalScope.removeAllEventListeners(); > >- // MicrotaskQueue references Heap. >+ // MicrotaskQueue and RejectedPromiseTracker reference Heap. > workerGlobalScope.removeMicrotaskQueue(); >+ workerGlobalScope.removeRejectedPromiseTracker(); > > // Stick a shutdown command at the end of the queue, so that we deal > // with all the cleanup tasks the databases post first. >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index a0213e0ab15815a9c561fdf087d6da8933e44677..835266c2dab9a06f0e59bf7c952c72cea63af9f6 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,46 @@ >+2018-08-12 Yusuke Suzuki <yusukesuzuki@slowstart.org> >+ >+ Worker should support unhandled promise rejections >+ https://bugs.webkit.org/show_bug.cgi?id=188265 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * fast/dom/reference-cycle-leaks-expected.txt: >+ * http/wpt/workers/promise-unhandled-rejection.any-expected.txt: Added. >+ * http/wpt/workers/promise-unhandled-rejection.any.html: Added. >+ * http/wpt/workers/promise-unhandled-rejection.any.js: Added. >+ (promise_test): >+ * http/wpt/workers/promise-unhandled-rejection.any.worker-expected.txt: Added. >+ * http/wpt/workers/promise-unhandled-rejection.any.worker.html: Added. >+ * js/dom/unhandled-promise-rejection-basic-in-workers-expected.txt: Added. >+ * js/dom/unhandled-promise-rejection-basic-in-workers.html: Added. >+ * js/dom/unhandled-promise-rejection-bindings-type-error-in-workers-expected.txt: Added. >+ * js/dom/unhandled-promise-rejection-bindings-type-error-in-workers.html: Added. >+ * js/dom/unhandled-promise-rejection-handle-during-event-in-workers-expected.txt: Added. >+ * js/dom/unhandled-promise-rejection-handle-during-event-in-workers.html: Added. >+ * js/dom/unhandled-promise-rejection-handle-in-handler-in-workers-expected.txt: Added. >+ * js/dom/unhandled-promise-rejection-handle-in-handler-in-workers.html: Added. >+ * js/dom/unhandled-promise-rejection-handle-in-workers-expected.txt: Added. >+ * js/dom/unhandled-promise-rejection-handle-in-workers.html: Added. >+ * js/dom/unhandled-promise-rejection-order-in-workers-expected.txt: Added. >+ * js/dom/unhandled-promise-rejection-order-in-workers.html: Added. >+ * js/resources/unhandled-promise-rejection-basic-in-workers.js: Added. >+ (global.onunhandledrejection): >+ * js/resources/unhandled-promise-rejection-bindings-type-error-in-workers.js: Added. >+ (global.onunhandledrejection): >+ (catch): >+ (setTimeout): >+ * js/resources/unhandled-promise-rejection-handle-during-event-in-workers.js: Added. >+ (global.onunhandledrejection): >+ * js/resources/unhandled-promise-rejection-handle-in-handler-in-workers.js: Added. >+ (global.onunhandledrejection): >+ (global.onrejectionhandled): >+ * js/resources/unhandled-promise-rejection-handle-in-workers.js: Added. >+ (global.onunhandledrejection): >+ (global.onrejectionhandled): >+ * js/resources/unhandled-promise-rejection-order-in-workers.js: Added. >+ (global.onunhandledrejection): >+ > 2018-08-12 Yusuke Suzuki <yusukesuzuki@slowstart.org> > > Break reference cycle in ErrorEvent by using JSValueInWrappedObject >diff --git a/LayoutTests/imported/w3c/ChangeLog b/LayoutTests/imported/w3c/ChangeLog >index cb3cafc97e2609826c46fd97b1263f5687eb7ae7..aea467ad8821c63535dfd856c76ac8240f3f0759 100644 >--- a/LayoutTests/imported/w3c/ChangeLog >+++ b/LayoutTests/imported/w3c/ChangeLog >@@ -1,3 +1,17 @@ >+2018-08-12 Yusuke Suzuki <yusukesuzuki@slowstart.org> >+ >+ Worker should support unhandled promise rejections >+ https://bugs.webkit.org/show_bug.cgi?id=188265 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * web-platform-tests/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.worker-expected.txt: >+ * web-platform-tests/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.worker-expected.txt: >+ * web-platform-tests/streams/readable-streams/tee.dedicatedworker-expected.txt: >+ * web-platform-tests/streams/readable-streams/tee.serviceworker.https-expected.txt: >+ * web-platform-tests/workers/interfaces.worker-expected.txt: >+ * web-platform-tests/workers/semantics/interface-objects/001.worker-expected.txt: >+ > 2018-08-10 Ali Juma <ajuma@chromium.org> > > [IntersectionObserver] Implement rootMargin parsing >diff --git a/LayoutTests/fast/dom/reference-cycle-leaks-expected.txt b/LayoutTests/fast/dom/reference-cycle-leaks-expected.txt >index aa337a075e2b88707cc3aa1608cfdbc6f14ffc5a..56a0c280bcfbb4f64428c881324dcf002568db41 100644 >--- a/LayoutTests/fast/dom/reference-cycle-leaks-expected.txt >+++ b/LayoutTests/fast/dom/reference-cycle-leaks-expected.txt >@@ -16,7 +16,7 @@ PASS checkForNodeLeaks(createMessageEventDataCycle) is "did not leak" > PASS checkForNodeLeaks(createPopStateEventStateCycle) is "did not leak" > FAIL checkForNodeLeaks(createPromiseRejectionEventPromiseCycle) should be did not leak. Was leaked. > PASS checkForNodeLeaks(createPromiseRejectionEventPromiseFunctionCycle) is "did not leak" >-FAIL checkForNodeLeaks(createPromiseRejectionEventReasonCycle) should be did not leak. Was leaked. >+PASS checkForNodeLeaks(createPromiseRejectionEventReasonCycle) is "did not leak" > PASS successfullyParsed is true > Some tests failed. > >diff --git a/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any-expected.txt b/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..72ca812adb827953634d612005fd3c9b81c5e3b7 >--- /dev/null >+++ b/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any-expected.txt >@@ -0,0 +1,6 @@ >+CONSOLE MESSAGE: Unhandled Promise Rejection: Reject >+ >+Harness Error (FAIL), message = undefined >+ >+PASS UnhaneldRejection event occurs if a rejected promise is not handled. >+ >diff --git a/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any.html b/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any.html >new file mode 100644 >index 0000000000000000000000000000000000000000..2382913528e693b3a5d56c660a45060980b548c3 >--- /dev/null >+++ b/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any.html >@@ -0,0 +1 @@ >+<!-- This file is required for WebKit test infrastructure to run the templated test --> >\ No newline at end of file >diff --git a/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any.js b/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any.js >new file mode 100644 >index 0000000000000000000000000000000000000000..fcb12bcad0b20d69958cb726f4179f5adb477e8a >--- /dev/null >+++ b/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any.js >@@ -0,0 +1,14 @@ >+promise_test(() => { >+ return new Promise(resolve => { >+ var promise = null; >+ self.addEventListener('unhandledrejection', ev => { >+ assert_equals(ev.type, "unhandledrejection"); >+ assert_equals(ev.cancelable, true); >+ assert_equals(ev.promise, promise); >+ assert_equals(ev.reason, "Reject"); >+ resolve(); >+ return false; >+ }, false); >+ promise = Promise.reject("Reject"); >+ }); >+}, "UnhaneldRejection event occurs if a rejected promise is not handled."); >diff --git a/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any.worker-expected.txt b/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any.worker-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..7c35d198bc4797fa00d6f8a614808438f7972dc6 >--- /dev/null >+++ b/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any.worker-expected.txt >@@ -0,0 +1,7 @@ >+CONSOLE MESSAGE: line 1774: TypeError: null is not an object (evaluating 'this.message_target.removeEventListener') >+CONSOLE MESSAGE: Unhandled Promise Rejection: Reject >+ >+Harness Error (FAIL), message = undefined >+ >+PASS UnhaneldRejection event occurs if a rejected promise is not handled. >+ >diff --git a/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any.worker.html b/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any.worker.html >new file mode 100644 >index 0000000000000000000000000000000000000000..2382913528e693b3a5d56c660a45060980b548c3 >--- /dev/null >+++ b/LayoutTests/http/wpt/workers/promise-unhandled-rejection.any.worker.html >@@ -0,0 +1 @@ >+<!-- This file is required for WebKit test infrastructure to run the templated test --> >\ No newline at end of file >diff --git a/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.worker-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.worker-expected.txt >index 8928f775e8fba8bbf959d0faddd22e4c1dcb3a5f..b3f3549c81bbf6283aaae77cb96dad847129af85 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.worker-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/derive_bits_keys/ecdh_bits.https.worker-expected.txt >@@ -1,4 +1,5 @@ >+CONSOLE MESSAGE: line 1774: TypeError: null is not an object (evaluating 'this.message_target.removeEventListener') >+CONSOLE MESSAGE: line 198: Unhandled Promise Rejection: DataError: Data provided to an operation does not meet requirements > >-Harness Error (TIMEOUT), message = null >- >+FAIL Untitled Data provided to an operation does not meet requirements > >diff --git a/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.worker-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.worker-expected.txt >index 8928f775e8fba8bbf959d0faddd22e4c1dcb3a5f..69c1f0a77ead9fa683e3af21d9513b2819829df1 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.worker-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/derive_bits_keys/ecdh_keys.https.worker-expected.txt >@@ -1,4 +1,5 @@ >+CONSOLE MESSAGE: line 1774: TypeError: null is not an object (evaluating 'this.message_target.removeEventListener') >+CONSOLE MESSAGE: line 167: Unhandled Promise Rejection: DataError: Data provided to an operation does not meet requirements > >-Harness Error (TIMEOUT), message = null >- >+FAIL Untitled Data provided to an operation does not meet requirements > >diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams/readable-streams/tee.dedicatedworker-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams/readable-streams/tee.dedicatedworker-expected.txt >index e03a5c2183c845526d1b0b2f9a7ea433981d3d5d..0563a2ed1b6d4b17779de5d87d549826f9db8980 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/streams/readable-streams/tee.dedicatedworker-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/streams/readable-streams/tee.dedicatedworker-expected.txt >@@ -1,3 +1,11 @@ >+CONSOLE MESSAGE: line 1774: TypeError: null is not an object (evaluating 'this.message_target.removeEventListener') >+CONSOLE MESSAGE: Unhandled Promise Rejection: [object Object] >+CONSOLE MESSAGE: line 1774: TypeError: null is not an object (evaluating 'this.message_target.removeEventListener') >+CONSOLE MESSAGE: Unhandled Promise Rejection: [object Object] >+CONSOLE MESSAGE: line 1774: TypeError: null is not an object (evaluating 'this.message_target.removeEventListener') >+CONSOLE MESSAGE: Unhandled Promise Rejection: [object Object] >+CONSOLE MESSAGE: line 1774: TypeError: null is not an object (evaluating 'this.message_target.removeEventListener') >+CONSOLE MESSAGE: Unhandled Promise Rejection: [object Object] > > PASS ReadableStream teeing: rs.tee() returns an array of two ReadableStreams > PASS ReadableStream teeing: should be able to read one branch to the end without affecting the other >diff --git a/LayoutTests/imported/w3c/web-platform-tests/streams/readable-streams/tee.serviceworker.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/streams/readable-streams/tee.serviceworker.https-expected.txt >index 2d1997c492057901f35117000d710516e30905e1..5842579d3e614b3d2f17e2f98faed230f942c145 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/streams/readable-streams/tee.serviceworker.https-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/streams/readable-streams/tee.serviceworker.https-expected.txt >@@ -1,4 +1,6 @@ > >+Harness Error (FAIL), message = undefined >+ > PASS Service worker test setup > PASS ReadableStream teeing: rs.tee() returns an array of two ReadableStreams > PASS ReadableStream teeing: should be able to read one branch to the end without affecting the other >diff --git a/LayoutTests/imported/w3c/web-platform-tests/workers/interfaces.worker-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/workers/interfaces.worker-expected.txt >index 121804582b83adfac6b0b1e8ff4ebb02bc87d500..1204a8412511799e6527bc97e37655f63b582ecb 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/workers/interfaces.worker-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/workers/interfaces.worker-expected.txt >@@ -34,9 +34,9 @@ PASS WorkerGlobalScope interface: attribute onoffline > PASS Unscopable handled correctly for onoffline property on WorkerGlobalScope > PASS WorkerGlobalScope interface: attribute ononline > PASS Unscopable handled correctly for ononline property on WorkerGlobalScope >-FAIL WorkerGlobalScope interface: attribute onrejectionhandled assert_true: The prototype object must have a property "onrejectionhandled" expected true got false >+PASS WorkerGlobalScope interface: attribute onrejectionhandled > PASS Unscopable handled correctly for onrejectionhandled property on WorkerGlobalScope >-FAIL WorkerGlobalScope interface: attribute onunhandledrejection assert_true: The prototype object must have a property "onunhandledrejection" expected true got false >+PASS WorkerGlobalScope interface: attribute onunhandledrejection > PASS Unscopable handled correctly for onunhandledrejection property on WorkerGlobalScope > PASS WorkerGlobalScope interface: attribute origin > PASS Unscopable handled correctly for origin property on WorkerGlobalScope >@@ -101,8 +101,8 @@ PASS WorkerGlobalScope interface: self must inherit property "onerror" with the > FAIL WorkerGlobalScope interface: self must inherit property "onlanguagechange" with the proper type assert_inherits: property "onlanguagechange" not found in prototype chain > PASS WorkerGlobalScope interface: self must inherit property "onoffline" with the proper type > PASS WorkerGlobalScope interface: self must inherit property "ononline" with the proper type >-FAIL WorkerGlobalScope interface: self must inherit property "onrejectionhandled" with the proper type assert_inherits: property "onrejectionhandled" not found in prototype chain >-FAIL WorkerGlobalScope interface: self must inherit property "onunhandledrejection" with the proper type assert_inherits: property "onunhandledrejection" not found in prototype chain >+PASS WorkerGlobalScope interface: self must inherit property "onrejectionhandled" with the proper type >+PASS WorkerGlobalScope interface: self must inherit property "onunhandledrejection" with the proper type > PASS WorkerGlobalScope interface: self must inherit property "origin" with the proper type > PASS WorkerGlobalScope interface: self must inherit property "btoa(DOMString)" with the proper type > PASS WorkerGlobalScope interface: calling btoa(DOMString) on self with too few arguments must throw TypeError >diff --git a/LayoutTests/imported/w3c/web-platform-tests/workers/semantics/interface-objects/001.worker-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/workers/semantics/interface-objects/001.worker-expected.txt >index 57e385273e0a5257f077e5b8fff538223ac6a088..706ac76327700ea22852e13908cc2990b68e1ea0 100644 >--- a/LayoutTests/imported/w3c/web-platform-tests/workers/semantics/interface-objects/001.worker-expected.txt >+++ b/LayoutTests/imported/w3c/web-platform-tests/workers/semantics/interface-objects/001.worker-expected.txt >@@ -12,7 +12,7 @@ PASS The ImageData interface object should be exposed. > PASS The ImageBitmap interface object should be exposed. > FAIL The CanvasPath interface object should be exposed. assert_own_property: expected property "CanvasPath" missing > PASS The Path2D interface object should be exposed. >-FAIL The PromiseRejectionEvent interface object should be exposed. assert_own_property: expected property "PromiseRejectionEvent" missing >+PASS The PromiseRejectionEvent interface object should be exposed. > PASS The EventSource interface object should be exposed. > PASS The WebSocket interface object should be exposed. > FAIL The CloseEvent interface object should be exposed. assert_own_property: expected property "CloseEvent" missing >diff --git a/LayoutTests/js/dom/unhandled-promise-rejection-basic-in-workers-expected.txt b/LayoutTests/js/dom/unhandled-promise-rejection-basic-in-workers-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..be3bb2427c5f49882e43f2e418b466bee7f42c77 >--- /dev/null >+++ b/LayoutTests/js/dom/unhandled-promise-rejection-basic-in-workers-expected.txt >@@ -0,0 +1,13 @@ >+[Worker] Test unhandled promise rejection event. >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+Starting worker: ../resources/unhandled-promise-rejection-basic-in-workers.js >+PASS [Worker] error.type is "unhandledrejection" >+PASS [Worker] error.cancelable is true >+PASS [Worker] error.promise is promise >+PASS [Worker] error.reason is "ERROR" >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >diff --git a/LayoutTests/js/dom/unhandled-promise-rejection-basic-in-workers.html b/LayoutTests/js/dom/unhandled-promise-rejection-basic-in-workers.html >new file mode 100644 >index 0000000000000000000000000000000000000000..74f60b4d8bedfe75ff44110643a9d22b6a09efa0 >--- /dev/null >+++ b/LayoutTests/js/dom/unhandled-promise-rejection-basic-in-workers.html >@@ -0,0 +1,14 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../../resources/js-test-pre.js"></script> >+</head> >+<body> >+<div id="description"></div> >+<div id="console"></div> >+<script> >+worker = startWorker('../resources/unhandled-promise-rejection-basic-in-workers.js'); >+</script> >+<script src="../../resources/js-test-post.js"></script> >+</body> >+</html> >diff --git a/LayoutTests/js/dom/unhandled-promise-rejection-bindings-type-error-in-workers-expected.txt b/LayoutTests/js/dom/unhandled-promise-rejection-bindings-type-error-in-workers-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..47c48bbe68b6e2e1d69dfca8503e88e6ddc820ba >--- /dev/null >+++ b/LayoutTests/js/dom/unhandled-promise-rejection-bindings-type-error-in-workers-expected.txt >@@ -0,0 +1,12 @@ >+[Worker] Test rejected promises are returned from bindings and trigger unhandledrejection. >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+Starting worker: ../resources/unhandled-promise-rejection-bindings-type-error-in-workers.js >+PASS [Worker] error.promise is promise >+PASS [Worker] error.reason instanceof TypeError is true >+Got error from worker: Unhandled Promise Rejection: TypeError: The PromiseRejectionEvent.promise getter can only be used on instances of PromiseRejectionEvent >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >diff --git a/LayoutTests/js/dom/unhandled-promise-rejection-bindings-type-error-in-workers.html b/LayoutTests/js/dom/unhandled-promise-rejection-bindings-type-error-in-workers.html >new file mode 100644 >index 0000000000000000000000000000000000000000..82ca646b3095a573cfcb0e017be59665d53cf5f8 >--- /dev/null >+++ b/LayoutTests/js/dom/unhandled-promise-rejection-bindings-type-error-in-workers.html >@@ -0,0 +1,14 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../../resources/js-test-pre.js"></script> >+</head> >+<body> >+<div id="description"></div> >+<div id="console"></div> >+<script> >+worker = startWorker('../resources/unhandled-promise-rejection-bindings-type-error-in-workers.js'); >+</script> >+<script src="../../resources/js-test-post.js"></script> >+</body> >+</html> >diff --git a/LayoutTests/js/dom/unhandled-promise-rejection-handle-during-event-in-workers-expected.txt b/LayoutTests/js/dom/unhandled-promise-rejection-handle-during-event-in-workers-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..6ba3b142f7fc62aa4f1c182458d12b72760ea5f1 >--- /dev/null >+++ b/LayoutTests/js/dom/unhandled-promise-rejection-handle-during-event-in-workers-expected.txt >@@ -0,0 +1,18 @@ >+[Worker] Test unhandled promise rejection event. >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+Starting worker: ../resources/unhandled-promise-rejection-handle-during-event-in-workers.js >+[Worker] global.promise[0] = Promise.reject(0); >+[Worker] global.promise[1] = Promise.reject(1); >+[Worker] global.promise[2] = Promise.reject(2); >+PASS [Worker] error.type is "unhandledrejection" >+PASS [Worker] error.cancelable is true >+PASS [Worker] error.promise is promise[0] >+PASS [Worker] error.reason is 0 >+[Worker] global.promise[1].catch(function () { }); >+[Worker] global.promise[2].catch(function () { }); >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >diff --git a/LayoutTests/js/dom/unhandled-promise-rejection-handle-during-event-in-workers.html b/LayoutTests/js/dom/unhandled-promise-rejection-handle-during-event-in-workers.html >new file mode 100644 >index 0000000000000000000000000000000000000000..eac427ef7e2afbfe625766275d9d23e59a0f8463 >--- /dev/null >+++ b/LayoutTests/js/dom/unhandled-promise-rejection-handle-during-event-in-workers.html >@@ -0,0 +1,14 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../../resources/js-test-pre.js"></script> >+</head> >+<body> >+<div id="description"></div> >+<div id="console"></div> >+<script> >+worker = startWorker('../resources/unhandled-promise-rejection-handle-during-event-in-workers.js'); >+</script> >+<script src="../../resources/js-test-post.js"></script> >+</body> >+</html> >diff --git a/LayoutTests/js/dom/unhandled-promise-rejection-handle-in-handler-in-workers-expected.txt b/LayoutTests/js/dom/unhandled-promise-rejection-handle-in-handler-in-workers-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..44f181e89cab56ef71e93051fb2aca5308184888 >--- /dev/null >+++ b/LayoutTests/js/dom/unhandled-promise-rejection-handle-in-handler-in-workers-expected.txt >@@ -0,0 +1,14 @@ >+[Worker] Test rejection handled event. >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+Starting worker: ../resources/unhandled-promise-rejection-handle-in-handler-in-workers.js >+PASS [Worker] error.type is "unhandledrejection" >+PASS [Worker] error.cancelable is true >+PASS [Worker] error.promise is promise >+PASS [Worker] error.reason is "ERROR" >+PASS [Worker] reason is "ERROR" >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >diff --git a/LayoutTests/js/dom/unhandled-promise-rejection-handle-in-handler-in-workers.html b/LayoutTests/js/dom/unhandled-promise-rejection-handle-in-handler-in-workers.html >new file mode 100644 >index 0000000000000000000000000000000000000000..f07b227adf3358e611f52fd17dd1545ac41d6ddb >--- /dev/null >+++ b/LayoutTests/js/dom/unhandled-promise-rejection-handle-in-handler-in-workers.html >@@ -0,0 +1,14 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../../resources/js-test-pre.js"></script> >+</head> >+<body> >+<div id="description"></div> >+<div id="console"></div> >+<script> >+worker = startWorker('../resources/unhandled-promise-rejection-handle-in-handler-in-workers.js'); >+</script> >+<script src="../../resources/js-test-post.js"></script> >+</body> >+</html> >diff --git a/LayoutTests/js/dom/unhandled-promise-rejection-handle-in-workers-expected.txt b/LayoutTests/js/dom/unhandled-promise-rejection-handle-in-workers-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..83f13290443d375a57f21ae92078cfa90723951e >--- /dev/null >+++ b/LayoutTests/js/dom/unhandled-promise-rejection-handle-in-workers-expected.txt >@@ -0,0 +1,18 @@ >+[Worker] Test rejection handled event. >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+Starting worker: ../resources/unhandled-promise-rejection-handle-in-workers.js >+PASS [Worker] error.type is "unhandledrejection" >+PASS [Worker] error.cancelable is true >+PASS [Worker] error.promise is promise >+PASS [Worker] error.reason is "ERROR" >+PASS [Worker] reason is "ERROR" >+PASS [Worker] handled.type is "rejectionhandled" >+PASS [Worker] handled.cancelable is false >+PASS [Worker] handled.promise is promise >+PASS [Worker] handled.reason is "ERROR" >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >diff --git a/LayoutTests/js/dom/unhandled-promise-rejection-handle-in-workers.html b/LayoutTests/js/dom/unhandled-promise-rejection-handle-in-workers.html >new file mode 100644 >index 0000000000000000000000000000000000000000..b25e0966e4c1d00556ab8ab8a54253bb4f174e60 >--- /dev/null >+++ b/LayoutTests/js/dom/unhandled-promise-rejection-handle-in-workers.html >@@ -0,0 +1,14 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../../resources/js-test-pre.js"></script> >+</head> >+<body> >+<div id="description"></div> >+<div id="console"></div> >+<script> >+worker = startWorker('../resources/unhandled-promise-rejection-handle-in-workers.js'); >+</script> >+<script src="../../resources/js-test-post.js"></script> >+</body> >+</html> >diff --git a/LayoutTests/js/dom/unhandled-promise-rejection-order-in-workers-expected.txt b/LayoutTests/js/dom/unhandled-promise-rejection-order-in-workers-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..72d708070c39dfcefe92b7b9cb3a672615fc9995 >--- /dev/null >+++ b/LayoutTests/js/dom/unhandled-promise-rejection-order-in-workers-expected.txt >@@ -0,0 +1,21 @@ >+[Worker] Test unhandled promise rejection event. >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+Starting worker: ../resources/unhandled-promise-rejection-order-in-workers.js >+PASS [Worker] error.type is "unhandledrejection" >+PASS [Worker] error.cancelable is true >+PASS [Worker] error.promise is promise[0] >+PASS [Worker] error.reason is 0 >+PASS [Worker] error.type is "unhandledrejection" >+PASS [Worker] error.cancelable is true >+PASS [Worker] error.promise is promise[1] >+PASS [Worker] error.reason is 1 >+PASS [Worker] error.type is "unhandledrejection" >+PASS [Worker] error.cancelable is true >+PASS [Worker] error.promise is promise[2] >+PASS [Worker] error.reason is 2 >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >diff --git a/LayoutTests/js/dom/unhandled-promise-rejection-order-in-workers.html b/LayoutTests/js/dom/unhandled-promise-rejection-order-in-workers.html >new file mode 100644 >index 0000000000000000000000000000000000000000..5a98c63df260a0c00542a4f01e68418ef1d17c98 >--- /dev/null >+++ b/LayoutTests/js/dom/unhandled-promise-rejection-order-in-workers.html >@@ -0,0 +1,14 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../../resources/js-test-pre.js"></script> >+</head> >+<body> >+<div id="description"></div> >+<div id="console"></div> >+<script> >+worker = startWorker('../resources/unhandled-promise-rejection-order-in-workers.js'); >+</script> >+<script src="../../resources/js-test-post.js"></script> >+</body> >+</html> >diff --git a/LayoutTests/js/resources/unhandled-promise-rejection-basic-in-workers.js b/LayoutTests/js/resources/unhandled-promise-rejection-basic-in-workers.js >new file mode 100644 >index 0000000000000000000000000000000000000000..79d431506d6145e35bd9e834bc86772097905c68 >--- /dev/null >+++ b/LayoutTests/js/resources/unhandled-promise-rejection-basic-in-workers.js >@@ -0,0 +1,20 @@ >+importScripts('../../resources/js-test-pre.js'); >+ >+description('Test unhandled promise rejection event.'); >+ >+var global = this; >+global.jsTestIsAsync = true; >+ >+global.error = null; >+global.promise = null; >+global.onunhandledrejection = function (e) { >+ error = e; >+ shouldBe(`error.type`, `"unhandledrejection"`); >+ shouldBe(`error.cancelable`, `true`); >+ shouldBe(`error.promise`, `promise`); >+ shouldBe(`error.reason`, `"ERROR"`); >+ finishJSTest(); >+ return false; >+}; >+ >+global.promise = Promise.reject("ERROR"); >diff --git a/LayoutTests/js/resources/unhandled-promise-rejection-bindings-type-error-in-workers.js b/LayoutTests/js/resources/unhandled-promise-rejection-bindings-type-error-in-workers.js >new file mode 100644 >index 0000000000000000000000000000000000000000..063eaa4784f853e80dee49c1775a9597ae9b9859 >--- /dev/null >+++ b/LayoutTests/js/resources/unhandled-promise-rejection-bindings-type-error-in-workers.js >@@ -0,0 +1,22 @@ >+importScripts('../../resources/js-test-pre.js'); >+ >+description('Test rejected promises are returned from bindings and trigger unhandledrejection.'); >+ >+var global = this; >+global.jsTestIsAsync = true; >+ >+global.error = null; >+global.promise = null; >+global.onunhandledrejection = function (e) { >+ error = e; >+ shouldBe(`error.promise`, `promise`); >+ shouldBeTrue(`error.reason instanceof TypeError`); >+}; >+ >+try { >+ promise = PromiseRejectionEvent.prototype.promise; >+} catch (e) { >+ testFailed("TypeErrors produced by getters for Promise results should be wrapped in a Promise"); >+} >+ >+setTimeout(function () { finishJSTest(); }, 100); >diff --git a/LayoutTests/js/resources/unhandled-promise-rejection-handle-during-event-in-workers.js b/LayoutTests/js/resources/unhandled-promise-rejection-handle-during-event-in-workers.js >new file mode 100644 >index 0000000000000000000000000000000000000000..3f4c3e4fe9a13ff10d4ebbcba20130d3fdbac083 >--- /dev/null >+++ b/LayoutTests/js/resources/unhandled-promise-rejection-handle-during-event-in-workers.js >@@ -0,0 +1,25 @@ >+importScripts('../../resources/js-test-pre.js'); >+ >+description('Test unhandled promise rejection event.'); >+ >+var global = this; >+global.jsTestIsAsync = true; >+ >+global.error = null; >+global.promise = []; >+global.onunhandledrejection = function (e) { >+ error = e; >+ >+ shouldBe(`error.type`, `"unhandledrejection"`); >+ shouldBe(`error.cancelable`, `true`); >+ shouldBe(`error.promise`, `promise[0]`); >+ shouldBe(`error.reason`, `0`); >+ >+ evalAndLog(`global.promise[1].catch(function () { });`); >+ evalAndLog(`global.promise[2].catch(function () { });`); >+ setTimeout(function () { finishJSTest(); }, 100); >+ return false; >+}; >+ >+for (let i = 0; i < 3; ++i) >+ evalAndLog(`global.promise[${i}] = Promise.reject(${i});`); >diff --git a/LayoutTests/js/resources/unhandled-promise-rejection-handle-in-handler-in-workers.js b/LayoutTests/js/resources/unhandled-promise-rejection-handle-in-handler-in-workers.js >new file mode 100644 >index 0000000000000000000000000000000000000000..28be6e9a768a96f1ae134033c28c13cba68ba793 >--- /dev/null >+++ b/LayoutTests/js/resources/unhandled-promise-rejection-handle-in-handler-in-workers.js >@@ -0,0 +1,33 @@ >+importScripts('../../resources/js-test-pre.js'); >+ >+description('Test rejection handled event.'); >+ >+var global = this; >+global.jsTestIsAsync = true; >+ >+global.error = null; >+global.promise = null; >+global.reason = null; >+ >+global.onunhandledrejection = function (e) { >+ error = e; >+ shouldBe(`error.type`, `"unhandledrejection"`); >+ shouldBe(`error.cancelable`, `true`); >+ shouldBe(`error.promise`, `promise`); >+ shouldBe(`error.reason`, `"ERROR"`); >+ promise.catch(function (r) { >+ global.reason = r; >+ shouldBe(`reason`, `"ERROR"`); >+ }); >+ >+ setTimeout(function () { >+ finishJSTest(); >+ }, 100); >+ return false; >+}; >+ >+global.onrejectionhandled = function (e) { >+ testFailed(`rejectionhandled is fired.`); >+}; >+ >+global.promise = Promise.reject("ERROR"); >diff --git a/LayoutTests/js/resources/unhandled-promise-rejection-handle-in-workers.js b/LayoutTests/js/resources/unhandled-promise-rejection-handle-in-workers.js >new file mode 100644 >index 0000000000000000000000000000000000000000..28097de57ebe95821b9c4f4e018bebad917f8995 >--- /dev/null >+++ b/LayoutTests/js/resources/unhandled-promise-rejection-handle-in-workers.js >@@ -0,0 +1,37 @@ >+importScripts('../../resources/js-test-pre.js'); >+ >+description('Test rejection handled event.'); >+ >+var global = this; >+global.jsTestIsAsync = true; >+ >+global.error = null; >+global.handled = null; >+global.promise = null; >+global.reason = null; >+ >+global.onunhandledrejection = function (e) { >+ error = e; >+ shouldBe(`error.type`, `"unhandledrejection"`); >+ shouldBe(`error.cancelable`, `true`); >+ shouldBe(`error.promise`, `promise`); >+ shouldBe(`error.reason`, `"ERROR"`); >+ setTimeout(function () { >+ promise.catch(function (r) { >+ global.reason = r; >+ shouldBe(`reason`, `"ERROR"`); >+ }); >+ }, 0); >+ return false; >+}; >+ >+global.onrejectionhandled = function (e) { >+ global.handled = e; >+ shouldBe(`handled.type`, `"rejectionhandled"`); >+ shouldBe(`handled.cancelable`, `false`); >+ shouldBe(`handled.promise`, `promise`); >+ shouldBe(`handled.reason`, `"ERROR"`); >+ finishJSTest(); >+}; >+ >+global.promise = Promise.reject("ERROR"); >diff --git a/LayoutTests/js/resources/unhandled-promise-rejection-order-in-workers.js b/LayoutTests/js/resources/unhandled-promise-rejection-order-in-workers.js >new file mode 100644 >index 0000000000000000000000000000000000000000..771365d6d7ce1f9d6496206dc0b2cb3cc0c8f463 >--- /dev/null >+++ b/LayoutTests/js/resources/unhandled-promise-rejection-order-in-workers.js >@@ -0,0 +1,27 @@ >+importScripts('../../resources/js-test-pre.js'); >+ >+description('Test unhandled promise rejection event.'); >+ >+var global = this; >+global.jsTestIsAsync = true; >+ >+global.error = null; >+global.promise = []; >+global.count = 0; >+global.index = 0; >+global.onunhandledrejection = function (e) { >+ error = e; >+ index = count++; >+ >+ shouldBe(`error.type`, `"unhandledrejection"`); >+ shouldBe(`error.cancelable`, `true`); >+ shouldBe(`error.promise`, `promise[${index}]`); >+ shouldBe(`error.reason`, `${index}`); >+ >+ if (count === 3) >+ finishJSTest(); >+ return false; >+}; >+ >+for (let i = 0; i < 3; ++i) >+ global.promise[i] = Promise.reject(i);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
darin
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 188265
:
346718
|
346719
|
346720
|
346721
|
346970
|
346971
|
346972
|
346973
|
346975
|
346976
|
346977
|
346980
|
346982
|
346983
|
346985
|
346986
| 346992