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