1/* 2 * Copyright (C) 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "JSPromiseFunctions.h" 28 29#if ENABLE(PROMISES) 30 31#include "Error.h" 32#include "JSCJSValueInlines.h" 33#include "JSCellInlines.h" 34#include "JSPromise.h" 35#include "JSPromiseConstructor.h" 36#include "JSPromiseDeferred.h" 37#include "NumberObject.h" 38#include "StructureInlines.h" 39 40namespace JSC { 41 42// Deferred Construction Functions 43static EncodedJSValue JSC_HOST_CALL deferredConstructionFunction(ExecState* exec) 44{ 45 JSObject* F = exec->callee(); 46 47 VM& vm = exec->vm(); 48 49 // 1. Set F's [[Resolve]] internal slot to resolve. 50 F->putDirect(vm, vm.propertyNames->resolvePrivateName, exec->argument(0)); 51 52 // 2. Set F's [[Reject]] internal slot to reject. 53 F->putDirect(vm, vm.propertyNames->rejectPrivateName, exec->argument(1)); 54 55 // 3. Return. 56 return JSValue::encode(jsUndefined()); 57} 58 59JSFunction* createDeferredConstructionFunction(VM& vm, JSGlobalObject* globalObject) 60{ 61 return JSFunction::create(vm, globalObject, 2, ASCIILiteral("DeferredConstructionFunction"), deferredConstructionFunction); 62} 63 64// Identity Functions 65 66static EncodedJSValue JSC_HOST_CALL identifyFunction(ExecState* exec) 67{ 68 return JSValue::encode(exec->argument(0)); 69} 70 71JSFunction* createIdentifyFunction(VM& vm, JSGlobalObject* globalObject) 72{ 73 return JSFunction::create(vm, globalObject, 1, ASCIILiteral("IdentityFunction"), identifyFunction); 74} 75 76// Promise.All Countdown Functions 77 78static EncodedJSValue JSC_HOST_CALL promiseAllCountdownFunction(ExecState* exec) 79{ 80 JSValue x = exec->argument(0); 81 VM& vm = exec->vm(); 82 JSObject* F = exec->callee(); 83 84 // 1. Let 'index' be the value of F's [[Index]] internal slot. 85 uint32_t index = F->get(exec, vm.propertyNames->indexPrivateName).asUInt32(); 86 87 // 2. Let 'values' be the value of F's [[Values]] internal slot.. 88 JSArray* values = jsCast<JSArray*>(F->get(exec, vm.propertyNames->valuesPrivateName)); 89 90 // 3. Let 'deferred' be the value of F's [[Deferred]] internal slot. 91 JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(F->get(exec, vm.propertyNames->deferredPrivateName)); 92 93 // 4. Let 'countdownHolder' be the value of F's [[CountdownHolder]] internal slot. 94 NumberObject* countdownHolder = jsCast<NumberObject*>(F->get(exec, vm.propertyNames->countdownHolderPrivateName)); 95 96 // 5. Let 'result' be the result of calling the [[DefineOwnProperty]] internal method 97 // of 'values' with arguments 'index' and Property Descriptor { [[Value]]: x, 98 // [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }. 99 values->putDirectIndex(exec, index, x); 100 101 // 6. RejectIfAbrupt(result, deferred). 102 if (exec->hadException()) 103 abruptRejection(exec, deferred); 104 105 // 7. Set countdownHolder.[[Countdown]] to countdownHolder.[[Countdown]] - 1. 106 uint32_t newCountdownValue = countdownHolder->internalValue().asUInt32() - 1; 107 countdownHolder->setInternalValue(vm, JSValue(newCountdownValue)); 108 109 // 8. If countdownHolder.[[Countdown]] is 0, 110 if (!newCountdownValue) { 111 // i. Return the result of calling the [[Call]] internal method of deferred.[[Resolve]] 112 // with undefined as thisArgument and a List containing 'values' as argumentsList. 113 performDeferredResolve(exec, deferred, values); 114 } 115 116 // 9. Return. 117 return JSValue::encode(jsUndefined()); 118} 119 120JSFunction* createPromiseAllCountdownFunction(VM& vm, JSGlobalObject* globalObject) 121{ 122 return JSFunction::create(vm, globalObject, 1, ASCIILiteral("PromiseAllCountdownFunction"), promiseAllCountdownFunction); 123} 124 125// Promise Resolution Handler Functions 126 127static EncodedJSValue JSC_HOST_CALL promiseResolutionHandlerFunction(ExecState* exec) 128{ 129 JSValue x = exec->argument(0); 130 VM& vm = exec->vm(); 131 JSObject* F = exec->callee(); 132 133 // 1. Let 'promise' be the value of F's [[Promise]] internal slot 134 JSPromise* promise = jsCast<JSPromise*>(F->get(exec, vm.propertyNames->promisePrivateName)); 135 136 // 2. Let 'fulfillmentHandler' be the value of F's [[FulfillmentHandler]] internal slot. 137 JSValue fulfillmentHandler = F->get(exec, vm.propertyNames->fulfillmentHandlerPrivateName); 138 139 // 3. Let 'rejectionHandler' be the value of F's [[RejectionHandler]] internal slot. 140 JSValue rejectionHandler = F->get(exec, vm.propertyNames->rejectionHandlerPrivateName); 141 142 // 4. If SameValue(x, promise) is true, 143 if (sameValue(exec, x, promise)) { 144 // i. Let 'selfResolutionError' be a newly-created TypeError object. 145 JSObject* selfResolutionError = createTypeError(exec, ASCIILiteral("Resolve a promise with itself")); 146 // ii. Return the result of calling the [[Call]] internal method of rejectionHandler with 147 // undefined as thisArgument and a List containing selfResolutionError as argumentsList. 148 CallData rejectCallData; 149 CallType rejectCallType = getCallData(rejectionHandler, rejectCallData); 150 ASSERT(rejectCallType != CallTypeNone); 151 152 MarkedArgumentBuffer rejectArguments; 153 rejectArguments.append(selfResolutionError); 154 155 return JSValue::encode(call(exec, rejectionHandler, rejectCallType, rejectCallData, jsUndefined(), rejectArguments)); 156 } 157 158 // 5. Let 'C' be the value of promise's [[PromiseConstructor]] internal slot. 159 JSValue C = promise->constructor(); 160 161 // 6. Let 'deferred' be the result of calling GetDeferred(C) 162 JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); 163 164 // 7. ReturnIfAbrupt(deferred). 165 if (exec->hadException()) 166 return JSValue::encode(jsUndefined()); 167 168 JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); 169 170 // 8. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(x, deferred). 171 ThenableStatus updateResult = updateDeferredFromPotentialThenable(exec, x, deferred); 172 173 // 9. ReturnIfAbrupt(updateResult). 174 if (exec->hadException()) 175 return JSValue::encode(jsUndefined()); 176 177 // 10. If 'updateResult' is not "not a thenable", return the result of calling 178 // Invoke(deferred.[[Promise]], "then", (fulfillmentHandler, rejectionHandler)). 179 // NOTE: Invoke does not seem to be defined anywhere, so I am guessing here. 180 if (updateResult != NotAThenable) { 181 JSObject* deferredPromise = deferred->promise(); 182 183 JSValue thenValue = deferredPromise->get(exec, exec->vm().propertyNames->then); 184 if (exec->hadException()) 185 return JSValue::encode(jsUndefined()); 186 187 CallData thenCallData; 188 CallType thenCallType = getCallData(thenValue, thenCallData); 189 if (thenCallType == CallTypeNone) 190 return JSValue::encode(throwTypeError(exec)); 191 192 MarkedArgumentBuffer arguments; 193 arguments.append(fulfillmentHandler); 194 arguments.append(rejectionHandler); 195 196 return JSValue::encode(call(exec, thenValue, thenCallType, thenCallData, deferredPromise, arguments)); 197 } 198 199 // 11. Return the result of calling the [[Call]] internal method of fulfillmentHandler 200 // with undefined as thisArgument and a List containing x as argumentsList. 201 CallData fulfillmentHandlerCallData; 202 CallType fulfillmentHandlerCallType = getCallData(fulfillmentHandler, fulfillmentHandlerCallData); 203 ASSERT(fulfillmentHandlerCallType != CallTypeNone); 204 205 MarkedArgumentBuffer fulfillmentHandlerArguments; 206 fulfillmentHandlerArguments.append(x); 207 208 return JSValue::encode(call(exec, fulfillmentHandler, fulfillmentHandlerCallType, fulfillmentHandlerCallData, jsUndefined(), fulfillmentHandlerArguments)); 209} 210 211JSFunction* createPromiseResolutionHandlerFunction(VM& vm, JSGlobalObject* globalObject) 212{ 213 return JSFunction::create(vm, globalObject, 1, ASCIILiteral("PromiseResolutionHandlerFunction"), promiseResolutionHandlerFunction); 214} 215 216// Reject Promise Functions 217 218static EncodedJSValue JSC_HOST_CALL rejectPromiseFunction(ExecState* exec) 219{ 220 JSValue reason = exec->argument(0); 221 JSObject* F = exec->callee(); 222 VM& vm = exec->vm(); 223 224 // 1. Let 'promise' be the value of F's [[Promise]] internal slot. 225 JSPromise* promise = jsCast<JSPromise*>(F->get(exec, exec->vm().propertyNames->promisePrivateName)); 226 227 // 2. Return the result of calling PromiseReject(promise, reason); 228 promise->reject(vm, reason); 229 230 return JSValue::encode(jsUndefined()); 231} 232 233JSFunction* createRejectPromiseFunction(VM& vm, JSGlobalObject* globalObject) 234{ 235 return JSFunction::create(vm, globalObject, 1, ASCIILiteral("RejectPromiseFunction"), rejectPromiseFunction); 236} 237 238// Resolve Promise Functions 239 240static EncodedJSValue JSC_HOST_CALL resolvePromiseFunction(ExecState* exec) 241{ 242 JSValue resolution = exec->argument(0); 243 JSObject* F = exec->callee(); 244 VM& vm = exec->vm(); 245 246 // 1. Let 'promise' be the value of F's [[Promise]] internal slot. 247 JSPromise* promise = jsCast<JSPromise*>(F->get(exec, vm.propertyNames->promisePrivateName)); 248 249 // 2. Return the result of calling PromiseResolve(promise, resolution); 250 promise->resolve(vm, resolution); 251 252 return JSValue::encode(jsUndefined()); 253} 254 255JSFunction* createResolvePromiseFunction(VM& vm, JSGlobalObject* globalObject) 256{ 257 return JSFunction::create(vm, globalObject, 1, ASCIILiteral("ResolvePromiseFunction"), resolvePromiseFunction); 258} 259 260// Thrower Functions 261 262static EncodedJSValue JSC_HOST_CALL throwerFunction(ExecState* exec) 263{ 264 return JSValue::encode(exec->vm().throwException(exec, exec->argument(0))); 265} 266 267JSFunction* createThrowerFunction(VM& vm, JSGlobalObject* globalObject) 268{ 269 return JSFunction::create(vm, globalObject, 1, ASCIILiteral("ThrowerFunction"), throwerFunction); 270} 271 272 273} // namespace JSC 274 275#endif // ENABLE(PROMISES) 276