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.cpp225
1 files changed, 54 insertions, 171 deletions
diff --git a/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp b/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp
index cbc42eb9f..7d3596c4d 100644
--- a/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp
+++ b/Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,29 +26,45 @@
#include "config.h"
#include "JSPromiseDeferred.h"
+#include "BuiltinNames.h"
#include "Error.h"
-#include "JSCJSValueInlines.h"
-#include "JSCellInlines.h"
+#include "Exception.h"
+#include "JSCInlines.h"
+#include "JSObjectInlines.h"
#include "JSPromise.h"
#include "JSPromiseConstructor.h"
-#include "JSPromiseFunctions.h"
-#include "SlotVisitorInlines.h"
namespace JSC {
-const ClassInfo JSPromiseDeferred::s_info = { "JSPromiseDeferred", 0, 0, 0, CREATE_METHOD_TABLE(JSPromiseDeferred) };
+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 != CallType::None);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(promiseConstructor);
+ return call(exec, newPromiseCapabilityFunction, callType, callData, jsUndefined(), arguments);
+}
+
JSPromiseDeferred* JSPromiseDeferred::create(ExecState* exec, JSGlobalObject* globalObject)
{
VM& vm = exec->vm();
-
- JSFunction* resolver = createDeferredConstructionFunction(vm, globalObject);
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSValue deferred = newPromiseCapability(exec, globalObject, globalObject->promiseConstructor());
+ RETURN_IF_EXCEPTION(scope, nullptr);
- JSPromise* promise = constructPromise(exec, globalObject, resolver);
- JSValue resolve = resolver->get(exec, vm.propertyNames->resolvePrivateName);
- JSValue reject = resolver->get(exec, vm.propertyNames->rejectPrivateName);
+ JSValue promise = deferred.get(exec, vm.propertyNames->builtinNames().promisePrivateName());
+ ASSERT(promise.inherits(vm, JSPromise::info()));
+ JSValue resolve = deferred.get(exec, vm.propertyNames->builtinNames().resolvePrivateName());
+ JSValue reject = deferred.get(exec, vm.propertyNames->builtinNames().rejectPrivateName());
- return JSPromiseDeferred::create(vm, promise, resolve, reject);
+ return JSPromiseDeferred::create(vm, jsCast<JSPromise*>(promise), resolve, reject);
}
JSPromiseDeferred* JSPromiseDeferred::create(VM& vm, JSObject* promise, JSValue resolve, JSValue reject)
@@ -59,188 +75,55 @@ JSPromiseDeferred* JSPromiseDeferred::create(VM& vm, JSObject* promise, JSValue
}
JSPromiseDeferred::JSPromiseDeferred(VM& vm)
- : Base(vm, vm.promiseDeferredStructure.get())
+ : JSPromiseDeferred(vm, vm.promiseDeferredStructure.get())
{
}
-void JSPromiseDeferred::finishCreation(VM& vm, JSObject* promise, JSValue resolve, JSValue reject)
+JSPromiseDeferred::JSPromiseDeferred(VM& vm, Structure* structure)
+ : Base(vm, structure)
{
- 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)
+static inline void callFunction(ExecState* exec, JSValue function, JSValue value)
{
- 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);
-}
-
-JSValue createJSPromiseDeferredFromConstructor(ExecState* exec, JSValue C)
-{
- // -- This implements the GetDeferred(C) abstract operation --
-
- // 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();
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ ASSERT(callType != CallType::None);
- // 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);
+ MarkedArgumentBuffer arguments;
+ arguments.append(value);
- // 9. Return the Deferred { [[Promise]]: promise, [[Resolve]]: resolve, [[Reject]]: reject }.
- return JSPromiseDeferred::create(exec->vm(), promise, resolve, reject);
+ call(exec, function, callType, callData, jsUndefined(), arguments);
}
-ThenableStatus updateDeferredFromPotentialThenable(ExecState* exec, JSValue x, JSPromiseDeferred* deferred)
+void JSPromiseDeferred::resolve(ExecState* exec, JSValue 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;
+ callFunction(exec, m_resolve.get(), value);
}
-void performDeferredResolve(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument)
+void JSPromiseDeferred::reject(ExecState* exec, JSValue 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);
+ callFunction(exec, m_reject.get(), reason);
}
-void performDeferredReject(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument)
+void JSPromiseDeferred::finishCreation(VM& vm, JSObject* promise, JSValue resolve, JSValue 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);
+ Base::finishCreation(vm);
+ m_promise.set(vm, this, promise);
+ m_resolve.set(vm, this, resolve);
+ m_reject.set(vm, this, reject);
}
-JSValue abruptRejection(ExecState* exec, JSPromiseDeferred* deferred)
+void JSPromiseDeferred::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
- ASSERT(exec->hadException());
- JSValue argument = exec->exception();
- exec->clearException();
-
- // 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);
+ JSPromiseDeferred* thisObject = jsCast<JSPromiseDeferred*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- // ii. ReturnIfAbrupt(rejectResult).
- if (exec->hadException())
- return jsUndefined();
+ Base::visitChildren(thisObject, visitor);
- // iii. Return deferred.[[Promise]].
- return deferred->promise();
+ visitor.append(thisObject->m_promise);
+ visitor.append(thisObject->m_resolve);
+ visitor.append(thisObject->m_reject);
}
} // namespace JSC