summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp')
-rw-r--r--Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp217
1 files changed, 167 insertions, 50 deletions
diff --git a/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp b/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp
index ba7697344..cbc42eb9f 100644
--- a/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp
+++ b/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp
@@ -26,45 +26,29 @@
#include "config.h"
#include "JSPromiseDeferred.h"
-#include "BuiltinNames.h"
#include "Error.h"
-#include "Exception.h"
#include "JSCJSValueInlines.h"
#include "JSCellInlines.h"
#include "JSPromise.h"
#include "JSPromiseConstructor.h"
+#include "JSPromiseFunctions.h"
#include "SlotVisitorInlines.h"
-#include "StructureInlines.h"
namespace JSC {
-const ClassInfo JSPromiseDeferred::s_info = { "JSPromiseDeferred", 0, 0, CREATE_METHOD_TABLE(JSPromiseDeferred) };
-
-JSValue newPromiseCapability(ExecState* exec, JSGlobalObject* globalObject, JSPromiseConstructor* promiseConstructor)
-{
- JSFunction* newPromiseCapabilityFunction = globalObject->newPromiseCapabilityFunction();
- CallData callData;
- CallType callType = JSC::getCallData(newPromiseCapabilityFunction, callData);
- ASSERT(callType != CallTypeNone);
-
- MarkedArgumentBuffer arguments;
- arguments.append(promiseConstructor);
- return call(exec, newPromiseCapabilityFunction, callType, callData, jsUndefined(), arguments);
-}
-
+const ClassInfo JSPromiseDeferred::s_info = { "JSPromiseDeferred", 0, 0, 0, CREATE_METHOD_TABLE(JSPromiseDeferred) };
JSPromiseDeferred* JSPromiseDeferred::create(ExecState* exec, JSGlobalObject* globalObject)
{
VM& vm = exec->vm();
+
+ JSFunction* resolver = createDeferredConstructionFunction(vm, globalObject);
- JSValue deferred = newPromiseCapability(exec, globalObject, globalObject->promiseConstructor());
-
- JSValue promise = deferred.get(exec, vm.propertyNames->promisePrivateName);
- ASSERT(promise.inherits(JSPromise::info()));
- JSValue resolve = deferred.get(exec, vm.propertyNames->builtinNames().resolvePrivateName());
- JSValue reject = deferred.get(exec, vm.propertyNames->builtinNames().rejectPrivateName());
+ JSPromise* promise = constructPromise(exec, globalObject, resolver);
+ JSValue resolve = resolver->get(exec, vm.propertyNames->resolvePrivateName);
+ JSValue reject = resolver->get(exec, vm.propertyNames->rejectPrivateName);
- return JSPromiseDeferred::create(vm, jsCast<JSPromise*>(promise), resolve, reject);
+ return JSPromiseDeferred::create(vm, promise, resolve, reject);
}
JSPromiseDeferred* JSPromiseDeferred::create(VM& vm, JSObject* promise, JSValue resolve, JSValue reject)
@@ -75,55 +59,188 @@ JSPromiseDeferred* JSPromiseDeferred::create(VM& vm, JSObject* promise, JSValue
}
JSPromiseDeferred::JSPromiseDeferred(VM& vm)
- : JSPromiseDeferred(vm, vm.promiseDeferredStructure.get())
+ : Base(vm, vm.promiseDeferredStructure.get())
{
}
-JSPromiseDeferred::JSPromiseDeferred(VM& vm, Structure* structure)
- : Base(vm, structure)
+void JSPromiseDeferred::finishCreation(VM& vm, JSObject* promise, JSValue resolve, JSValue reject)
+{
+ Base::finishCreation(vm);
+ m_promise.set(vm, this, promise);
+ m_resolve.set(vm, this, resolve);
+ m_reject.set(vm, this, reject);
+}
+
+void JSPromiseDeferred::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
+ JSPromiseDeferred* thisObject = jsCast<JSPromiseDeferred*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_promise);
+ visitor.append(&thisObject->m_resolve);
+ visitor.append(&thisObject->m_reject);
}
-static inline void callFunction(ExecState* exec, JSValue function, JSValue value)
+JSValue createJSPromiseDeferredFromConstructor(ExecState* exec, JSValue C)
{
- CallData callData;
- CallType callType = getCallData(function, callData);
- ASSERT(callType != CallTypeNone);
+ // -- This implements the GetDeferred(C) abstract operation --
- MarkedArgumentBuffer arguments;
- arguments.append(value);
+ // 1. If IsConstructor(C) is false, throw a TypeError.
+ if (!C.isObject())
+ return throwTypeError(exec);
+
+ ConstructData constructData;
+ ConstructType constructType = getConstructData(C, constructData);
+ if (constructType == ConstructTypeNone)
+ return throwTypeError(exec);
+
+ VM& vm = exec->vm();
- call(exec, function, callType, callData, jsUndefined(), arguments);
+ // 2. Let 'resolver' be a new built-in function object as defined in Deferred Construction Functions.
+ JSFunction* resolver = createDeferredConstructionFunction(vm, asObject(C)->globalObject());
+
+ // 3. Let 'promise' be the result of calling the [[Construct]] internal method of 'C' with
+ // an argument list containing the single item resolver.
+ MarkedArgumentBuffer constructArguments;
+ constructArguments.append(resolver);
+ JSObject* promise = construct(exec, C, constructType, constructData, constructArguments);
+
+ // 4. ReturnIfAbrupt(promise).
+ if (exec->hadException())
+ return jsUndefined();
+
+ // 5. Let 'resolve' be the value of resolver's [[Resolve]] internal slot.
+ JSValue resolve = resolver->get(exec, vm.propertyNames->resolvePrivateName);
+
+ // 6. If IsCallable(resolve) is false, throw a TypeError.
+ CallData resolveCallData;
+ CallType resolveCallType = getCallData(resolve, resolveCallData);
+ if (resolveCallType == CallTypeNone)
+ return throwTypeError(exec);
+
+ // 7. Let 'reject' be the value of resolver's [[Reject]] internal slot.
+ JSValue reject = resolver->get(exec, vm.propertyNames->rejectPrivateName);
+
+ // 8. If IsCallable(reject) is false, throw a TypeError.
+ CallData rejectCallData;
+ CallType rejectCallType = getCallData(reject, rejectCallData);
+ if (rejectCallType == CallTypeNone)
+ return throwTypeError(exec);
+
+ // 9. Return the Deferred { [[Promise]]: promise, [[Resolve]]: resolve, [[Reject]]: reject }.
+ return JSPromiseDeferred::create(exec->vm(), promise, resolve, reject);
}
-void JSPromiseDeferred::resolve(ExecState* exec, JSValue value)
+ThenableStatus updateDeferredFromPotentialThenable(ExecState* exec, JSValue x, JSPromiseDeferred* deferred)
{
- callFunction(exec, m_resolve.get(), value);
+ // 1. If Type(x) is not Object, return "not a thenable".
+ if (!x.isObject())
+ return NotAThenable;
+
+ // 2. Let 'then' be the result of calling Get(x, "then").
+ JSValue thenValue = x.get(exec, exec->vm().propertyNames->then);
+
+ // 3. If then is an abrupt completion,
+ if (exec->hadException()) {
+ // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of
+ // deferred.[[Reject]] with undefined as thisArgument and a List containing
+ // then.[[value]] as argumentsList.
+ JSValue exception = exec->exception();
+ exec->clearException();
+
+ performDeferredReject(exec, deferred, exception);
+
+ // ii. ReturnIfAbrupt(rejectResult).
+ // NOTE: Nothing to do.
+
+ // iii. Return.
+ return WasAThenable;
+ }
+
+ // 4. Let 'then' be then.[[value]].
+ // Note: Nothing to do.
+
+ // 5. If IsCallable(then) is false, return "not a thenable".
+ CallData thenCallData;
+ CallType thenCallType = getCallData(thenValue, thenCallData);
+ if (thenCallType == CallTypeNone)
+ return NotAThenable;
+
+ // 6. Let 'thenCallResult' be the result of calling the [[Call]] internal method of
+ // 'then' passing x as thisArgument and a List containing deferred.[[Resolve]] and
+ // deferred.[[Reject]] as argumentsList.
+ MarkedArgumentBuffer thenArguments;
+ thenArguments.append(deferred->resolve());
+ thenArguments.append(deferred->reject());
+
+ call(exec, thenValue, thenCallType, thenCallData, x, thenArguments);
+
+ // 7. If 'thenCallResult' is an abrupt completion,
+ if (exec->hadException()) {
+ // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of
+ // deferred.[[Reject]] with undefined as thisArgument and a List containing
+ // thenCallResult.[[value]] as argumentsList.
+ JSValue exception = exec->exception();
+ exec->clearException();
+
+ performDeferredReject(exec, deferred, exception);
+
+ // ii. ReturnIfAbrupt(rejectResult).
+ // NOTE: Nothing to do.
+ }
+
+ return WasAThenable;
}
-void JSPromiseDeferred::reject(ExecState* exec, JSValue reason)
+void performDeferredResolve(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument)
{
- callFunction(exec, m_reject.get(), reason);
+ JSValue deferredResolve = deferred->resolve();
+
+ CallData resolveCallData;
+ CallType resolveCallType = getCallData(deferredResolve, resolveCallData);
+ ASSERT(resolveCallType != CallTypeNone);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(argument);
+
+ call(exec, deferredResolve, resolveCallType, resolveCallData, jsUndefined(), arguments);
}
-void JSPromiseDeferred::finishCreation(VM& vm, JSObject* promise, JSValue resolve, JSValue reject)
+void performDeferredReject(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument)
{
- Base::finishCreation(vm);
- m_promise.set(vm, this, promise);
- m_resolve.set(vm, this, resolve);
- m_reject.set(vm, this, reject);
+ JSValue deferredReject = deferred->reject();
+
+ CallData rejectCallData;
+ CallType rejectCallType = getCallData(deferredReject, rejectCallData);
+ ASSERT(rejectCallType != CallTypeNone);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(argument);
+
+ call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), arguments);
}
-void JSPromiseDeferred::visitChildren(JSCell* cell, SlotVisitor& visitor)
+JSValue abruptRejection(ExecState* exec, JSPromiseDeferred* deferred)
{
- JSPromiseDeferred* thisObject = jsCast<JSPromiseDeferred*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ ASSERT(exec->hadException());
+ JSValue argument = exec->exception();
+ exec->clearException();
- Base::visitChildren(thisObject, visitor);
+ // i. Let 'rejectResult' be the result of calling the [[Call]] internal method
+ // of deferred.[[Reject]] with undefined as thisArgument and a List containing
+ // argument.[[value]] as argumentsList.
+ performDeferredReject(exec, deferred, argument);
- visitor.append(&thisObject->m_promise);
- visitor.append(&thisObject->m_resolve);
- visitor.append(&thisObject->m_reject);
+ // ii. ReturnIfAbrupt(rejectResult).
+ if (exec->hadException())
+ return jsUndefined();
+
+ // iii. Return deferred.[[Promise]].
+ return deferred->promise();
}
} // namespace JSC