• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
cachedObjectTemplate(void * privateTemplateUniqueKey,int internalFieldCount,v8::Isolate * isolate)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 
promiseAllEnvironmentObjectTemplate(v8::Isolate * isolate)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 
primitiveWrapperObjectTemplate(v8::Isolate * isolate)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 
internalObjectTemplate(v8::Isolate * isolate)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 
promiseResolveCallback(const v8::FunctionCallbackInfo<v8::Value> & info)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 
promiseRejectCallback(const v8::FunctionCallbackInfo<v8::Value> & info)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 
promiseAllFulfillCallback(const v8::FunctionCallbackInfo<v8::Value> & info)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 
promiseAllEnvironment(v8::Handle<v8::Object> promise,v8::Handle<v8::Object> countdownWrapper,int index,v8::Handle<v8::Array> results,v8::Isolate * isolate)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.
clearDerived(v8::Handle<v8::Object> internal,v8::Isolate * isolate)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.
addToDerived(v8::Handle<v8::Object> internal,v8::Handle<v8::Object> derivedPromise,v8::Handle<v8::Function> onFulfilled,v8::Handle<v8::Function> onRejected,v8::Isolate * isolate)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:
CallHandlerTask(v8::Handle<v8::Object> promise,v8::Handle<v8::Function> handler,v8::Handle<v8::Value> argument,v8::Isolate * isolate,ExecutionContext * context)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     }
~CallHandlerTask()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 
performTask(ExecutionContext * context)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:
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)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     }
~UpdateDerivedTask()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 
performTask(ExecutionContext * context)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:
PromisePropagator()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:
Derived(v8::Handle<v8::Object> promise,v8::Handle<v8::Function> onFulfilled,v8::Handle<v8::Function> onRejected,v8::Handle<v8::Object> originator,v8::Isolate * isolate)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 
create(v8::Handle<v8::Object> promise,v8::Handle<v8::Function> onFulfilled,v8::Handle<v8::Function> onRejected,v8::Handle<v8::Object> originator,v8::Isolate * isolate)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 
promise(v8::Isolate * isolate) const342         v8::Local<v8::Object> promise(v8::Isolate* isolate) const { return m_promise.newLocal(isolate); }
onFulfilled(v8::Isolate * isolate) const343         v8::Local<v8::Function> onFulfilled(v8::Isolate* isolate) const { return m_onFulfilled.newLocal(isolate); }
onRejected(v8::Isolate * isolate) const344         v8::Local<v8::Function> onRejected(v8::Isolate* isolate) const { return m_onRejected.newLocal(isolate); }
originator(v8::Isolate * isolate) const345         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 
performPropagation(v8::Isolate * isolate)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 
setValue(v8::Handle<v8::Object> promise,v8::Handle<v8::Value> value,v8::Isolate * isolate)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 
setReason(v8::Handle<v8::Object> promise,v8::Handle<v8::Value> reason,v8::Isolate * isolate)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 
propagateToDerived(v8::Handle<v8::Object> promise,v8::Isolate * isolate)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 
updateDerivedFromValue(v8::Handle<v8::Object> derivedPromise,v8::Handle<v8::Function> onFulfilled,v8::Handle<v8::Value> value,v8::Isolate * isolate)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 
updateDerivedFromReason(v8::Handle<v8::Object> derivedPromise,v8::Handle<v8::Function> onRejected,v8::Handle<v8::Value> reason,v8::Isolate * isolate)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 
updateDerived(v8::Handle<v8::Object> derivedPromise,v8::Handle<v8::Function> onFulfilled,v8::Handle<v8::Function> onRejected,v8::Handle<v8::Object> originator,v8::Isolate * isolate)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 
updateDerivedFromPromise(v8::Handle<v8::Object> derivedPromise,v8::Handle<v8::Function> onFulfilled,v8::Handle<v8::Function> onRejected,v8::Handle<v8::Object> promise,v8::Isolate * isolate)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 
constructorCustom(const v8::FunctionCallbackInfo<v8::Value> & info)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 
thenMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)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 
castMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)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 
catchMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)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 
resolveMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)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 
rejectMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)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 
raceMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)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 
allMethodCustom(const v8::FunctionCallbackInfo<v8::Value> & info)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 --
createPromise(v8::Handle<v8::Object> creationContext,v8::Isolate * isolate)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 
getInternal(v8::Handle<v8::Object> promise)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 
getState(v8::Handle<v8::Object> internal)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 
setState(v8::Handle<v8::Object> internal,PromiseState state,v8::Handle<v8::Value> value,v8::Isolate * isolate)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 
isPromise(v8::Handle<v8::Value> maybePromise,v8::Isolate * isolate)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 
toPromise(v8::Handle<v8::Value> maybePromise,v8::Isolate * isolate)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 
resolve(v8::Handle<v8::Object> promise,v8::Handle<v8::Value> result,v8::Isolate * isolate)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 
reject(v8::Handle<v8::Object> promise,v8::Handle<v8::Value> reason,v8::Isolate * isolate)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 
then(v8::Handle<v8::Object> promise,v8::Handle<v8::Function> onFulfilled,v8::Handle<v8::Function> onRejected,v8::Isolate * isolate)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 
setValue(v8::Handle<v8::Object> promise,v8::Handle<v8::Value> value,v8::Isolate * isolate)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 
setReason(v8::Handle<v8::Object> promise,v8::Handle<v8::Value> reason,v8::Isolate * isolate)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 
propagateToDerived(v8::Handle<v8::Object> promise,v8::Isolate * isolate)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 
updateDerived(v8::Handle<v8::Object> derivedPromise,v8::Handle<v8::Function> onFulfilled,v8::Handle<v8::Function> onRejected,v8::Handle<v8::Object> originator,v8::Isolate * isolate)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 
updateDerivedFromValue(v8::Handle<v8::Object> derivedPromise,v8::Handle<v8::Function> onFulfilled,v8::Handle<v8::Value> value,v8::Isolate * isolate)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 
updateDerivedFromReason(v8::Handle<v8::Object> derivedPromise,v8::Handle<v8::Function> onRejected,v8::Handle<v8::Value> reason,v8::Isolate * isolate)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 
updateDerivedFromPromise(v8::Handle<v8::Object> derivedPromise,v8::Handle<v8::Function> onFulfilled,v8::Handle<v8::Function> onRejected,v8::Handle<v8::Object> promise,v8::Isolate * isolate)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 
coerceThenable(v8::Handle<v8::Object> thenable,v8::Handle<v8::Function> then,v8::Isolate * isolate)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 
callHandler(v8::Handle<v8::Object> promise,v8::Handle<v8::Function> handler,v8::Handle<v8::Value> argument,v8::Isolate * isolate)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