1 /* 2 * Copyright (C) 2013 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "bindings/v8/custom/V8PromiseCustom.h" 33 34 #include <v8.h> 35 #include "V8Promise.h" 36 #include "bindings/v8/DOMRequestState.h" 37 #include "bindings/v8/ScopedPersistent.h" 38 #include "bindings/v8/ScriptFunctionCall.h" 39 #include "bindings/v8/ScriptState.h" 40 #include "bindings/v8/V8Binding.h" 41 #include "bindings/v8/V8HiddenPropertyName.h" 42 #include "bindings/v8/V8PerIsolateData.h" 43 #include "bindings/v8/V8ScriptRunner.h" 44 #include "bindings/v8/WrapperTypeInfo.h" 45 #include "core/dom/Document.h" 46 #include "core/dom/ExecutionContextTask.h" 47 #include "core/frame/DOMWindow.h" 48 #include "core/workers/WorkerGlobalScope.h" 49 #include "platform/Task.h" 50 #include "wtf/Deque.h" 51 #include "wtf/Functional.h" 52 #include "wtf/Noncopyable.h" 53 #include "wtf/PassOwnPtr.h" 54 55 namespace WebCore { 56 57 namespace { 58 59 v8::Local<v8::ObjectTemplate> cachedObjectTemplate(void* privateTemplateUniqueKey, int internalFieldCount, v8::Isolate* isolate) 60 { 61 V8PerIsolateData* data = V8PerIsolateData::from(isolate); 62 WrapperWorldType currentWorldType = worldType(isolate); 63 v8::Handle<v8::FunctionTemplate> functionDescriptor = data->privateTemplateIfExists(currentWorldType, privateTemplateUniqueKey); 64 if (!functionDescriptor.IsEmpty()) 65 return functionDescriptor->InstanceTemplate(); 66 67 functionDescriptor = v8::FunctionTemplate::New(isolate); 68 v8::Local<v8::ObjectTemplate> instanceTemplate = functionDescriptor->InstanceTemplate(); 69 instanceTemplate->SetInternalFieldCount(internalFieldCount); 70 data->setPrivateTemplate(currentWorldType, privateTemplateUniqueKey, functionDescriptor); 71 return instanceTemplate; 72 } 73 74 v8::Local<v8::ObjectTemplate> promiseAllEnvironmentObjectTemplate(v8::Isolate* isolate) 75 { 76 // This is only for getting a unique pointer which we can pass to privateTemplate. 77 static int privateTemplateUniqueKey; 78 return cachedObjectTemplate(&privateTemplateUniqueKey, V8PromiseCustom::PromiseAllEnvironmentFieldCount, isolate); 79 } 80 81 v8::Local<v8::ObjectTemplate> primitiveWrapperObjectTemplate(v8::Isolate* isolate) 82 { 83 // This is only for getting a unique pointer which we can pass to privateTemplate. 84 static int privateTemplateUniqueKey; 85 return cachedObjectTemplate(&privateTemplateUniqueKey, V8PromiseCustom::PrimitiveWrapperFieldCount, isolate); 86 } 87 88 v8::Local<v8::ObjectTemplate> internalObjectTemplate(v8::Isolate* isolate) 89 { 90 // This is only for getting a unique pointer which we can pass to privateTemplate. 91 static int privateTemplateUniqueKey; 92 return cachedObjectTemplate(&privateTemplateUniqueKey, V8PromiseCustom::InternalFieldCount, isolate); 93 } 94 95 void promiseResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& info) 96 { 97 ASSERT(!info.Data().IsEmpty()); 98 v8::Local<v8::Object> promise = info.Data().As<v8::Object>(); 99 v8::Local<v8::Value> result = v8::Undefined(info.GetIsolate()); 100 if (info.Length() > 0) 101 result = info[0]; 102 103 V8PromiseCustom::resolve(promise, result, info.GetIsolate()); 104 } 105 106 void promiseRejectCallback(const v8::FunctionCallbackInfo<v8::Value>& info) 107 { 108 ASSERT(!info.Data().IsEmpty()); 109 v8::Local<v8::Object> promise = info.Data().As<v8::Object>(); 110 v8::Local<v8::Value> result = v8::Undefined(info.GetIsolate()); 111 if (info.Length() > 0) 112 result = info[0]; 113 114 V8PromiseCustom::reject(promise, result, info.GetIsolate()); 115 } 116 117 void promiseAllFulfillCallback(const v8::FunctionCallbackInfo<v8::Value>& info) 118 { 119 v8::Isolate* isolate = info.GetIsolate(); 120 ASSERT(!info.Data().IsEmpty()); 121 v8::Local<v8::Object> environment = info.Data().As<v8::Object>(); 122 v8::Local<v8::Value> result = v8::Undefined(isolate); 123 if (info.Length() > 0) 124 result = info[0]; 125 126 v8::Local<v8::Object> promise = environment->GetInternalField(V8PromiseCustom::PromiseAllEnvironmentPromiseIndex).As<v8::Object>(); 127 v8::Local<v8::Object> countdownWrapper = environment->GetInternalField(V8PromiseCustom::PromiseAllEnvironmentCountdownIndex).As<v8::Object>(); 128 v8::Local<v8::Integer> index = environment->GetInternalField(V8PromiseCustom::PromiseAllEnvironmentIndexIndex).As<v8::Integer>(); 129 v8::Local<v8::Array> results = environment->GetInternalField(V8PromiseCustom::PromiseAllEnvironmentResultsIndex).As<v8::Array>(); 130 131 results->Set(index->Value(), result); 132 133 v8::Local<v8::Integer> countdown = countdownWrapper->GetInternalField(V8PromiseCustom::PrimitiveWrapperPrimitiveIndex).As<v8::Integer>(); 134 ASSERT(countdown->Value() >= 1); 135 if (countdown->Value() == 1) { 136 V8PromiseCustom::resolve(promise, results, isolate); 137 return; 138 } 139 countdownWrapper->SetInternalField(V8PromiseCustom::PrimitiveWrapperPrimitiveIndex, v8::Integer::New(countdown->Value() - 1, isolate)); 140 } 141 142 v8::Local<v8::Object> promiseAllEnvironment(v8::Handle<v8::Object> promise, v8::Handle<v8::Object> countdownWrapper, int index, v8::Handle<v8::Array> results, v8::Isolate* isolate) 143 { 144 v8::Local<v8::ObjectTemplate> objectTemplate = promiseAllEnvironmentObjectTemplate(isolate); 145 v8::Local<v8::Object> environment = objectTemplate->NewInstance(); 146 147 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentPromiseIndex, promise); 148 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentCountdownIndex, countdownWrapper); 149 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentIndexIndex, v8::Integer::New(index, isolate)); 150 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentResultsIndex, results); 151 return environment; 152 } 153 154 // Clear |internal|'s derived array. 155 void clearDerived(v8::Handle<v8::Object> internal, v8::Isolate* isolate) 156 { 157 internal->SetInternalField(V8PromiseCustom::InternalFulfillCallbackIndex, v8::Array::New(isolate)); 158 internal->SetInternalField(V8PromiseCustom::InternalRejectCallbackIndex, v8::Array::New(isolate)); 159 internal->SetInternalField(V8PromiseCustom::InternalDerivedPromiseIndex, v8::Array::New(isolate)); 160 } 161 162 // Add a tuple (|derivedPromise|, |onFulfilled|, |onRejected|) to 163 // |internal|'s derived array. 164 // |internal| must be a Promise internal object. 165 // |derivedPromise| must be a Promise instance. 166 // |onFulfilled| and |onRejected| can be an empty value respectively. 167 void addToDerived(v8::Handle<v8::Object> internal, v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Isolate* isolate) 168 { 169 v8::Local<v8::Array> fulfillCallbacks = internal->GetInternalField(V8PromiseCustom::InternalFulfillCallbackIndex).As<v8::Array>(); 170 v8::Local<v8::Array> rejectCallbacks = internal->GetInternalField(V8PromiseCustom::InternalRejectCallbackIndex).As<v8::Array>(); 171 v8::Local<v8::Array> derivedPromises = internal->GetInternalField(V8PromiseCustom::InternalDerivedPromiseIndex).As<v8::Array>(); 172 173 if (onFulfilled.IsEmpty()) { 174 fulfillCallbacks->Set(fulfillCallbacks->Length(), v8::Undefined(isolate)); 175 } else { 176 fulfillCallbacks->Set(fulfillCallbacks->Length(), onFulfilled); 177 } 178 179 if (onRejected.IsEmpty()) { 180 rejectCallbacks->Set(rejectCallbacks->Length(), v8::Undefined(isolate)); 181 } else { 182 rejectCallbacks->Set(rejectCallbacks->Length(), onRejected); 183 } 184 185 ASSERT(!derivedPromise.IsEmpty()); 186 derivedPromises->Set(derivedPromises->Length(), derivedPromise); 187 188 // Since they are treated as a tuple, 189 // we need to guaranteed that the length of these arrays are same. 190 ASSERT(fulfillCallbacks->Length() == rejectCallbacks->Length() && rejectCallbacks->Length() == derivedPromises->Length()); 191 } 192 193 class CallHandlerTask : public ExecutionContextTask { 194 public: 195 CallHandlerTask(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> handler, v8::Handle<v8::Value> argument, v8::Isolate* isolate, ExecutionContext* context) 196 : m_promise(isolate, promise) 197 , m_handler(isolate, handler) 198 , m_argument(isolate, argument) 199 , m_requestState(context) 200 { 201 ASSERT(!m_promise.isEmpty()); 202 ASSERT(!m_handler.isEmpty()); 203 ASSERT(!m_argument.isEmpty()); 204 } 205 virtual ~CallHandlerTask() { } 206 207 virtual void performTask(ExecutionContext*) OVERRIDE; 208 209 private: 210 ScopedPersistent<v8::Object> m_promise; 211 ScopedPersistent<v8::Function> m_handler; 212 ScopedPersistent<v8::Value> m_argument; 213 DOMRequestState m_requestState; 214 }; 215 216 void CallHandlerTask::performTask(ExecutionContext* context) 217 { 218 ASSERT(context); 219 if (context->activeDOMObjectsAreStopped()) 220 return; 221 222 DOMRequestState::Scope scope(m_requestState); 223 v8::Isolate* isolate = m_requestState.isolate(); 224 v8::Handle<v8::Value> info[] = { m_argument.newLocal(isolate) }; 225 v8::TryCatch trycatch; 226 v8::Local<v8::Value> value = V8ScriptRunner::callFunction(m_handler.newLocal(isolate), context, v8::Undefined(isolate), WTF_ARRAY_LENGTH(info), info, isolate); 227 if (value.IsEmpty()) { 228 V8PromiseCustom::reject(m_promise.newLocal(isolate), trycatch.Exception(), isolate); 229 } else { 230 V8PromiseCustom::resolve(m_promise.newLocal(isolate), value, isolate); 231 } 232 } 233 234 class UpdateDerivedTask : public ExecutionContextTask { 235 public: 236 UpdateDerivedTask(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> originatorValueObject, v8::Isolate* isolate, ExecutionContext* context) 237 : m_promise(isolate, promise) 238 , m_onFulfilled(isolate, onFulfilled) 239 , m_onRejected(isolate, onRejected) 240 , m_originatorValueObject(isolate, originatorValueObject) 241 , m_requestState(context) 242 { 243 ASSERT(!m_promise.isEmpty()); 244 ASSERT(!m_originatorValueObject.isEmpty()); 245 } 246 virtual ~UpdateDerivedTask() { } 247 248 virtual void performTask(ExecutionContext*) OVERRIDE; 249 250 private: 251 ScopedPersistent<v8::Object> m_promise; 252 ScopedPersistent<v8::Function> m_onFulfilled; 253 ScopedPersistent<v8::Function> m_onRejected; 254 ScopedPersistent<v8::Object> m_originatorValueObject; 255 DOMRequestState m_requestState; 256 }; 257 258 void UpdateDerivedTask::performTask(ExecutionContext* context) 259 { 260 ASSERT(context); 261 if (context->activeDOMObjectsAreStopped()) 262 return; 263 264 DOMRequestState::Scope scope(m_requestState); 265 v8::Isolate* isolate = m_requestState.isolate(); 266 v8::Local<v8::Object> originatorValueObject = m_originatorValueObject.newLocal(isolate); 267 v8::Local<v8::Value> coercedAlready = originatorValueObject->GetHiddenValue(V8HiddenPropertyName::thenableHiddenPromise(isolate)); 268 if (!coercedAlready.IsEmpty() && coercedAlready->IsObject()) { 269 ASSERT(V8PromiseCustom::isPromise(coercedAlready.As<v8::Object>(), isolate)); 270 V8PromiseCustom::updateDerivedFromPromise(m_promise.newLocal(isolate), m_onFulfilled.newLocal(isolate), m_onRejected.newLocal(isolate), coercedAlready.As<v8::Object>(), isolate); 271 return; 272 } 273 274 v8::Local<v8::Value> then; 275 v8::TryCatch trycatch; 276 then = originatorValueObject->Get(v8AtomicString(isolate, "then")); 277 if (then.IsEmpty()) { 278 // If calling the [[Get]] internal method threw an exception, catch it and run updateDerivedFromReason. 279 V8PromiseCustom::updateDerivedFromReason(m_promise.newLocal(isolate), m_onRejected.newLocal(isolate), trycatch.Exception(), isolate); 280 return; 281 } 282 283 if (then->IsFunction()) { 284 ASSERT(then->IsObject()); 285 v8::Local<v8::Object> coerced = V8PromiseCustom::coerceThenable(originatorValueObject, then.As<v8::Function>(), isolate); 286 V8PromiseCustom::updateDerivedFromPromise(m_promise.newLocal(isolate), m_onFulfilled.newLocal(isolate), m_onRejected.newLocal(isolate), coerced, isolate); 287 return; 288 } 289 290 V8PromiseCustom::updateDerivedFromValue(m_promise.newLocal(isolate), m_onFulfilled.newLocal(isolate), originatorValueObject, isolate); 291 } 292 293 // Since Promises state propagation routines are executed recursively, they cause 294 // stack overflow. 295 // (e.g. UpdateDerived -> UpdateDerivedFromValue -> SetValue -> 296 // PropagateToDerived -> UpdateDerived) 297 // 298 // To fix that, we introduce PromisePropagator. It holds the stack. When 299 // propagating the result to the derived tuples, we append the derived tuples 300 // to the stack. After that, we drain the stack to propagate the result to 301 // the stored tuples. 302 // 303 // PromisePropagator should be held on the stack and should not be held 304 // as other object's member. PromisePropagator holds Derived tuples. Since 305 // Derived tuples hold persistent handles to JS objects, retaining 306 // PromisePropagator in the heap causes memory leaks. 307 // 308 class PromisePropagator { 309 WTF_MAKE_NONCOPYABLE(PromisePropagator); 310 public: 311 PromisePropagator() { } 312 313 void performPropagation(v8::Isolate*); 314 315 void setValue(v8::Handle<v8::Object> promise, v8::Handle<v8::Value>, v8::Isolate*); 316 void setReason(v8::Handle<v8::Object> promise, v8::Handle<v8::Value>, v8::Isolate*); 317 void propagateToDerived(v8::Handle<v8::Object> promise, v8::Isolate*); 318 void updateDerived(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> originator, v8::Isolate*); 319 void updateDerivedFromValue(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Value>, v8::Isolate*); 320 void updateDerivedFromReason(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Value>, v8::Isolate*); 321 void updateDerivedFromPromise(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> promise, v8::Isolate*); 322 323 private: 324 class Derived { 325 WTF_MAKE_NONCOPYABLE(Derived); 326 public: 327 Derived(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> originator, v8::Isolate* isolate) 328 : m_promise(isolate, promise) 329 , m_onFulfilled(isolate, onFulfilled) 330 , m_onRejected(isolate, onRejected) 331 , m_originator(isolate, originator) 332 { 333 ASSERT(!m_promise.isEmpty()); 334 ASSERT(!m_originator.isEmpty()); 335 } 336 337 static PassOwnPtr<Derived> create(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> originator, v8::Isolate* isolate) 338 { 339 return adoptPtr(new Derived(promise, onFulfilled, onRejected, originator, isolate)); 340 } 341 342 v8::Local<v8::Object> promise(v8::Isolate* isolate) const { return m_promise.newLocal(isolate); } 343 v8::Local<v8::Function> onFulfilled(v8::Isolate* isolate) const { return m_onFulfilled.newLocal(isolate); } 344 v8::Local<v8::Function> onRejected(v8::Isolate* isolate) const { return m_onRejected.newLocal(isolate); } 345 v8::Local<v8::Object> originator(v8::Isolate* isolate) const { return m_originator.newLocal(isolate); } 346 347 private: 348 ScopedPersistent<v8::Object> m_promise; 349 ScopedPersistent<v8::Function> m_onFulfilled; 350 ScopedPersistent<v8::Function> m_onRejected; 351 ScopedPersistent<v8::Object> m_originator; 352 }; 353 354 Deque<OwnPtr<Derived> > m_derivedStack; 355 }; 356 357 void PromisePropagator::performPropagation(v8::Isolate* isolate) 358 { 359 while (!m_derivedStack.isEmpty()) { 360 v8::HandleScope handleScope(isolate); 361 OwnPtr<Derived> derived = m_derivedStack.takeLast(); 362 updateDerived(derived->promise(isolate), derived->onFulfilled(isolate), derived->onRejected(isolate), derived->originator(isolate), isolate); 363 } 364 } 365 366 void PromisePropagator::setValue(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> value, v8::Isolate* isolate) 367 { 368 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise); 369 ASSERT(V8PromiseCustom::getState(internal) != V8PromiseCustom::Fulfilled && V8PromiseCustom::getState(internal) != V8PromiseCustom::Rejected); 370 V8PromiseCustom::setState(internal, V8PromiseCustom::Fulfilled, value, isolate); 371 propagateToDerived(promise, isolate); 372 } 373 374 void PromisePropagator::setReason(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> reason, v8::Isolate* isolate) 375 { 376 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise); 377 ASSERT(V8PromiseCustom::getState(internal) != V8PromiseCustom::Fulfilled && V8PromiseCustom::getState(internal) != V8PromiseCustom::Rejected); 378 V8PromiseCustom::setState(internal, V8PromiseCustom::Rejected, reason, isolate); 379 propagateToDerived(promise, isolate); 380 } 381 382 void PromisePropagator::propagateToDerived(v8::Handle<v8::Object> promise, v8::Isolate* isolate) 383 { 384 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise); 385 ASSERT(V8PromiseCustom::getState(internal) == V8PromiseCustom::Fulfilled || V8PromiseCustom::getState(internal) == V8PromiseCustom::Rejected); 386 v8::Local<v8::Array> fulfillCallbacks = internal->GetInternalField(V8PromiseCustom::InternalFulfillCallbackIndex).As<v8::Array>(); 387 v8::Local<v8::Array> rejectCallbacks = internal->GetInternalField(V8PromiseCustom::InternalRejectCallbackIndex).As<v8::Array>(); 388 v8::Local<v8::Array> derivedPromises = internal->GetInternalField(V8PromiseCustom::InternalDerivedPromiseIndex).As<v8::Array>(); 389 // Since they are treated as a tuple, 390 // we need to guaranteed that the length of these arrays are same. 391 ASSERT(fulfillCallbacks->Length() == rejectCallbacks->Length() && rejectCallbacks->Length() == derivedPromises->Length()); 392 393 // Append Derived tuple to the stack in reverse order. 394 for (uint32_t count = 0, length = derivedPromises->Length(); count < length; ++count) { 395 uint32_t i = length - count - 1; 396 v8::Local<v8::Object> derivedPromise = derivedPromises->Get(i).As<v8::Object>(); 397 398 v8::Local<v8::Function> onFulfilled, onRejected; 399 v8::Local<v8::Value> onFulfilledValue = fulfillCallbacks->Get(i); 400 if (onFulfilledValue->IsFunction()) { 401 onFulfilled = onFulfilledValue.As<v8::Function>(); 402 } 403 v8::Local<v8::Value> onRejectedValue = rejectCallbacks->Get(i); 404 if (onRejectedValue->IsFunction()) { 405 onRejected = onRejectedValue.As<v8::Function>(); 406 } 407 408 m_derivedStack.append(Derived::create(derivedPromise, onFulfilled, onRejected, promise, isolate)); 409 } 410 clearDerived(internal, isolate); 411 } 412 413 void PromisePropagator::updateDerivedFromValue(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Value> value, v8::Isolate* isolate) 414 { 415 if (!onFulfilled.IsEmpty()) { 416 V8PromiseCustom::callHandler(derivedPromise, onFulfilled, value, isolate); 417 } else { 418 setValue(derivedPromise, value, isolate); 419 } 420 } 421 422 void PromisePropagator::updateDerivedFromReason(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Value> reason, v8::Isolate* isolate) 423 { 424 if (!onRejected.IsEmpty()) { 425 V8PromiseCustom::callHandler(derivedPromise, onRejected, reason, isolate); 426 } else { 427 setReason(derivedPromise, reason, isolate); 428 } 429 } 430 431 void PromisePropagator::updateDerived(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> originator, v8::Isolate* isolate) 432 { 433 v8::Local<v8::Object> originatorInternal = V8PromiseCustom::getInternal(originator); 434 V8PromiseCustom::PromiseState originatorState = V8PromiseCustom::getState(originatorInternal); 435 ASSERT(originatorState == V8PromiseCustom::Fulfilled || originatorState == V8PromiseCustom::Rejected); 436 v8::Local<v8::Value> originatorValue = originatorInternal->GetInternalField(V8PromiseCustom::InternalResultIndex); 437 if (originatorState == V8PromiseCustom::Fulfilled) { 438 if (originatorValue->IsObject()) { 439 ExecutionContext* executionContext = getExecutionContext(); 440 ASSERT(executionContext && executionContext->isContextThread()); 441 executionContext->postTask(adoptPtr(new UpdateDerivedTask(derivedPromise, onFulfilled, onRejected, originatorValue.As<v8::Object>(), isolate, executionContext))); 442 } else { 443 updateDerivedFromValue(derivedPromise, onFulfilled, originatorValue, isolate); 444 } 445 } else { 446 updateDerivedFromReason(derivedPromise, onRejected, originatorValue, isolate); 447 } 448 } 449 450 void PromisePropagator::updateDerivedFromPromise(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> promise, v8::Isolate* isolate) 451 { 452 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise); 453 V8PromiseCustom::PromiseState state = V8PromiseCustom::getState(internal); 454 if (state == V8PromiseCustom::Fulfilled || state == V8PromiseCustom::Rejected) { 455 updateDerived(derivedPromise, onFulfilled, onRejected, promise, isolate); 456 } else { 457 addToDerived(internal, derivedPromise, onFulfilled, onRejected, isolate); 458 } 459 } 460 461 } // namespace 462 463 void V8Promise::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& info) 464 { 465 v8SetReturnValue(info, v8::Local<v8::Value>()); 466 v8::Isolate* isolate = info.GetIsolate(); 467 if (!info.Length() || !info[0]->IsFunction()) { 468 throwTypeError("Promise constructor takes a function argument", isolate); 469 return; 470 } 471 v8::Local<v8::Function> init = info[0].As<v8::Function>(); 472 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(info.Holder(), isolate); 473 v8::Handle<v8::Value> argv[] = { 474 createClosure(promiseResolveCallback, promise, isolate), 475 createClosure(promiseRejectCallback, promise, isolate) 476 }; 477 v8::TryCatch trycatch; 478 if (V8ScriptRunner::callFunction(init, getExecutionContext(), v8::Undefined(isolate), WTF_ARRAY_LENGTH(argv), argv, isolate).IsEmpty()) { 479 // An exception is thrown. Reject the promise if its resolved flag is unset. 480 V8PromiseCustom::reject(promise, trycatch.Exception(), isolate); 481 } 482 v8SetReturnValue(info, promise); 483 return; 484 } 485 486 void V8Promise::thenMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info) 487 { 488 v8::Isolate* isolate = info.GetIsolate(); 489 v8::Local<v8::Function> onFulfilled, onRejected; 490 if (info.Length() > 0 && info[0]->IsFunction()) 491 onFulfilled = info[0].As<v8::Function>(); 492 if (info.Length() > 1 && info[1]->IsFunction()) 493 onRejected = info[1].As<v8::Function>(); 494 v8SetReturnValue(info, V8PromiseCustom::then(info.Holder(), onFulfilled, onRejected, isolate)); 495 } 496 497 void V8Promise::castMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info) 498 { 499 v8::Isolate* isolate = info.GetIsolate(); 500 v8::Local<v8::Value> result = v8::Undefined(isolate); 501 if (info.Length() > 0) 502 result = info[0]; 503 504 v8SetReturnValue(info, V8PromiseCustom::toPromise(result, isolate)); 505 } 506 507 void V8Promise::catchMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info) 508 { 509 v8::Isolate* isolate = info.GetIsolate(); 510 v8::Local<v8::Function> onFulfilled, onRejected; 511 512 if (info.Length() > 0 && !info[0]->IsUndefined()) { 513 if (!info[0]->IsFunction()) { 514 v8SetReturnValue(info, throwTypeError("onRejected must be a function or undefined", isolate)); 515 return; 516 } 517 onRejected = info[0].As<v8::Function>(); 518 } 519 v8SetReturnValue(info, V8PromiseCustom::then(info.Holder(), onFulfilled, onRejected, isolate)); 520 } 521 522 void V8Promise::resolveMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info) 523 { 524 v8::Isolate* isolate = info.GetIsolate(); 525 v8::Local<v8::Value> result = v8::Undefined(isolate); 526 if (info.Length() > 0) 527 result = info[0]; 528 529 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(info.Holder(), isolate); 530 V8PromiseCustom::resolve(promise, result, isolate); 531 v8SetReturnValue(info, promise); 532 } 533 534 void V8Promise::rejectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info) 535 { 536 v8::Isolate* isolate = info.GetIsolate(); 537 v8::Local<v8::Value> result = v8::Undefined(isolate); 538 if (info.Length() > 0) 539 result = info[0]; 540 541 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(info.Holder(), isolate); 542 V8PromiseCustom::reject(promise, result, isolate); 543 v8SetReturnValue(info, promise); 544 } 545 546 void V8Promise::raceMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info) 547 { 548 v8::Isolate* isolate = info.GetIsolate(); 549 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(info.Holder(), isolate); 550 551 if (!info.Length() || !info[0]->IsArray()) { 552 v8SetReturnValue(info, promise); 553 return; 554 } 555 556 // FIXME: Now we limit the iterable type to the Array type. 557 v8::Local<v8::Array> iterable = info[0].As<v8::Array>(); 558 v8::Local<v8::Function> onFulfilled = createClosure(promiseResolveCallback, promise, isolate); 559 v8::Local<v8::Function> onRejected = createClosure(promiseRejectCallback, promise, isolate); 560 561 for (unsigned i = 0, length = iterable->Length(); i < length; ++i) { 562 // Array-holes should not be skipped by for-of iteration semantics. 563 V8TRYCATCH_VOID(v8::Local<v8::Value>, nextValue, iterable->Get(i)); 564 v8::Local<v8::Object> nextPromise = V8PromiseCustom::toPromise(nextValue, isolate); 565 V8PromiseCustom::then(nextPromise, onFulfilled, onRejected, isolate); 566 } 567 v8SetReturnValue(info, promise); 568 } 569 570 void V8Promise::allMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info) 571 { 572 v8::Isolate* isolate = info.GetIsolate(); 573 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(info.Holder(), isolate); 574 v8::Local<v8::Array> results = v8::Array::New(info.GetIsolate()); 575 576 if (!info.Length() || !info[0]->IsArray()) { 577 V8PromiseCustom::resolve(promise, results, isolate); 578 v8SetReturnValue(info, promise); 579 return; 580 } 581 582 // FIXME: Now we limit the iterable type to the Array type. 583 v8::Local<v8::Array> iterable = info[0].As<v8::Array>(); 584 585 if (!iterable->Length()) { 586 V8PromiseCustom::resolve(promise, results, isolate); 587 v8SetReturnValue(info, promise); 588 return; 589 } 590 591 v8::Local<v8::ObjectTemplate> objectTemplate = primitiveWrapperObjectTemplate(isolate); 592 v8::Local<v8::Object> countdownWrapper = objectTemplate->NewInstance(); 593 countdownWrapper->SetInternalField(V8PromiseCustom::PrimitiveWrapperPrimitiveIndex, v8::Integer::New(iterable->Length(), isolate)); 594 595 v8::Local<v8::Function> onRejected = createClosure(promiseRejectCallback, promise, isolate); 596 for (unsigned i = 0, length = iterable->Length(); i < length; ++i) { 597 // Array-holes should not be skipped by for-of iteration semantics. 598 v8::Local<v8::Object> environment = promiseAllEnvironment(promise, countdownWrapper, i, results, isolate); 599 v8::Local<v8::Function> onFulfilled = createClosure(promiseAllFulfillCallback, environment, isolate); 600 V8TRYCATCH_VOID(v8::Local<v8::Value>, nextValue, iterable->Get(i)); 601 v8::Local<v8::Object> nextPromise = V8PromiseCustom::toPromise(nextValue, isolate); 602 V8PromiseCustom::then(nextPromise, onFulfilled, onRejected, isolate); 603 } 604 v8SetReturnValue(info, promise); 605 } 606 607 // 608 // -- V8PromiseCustom -- 609 v8::Local<v8::Object> V8PromiseCustom::createPromise(v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 610 { 611 v8::Local<v8::ObjectTemplate> internalTemplate = internalObjectTemplate(isolate); 612 v8::Local<v8::Object> internal = internalTemplate->NewInstance(); 613 v8::Local<v8::Object> promise = V8DOMWrapper::createWrapper(creationContext, &V8Promise::wrapperTypeInfo, 0, isolate); 614 615 clearDerived(internal, isolate); 616 setState(internal, Pending, v8::Undefined(isolate), isolate); 617 618 promise->SetInternalField(v8DOMWrapperObjectIndex, internal); 619 return promise; 620 } 621 622 v8::Local<v8::Object> V8PromiseCustom::getInternal(v8::Handle<v8::Object> promise) 623 { 624 v8::Local<v8::Value> value = promise->GetInternalField(v8DOMWrapperObjectIndex); 625 return value.As<v8::Object>(); 626 } 627 628 V8PromiseCustom::PromiseState V8PromiseCustom::getState(v8::Handle<v8::Object> internal) 629 { 630 v8::Handle<v8::Value> value = internal->GetInternalField(V8PromiseCustom::InternalStateIndex); 631 bool ok = false; 632 uint32_t number = toInt32(value, ok); 633 ASSERT(ok && (number == Pending || number == Fulfilled || number == Rejected || number == Following)); 634 return static_cast<PromiseState>(number); 635 } 636 637 void V8PromiseCustom::setState(v8::Handle<v8::Object> internal, PromiseState state, v8::Handle<v8::Value> value, v8::Isolate* isolate) 638 { 639 ASSERT(!value.IsEmpty()); 640 ASSERT(state == Pending || state == Fulfilled || state == Rejected || state == Following); 641 internal->SetInternalField(InternalStateIndex, v8::Integer::New(state, isolate)); 642 internal->SetInternalField(InternalResultIndex, value); 643 } 644 645 bool V8PromiseCustom::isPromise(v8::Handle<v8::Value> maybePromise, v8::Isolate* isolate) 646 { 647 WrapperWorldType currentWorldType = worldType(isolate); 648 return V8Promise::domTemplate(isolate, currentWorldType)->HasInstance(maybePromise); 649 } 650 651 v8::Local<v8::Object> V8PromiseCustom::toPromise(v8::Handle<v8::Value> maybePromise, v8::Isolate* isolate) 652 { 653 // FIXME: Currently we don't check [[PromiseConstructor]] since we limit 654 // the creation of the promise objects only from the Blink Promise 655 // constructor. 656 if (isPromise(maybePromise, isolate)) 657 return maybePromise.As<v8::Object>(); 658 659 v8::Local<v8::Object> promise = createPromise(v8::Handle<v8::Object>(), isolate); 660 resolve(promise, maybePromise, isolate); 661 return promise; 662 } 663 664 void V8PromiseCustom::resolve(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> result, v8::Isolate* isolate) 665 { 666 ASSERT(!result.IsEmpty()); 667 v8::Local<v8::Object> internal = getInternal(promise); 668 PromiseState state = getState(internal); 669 if (state != Pending) 670 return; 671 672 if (isPromise(result, isolate)) { 673 v8::Local<v8::Object> valuePromise = result.As<v8::Object>(); 674 v8::Local<v8::Object> valueInternal = getInternal(valuePromise); 675 PromiseState valueState = getState(valueInternal); 676 if (promise->SameValue(valuePromise)) { 677 v8::Local<v8::Value> reason = V8ThrowException::createTypeError("Resolve a promise with itself", isolate); 678 setReason(promise, reason, isolate); 679 } else if (valueState == Following) { 680 v8::Local<v8::Object> valuePromiseFollowing = valueInternal->GetInternalField(InternalResultIndex).As<v8::Object>(); 681 setState(internal, Following, valuePromiseFollowing, isolate); 682 addToDerived(getInternal(valuePromiseFollowing), promise, v8::Handle<v8::Function>(), v8::Handle<v8::Function>(), isolate); 683 } else if (valueState == Fulfilled) { 684 setValue(promise, valueInternal->GetInternalField(InternalResultIndex), isolate); 685 } else if (valueState == Rejected) { 686 setReason(promise, valueInternal->GetInternalField(InternalResultIndex), isolate); 687 } else { 688 ASSERT(valueState == Pending); 689 setState(internal, Following, valuePromise, isolate); 690 addToDerived(valueInternal, promise, v8::Handle<v8::Function>(), v8::Handle<v8::Function>(), isolate); 691 } 692 } else { 693 setValue(promise, result, isolate); 694 } 695 } 696 697 void V8PromiseCustom::reject(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> reason, v8::Isolate* isolate) 698 { 699 v8::Local<v8::Object> internal = getInternal(promise); 700 PromiseState state = getState(internal); 701 if (state != Pending) 702 return; 703 setReason(promise, reason, isolate); 704 } 705 706 v8::Local<v8::Object> V8PromiseCustom::then(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Isolate* isolate) 707 { 708 v8::Handle<v8::Object> internal = getInternal(promise); 709 while (getState(internal) == Following) { 710 promise = internal->GetInternalField(InternalResultIndex).As<v8::Object>(); 711 internal = getInternal(promise); 712 } 713 // FIXME: Currently we don't lookup "constructor" property since we limit 714 // the creation of the promise objects only from the Blink Promise 715 // constructor. 716 v8::Local<v8::Object> derivedPromise = createPromise(v8::Handle<v8::Object>(), isolate); 717 updateDerivedFromPromise(derivedPromise, onFulfilled, onRejected, promise, isolate); 718 return derivedPromise; 719 } 720 721 void V8PromiseCustom::setValue(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> value, v8::Isolate* isolate) 722 { 723 PromisePropagator propagator; 724 propagator.setValue(promise, value, isolate); 725 propagator.performPropagation(isolate); 726 } 727 728 void V8PromiseCustom::setReason(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> reason, v8::Isolate* isolate) 729 { 730 PromisePropagator propagator; 731 propagator.setReason(promise, reason, isolate); 732 propagator.performPropagation(isolate); 733 } 734 735 void V8PromiseCustom::propagateToDerived(v8::Handle<v8::Object> promise, v8::Isolate* isolate) 736 { 737 PromisePropagator propagator; 738 propagator.propagateToDerived(promise, isolate); 739 propagator.performPropagation(isolate); 740 } 741 742 void V8PromiseCustom::updateDerived(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> originator, v8::Isolate* isolate) 743 { 744 PromisePropagator propagator; 745 propagator.updateDerived(derivedPromise, onFulfilled, onRejected, originator, isolate); 746 propagator.performPropagation(isolate); 747 } 748 749 void V8PromiseCustom::updateDerivedFromValue(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Value> value, v8::Isolate* isolate) 750 { 751 PromisePropagator propagator; 752 propagator.updateDerivedFromValue(derivedPromise, onFulfilled, value, isolate); 753 propagator.performPropagation(isolate); 754 } 755 756 void V8PromiseCustom::updateDerivedFromReason(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Value> reason, v8::Isolate* isolate) 757 { 758 PromisePropagator propagator; 759 propagator.updateDerivedFromReason(derivedPromise, onRejected, reason, isolate); 760 propagator.performPropagation(isolate); 761 } 762 763 void V8PromiseCustom::updateDerivedFromPromise(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> promise, v8::Isolate* isolate) 764 { 765 PromisePropagator propagator; 766 propagator.updateDerivedFromPromise(derivedPromise, onFulfilled, onRejected, promise, isolate); 767 propagator.performPropagation(isolate); 768 } 769 770 v8::Local<v8::Object> V8PromiseCustom::coerceThenable(v8::Handle<v8::Object> thenable, v8::Handle<v8::Function> then, v8::Isolate* isolate) 771 { 772 ASSERT(!thenable.IsEmpty()); 773 ASSERT(!then.IsEmpty()); 774 v8::Local<v8::Object> promise = createPromise(v8::Handle<v8::Object>(), isolate); 775 v8::Handle<v8::Value> argv[] = { 776 createClosure(promiseResolveCallback, promise, isolate), 777 createClosure(promiseRejectCallback, promise, isolate) 778 }; 779 v8::TryCatch trycatch; 780 if (V8ScriptRunner::callFunction(then, getExecutionContext(), thenable, WTF_ARRAY_LENGTH(argv), argv, isolate).IsEmpty()) { 781 reject(promise, trycatch.Exception(), isolate); 782 } 783 thenable->SetHiddenValue(V8HiddenPropertyName::thenableHiddenPromise(isolate), promise); 784 return promise; 785 } 786 787 void V8PromiseCustom::callHandler(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> handler, v8::Handle<v8::Value> argument, v8::Isolate* isolate) 788 { 789 ExecutionContext* executionContext = getExecutionContext(); 790 ASSERT(executionContext && executionContext->isContextThread()); 791 executionContext->postTask(adoptPtr(new CallHandlerTask(promise, handler, argument, isolate, executionContext))); 792 } 793 794 } // namespace WebCore 795