Home | History | Annotate | Download | only in v8
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef ScriptPromiseProperty_h
      6 #define ScriptPromiseProperty_h
      7 
      8 #include "bindings/core/v8/ScriptPromise.h"
      9 #include "bindings/core/v8/ScriptPromisePropertyBase.h"
     10 #include "bindings/core/v8/V8Binding.h"
     11 #include "wtf/Noncopyable.h"
     12 #include "wtf/PassRefPtr.h"
     13 
     14 namespace blink {
     15 
     16 class ExecutionContext;
     17 
     18 // ScriptPromiseProperty is a helper for implementing a DOM method or
     19 // attribute whose value is a Promise, and the same Promise must be
     20 // returned each time.
     21 //
     22 // ScriptPromiseProperty does not keep Promises or worlds alive to
     23 // deliver Promise resolution/rejection to them; the Promise
     24 // resolution/rejections are delivered if the holder's wrapper is
     25 // alive. This is achieved by keeping a weak reference from
     26 // ScriptPromiseProperty to the holder's wrapper, and references in
     27 // hidden values from the wrapper to the promise and resolver
     28 // (coincidentally the Resolver and Promise may be the same object,
     29 // but that is an implementation detail of v8.)
     30 //
     31 //                                             ----> Resolver
     32 //                                            /
     33 // ScriptPromiseProperty - - -> Holder Wrapper ----> Promise
     34 //
     35 // To avoid exposing the action of the garbage collector to script,
     36 // you should keep the wrapper alive as long as a promise may be
     37 // settled.
     38 //
     39 // To avoid clobbering hidden values, a holder should only have one
     40 // ScriptPromiseProperty object for a given name at a time. See reset.
     41 template<typename HolderType, typename ResolvedType, typename RejectedType>
     42 class ScriptPromiseProperty : public ScriptPromisePropertyBase {
     43     WTF_MAKE_NONCOPYABLE(ScriptPromiseProperty);
     44 public:
     45     // Creates a ScriptPromiseProperty that will create Promises in
     46     // the specified ExecutionContext for a property of 'holder'
     47     // (typically ScriptPromiseProperty should be a member of the
     48     // property holder).
     49     //
     50     // When implementing a ScriptPromiseProperty add the property name
     51     // to ScriptPromiseProperties.h and pass
     52     // ScriptPromiseProperty::Foo to create. The name must be unique
     53     // per kind of holder.
     54     template<typename PassHolderType>
     55     ScriptPromiseProperty(ExecutionContext*, PassHolderType, Name);
     56 
     57     virtual ~ScriptPromiseProperty() { }
     58 
     59     template<typename PassResolvedType>
     60     void resolve(PassResolvedType);
     61 
     62     template<typename PassRejectedType>
     63     void reject(PassRejectedType);
     64 
     65     // Resets this property by unregistering the Promise property from the
     66     // holder wrapper. Resets the internal state to Pending and clears the
     67     // resolved and the rejected values.
     68     // This method keeps the holder object and the property name.
     69     void reset();
     70 
     71     virtual void trace(Visitor*) OVERRIDE;
     72 
     73 private:
     74     virtual v8::Handle<v8::Object> holder(v8::Handle<v8::Object> creationContext, v8::Isolate*) OVERRIDE;
     75     virtual v8::Handle<v8::Value> resolvedValue(v8::Handle<v8::Object> creationContext, v8::Isolate*) OVERRIDE;
     76     virtual v8::Handle<v8::Value> rejectedValue(v8::Handle<v8::Object> creationContext, v8::Isolate*) OVERRIDE;
     77 
     78     HolderType m_holder;
     79     ResolvedType m_resolved;
     80     RejectedType m_rejected;
     81 };
     82 
     83 template<typename HolderType, typename ResolvedType, typename RejectedType>
     84 template<typename PassHolderType>
     85 ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::ScriptPromiseProperty(ExecutionContext* executionContext, PassHolderType holder, Name name)
     86     : ScriptPromisePropertyBase(executionContext, name)
     87     , m_holder(holder)
     88 {
     89 }
     90 
     91 template<typename HolderType, typename ResolvedType, typename RejectedType>
     92 template<typename PassResolvedType>
     93 void ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::resolve(PassResolvedType value)
     94 {
     95     if (state() != Pending) {
     96         ASSERT_NOT_REACHED();
     97         return;
     98     }
     99     if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
    100         return;
    101     m_resolved = value;
    102     resolveOrReject(Resolved);
    103 }
    104 
    105 template<typename HolderType, typename ResolvedType, typename RejectedType>
    106 template<typename PassRejectedType>
    107 void ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::reject(PassRejectedType value)
    108 {
    109     if (state() != Pending) {
    110         ASSERT_NOT_REACHED();
    111         return;
    112     }
    113     if (!executionContext() || executionContext()->activeDOMObjectsAreStopped())
    114         return;
    115     m_rejected = value;
    116     resolveOrReject(Rejected);
    117 }
    118 
    119 template<typename HolderType, typename ResolvedType, typename RejectedType>
    120 v8::Handle<v8::Object> ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::holder(v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
    121 {
    122     v8::Handle<v8::Value> value = V8ValueTraits<HolderType>::toV8Value(m_holder, creationContext, isolate);
    123     return value.As<v8::Object>();
    124 }
    125 
    126 template<typename HolderType, typename ResolvedType, typename RejectedType>
    127 v8::Handle<v8::Value> ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::resolvedValue(v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
    128 {
    129     ASSERT(state() == Resolved);
    130     return V8ValueTraits<ResolvedType>::toV8Value(m_resolved, creationContext, isolate);
    131 }
    132 
    133 template<typename HolderType, typename ResolvedType, typename RejectedType>
    134 v8::Handle<v8::Value> ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::rejectedValue(v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
    135 {
    136     ASSERT(state() == Rejected);
    137     return V8ValueTraits<RejectedType>::toV8Value(m_rejected, creationContext, isolate);
    138 }
    139 
    140 template<typename HolderType, typename ResolvedType, typename RejectedType>
    141 void ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::reset()
    142 {
    143     resetBase();
    144     m_resolved = ResolvedType();
    145     m_rejected = RejectedType();
    146 }
    147 
    148 template<typename HolderType, typename ResolvedType, typename RejectedType>
    149 void ScriptPromiseProperty<HolderType, ResolvedType, RejectedType>::trace(Visitor* visitor)
    150 {
    151     TraceIfNeeded<HolderType>::trace(visitor, &m_holder);
    152     TraceIfNeeded<ResolvedType>::trace(visitor, &m_resolved);
    153     TraceIfNeeded<RejectedType>::trace(visitor, &m_rejected);
    154     ScriptPromisePropertyBase::trace(visitor);
    155 }
    156 
    157 } // namespace blink
    158 
    159 #endif // ScriptPromiseProperty_h
    160