Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / bindings / v8 / custom / V8PromiseCustom.cpp
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/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"
55
56 namespace WebCore {
57
58 namespace {
59
60 v8::Local<v8::ObjectTemplate> cachedObjectTemplate(void* privateTemplateUniqueKey, int internalFieldCount, v8::Isolate* isolate)
61 {
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();
67
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;
73 }
74
75 v8::Local<v8::ObjectTemplate> promiseAllEnvironmentObjectTemplate(v8::Isolate* isolate)
76 {
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);
80 }
81
82 v8::Local<v8::ObjectTemplate> primitiveWrapperObjectTemplate(v8::Isolate* isolate)
83 {
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);
87 }
88
89 v8::Local<v8::ObjectTemplate> internalObjectTemplate(v8::Isolate* isolate)
90 {
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);
94 }
95
96 void promiseResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
97 {
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)
102         result = info[0];
103
104     V8PromiseCustom::resolve(promise, result, info.GetIsolate());
105 }
106
107 void promiseRejectCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
108 {
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)
113         result = info[0];
114
115     V8PromiseCustom::reject(promise, result, info.GetIsolate());
116 }
117
118 void promiseAllFulfillCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
119 {
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)
125         result = info[0];
126
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>();
131
132     results->Set(index->Value(), result);
133
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);
138         return;
139     }
140     countdownWrapper->SetInternalField(V8PromiseCustom::PrimitiveWrapperPrimitiveIndex, v8::Integer::New(isolate, countdown->Value() - 1));
141 }
142
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)
144 {
145     v8::Local<v8::ObjectTemplate> objectTemplate = promiseAllEnvironmentObjectTemplate(isolate);
146     v8::Local<v8::Object> environment = objectTemplate->NewInstance();
147
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);
152     return environment;
153 }
154
155 // Clear |internal|'s derived array.
156 void clearDerived(v8::Handle<v8::Object> internal, v8::Isolate* isolate)
157 {
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));
161 }
162
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)
169 {
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>();
173
174     if (onFulfilled.IsEmpty()) {
175         fulfillCallbacks->Set(fulfillCallbacks->Length(), v8::Undefined(isolate));
176     } else {
177         fulfillCallbacks->Set(fulfillCallbacks->Length(), onFulfilled);
178     }
179
180     if (onRejected.IsEmpty()) {
181         rejectCallbacks->Set(rejectCallbacks->Length(), v8::Undefined(isolate));
182     } else {
183         rejectCallbacks->Set(rejectCallbacks->Length(), onRejected);
184     }
185
186     ASSERT(!derivedPromise.IsEmpty());
187     derivedPromises->Set(derivedPromises->Length(), derivedPromise);
188
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());
192 }
193
194 class TaskPerformScopeForInstrumentation {
195 public:
196     TaskPerformScopeForInstrumentation(ExecutionContext* context, ExecutionContextTask* task)
197         : m_cookie(InspectorInstrumentation::willPerformPromiseTask(context, task))
198     {
199     }
200
201     ~TaskPerformScopeForInstrumentation()
202     {
203         InspectorInstrumentation::didPerformPromiseTask(m_cookie);
204     }
205
206 private:
207     InspectorInstrumentationCookie m_cookie;
208 };
209
210 class CallHandlerTask FINAL : public ExecutionContextTask {
211 public:
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)
217     {
218         ASSERT(!m_promise.isEmpty());
219         ASSERT(!m_handler.isEmpty());
220         ASSERT(!m_argument.isEmpty());
221         InspectorInstrumentation::didPostPromiseTask(context, this, originatorState == V8PromiseCustom::Fulfilled);
222     }
223     virtual ~CallHandlerTask() { }
224
225     virtual void performTask(ExecutionContext*) OVERRIDE;
226
227 private:
228     ScopedPersistent<v8::Object> m_promise;
229     ScopedPersistent<v8::Function> m_handler;
230     ScopedPersistent<v8::Value> m_argument;
231     DOMRequestState m_requestState;
232 };
233
234 void CallHandlerTask::performTask(ExecutionContext* context)
235 {
236     TaskPerformScopeForInstrumentation performTaskScope(context, this);
237
238     ASSERT(context);
239     if (context->activeDOMObjectsAreStopped())
240         return;
241
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);
249     } else {
250         V8PromiseCustom::resolve(m_promise.newLocal(isolate), value, isolate);
251     }
252 }
253
254 class UpdateDerivedTask FINAL : public ExecutionContextTask {
255 public:
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)
262     {
263         ASSERT(!m_promise.isEmpty());
264         ASSERT(!m_originatorValueObject.isEmpty());
265         InspectorInstrumentation::didPostPromiseTask(context, this, true);
266     }
267     virtual ~UpdateDerivedTask() { }
268
269     virtual void performTask(ExecutionContext*) OVERRIDE;
270
271 private:
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;
277 };
278
279 void UpdateDerivedTask::performTask(ExecutionContext* context)
280 {
281     TaskPerformScopeForInstrumentation performTaskScope(context, this);
282
283     ASSERT(context);
284     if (context->activeDOMObjectsAreStopped())
285         return;
286
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);
294         return;
295     }
296
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);
303         return;
304     }
305
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);
310         return;
311     }
312
313     V8PromiseCustom::updateDerivedFromValue(m_promise.newLocal(isolate), m_onFulfilled.newLocal(isolate), originatorValueObject, isolate);
314 }
315
316 // Since Promises state propagation routines are executed recursively, they cause
317 // stack overflow.
318 // (e.g. UpdateDerived -> UpdateDerivedFromValue -> SetValue ->
319 //  PropagateToDerived -> UpdateDerived)
320 //
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.
325 //
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.
330 //
331 class PromisePropagator {
332     WTF_MAKE_NONCOPYABLE(PromisePropagator);
333 public:
334     PromisePropagator() { }
335
336     void performPropagation(v8::Isolate*);
337
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*);
345
346 private:
347     class Derived {
348         WTF_MAKE_NONCOPYABLE(Derived);
349     public:
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)
355         {
356             ASSERT(!m_promise.isEmpty());
357             ASSERT(!m_originator.isEmpty());
358         }
359
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)
361         {
362             return adoptPtr(new Derived(promise, onFulfilled, onRejected, originator, isolate));
363         }
364
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); }
369
370     private:
371         ScopedPersistent<v8::Object> m_promise;
372         ScopedPersistent<v8::Function> m_onFulfilled;
373         ScopedPersistent<v8::Function> m_onRejected;
374         ScopedPersistent<v8::Object> m_originator;
375     };
376
377     Deque<OwnPtr<Derived> > m_derivedStack;
378 };
379
380 void PromisePropagator::performPropagation(v8::Isolate* isolate)
381 {
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);
386     }
387 }
388
389 void PromisePropagator::setValue(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> value, v8::Isolate* isolate)
390 {
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);
395 }
396
397 void PromisePropagator::setReason(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> reason, v8::Isolate* isolate)
398 {
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);
403 }
404
405 void PromisePropagator::propagateToDerived(v8::Handle<v8::Object> promise, v8::Isolate* isolate)
406 {
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());
415
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>();
420
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>();
425         }
426         v8::Local<v8::Value> onRejectedValue = rejectCallbacks->Get(i);
427         if (onRejectedValue->IsFunction()) {
428             onRejected = onRejectedValue.As<v8::Function>();
429         }
430
431         m_derivedStack.append(Derived::create(derivedPromise, onFulfilled, onRejected, promise, isolate));
432     }
433     clearDerived(internal, isolate);
434 }
435
436 void PromisePropagator::updateDerivedFromValue(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Value> value, v8::Isolate* isolate)
437 {
438     if (!onFulfilled.IsEmpty()) {
439         V8PromiseCustom::callHandler(derivedPromise, onFulfilled, value, V8PromiseCustom::Fulfilled, isolate);
440     } else {
441         setValue(derivedPromise, value, isolate);
442     }
443 }
444
445 void PromisePropagator::updateDerivedFromReason(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Value> reason, v8::Isolate* isolate)
446 {
447     if (!onRejected.IsEmpty()) {
448         V8PromiseCustom::callHandler(derivedPromise, onRejected, reason, V8PromiseCustom::Rejected, isolate);
449     } else {
450         setReason(derivedPromise, reason, isolate);
451     }
452 }
453
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)
455 {
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)));
465         } else {
466             updateDerivedFromValue(derivedPromise, onFulfilled, originatorValue, isolate);
467         }
468     } else {
469         updateDerivedFromReason(derivedPromise, onRejected, originatorValue, isolate);
470     }
471 }
472
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)
474 {
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);
479     } else {
480         addToDerived(internal, derivedPromise, onFulfilled, onRejected, isolate);
481     }
482 }
483
484 } // namespace
485
486 void V8Promise::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
487 {
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);
494         return;
495     }
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)
501     };
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);
506     }
507     v8SetReturnValue(info, promise);
508     return;
509 }
510
511 void V8Promise::thenMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
512 {
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));
520 }
521
522 void V8Promise::castMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
523 {
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)
529         result = info[0];
530
531     v8SetReturnValue(info, V8PromiseCustom::toPromise(result, isolate));
532 }
533
534 void V8Promise::catchMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
535 {
536     v8::Isolate* isolate = info.GetIsolate();
537     v8::Local<v8::Function> onFulfilled, onRejected;
538
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));
542             return;
543         }
544         onRejected = info[0].As<v8::Function>();
545     }
546     v8SetReturnValue(info, V8PromiseCustom::then(info.Holder(), onFulfilled, onRejected, isolate));
547 }
548
549 void V8Promise::resolveMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
550 {
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)
556         result = info[0];
557
558     v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(info.Holder(), isolate);
559     V8PromiseCustom::resolve(promise, result, isolate);
560     v8SetReturnValue(info, promise);
561 }
562
563 void V8Promise::rejectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
564 {
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)
570         result = info[0];
571
572     v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(info.Holder(), isolate);
573     V8PromiseCustom::reject(promise, result, isolate);
574     v8SetReturnValue(info, promise);
575 }
576
577 void V8Promise::raceMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
578 {
579     v8::Isolate* isolate = info.GetIsolate();
580     v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(info.Holder(), isolate);
581
582     if (!info.Length() || !info[0]->IsArray()) {
583         v8SetReturnValue(info, promise);
584         return;
585     }
586
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);
591
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);
597     }
598     v8SetReturnValue(info, promise);
599 }
600
601 void V8Promise::allMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
602 {
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());
606
607     if (!info.Length() || !info[0]->IsArray()) {
608         V8PromiseCustom::resolve(promise, results, isolate);
609         v8SetReturnValue(info, promise);
610         return;
611     }
612
613     // FIXME: Now we limit the iterable type to the Array type.
614     v8::Local<v8::Array> iterable = info[0].As<v8::Array>();
615
616     if (!iterable->Length()) {
617         V8PromiseCustom::resolve(promise, results, isolate);
618         v8SetReturnValue(info, promise);
619         return;
620     }
621
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()));
625
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);
634     }
635     v8SetReturnValue(info, promise);
636 }
637
638 //
639 // -- V8PromiseCustom --
640 v8::Local<v8::Object> V8PromiseCustom::createPromise(v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
641 {
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);
645
646     clearDerived(internal, isolate);
647     setState(internal, Pending, v8::Undefined(isolate), isolate);
648
649     promise->SetInternalField(v8DOMWrapperObjectIndex, internal);
650     return promise;
651 }
652
653 v8::Local<v8::Object> V8PromiseCustom::getInternal(v8::Handle<v8::Object> promise)
654 {
655     v8::Local<v8::Value> value = promise->GetInternalField(v8DOMWrapperObjectIndex);
656     return value.As<v8::Object>();
657 }
658
659 V8PromiseCustom::PromiseState V8PromiseCustom::getState(v8::Handle<v8::Object> internal)
660 {
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);
665 }
666
667 void V8PromiseCustom::setState(v8::Handle<v8::Object> internal, PromiseState state, v8::Handle<v8::Value> value, v8::Isolate* isolate)
668 {
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);
673 }
674
675 bool V8PromiseCustom::isPromise(v8::Handle<v8::Value> maybePromise, v8::Isolate* isolate)
676 {
677     WrapperWorldType currentWorldType = worldType(isolate);
678     return V8Promise::domTemplate(isolate, currentWorldType)->HasInstance(maybePromise);
679 }
680
681 v8::Local<v8::Object> V8PromiseCustom::toPromise(v8::Handle<v8::Value> maybePromise, v8::Isolate* isolate)
682 {
683     // FIXME: Currently we don't check [[PromiseConstructor]] since we limit
684     // the creation of the promise objects only from the Blink Promise
685     // constructor.
686     if (isPromise(maybePromise, isolate))
687         return maybePromise.As<v8::Object>();
688
689     v8::Local<v8::Object> promise = createPromise(v8::Handle<v8::Object>(), isolate);
690     resolve(promise, maybePromise, isolate);
691     return promise;
692 }
693
694 void V8PromiseCustom::resolve(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> result, v8::Isolate* isolate)
695 {
696     ASSERT(!result.IsEmpty());
697     v8::Local<v8::Object> internal = getInternal(promise);
698     PromiseState state = getState(internal);
699     if (state != Pending)
700         return;
701
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);
717         } else {
718             ASSERT(valueState == Pending);
719             setState(internal, Following, valuePromise, isolate);
720             addToDerived(valueInternal, promise, v8::Handle<v8::Function>(), v8::Handle<v8::Function>(), isolate);
721         }
722     } else {
723         setValue(promise, result, isolate);
724     }
725 }
726
727 void V8PromiseCustom::reject(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> reason, v8::Isolate* isolate)
728 {
729     v8::Local<v8::Object> internal = getInternal(promise);
730     PromiseState state = getState(internal);
731     if (state != Pending)
732         return;
733     setReason(promise, reason, isolate);
734 }
735
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)
737 {
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);
742     }
743     // FIXME: Currently we don't lookup "constructor" property since we limit
744     // the creation of the promise objects only from the Blink Promise
745     // constructor.
746     v8::Local<v8::Object> derivedPromise = createPromise(v8::Handle<v8::Object>(), isolate);
747     updateDerivedFromPromise(derivedPromise, onFulfilled, onRejected, promise, isolate);
748     return derivedPromise;
749 }
750
751 void V8PromiseCustom::setValue(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> value, v8::Isolate* isolate)
752 {
753     PromisePropagator propagator;
754     propagator.setValue(promise, value, isolate);
755     propagator.performPropagation(isolate);
756 }
757
758 void V8PromiseCustom::setReason(v8::Handle<v8::Object> promise, v8::Handle<v8::Value> reason, v8::Isolate* isolate)
759 {
760     PromisePropagator propagator;
761     propagator.setReason(promise, reason, isolate);
762     propagator.performPropagation(isolate);
763 }
764
765 void V8PromiseCustom::propagateToDerived(v8::Handle<v8::Object> promise, v8::Isolate* isolate)
766 {
767     PromisePropagator propagator;
768     propagator.propagateToDerived(promise, isolate);
769     propagator.performPropagation(isolate);
770 }
771
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)
773 {
774     PromisePropagator propagator;
775     propagator.updateDerived(derivedPromise, onFulfilled, onRejected, originator, isolate);
776     propagator.performPropagation(isolate);
777 }
778
779 void V8PromiseCustom::updateDerivedFromValue(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Value> value, v8::Isolate* isolate)
780 {
781     PromisePropagator propagator;
782     propagator.updateDerivedFromValue(derivedPromise, onFulfilled, value, isolate);
783     propagator.performPropagation(isolate);
784 }
785
786 void V8PromiseCustom::updateDerivedFromReason(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Value> reason, v8::Isolate* isolate)
787 {
788     PromisePropagator propagator;
789     propagator.updateDerivedFromReason(derivedPromise, onRejected, reason, isolate);
790     propagator.performPropagation(isolate);
791 }
792
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)
794 {
795     PromisePropagator propagator;
796     propagator.updateDerivedFromPromise(derivedPromise, onFulfilled, onRejected, promise, isolate);
797     propagator.performPropagation(isolate);
798 }
799
800 v8::Local<v8::Object> V8PromiseCustom::coerceThenable(v8::Handle<v8::Object> thenable, v8::Handle<v8::Function> then, v8::Isolate* isolate)
801 {
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)
808     };
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);
812     }
813     setHiddenValue(isolate, thenable, "thenableHiddenPromise", promise);
814     return promise;
815 }
816
817 void V8PromiseCustom::callHandler(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> handler, v8::Handle<v8::Value> argument, PromiseState originatorState, v8::Isolate* isolate)
818 {
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)));
823 }
824
825 } // namespace WebCore