Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(251)

Side by Side Diff: Source/bindings/v8/custom/V8PromiseCustom.cpp

Issue 293933002: Remove the Promises old implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/bindings/v8/custom/V8PromiseCustom.h ('k') | Source/core/core.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "V8Promise.h"
35 #include "bindings/v8/ScopedPersistent.h"
36 #include "bindings/v8/ScriptFunctionCall.h"
37 #include "bindings/v8/ScriptState.h"
38 #include "bindings/v8/V8Binding.h"
39 #include "bindings/v8/V8HiddenValue.h"
40 #include "bindings/v8/V8PerIsolateData.h"
41 #include "bindings/v8/V8ScriptRunner.h"
42 #include "bindings/v8/WrapperTypeInfo.h"
43 #include "core/dom/Document.h"
44 #include "core/dom/ExecutionContextTask.h"
45 #include "core/frame/DOMWindow.h"
46 #include "core/frame/UseCounter.h"
47 #include "core/workers/WorkerGlobalScope.h"
48 #include "platform/Task.h"
49 #include "wtf/Deque.h"
50 #include "wtf/Functional.h"
51 #include "wtf/Noncopyable.h"
52 #include "wtf/PassOwnPtr.h"
53 #include <v8.h>
54
55 #define TONATIVE_VOID_EMPTY(type, var, value) \
56 type var; \
57 { \
58 v8::TryCatch block; \
59 var = (value); \
60 if (UNLIKELY(block.HasCaught())) { \
61 return; \
62 } \
63 }
64
65 namespace WebCore {
66
67 namespace {
68
69 v8::Local<v8::ObjectTemplate> cachedObjectTemplate(void* domTemplateKey, int int ernalFieldCount, v8::Isolate* isolate)
70 {
71 V8PerIsolateData* data = V8PerIsolateData::from(isolate);
72 v8::Handle<v8::FunctionTemplate> functionDescriptor = data->existingDOMTempl ate(domTemplateKey);
73 if (!functionDescriptor.IsEmpty())
74 return functionDescriptor->InstanceTemplate();
75
76 functionDescriptor = v8::FunctionTemplate::New(isolate);
77 v8::Local<v8::ObjectTemplate> instanceTemplate = functionDescriptor->Instanc eTemplate();
78 instanceTemplate->SetInternalFieldCount(internalFieldCount);
79 data->setDOMTemplate(domTemplateKey, functionDescriptor);
80 return instanceTemplate;
81 }
82
83 v8::Local<v8::ObjectTemplate> promiseAllEnvironmentObjectTemplate(v8::Isolate* i solate)
84 {
85 static int domTemplateKey; // This address is used for a key to look up the dom template.
86 return cachedObjectTemplate(&domTemplateKey, V8PromiseCustom::PromiseAllEnvi ronmentFieldCount, isolate);
87 }
88
89 v8::Local<v8::ObjectTemplate> primitiveWrapperObjectTemplate(v8::Isolate* isolat e)
90 {
91 static int domTemplateKey; // This address is used for a key to look up the dom template.
92 return cachedObjectTemplate(&domTemplateKey, V8PromiseCustom::PrimitiveWrapp erFieldCount, isolate);
93 }
94
95 v8::Local<v8::ObjectTemplate> internalObjectTemplate(v8::Isolate* isolate)
96 {
97 static int domTemplateKey; // This address is used for a key to look up the dom template.
98 return cachedObjectTemplate(&domTemplateKey, V8PromiseCustom::InternalFieldC ount, isolate);
99 }
100
101 void promiseResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
102 {
103 ASSERT(!info.Data().IsEmpty());
104 v8::Local<v8::Object> promise = info.Data().As<v8::Object>();
105 v8::Local<v8::Value> result = v8::Undefined(info.GetIsolate());
106 if (info.Length() > 0)
107 result = info[0];
108
109 V8PromiseCustom::resolve(promise, result, info.GetIsolate());
110 }
111
112 void promiseRejectCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
113 {
114 ASSERT(!info.Data().IsEmpty());
115 v8::Local<v8::Object> promise = info.Data().As<v8::Object>();
116 v8::Local<v8::Value> result = v8::Undefined(info.GetIsolate());
117 if (info.Length() > 0)
118 result = info[0];
119
120 V8PromiseCustom::reject(promise, result, info.GetIsolate());
121 }
122
123 void promiseAllFulfillCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
124 {
125 v8::Isolate* isolate = info.GetIsolate();
126 ASSERT(!info.Data().IsEmpty());
127 v8::Local<v8::Object> environment = info.Data().As<v8::Object>();
128 v8::Local<v8::Value> result = v8::Undefined(isolate);
129 if (info.Length() > 0)
130 result = info[0];
131
132 v8::Local<v8::Object> promise = environment->GetInternalField(V8PromiseCusto m::PromiseAllEnvironmentPromiseIndex).As<v8::Object>();
133 v8::Local<v8::Object> countdownWrapper = environment->GetInternalField(V8Pro miseCustom::PromiseAllEnvironmentCountdownIndex).As<v8::Object>();
134 v8::Local<v8::Integer> index = environment->GetInternalField(V8PromiseCustom ::PromiseAllEnvironmentIndexIndex).As<v8::Integer>();
135 v8::Local<v8::Array> results = environment->GetInternalField(V8PromiseCustom ::PromiseAllEnvironmentResultsIndex).As<v8::Array>();
136
137 results->Set(index->Value(), result);
138
139 v8::Local<v8::Integer> countdown = countdownWrapper->GetInternalField(V8Prom iseCustom::PrimitiveWrapperPrimitiveIndex).As<v8::Integer>();
140 ASSERT(countdown->Value() >= 1);
141 if (countdown->Value() == 1) {
142 V8PromiseCustom::resolve(promise, results, isolate);
143 return;
144 }
145 countdownWrapper->SetInternalField(V8PromiseCustom::PrimitiveWrapperPrimitiv eIndex, v8::Integer::New(isolate, countdown->Value() - 1));
146 }
147
148 v8::Local<v8::Object> promiseAllEnvironment(v8::Handle<v8::Object> promise, v8:: Handle<v8::Object> countdownWrapper, int index, v8::Handle<v8::Array> results, v 8::Isolate* isolate)
149 {
150 v8::Local<v8::ObjectTemplate> objectTemplate = promiseAllEnvironmentObjectTe mplate(isolate);
151 v8::Local<v8::Object> environment = objectTemplate->NewInstance();
152 if (environment.IsEmpty())
153 return v8::Local<v8::Object>();
154
155 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentPromiseI ndex, promise);
156 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentCountdow nIndex, countdownWrapper);
157 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentIndexInd ex, v8::Integer::New(isolate, index));
158 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentResultsI ndex, results);
159 return environment;
160 }
161
162 // Clear |internal|'s derived array.
163 void clearDerived(v8::Handle<v8::Object> internal, v8::Isolate* isolate)
164 {
165 internal->SetInternalField(V8PromiseCustom::InternalFulfillCallbackIndex, v8 ::Array::New(isolate));
166 internal->SetInternalField(V8PromiseCustom::InternalRejectCallbackIndex, v8: :Array::New(isolate));
167 internal->SetInternalField(V8PromiseCustom::InternalDerivedPromiseIndex, v8: :Array::New(isolate));
168 }
169
170 // Add a tuple (|derivedPromise|, |onFulfilled|, |onRejected|) to
171 // |internal|'s derived array.
172 // |internal| must be a Promise internal object.
173 // |derivedPromise| must be a Promise instance.
174 // |onFulfilled| and |onRejected| can be an empty value respectively.
175 void addToDerived(v8::Handle<v8::Object> internal, v8::Handle<v8::Object> derive dPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejec ted, v8::Isolate* isolate)
176 {
177 v8::Local<v8::Array> fulfillCallbacks = internal->GetInternalField(V8Promise Custom::InternalFulfillCallbackIndex).As<v8::Array>();
178 v8::Local<v8::Array> rejectCallbacks = internal->GetInternalField(V8PromiseC ustom::InternalRejectCallbackIndex).As<v8::Array>();
179 v8::Local<v8::Array> derivedPromises = internal->GetInternalField(V8PromiseC ustom::InternalDerivedPromiseIndex).As<v8::Array>();
180
181 if (onFulfilled.IsEmpty()) {
182 fulfillCallbacks->Set(fulfillCallbacks->Length(), v8::Undefined(isolate) );
183 } else {
184 fulfillCallbacks->Set(fulfillCallbacks->Length(), onFulfilled);
185 }
186
187 if (onRejected.IsEmpty()) {
188 rejectCallbacks->Set(rejectCallbacks->Length(), v8::Undefined(isolate));
189 } else {
190 rejectCallbacks->Set(rejectCallbacks->Length(), onRejected);
191 }
192
193 ASSERT(!derivedPromise.IsEmpty());
194 derivedPromises->Set(derivedPromises->Length(), derivedPromise);
195
196 // Since they are treated as a tuple,
197 // we need to guaranteed that the length of these arrays are same.
198 ASSERT(fulfillCallbacks->Length() == rejectCallbacks->Length() && rejectCall backs->Length() == derivedPromises->Length());
199 }
200
201 // Set a |promise|'s state and result that correspond to the state.
202 // |promise| must be a Promise instance.
203 void setStateForPromise(v8::Handle<v8::Object> promise, V8PromiseCustom::Promise State state, v8::Handle<v8::Value> value, v8::Isolate* isolate)
204 {
205 ASSERT(!value.IsEmpty());
206 ASSERT(state == V8PromiseCustom::Pending || state == V8PromiseCustom::Fulfil led || state == V8PromiseCustom::Rejected || state == V8PromiseCustom::Following );
207 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise);
208 internal->SetInternalField(V8PromiseCustom::InternalStateIndex, v8::Integer: :New(isolate, state));
209 internal->SetInternalField(V8PromiseCustom::InternalResultIndex, value);
210 }
211
212 class CallHandlerTask FINAL : public ExecutionContextTask {
213 public:
214 CallHandlerTask(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> han dler, v8::Handle<v8::Value> argument, V8PromiseCustom::PromiseState originatorSt ate, v8::Isolate* isolate, ExecutionContext* context)
215 : m_promise(isolate, promise)
216 , m_handler(isolate, handler)
217 , m_argument(isolate, argument)
218 , m_scriptState(ScriptState::current(isolate))
219 {
220 ASSERT(!m_promise.isEmpty());
221 ASSERT(!m_handler.isEmpty());
222 ASSERT(!m_argument.isEmpty());
223 }
224 virtual ~CallHandlerTask() { }
225
226 virtual void performTask(ExecutionContext*) OVERRIDE;
227
228 private:
229 ScopedPersistent<v8::Object> m_promise;
230 ScopedPersistent<v8::Function> m_handler;
231 ScopedPersistent<v8::Value> m_argument;
232 RefPtr<ScriptState> m_scriptState;
233 };
234
235 void CallHandlerTask::performTask(ExecutionContext* context)
236 {
237 ASSERT(context);
238 if (context->activeDOMObjectsAreStopped())
239 return;
240
241 ScriptState::Scope scope(m_scriptState.get());
242 v8::Isolate* isolate = m_scriptState->isolate();
243 v8::Handle<v8::Value> info[] = { m_argument.newLocal(isolate) };
244 v8::TryCatch trycatch;
245 v8::Local<v8::Value> value = V8ScriptRunner::callFunction(m_handler.newLocal (isolate), context, v8::Undefined(isolate), WTF_ARRAY_LENGTH(info), info, isolat e);
246 if (value.IsEmpty()) {
247 V8PromiseCustom::reject(m_promise.newLocal(isolate), trycatch.Exception( ), isolate);
248 } else {
249 V8PromiseCustom::resolve(m_promise.newLocal(isolate), value, isolate);
250 }
251 }
252
253 class UpdateDerivedTask FINAL : public ExecutionContextTask {
254 public:
255 UpdateDerivedTask(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> o nFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> originat orValueObject, v8::Isolate* isolate, ExecutionContext* context)
256 : m_promise(isolate, promise)
257 , m_onFulfilled(isolate, onFulfilled)
258 , m_onRejected(isolate, onRejected)
259 , m_originatorValueObject(isolate, originatorValueObject)
260 , m_scriptState(ScriptState::current(isolate))
261 {
262 ASSERT(!m_promise.isEmpty());
263 ASSERT(!m_originatorValueObject.isEmpty());
264 }
265 virtual ~UpdateDerivedTask() { }
266
267 virtual void performTask(ExecutionContext*) OVERRIDE;
268
269 private:
270 ScopedPersistent<v8::Object> m_promise;
271 ScopedPersistent<v8::Function> m_onFulfilled;
272 ScopedPersistent<v8::Function> m_onRejected;
273 ScopedPersistent<v8::Object> m_originatorValueObject;
274 RefPtr<ScriptState> m_scriptState;
275 };
276
277 void UpdateDerivedTask::performTask(ExecutionContext* context)
278 {
279 ASSERT(context);
280 if (context->activeDOMObjectsAreStopped())
281 return;
282
283 ScriptState::Scope scope(m_scriptState.get());
284 v8::Isolate* isolate = m_scriptState->isolate();
285 v8::Local<v8::Object> originatorValueObject = m_originatorValueObject.newLoc al(isolate);
286 v8::Local<v8::Value> coercedAlready = V8HiddenValue::getHiddenValue(isolate, originatorValueObject, V8HiddenValue::thenableHiddenPromise(isolate));
287 if (!coercedAlready.IsEmpty() && coercedAlready->IsObject()) {
288 ASSERT(V8PromiseCustom::isPromise(coercedAlready.As<v8::Object>(), isola te));
289 V8PromiseCustom::updateDerivedFromPromise(m_promise.newLocal(isolate), m _onFulfilled.newLocal(isolate), m_onRejected.newLocal(isolate), coercedAlready.A s<v8::Object>(), isolate);
290 return;
291 }
292
293 v8::Local<v8::Value> then;
294 v8::TryCatch trycatch;
295 then = originatorValueObject->Get(v8AtomicString(isolate, "then"));
296 if (then.IsEmpty()) {
297 // If calling the [[Get]] internal method threw an exception, catch it a nd run updateDerivedFromReason.
298 V8PromiseCustom::updateDerivedFromReason(m_promise.newLocal(isolate), m_ onRejected.newLocal(isolate), trycatch.Exception(), isolate);
299 return;
300 }
301
302 if (then->IsFunction()) {
303 ASSERT(then->IsObject());
304 v8::Local<v8::Object> coerced = V8PromiseCustom::coerceThenable(originat orValueObject, then.As<v8::Function>(), isolate);
305 // If the stack is exhausted coerced can be empty, but it is impossible
306 // because this function is executed on a fresh stack.
307 ASSERT(!coerced.IsEmpty());
308 V8PromiseCustom::updateDerivedFromPromise(m_promise.newLocal(isolate), m _onFulfilled.newLocal(isolate), m_onRejected.newLocal(isolate), coerced, isolate );
309 return;
310 }
311
312 V8PromiseCustom::updateDerivedFromValue(m_promise.newLocal(isolate), m_onFul filled.newLocal(isolate), originatorValueObject, isolate);
313 }
314
315 // Since Promises state propagation routines are executed recursively, they caus e
316 // stack overflow.
317 // (e.g. UpdateDerived -> UpdateDerivedFromValue -> SetValue ->
318 // PropagateToDerived -> UpdateDerived)
319 //
320 // To fix that, we introduce PromisePropagator. It holds the stack. When
321 // propagating the result to the derived tuples, we append the derived tuples
322 // to the stack. After that, we drain the stack to propagate the result to
323 // the stored tuples.
324 //
325 // PromisePropagator should be held on the stack and should not be held
326 // as other object's member. PromisePropagator holds Derived tuples. Since
327 // Derived tuples hold persistent handles to JS objects, retaining
328 // PromisePropagator in the heap causes memory leaks.
329 //
330 class PromisePropagator {
331 WTF_MAKE_NONCOPYABLE(PromisePropagator);
332 public:
333 PromisePropagator() { }
334
335 void performPropagation(v8::Isolate*);
336
337 void setValue(v8::Handle<v8::Object> promise, v8::Handle<v8::Value>, v8::Iso late*);
338 void setReason(v8::Handle<v8::Object> promise, v8::Handle<v8::Value>, v8::Is olate*);
339 void propagateToDerived(v8::Handle<v8::Object> promise, v8::Isolate*);
340 void updateDerived(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Fun ction> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> originator, v8::Isolate*);
341 void updateDerivedFromValue(v8::Handle<v8::Object> derivedPromise, v8::Handl e<v8::Function> onFulfilled, v8::Handle<v8::Value>, v8::Isolate*);
342 void updateDerivedFromReason(v8::Handle<v8::Object> derivedPromise, v8::Hand le<v8::Function> onRejected, v8::Handle<v8::Value>, v8::Isolate*);
343 void updateDerivedFromPromise(v8::Handle<v8::Object> derivedPromise, v8::Han dle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v 8::Object> promise, v8::Isolate*);
344
345 private:
346 class Derived {
347 WTF_MAKE_NONCOPYABLE(Derived);
348 public:
349 Derived(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> onFulfi lled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> originator, v8 ::Isolate* isolate)
350 : m_promise(isolate, promise)
351 , m_onFulfilled(isolate, onFulfilled)
352 , m_onRejected(isolate, onRejected)
353 , m_originator(isolate, originator)
354 {
355 ASSERT(!m_promise.isEmpty());
356 ASSERT(!m_originator.isEmpty());
357 }
358
359 static PassOwnPtr<Derived> create(v8::Handle<v8::Object> promise, v8::Ha ndle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle< v8::Object> originator, v8::Isolate* isolate)
360 {
361 return adoptPtr(new Derived(promise, onFulfilled, onRejected, origin ator, isolate));
362 }
363
364 v8::Local<v8::Object> promise(v8::Isolate* isolate) const { return m_pro mise.newLocal(isolate); }
365 v8::Local<v8::Function> onFulfilled(v8::Isolate* isolate) const { return m_onFulfilled.newLocal(isolate); }
366 v8::Local<v8::Function> onRejected(v8::Isolate* isolate) const { return m_onRejected.newLocal(isolate); }
367 v8::Local<v8::Object> originator(v8::Isolate* isolate) const { return m_ originator.newLocal(isolate); }
368
369 private:
370 ScopedPersistent<v8::Object> m_promise;
371 ScopedPersistent<v8::Function> m_onFulfilled;
372 ScopedPersistent<v8::Function> m_onRejected;
373 ScopedPersistent<v8::Object> m_originator;
374 };
375
376 Deque<OwnPtr<Derived> > m_derivedStack;
377 };
378
379 void PromisePropagator::performPropagation(v8::Isolate* isolate)
380 {
381 while (!m_derivedStack.isEmpty()) {
382 v8::HandleScope handleScope(isolate);
383 OwnPtr<Derived> derived = m_derivedStack.takeLast();
384 updateDerived(derived->promise(isolate), derived->onFulfilled(isolate), derived->onRejected(isolate), derived->originator(isolate), isolate);
385 }
386 }
387
388 void PromisePropagator::setValue(v8::Handle<v8::Object> promise, v8::Handle<v8:: Value> value, v8::Isolate* isolate)
389 {
390 ASSERT(V8PromiseCustom::getState(V8PromiseCustom::getInternal(promise)) != V 8PromiseCustom::Fulfilled && V8PromiseCustom::getState(V8PromiseCustom::getInter nal(promise)) != V8PromiseCustom::Rejected);
391 setStateForPromise(promise, V8PromiseCustom::Fulfilled, value, isolate);
392 propagateToDerived(promise, isolate);
393 }
394
395 void PromisePropagator::setReason(v8::Handle<v8::Object> promise, v8::Handle<v8: :Value> reason, v8::Isolate* isolate)
396 {
397 ASSERT(V8PromiseCustom::getState(V8PromiseCustom::getInternal(promise)) != V 8PromiseCustom::Fulfilled && V8PromiseCustom::getState(V8PromiseCustom::getInter nal(promise)) != V8PromiseCustom::Rejected);
398 setStateForPromise(promise, V8PromiseCustom::Rejected, reason, isolate);
399 propagateToDerived(promise, isolate);
400 }
401
402 void PromisePropagator::propagateToDerived(v8::Handle<v8::Object> promise, v8::I solate* isolate)
403 {
404 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise);
405 ASSERT(V8PromiseCustom::getState(internal) == V8PromiseCustom::Fulfilled || V8PromiseCustom::getState(internal) == V8PromiseCustom::Rejected);
406 v8::Local<v8::Array> fulfillCallbacks = internal->GetInternalField(V8Promise Custom::InternalFulfillCallbackIndex).As<v8::Array>();
407 v8::Local<v8::Array> rejectCallbacks = internal->GetInternalField(V8PromiseC ustom::InternalRejectCallbackIndex).As<v8::Array>();
408 v8::Local<v8::Array> derivedPromises = internal->GetInternalField(V8PromiseC ustom::InternalDerivedPromiseIndex).As<v8::Array>();
409 // Since they are treated as a tuple,
410 // we need to guaranteed that the length of these arrays are same.
411 ASSERT(fulfillCallbacks->Length() == rejectCallbacks->Length() && rejectCall backs->Length() == derivedPromises->Length());
412
413 // Append Derived tuple to the stack in reverse order.
414 for (uint32_t count = 0, length = derivedPromises->Length(); count < length; ++count) {
415 uint32_t i = length - count - 1;
416 v8::Local<v8::Object> derivedPromise = derivedPromises->Get(i).As<v8::Ob ject>();
417
418 v8::Local<v8::Function> onFulfilled, onRejected;
419 v8::Local<v8::Value> onFulfilledValue = fulfillCallbacks->Get(i);
420 if (onFulfilledValue->IsFunction()) {
421 onFulfilled = onFulfilledValue.As<v8::Function>();
422 }
423 v8::Local<v8::Value> onRejectedValue = rejectCallbacks->Get(i);
424 if (onRejectedValue->IsFunction()) {
425 onRejected = onRejectedValue.As<v8::Function>();
426 }
427
428 m_derivedStack.append(Derived::create(derivedPromise, onFulfilled, onRej ected, promise, isolate));
429 }
430 clearDerived(internal, isolate);
431 }
432
433 void PromisePropagator::updateDerivedFromValue(v8::Handle<v8::Object> derivedPro mise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Value> value, v8::Iso late* isolate)
434 {
435 if (!onFulfilled.IsEmpty()) {
436 V8PromiseCustom::callHandler(derivedPromise, onFulfilled, value, V8Promi seCustom::Fulfilled, isolate);
437 } else {
438 setValue(derivedPromise, value, isolate);
439 }
440 }
441
442 void PromisePropagator::updateDerivedFromReason(v8::Handle<v8::Object> derivedPr omise, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Value> reason, v8::Is olate* isolate)
443 {
444 if (!onRejected.IsEmpty()) {
445 V8PromiseCustom::callHandler(derivedPromise, onRejected, reason, V8Promi seCustom::Rejected, isolate);
446 } else {
447 setReason(derivedPromise, reason, isolate);
448 }
449 }
450
451 void PromisePropagator::updateDerived(v8::Handle<v8::Object> derivedPromise, v8: :Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Hand le<v8::Object> originator, v8::Isolate* isolate)
452 {
453 v8::Local<v8::Object> originatorInternal = V8PromiseCustom::getInternal(orig inator);
454 V8PromiseCustom::PromiseState originatorState = V8PromiseCustom::getState(or iginatorInternal);
455 ASSERT(originatorState == V8PromiseCustom::Fulfilled || originatorState == V 8PromiseCustom::Rejected);
456 v8::Local<v8::Value> originatorValue = originatorInternal->GetInternalField( V8PromiseCustom::InternalResultIndex);
457 if (originatorState == V8PromiseCustom::Fulfilled) {
458 if (originatorValue->IsObject()) {
459 ExecutionContext* executionContext = currentExecutionContext(isolate );
460 ASSERT(executionContext && executionContext->isContextThread());
461 executionContext->postTask(adoptPtr(new UpdateDerivedTask(derivedPro mise, onFulfilled, onRejected, originatorValue.As<v8::Object>(), isolate, execut ionContext)));
462 } else {
463 updateDerivedFromValue(derivedPromise, onFulfilled, originatorValue, isolate);
464 }
465 } else {
466 updateDerivedFromReason(derivedPromise, onRejected, originatorValue, iso late);
467 }
468 }
469
470 void PromisePropagator::updateDerivedFromPromise(v8::Handle<v8::Object> derivedP romise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejecte d, v8::Handle<v8::Object> promise, v8::Isolate* isolate)
471 {
472 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise);
473 V8PromiseCustom::PromiseState state = V8PromiseCustom::getState(internal);
474 if (state == V8PromiseCustom::Fulfilled || state == V8PromiseCustom::Rejecte d) {
475 updateDerived(derivedPromise, onFulfilled, onRejected, promise, isolate) ;
476 } else {
477 addToDerived(internal, derivedPromise, onFulfilled, onRejected, isolate) ;
478 }
479 }
480
481 } // namespace
482
483 void V8Promise::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& inf o)
484 {
485 v8SetReturnValue(info, v8::Local<v8::Value>());
486 v8::Isolate* isolate = info.GetIsolate();
487 ExecutionContext* executionContext = callingExecutionContext(isolate);
488 UseCounter::count(executionContext, UseCounter::PromiseConstructor);
489 if (!info.Length() || !info[0]->IsFunction()) {
490 throwTypeError("Promise constructor takes a function argument", isolate) ;
491 return;
492 }
493 v8::Local<v8::Function> init = info[0].As<v8::Function>();
494 TONATIVE_VOID_EMPTY(v8::Local<v8::Object>, promise, V8PromiseCustom::createP romise(info.Holder(), isolate));
495 TONATIVE_VOID_EMPTY(v8::Handle<v8::Value>, resolve, createClosure(promiseRes olveCallback, promise, isolate));
496 TONATIVE_VOID_EMPTY(v8::Handle<v8::Value>, reject, createClosure(promiseReje ctCallback, promise, isolate));
497 v8::Handle<v8::Value> argv[] = { resolve, reject };
498 v8::TryCatch trycatch;
499 if (V8ScriptRunner::callFunction(init, currentExecutionContext(isolate), v8: :Undefined(isolate), WTF_ARRAY_LENGTH(argv), argv, isolate).IsEmpty()) {
500 // An exception is thrown. Reject the promise if its resolved flag is un set.
501 V8PromiseCustom::reject(promise, trycatch.Exception(), isolate);
502 }
503 v8SetReturnValue(info, promise);
504 return;
505 }
506
507 void V8Promise::thenMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info )
508 {
509 v8::Isolate* isolate = info.GetIsolate();
510 v8::Local<v8::Function> onFulfilled, onRejected;
511 if (info.Length() > 0 && info[0]->IsFunction())
512 onFulfilled = info[0].As<v8::Function>();
513 if (info.Length() > 1 && info[1]->IsFunction())
514 onRejected = info[1].As<v8::Function>();
515 TONATIVE_VOID_EMPTY(v8::Local<v8::Value>, newPromise, V8PromiseCustom::then( info.Holder(), onFulfilled, onRejected, isolate));
516 v8SetReturnValue(info, newPromise);
517 }
518
519 void V8Promise::castMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info )
520 {
521 v8::Isolate* isolate = info.GetIsolate();
522 ExecutionContext* executionContext = callingExecutionContext(isolate);
523 UseCounter::count(executionContext, UseCounter::PromiseCast);
524 v8::Local<v8::Value> result = v8::Undefined(isolate);
525 if (info.Length() > 0)
526 result = info[0];
527
528 TONATIVE_VOID_EMPTY(v8::Local<v8::Value>, cast, V8PromiseCustom::toPromise(r esult, isolate));
529 v8SetReturnValue(info, cast);
530 }
531
532 void V8Promise::catchMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& inf o)
533 {
534 v8::Isolate* isolate = info.GetIsolate();
535 v8::Local<v8::Function> onFulfilled, onRejected;
536
537 if (info.Length() > 0 && !info[0]->IsUndefined()) {
538 if (!info[0]->IsFunction()) {
539 v8SetReturnValue(info, throwTypeError("onRejected must be a function or undefined", isolate));
540 return;
541 }
542 onRejected = info[0].As<v8::Function>();
543 }
544 TONATIVE_VOID_EMPTY(v8::Local<v8::Value>, newPromise, V8PromiseCustom::then( info.Holder(), onFulfilled, onRejected, isolate));
545 v8SetReturnValue(info, newPromise);
546 }
547
548 void V8Promise::resolveMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& i nfo)
549 {
550 v8::Isolate* isolate = info.GetIsolate();
551 ExecutionContext* executionContext = callingExecutionContext(isolate);
552 UseCounter::count(executionContext, UseCounter::PromiseResolve);
553 v8::Local<v8::Value> result = v8::Undefined(isolate);
554 if (info.Length() > 0)
555 result = info[0];
556
557 TONATIVE_VOID_EMPTY(v8::Local<v8::Object>, promise, V8PromiseCustom::createP romise(info.Holder(), isolate));
558 V8PromiseCustom::resolve(promise, result, isolate);
559 v8SetReturnValue(info, promise);
560 }
561
562 void V8Promise::rejectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& in fo)
563 {
564 v8::Isolate* isolate = info.GetIsolate();
565 ExecutionContext* executionContext = callingExecutionContext(isolate);
566 UseCounter::count(executionContext, UseCounter::PromiseReject);
567 v8::Local<v8::Value> result = v8::Undefined(isolate);
568 if (info.Length() > 0)
569 result = info[0];
570
571 TONATIVE_VOID_EMPTY(v8::Local<v8::Object>, promise, V8PromiseCustom::createP romise(info.Holder(), isolate));
572 V8PromiseCustom::reject(promise, result, isolate);
573 v8SetReturnValue(info, promise);
574 }
575
576 void V8Promise::raceMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info )
577 {
578 v8::Isolate* isolate = info.GetIsolate();
579 TONATIVE_VOID_EMPTY(v8::Local<v8::Object>, promise, V8PromiseCustom::createP romise(info.Holder(), isolate));
580
581 if (!info.Length() || !info[0]->IsArray()) {
582 v8SetReturnValue(info, promise);
583 return;
584 }
585
586 // FIXME: Now we limit the iterable type to the Array type.
587 v8::Local<v8::Array> iterable = info[0].As<v8::Array>();
588 TONATIVE_VOID_EMPTY(v8::Local<v8::Function>, onFulfilled, createClosure(prom iseResolveCallback, promise, isolate));
589 TONATIVE_VOID_EMPTY(v8::Local<v8::Function>, onRejected, createClosure(promi seRejectCallback, promise, isolate));
590
591 for (unsigned i = 0, length = iterable->Length(); i < length; ++i) {
592 // Array-holes should not be skipped by for-of iteration semantics.
593 TONATIVE_VOID_EMPTY(v8::Local<v8::Value>, nextValue, iterable->Get(i));
594 TONATIVE_VOID_EMPTY(v8::Local<v8::Object>, nextPromise, V8PromiseCustom: :toPromise(nextValue, isolate));
595 TONATIVE_VOID_EMPTY(v8::Local<v8::Value>, unused, V8PromiseCustom::then( nextPromise, onFulfilled, onRejected, isolate));
596 }
597 v8SetReturnValue(info, promise);
598 }
599
600 void V8Promise::allMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
601 {
602 v8::Isolate* isolate = info.GetIsolate();
603 TONATIVE_VOID_EMPTY(v8::Local<v8::Object>, promise, V8PromiseCustom::createP romise(info.Holder(), isolate));
604 v8::Local<v8::Array> results = v8::Array::New(info.GetIsolate());
605
606 if (!info.Length() || !info[0]->IsArray()) {
607 V8PromiseCustom::resolve(promise, results, isolate);
608 v8SetReturnValue(info, promise);
609 return;
610 }
611
612 // FIXME: Now we limit the iterable type to the Array type.
613 v8::Local<v8::Array> iterable = info[0].As<v8::Array>();
614
615 if (!iterable->Length()) {
616 V8PromiseCustom::resolve(promise, results, isolate);
617 v8SetReturnValue(info, promise);
618 return;
619 }
620
621 v8::Local<v8::ObjectTemplate> objectTemplate = primitiveWrapperObjectTemplat e(isolate);
622 TONATIVE_VOID_EMPTY(v8::Local<v8::Object>, countdownWrapper, objectTemplate- >NewInstance());
623 countdownWrapper->SetInternalField(V8PromiseCustom::PrimitiveWrapperPrimitiv eIndex, v8::Integer::New(isolate, iterable->Length()));
624
625 TONATIVE_VOID_EMPTY(v8::Local<v8::Function>, onRejected, createClosure(promi seRejectCallback, promise, isolate));
626 for (unsigned i = 0, length = iterable->Length(); i < length; ++i) {
627 // Array-holes should not be skipped by for-of iteration semantics.
628 TONATIVE_VOID_EMPTY(v8::Local<v8::Object>, environment, promiseAllEnviro nment(promise, countdownWrapper, i, results, isolate));
629 TONATIVE_VOID_EMPTY(v8::Local<v8::Function>, onFulfilled, createClosure( promiseAllFulfillCallback, environment, isolate));
630 TONATIVE_VOID_EMPTY(v8::Local<v8::Value>, nextValue, iterable->Get(i));
631 TONATIVE_VOID_EMPTY(v8::Local<v8::Object>, nextPromise, V8PromiseCustom: :toPromise(nextValue, isolate));
632 TONATIVE_VOID_EMPTY(v8::Local<v8::Value>, unused, V8PromiseCustom::then( nextPromise, onFulfilled, onRejected, isolate));
633 }
634 v8SetReturnValue(info, promise);
635 }
636
637 //
638 // -- V8PromiseCustom --
639 v8::Local<v8::Object> V8PromiseCustom::createPromise(v8::Handle<v8::Object> crea tionContext, v8::Isolate* isolate)
640 {
641 v8::Local<v8::ObjectTemplate> internalTemplate = internalObjectTemplate(isol ate);
642 v8::Local<v8::Object> internal = internalTemplate->NewInstance();
643 if (internal.IsEmpty())
644 return v8::Local<v8::Object>();
645 v8::Local<v8::Object> promise = V8DOMWrapper::createWrapper(creationContext, &V8Promise::wrapperTypeInfo, 0, isolate);
646
647 clearDerived(internal, isolate);
648 promise->SetInternalField(v8DOMWrapperObjectIndex, internal);
649
650 setStateForPromise(promise, Pending, v8::Undefined(isolate), isolate);
651 return promise;
652 }
653
654 v8::Local<v8::Object> V8PromiseCustom::getInternal(v8::Handle<v8::Object> promis e)
655 {
656 v8::Local<v8::Value> value = promise->GetInternalField(v8DOMWrapperObjectInd ex);
657 return value.As<v8::Object>();
658 }
659
660 V8PromiseCustom::PromiseState V8PromiseCustom::getState(v8::Handle<v8::Object> i nternal)
661 {
662 v8::Handle<v8::Value> value = internal->GetInternalField(V8PromiseCustom::In ternalStateIndex);
663 uint32_t number = toInt32(value);
664 ASSERT(number == Pending || number == Fulfilled || number == Rejected || num ber == Following);
665 return static_cast<PromiseState>(number);
666 }
667
668 bool V8PromiseCustom::isPromise(v8::Handle<v8::Value> maybePromise, v8::Isolate* isolate)
669 {
670 return V8Promise::domTemplate(isolate)->HasInstance(maybePromise);
671 }
672
673 v8::Local<v8::Object> V8PromiseCustom::toPromise(v8::Handle<v8::Value> maybeProm ise, v8::Isolate* isolate)
674 {
675 // FIXME: Currently we don't check [[PromiseConstructor]] since we limit
676 // the creation of the promise objects only from the Blink Promise
677 // constructor.
678 if (isPromise(maybePromise, isolate))
679 return maybePromise.As<v8::Object>();
680
681 v8::Local<v8::Object> promise = createPromise(v8::Handle<v8::Object>(), isol ate);
682 if (promise.IsEmpty())
683 return v8::Local<v8::Object>();
684 resolve(promise, maybePromise, isolate);
685 return promise;
686 }
687
688 void V8PromiseCustom::resolve(v8::Handle<v8::Object> promise, v8::Handle<v8::Val ue> result, v8::Isolate* isolate)
689 {
690 ASSERT(!result.IsEmpty());
691 v8::Local<v8::Object> internal = getInternal(promise);
692 PromiseState state = getState(internal);
693 if (state != Pending)
694 return;
695
696 if (isPromise(result, isolate)) {
697 v8::Local<v8::Object> valuePromise = result.As<v8::Object>();
698 v8::Local<v8::Object> valueInternal = getInternal(valuePromise);
699 PromiseState valueState = getState(valueInternal);
700 if (promise->SameValue(valuePromise)) {
701 v8::Local<v8::Value> reason = V8ThrowException::createTypeError("Res olve a promise with itself", isolate);
702 setReason(promise, reason, isolate);
703 } else if (valueState == Following) {
704 v8::Local<v8::Object> valuePromiseFollowing = valueInternal->GetInte rnalField(InternalResultIndex).As<v8::Object>();
705 setStateForPromise(promise, Following, valuePromiseFollowing, isolat e);
706 addToDerived(getInternal(valuePromiseFollowing), promise, v8::Handle <v8::Function>(), v8::Handle<v8::Function>(), isolate);
707 } else if (valueState == Fulfilled) {
708 setValue(promise, valueInternal->GetInternalField(InternalResultInde x), isolate);
709 } else if (valueState == Rejected) {
710 setReason(promise, valueInternal->GetInternalField(InternalResultInd ex), isolate);
711 } else {
712 ASSERT(valueState == Pending);
713 setStateForPromise(promise, Following, valuePromise, isolate);
714 addToDerived(valueInternal, promise, v8::Handle<v8::Function>(), v8: :Handle<v8::Function>(), isolate);
715 }
716 } else {
717 setValue(promise, result, isolate);
718 }
719 }
720
721 void V8PromiseCustom::reject(v8::Handle<v8::Object> promise, v8::Handle<v8::Valu e> reason, v8::Isolate* isolate)
722 {
723 v8::Local<v8::Object> internal = getInternal(promise);
724 PromiseState state = getState(internal);
725 if (state != Pending)
726 return;
727 setReason(promise, reason, isolate);
728 }
729
730 v8::Local<v8::Object> V8PromiseCustom::then(v8::Handle<v8::Object> promise, v8:: Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Isola te* isolate)
731 {
732 v8::Handle<v8::Object> internal = getInternal(promise);
733 while (getState(internal) == Following) {
734 promise = internal->GetInternalField(InternalResultIndex).As<v8::Object> ();
735 internal = getInternal(promise);
736 }
737 // FIXME: Currently we don't lookup "constructor" property since we limit
738 // the creation of the promise objects only from the Blink Promise
739 // constructor.
740 v8::Local<v8::Object> derivedPromise = createPromise(v8::Handle<v8::Object>( ), isolate);
741 if (derivedPromise.IsEmpty())
742 return v8::Local<v8::Object>();
743 updateDerivedFromPromise(derivedPromise, onFulfilled, onRejected, promise, i solate);
744 return derivedPromise;
745 }
746
747 void V8PromiseCustom::setValue(v8::Handle<v8::Object> promise, v8::Handle<v8::Va lue> value, v8::Isolate* isolate)
748 {
749 PromisePropagator propagator;
750 propagator.setValue(promise, value, isolate);
751 propagator.performPropagation(isolate);
752 }
753
754 void V8PromiseCustom::setReason(v8::Handle<v8::Object> promise, v8::Handle<v8::V alue> reason, v8::Isolate* isolate)
755 {
756 PromisePropagator propagator;
757 propagator.setReason(promise, reason, isolate);
758 propagator.performPropagation(isolate);
759 }
760
761 void V8PromiseCustom::propagateToDerived(v8::Handle<v8::Object> promise, v8::Iso late* isolate)
762 {
763 PromisePropagator propagator;
764 propagator.propagateToDerived(promise, isolate);
765 propagator.performPropagation(isolate);
766 }
767
768 void V8PromiseCustom::updateDerived(v8::Handle<v8::Object> derivedPromise, v8::H andle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle <v8::Object> originator, v8::Isolate* isolate)
769 {
770 PromisePropagator propagator;
771 propagator.updateDerived(derivedPromise, onFulfilled, onRejected, originator , isolate);
772 propagator.performPropagation(isolate);
773 }
774
775 void V8PromiseCustom::updateDerivedFromValue(v8::Handle<v8::Object> derivedPromi se, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Value> value, v8::Isola te* isolate)
776 {
777 PromisePropagator propagator;
778 propagator.updateDerivedFromValue(derivedPromise, onFulfilled, value, isolat e);
779 propagator.performPropagation(isolate);
780 }
781
782 void V8PromiseCustom::updateDerivedFromReason(v8::Handle<v8::Object> derivedProm ise, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Value> reason, v8::Isol ate* isolate)
783 {
784 PromisePropagator propagator;
785 propagator.updateDerivedFromReason(derivedPromise, onRejected, reason, isola te);
786 propagator.performPropagation(isolate);
787 }
788
789 void V8PromiseCustom::updateDerivedFromPromise(v8::Handle<v8::Object> derivedPro mise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> promise, v8::Isolate* isolate)
790 {
791 PromisePropagator propagator;
792 propagator.updateDerivedFromPromise(derivedPromise, onFulfilled, onRejected, promise, isolate);
793 propagator.performPropagation(isolate);
794 }
795
796 v8::Local<v8::Object> V8PromiseCustom::coerceThenable(v8::Handle<v8::Object> the nable, v8::Handle<v8::Function> then, v8::Isolate* isolate)
797 {
798 ASSERT(!thenable.IsEmpty());
799 ASSERT(!then.IsEmpty());
800 v8::Local<v8::Object> promise = createPromise(v8::Handle<v8::Object>(), isol ate);
801 if (promise.IsEmpty())
802 return v8::Local<v8::Object>();
803 v8::Handle<v8::Value> onFulfilled = createClosure(promiseResolveCallback, pr omise, isolate);
804 if (onFulfilled.IsEmpty())
805 return v8::Local<v8::Object>();
806 v8::Handle<v8::Value> onRejected = createClosure(promiseRejectCallback, prom ise, isolate);
807 if (onRejected.IsEmpty())
808 return v8::Local<v8::Object>();
809 v8::Handle<v8::Value> argv[] = { onFulfilled, onRejected };
810
811 v8::TryCatch trycatch;
812 if (V8ScriptRunner::callFunction(then, currentExecutionContext(isolate), the nable, WTF_ARRAY_LENGTH(argv), argv, isolate).IsEmpty()) {
813 reject(promise, trycatch.Exception(), isolate);
814 }
815 V8HiddenValue::setHiddenValue(isolate, thenable, V8HiddenValue::thenableHidd enPromise(isolate), promise);
816 return promise;
817 }
818
819 void V8PromiseCustom::callHandler(v8::Handle<v8::Object> promise, v8::Handle<v8: :Function> handler, v8::Handle<v8::Value> argument, PromiseState originatorState , v8::Isolate* isolate)
820 {
821 ASSERT(originatorState == Fulfilled || originatorState == Rejected);
822 ExecutionContext* executionContext = currentExecutionContext(isolate);
823 ASSERT(executionContext && executionContext->isContextThread());
824 executionContext->postTask(adoptPtr(new CallHandlerTask(promise, handler, ar gument, originatorState, isolate, executionContext)));
825 }
826
827 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/bindings/v8/custom/V8PromiseCustom.h ('k') | Source/core/core.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698