2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "bindings/v8/custom/V8PromiseCustom.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/V8PerIsolateData.h"
42 #include "bindings/v8/V8ScriptRunner.h"
43 #include "bindings/v8/WrapperTypeInfo.h"
44 #include "core/dom/Document.h"
45 #include "core/dom/ExecutionContextTask.h"
46 #include "core/frame/DOMWindow.h"
47 #include "core/frame/UseCounter.h"
48 #include "core/inspector/InspectorInstrumentation.h"
49 #include "core/workers/WorkerGlobalScope.h"
50 #include "platform/Task.h"
51 #include "wtf/Deque.h"
52 #include "wtf/Functional.h"
53 #include "wtf/Noncopyable.h"
54 #include "wtf/PassOwnPtr.h"
60 v8::Local<v8::ObjectTemplate> cachedObjectTemplate(void* privateTemplateUniqueKey, int internalFieldCount, v8::Isolate* isolate)
62 V8PerIsolateData* data = V8PerIsolateData::from(isolate);
63 WrapperWorldType currentWorldType = worldType(isolate);
64 v8::Handle<v8::FunctionTemplate> functionDescriptor = data->privateTemplateIfExists(currentWorldType, privateTemplateUniqueKey);
65 if (!functionDescriptor.IsEmpty())
66 return functionDescriptor->InstanceTemplate();
68 functionDescriptor = v8::FunctionTemplate::New(isolate);
69 v8::Local<v8::ObjectTemplate> instanceTemplate = functionDescriptor->InstanceTemplate();
70 instanceTemplate->SetInternalFieldCount(internalFieldCount);
71 data->setPrivateTemplate(currentWorldType, privateTemplateUniqueKey, functionDescriptor);
72 return instanceTemplate;
75 v8::Local<v8::ObjectTemplate> promiseAllEnvironmentObjectTemplate(v8::Isolate* isolate)
77 // This is only for getting a unique pointer which we can pass to privateTemplate.
78 static int privateTemplateUniqueKey;
79 return cachedObjectTemplate(&privateTemplateUniqueKey, V8PromiseCustom::PromiseAllEnvironmentFieldCount, isolate);
82 v8::Local<v8::ObjectTemplate> primitiveWrapperObjectTemplate(v8::Isolate* isolate)
84 // This is only for getting a unique pointer which we can pass to privateTemplate.
85 static int privateTemplateUniqueKey;
86 return cachedObjectTemplate(&privateTemplateUniqueKey, V8PromiseCustom::PrimitiveWrapperFieldCount, isolate);
89 v8::Local<v8::ObjectTemplate> internalObjectTemplate(v8::Isolate* isolate)
91 // This is only for getting a unique pointer which we can pass to privateTemplate.
92 static int privateTemplateUniqueKey;
93 return cachedObjectTemplate(&privateTemplateUniqueKey, V8PromiseCustom::InternalFieldCount, isolate);
96 void promiseResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
98 ASSERT(!info.Data().IsEmpty());
99 v8::Local<v8::Object> promise = info.Data().As<v8::Object>();
100 v8::Local<v8::Value> result = v8::Undefined(info.GetIsolate());
101 if (info.Length() > 0)
104 V8PromiseCustom::resolve(promise, result, info.GetIsolate());
107 void promiseRejectCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
109 ASSERT(!info.Data().IsEmpty());
110 v8::Local<v8::Object> promise = info.Data().As<v8::Object>();
111 v8::Local<v8::Value> result = v8::Undefined(info.GetIsolate());
112 if (info.Length() > 0)
115 V8PromiseCustom::reject(promise, result, info.GetIsolate());
118 void promiseAllFulfillCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
120 v8::Isolate* isolate = info.GetIsolate();
121 ASSERT(!info.Data().IsEmpty());
122 v8::Local<v8::Object> environment = info.Data().As<v8::Object>();
123 v8::Local<v8::Value> result = v8::Undefined(isolate);
124 if (info.Length() > 0)
127 v8::Local<v8::Object> promise = environment->GetInternalField(V8PromiseCustom::PromiseAllEnvironmentPromiseIndex).As<v8::Object>();
128 v8::Local<v8::Object> countdownWrapper = environment->GetInternalField(V8PromiseCustom::PromiseAllEnvironmentCountdownIndex).As<v8::Object>();
129 v8::Local<v8::Integer> index = environment->GetInternalField(V8PromiseCustom::PromiseAllEnvironmentIndexIndex).As<v8::Integer>();
130 v8::Local<v8::Array> results = environment->GetInternalField(V8PromiseCustom::PromiseAllEnvironmentResultsIndex).As<v8::Array>();
132 results->Set(index->Value(), result);
134 v8::Local<v8::Integer> countdown = countdownWrapper->GetInternalField(V8PromiseCustom::PrimitiveWrapperPrimitiveIndex).As<v8::Integer>();
135 ASSERT(countdown->Value() >= 1);
136 if (countdown->Value() == 1) {
137 V8PromiseCustom::resolve(promise, results, isolate);
140 countdownWrapper->SetInternalField(V8PromiseCustom::PrimitiveWrapperPrimitiveIndex, v8::Integer::New(isolate, countdown->Value() - 1));
143 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)
145 v8::Local<v8::ObjectTemplate> objectTemplate = promiseAllEnvironmentObjectTemplate(isolate);
146 v8::Local<v8::Object> environment = objectTemplate->NewInstance();
148 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentPromiseIndex, promise);
149 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentCountdownIndex, countdownWrapper);
150 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentIndexIndex, v8::Integer::New(isolate, index));
151 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentResultsIndex, results);
155 // Clear |internal|'s derived array.
156 void clearDerived(v8::Handle<v8::Object> internal, v8::Isolate* isolate)
158 internal->SetInternalField(V8PromiseCustom::InternalFulfillCallbackIndex, v8::Array::New(isolate));
159 internal->SetInternalField(V8PromiseCustom::InternalRejectCallbackIndex, v8::Array::New(isolate));
160 internal->SetInternalField(V8PromiseCustom::InternalDerivedPromiseIndex, v8::Array::New(isolate));
163 // Add a tuple (|derivedPromise|, |onFulfilled|, |onRejected|) to
164 // |internal|'s derived array.
165 // |internal| must be a Promise internal object.
166 // |derivedPromise| must be a Promise instance.
167 // |onFulfilled| and |onRejected| can be an empty value respectively.
168 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)
170 v8::Local<v8::Array> fulfillCallbacks = internal->GetInternalField(V8PromiseCustom::InternalFulfillCallbackIndex).As<v8::Array>();
171 v8::Local<v8::Array> rejectCallbacks = internal->GetInternalField(V8PromiseCustom::InternalRejectCallbackIndex).As<v8::Array>();
172 v8::Local<v8::Array> derivedPromises = internal->GetInternalField(V8PromiseCustom::InternalDerivedPromiseIndex).As<v8::Array>();
174 if (onFulfilled.IsEmpty()) {
175 fulfillCallbacks->Set(fulfillCallbacks->Length(), v8::Undefined(isolate));
177 fulfillCallbacks->Set(fulfillCallbacks->Length(), onFulfilled);
180 if (onRejected.IsEmpty()) {
181 rejectCallbacks->Set(rejectCallbacks->Length(), v8::Undefined(isolate));
183 rejectCallbacks->Set(rejectCallbacks->Length(), onRejected);
186 ASSERT(!derivedPromise.IsEmpty());
187 derivedPromises->Set(derivedPromises->Length(), derivedPromise);
189 // Since they are treated as a tuple,
190 // we need to guaranteed that the length of these arrays are same.
191 ASSERT(fulfillCallbacks->Length() == rejectCallbacks->Length() && rejectCallbacks->Length() == derivedPromises->Length());
194 class TaskPerformScopeForInstrumentation {
196 TaskPerformScopeForInstrumentation(ExecutionContext* context, ExecutionContextTask* task)
197 : m_cookie(InspectorInstrumentation::willPerformPromiseTask(context, task))
201 ~TaskPerformScopeForInstrumentation()
203 InspectorInstrumentation::didPerformPromiseTask(m_cookie);
207 InspectorInstrumentationCookie m_cookie;
210 class CallHandlerTask FINAL : public ExecutionContextTask {
212 CallHandlerTask(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> handler, v8::Handle<v8::Value> argument, V8PromiseCustom::PromiseState originatorState, v8::Isolate* isolate, ExecutionContext* context)
213 : m_promise(isolate, promise)
214 , m_handler(isolate, handler)
215 , m_argument(isolate, argument)
216 , m_requestState(context)
218 ASSERT(!m_promise.isEmpty());
219 ASSERT(!m_handler.isEmpty());
220 ASSERT(!m_argument.isEmpty());
221 InspectorInstrumentation::didPostPromiseTask(context, this, originatorState == V8PromiseCustom::Fulfilled);
223 virtual ~CallHandlerTask() { }
225 virtual void performTask(ExecutionContext*) OVERRIDE;
228 ScopedPersistent<v8::Object> m_promise;
229 ScopedPersistent<v8::Function> m_handler;
230 ScopedPersistent<v8::Value> m_argument;
231 DOMRequestState m_requestState;
234 void CallHandlerTask::performTask(ExecutionContext* context)
236 TaskPerformScopeForInstrumentation performTaskScope(context, this);
239 if (context->activeDOMObjectsAreStopped())
242 DOMRequestState::Scope scope(m_requestState);
243 v8::Isolate* isolate = m_requestState.isolate();
244 v8::Handle<v8::Value> info[] = { m_argument.newLocal(isolate) };
245 v8::TryCatch trycatch;
246 v8::Local<v8::Value> value = V8ScriptRunner::callFunction(m_handler.newLocal(isolate), context, v8::Undefined(isolate), WTF_ARRAY_LENGTH(info), info, isolate);
247 if (value.IsEmpty()) {
248 V8PromiseCustom::reject(m_promise.newLocal(isolate), trycatch.Exception(), isolate);
250 V8PromiseCustom::resolve(m_promise.newLocal(isolate), value, isolate);
254 class UpdateDerivedTask FINAL : public ExecutionContextTask {
256 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)
257 : m_promise(isolate, promise)
258 , m_onFulfilled(isolate, onFulfilled)
259 , m_onRejected(isolate, onRejected)
260 , m_originatorValueObject(isolate, originatorValueObject)
261 , m_requestState(context)
263 ASSERT(!m_promise.isEmpty());
264 ASSERT(!m_originatorValueObject.isEmpty());
265 InspectorInstrumentation::didPostPromiseTask(context, this, true);
267 virtual ~UpdateDerivedTask() { }
269 virtual void performTask(ExecutionContext*) OVERRIDE;
272 ScopedPersistent<v8::Object> m_promise;
273 ScopedPersistent<v8::Function> m_onFulfilled;
274 ScopedPersistent<v8::Function> m_onRejected;
275 ScopedPersistent<v8::Object> m_originatorValueObject;
276 DOMRequestState m_requestState;
279 void UpdateDerivedTask::performTask(ExecutionContext* context)
281 TaskPerformScopeForInstrumentation performTaskScope(context, this);
284 if (context->activeDOMObjectsAreStopped())
287 DOMRequestState::Scope scope(m_requestState);
288 v8::Isolate* isolate = m_requestState.isolate();
289 v8::Local<v8::Object> originatorValueObject = m_originatorValueObject.newLocal(isolate);
290 v8::Local<v8::Value> coercedAlready = getHiddenValue(isolate, originatorValueObject, "thenableHiddenPromise");
291 if (!coercedAlready.IsEmpty() && coercedAlready->IsObject()) {
292 ASSERT(V8PromiseCustom::isPromise(coercedAlready.As<v8::Object>(), isolate));
293 V8PromiseCustom::updateDerivedFromPromise(m_promise.newLocal(isolate), m_onFulfilled.newLocal(isolate), m_onRejected.newLocal(isolate), coercedAlready.As<v8::Object>(), isolate);
297 v8::Local<v8::Value> then;
298 v8::TryCatch trycatch;
299 then = originatorValueObject->Get(v8AtomicString(isolate, "then"));
300 if (then.IsEmpty()) {
301 // If calling the [[Get]] internal method threw an exception, catch it and run updateDerivedFromReason.
302 V8PromiseCustom::updateDerivedFromReason(m_promise.newLocal(isolate), m_onRejected.newLocal(isolate), trycatch.Exception(), isolate);
306 if (then->IsFunction()) {
307 ASSERT(then->IsObject());
308 v8::Local<v8::Object> coerced = V8PromiseCustom::coerceThenable(originatorValueObject, then.As<v8::Function>(), isolate);
309 V8PromiseCustom::updateDerivedFromPromise(m_promise.newLocal(isolate), m_onFulfilled.newLocal(isolate), m_onRejected.newLocal(isolate), coerced, isolate);
313 V8PromiseCustom::updateDerivedFromValue(m_promise.newLocal(isolate), m_onFulfilled.newLocal(isolate), originatorValueObject, isolate);
316 // Since Promises state propagation routines are executed recursively, they cause
318 // (e.g. UpdateDerived -> UpdateDerivedFromValue -> SetValue ->
319 // PropagateToDerived -> UpdateDerived)
321 // To fix that, we introduce PromisePropagator. It holds the stack. When
322 // propagating the result to the derived tuples, we append the derived tuples
323 // to the stack. After that, we drain the stack to propagate the result to
324 // the stored tuples.
326 // PromisePropagator should be held on the stack and should not be held
327 // as other object's member. PromisePropagator holds Derived tuples. Since
328 // Derived tuples hold persistent handles to JS objects, retaining
329 // PromisePropagator in the heap causes memory leaks.
331 class PromisePropagator {
332 WTF_MAKE_NONCOPYABLE(PromisePropagator);
334 PromisePropagator() { }
336 void performPropagation(v8::Isolate*);
338 void setValue(v8::Handle<v8::Object> promise, v8::Handle<v8::Value>, v8::Isolate*);
339 void setReason(v8::Handle<v8::Object> promise, v8::Handle<v8::Value>, v8::Isolate*);
340 void propagateToDerived(v8::Handle<v8::Object> promise, v8::Isolate*);
341 void updateDerived(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> originator, v8::Isolate*);
342 void updateDerivedFromValue(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Value>, v8::Isolate*);
343 void updateDerivedFromReason(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Value>, v8::Isolate*);
344 void updateDerivedFromPromise(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> promise, v8::Isolate*);
348 WTF_MAKE_NONCOPYABLE(Derived);
350 Derived(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> originator, v8::Isolate* isolate)
351 : m_promise(isolate, promise)
352 , m_onFulfilled(isolate, onFulfilled)
353 , m_onRejected(isolate, onRejected)
354 , m_originator(isolate, originator)
356 ASSERT(!m_promise.isEmpty());
357 ASSERT(!m_originator.isEmpty());
360 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)
362 return adoptPtr(new Derived(promise, onFulfilled, onRejected, originator, isolate));
365 v8::Local<v8::Object> promise(v8::Isolate* isolate) const { return m_promise.newLocal(isolate); }
366 v8::Local<v8::Function> onFulfilled(v8::Isolate* isolate) const { return m_onFulfilled.newLocal(isolate); }
367 v8::Local<v8::Function> onRejected(v8::Isolate* isolate) const { return m_onRejected.newLocal(isolate); }
368 v8::Local<v8::Object> originator(v8::Isolate* isolate) const { return m_originator.newLocal(isolate); }
371 ScopedPersistent<v8::Object> m_promise;
372 ScopedPersistent<v8::Function> m_onFulfilled;
373 ScopedPersistent<v8::Function> m_onRejected;
374 ScopedPersistent<v8::Object> m_originator;
377 Deque<OwnPtr<Derived> > m_derivedStack;
380 void PromisePropagator::performPropagation(v8::Isolate* isolate)
382 while (!m_derivedStack.isEmpty()) {
383 v8::HandleScope handleScope(isolate);
384 OwnPtr<Derived> derived = m_derivedStack.takeLast();
385 updateDerived(derived->promise(isolate), derived->onFulfilled(isolate), derived->onRejected(isolate), derived->originator(isolate), isolate);
389 void PromisePropagator::setValue(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> value, v8::Isolate* isolate)
391 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise);
392 ASSERT(V8PromiseCustom::getState(internal) != V8PromiseCustom::Fulfilled && V8PromiseCustom::getState(internal) != V8PromiseCustom::Rejected);
393 V8PromiseCustom::setState(internal, V8PromiseCustom::Fulfilled, value, isolate);
394 propagateToDerived(promise, isolate);
397 void PromisePropagator::setReason(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> reason, v8::Isolate* isolate)
399 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise);
400 ASSERT(V8PromiseCustom::getState(internal) != V8PromiseCustom::Fulfilled && V8PromiseCustom::getState(internal) != V8PromiseCustom::Rejected);
401 V8PromiseCustom::setState(internal, V8PromiseCustom::Rejected, reason, isolate);
402 propagateToDerived(promise, isolate);
405 void PromisePropagator::propagateToDerived(v8::Handle<v8::Object> promise, v8::Isolate* isolate)
407 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise);
408 ASSERT(V8PromiseCustom::getState(internal) == V8PromiseCustom::Fulfilled || V8PromiseCustom::getState(internal) == V8PromiseCustom::Rejected);
409 v8::Local<v8::Array> fulfillCallbacks = internal->GetInternalField(V8PromiseCustom::InternalFulfillCallbackIndex).As<v8::Array>();
410 v8::Local<v8::Array> rejectCallbacks = internal->GetInternalField(V8PromiseCustom::InternalRejectCallbackIndex).As<v8::Array>();
411 v8::Local<v8::Array> derivedPromises = internal->GetInternalField(V8PromiseCustom::InternalDerivedPromiseIndex).As<v8::Array>();
412 // Since they are treated as a tuple,
413 // we need to guaranteed that the length of these arrays are same.
414 ASSERT(fulfillCallbacks->Length() == rejectCallbacks->Length() && rejectCallbacks->Length() == derivedPromises->Length());
416 // Append Derived tuple to the stack in reverse order.
417 for (uint32_t count = 0, length = derivedPromises->Length(); count < length; ++count) {
418 uint32_t i = length - count - 1;
419 v8::Local<v8::Object> derivedPromise = derivedPromises->Get(i).As<v8::Object>();
421 v8::Local<v8::Function> onFulfilled, onRejected;
422 v8::Local<v8::Value> onFulfilledValue = fulfillCallbacks->Get(i);
423 if (onFulfilledValue->IsFunction()) {
424 onFulfilled = onFulfilledValue.As<v8::Function>();
426 v8::Local<v8::Value> onRejectedValue = rejectCallbacks->Get(i);
427 if (onRejectedValue->IsFunction()) {
428 onRejected = onRejectedValue.As<v8::Function>();
431 m_derivedStack.append(Derived::create(derivedPromise, onFulfilled, onRejected, promise, isolate));
433 clearDerived(internal, isolate);
436 void PromisePropagator::updateDerivedFromValue(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Value> value, v8::Isolate* isolate)
438 if (!onFulfilled.IsEmpty()) {
439 V8PromiseCustom::callHandler(derivedPromise, onFulfilled, value, V8PromiseCustom::Fulfilled, isolate);
441 setValue(derivedPromise, value, isolate);
445 void PromisePropagator::updateDerivedFromReason(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Value> reason, v8::Isolate* isolate)
447 if (!onRejected.IsEmpty()) {
448 V8PromiseCustom::callHandler(derivedPromise, onRejected, reason, V8PromiseCustom::Rejected, isolate);
450 setReason(derivedPromise, reason, isolate);
454 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)
456 v8::Local<v8::Object> originatorInternal = V8PromiseCustom::getInternal(originator);
457 V8PromiseCustom::PromiseState originatorState = V8PromiseCustom::getState(originatorInternal);
458 ASSERT(originatorState == V8PromiseCustom::Fulfilled || originatorState == V8PromiseCustom::Rejected);
459 v8::Local<v8::Value> originatorValue = originatorInternal->GetInternalField(V8PromiseCustom::InternalResultIndex);
460 if (originatorState == V8PromiseCustom::Fulfilled) {
461 if (originatorValue->IsObject()) {
462 ExecutionContext* executionContext = currentExecutionContext(isolate);
463 ASSERT(executionContext && executionContext->isContextThread());
464 executionContext->postTask(adoptPtr(new UpdateDerivedTask(derivedPromise, onFulfilled, onRejected, originatorValue.As<v8::Object>(), isolate, executionContext)));
466 updateDerivedFromValue(derivedPromise, onFulfilled, originatorValue, isolate);
469 updateDerivedFromReason(derivedPromise, onRejected, originatorValue, isolate);
473 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)
475 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise);
476 V8PromiseCustom::PromiseState state = V8PromiseCustom::getState(internal);
477 if (state == V8PromiseCustom::Fulfilled || state == V8PromiseCustom::Rejected) {
478 updateDerived(derivedPromise, onFulfilled, onRejected, promise, isolate);
480 addToDerived(internal, derivedPromise, onFulfilled, onRejected, isolate);
486 void V8Promise::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
488 v8SetReturnValue(info, v8::Local<v8::Value>());
489 v8::Isolate* isolate = info.GetIsolate();
490 ExecutionContext* executionContext = activeExecutionContext(isolate);
491 UseCounter::count(executionContext, UseCounter::PromiseConstructor);
492 if (!info.Length() || !info[0]->IsFunction()) {
493 throwTypeError("Promise constructor takes a function argument", isolate);
496 v8::Local<v8::Function> init = info[0].As<v8::Function>();
497 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(info.Holder(), isolate);
498 v8::Handle<v8::Value> argv[] = {
499 createClosure(promiseResolveCallback, promise, isolate),
500 createClosure(promiseRejectCallback, promise, isolate)
502 v8::TryCatch trycatch;
503 if (V8ScriptRunner::callFunction(init, currentExecutionContext(isolate), v8::Undefined(isolate), WTF_ARRAY_LENGTH(argv), argv, isolate).IsEmpty()) {
504 // An exception is thrown. Reject the promise if its resolved flag is unset.
505 V8PromiseCustom::reject(promise, trycatch.Exception(), isolate);
507 v8SetReturnValue(info, promise);
511 void V8Promise::thenMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
513 v8::Isolate* isolate = info.GetIsolate();
514 v8::Local<v8::Function> onFulfilled, onRejected;
515 if (info.Length() > 0 && info[0]->IsFunction())
516 onFulfilled = info[0].As<v8::Function>();
517 if (info.Length() > 1 && info[1]->IsFunction())
518 onRejected = info[1].As<v8::Function>();
519 v8SetReturnValue(info, V8PromiseCustom::then(info.Holder(), onFulfilled, onRejected, isolate));
522 void V8Promise::castMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
524 v8::Isolate* isolate = info.GetIsolate();
525 ExecutionContext* executionContext = activeExecutionContext(isolate);
526 UseCounter::count(executionContext, UseCounter::PromiseCast);
527 v8::Local<v8::Value> result = v8::Undefined(isolate);
528 if (info.Length() > 0)
531 v8SetReturnValue(info, V8PromiseCustom::toPromise(result, isolate));
534 void V8Promise::catchMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
536 v8::Isolate* isolate = info.GetIsolate();
537 v8::Local<v8::Function> onFulfilled, onRejected;
539 if (info.Length() > 0 && !info[0]->IsUndefined()) {
540 if (!info[0]->IsFunction()) {
541 v8SetReturnValue(info, throwTypeError("onRejected must be a function or undefined", isolate));
544 onRejected = info[0].As<v8::Function>();
546 v8SetReturnValue(info, V8PromiseCustom::then(info.Holder(), onFulfilled, onRejected, isolate));
549 void V8Promise::resolveMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
551 v8::Isolate* isolate = info.GetIsolate();
552 ExecutionContext* executionContext = activeExecutionContext(isolate);
553 UseCounter::count(executionContext, UseCounter::PromiseResolve);
554 v8::Local<v8::Value> result = v8::Undefined(isolate);
555 if (info.Length() > 0)
558 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(info.Holder(), isolate);
559 V8PromiseCustom::resolve(promise, result, isolate);
560 v8SetReturnValue(info, promise);
563 void V8Promise::rejectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
565 v8::Isolate* isolate = info.GetIsolate();
566 ExecutionContext* executionContext = activeExecutionContext(isolate);
567 UseCounter::count(executionContext, UseCounter::PromiseReject);
568 v8::Local<v8::Value> result = v8::Undefined(isolate);
569 if (info.Length() > 0)
572 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(info.Holder(), isolate);
573 V8PromiseCustom::reject(promise, result, isolate);
574 v8SetReturnValue(info, promise);
577 void V8Promise::raceMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
579 v8::Isolate* isolate = info.GetIsolate();
580 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(info.Holder(), isolate);
582 if (!info.Length() || !info[0]->IsArray()) {
583 v8SetReturnValue(info, promise);
587 // FIXME: Now we limit the iterable type to the Array type.
588 v8::Local<v8::Array> iterable = info[0].As<v8::Array>();
589 v8::Local<v8::Function> onFulfilled = createClosure(promiseResolveCallback, promise, isolate);
590 v8::Local<v8::Function> onRejected = createClosure(promiseRejectCallback, promise, isolate);
592 for (unsigned i = 0, length = iterable->Length(); i < length; ++i) {
593 // Array-holes should not be skipped by for-of iteration semantics.
594 V8TRYCATCH_VOID(v8::Local<v8::Value>, nextValue, iterable->Get(i));
595 v8::Local<v8::Object> nextPromise = V8PromiseCustom::toPromise(nextValue, isolate);
596 V8PromiseCustom::then(nextPromise, onFulfilled, onRejected, isolate);
598 v8SetReturnValue(info, promise);
601 void V8Promise::allMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
603 v8::Isolate* isolate = info.GetIsolate();
604 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(info.Holder(), isolate);
605 v8::Local<v8::Array> results = v8::Array::New(info.GetIsolate());
607 if (!info.Length() || !info[0]->IsArray()) {
608 V8PromiseCustom::resolve(promise, results, isolate);
609 v8SetReturnValue(info, promise);
613 // FIXME: Now we limit the iterable type to the Array type.
614 v8::Local<v8::Array> iterable = info[0].As<v8::Array>();
616 if (!iterable->Length()) {
617 V8PromiseCustom::resolve(promise, results, isolate);
618 v8SetReturnValue(info, promise);
622 v8::Local<v8::ObjectTemplate> objectTemplate = primitiveWrapperObjectTemplate(isolate);
623 v8::Local<v8::Object> countdownWrapper = objectTemplate->NewInstance();
624 countdownWrapper->SetInternalField(V8PromiseCustom::PrimitiveWrapperPrimitiveIndex, v8::Integer::New(isolate, iterable->Length()));
626 v8::Local<v8::Function> onRejected = createClosure(promiseRejectCallback, promise, isolate);
627 for (unsigned i = 0, length = iterable->Length(); i < length; ++i) {
628 // Array-holes should not be skipped by for-of iteration semantics.
629 v8::Local<v8::Object> environment = promiseAllEnvironment(promise, countdownWrapper, i, results, isolate);
630 v8::Local<v8::Function> onFulfilled = createClosure(promiseAllFulfillCallback, environment, isolate);
631 V8TRYCATCH_VOID(v8::Local<v8::Value>, nextValue, iterable->Get(i));
632 v8::Local<v8::Object> nextPromise = V8PromiseCustom::toPromise(nextValue, isolate);
633 V8PromiseCustom::then(nextPromise, onFulfilled, onRejected, isolate);
635 v8SetReturnValue(info, promise);
639 // -- V8PromiseCustom --
640 v8::Local<v8::Object> V8PromiseCustom::createPromise(v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
642 v8::Local<v8::ObjectTemplate> internalTemplate = internalObjectTemplate(isolate);
643 v8::Local<v8::Object> internal = internalTemplate->NewInstance();
644 v8::Local<v8::Object> promise = V8DOMWrapper::createWrapper(creationContext, &V8Promise::wrapperTypeInfo, 0, isolate);
646 clearDerived(internal, isolate);
647 setState(internal, Pending, v8::Undefined(isolate), isolate);
649 promise->SetInternalField(v8DOMWrapperObjectIndex, internal);
653 v8::Local<v8::Object> V8PromiseCustom::getInternal(v8::Handle<v8::Object> promise)
655 v8::Local<v8::Value> value = promise->GetInternalField(v8DOMWrapperObjectIndex);
656 return value.As<v8::Object>();
659 V8PromiseCustom::PromiseState V8PromiseCustom::getState(v8::Handle<v8::Object> internal)
661 v8::Handle<v8::Value> value = internal->GetInternalField(V8PromiseCustom::InternalStateIndex);
662 uint32_t number = toInt32(value);
663 ASSERT(number == Pending || number == Fulfilled || number == Rejected || number == Following);
664 return static_cast<PromiseState>(number);
667 void V8PromiseCustom::setState(v8::Handle<v8::Object> internal, PromiseState state, v8::Handle<v8::Value> value, v8::Isolate* isolate)
669 ASSERT(!value.IsEmpty());
670 ASSERT(state == Pending || state == Fulfilled || state == Rejected || state == Following);
671 internal->SetInternalField(InternalStateIndex, v8::Integer::New(isolate, state));
672 internal->SetInternalField(InternalResultIndex, value);
675 bool V8PromiseCustom::isPromise(v8::Handle<v8::Value> maybePromise, v8::Isolate* isolate)
677 WrapperWorldType currentWorldType = worldType(isolate);
678 return V8Promise::domTemplate(isolate, currentWorldType)->HasInstance(maybePromise);
681 v8::Local<v8::Object> V8PromiseCustom::toPromise(v8::Handle<v8::Value> maybePromise, v8::Isolate* isolate)
683 // FIXME: Currently we don't check [[PromiseConstructor]] since we limit
684 // the creation of the promise objects only from the Blink Promise
686 if (isPromise(maybePromise, isolate))
687 return maybePromise.As<v8::Object>();
689 v8::Local<v8::Object> promise = createPromise(v8::Handle<v8::Object>(), isolate);
690 resolve(promise, maybePromise, isolate);
694 void V8PromiseCustom::resolve(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> result, v8::Isolate* isolate)
696 ASSERT(!result.IsEmpty());
697 v8::Local<v8::Object> internal = getInternal(promise);
698 PromiseState state = getState(internal);
699 if (state != Pending)
702 if (isPromise(result, isolate)) {
703 v8::Local<v8::Object> valuePromise = result.As<v8::Object>();
704 v8::Local<v8::Object> valueInternal = getInternal(valuePromise);
705 PromiseState valueState = getState(valueInternal);
706 if (promise->SameValue(valuePromise)) {
707 v8::Local<v8::Value> reason = V8ThrowException::createTypeError("Resolve a promise with itself", isolate);
708 setReason(promise, reason, isolate);
709 } else if (valueState == Following) {
710 v8::Local<v8::Object> valuePromiseFollowing = valueInternal->GetInternalField(InternalResultIndex).As<v8::Object>();
711 setState(internal, Following, valuePromiseFollowing, isolate);
712 addToDerived(getInternal(valuePromiseFollowing), promise, v8::Handle<v8::Function>(), v8::Handle<v8::Function>(), isolate);
713 } else if (valueState == Fulfilled) {
714 setValue(promise, valueInternal->GetInternalField(InternalResultIndex), isolate);
715 } else if (valueState == Rejected) {
716 setReason(promise, valueInternal->GetInternalField(InternalResultIndex), isolate);
718 ASSERT(valueState == Pending);
719 setState(internal, Following, valuePromise, isolate);
720 addToDerived(valueInternal, promise, v8::Handle<v8::Function>(), v8::Handle<v8::Function>(), isolate);
723 setValue(promise, result, isolate);
727 void V8PromiseCustom::reject(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> reason, v8::Isolate* isolate)
729 v8::Local<v8::Object> internal = getInternal(promise);
730 PromiseState state = getState(internal);
731 if (state != Pending)
733 setReason(promise, reason, isolate);
736 v8::Local<v8::Object> V8PromiseCustom::then(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Isolate* isolate)
738 v8::Handle<v8::Object> internal = getInternal(promise);
739 while (getState(internal) == Following) {
740 promise = internal->GetInternalField(InternalResultIndex).As<v8::Object>();
741 internal = getInternal(promise);
743 // FIXME: Currently we don't lookup "constructor" property since we limit
744 // the creation of the promise objects only from the Blink Promise
746 v8::Local<v8::Object> derivedPromise = createPromise(v8::Handle<v8::Object>(), isolate);
747 updateDerivedFromPromise(derivedPromise, onFulfilled, onRejected, promise, isolate);
748 return derivedPromise;
751 void V8PromiseCustom::setValue(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> value, v8::Isolate* isolate)
753 PromisePropagator propagator;
754 propagator.setValue(promise, value, isolate);
755 propagator.performPropagation(isolate);
758 void V8PromiseCustom::setReason(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> reason, v8::Isolate* isolate)
760 PromisePropagator propagator;
761 propagator.setReason(promise, reason, isolate);
762 propagator.performPropagation(isolate);
765 void V8PromiseCustom::propagateToDerived(v8::Handle<v8::Object> promise, v8::Isolate* isolate)
767 PromisePropagator propagator;
768 propagator.propagateToDerived(promise, isolate);
769 propagator.performPropagation(isolate);
772 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)
774 PromisePropagator propagator;
775 propagator.updateDerived(derivedPromise, onFulfilled, onRejected, originator, isolate);
776 propagator.performPropagation(isolate);
779 void V8PromiseCustom::updateDerivedFromValue(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Value> value, v8::Isolate* isolate)
781 PromisePropagator propagator;
782 propagator.updateDerivedFromValue(derivedPromise, onFulfilled, value, isolate);
783 propagator.performPropagation(isolate);
786 void V8PromiseCustom::updateDerivedFromReason(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Value> reason, v8::Isolate* isolate)
788 PromisePropagator propagator;
789 propagator.updateDerivedFromReason(derivedPromise, onRejected, reason, isolate);
790 propagator.performPropagation(isolate);
793 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)
795 PromisePropagator propagator;
796 propagator.updateDerivedFromPromise(derivedPromise, onFulfilled, onRejected, promise, isolate);
797 propagator.performPropagation(isolate);
800 v8::Local<v8::Object> V8PromiseCustom::coerceThenable(v8::Handle<v8::Object> thenable, v8::Handle<v8::Function> then, v8::Isolate* isolate)
802 ASSERT(!thenable.IsEmpty());
803 ASSERT(!then.IsEmpty());
804 v8::Local<v8::Object> promise = createPromise(v8::Handle<v8::Object>(), isolate);
805 v8::Handle<v8::Value> argv[] = {
806 createClosure(promiseResolveCallback, promise, isolate),
807 createClosure(promiseRejectCallback, promise, isolate)
809 v8::TryCatch trycatch;
810 if (V8ScriptRunner::callFunction(then, currentExecutionContext(isolate), thenable, WTF_ARRAY_LENGTH(argv), argv, isolate).IsEmpty()) {
811 reject(promise, trycatch.Exception(), isolate);
813 setHiddenValue(isolate, thenable, "thenableHiddenPromise", promise);
817 void V8PromiseCustom::callHandler(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> handler, v8::Handle<v8::Value> argument, PromiseState originatorState, v8::Isolate* isolate)
819 ASSERT(originatorState == Fulfilled || originatorState == Rejected);
820 ExecutionContext* executionContext = currentExecutionContext(isolate);
821 ASSERT(executionContext && executionContext->isContextThread());
822 executionContext->postTask(adoptPtr(new CallHandlerTask(promise, handler, argument, originatorState, isolate, executionContext)));
825 } // namespace WebCore