diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
commit | 32761a6cee1d0dee366b885b7b9c777e67885688 (patch) | |
tree | d6bec92bebfb216f4126356e55518842c2f476a1 /Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp | |
parent | a4e969f4965059196ca948db781e52f7cfebf19e (diff) | |
download | WebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz |
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp | 217 |
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 |