зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1170760 part 6. Fix GetDependentPromise to deal with a situation when someone called then() and passed it the resolve/reject functions that come from a promise's constructor. r=baku
This commit is contained in:
Родитель
7e919bdf2d
Коммит
2296e841e7
|
@ -115,11 +115,6 @@ private:
|
|||
NS_DECL_OWNINGTHREAD;
|
||||
};
|
||||
|
||||
enum {
|
||||
SLOT_PROMISE = 0,
|
||||
SLOT_DATA
|
||||
};
|
||||
|
||||
/*
|
||||
* Utilities for thenable callbacks.
|
||||
*
|
||||
|
@ -134,9 +129,9 @@ void
|
|||
LinkThenableCallables(JSContext* aCx, JS::Handle<JSObject*> aResolveFunc,
|
||||
JS::Handle<JSObject*> aRejectFunc)
|
||||
{
|
||||
js::SetFunctionNativeReserved(aResolveFunc, SLOT_DATA,
|
||||
js::SetFunctionNativeReserved(aResolveFunc, Promise::SLOT_DATA,
|
||||
JS::ObjectValue(*aRejectFunc));
|
||||
js::SetFunctionNativeReserved(aRejectFunc, SLOT_DATA,
|
||||
js::SetFunctionNativeReserved(aRejectFunc, Promise::SLOT_DATA,
|
||||
JS::ObjectValue(*aResolveFunc));
|
||||
}
|
||||
|
||||
|
@ -147,18 +142,22 @@ LinkThenableCallables(JSContext* aCx, JS::Handle<JSObject*> aResolveFunc,
|
|||
bool
|
||||
MarkAsCalledIfNotCalledBefore(JSContext* aCx, JS::Handle<JSObject*> aFunc)
|
||||
{
|
||||
JS::Value otherFuncVal = js::GetFunctionNativeReserved(aFunc, SLOT_DATA);
|
||||
JS::Value otherFuncVal =
|
||||
js::GetFunctionNativeReserved(aFunc, Promise::SLOT_DATA);
|
||||
|
||||
if (!otherFuncVal.isObject()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject* otherFuncObj = &otherFuncVal.toObject();
|
||||
MOZ_ASSERT(js::GetFunctionNativeReserved(otherFuncObj, SLOT_DATA).isObject());
|
||||
MOZ_ASSERT(js::GetFunctionNativeReserved(otherFuncObj,
|
||||
Promise::SLOT_DATA).isObject());
|
||||
|
||||
// Break both references.
|
||||
js::SetFunctionNativeReserved(aFunc, SLOT_DATA, JS::UndefinedValue());
|
||||
js::SetFunctionNativeReserved(otherFuncObj, SLOT_DATA, JS::UndefinedValue());
|
||||
js::SetFunctionNativeReserved(aFunc, Promise::SLOT_DATA,
|
||||
JS::UndefinedValue());
|
||||
js::SetFunctionNativeReserved(otherFuncObj, Promise::SLOT_DATA,
|
||||
JS::UndefinedValue());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -166,7 +165,8 @@ MarkAsCalledIfNotCalledBefore(JSContext* aCx, JS::Handle<JSObject*> aFunc)
|
|||
Promise*
|
||||
GetPromise(JSContext* aCx, JS::Handle<JSObject*> aFunc)
|
||||
{
|
||||
JS::Value promiseVal = js::GetFunctionNativeReserved(aFunc, SLOT_PROMISE);
|
||||
JS::Value promiseVal = js::GetFunctionNativeReserved(aFunc,
|
||||
Promise::SLOT_PROMISE);
|
||||
|
||||
MOZ_ASSERT(promiseVal.isObject());
|
||||
|
||||
|
@ -700,6 +700,8 @@ Promise::JSCallbackThenableRejecter(JSContext* aCx,
|
|||
/* static */ JSObject*
|
||||
Promise::CreateFunction(JSContext* aCx, Promise* aPromise, int32_t aTask)
|
||||
{
|
||||
// If this function ever changes, make sure to update
|
||||
// WrapperPromiseCallback::GetDependentPromise.
|
||||
JSFunction* func = js::NewFunctionWithReserved(aCx, JSCallback,
|
||||
1 /* nargs */, 0 /* flags */,
|
||||
nullptr);
|
||||
|
|
|
@ -214,6 +214,11 @@ public:
|
|||
static void
|
||||
DispatchToMicroTask(nsIRunnable* aRunnable);
|
||||
|
||||
enum JSCallbackSlots {
|
||||
SLOT_PROMISE = 0,
|
||||
SLOT_DATA
|
||||
};
|
||||
|
||||
protected:
|
||||
struct PromiseCapability;
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jswrapper.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -309,6 +311,32 @@ WrapperPromiseCallback::Call(JSContext* aCx,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
Promise*
|
||||
WrapperPromiseCallback::GetDependentPromise()
|
||||
{
|
||||
// Per spec, various algorithms like all() and race() are actually implemented
|
||||
// in terms of calling then() but passing it the resolve/reject functions that
|
||||
// are passed as arguments to function passed to the Promise constructor.
|
||||
// That will cause the promise in question to hold on to a
|
||||
// WrapperPromiseCallback, but the dependent promise should really be the one
|
||||
// whose constructor those functions came from, not the about-to-be-ignored
|
||||
// return value of "then". So try to determine whether we're in that case and
|
||||
// if so go ahead and dig the dependent promise out of the function we have.
|
||||
JSObject* callable = mCallback->Callable();
|
||||
// Unwrap it, in case it's a cross-compartment wrapper. Our caller here is
|
||||
// system, so it's really ok to just go and unwrap.
|
||||
callable = js::UncheckedUnwrap(callable);
|
||||
if (JS_IsNativeFunction(callable, Promise::JSCallback)) {
|
||||
JS::Value promiseVal =
|
||||
js::GetFunctionNativeReserved(callable, Promise::SLOT_PROMISE);
|
||||
Promise* promise;
|
||||
UNWRAP_OBJECT(Promise, &promiseVal.toObject(), promise);
|
||||
return promise;
|
||||
}
|
||||
|
||||
return mNextPromise;
|
||||
}
|
||||
|
||||
// NativePromiseCallback
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(NativePromiseCallback,
|
||||
|
|
|
@ -57,10 +57,7 @@ public:
|
|||
nsresult Call(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue) override;
|
||||
|
||||
Promise* GetDependentPromise() override
|
||||
{
|
||||
return mNextPromise;
|
||||
}
|
||||
Promise* GetDependentPromise() override;
|
||||
|
||||
WrapperPromiseCallback(Promise* aNextPromise, JS::Handle<JSObject*> aGlobal,
|
||||
AnyCallback* aCallback);
|
||||
|
|
Загрузка…
Ссылка в новой задаче