| Differences between
and this patch
- a/Source/JavaScriptCore/ChangeLog +58 lines
Lines 1-3 a/Source/JavaScriptCore/ChangeLog_sec1
1
2019-07-14  Ross Kirsling  <ross.kirsling@sony.com>
2
3
        JSC should have public API for unhandled promise rejections
4
        https://bugs.webkit.org/show_bug.cgi?id=197172
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        This patch allows callbacks for unhandled and late-handled promise rejections to be set via JSC's public C API.
9
        Since there is no task queue in such an environment, these callbacks fire off of the run loop.
10
        Callbacks receive the promise and rejection reason as arguments and their return value is ignored.
11
12
        * API/JSContextRef.cpp:
13
        (JSGlobalContextSetUnhandledRejectionCallback): Added.
14
        (JSGlobalContextSetRejectionHandledCallback): Added.
15
        * API/JSContextRef.h:
16
        Add new public API calls.
17
18
        * API/tests/testapi.cpp:
19
        (TestAPI::promiseResolveTrue): Clean up test output.
20
        (TestAPI::promiseRejectTrue): Clean up test output.
21
        (TestAPI::promiseRejectionCallbacks): Added.
22
        (testCAPIViaCpp):
23
        Add new C++ API test.
24
25
        * jsc.cpp:
26
        (GlobalObject::finishCreation):
27
        (functionSetUnhandledRejectionCallback): Added.
28
        (functionSetRejectionHandledCallback): Added.
29
        Add corresponding globals to JSC shell.
30
31
        * runtime/JSGlobalObject.h:
32
        (JSC::JSGlobalObject::setUnhandledRejectionCallback): Added.
33
        (JSC::JSGlobalObject::unhandledRejectionCallback const): Added.
34
        (JSC::JSGlobalObject::setRejectionHandledCallback): Added.
35
        (JSC::JSGlobalObject::rejectionHandledCallback const): Added.
36
        Keep strong references to the callbacks.
37
38
        * runtime/JSGlobalObjectFunctions.cpp:
39
        (JSC::globalFuncHostPromiseRejectionTracker):
40
        Add default behavior.
41
42
        * runtime/VM.cpp:
43
        (JSC::VM::VM):
44
        (JSC::VM::callPromiseRejectionCallback): Added.
45
        (JSC::VM::reportUnhandledRejectionsSoon): Added.
46
        (JSC::VM::promiseRejected): Added.
47
        (JSC::VM::promiseHandled): Added.
48
        (JSC::VM::drainMicrotasks):
49
        Mimic RejectedPromiseTracker using the run loop (via PromiseDeferredTimer).
50
        Specifically:
51
          1. When a promise rejection goes unhandled, store the promise for later reporting.
52
          2. After draining microtasks, schedule reporting of any stored unhandled rejections.
53
          3. If an already-reported (and not-yet-GCed) rejection gets handled at a later time,
54
             immediately schedule it to be reported.
55
56
        * runtime/VM.h:
57
        Store unhandled rejections (these collections will always be empty in the presence of WebCore).
58
1
2019-07-12  Keith Miller  <keith_miller@apple.com>
59
2019-07-12  Keith Miller  <keith_miller@apple.com>
2
60
3
        Add API to get all the dependencies of a given JSScript
61
        Add API to get all the dependencies of a given JSScript
- a/Source/WebCore/ChangeLog +11 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2019-07-14  Ross Kirsling  <ross.kirsling@sony.com>
2
3
        JSC should have public API for unhandled promise rejections
4
        https://bugs.webkit.org/show_bug.cgi?id=197172
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        * bindings/js/JSDOMGlobalObject.cpp:
9
        (WebCore::JSDOMGlobalObject::promiseRejectionTracker):
10
        Move JSInternalPromise early-out to JSC side.
11
1
2019-07-12  Thibault Saunier  <tsaunier@igalia.com>
12
2019-07-12  Thibault Saunier  <tsaunier@igalia.com>
2
13
3
        [GStreamer] Mock GStreamer realtime sources should keep a Ref of their mock realtime media sources
14
        [GStreamer] Mock GStreamer realtime sources should keep a Ref of their mock realtime media sources
- a/Source/JavaScriptCore/API/JSContextRef.cpp +41 lines
Lines 28-33 a/Source/JavaScriptCore/API/JSContextRef.cpp_sec1
28
#include "JSContextRefInternal.h"
28
#include "JSContextRefInternal.h"
29
29
30
#include "APICast.h"
30
#include "APICast.h"
31
#include "APIUtils.h"
31
#include "CallFrame.h"
32
#include "CallFrame.h"
32
#include "InitializeThreading.h"
33
#include "InitializeThreading.h"
33
#include "JSAPIGlobalObject.h"
34
#include "JSAPIGlobalObject.h"
Lines 37-42 a/Source/JavaScriptCore/API/JSContextRef.cpp_sec2
37
#include "JSCInlines.h"
38
#include "JSCInlines.h"
38
#include "SourceProvider.h"
39
#include "SourceProvider.h"
39
#include "StackVisitor.h"
40
#include "StackVisitor.h"
41
#include "StrongInlines.h"
40
#include "Watchdog.h"
42
#include "Watchdog.h"
41
#include <wtf/text/StringBuilder.h>
43
#include <wtf/text/StringBuilder.h>
42
#include <wtf/text/StringHash.h>
44
#include <wtf/text/StringHash.h>
Lines 249-254 void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name) a/Source/JavaScriptCore/API/JSContextRef.cpp_sec3
249
    vm.vmEntryGlobalObject(exec)->setName(name ? name->string() : String());
251
    vm.vmEntryGlobalObject(exec)->setName(name ? name->string() : String());
250
}
252
}
251
253
254
void JSGlobalContextSetUnhandledRejectionCallback(JSGlobalContextRef ctx, JSObjectRef function, JSValueRef* exception)
255
{
256
    if (!ctx) {
257
        ASSERT_NOT_REACHED();
258
        return;
259
    }
260
261
    ExecState* exec = toJS(ctx);
262
    VM& vm = exec->vm();
263
    JSLockHolder locker(vm);
264
265
    JSObject* object = toJS(function);
266
    if (!object->isFunction(vm)) {
267
        *exception = toRef(createTypeError(exec));
268
        return;
269
    }
270
271
    vm.vmEntryGlobalObject(exec)->setUnhandledRejectionCallback(vm, object);
272
}
273
274
void JSGlobalContextSetRejectionHandledCallback(JSGlobalContextRef ctx, JSObjectRef function, JSValueRef* exception)
275
{
276
    if (!ctx) {
277
        ASSERT_NOT_REACHED();
278
        return;
279
    }
280
281
    ExecState* exec = toJS(ctx);
282
    VM& vm = exec->vm();
283
    JSLockHolder locker(vm);
284
285
    JSObject* object = toJS(function);
286
    if (!object->isFunction(vm)) {
287
        *exception = toRef(createTypeError(exec));
288
        return;
289
    }
290
291
    vm.vmEntryGlobalObject(exec)->setRejectionHandledCallback(vm, object);
292
}
252
293
253
class BacktraceFunctor {
294
class BacktraceFunctor {
254
public:
295
public:
- a/Source/JavaScriptCore/API/JSContextRef.h +20 lines
Lines 156-161 JS_EXPORT JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx) JSC_API_AV a/Source/JavaScriptCore/API/JSContextRef.h_sec1
156
*/
156
*/
157
JS_EXPORT void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name) JSC_API_AVAILABLE(macos(10.10), ios(8.0));
157
JS_EXPORT void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name) JSC_API_AVAILABLE(macos(10.10), ios(8.0));
158
158
159
/*!
160
@function
161
@abstract Sets the "unhandled promise rejection" callback for a context.
162
@discussion JSC-only alternative to window.addEventListener('unhandledrejection').
163
@param ctx The JSGlobalContext to set the callback on.
164
@param function The callback function to set, which receives the promise and rejection reason as arguments.
165
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
166
*/
167
JS_EXPORT void JSGlobalContextSetUnhandledRejectionCallback(JSGlobalContextRef ctx, JSObjectRef function, JSValueRef* exception);
168
169
/*!
170
@function
171
@abstract Sets the "late-handled promise rejection" callback for a context.
172
@discussion JSC-only alternative to window.addEventListener('rejectionhandled').
173
@param ctx The JSGlobalContext to set the callback on.
174
@param function The callback function to set, which receives the promise and rejection reason as arguments.
175
@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
176
*/
177
JS_EXPORT void JSGlobalContextSetRejectionHandledCallback(JSGlobalContextRef ctx, JSObjectRef function, JSValueRef* exception);
178
159
#ifdef __cplusplus
179
#ifdef __cplusplus
160
}
180
}
161
#endif
181
#endif
- a/Source/JavaScriptCore/API/tests/testapi.cpp -4 / +45 lines
Lines 137-142 public: a/Source/JavaScriptCore/API/tests/testapi.cpp_sec1
137
    void symbolsDeletePropertyForKey();
137
    void symbolsDeletePropertyForKey();
138
    void promiseResolveTrue();
138
    void promiseResolveTrue();
139
    void promiseRejectTrue();
139
    void promiseRejectTrue();
140
    void promiseRejectionCallbacks();
140
141
141
    int failed() const { return m_failed; }
142
    int failed() const { return m_failed; }
142
143
Lines 454-460 void TestAPI::promiseResolveTrue() a/Source/JavaScriptCore/API/tests/testapi.cpp_sec2
454
455
455
    auto trueValue = JSValueMakeBoolean(context, true);
456
    auto trueValue = JSValueMakeBoolean(context, true);
456
    JSObjectCallAsFunction(context, resolve, resolve, 1, &trueValue, &exception);
457
    JSObjectCallAsFunction(context, resolve, resolve, 1, &trueValue, &exception);
457
    check(!exception, "No exception should be thrown resolve promise");
458
    check(!exception, "No exception should be thrown resolving promise");
458
    check(passedTrueCalled, "then response function should have been called.");
459
    check(passedTrueCalled, "then response function should have been called.");
459
}
460
}
460
461
Lines 479-485 void TestAPI::promiseRejectTrue() a/Source/JavaScriptCore/API/tests/testapi.cpp_sec3
479
480
480
    APIString catchString("catch");
481
    APIString catchString("catch");
481
    JSValueRef catchFunction = JSObjectGetProperty(context, promise, catchString, &exception);
482
    JSValueRef catchFunction = JSObjectGetProperty(context, promise, catchString, &exception);
482
    check(!exception && catchFunction && JSValueIsObject(context, catchFunction), "Promise should have a then object property");
483
    check(!exception && catchFunction && JSValueIsObject(context, catchFunction), "Promise should have a catch object property");
483
484
484
    JSValueRef passedTrueFunction = JSObjectMakeFunctionWithCallback(context, trueString, passedTrue);
485
    JSValueRef passedTrueFunction = JSObjectMakeFunctionWithCallback(context, trueString, passedTrue);
485
    JSObjectCallAsFunction(context, const_cast<JSObjectRef>(catchFunction), promise, 1, &passedTrueFunction, &exception);
486
    JSObjectCallAsFunction(context, const_cast<JSObjectRef>(catchFunction), promise, 1, &passedTrueFunction, &exception);
Lines 487-494 void TestAPI::promiseRejectTrue() a/Source/JavaScriptCore/API/tests/testapi.cpp_sec4
487
488
488
    auto trueValue = JSValueMakeBoolean(context, true);
489
    auto trueValue = JSValueMakeBoolean(context, true);
489
    JSObjectCallAsFunction(context, reject, reject, 1, &trueValue, &exception);
490
    JSObjectCallAsFunction(context, reject, reject, 1, &trueValue, &exception);
490
    check(!exception, "No exception should be thrown resolve promise");
491
    check(!exception, "No exception should be thrown rejecting promise");
491
    check(passedTrueCalled, "then response function should have been called.");
492
    check(passedTrueCalled, "catch response function should have been called.");
493
}
494
495
void TestAPI::promiseRejectionCallbacks()
496
{
497
    JSObjectRef reject;
498
    JSValueRef exception = nullptr;
499
    static auto promise = JSObjectMakeDeferredPromise(context, nullptr, &reject, &exception);
500
    check(!exception, "creating a (reject-only) deferred promise should not throw");
501
    static auto reason = JSValueMakeString(context, APIString("reason"));
502
503
    static TestAPI* tester = this;
504
    static auto callbackCallCount = 0;
505
506
    auto callback = [](JSContextRef ctx, JSObjectRef, JSObjectRef, size_t argumentCount, const JSValueRef arguments[], JSValueRef*) -> JSValueRef {
507
        tester->check(argumentCount && JSValueIsStrictEqual(ctx, arguments[0], promise), "callback should receive rejected promise as first argument");
508
        tester->check(argumentCount > 1 && JSValueIsStrictEqual(ctx, arguments[1], reason), "callback should receive rejection reason as second argument");
509
        tester->check(argumentCount == 2, "callback should not receive a third argument");
510
        callbackCallCount++;
511
        return JSValueMakeUndefined(ctx);
512
    };
513
    auto callbackFunction = JSObjectMakeFunctionWithCallback(context, APIString("callback"), callback);
514
515
    JSGlobalContextSetUnhandledRejectionCallback(context, callbackFunction, &exception);
516
    check(!exception, "setting unhandled rejection callback should not throw");
517
518
    JSObjectCallAsFunction(context, reject, reject, 1, &reason, &exception);
519
    check(!exception && callbackCallCount == 1, "unhandled rejection callback should be called upon unhandled rejection");
520
521
    auto noopFunction = JSObjectMakeFunction(context, APIString("noop"), 0, nullptr, APIString(""), nullptr, 1, &exception);
522
    check(!exception, "creating a no-op function should not throw");
523
524
    JSGlobalContextSetUnhandledRejectionCallback(context, noopFunction, &exception);
525
    check(!exception, "resetting unhandled rejection callback should not throw");
526
    JSGlobalContextSetRejectionHandledCallback(context, callbackFunction, &exception);
527
    check(!exception, "setting rejection handled callback should not throw");
528
529
    auto catchFunction = JSObjectGetProperty(context, promise, APIString("catch"), &exception);
530
    JSObjectCallAsFunction(context, const_cast<JSObjectRef>(catchFunction), promise, 1, &noopFunction, &exception);
531
    check(!exception && callbackCallCount == 2, "rejection handled callback should be called upon late-handled rejection");
492
}
532
}
493
533
494
#define RUN(test) do {                                 \
534
#define RUN(test) do {                                 \
Lines 521-526 int testCAPIViaCpp(const char* filter) a/Source/JavaScriptCore/API/tests/testapi.cpp_sec5
521
    RUN(symbolsDeletePropertyForKey());
561
    RUN(symbolsDeletePropertyForKey());
522
    RUN(promiseResolveTrue());
562
    RUN(promiseResolveTrue());
523
    RUN(promiseRejectTrue());
563
    RUN(promiseRejectTrue());
564
    RUN(promiseRejectionCallbacks());
524
565
525
    if (tasks.isEmpty()) {
566
    if (tasks.isEmpty()) {
526
        dataLogLn("Filtered all tests: ERROR");
567
        dataLogLn("Filtered all tests: ERROR");
- a/Source/JavaScriptCore/jsc.cpp +32 lines
Lines 377-382 static EncodedJSValue JSC_HOST_CALL functionDisableRichSourceInfo(ExecState*); a/Source/JavaScriptCore/jsc.cpp_sec1
377
static EncodedJSValue JSC_HOST_CALL functionMallocInALoop(ExecState*);
377
static EncodedJSValue JSC_HOST_CALL functionMallocInALoop(ExecState*);
378
static EncodedJSValue JSC_HOST_CALL functionTotalCompileTime(ExecState*);
378
static EncodedJSValue JSC_HOST_CALL functionTotalCompileTime(ExecState*);
379
379
380
static EncodedJSValue JSC_HOST_CALL functionSetUnhandledRejectionCallback(ExecState*);
381
static EncodedJSValue JSC_HOST_CALL functionSetRejectionHandledCallback(ExecState*);
382
380
struct Script {
383
struct Script {
381
    enum class StrictMode {
384
    enum class StrictMode {
382
        Strict,
385
        Strict,
Lines 631-636 protected: a/Source/JavaScriptCore/jsc.cpp_sec2
631
        addFunction(vm, "disableRichSourceInfo", functionDisableRichSourceInfo, 0);
634
        addFunction(vm, "disableRichSourceInfo", functionDisableRichSourceInfo, 0);
632
        addFunction(vm, "mallocInALoop", functionMallocInALoop, 0);
635
        addFunction(vm, "mallocInALoop", functionMallocInALoop, 0);
633
        addFunction(vm, "totalCompileTime", functionTotalCompileTime, 0);
636
        addFunction(vm, "totalCompileTime", functionTotalCompileTime, 0);
637
638
        addFunction(vm, "setUnhandledRejectionCallback", functionSetUnhandledRejectionCallback, 1);
639
        addFunction(vm, "setRejectionHandledCallback", functionSetRejectionHandledCallback, 1);
634
    }
640
    }
635
    
641
    
636
    void addFunction(VM& vm, JSObject* object, const char* name, NativeFunction function, unsigned arguments)
642
    void addFunction(VM& vm, JSObject* object, const char* name, NativeFunction function, unsigned arguments)
Lines 2383-2388 static EncodedJSValue JSC_HOST_CALL functionWebAssemblyMemoryMode(ExecState* exe a/Source/JavaScriptCore/jsc.cpp_sec3
2383
2389
2384
#endif // ENABLE(WEBASSEMBLY)
2390
#endif // ENABLE(WEBASSEMBLY)
2385
2391
2392
EncodedJSValue JSC_HOST_CALL functionSetUnhandledRejectionCallback(ExecState* exec)
2393
{
2394
    VM& vm = exec->vm();
2395
    JSObject* object = exec->argument(0).getObject();
2396
    auto scope = DECLARE_THROW_SCOPE(vm);
2397
2398
    if (!object || !object->isFunction(vm))
2399
        return throwVMTypeError(exec, scope);
2400
2401
    exec->lexicalGlobalObject()->setUnhandledRejectionCallback(vm, object);
2402
    return JSValue::encode(jsUndefined());
2403
}
2404
2405
EncodedJSValue JSC_HOST_CALL functionSetRejectionHandledCallback(ExecState* exec)
2406
{
2407
    VM& vm = exec->vm();
2408
    JSObject* object = exec->argument(0).getObject();
2409
    auto scope = DECLARE_THROW_SCOPE(vm);
2410
2411
    if (!object || !object->isFunction(vm))
2412
        return throwVMTypeError(exec, scope);
2413
2414
    exec->lexicalGlobalObject()->setRejectionHandledCallback(vm, object);
2415
    return JSValue::encode(jsUndefined());
2416
}
2417
2386
// Use SEH for Release builds only to get rid of the crash report dialog
2418
// Use SEH for Release builds only to get rid of the crash report dialog
2387
// (luckily the same tests fail in Release and Debug builds so far). Need to
2419
// (luckily the same tests fail in Release and Debug builds so far). Need to
2388
// be in a separate main function because the jscmain function requires object
2420
// be in a separate main function because the jscmain function requires object
- a/Source/JavaScriptCore/runtime/JSGlobalObject.h +9 lines
Lines 427-432 public: a/Source/JavaScriptCore/runtime/JSGlobalObject.h_sec1
427
427
428
    String m_name;
428
    String m_name;
429
429
430
    Strong<JSObject> m_unhandledRejectionCallback;
431
    Strong<JSObject> m_rejectionHandledCallback;
432
430
    Debugger* m_debugger;
433
    Debugger* m_debugger;
431
434
432
    VM& m_vm;
435
    VM& m_vm;
Lines 807-812 public: a/Source/JavaScriptCore/runtime/JSGlobalObject.h_sec2
807
    void setName(const String&);
810
    void setName(const String&);
808
    const String& name() const { return m_name; }
811
    const String& name() const { return m_name; }
809
812
813
    void setUnhandledRejectionCallback(VM& vm, JSObject* function) { m_unhandledRejectionCallback.set(vm, function); }
814
    JSObject* unhandledRejectionCallback() const { return m_unhandledRejectionCallback.get(); }
815
816
    void setRejectionHandledCallback(VM& vm, JSObject* function) { m_rejectionHandledCallback.set(vm, function); }
817
    JSObject* rejectionHandledCallback() const { return m_rejectionHandledCallback.get(); }
818
810
    JSObject* arrayBufferConstructor() const { return m_arrayBufferStructure.constructor(this); }
819
    JSObject* arrayBufferConstructor() const { return m_arrayBufferStructure.constructor(this); }
811
820
812
    JSObject* arrayBufferPrototype(ArrayBufferSharingMode sharingMode) const
821
    JSObject* arrayBufferPrototype(ArrayBufferSharingMode sharingMode) const
- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp -3 / +16 lines
Lines 766-775 EncodedJSValue JSC_HOST_CALL globalFuncHostPromiseRejectionTracker(ExecState* ex a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp_sec1
766
    VM& vm = globalObject->vm();
766
    VM& vm = globalObject->vm();
767
    auto scope = DECLARE_THROW_SCOPE(vm);
767
    auto scope = DECLARE_THROW_SCOPE(vm);
768
768
769
    if (!globalObject->globalObjectMethodTable()->promiseRejectionTracker)
769
    JSPromise* promise = jsCast<JSPromise*>(exec->argument(0));
770
771
    // InternalPromises should not be exposed to user scripts.
772
    if (promise->inherits<JSInternalPromise>(vm))
770
        return JSValue::encode(jsUndefined());
773
        return JSValue::encode(jsUndefined());
771
774
772
    JSPromise* promise = jsCast<JSPromise*>(exec->argument(0));
773
    JSValue operationValue = exec->argument(1);
775
    JSValue operationValue = exec->argument(1);
774
776
775
    ASSERT(operationValue.isNumber());
777
    ASSERT(operationValue.isNumber());
Lines 777-783 EncodedJSValue JSC_HOST_CALL globalFuncHostPromiseRejectionTracker(ExecState* ex a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp_sec2
777
    ASSERT(operation == JSPromiseRejectionOperation::Reject || operation == JSPromiseRejectionOperation::Handle);
779
    ASSERT(operation == JSPromiseRejectionOperation::Reject || operation == JSPromiseRejectionOperation::Handle);
778
    scope.assertNoException();
780
    scope.assertNoException();
779
781
780
    globalObject->globalObjectMethodTable()->promiseRejectionTracker(globalObject, exec, promise, operation);
782
    if (globalObject->globalObjectMethodTable()->promiseRejectionTracker)
783
        globalObject->globalObjectMethodTable()->promiseRejectionTracker(globalObject, exec, promise, operation);
784
    else {
785
        switch (operation) {
786
        case JSPromiseRejectionOperation::Reject:
787
            vm.promiseRejected(promise);
788
            break;
789
        case JSPromiseRejectionOperation::Handle:
790
            vm.promiseHandled(promise);
791
            break;
792
        }
793
    }
781
    RETURN_IF_EXCEPTION(scope, { });
794
    RETURN_IF_EXCEPTION(scope, { });
782
795
783
    return JSValue::encode(jsUndefined());
796
    return JSValue::encode(jsUndefined());
- a/Source/JavaScriptCore/runtime/VM.cpp +80 lines
Lines 317-322 VM::VM(VMType vmType, HeapType heapType) a/Source/JavaScriptCore/runtime/VM.cpp_sec1
317
    , m_typeProfilerEnabledCount(0)
317
    , m_typeProfilerEnabledCount(0)
318
    , m_primitiveGigacageEnabled(IsWatched)
318
    , m_primitiveGigacageEnabled(IsWatched)
319
    , m_controlFlowProfilerEnabledCount(0)
319
    , m_controlFlowProfilerEnabledCount(0)
320
    , m_outstandingRejectedPromises(*this)
320
{
321
{
321
    if (UNLIKELY(vmCreationShouldCrash))
322
    if (UNLIKELY(vmCreationShouldCrash))
322
        CRASH_WITH_INFO(0x4242424220202020, 0xbadbeef0badbeef, 0x1234123412341234, 0x1337133713371337);
323
        CRASH_WITH_INFO(0x4242424220202020, 0xbadbeef0badbeef, 0x1234123412341234, 0x1337133713371337);
Lines 1089-1094 void VM::queueMicrotask(JSGlobalObject& globalObject, Ref<Microtask>&& task) a/Source/JavaScriptCore/runtime/VM.cpp_sec2
1089
    m_microtaskQueue.append(std::make_unique<QueuedTask>(*this, &globalObject, WTFMove(task)));
1090
    m_microtaskQueue.append(std::make_unique<QueuedTask>(*this, &globalObject, WTFMove(task)));
1090
}
1091
}
1091
1092
1093
void VM::callPromiseRejectionCallback(JSPromiseRejectionOperation operation, JSPromise* promise)
1094
{
1095
    JSObject* callback = operation == JSPromiseRejectionOperation::Reject
1096
        ? promise->globalObject()->unhandledRejectionCallback()
1097
        : promise->globalObject()->rejectionHandledCallback();
1098
1099
    if (!callback)
1100
        return;
1101
1102
    auto scope = DECLARE_CATCH_SCOPE(*this);
1103
1104
    CallData callData;
1105
    CallType callType = getCallData(*this, callback, callData);
1106
    ASSERT(callType != CallType::None);
1107
1108
    MarkedArgumentBuffer args;
1109
    args.append(promise);
1110
    args.append(promise->result(*this));
1111
    call(promise->globalObject()->globalExec(), callback, callType, callData, jsNull(), args);
1112
    scope.clearException();
1113
}
1114
1115
void VM::reportUnhandledRejectionsSoon()
1116
{
1117
    if (m_aboutToBeNotifiedRejectedPromises.isEmpty())
1118
        return;
1119
1120
    auto scope = DECLARE_THROW_SCOPE(*this);
1121
    JSGlobalObject* globalObject = m_aboutToBeNotifiedRejectedPromises.first()->globalObject();
1122
    JSPromiseDeferred* deferred = JSPromiseDeferred::tryCreate(globalObject->globalExec(), globalObject);
1123
    RETURN_IF_EXCEPTION(scope, void());
1124
1125
    promiseDeferredTimer->addPendingPromise(*this, deferred, { });
1126
1127
    promiseDeferredTimer->scheduleWorkSoon(deferred, [this, deferred, unhandledRejections = WTFMove(m_aboutToBeNotifiedRejectedPromises)] () {
1128
        for (auto& promise : unhandledRejections) {
1129
            if (promise->isHandled(*this))
1130
                continue;
1131
1132
            callPromiseRejectionCallback(JSPromiseRejectionOperation::Reject, promise.get());
1133
1134
            if (!promise->isHandled(*this))
1135
                m_outstandingRejectedPromises.set(promise.get(), promise.get());
1136
        }
1137
        deferred->resolve(unhandledRejections.first()->globalObject()->globalExec(), jsUndefined());
1138
    });
1139
}
1140
1141
void VM::promiseRejected(JSPromise* promise)
1142
{
1143
    m_aboutToBeNotifiedRejectedPromises.constructAndAppend(*this, promise);
1144
}
1145
1146
void VM::promiseHandled(JSPromise* promise)
1147
{
1148
    bool wasNotReported = m_aboutToBeNotifiedRejectedPromises.removeFirstMatching([promise] (Strong<JSPromise>& unhandledPromise) {
1149
        return unhandledPromise.get() == promise;
1150
    });
1151
1152
    if (wasNotReported || !m_outstandingRejectedPromises.remove(promise))
1153
        return;
1154
1155
    auto scope = DECLARE_THROW_SCOPE(*this);
1156
    JSGlobalObject* globalObject = promise->globalObject();
1157
    JSPromiseDeferred* deferred = JSPromiseDeferred::tryCreate(globalObject->globalExec(), globalObject);
1158
    RETURN_IF_EXCEPTION(scope, void());
1159
1160
    // Vector<Strong<JSCell>> dependencies;
1161
    // dependencies.append(Strong<JSCell>(*this, promise));
1162
    // promiseDeferredTimer->addPendingPromise(*this, deferred, WTFMove(dependencies));
1163
    promiseDeferredTimer->addPendingPromise(*this, deferred, { });
1164
1165
    promiseDeferredTimer->scheduleWorkSoon(deferred, [this, deferred, promise] () {
1166
        callPromiseRejectionCallback(JSPromiseRejectionOperation::Handle, promise);
1167
        deferred->resolve(promise->globalObject()->globalExec(), jsUndefined());
1168
    });
1169
}
1170
1092
void VM::drainMicrotasks()
1171
void VM::drainMicrotasks()
1093
{
1172
{
1094
    while (!m_microtaskQueue.isEmpty()) {
1173
    while (!m_microtaskQueue.isEmpty()) {
Lines 1097-1102 void VM::drainMicrotasks() a/Source/JavaScriptCore/runtime/VM.cpp_sec3
1097
            m_onEachMicrotaskTick(*this);
1176
            m_onEachMicrotaskTick(*this);
1098
    }
1177
    }
1099
    finalizeSynchronousJSExecution();
1178
    finalizeSynchronousJSExecution();
1179
    reportUnhandledRejectionsSoon();
1100
}
1180
}
1101
1181
1102
void QueuedTask::run()
1182
void QueuedTask::run()
- a/Source/JavaScriptCore/runtime/VM.h +12 lines
Lines 123-128 class JSCustomGetterSetterFunction; a/Source/JavaScriptCore/runtime/VM.h_sec1
123
class JSDestructibleObjectHeapCellType;
123
class JSDestructibleObjectHeapCellType;
124
class JSGlobalObject;
124
class JSGlobalObject;
125
class JSObject;
125
class JSObject;
126
class JSPromise;
126
class JSRunLoopTimer;
127
class JSRunLoopTimer;
127
class JSStringHeapCellType;
128
class JSStringHeapCellType;
128
class JSWebAssemblyCodeBlockHeapCellType;
129
class JSWebAssemblyCodeBlockHeapCellType;
Lines 172-177 namespace DOMJIT { a/Source/JavaScriptCore/runtime/VM.h_sec2
172
class Signature;
173
class Signature;
173
}
174
}
174
175
176
enum class JSPromiseRejectionOperation : unsigned;
177
175
struct EntryFrame;
178
struct EntryFrame;
176
struct HashTable;
179
struct HashTable;
177
struct Instruction;
180
struct Instruction;
Lines 916-921 public: a/Source/JavaScriptCore/runtime/VM.h_sec3
916
    void notifyNeedTermination() { m_traps.fireTrap(VMTraps::NeedTermination); }
919
    void notifyNeedTermination() { m_traps.fireTrap(VMTraps::NeedTermination); }
917
    void notifyNeedWatchdogCheck() { m_traps.fireTrap(VMTraps::NeedWatchdogCheck); }
920
    void notifyNeedWatchdogCheck() { m_traps.fireTrap(VMTraps::NeedWatchdogCheck); }
918
921
922
    void promiseRejected(JSPromise*);
923
    void promiseHandled(JSPromise*);
924
919
#if ENABLE(EXCEPTION_SCOPE_VERIFICATION)
925
#if ENABLE(EXCEPTION_SCOPE_VERIFICATION)
920
    StackTrace* nativeStackTraceOfLastThrow() const { return m_nativeStackTraceOfLastThrow.get(); }
926
    StackTrace* nativeStackTraceOfLastThrow() const { return m_nativeStackTraceOfLastThrow.get(); }
921
    Thread* throwingThread() const { return m_throwingThread.get(); }
927
    Thread* throwingThread() const { return m_throwingThread.get(); }
Lines 1001-1006 private: a/Source/JavaScriptCore/runtime/VM.h_sec4
1001
    static void primitiveGigacageDisabledCallback(void*);
1007
    static void primitiveGigacageDisabledCallback(void*);
1002
    void primitiveGigacageDisabled();
1008
    void primitiveGigacageDisabled();
1003
1009
1010
    void callPromiseRejectionCallback(JSPromiseRejectionOperation, JSPromise*);
1011
    void reportUnhandledRejectionsSoon();
1012
1004
#if ENABLE(GC_VALIDATION)
1013
#if ENABLE(GC_VALIDATION)
1005
    const ClassInfo* m_initializingObjectClass;
1014
    const ClassInfo* m_initializingObjectClass;
1006
#endif
1015
#endif
Lines 1056-1061 private: a/Source/JavaScriptCore/runtime/VM.h_sec5
1056
    std::unique_ptr<ShadowChicken> m_shadowChicken;
1065
    std::unique_ptr<ShadowChicken> m_shadowChicken;
1057
    std::unique_ptr<BytecodeIntrinsicRegistry> m_bytecodeIntrinsicRegistry;
1066
    std::unique_ptr<BytecodeIntrinsicRegistry> m_bytecodeIntrinsicRegistry;
1058
1067
1068
    Vector<Strong<JSPromise>> m_aboutToBeNotifiedRejectedPromises;
1069
    WeakGCMap<JSPromise*, JSPromise> m_outstandingRejectedPromises;
1070
1059
    WTF::Function<void(VM&)> m_onEachMicrotaskTick;
1071
    WTF::Function<void(VM&)> m_onEachMicrotaskTick;
1060
    uintptr_t m_currentWeakRefVersion { 0 };
1072
    uintptr_t m_currentWeakRefVersion { 0 };
1061
1073
- a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp -5 lines
Lines 216-231 void JSDOMGlobalObject::promiseRejectionTracker(JSGlobalObject* jsGlobalObject, a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp_sec1
216
{
216
{
217
    // https://html.spec.whatwg.org/multipage/webappapis.html#the-hostpromiserejectiontracker-implementation
217
    // https://html.spec.whatwg.org/multipage/webappapis.html#the-hostpromiserejectiontracker-implementation
218
218
219
    VM& vm = exec->vm();
220
    auto& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(jsGlobalObject);
219
    auto& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(jsGlobalObject);
221
    auto* context = globalObject.scriptExecutionContext();
220
    auto* context = globalObject.scriptExecutionContext();
222
    if (!context)
221
    if (!context)
223
        return;
222
        return;
224
223
225
    // InternalPromises should not be exposed to user scripts.
226
    if (JSC::jsDynamicCast<JSC::JSInternalPromise*>(vm, promise))
227
        return;
228
229
    // FIXME: If script has muted errors (cross origin), terminate these steps.
224
    // FIXME: If script has muted errors (cross origin), terminate these steps.
230
    // <https://webkit.org/b/171415> Implement the `muted-errors` property of Scripts to avoid onerror/onunhandledrejection for cross-origin scripts
225
    // <https://webkit.org/b/171415> Implement the `muted-errors` property of Scripts to avoid onerror/onunhandledrejection for cross-origin scripts
231
226

Return to Bug 197172