Upgrade AbortSignal & AbortController to latest from WebKit (#10106)

Fixes https://github.com/oven-sh/bun/issues/9977
Closes https://github.com/oven-sh/bun/pull/10086

Thank you @lithdew for investigating and most of the fixes. This adds more of the changes we missed from WebKit into Bun like the ability to follow other signals

Co-authored-by: Kenta Iwasaki <63115601+lithdew@users.noreply.github.com>
This commit is contained in:
Jarred Sumner
2024-04-09 00:49:13 -07:00
committed by GitHub
parent 0dc0919119
commit df49a5a8e4
19 changed files with 399 additions and 184 deletions

View File

@@ -26,6 +26,8 @@
#pragma once
#include "Node.h"
namespace WebCore {
class WebCoreOpaqueRoot {
@@ -38,48 +40,28 @@ public:
WebCoreOpaqueRoot(std::nullptr_t) {}
bool isNode() const { return false; }
void* pointer() const { return m_pointer; }
private:
void* m_pointer { nullptr };
bool m_isNode { false };
};
template<typename Visitor>
ALWAYS_INLINE void addWebCoreOpaqueRoot(Visitor& visitor, WebCoreOpaqueRoot root)
{
visitor.addOpaqueRoot(root.pointer());
}
inline void addWebCoreOpaqueRoot(Visitor&, WebCoreOpaqueRoot);
template<typename Visitor, typename ImplType>
ALWAYS_INLINE void addWebCoreOpaqueRoot(Visitor& visitor, ImplType* impl)
{
addWebCoreOpaqueRoot(visitor, root(impl));
}
inline void addWebCoreOpaqueRoot(Visitor&, ImplType*);
template<typename Visitor, typename ImplType>
ALWAYS_INLINE void addWebCoreOpaqueRoot(Visitor& visitor, ImplType& impl)
{
addWebCoreOpaqueRoot(visitor, root(&impl));
}
inline void addWebCoreOpaqueRoot(Visitor&, ImplType&);
template<typename Visitor>
ALWAYS_INLINE bool containsWebCoreOpaqueRoot(Visitor& visitor, WebCoreOpaqueRoot root)
{
return visitor.containsOpaqueRoot(root.pointer());
}
inline bool containsWebCoreOpaqueRoot(Visitor&, WebCoreOpaqueRoot);
template<typename Visitor, typename ImplType>
ALWAYS_INLINE bool containsWebCoreOpaqueRoot(Visitor& visitor, ImplType& impl)
{
return containsWebCoreOpaqueRoot(visitor, root(&impl));
}
inline bool containsWebCoreOpaqueRoot(Visitor&, ImplType&);
template<typename Visitor, typename ImplType>
ALWAYS_INLINE bool containsWebCoreOpaqueRoot(Visitor& visitor, ImplType* impl)
{
return containsWebCoreOpaqueRoot(visitor, root(impl));
}
inline bool containsWebCoreOpaqueRoot(Visitor&, ImplType*);
} // namespace WebCore

View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2023 Apple Inc. All rights reserved.
*
* 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.
*/
#pragma once
#include "WebCoreOpaqueRoot.h"
namespace WebCore {
template<typename Visitor>
ALWAYS_INLINE void addWebCoreOpaqueRoot(Visitor& visitor, WebCoreOpaqueRoot root)
{
visitor.addOpaqueRoot(root.pointer());
}
template<typename Visitor, typename ImplType>
ALWAYS_INLINE void addWebCoreOpaqueRoot(Visitor& visitor, ImplType* impl)
{
addWebCoreOpaqueRoot(visitor, root(impl));
}
template<typename Visitor, typename ImplType>
ALWAYS_INLINE void addWebCoreOpaqueRoot(Visitor& visitor, ImplType& impl)
{
addWebCoreOpaqueRoot(visitor, root(&impl));
}
template<typename Visitor>
ALWAYS_INLINE bool containsWebCoreOpaqueRoot(Visitor& visitor, WebCoreOpaqueRoot root)
{
return visitor.containsOpaqueRoot(root.pointer());
}
template<typename Visitor, typename ImplType>
ALWAYS_INLINE bool containsWebCoreOpaqueRoot(Visitor& visitor, ImplType& impl)
{
return containsWebCoreOpaqueRoot(visitor, root(&impl));
}
template<typename Visitor, typename ImplType>
ALWAYS_INLINE bool containsWebCoreOpaqueRoot(Visitor& visitor, ImplType* impl)
{
return containsWebCoreOpaqueRoot(visitor, root(impl));
}
} // namespace WebCore

View File

@@ -1835,7 +1835,6 @@ JSC_DECLARE_HOST_FUNCTION(makeGetterTypeErrorForBuiltins);
JSC_DECLARE_HOST_FUNCTION(makeDOMExceptionForBuiltins);
JSC_DECLARE_HOST_FUNCTION(createWritableStreamFromInternal);
JSC_DECLARE_HOST_FUNCTION(getInternalWritableStream);
JSC_DECLARE_HOST_FUNCTION(whenSignalAborted);
JSC_DECLARE_HOST_FUNCTION(isAbortSignal);
JSC_DEFINE_HOST_FUNCTION(makeThisTypeErrorForBuiltins, (JSGlobalObject * globalObject, CallFrame* callFrame))
@@ -1918,7 +1917,7 @@ JSC_DEFINE_HOST_FUNCTION(createWritableStreamFromInternal, (JSGlobalObject * glo
return JSValue::encode(toJSNewlyCreated(globalObject, jsDOMGlobalObject, WritableStream::create(WTFMove(internalWritableStream))));
}
JSC_DEFINE_HOST_FUNCTION(whenSignalAborted, (JSGlobalObject * globalObject, CallFrame* callFrame))
JSC_DEFINE_HOST_FUNCTION(addAbortAlgorithmToSignal, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
ASSERT(callFrame);
ASSERT(callFrame->argumentCount() == 2);
@@ -1930,8 +1929,21 @@ JSC_DEFINE_HOST_FUNCTION(whenSignalAborted, (JSGlobalObject * globalObject, Call
Ref<AbortAlgorithm> abortAlgorithm = JSAbortAlgorithm::create(vm, callFrame->uncheckedArgument(1).getObject());
bool result = WebCore::AbortSignal::whenSignalAborted(abortSignal->wrapped(), WTFMove(abortAlgorithm));
return JSValue::encode(result ? JSValue(JSC::JSValue::JSTrue) : JSValue(JSC::JSValue::JSFalse));
auto algorithmIdentifier = AbortSignal::addAbortAlgorithmToSignal(abortSignal->wrapped(), WTFMove(abortAlgorithm));
return JSValue::encode(JSC::jsNumber(algorithmIdentifier));
}
JSC_DEFINE_HOST_FUNCTION(removeAbortAlgorithmFromSignal, (JSGlobalObject*, CallFrame* callFrame))
{
ASSERT(callFrame);
ASSERT(callFrame->argumentCount() == 2);
auto* abortSignal = jsDynamicCast<JSAbortSignal*>(callFrame->uncheckedArgument(0));
if (UNLIKELY(!abortSignal))
return JSValue::encode(JSValue(JSC::JSValue::JSFalse));
AbortSignal::removeAbortAlgorithmFromSignal(abortSignal->wrapped(), callFrame->uncheckedArgument(1).asUInt32());
return JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(isAbortSignal, (JSGlobalObject*, CallFrame* callFrame))
@@ -3351,7 +3363,8 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm)
GlobalPropertyInfo(builtinNames.makeThisTypeErrorPrivateName(), JSFunction::create(vm, this, 2, String(), makeThisTypeErrorForBuiltins, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
GlobalPropertyInfo(builtinNames.makeGetterTypeErrorPrivateName(), JSFunction::create(vm, this, 2, String(), makeGetterTypeErrorForBuiltins, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
GlobalPropertyInfo(builtinNames.makeDOMExceptionPrivateName(), JSFunction::create(vm, this, 2, String(), makeDOMExceptionForBuiltins, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
GlobalPropertyInfo(builtinNames.whenSignalAbortedPrivateName(), JSFunction::create(vm, this, 2, String(), whenSignalAborted, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
GlobalPropertyInfo(builtinNames.addAbortAlgorithmToSignalPrivateName(), JSFunction::create(vm, this, 2, String(), addAbortAlgorithmToSignal, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
GlobalPropertyInfo(builtinNames.removeAbortAlgorithmFromSignalPrivateName(), JSFunction::create(vm, this, 2, String(), removeAbortAlgorithmFromSignal, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
GlobalPropertyInfo(builtinNames.cloneArrayBufferPrivateName(), JSFunction::create(vm, this, 3, String(), cloneArrayBuffer, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
GlobalPropertyInfo(builtinNames.structuredCloneForStreamPrivateName(), JSFunction::create(vm, this, 1, String(), structuredCloneForStream, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),
GlobalPropertyInfo(builtinNames.isAbortSignalPrivateName(), JSFunction::create(vm, this, 1, String(), isAbortSignal, ImplementationVisibility::Public), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly),

View File

@@ -5261,7 +5261,7 @@ extern "C" bool WebCore__AbortSignal__aborted(WebCore__AbortSignal* arg0)
extern "C" JSC__JSValue WebCore__AbortSignal__abortReason(WebCore__AbortSignal* arg0)
{
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
return JSC::JSValue::encode(abortSignal->reason());
return JSC::JSValue::encode(abortSignal->reason().getValue(jsNull()));
}
extern "C" WebCore__AbortSignal* WebCore__AbortSignal__ref(WebCore__AbortSignal* arg0)
@@ -5288,7 +5288,7 @@ extern "C" WebCore__AbortSignal* WebCore__AbortSignal__addListener(WebCore__Abor
WebCore::AbortSignal* abortSignal = reinterpret_cast<WebCore::AbortSignal*>(arg0);
if (abortSignal->aborted()) {
callback(ctx, JSC::JSValue::encode(abortSignal->reason()));
callback(ctx, JSC::JSValue::encode(abortSignal->reason().getValue(jsNull())));
return arg0;
}

View File

@@ -29,7 +29,9 @@
#include "AbortSignal.h"
#include "DOMException.h"
#include "JSDOMException.h"
// #include <wtf/IsoMallocInlines.h>
#include <wtf/IsoMallocInlines.h>
#include "WebCoreOpaqueRoot.h"
#include "WebCoreOpaqueRootInlines.h"
namespace WebCore {
@@ -56,9 +58,19 @@ void AbortController::abort(JSDOMGlobalObject& globalObject, JSC::JSValue reason
{
ASSERT(reason);
if (reason.isUndefined())
reason = toJS(&globalObject, &globalObject, DOMException::create(AbortError));
reason = toJS(&globalObject, &globalObject, DOMException::create(ExceptionCode::AbortError));
m_signal->signalAbort(reason);
protectedSignal()->signalAbort(reason);
}
WebCoreOpaqueRoot AbortController::opaqueRoot()
{
return root(&signal());
}
Ref<AbortSignal> AbortController::protectedSignal() const
{
return m_signal;
}
}

View File

@@ -43,6 +43,8 @@ class GlobalObject;
namespace WebCore {
class WebCoreOpaqueRoot;
class AbortSignal;
class ScriptExecutionContext;
@@ -55,8 +57,11 @@ public:
~AbortController();
AbortSignal& signal();
Ref<AbortSignal> protectedSignal() const;
void abort(Zig::GlobalObject&, JSC::JSValue reason);
WebCoreOpaqueRoot opaqueRoot();
private:
explicit AbortController(ScriptExecutionContext&);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2022 Apple Inc. All rights reserved.
* Copyright (C) 2017-2023 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,9 +33,10 @@
#include "EventNames.h"
#include "JSDOMException.h"
#include "ScriptExecutionContext.h"
#include "WebCoreOpaqueRoot.h"
#include <JavaScriptCore/Exception.h>
#include <JavaScriptCore/JSCast.h>
// #include <wtf/IsoMallocInlines.h>
#include <wtf/IsoMallocInlines.h>
namespace WebCore {
@@ -51,7 +52,7 @@ Ref<AbortSignal> AbortSignal::abort(JSDOMGlobalObject& globalObject, ScriptExecu
{
ASSERT(reason);
if (reason.isUndefined())
reason = toJS(&globalObject, &globalObject, DOMException::create(AbortError));
reason = toJS(&globalObject, &globalObject, DOMException::create(ExceptionCode::AbortError));
return adoptRef(*new AbortSignal(&context, Aborted::Yes, reason));
}
@@ -82,16 +83,51 @@ Ref<AbortSignal> AbortSignal::timeout(ScriptExecutionContext& context, uint64_t
return signal;
}
Ref<AbortSignal> AbortSignal::any(ScriptExecutionContext& context, const Vector<RefPtr<AbortSignal>>& signals)
{
Ref resultSignal = AbortSignal::create(&context);
auto abortedSignalIndex = signals.findIf([](auto& signal) { return signal->aborted(); });
if (abortedSignalIndex != notFound) {
resultSignal->signalAbort(signals[abortedSignalIndex]->reason().getValue());
return resultSignal;
}
resultSignal->markAsDependent();
for (auto& signal : signals)
resultSignal->addSourceSignal(*signal);
return resultSignal;
}
AbortSignal::AbortSignal(ScriptExecutionContext* context, Aborted aborted, JSC::JSValue reason)
: ContextDestructionObserver(context)
, m_reason(reason)
, m_aborted(aborted == Aborted::Yes)
, m_reason(context->vm(), reason)
{
ASSERT(reason);
}
AbortSignal::~AbortSignal() = default;
void AbortSignal::addSourceSignal(AbortSignal& signal)
{
if (signal.isDependent()) {
for (Ref sourceSignal : signal.sourceSignals())
addSourceSignal(sourceSignal);
return;
}
ASSERT(!signal.aborted());
ASSERT(signal.sourceSignals().isEmptyIgnoringNullReferences());
m_sourceSignals.add(signal);
signal.addDependentSignal(*this);
}
void AbortSignal::addDependentSignal(AbortSignal& signal)
{
m_dependentSignals.add(signal);
}
// https://dom.spec.whatwg.org/#abortsignal-signal-abort
void AbortSignal::signalAbort(JSC::JSValue reason)
{
@@ -101,15 +137,12 @@ void AbortSignal::signalAbort(JSC::JSValue reason)
// 2. Set signals aborted flag.
m_aborted = true;
m_sourceSignals.clear();
// FIXME: This code is wrong: we should emit a write-barrier. Otherwise, GC can collect it.
// https://bugs.webkit.org/show_bug.cgi?id=236353
ASSERT(reason);
auto& vm = scriptExecutionContext()->vm();
m_reason.set(vm, reason);
Ref protectedThis { *this };
auto algorithms = std::exchange(m_algorithms, {});
for (auto& algorithm : algorithms)
algorithm(reason);
m_reason.setWeakly(reason);
auto callbacks = std::exchange(m_native_callbacks, {});
for (auto callback : callbacks) {
@@ -117,6 +150,10 @@ void AbortSignal::signalAbort(JSC::JSValue reason)
func(ctx, JSC::JSValue::encode(reason));
}
auto algorithms = std::exchange(m_algorithms, {});
for (auto& algorithm : algorithms)
algorithm.second(reason);
// 5. Fire an event named abort at signal.
dispatchEvent(Event::create(eventNames().abortEvent, Event::CanBubble::No, Event::IsCancelable::No));
}
@@ -140,21 +177,15 @@ void AbortSignal::signalFollow(AbortSignal& signal)
return;
if (signal.aborted()) {
signalAbort(signal.reason());
signalAbort(signal.reason().getValue());
return;
}
ASSERT(!m_followingSignal);
m_followingSignal = signal;
signal.addAlgorithm([weakThis = WeakPtr { this }](JSC::JSValue reason) {
if (weakThis) {
if (reason.isEmpty() || reason.isUndefined()) {
weakThis->signalAbort(weakThis->m_followingSignal ? weakThis->m_followingSignal->reason()
: JSC::jsUndefined());
} else {
weakThis->signalAbort(reason);
}
}
signal.addAlgorithm([weakThis = WeakPtr { *this }](JSC::JSValue reason) {
if (RefPtr signal = weakThis.get())
signal->signalAbort(reason);
});
}
@@ -163,16 +194,33 @@ void AbortSignal::eventListenersDidChange()
m_hasAbortEventListener = hasEventListeners(eventNames().abortEvent);
}
bool AbortSignal::whenSignalAborted(AbortSignal& signal, Ref<AbortAlgorithm>&& algorithm)
uint32_t AbortSignal::addAbortAlgorithmToSignal(AbortSignal& signal, Ref<AbortAlgorithm>&& algorithm)
{
if (signal.aborted()) {
algorithm->handleEvent(signal.m_reason.get());
return true;
algorithm->handleEvent(signal.m_reason.getValue());
return 0;
}
signal.addAlgorithm([algorithm = WTFMove(algorithm)](JSC::JSValue value) mutable {
return signal.addAlgorithm([algorithm = WTFMove(algorithm)](JSC::JSValue value) mutable {
algorithm->handleEvent(value);
});
return false;
}
void AbortSignal::removeAbortAlgorithmFromSignal(AbortSignal& signal, uint32_t algorithmIdentifier)
{
signal.removeAlgorithm(algorithmIdentifier);
}
uint32_t AbortSignal::addAlgorithm(Algorithm&& algorithm)
{
m_algorithms.append(std::make_pair(++m_algorithmIdentifier, WTFMove(algorithm)));
return m_algorithmIdentifier;
}
void AbortSignal::removeAlgorithm(uint32_t algorithmIdentifier)
{
m_algorithms.removeFirstMatching([algorithmIdentifier](auto& pair) {
return pair.first == algorithmIdentifier;
});
}
void AbortSignal::throwIfAborted(JSC::JSGlobalObject& lexicalGlobalObject)
@@ -180,9 +228,14 @@ void AbortSignal::throwIfAborted(JSC::JSGlobalObject& lexicalGlobalObject)
if (!aborted())
return;
auto& vm = lexicalGlobalObject.vm();
Ref vm = lexicalGlobalObject.vm();
auto scope = DECLARE_THROW_SCOPE(vm);
throwException(&lexicalGlobalObject, scope, m_reason.get());
throwException(&lexicalGlobalObject, scope, m_reason.getValue());
}
WebCoreOpaqueRoot root(AbortSignal* signal)
{
return WebCoreOpaqueRoot { signal };
}
} // namespace WebCore

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017-2022 Apple Inc. All rights reserved.
* Copyright (C) 2017-2023 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,19 +25,22 @@
#pragma once
#include "config.h"
#include "ContextDestructionObserver.h"
#include "EventTarget.h"
// #include "JSDOMPromiseDeferred.h"
#include "JSValueInWrappedObject.h"
#include <wtf/Function.h>
#include <wtf/Ref.h>
#include <wtf/RefCounted.h>
#include <wtf/WeakListHashSet.h>
#include <wtf/WeakPtr.h>
namespace WebCore {
class AbortAlgorithm;
class ScriptExecutionContext;
class WebCoreOpaqueRoot;
class AbortSignal final : public RefCounted<AbortSignal>, public EventTargetWithInlineData, private ContextDestructionObserver {
WTF_MAKE_ISO_ALLOCATED_EXPORT(AbortSignal, WEBCORE_EXPORT);
@@ -49,14 +52,19 @@ public:
static Ref<AbortSignal> abort(JSDOMGlobalObject&, ScriptExecutionContext&, JSC::JSValue reason);
static Ref<AbortSignal> timeout(ScriptExecutionContext&, uint64_t milliseconds);
static Ref<AbortSignal> any(ScriptExecutionContext&, const Vector<RefPtr<AbortSignal>>&);
static bool whenSignalAborted(AbortSignal&, Ref<AbortAlgorithm>&&);
static uint32_t addAbortAlgorithmToSignal(AbortSignal&, Ref<AbortAlgorithm>&&);
static void removeAbortAlgorithmFromSignal(AbortSignal&, uint32_t algorithmIdentifier);
void signalAbort(JSC::JSValue reason);
void signalFollow(AbortSignal&);
bool aborted() const { return m_aborted; }
JSValue reason() const { return m_reason.get(); }
const JSValueInWrappedObject& reason() const { return m_reason; }
void cleanNativeBindings(void* ref);
void addNativeCallback(NativeCallbackTuple callback) { m_native_callbacks.append(callback); }
bool hasActiveTimeoutTimer() const { return m_hasActiveTimeoutTimer; }
bool hasAbortEventListener() const { return m_hasAbortEventListener; }
@@ -64,15 +72,18 @@ public:
using RefCounted::deref;
using RefCounted::ref;
using Algorithm = Function<void(JSValue)>;
void addAlgorithm(Algorithm&& algorithm) { m_algorithms.append(WTFMove(algorithm)); }
void cleanNativeBindings(void* ref);
void addNativeCallback(NativeCallbackTuple callback) { m_native_callbacks.append(callback); }
using Algorithm = Function<void(JSC::JSValue reason)>;
uint32_t addAlgorithm(Algorithm&&);
void removeAlgorithm(uint32_t);
bool isFollowingSignal() const { return !!m_followingSignal; }
void throwIfAborted(JSC::JSGlobalObject&);
using AbortSignalSet = WeakListHashSet<AbortSignal, WeakPtrImplWithEventTargetData>;
const AbortSignalSet& sourceSignals() const { return m_sourceSignals; }
AbortSignalSet& sourceSignals() { return m_sourceSignals; }
private:
enum class Aborted : bool { No,
Yes };
@@ -80,6 +91,11 @@ private:
void setHasActiveTimeoutTimer(bool hasActiveTimeoutTimer) { m_hasActiveTimeoutTimer = hasActiveTimeoutTimer; }
bool isDependent() const { return m_isDependent; }
void markAsDependent() { m_isDependent = true; }
void addSourceSignal(AbortSignal&);
void addDependentSignal(AbortSignal&);
// EventTarget.
EventTargetInterface eventTargetInterface() const final { return AbortSignalEventTargetInterfaceType; }
ScriptExecutionContext* scriptExecutionContext() const final { return ContextDestructionObserver::scriptExecutionContext(); }
@@ -87,13 +103,19 @@ private:
void derefEventTarget() final { deref(); }
void eventListenersDidChange() final;
bool m_aborted { false };
Vector<Algorithm, 2> m_algorithms;
Vector<std::pair<uint32_t, Algorithm>> m_algorithms;
WeakPtr<AbortSignal, WeakPtrImplWithEventTargetData> m_followingSignal;
AbortSignalSet m_sourceSignals;
AbortSignalSet m_dependentSignals;
JSValueInWrappedObject m_reason;
Vector<NativeCallbackTuple, 2> m_native_callbacks;
WeakPtr<AbortSignal> m_followingSignal;
JSC::Strong<JSC::Unknown> m_reason;
uint32_t m_algorithmIdentifier { 0 };
bool m_aborted { false };
bool m_hasActiveTimeoutTimer { false };
bool m_hasAbortEventListener { false };
bool m_isDependent { false };
};
}
WebCoreOpaqueRoot root(AbortSignal*);
} // namespace WebCore

View File

@@ -72,7 +72,7 @@ static HashMap<BroadcastChannelIdentifier, ScriptExecutionContextIdentifier>& ch
// return { WTFMove(topOrigin), WTFMove(securityOrigin) };
// }
class BroadcastChannel::MainThreadBridge : public ThreadSafeRefCounted<MainThreadBridge, WTF::DestructionThread::Main> {
class BroadcastChannel::MainThreadBridge : public ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr<MainThreadBridge> {
public:
static Ref<MainThreadBridge> create(BroadcastChannel& channel, const String& name, ScriptExecutionContext& context)
{
@@ -87,13 +87,15 @@ public:
BroadcastChannelIdentifier identifier() const { return m_identifier; }
ScriptExecutionContextIdentifier contextId() const { return m_contextId; }
using ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr::deref;
using ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr::ref;
private:
MainThreadBridge(BroadcastChannel&, const String& name, ScriptExecutionContext&);
void ensureOnMainThread(Function<void(void*)>&&);
// WeakPtr<BroadcastChannel, WeakPtrImplWithEventTargetData> m_broadcastChannel;
WeakPtr<BroadcastChannel> m_broadcastChannel;
WeakPtr<BroadcastChannel, WeakPtrImplWithEventTargetData> m_broadcastChannel;
const BroadcastChannelIdentifier m_identifier;
const String m_name; // Main thread only.
ScriptExecutionContextIdentifier m_contextId;

View File

@@ -65,7 +65,22 @@ public:
bool isFiringEventListeners { false };
};
class EventTarget : public ScriptWrappable, public CanMakeWeakPtr<EventTarget> {
// Do not make WeakPtrImplWithEventTargetData a derived class of DefaultWeakPtrImpl to catch the bug which uses incorrect impl class.
class WeakPtrImplWithEventTargetData final : public WTF::WeakPtrImplBaseSingleThread<WeakPtrImplWithEventTargetData> {
public:
EventTargetData& eventTargetData() { return m_eventTargetData; }
const EventTargetData& eventTargetData() const { return m_eventTargetData; }
template<typename T> WeakPtrImplWithEventTargetData(T* ptr)
: WTF::WeakPtrImplBaseSingleThread<WeakPtrImplWithEventTargetData>(ptr)
{
}
private:
EventTargetData m_eventTargetData;
};
class EventTarget : public ScriptWrappable, public CanMakeWeakPtrWithBitField<EventTarget, WeakPtrFactoryInitialization::Lazy, WeakPtrImplWithEventTargetData> {
WTF_MAKE_ISO_ALLOCATED(EventTarget);
public:

View File

@@ -39,9 +39,10 @@
#include "JSDOMWrapperCache.h"
#include "ScriptExecutionContext.h"
#include "WebCoreJSClientData.h"
#include "WebCoreOpaqueRootInlines.h"
#include <JavaScriptCore/FunctionPrototype.h>
#include <JavaScriptCore/HeapAnalyzer.h>
#include <JavaScriptCore/JSCInlines.h>
#include <JavaScriptCore/JSDestructibleObjectHeapCellType.h>
#include <JavaScriptCore/SlotVisitorMacros.h>
#include <JavaScriptCore/SubspaceInlines.h>
@@ -49,8 +50,6 @@
#include <wtf/PointerPreparations.h>
#include <wtf/URL.h>
#include "weak_handle.h"
namespace WebCore {
using namespace JSC;
@@ -97,9 +96,9 @@ STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSAbortControllerPrototype, JSAbortControlle
using JSAbortControllerDOMConstructor = JSDOMConstructor<JSAbortController>;
template<> JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSAbortControllerDOMConstructor::construct(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame)
template<> EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSAbortControllerDOMConstructor::construct(JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame)
{
VM& vm = lexicalGlobalObject->vm();
auto& vm = lexicalGlobalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto* castedThis = jsCast<JSAbortControllerDOMConstructor*>(callFrame->jsCallee());
ASSERT(castedThis);
@@ -139,8 +138,8 @@ template<> void JSAbortControllerDOMConstructor::initializeProperties(VM& vm, JS
/* Hash table for prototype */
static const HashTableValue JSAbortControllerPrototypeTableValues[] = {
{ "constructor"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsAbortControllerConstructor, 0 } },
{ "signal"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, jsAbortController_signal, 0 } },
{ "constructor"_s, static_cast<unsigned>(PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsAbortControllerConstructor, 0 } },
{ "signal"_s, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute, NoIntrinsic, { HashTableValue::GetterSetterType, jsAbortController_signal, 0 } },
{ "abort"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsAbortControllerPrototypeFunction_abort, 0 } },
};
@@ -160,13 +159,7 @@ JSAbortController::JSAbortController(Structure* structure, JSDOMGlobalObject& gl
{
}
void JSAbortController::finishCreation(VM& vm)
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
// static_assert(!std::is_base_of<ActiveDOMObject, AbortController>::value, "Interface is not marked as [ActiveDOMObject] even though implementation class subclasses ActiveDOMObject.");
}
// static_assert(!std::is_base_of<ActiveDOMObject, AbortController>::value, "Interface is not marked as [ActiveDOMObject] even though implementation class subclasses ActiveDOMObject.");
JSObject* JSAbortController::createPrototype(VM& vm, JSDOMGlobalObject& globalObject)
{
@@ -191,14 +184,14 @@ void JSAbortController::destroy(JSC::JSCell* cell)
thisObject->JSAbortController::~JSAbortController();
}
JSC_DEFINE_CUSTOM_GETTER(jsAbortControllerConstructor, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName))
JSC_DEFINE_CUSTOM_GETTER(jsAbortControllerConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName))
{
VM& vm = JSC::getVM(lexicalGlobalObject);
auto& vm = JSC::getVM(lexicalGlobalObject);
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto* prototype = jsDynamicCast<JSAbortControllerPrototype*>(JSValue::decode(thisValue));
if (UNLIKELY(!prototype))
return throwVMTypeError(lexicalGlobalObject, throwScope);
return JSValue::encode(JSAbortController::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject()));
return JSValue::encode(JSAbortController::getConstructor(vm, prototype->globalObject()));
}
static inline JSValue jsAbortController_signalGetter(JSGlobalObject& lexicalGlobalObject, JSAbortController& thisObject)
@@ -209,7 +202,7 @@ static inline JSValue jsAbortController_signalGetter(JSGlobalObject& lexicalGlob
RELEASE_AND_RETURN(throwScope, (toJS<IDLInterface<AbortSignal>>(lexicalGlobalObject, *thisObject.globalObject(), throwScope, impl.signal())));
}
JSC_DEFINE_CUSTOM_GETTER(jsAbortController_signal, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName attributeName))
JSC_DEFINE_CUSTOM_GETTER(jsAbortController_signal, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
{
return IDLAttribute<JSAbortController>::get<jsAbortController_signalGetter, CastedThisErrorBehavior::Assert>(*lexicalGlobalObject, thisValue, attributeName);
}
@@ -248,7 +241,7 @@ void JSAbortController::visitChildrenImpl(JSCell* cell, Visitor& visitor)
auto* thisObject = jsCast<JSAbortController*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
Base::visitChildren(thisObject, visitor);
visitor.addOpaqueRoot(WTF::getPtr(thisObject->wrapped().signal()));
addWebCoreOpaqueRoot(visitor, thisObject->wrapped().opaqueRoot());
}
DEFINE_VISIT_CHILDREN(JSAbortController);
@@ -258,7 +251,7 @@ void JSAbortController::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
auto* thisObject = jsCast<JSAbortController*>(cell);
analyzer.setWrappedObjectForCell(cell, &thisObject->wrapped());
if (thisObject->scriptExecutionContext())
analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string());
analyzer.setLabelForCell(cell, "url "_s + thisObject->scriptExecutionContext()->url().string());
Base::analyzeHeap(cell, analyzer);
}
@@ -277,8 +270,44 @@ void JSAbortControllerOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* co
uncacheWrapper(world, &jsAbortController->wrapped(), jsAbortController);
}
void JSAbortController::finishCreation(VM& vm)
{
Base::finishCreation(vm);
ASSERT(inherits(info()));
}
#if ENABLE(BINDING_INTEGRITY)
#if PLATFORM(WIN)
#pragma warning(disable : 4483)
extern "C" {
extern void (*const __identifier("??_7AbortController@WebCore@@6B@")[])();
}
#else
extern "C" {
extern void* _ZTVN7WebCore15AbortControllerE[];
}
#endif
#endif
JSC::JSValue toJSNewlyCreated(JSC::JSGlobalObject*, JSDOMGlobalObject* globalObject, Ref<AbortController>&& impl)
{
if constexpr (std::is_polymorphic_v<AbortController>) {
#if ENABLE(BINDING_INTEGRITY)
const void* actualVTablePointer = getVTablePointer(impl.ptr());
#if PLATFORM(WIN)
void* expectedVTablePointer = __identifier("??_7AbortController@WebCore@@6B@");
#else
void* expectedVTablePointer = &_ZTVN7WebCore15AbortControllerE[2];
#endif
// If you hit this assertion you either have a use after free bug, or
// AbortController has subclasses. If AbortController has subclasses that get passed
// to toJS() we currently require AbortController you to opt out of binding hardening
// by adding the SkipVTableValidation attribute to the interface IDL definition
RELEASE_ASSERT(actualVTablePointer == expectedVTablePointer);
#endif
}
return createWrapper<AbortController>(globalObject, WTFMove(impl));
}
@@ -287,7 +316,7 @@ JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* g
return wrap(lexicalGlobalObject, globalObject, impl);
}
AbortController* JSAbortController::toWrapped(JSC::VM& vm, JSC::JSValue value)
AbortController* JSAbortController::toWrapped(JSC::VM&, JSC::JSValue value)
{
if (auto* wrapper = jsDynamicCast<JSAbortController*>(value))
return &wrapper->wrapped();

View File

@@ -20,8 +20,6 @@
#pragma once
#include "root.h"
#include "AbortController.h"
#include "JSDOMWrapper.h"
#include <wtf/NeverDestroyed.h>
@@ -33,8 +31,9 @@ public:
using Base = JSDOMWrapper<AbortController>;
static JSAbortController* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<AbortController>&& impl)
{
JSAbortController* ptr = new (NotNull, JSC::allocateCell<JSAbortController>(globalObject->vm())) JSAbortController(structure, *globalObject, WTFMove(impl));
ptr->finishCreation(globalObject->vm());
auto& vm = globalObject->vm();
JSAbortController* ptr = new (NotNull, JSC::allocateCell<JSAbortController>(vm)) JSAbortController(structure, *globalObject, WTFMove(impl));
ptr->finishCreation(vm);
return ptr;
}

View File

@@ -26,7 +26,6 @@
#include "ExtendedDOMClientIsoSubspaces.h"
#include "ExtendedDOMIsoSubspaces.h"
#include "IDLTypes.h"
#include "JSAbortAlgorithm.h"
#include "JSAbortSignal.h"
#include "JSDOMAttribute.h"
#include "JSDOMBinding.h"
@@ -34,9 +33,9 @@
#include "JSDOMConvertAny.h"
#include "JSDOMConvertBase.h"
#include "JSDOMConvertBoolean.h"
#include "JSDOMConvertCallbacks.h"
#include "JSDOMConvertInterface.h"
#include "JSDOMConvertNumbers.h"
#include "JSDOMConvertSequences.h"
#include "JSDOMExceptionHandling.h"
#include "JSDOMGlobalObject.h"
#include "JSDOMGlobalObjectInlines.h"
@@ -46,6 +45,7 @@
#include "ScriptExecutionContext.h"
#include "WebCoreJSClientData.h"
#include <JavaScriptCore/HeapAnalyzer.h>
#include <JavaScriptCore/JSArray.h>
#include <JavaScriptCore/JSCInlines.h>
#include <JavaScriptCore/JSDestructibleObjectHeapCellType.h>
#include <JavaScriptCore/SlotVisitorMacros.h>
@@ -59,9 +59,9 @@ using namespace JSC;
// Functions
static JSC_DECLARE_HOST_FUNCTION(jsAbortSignalConstructorFunction_whenSignalAborted);
static JSC_DECLARE_HOST_FUNCTION(jsAbortSignalConstructorFunction_abort);
static JSC_DECLARE_HOST_FUNCTION(jsAbortSignalConstructorFunction_timeout);
static JSC_DECLARE_HOST_FUNCTION(jsAbortSignalConstructorFunction_any);
static JSC_DECLARE_HOST_FUNCTION(jsAbortSignalPrototypeFunction_throwIfAborted);
// Attributes
@@ -109,9 +109,9 @@ using JSAbortSignalDOMConstructor = JSDOMConstructorNotConstructable<JSAbortSign
/* Hash table for constructor */
static const HashTableValue JSAbortSignalConstructorTableValues[] = {
{ "whenSignalAborted"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsAbortSignalConstructorFunction_whenSignalAborted, 2 } },
{ "abort"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsAbortSignalConstructorFunction_abort, 0 } },
{ "timeout"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsAbortSignalConstructorFunction_timeout, 1 } },
{ "any"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsAbortSignalConstructorFunction_any, 1 } },
};
template<> const ClassInfo JSAbortSignalDOMConstructor::s_info = { "AbortSignal"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSAbortSignalDOMConstructor) };
@@ -129,18 +129,27 @@ template<> void JSAbortSignalDOMConstructor::initializeProperties(VM& vm, JSDOMG
putDirect(vm, vm.propertyNames->name, nameString, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
putDirect(vm, vm.propertyNames->prototype, JSAbortSignal::prototype(vm, globalObject), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete);
reifyStaticProperties(vm, JSAbortSignal::info(), JSAbortSignalConstructorTableValues, *this);
// if (!((&globalObject)->inherits<JSDOMWindowBase>() || (&globalObject)->inherits<JSWorkerGlobalScopeBase>())) {
// auto propertyName = Identifier::fromString(vm, "timeout"_s);
// VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
// DeletePropertySlot slot;
// JSObject::deleteProperty(this, &globalObject, propertyName, slot);
// }
// if (!jsCast<JSDOMGlobalObject*>(&globalObject)->scriptExecutionContext()->settingsValues().abortSignalAnyOperationEnabled) {
// auto propertyName = Identifier::fromString(vm, "any"_s);
// VM::DeletePropertyModeScope scope(vm, VM::DeletePropertyMode::IgnoreConfigurable);
// DeletePropertySlot slot;
// JSObject::deleteProperty(this, &globalObject, propertyName, slot);
// }
}
/* Hash table for prototype */
static const HashTableValue JSAbortSignalPrototypeTableValues[] = {
{ "constructor"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsAbortSignalConstructor, 0 } },
{ "aborted"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, jsAbortSignal_aborted, 0 } },
{ "reason"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, jsAbortSignal_reason, 0 } },
{ "onabort"_s,
static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute),
NoIntrinsic,
{ HashTableValue::GetterSetterType, jsAbortSignal_onabort, setJSAbortSignal_onabort } },
{ "constructor"_s, static_cast<unsigned>(PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, jsAbortSignalConstructor, 0 } },
{ "aborted"_s, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute, NoIntrinsic, { HashTableValue::GetterSetterType, jsAbortSignal_aborted, 0 } },
{ "reason"_s, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute, NoIntrinsic, { HashTableValue::GetterSetterType, jsAbortSignal_reason, 0 } },
{ "onabort"_s, JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute, NoIntrinsic, { HashTableValue::GetterSetterType, jsAbortSignal_onabort, setJSAbortSignal_onabort } },
{ "throwIfAborted"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsAbortSignalPrototypeFunction_throwIfAborted, 0 } },
};
@@ -150,7 +159,6 @@ void JSAbortSignalPrototype::finishCreation(VM& vm)
{
Base::finishCreation(vm);
reifyStaticProperties(vm, JSAbortSignal::info(), JSAbortSignalPrototypeTableValues, *this);
putDirect(vm, static_cast<JSVMClientData*>(vm.clientData)->builtinNames().whenSignalAbortedPrivateName(), JSFunction::create(vm, globalObject(), 0, String(), jsAbortSignalConstructorFunction_whenSignalAborted, ImplementationVisibility::Public), JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum);
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
}
@@ -167,9 +175,16 @@ void JSAbortSignal::finishCreation(VM& vm)
ASSERT(inherits(info()));
}
Ref<AbortSignal> JSAbortSignal::protectedWrapped() const
{
return wrapped();
}
JSObject* JSAbortSignal::createPrototype(VM& vm, JSDOMGlobalObject& globalObject)
{
return JSAbortSignalPrototype::create(vm, &globalObject, JSAbortSignalPrototype::createStructure(vm, &globalObject, JSEventTarget::prototype(vm, globalObject)));
auto* structure = JSAbortSignalPrototype::createStructure(vm, &globalObject, JSEventTarget::prototype(vm, globalObject));
structure->setMayBePrototype(true);
return JSAbortSignalPrototype::create(vm, &globalObject, structure);
}
JSObject* JSAbortSignal::prototype(VM& vm, JSDOMGlobalObject& globalObject)
@@ -182,14 +197,14 @@ JSValue JSAbortSignal::getConstructor(VM& vm, const JSGlobalObject* globalObject
return getDOMConstructor<JSAbortSignalDOMConstructor, DOMConstructorID::AbortSignal>(vm, *jsCast<const JSDOMGlobalObject*>(globalObject));
}
JSC_DEFINE_CUSTOM_GETTER(jsAbortSignalConstructor, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName))
JSC_DEFINE_CUSTOM_GETTER(jsAbortSignalConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName))
{
VM& vm = JSC::getVM(lexicalGlobalObject);
auto& vm = JSC::getVM(lexicalGlobalObject);
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto* prototype = jsDynamicCast<JSAbortSignalPrototype*>(JSValue::decode(thisValue));
if (UNLIKELY(!prototype))
return throwVMTypeError(lexicalGlobalObject, throwScope);
return JSValue::encode(JSAbortSignal::getConstructor(JSC::getVM(lexicalGlobalObject), prototype->globalObject()));
return JSValue::encode(JSAbortSignal::getConstructor(vm, prototype->globalObject()));
}
static inline JSValue jsAbortSignal_abortedGetter(JSGlobalObject& lexicalGlobalObject, JSAbortSignal& thisObject)
@@ -200,7 +215,7 @@ static inline JSValue jsAbortSignal_abortedGetter(JSGlobalObject& lexicalGlobalO
RELEASE_AND_RETURN(throwScope, (toJS<IDLBoolean>(lexicalGlobalObject, throwScope, impl.aborted())));
}
JSC_DEFINE_CUSTOM_GETTER(jsAbortSignal_aborted, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName attributeName))
JSC_DEFINE_CUSTOM_GETTER(jsAbortSignal_aborted, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
{
return IDLAttribute<JSAbortSignal>::get<jsAbortSignal_abortedGetter, CastedThisErrorBehavior::Assert>(*lexicalGlobalObject, thisValue, attributeName);
}
@@ -213,7 +228,7 @@ static inline JSValue jsAbortSignal_reasonGetter(JSGlobalObject& lexicalGlobalOb
RELEASE_AND_RETURN(throwScope, (toJS<IDLAny>(lexicalGlobalObject, throwScope, impl.reason())));
}
JSC_DEFINE_CUSTOM_GETTER(jsAbortSignal_reason, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName attributeName))
JSC_DEFINE_CUSTOM_GETTER(jsAbortSignal_reason, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
{
return IDLAttribute<JSAbortSignal>::get<jsAbortSignal_reasonGetter, CastedThisErrorBehavior::Assert>(*lexicalGlobalObject, thisValue, attributeName);
}
@@ -221,10 +236,10 @@ JSC_DEFINE_CUSTOM_GETTER(jsAbortSignal_reason, (JSGlobalObject * lexicalGlobalOb
static inline JSValue jsAbortSignal_onabortGetter(JSGlobalObject& lexicalGlobalObject, JSAbortSignal& thisObject)
{
UNUSED_PARAM(lexicalGlobalObject);
return eventHandlerAttribute(thisObject.wrapped(), eventNames().abortEvent, worldForDOMObject(thisObject));
return eventHandlerAttribute(thisObject.protectedWrapped(), eventNames().abortEvent, worldForDOMObject(thisObject));
}
JSC_DEFINE_CUSTOM_GETTER(jsAbortSignal_onabort, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, PropertyName attributeName))
JSC_DEFINE_CUSTOM_GETTER(jsAbortSignal_onabort, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
{
return IDLAttribute<JSAbortSignal>::get<jsAbortSignal_onabortGetter, CastedThisErrorBehavior::Assert>(*lexicalGlobalObject, thisValue, attributeName);
}
@@ -232,40 +247,19 @@ JSC_DEFINE_CUSTOM_GETTER(jsAbortSignal_onabort, (JSGlobalObject * lexicalGlobalO
static inline bool setJSAbortSignal_onabortSetter(JSGlobalObject& lexicalGlobalObject, JSAbortSignal& thisObject, JSValue value)
{
auto& vm = JSC::getVM(&lexicalGlobalObject);
setEventHandlerAttribute<JSEventListener>(thisObject.wrapped(), eventNames().abortEvent, value, thisObject);
UNUSED_PARAM(vm);
setEventHandlerAttribute<JSEventListener>(thisObject.protectedWrapped(), eventNames().abortEvent, value, thisObject);
vm.writeBarrier(&thisObject, value);
ensureStillAliveHere(value);
return true;
}
JSC_DEFINE_CUSTOM_SETTER(setJSAbortSignal_onabort, (JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue encodedValue, PropertyName attributeName))
JSC_DEFINE_CUSTOM_SETTER(setJSAbortSignal_onabort, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName))
{
return IDLAttribute<JSAbortSignal>::set<setJSAbortSignal_onabortSetter>(*lexicalGlobalObject, thisValue, encodedValue, attributeName);
}
static inline JSC::EncodedJSValue jsAbortSignalConstructorFunction_whenSignalAbortedBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
{
auto& vm = JSC::getVM(lexicalGlobalObject);
auto throwScope = DECLARE_THROW_SCOPE(vm);
UNUSED_PARAM(throwScope);
UNUSED_PARAM(callFrame);
if (UNLIKELY(callFrame->argumentCount() < 2))
return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0);
auto object = convert<IDLInterface<AbortSignal>>(*lexicalGlobalObject, argument0.value(), [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { throwArgumentTypeError(lexicalGlobalObject, scope, 0, "object", "AbortSignal", "whenSignalAborted", "AbortSignal"); });
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
EnsureStillAliveScope argument1 = callFrame->uncheckedArgument(1);
auto algorithm = convert<IDLCallbackFunction<JSAbortAlgorithm>>(*lexicalGlobalObject, argument1.value(), [](JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope) { throwArgumentMustBeFunctionError(lexicalGlobalObject, scope, 1, "algorithm", "AbortSignal", "whenSignalAborted"); });
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLBoolean>(*lexicalGlobalObject, throwScope, AbortSignal::whenSignalAborted(*object, algorithm.releaseNonNull()))));
}
JSC_DEFINE_HOST_FUNCTION(jsAbortSignalConstructorFunction_whenSignalAborted, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
{
return IDLOperation<JSAbortSignal>::callStatic<jsAbortSignalConstructorFunction_whenSignalAbortedBody, CastedThisErrorBehavior::Assert>(*lexicalGlobalObject, *callFrame, "whenSignalAborted");
}
static inline JSC::EncodedJSValue jsAbortSignalConstructorFunction_abortBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
{
auto& vm = JSC::getVM(lexicalGlobalObject);
@@ -308,6 +302,28 @@ JSC_DEFINE_HOST_FUNCTION(jsAbortSignalConstructorFunction_timeout, (JSGlobalObje
return IDLOperation<JSAbortSignal>::callStatic<jsAbortSignalConstructorFunction_timeoutBody>(*lexicalGlobalObject, *callFrame, "timeout");
}
static inline JSC::EncodedJSValue jsAbortSignalConstructorFunction_anyBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
{
auto& vm = JSC::getVM(lexicalGlobalObject);
auto throwScope = DECLARE_THROW_SCOPE(vm);
UNUSED_PARAM(throwScope);
UNUSED_PARAM(callFrame);
if (UNLIKELY(callFrame->argumentCount() < 1))
return throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
auto* context = jsCast<JSDOMGlobalObject*>(lexicalGlobalObject)->scriptExecutionContext();
if (UNLIKELY(!context))
return JSValue::encode(jsUndefined());
EnsureStillAliveScope argument0 = callFrame->uncheckedArgument(0);
auto signals = convert<IDLSequence<IDLInterface<AbortSignal>>>(*lexicalGlobalObject, argument0.value());
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
RELEASE_AND_RETURN(throwScope, JSValue::encode(toJSNewlyCreated<IDLInterface<AbortSignal>>(*lexicalGlobalObject, *jsCast<JSDOMGlobalObject*>(lexicalGlobalObject), throwScope, AbortSignal::any(*context, WTFMove(signals)))));
}
JSC_DEFINE_HOST_FUNCTION(jsAbortSignalConstructorFunction_any, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
{
return IDLOperation<JSAbortSignal>::callStatic<jsAbortSignalConstructorFunction_anyBody>(*lexicalGlobalObject, *callFrame, "any");
}
static inline JSC::EncodedJSValue jsAbortSignalPrototypeFunction_throwIfAbortedBody(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, typename IDLOperation<JSAbortSignal>::ClassParameter castedThis)
{
auto& vm = JSC::getVM(lexicalGlobalObject);
@@ -360,7 +376,7 @@ void JSAbortSignal::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
auto* thisObject = jsCast<JSAbortSignal*>(cell);
analyzer.setWrappedObjectForCell(cell, &thisObject->wrapped());
if (thisObject->scriptExecutionContext())
analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string());
analyzer.setLabelForCell(cell, "url "_s + thisObject->scriptExecutionContext()->url().string());
Base::analyzeHeap(cell, analyzer);
}
@@ -368,7 +384,7 @@ void JSAbortSignalOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* contex
{
auto* jsAbortSignal = static_cast<JSAbortSignal*>(handle.slot()->asCell());
auto& world = *static_cast<DOMWrapperWorld*>(context);
uncacheWrapper(world, &jsAbortSignal->wrapped(), jsAbortSignal);
uncacheWrapper(world, jsAbortSignal->protectedWrapped().ptr(), jsAbortSignal);
}
#if ENABLE(BINDING_INTEGRITY)
@@ -411,10 +427,11 @@ JSC::JSValue toJS(JSC::JSGlobalObject* lexicalGlobalObject, JSDOMGlobalObject* g
return wrap(lexicalGlobalObject, globalObject, impl);
}
AbortSignal* JSAbortSignal::toWrapped(JSC::VM& vm, JSC::JSValue value)
AbortSignal* JSAbortSignal::toWrapped(JSC::VM&, JSC::JSValue value)
{
if (auto* wrapper = jsDynamicCast<JSAbortSignal*>(value))
return &wrapper->wrapped();
return nullptr;
}
}

View File

@@ -33,8 +33,9 @@ public:
using DOMWrapped = AbortSignal;
static JSAbortSignal* create(JSC::Structure* structure, JSDOMGlobalObject* globalObject, Ref<AbortSignal>&& impl)
{
JSAbortSignal* ptr = new (NotNull, JSC::allocateCell<JSAbortSignal>(globalObject->vm())) JSAbortSignal(structure, *globalObject, WTFMove(impl));
ptr->finishCreation(globalObject->vm());
auto& vm = globalObject->vm();
JSAbortSignal* ptr = new (NotNull, JSC::allocateCell<JSAbortSignal>(vm)) JSAbortSignal(structure, *globalObject, WTFMove(impl));
ptr->finishCreation(vm);
return ptr;
}
@@ -66,6 +67,9 @@ public:
{
return static_cast<AbortSignal&>(Base::wrapped());
}
Ref<AbortSignal> protectedWrapped() const;
protected:
JSAbortSignal(JSC::Structure*, JSDOMGlobalObject&, Ref<AbortSignal>&&);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2017 Apple Inc. All rights reserved.
* Copyright (C) 2016-2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -95,23 +95,24 @@ struct NumericSequenceConverter {
auto indexValue = array->butterfly()->contiguousInt32().at(array, i).get();
ASSERT(!indexValue || indexValue.isInt32());
if (!indexValue)
result.unsafeAppendWithoutCapacityCheck(0);
result.append(0);
else
result.unsafeAppendWithoutCapacityCheck(indexValue.asInt32());
result.append(indexValue.asInt32());
}
return WTFMove(result);
}
ASSERT(indexingType == JSC::DoubleShape);
ASSERT(JSC::Options::allowDoubleShape());
for (unsigned i = 0; i < length; i++) {
double doubleValue = array->butterfly()->contiguousDouble().at(array, i);
if (std::isnan(doubleValue))
result.unsafeAppendWithoutCapacityCheck(0);
result.append(0);
else {
auto convertedValue = Converter<IDLType>::convert(lexicalGlobalObject, scope, doubleValue);
RETURN_IF_EXCEPTION(scope, {});
result.unsafeAppendWithoutCapacityCheck(convertedValue);
result.append(convertedValue);
}
}
return WTFMove(result);
@@ -219,7 +220,7 @@ struct SequenceConverter {
auto convertedValue = Converter<IDLType>::convert(lexicalGlobalObject, indexValue);
RETURN_IF_EXCEPTION(scope, {});
result.unsafeAppendWithoutCapacityCheck(convertedValue);
result.append(convertedValue);
}
return result;
}
@@ -234,7 +235,7 @@ struct SequenceConverter {
auto convertedValue = Converter<IDLType>::convert(lexicalGlobalObject, indexValue);
RETURN_IF_EXCEPTION(scope, {});
result.unsafeAppendWithoutCapacityCheck(convertedValue);
result.append(convertedValue);
}
return result;
}

View File

@@ -26,9 +26,9 @@
#include "DOMWrapperWorld.h"
#include "JSDOMWrapper.h"
#include <JavaScriptCore/JSCJSValue.h>
#include <JavaScriptCore/JSCJSValueInlines.h>
#include <JavaScriptCore/SlotVisitor.h>
#include <JavaScriptCore/Weak.h>
#include <JavaScriptCore/WeakInlines.h>
#include <variant>
namespace WebCore {
@@ -51,10 +51,6 @@ public:
void setWeakly(JSC::JSValue);
JSC::JSValue getValue(JSC::JSValue nullValue = JSC::jsUndefined()) const;
// FIXME: Remove this once IDBRequest semantic bug is fixed.
// https://bugs.webkit.org/show_bug.cgi?id=236278
void setWithoutBarrier(JSValueInWrappedObject&);
private:
// Keep in mind that all of these fields are accessed concurrently without lock from concurrent GC thread.
JSC::JSValue m_nonCell {};
@@ -62,7 +58,6 @@ private:
};
JSC::JSValue cachedPropertyValue(JSC::ThrowScope&, JSC::JSGlobalObject&, const JSDOMObject& owner, JSValueInWrappedObject& cacheSlot, const Function<JSC::JSValue(JSC::ThrowScope&)>&);
JSC::JSValue cachedPropertyValue(JSC::JSGlobalObject&, const JSDOMObject& owner, JSValueInWrappedObject& cacheSlot, const Function<JSC::JSValue()>&);
inline JSValueInWrappedObject::JSValueInWrappedObject(JSC::JSValue value)
{
@@ -115,14 +110,6 @@ inline void JSValueInWrappedObject::clear()
m_cell.clear();
}
inline void JSValueInWrappedObject::setWithoutBarrier(JSValueInWrappedObject& other)
{
JSC::Weak weak { other.m_cell.get() };
WTF::storeStoreFence(); // Ensure Weak is fully initialized for concurrent access.
m_nonCell = other.m_nonCell;
m_cell = WTFMove(weak);
}
inline JSC::JSValue cachedPropertyValue(JSC::JSGlobalObject& lexicalGlobalObject, const JSDOMObject& owner, JSValueInWrappedObject& cachedValue, const Function<JSC::JSValue()>& function)
{
if (cachedValue && isWorldCompatible(lexicalGlobalObject, cachedValue.getValue()))

View File

@@ -228,6 +228,7 @@ declare const $asyncContext: InternalFieldObject<[ReadonlyArray<any> | undefined
declare var $_events: TODO;
declare function $abortAlgorithm(): TODO;
declare function $abortSteps(): TODO;
declare function $addAbortAlgorithmToSignal(signal: AbortSignal, algorithm: () => void): TODO;
declare function $addEventListener(): TODO;
declare function $appendFromJS(): TODO;
declare function $argv(): TODO;
@@ -367,6 +368,7 @@ declare function $readableStreamToArray(): TODO;
declare function $reader(): TODO;
declare function $readyPromise(): TODO;
declare function $readyPromiseCapability(): TODO;
declare function $removeAbortAlgorithmFromSignal(signal: AbortSignal, algorithmIdentifier: number): TODO;
declare function $redirect(): TODO;
declare function $relative(): TODO;
declare function $releaseLock(): TODO;

View File

@@ -25,6 +25,7 @@ using namespace JSC;
macro(abortAlgorithm) \
macro(AbortSignal) \
macro(abortSteps) \
macro(addAbortAlgorithmToSignal) \
macro(addEventListener) \
macro(appendFromJS) \
macro(argv) \
@@ -180,6 +181,7 @@ using namespace JSC;
macro(readRequests) \
macro(readyPromise) \
macro(readyPromiseCapability) \
macro(removeAbortAlgorithmFromSignal) \
macro(redirect) \
macro(relative) \
macro(releaseLock) \
@@ -234,7 +236,6 @@ using namespace JSC;
macro(version) \
macro(versions) \
macro(view) \
macro(whenSignalAborted) \
macro(writable) \
macro(WritableStream) \
macro(WritableStreamDefaultController) \

View File

@@ -245,7 +245,6 @@ export function readableStreamPipeToWritableStream(
source.$disturbed = true;
pipeState.finalized = false;
pipeState.shuttingDown = false;
pipeState.promiseCapability = $newPromiseCapability(Promise);
pipeState.pendingReadPromiseCapability = $newPromiseCapability(Promise);
@@ -254,8 +253,6 @@ export function readableStreamPipeToWritableStream(
if (signal !== undefined) {
const algorithm = reason => {
if (pipeState.finalized) return;
$pipeToShutdownWithAction(
pipeState,
() => {
@@ -290,7 +287,13 @@ export function readableStreamPipeToWritableStream(
reason,
);
};
if ($whenSignalAborted(signal, algorithm)) return pipeState.promiseCapability.promise;
const abortAlgorithmIdentifier = (pipeState.abortAlgorithmIdentifier = $addAbortAlgorithmToSignal(
signal,
algorithm,
));
if (!abortAlgorithmIdentifier) return pipeState.promiseCapability.promise;
pipeState.signal = signal;
}
$pipeToErrorsMustBePropagatedForward(pipeState);
@@ -480,8 +483,8 @@ export function pipeToFinalize(pipeState) {
$writableStreamDefaultWriterRelease(pipeState.writer);
$readableStreamReaderGenericRelease(pipeState.reader);
// Instead of removing the abort algorithm as per spec, we make it a no-op which is equivalent.
pipeState.finalized = true;
const signal = pipeState.signal;
if (signal) $removeAbortAlgorithmFromSignal(signal, pipeState.abortAlgorithmIdentifier);
if (arguments.length > 1) pipeState.promiseCapability.reject.$call(undefined, arguments[1]);
else pipeState.promiseCapability.resolve.$call();