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 "JSPromiseDeferred.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 "JSPromiseFunctions.h" 37#include "SlotVisitorInlines.h" 38#include "StructureInlines.h" 39 40namespace JSC { 41 42const ClassInfo JSPromiseDeferred::s_info = { "JSPromiseDeferred", 0, 0, 0, CREATE_METHOD_TABLE(JSPromiseDeferred) }; 43 44JSPromiseDeferred* JSPromiseDeferred::create(ExecState* exec, JSGlobalObject* globalObject) 45{ 46 VM& vm = exec->vm(); 47 48 JSFunction* resolver = createDeferredConstructionFunction(vm, globalObject); 49 50 JSPromise* promise = constructPromise(exec, globalObject, resolver); 51 JSValue resolve = resolver->get(exec, vm.propertyNames->resolvePrivateName); 52 JSValue reject = resolver->get(exec, vm.propertyNames->rejectPrivateName); 53 54 return JSPromiseDeferred::create(vm, promise, resolve, reject); 55} 56 57JSPromiseDeferred* JSPromiseDeferred::create(VM& vm, JSObject* promise, JSValue resolve, JSValue reject) 58{ 59 JSPromiseDeferred* deferred = new (NotNull, allocateCell<JSPromiseDeferred>(vm.heap)) JSPromiseDeferred(vm); 60 deferred->finishCreation(vm, promise, resolve, reject); 61 return deferred; 62} 63 64JSPromiseDeferred::JSPromiseDeferred(VM& vm) 65 : Base(vm, vm.promiseDeferredStructure.get()) 66{ 67} 68 69void JSPromiseDeferred::finishCreation(VM& vm, JSObject* promise, JSValue resolve, JSValue reject) 70{ 71 Base::finishCreation(vm); 72 m_promise.set(vm, this, promise); 73 m_resolve.set(vm, this, resolve); 74 m_reject.set(vm, this, reject); 75} 76 77void JSPromiseDeferred::visitChildren(JSCell* cell, SlotVisitor& visitor) 78{ 79 JSPromiseDeferred* thisObject = jsCast<JSPromiseDeferred*>(cell); 80 ASSERT_GC_OBJECT_INHERITS(thisObject, info()); 81 COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); 82 ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); 83 84 Base::visitChildren(thisObject, visitor); 85 86 visitor.append(&thisObject->m_promise); 87 visitor.append(&thisObject->m_resolve); 88 visitor.append(&thisObject->m_reject); 89} 90 91JSValue createJSPromiseDeferredFromConstructor(ExecState* exec, JSValue C) 92{ 93 // -- This implements the GetDeferred(C) abstract operation -- 94 95 // 1. If IsConstructor(C) is false, throw a TypeError. 96 if (!C.isObject()) 97 return throwTypeError(exec); 98 99 ConstructData constructData; 100 ConstructType constructType = getConstructData(C, constructData); 101 if (constructType == ConstructTypeNone) 102 return throwTypeError(exec); 103 104 VM& vm = exec->vm(); 105 106 // 2. Let 'resolver' be a new built-in function object as defined in Deferred Construction Functions. 107 JSFunction* resolver = createDeferredConstructionFunction(vm, asObject(C)->globalObject()); 108 109 // 3. Let 'promise' be the result of calling the [[Construct]] internal method of 'C' with 110 // an argument list containing the single item resolver. 111 MarkedArgumentBuffer constructArguments; 112 constructArguments.append(resolver); 113 JSObject* promise = construct(exec, C, constructType, constructData, constructArguments); 114 115 // 4. ReturnIfAbrupt(promise). 116 if (exec->hadException()) 117 return jsUndefined(); 118 119 // 5. Let 'resolve' be the value of resolver's [[Resolve]] internal slot. 120 JSValue resolve = resolver->get(exec, vm.propertyNames->resolvePrivateName); 121 122 // 6. If IsCallable(resolve) is false, throw a TypeError. 123 CallData resolveCallData; 124 CallType resolveCallType = getCallData(resolve, resolveCallData); 125 if (resolveCallType == CallTypeNone) 126 return throwTypeError(exec); 127 128 // 7. Let 'reject' be the value of resolver's [[Reject]] internal slot. 129 JSValue reject = resolver->get(exec, vm.propertyNames->rejectPrivateName); 130 131 // 8. If IsCallable(reject) is false, throw a TypeError. 132 CallData rejectCallData; 133 CallType rejectCallType = getCallData(reject, rejectCallData); 134 if (rejectCallType == CallTypeNone) 135 return throwTypeError(exec); 136 137 // 9. Return the Deferred { [[Promise]]: promise, [[Resolve]]: resolve, [[Reject]]: reject }. 138 return JSPromiseDeferred::create(exec->vm(), promise, resolve, reject); 139} 140 141ThenableStatus updateDeferredFromPotentialThenable(ExecState* exec, JSValue x, JSPromiseDeferred* deferred) 142{ 143 // 1. If Type(x) is not Object, return "not a thenable". 144 if (!x.isObject()) 145 return NotAThenable; 146 147 // 2. Let 'then' be the result of calling Get(x, "then"). 148 JSValue thenValue = x.get(exec, exec->vm().propertyNames->then); 149 150 // 3. If then is an abrupt completion, 151 if (exec->hadException()) { 152 // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of 153 // deferred.[[Reject]] with undefined as thisArgument and a List containing 154 // then.[[value]] as argumentsList. 155 JSValue exception = exec->exception(); 156 exec->clearException(); 157 158 performDeferredReject(exec, deferred, exception); 159 160 // ii. ReturnIfAbrupt(rejectResult). 161 // NOTE: Nothing to do. 162 163 // iii. Return. 164 return WasAThenable; 165 } 166 167 // 4. Let 'then' be then.[[value]]. 168 // Note: Nothing to do. 169 170 // 5. If IsCallable(then) is false, return "not a thenable". 171 CallData thenCallData; 172 CallType thenCallType = getCallData(thenValue, thenCallData); 173 if (thenCallType == CallTypeNone) 174 return NotAThenable; 175 176 // 6. Let 'thenCallResult' be the result of calling the [[Call]] internal method of 177 // 'then' passing x as thisArgument and a List containing deferred.[[Resolve]] and 178 // deferred.[[Reject]] as argumentsList. 179 MarkedArgumentBuffer thenArguments; 180 thenArguments.append(deferred->resolve()); 181 thenArguments.append(deferred->reject()); 182 183 call(exec, thenValue, thenCallType, thenCallData, x, thenArguments); 184 185 // 7. If 'thenCallResult' is an abrupt completion, 186 if (exec->hadException()) { 187 // i. Let 'rejectResult' be the result of calling the [[Call]] internal method of 188 // deferred.[[Reject]] with undefined as thisArgument and a List containing 189 // thenCallResult.[[value]] as argumentsList. 190 JSValue exception = exec->exception(); 191 exec->clearException(); 192 193 performDeferredReject(exec, deferred, exception); 194 195 // ii. ReturnIfAbrupt(rejectResult). 196 // NOTE: Nothing to do. 197 } 198 199 return WasAThenable; 200} 201 202void performDeferredResolve(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument) 203{ 204 JSValue deferredResolve = deferred->resolve(); 205 206 CallData resolveCallData; 207 CallType resolveCallType = getCallData(deferredResolve, resolveCallData); 208 ASSERT(resolveCallType != CallTypeNone); 209 210 MarkedArgumentBuffer arguments; 211 arguments.append(argument); 212 213 call(exec, deferredResolve, resolveCallType, resolveCallData, jsUndefined(), arguments); 214} 215 216void performDeferredReject(ExecState* exec, JSPromiseDeferred* deferred, JSValue argument) 217{ 218 JSValue deferredReject = deferred->reject(); 219 220 CallData rejectCallData; 221 CallType rejectCallType = getCallData(deferredReject, rejectCallData); 222 ASSERT(rejectCallType != CallTypeNone); 223 224 MarkedArgumentBuffer arguments; 225 arguments.append(argument); 226 227 call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), arguments); 228} 229 230JSValue abruptRejection(ExecState* exec, JSPromiseDeferred* deferred) 231{ 232 ASSERT(exec->hadException()); 233 JSValue argument = exec->exception(); 234 exec->clearException(); 235 236 // i. Let 'rejectResult' be the result of calling the [[Call]] internal method 237 // of deferred.[[Reject]] with undefined as thisArgument and a List containing 238 // argument.[[value]] as argumentsList. 239 performDeferredReject(exec, deferred, argument); 240 241 // ii. ReturnIfAbrupt(rejectResult). 242 if (exec->hadException()) 243 return jsUndefined(); 244 245 // iii. Return deferred.[[Promise]]. 246 return deferred->promise(); 247} 248 249} // namespace JSC 250 251#endif // ENABLE(PROMISES) 252