diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSPromiseDeferred.cpp | 225 |
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 |