JSValue JSWebNfc::requestAdapter(ExecState* exec) { JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject()); DeferredWrapper* deferredWrapper = new DeferredWrapper(exec, globalObject(), promiseDeferred); impl().requestAdapter(deferredWrapper); return promiseDeferred->promise(); }
JSValue JSSubtleCrypto::exportKey(ExecState* exec) { if (exec->argumentCount() < 2) return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); CryptoKeyFormat keyFormat; if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) { ASSERT(exec->hadException()); return jsUndefined(); } RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(exec->uncheckedArgument(1)); if (!key) return throwTypeError(exec); JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject()); DeferredWrapper wrapper(exec, globalObject(), promiseDeferred); auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable { wrapper.resolve(result); }; auto failureCallback = [wrapper]() mutable { wrapper.reject(nullptr); }; WebCore::exportKey(exec, keyFormat, *key, WTF::move(successCallback), WTF::move(failureCallback)); if (exec->hadException()) return jsUndefined(); return promiseDeferred->promise(); }
EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncReject(ExecState* exec) { // -- Promise.reject(x) -- JSValue r = exec->argument(0); // 1. Let 'C' be the this value. JSValue C = exec->thisValue(); // 2. Let 'deferred' be the result of calling GetDeferred(C). JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); // 3. ReturnIfAbrupt(deferred). if (exec->hadException()) return JSValue::encode(jsUndefined()); JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); // 4. Let 'rejectResult' be the result of calling the [[Call]] internal method // of deferred.[[Reject]] with undefined as thisArgument and a List containing r // as argumentsList. performDeferredReject(exec, deferred, r); // 5. ReturnIfAbrupt(resolveResult). if (exec->hadException()) return JSValue::encode(jsUndefined()); // 6. Return deferred.[[Promise]]. return JSValue::encode(deferred->promise()); }
JSValue JSMediaDevices::getUserMedia(ExecState* exec) { JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject()); DeferredWrapper wrapper(exec, globalObject(), promiseDeferred); Dictionary options(exec, exec->argument(0)); if (exec->hadException()) { Exception* exception = exec->exception(); exec->clearException(); wrapper.reject(exception->value()); return promiseDeferred->promise(); } if (!options.isObject()) { JSValue error = createTypeError(exec, "First argument of getUserMedia must be a valid Dictionary"); wrapper.reject(error); return promiseDeferred->promise(); } auto resolveCallback = [wrapper](MediaStream& stream) mutable { wrapper.resolve(&stream); }; auto rejectCallback = [wrapper](NavigatorUserMediaError& error) mutable { wrapper.reject(&error); }; ExceptionCode ec = 0; impl().getUserMedia(options, WTF::move(resolveCallback), WTF::move(rejectCallback), ec); if (ec) wrapper.reject(ec); return promiseDeferred->promise(); }
JSValue JSSubtleCrypto::verify(ExecState* exec) { if (exec->argumentCount() < 4) return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0)); if (!algorithm) { ASSERT(exec->hadException()); return jsUndefined(); } auto parameters = JSCryptoAlgorithmDictionary::createParametersForVerify(exec, algorithm->identifier(), exec->uncheckedArgument(0)); if (!parameters) { ASSERT(exec->hadException()); return jsUndefined(); } RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(exec->uncheckedArgument(1)); if (!key) return throwTypeError(exec); if (!key->allows(CryptoKeyUsageVerify)) { m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'verify'")); setDOMException(exec, NOT_SUPPORTED_ERR); return jsUndefined(); } CryptoOperationData signature; if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(2), signature)) { ASSERT(exec->hadException()); return jsUndefined(); } CryptoOperationData data; if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(3), data)) { ASSERT(exec->hadException()); return jsUndefined(); } JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject()); DeferredWrapper wrapper(exec, globalObject(), promiseDeferred); auto successCallback = [wrapper](bool result) mutable { wrapper.resolve(result); }; auto failureCallback = [wrapper]() mutable { wrapper.reject(nullptr); }; ExceptionCode ec = 0; algorithm->verify(*parameters, *key, signature, data, WTF::move(successCallback), WTF::move(failureCallback), ec); if (ec) { setDOMException(exec, ec); return jsUndefined(); } return promiseDeferred->promise(); }
JSValue JSSubtleCrypto::generateKey(ExecState* exec) { if (exec->argumentCount() < 1) return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0)); if (!algorithm) { ASSERT(exec->hadException()); return jsUndefined(); } auto parameters = JSCryptoAlgorithmDictionary::createParametersForGenerateKey(exec, algorithm->identifier(), exec->uncheckedArgument(0)); if (!parameters) { ASSERT(exec->hadException()); return jsUndefined(); } bool extractable = false; if (exec->argumentCount() >= 2) { extractable = exec->uncheckedArgument(1).toBoolean(exec); if (exec->hadException()) return jsUndefined(); } CryptoKeyUsage keyUsages = 0; if (exec->argumentCount() >= 3) { if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(2), keyUsages)) { ASSERT(exec->hadException()); return jsUndefined(); } } JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject()); DeferredWrapper wrapper(exec, globalObject(), promiseDeferred); auto successCallback = [wrapper](CryptoKey* key, CryptoKeyPair* keyPair) mutable { ASSERT(key || keyPair); ASSERT(!key || !keyPair); if (key) wrapper.resolve(key); else wrapper.resolve(keyPair); }; auto failureCallback = [wrapper]() mutable { wrapper.reject(nullptr); }; ExceptionCode ec = 0; algorithm->generateKey(*parameters, extractable, keyUsages, WTF::move(successCallback), WTF::move(failureCallback), ec); if (ec) { setDOMException(exec, ec); return jsUndefined(); } return promiseDeferred->promise(); }
EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncRace(ExecState* exec) { // -- Promise.race(iterable) -- JSValue iterable = exec->argument(0); VM& vm = exec->vm(); // 1. Let 'C' be the this value. JSValue C = exec->thisValue(); // 2. Let 'deferred' be the result of calling GetDeferred(C). JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); // 3. ReturnIfAbrupt(deferred). if (exec->hadException()) return JSValue::encode(jsUndefined()); JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); // 4. Let 'iterator' be the result of calling GetIterator(iterable). JSValue iteratorFunction = iterable.get(exec, vm.propertyNames->iteratorSymbol); if (exec->hadException()) return JSValue::encode(abruptRejection(exec, deferred)); CallData iteratorFunctionCallData; CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData); if (iteratorFunctionCallType == CallTypeNone) { throwTypeError(exec); return JSValue::encode(abruptRejection(exec, deferred)); } ArgList iteratorFunctionArguments; JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments); // 5. RejectIfAbrupt(iterator, deferred). if (exec->hadException()) return JSValue::encode(abruptRejection(exec, deferred)); performPromiseRaceLoop(exec, iterator, deferred, C); if (exec->hadException()) iteratorClose(exec, iterator); if (exec->hadException()) return JSValue::encode(abruptRejection(exec, deferred)); return JSValue::encode(deferred->promise()); }
EncodedJSValue JSC_HOST_CALL webAssemblyCompileFunc(ExecState* exec) { VM& vm = exec->vm(); auto catchScope = DECLARE_CATCH_SCOPE(vm); JSPromiseDeferred* promise = JSPromiseDeferred::create(exec, exec->lexicalGlobalObject()); RETURN_IF_EXCEPTION(catchScope, encodedJSValue()); // FIXME: Make this truly asynchronous: // https://bugs.webkit.org/show_bug.cgi?id=166016 JSValue module = WebAssemblyModuleConstructor::createModule(exec, exec->lexicalGlobalObject()->WebAssemblyModuleStructure()); if (Exception* exception = catchScope.exception()) { catchScope.clearException(); promise->reject(exec, exception); return JSValue::encode(promise->promise()); } promise->resolve(exec, module); return JSValue::encode(promise->promise()); }
JSValue JSSubtleCrypto::digest(ExecState* exec) { if (exec->argumentCount() < 2) return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(0)); if (!algorithm) { ASSERT(exec->hadException()); return jsUndefined(); } auto parameters = JSCryptoAlgorithmDictionary::createParametersForDigest(exec, algorithm->identifier(), exec->uncheckedArgument(0)); if (!parameters) { ASSERT(exec->hadException()); return jsUndefined(); } CryptoOperationData data; if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), data)) { ASSERT(exec->hadException()); return jsUndefined(); } JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject()); DeferredWrapper wrapper(exec, globalObject(), promiseDeferred); auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable { wrapper.resolve(result); }; auto failureCallback = [wrapper]() mutable { wrapper.reject(nullptr); }; ExceptionCode ec = 0; algorithm->digest(*parameters, data, WTF::move(successCallback), WTF::move(failureCallback), ec); if (ec) { setDOMException(exec, ec); return jsUndefined(); } return promiseDeferred->promise(); }
EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncResolve(ExecState* exec) { // -- Promise.resolve(x) -- JSValue x = exec->argument(0); // 1. Let 'C' be the this value. JSValue C = exec->thisValue(); // 2. If IsPromise(x) is true, JSPromise* promise = jsDynamicCast<JSPromise*>(x); if (promise) { // i. Let 'constructor' be the value of x's [[PromiseConstructor]] internal slot. JSValue constructor = promise->constructor(); // ii. If SameValue(constructor, C) is true, return x. if (sameValue(exec, constructor, C)) return JSValue::encode(x); } // 3. Let 'deferred' be the result of calling GetDeferred(C). JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); // 4. ReturnIfAbrupt(deferred). if (exec->hadException()) return JSValue::encode(jsUndefined()); JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); // 5. Let 'resolveResult' be the result of calling the [[Call]] internal method // of deferred.[[Resolve]] with undefined as thisArgument and a List containing x // as argumentsList. performDeferredResolve(exec, deferred, x); // 6. ReturnIfAbrupt(resolveResult). if (exec->hadException()) return JSValue::encode(jsUndefined()); // 7. Return deferred.[[Promise]]. return JSValue::encode(deferred->promise()); }
JSValue JSSubtleCrypto::unwrapKey(ExecState* exec) { if (exec->argumentCount() < 5) return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); CryptoKeyFormat keyFormat; if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) { ASSERT(exec->hadException()); return jsUndefined(); } CryptoOperationData wrappedKeyData; if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), wrappedKeyData)) { ASSERT(exec->hadException()); return jsUndefined(); } RefPtr<CryptoKey> unwrappingKey = JSCryptoKey::toWrapped(exec->uncheckedArgument(2)); if (!unwrappingKey) return throwTypeError(exec); if (!unwrappingKey->allows(CryptoKeyUsageUnwrapKey)) { m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'unwrapKey'")); setDOMException(exec, NOT_SUPPORTED_ERR); return jsUndefined(); } std::unique_ptr<CryptoAlgorithm> unwrapAlgorithm; std::unique_ptr<CryptoAlgorithmParameters> unwrapAlgorithmParameters; unwrapAlgorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(3)); if (!unwrapAlgorithm) { ASSERT(exec->hadException()); return jsUndefined(); } unwrapAlgorithmParameters = JSCryptoAlgorithmDictionary::createParametersForDecrypt(exec, unwrapAlgorithm->identifier(), exec->uncheckedArgument(3)); if (!unwrapAlgorithmParameters) { ASSERT(exec->hadException()); return jsUndefined(); } std::unique_ptr<CryptoAlgorithm> unwrappedKeyAlgorithm; std::unique_ptr<CryptoAlgorithmParameters> unwrappedKeyAlgorithmParameters; if (!exec->uncheckedArgument(4).isNull()) { unwrappedKeyAlgorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(4)); if (!unwrappedKeyAlgorithm) { ASSERT(exec->hadException()); return jsUndefined(); } unwrappedKeyAlgorithmParameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(exec, unwrappedKeyAlgorithm->identifier(), exec->uncheckedArgument(4)); if (!unwrappedKeyAlgorithmParameters) { ASSERT(exec->hadException()); return jsUndefined(); } } bool extractable = false; if (exec->argumentCount() >= 6) { extractable = exec->uncheckedArgument(5).toBoolean(exec); if (exec->hadException()) return jsUndefined(); } CryptoKeyUsage keyUsages = 0; if (exec->argumentCount() >= 7) { if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(6), keyUsages)) { ASSERT(exec->hadException()); return jsUndefined(); } } JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject()); DeferredWrapper wrapper(exec, globalObject(), promiseDeferred); Strong<JSDOMGlobalObject> domGlobalObject(exec->vm(), globalObject()); CryptoAlgorithm* unwrappedKeyAlgorithmPtr = unwrappedKeyAlgorithm.release(); CryptoAlgorithmParameters* unwrappedKeyAlgorithmParametersPtr = unwrappedKeyAlgorithmParameters.release(); auto decryptSuccessCallback = [domGlobalObject, keyFormat, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr, extractable, keyUsages, wrapper](const Vector<uint8_t>& result) mutable { auto importSuccessCallback = [wrapper](CryptoKey& key) mutable { wrapper.resolve(&key); }; auto importFailureCallback = [wrapper]() mutable { wrapper.reject(nullptr); }; ExecState* exec = domGlobalObject->globalExec(); WebCore::importKey(exec, keyFormat, std::make_pair(result.data(), result.size()), std::unique_ptr<CryptoAlgorithm>(unwrappedKeyAlgorithmPtr), std::unique_ptr<CryptoAlgorithmParameters>(unwrappedKeyAlgorithmParametersPtr), extractable, keyUsages, WTF::move(importSuccessCallback), WTF::move(importFailureCallback)); if (exec->hadException()) { // FIXME: Report exception details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions. exec->clearException(); importFailureCallback(); } }; auto decryptFailureCallback = [wrapper, unwrappedKeyAlgorithmPtr, unwrappedKeyAlgorithmParametersPtr]() mutable { delete unwrappedKeyAlgorithmPtr; delete unwrappedKeyAlgorithmParametersPtr; wrapper.reject(nullptr); }; ExceptionCode ec = 0; unwrapAlgorithm->decryptForUnwrapKey(*unwrapAlgorithmParameters, *unwrappingKey, wrappedKeyData, WTF::move(decryptSuccessCallback), WTF::move(decryptFailureCallback), ec); if (ec) { delete unwrappedKeyAlgorithmPtr; delete unwrappedKeyAlgorithmParametersPtr; setDOMException(exec, ec); return jsUndefined(); } return promiseDeferred->promise(); }
JSValue JSSubtleCrypto::wrapKey(ExecState* exec) { if (exec->argumentCount() < 4) return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); CryptoKeyFormat keyFormat; if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) { ASSERT(exec->hadException()); return jsUndefined(); } RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(exec->uncheckedArgument(1)); if (!key) return throwTypeError(exec); RefPtr<CryptoKey> wrappingKey = JSCryptoKey::toWrapped(exec->uncheckedArgument(2)); if (!key) return throwTypeError(exec); if (!wrappingKey->allows(CryptoKeyUsageWrapKey)) { m_impl->document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'wrapKey'")); setDOMException(exec, NOT_SUPPORTED_ERR); return jsUndefined(); } auto algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(3)); if (!algorithm) { ASSERT(exec->hadException()); return jsUndefined(); } auto parameters = JSCryptoAlgorithmDictionary::createParametersForEncrypt(exec, algorithm->identifier(), exec->uncheckedArgument(3)); if (!parameters) { ASSERT(exec->hadException()); return jsUndefined(); } JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject()); DeferredWrapper wrapper(exec, globalObject(), promiseDeferred); CryptoAlgorithm* algorithmPtr = algorithm.release(); CryptoAlgorithmParameters* parametersPtr = parameters.release(); auto exportSuccessCallback = [keyFormat, algorithmPtr, parametersPtr, wrappingKey, wrapper](const Vector<uint8_t>& exportedKeyData) mutable { auto encryptSuccessCallback = [wrapper, algorithmPtr, parametersPtr](const Vector<uint8_t>& encryptedData) mutable { delete algorithmPtr; delete parametersPtr; wrapper.resolve(encryptedData); }; auto encryptFailureCallback = [wrapper, algorithmPtr, parametersPtr]() mutable { delete algorithmPtr; delete parametersPtr; wrapper.reject(nullptr); }; ExceptionCode ec = 0; algorithmPtr->encryptForWrapKey(*parametersPtr, *wrappingKey, std::make_pair(exportedKeyData.data(), exportedKeyData.size()), WTF::move(encryptSuccessCallback), WTF::move(encryptFailureCallback), ec); if (ec) { // FIXME: Report failure details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions. encryptFailureCallback(); } }; auto exportFailureCallback = [wrapper, algorithmPtr, parametersPtr]() mutable { delete algorithmPtr; delete parametersPtr; wrapper.reject(nullptr); }; ExceptionCode ec = 0; WebCore::exportKey(exec, keyFormat, *key, WTF::move(exportSuccessCallback), WTF::move(exportFailureCallback)); if (ec) { delete algorithmPtr; delete parametersPtr; setDOMException(exec, ec); return jsUndefined(); } return promiseDeferred->promise(); }
JSValue JSSubtleCrypto::importKey(ExecState* exec) { if (exec->argumentCount() < 3) return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); CryptoKeyFormat keyFormat; if (!cryptoKeyFormatFromJSValue(exec, exec->argument(0), keyFormat)) { ASSERT(exec->hadException()); return jsUndefined(); } CryptoOperationData data; if (!cryptoOperationDataFromJSValue(exec, exec->uncheckedArgument(1), data)) { ASSERT(exec->hadException()); return jsUndefined(); } std::unique_ptr<CryptoAlgorithm> algorithm; std::unique_ptr<CryptoAlgorithmParameters> parameters; if (!exec->uncheckedArgument(2).isNull()) { algorithm = createAlgorithmFromJSValue(exec, exec->uncheckedArgument(2)); if (!algorithm) { ASSERT(exec->hadException()); return jsUndefined(); } parameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(exec, algorithm->identifier(), exec->uncheckedArgument(2)); if (!parameters) { ASSERT(exec->hadException()); return jsUndefined(); } } bool extractable = false; if (exec->argumentCount() >= 4) { extractable = exec->uncheckedArgument(3).toBoolean(exec); if (exec->hadException()) return jsUndefined(); } CryptoKeyUsage keyUsages = 0; if (exec->argumentCount() >= 5) { if (!cryptoKeyUsagesFromJSValue(exec, exec->argument(4), keyUsages)) { ASSERT(exec->hadException()); return jsUndefined(); } } JSPromiseDeferred* promiseDeferred = JSPromiseDeferred::create(exec, globalObject()); DeferredWrapper wrapper(exec, globalObject(), promiseDeferred); auto successCallback = [wrapper](CryptoKey& result) mutable { wrapper.resolve(&result); }; auto failureCallback = [wrapper]() mutable { wrapper.reject(nullptr); }; WebCore::importKey(exec, keyFormat, data, WTF::move(algorithm), WTF::move(parameters), extractable, keyUsages, WTF::move(successCallback), WTF::move(failureCallback)); if (exec->hadException()) return jsUndefined(); return promiseDeferred->promise(); }
JSPromiseDeferred* JSPromiseDeferred::create(VM& vm, JSObject* promise, JSValue resolve, JSValue reject) { JSPromiseDeferred* deferred = new (NotNull, allocateCell<JSPromiseDeferred>(vm.heap)) JSPromiseDeferred(vm); deferred->finishCreation(vm, promise, resolve, reject); return deferred; }
static EncodedJSValue JSC_HOST_CALL promiseResolutionHandlerFunction(ExecState* exec) { JSValue x = exec->argument(0); VM& vm = exec->vm(); JSObject* F = exec->callee(); // 1. Let 'promise' be the value of F's [[Promise]] internal slot JSPromise* promise = jsCast<JSPromise*>(F->get(exec, vm.propertyNames->promisePrivateName)); // 2. Let 'fulfillmentHandler' be the value of F's [[FulfillmentHandler]] internal slot. JSValue fulfillmentHandler = F->get(exec, vm.propertyNames->fulfillmentHandlerPrivateName); // 3. Let 'rejectionHandler' be the value of F's [[RejectionHandler]] internal slot. JSValue rejectionHandler = F->get(exec, vm.propertyNames->rejectionHandlerPrivateName); // 4. If SameValue(x, promise) is true, if (sameValue(exec, x, promise)) { // i. Let 'selfResolutionError' be a newly-created TypeError object. JSObject* selfResolutionError = createTypeError(exec, ASCIILiteral("Resolve a promise with itself")); // ii. Return the result of calling the [[Call]] internal method of rejectionHandler with // undefined as thisArgument and a List containing selfResolutionError as argumentsList. CallData rejectCallData; CallType rejectCallType = getCallData(rejectionHandler, rejectCallData); ASSERT(rejectCallType != CallTypeNone); MarkedArgumentBuffer rejectArguments; rejectArguments.append(selfResolutionError); return JSValue::encode(call(exec, rejectionHandler, rejectCallType, rejectCallData, jsUndefined(), rejectArguments)); } // 5. Let 'C' be the value of promise's [[PromiseConstructor]] internal slot. JSValue C = promise->constructor(); // 6. Let 'deferred' be the result of calling GetDeferred(C) JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); // 7. ReturnIfAbrupt(deferred). if (exec->hadException()) return JSValue::encode(jsUndefined()); JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); // 8. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(x, deferred). ThenableStatus updateResult = updateDeferredFromPotentialThenable(exec, x, deferred); // 9. ReturnIfAbrupt(updateResult). if (exec->hadException()) return JSValue::encode(jsUndefined()); // 10. If 'updateResult' is not "not a thenable", return the result of calling // Invoke(deferred.[[Promise]], "then", (fulfillmentHandler, rejectionHandler)). // NOTE: Invoke does not seem to be defined anywhere, so I am guessing here. if (updateResult != NotAThenable) { JSObject* deferredPromise = deferred->promise(); JSValue thenValue = deferredPromise->get(exec, exec->vm().propertyNames->then); if (exec->hadException()) return JSValue::encode(jsUndefined()); CallData thenCallData; CallType thenCallType = getCallData(thenValue, thenCallData); if (thenCallType == CallTypeNone) return JSValue::encode(throwTypeError(exec)); MarkedArgumentBuffer arguments; arguments.append(fulfillmentHandler); arguments.append(rejectionHandler); return JSValue::encode(call(exec, thenValue, thenCallType, thenCallData, deferredPromise, arguments)); } // 11. Return the result of calling the [[Call]] internal method of fulfillmentHandler // with undefined as thisArgument and a List containing x as argumentsList. CallData fulfillmentHandlerCallData; CallType fulfillmentHandlerCallType = getCallData(fulfillmentHandler, fulfillmentHandlerCallData); ASSERT(fulfillmentHandlerCallType != CallTypeNone); MarkedArgumentBuffer fulfillmentHandlerArguments; fulfillmentHandlerArguments.append(x); return JSValue::encode(call(exec, fulfillmentHandler, fulfillmentHandlerCallType, fulfillmentHandlerCallData, jsUndefined(), fulfillmentHandlerArguments)); }