Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / bindings / core / v8 / ScriptPromisePropertyBase.cpp
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 #include "config.h"
6 #include "bindings/core/v8/ScriptPromisePropertyBase.h"
7
8 #include "bindings/core/v8/ScopedPersistent.h"
9 #include "bindings/core/v8/ScriptState.h"
10 #include "bindings/core/v8/V8Binding.h"
11 #include "bindings/core/v8/V8HiddenValue.h"
12 #include "core/dom/ExecutionContext.h"
13
14 namespace blink {
15
16 ScriptPromisePropertyBase::ScriptPromisePropertyBase(ExecutionContext* executionContext, Name name)
17     : ContextLifecycleObserver(executionContext)
18     , m_isolate(toIsolate(executionContext))
19     , m_name(name)
20     , m_state(Pending)
21 {
22 }
23
24 ScriptPromisePropertyBase::~ScriptPromisePropertyBase()
25 {
26     clearWrappers();
27 }
28
29 static void clearHandle(const v8::WeakCallbackData<v8::Object, ScopedPersistent<v8::Object> >& data)
30 {
31     data.GetParameter()->clear();
32 }
33
34 ScriptPromise ScriptPromisePropertyBase::promise(DOMWrapperWorld& world)
35 {
36     if (!executionContext())
37         return ScriptPromise();
38
39     v8::HandleScope handleScope(m_isolate);
40     v8::Handle<v8::Context> context = toV8Context(executionContext(), world);
41     if (context.IsEmpty())
42         return ScriptPromise();
43     ScriptState* scriptState = ScriptState::from(context);
44     ScriptState::Scope scope(scriptState);
45
46     v8::Handle<v8::Object> wrapper = ensureHolderWrapper(scriptState);
47     ASSERT(wrapper->CreationContext() == context);
48
49     v8::Handle<v8::Value> cachedPromise = V8HiddenValue::getHiddenValue(m_isolate, wrapper, promiseName());
50     if (!cachedPromise.IsEmpty())
51         return ScriptPromise(scriptState, cachedPromise);
52
53     // Create and cache the Promise
54     v8::Handle<v8::Promise::Resolver> resolver = v8::Promise::Resolver::New(m_isolate);
55     v8::Handle<v8::Promise> promise = resolver->GetPromise();
56     V8HiddenValue::setHiddenValue(m_isolate, wrapper, promiseName(), promise);
57
58     switch (m_state) {
59     case Pending:
60         // Cache the resolver too
61         V8HiddenValue::setHiddenValue(m_isolate, wrapper, resolverName(), resolver);
62         break;
63     case Resolved:
64     case Rejected:
65         resolveOrRejectInternal(resolver);
66         break;
67     }
68
69     return ScriptPromise(scriptState, promise);
70 }
71
72 void ScriptPromisePropertyBase::resolveOrReject(State targetState)
73 {
74     ASSERT(executionContext());
75     ASSERT(m_state == Pending);
76     ASSERT(targetState == Resolved || targetState == Rejected);
77
78     m_state = targetState;
79
80     v8::HandleScope handleScope(m_isolate);
81     size_t i = 0;
82     while (i < m_wrappers.size()) {
83         const OwnPtr<ScopedPersistent<v8::Object> >& persistent = m_wrappers[i];
84         if (persistent->isEmpty()) {
85             // wrapper has died.
86             // Since v8 GC can run during the iteration and clear the reference,
87             // we can't move this check out of the loop.
88             m_wrappers.remove(i);
89             continue;
90         }
91         v8::Local<v8::Object> wrapper = persistent->newLocal(m_isolate);
92         ScriptState::Scope scope(ScriptState::from(wrapper->CreationContext()));
93
94         v8::Local<v8::Promise::Resolver> resolver = V8HiddenValue::getHiddenValue(m_isolate, wrapper, resolverName()).As<v8::Promise::Resolver>();
95
96         V8HiddenValue::deleteHiddenValue(m_isolate, wrapper, resolverName());
97         resolveOrRejectInternal(resolver);
98         ++i;
99     }
100 }
101
102 void ScriptPromisePropertyBase::resetBase()
103 {
104     clearWrappers();
105     m_state = Pending;
106 }
107
108 void ScriptPromisePropertyBase::resolveOrRejectInternal(v8::Handle<v8::Promise::Resolver> resolver)
109 {
110     switch (m_state) {
111     case Pending:
112         ASSERT_NOT_REACHED();
113         break;
114     case Resolved:
115         resolver->Resolve(resolvedValue(m_isolate, resolver->CreationContext()->Global()));
116         break;
117     case Rejected:
118         resolver->Reject(rejectedValue(m_isolate, resolver->CreationContext()->Global()));
119         break;
120     }
121 }
122
123 v8::Local<v8::Object> ScriptPromisePropertyBase::ensureHolderWrapper(ScriptState* scriptState)
124 {
125     v8::Local<v8::Context> context = scriptState->context();
126     size_t i = 0;
127     while (i < m_wrappers.size()) {
128         const OwnPtr<ScopedPersistent<v8::Object> >& persistent = m_wrappers[i];
129         if (persistent->isEmpty()) {
130             // wrapper has died.
131             // Since v8 GC can run during the iteration and clear the reference,
132             // we can't move this check out of the loop.
133             m_wrappers.remove(i);
134             continue;
135         }
136
137         v8::Local<v8::Object> wrapper = persistent->newLocal(m_isolate);
138         if (wrapper->CreationContext() == context)
139             return wrapper;
140         ++i;
141     }
142     v8::Local<v8::Object> wrapper = holder(context->Global(), m_isolate);
143     OwnPtr<ScopedPersistent<v8::Object> > weakPersistent = adoptPtr(new ScopedPersistent<v8::Object>);
144     weakPersistent->set(m_isolate, wrapper);
145     weakPersistent->setWeak(weakPersistent.get(), &clearHandle);
146     m_wrappers.append(weakPersistent.release());
147     return wrapper;
148 }
149
150 void ScriptPromisePropertyBase::clearWrappers()
151 {
152     v8::HandleScope handleScope(m_isolate);
153     for (WeakPersistentSet::iterator i = m_wrappers.begin(); i != m_wrappers.end(); ++i) {
154         v8::Local<v8::Object> wrapper = (*i)->newLocal(m_isolate);
155         if (!wrapper.IsEmpty()) {
156             wrapper->DeleteHiddenValue(resolverName());
157             wrapper->DeleteHiddenValue(promiseName());
158         }
159     }
160     m_wrappers.clear();
161 }
162
163 v8::Handle<v8::String> ScriptPromisePropertyBase::promiseName()
164 {
165     switch (m_name) {
166 #define P(Name)                                           \
167     case Name:                                            \
168         return V8HiddenValue::Name ## Promise(m_isolate);
169
170         SCRIPT_PROMISE_PROPERTIES(P)
171
172 #undef P
173     }
174     ASSERT_NOT_REACHED();
175     return v8::Handle<v8::String>();
176 }
177
178 v8::Handle<v8::String> ScriptPromisePropertyBase::resolverName()
179 {
180     switch (m_name) {
181 #define P(Name)                                            \
182     case Name:                                             \
183         return V8HiddenValue::Name ## Resolver(m_isolate);
184
185         SCRIPT_PROMISE_PROPERTIES(P)
186
187 #undef P
188     }
189     ASSERT_NOT_REACHED();
190     return v8::Handle<v8::String>();
191 }
192
193 } // namespace blink