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

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

Issue 17874002: [ABANDONED] Implement non-static methods of Promise and PromiseResolver. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 7 years, 6 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
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 15 matching lines...) Expand all
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31 #include "config.h" 31 #include "config.h"
32 #include "bindings/v8/custom/V8PromiseCustom.h" 32 #include "bindings/v8/custom/V8PromiseCustom.h"
33 33
34 #include "V8Promise.h" 34 #include "V8Promise.h"
35 #include "V8PromiseResolver.h" 35 #include "V8PromiseResolver.h"
36 #include "bindings/v8/ScopedPersistent.h"
37 #include "bindings/v8/ScriptFunctionCall.h"
36 #include "bindings/v8/V8Binding.h" 38 #include "bindings/v8/V8Binding.h"
39 #include "bindings/v8/V8PerIsolateData.h"
37 #include "bindings/v8/V8ScriptRunner.h" 40 #include "bindings/v8/V8ScriptRunner.h"
38 #include "bindings/v8/WrapperTypeInfo.h" 41 #include "bindings/v8/WrapperTypeInfo.h"
42 #include "core/dom/Document.h"
43 #include "core/dom/ExceptionCode.h"
44 #include "core/page/DOMWindow.h"
45 #include "core/platform/Task.h"
46 #include "wtf/Functional.h"
47 #include "wtf/PassOwnPtr.h"
39 #include <v8.h> 48 #include <v8.h>
40 49
41 namespace WebCore { 50 namespace WebCore {
42 51
52 namespace {
53
54 int wrapperCallbackTag = 0;
55 int promiseFulfillCallbackTag = 0;
56 int promiseResolveCallbackTag = 0;
57 int promiseRejectCallbackTag = 0;
58
59 // tag must be a pointer of one of the above tags.
60 v8::Local<v8::Function> getFunction(v8::FunctionCallback callback, int* tag, v8: :Isolate* isolate)
61 {
62 WrapperWorldType worldType = WebCore::worldType(isolate);
63 V8PerIsolateData* data = V8PerIsolateData::from(isolate);
64 ASSERT(data);
65 V8PerIsolateData::TemplateMap::iterator result = data->templateMap(worldType ).find(tag);
66 if (result != data->templateMap(worldType).end())
67 return result->value.newLocal(isolate)->GetFunction();
68
69 v8::HandleScope handleScope(isolate);
70 v8::Handle<v8::FunctionTemplate> functionTemplate = v8::FunctionTemplate::Ne w(callback);
71 data->templateMap(worldType).add(tag, UnsafePersistent<v8::FunctionTemplate> (isolate, functionTemplate));
72 return handleScope.Close(functionTemplate->GetFunction());
73 }
74
75 class PromiseTask : public ScriptExecutionContext::Task {
76 public:
77 PromiseTask(v8::Handle<v8::Function> callback, v8::Handle<v8::Object> receiv er, v8::Handle<v8::Value> result)
78 : m_callback(callback)
79 , m_receiver(receiver)
80 , m_result(result)
81 {
82 ASSERT(!callback.IsEmpty());
83 ASSERT(!receiver.IsEmpty());
84 ASSERT(!result.IsEmpty());
85 }
86 virtual ~PromiseTask() { }
87
88 virtual void performTask(ScriptExecutionContext*) OVERRIDE;
89
90 private:
91 ScopedPersistent<v8::Function> m_callback;
92 ScopedPersistent<v8::Object> m_receiver;
93 ScopedPersistent<v8::Value> m_result;
94 };
95
96 void PromiseTask::performTask(ScriptExecutionContext* context)
97 {
98 if (context->activeDOMObjectsAreStopped())
99 return;
100 ASSERT(context->isDocument());
101 ScriptState* state = mainWorldScriptState(static_cast<Document*>(context)->f rame());
102 v8::HandleScope handleScope;
103 ASSERT(state);
104 v8::Handle<v8::Context> v8Context = state->context();
105 ASSERT(!v8Context.IsEmpty());
106 v8::Context::Scope scope(v8Context);
107 v8::Isolate* isolate = v8Context->GetIsolate();
108 ASSERT(!m_callback.newLocal(isolate).IsEmpty());
109 ASSERT(!m_receiver.newLocal(isolate).IsEmpty());
110 ASSERT(!m_result.newLocal(isolate).IsEmpty());
111 v8::Handle<v8::Value> result = m_result.newLocal(isolate);
112 V8ScriptRunner::callFunction(m_callback.newLocal(isolate), context, m_receiv er.newLocal(isolate), 1, &result);
113 };
114
115 v8::Handle<v8::Value> postTask(v8::Handle<v8::Function> callback, v8::Handle<v8: :Object> receiver, v8::Handle<v8::Value> value, v8::Isolate* isolate)
116 {
117 DOMWindow* window = activeDOMWindow();
118 ASSERT(window);
119 Document* document = window->document();
120 ASSERT(document);
121 document->postTask(adoptPtr(new PromiseTask(callback, receiver, value)));
122 return v8::Undefined(isolate);
123 }
124
125 void wrapperCallbackRaw(const v8::FunctionCallbackInfo<v8::Value>& args)
126 {
127 v8::Isolate* isolate = args.GetIsolate();
128 v8SetReturnValue(args, v8::Undefined(args.GetIsolate()));
129 v8::Local<v8::Object> environment;
130 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate());
131 ASSERT(args.Length() > 0);
132 ASSERT(!args[0].IsEmpty());
133 ASSERT(args[0]->IsObject());
134 environment = args[0].As<v8::Object>();
135 if (args.Length() > 1 && !args[1].IsEmpty())
136 result = args[1];
137
138 v8::Local<v8::Value> value;
139
140 value = environment->GetInternalField(V8PromiseCustom::WrapperCallbackEnviro nmentPromiseIndex);
141 ASSERT(!value.IsEmpty());
142 ASSERT(value->IsObject());
143 v8::Local<v8::Object> promise = value.As<v8::Object>();
144
145 value = environment->GetInternalField(V8PromiseCustom::WrapperCallbackEnviro nmentPromiseResolverIndex);
146 ASSERT(!value.IsEmpty());
147 ASSERT(value->IsObject());
148 v8::Local<v8::Object> resolver = value.As<v8::Object>();
149
150 value = environment->GetInternalField(V8PromiseCustom::WrapperCallbackEnviro nmentCallbackIndex);
151 ASSERT(!value.IsEmpty());
152 ASSERT(value->IsFunction());
153 v8::Local<v8::Function> callback = value.As<v8::Function>();
154
155 v8::TryCatch trycatch;
156 result = V8ScriptRunner::callFunction(callback, getScriptExecutionContext(), promise, 1, &result);
157 if (result.IsEmpty()) {
158 V8PromiseCustom::rejectResolver(resolver, trycatch.Exception(), V8Promis eCustom::Synchronous, isolate);
159 return;
160 }
161 V8PromiseCustom::resolveResolver(resolver, result, V8PromiseCustom::Synchron ous, isolate);
162 }
163
164 v8::Handle<v8::Function> wrapperCallback(v8::Handle<v8::Object> promise, v8::Han dle<v8::Object> resolver, v8::Handle<v8::Function> callback, v8::Isolate* isolat e)
165 {
166 ASSERT(!promise.IsEmpty());
167 ASSERT(!resolver.IsEmpty());
168 ASSERT(!callback.IsEmpty());
169 // FIXME: v8::ObjectTemplate::New should be cached.
170 v8::Local<v8::ObjectTemplate> objectTemplate = v8::ObjectTemplate::New();
171 objectTemplate->SetInternalFieldCount(V8PromiseCustom::WrapperCallbackEnviro nmentFieldCount);
172 v8::Local<v8::Object> environment = objectTemplate->NewInstance();
173 environment->SetInternalField(V8PromiseCustom::WrapperCallbackEnvironmentPro miseIndex, promise);
174 environment->SetInternalField(V8PromiseCustom::WrapperCallbackEnvironmentPro miseResolverIndex, resolver);
175 environment->SetInternalField(V8PromiseCustom::WrapperCallbackEnvironmentCal lbackIndex, callback);
176
177 // FIXME: If there is a way to bind an object to a function other than evalu ate a JavaScript, it will be preferable.
178 // FIXME: script compilation should be cached.
179 // We should not depend on the global context that user can change, such as accessing a property, calling a method or so.
180 v8::Local<v8::String> script = v8::String::New("(function(f, v1) { return fu nction(v2) { return f(v1, v2); }; })");
181 v8::Local<v8::Value> value = V8ScriptRunner::compileAndRunInternalScript(scr ipt, isolate);
182 ASSERT(!value.IsEmpty());
183 ASSERT(value->IsFunction());
184
185 v8::Local<v8::Value> argv[] = {
186 getFunction(wrapperCallbackRaw, &wrapperCallbackTag, isolate),
187 environment,
188 };
189 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global();
190
191 value = V8ScriptRunner::callFunction(value.As<v8::Function>(), getScriptExec utionContext(), global, WTF_ARRAY_LENGTH(argv), argv);
192 ASSERT(!value.IsEmpty());
193 ASSERT(value->IsFunction());
194 return value.As<v8::Function>();
195 }
196
197 void promiseFulfillCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
198 {
199 v8::Local<v8::Object> resolver;
200 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate());
201 ASSERT(args.Length() > 0);
202 ASSERT(!args[0].IsEmpty());
203 ASSERT(args[0]->IsObject());
204 resolver = args[0].As<v8::Object>();
205 if (args.Length() > 1 && !args[1].IsEmpty())
206 result = args[1];
207
208 V8PromiseCustom::fulfillResolver(resolver, result, V8PromiseCustom::Synchron ous, args.GetIsolate());
209 }
210
211 void promiseResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
212 {
213 v8::Local<v8::Object> resolver;
214 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate());
215 ASSERT(args.Length() > 0);
216 ASSERT(!args[0].IsEmpty());
217 ASSERT(args[0]->IsObject());
218 resolver = args[0].As<v8::Object>();
219 if (args.Length() > 1 && !args[1].IsEmpty())
220 result = args[1];
221
222 V8PromiseCustom::resolveResolver(resolver, result, V8PromiseCustom::Synchron ous, args.GetIsolate());
223 }
224
225 void promiseRejectCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
226 {
227 v8::Local<v8::Object> resolver;
228 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate());
229 ASSERT(args.Length() > 0);
230 ASSERT(!args[0].IsEmpty());
231 ASSERT(args[0]->IsObject());
232 resolver = args[0].As<v8::Object>();
233 if (args.Length() > 1 && !args[1].IsEmpty())
234 result = args[1];
235
236 V8PromiseCustom::rejectResolver(resolver, result, V8PromiseCustom::Synchrono us, args.GetIsolate());
237 }
238
239 v8::Local<v8::Function> promiseCallback(v8::Handle<v8::Object> resolver, V8Promi seCustom::PromiseAlgorithm algorithm, v8::Isolate* isolate)
240 {
241 ASSERT(!resolver.IsEmpty());
242 v8::Local<v8::Function> callback;
243 switch (algorithm) {
244 case V8PromiseCustom::FulfillAlgorithm:
245 callback = getFunction(promiseFulfillCallback, &promiseFulfillCallbackTa g, isolate);
246 break;
247 case V8PromiseCustom::ResolveAlgorithm:
248 callback = getFunction(promiseResolveCallback, &promiseResolveCallbackTa g, isolate);
249 break;
250 case V8PromiseCustom::RejectAlgorithm:
251 callback = getFunction(promiseRejectCallback, &promiseRejectCallbackTag, isolate);
252 break;
253 default:
254 ASSERT(0);
255 }
256
257 // FIXME: If there is a way to bind an object to a function other than evalu ate a JavaScript, it will be preferable.
258 // FIXME: script compilation should be cached.
259 // We should not depend on the global context that user can change, such as accessing a property, calling a method or so.
260 v8::Local<v8::String> script = v8::String::New("(function(f, v1) { return fu nction(v2) { return f(v1, v2); }; })");
261 v8::Local<v8::Value> value = V8ScriptRunner::compileAndRunInternalScript(scr ipt, isolate);
262 ASSERT(!value.IsEmpty());
263 ASSERT(value->IsFunction());
264
265 v8::Local<v8::Value> argv[] = {
266 callback,
267 resolver,
268 };
269 v8::Local<v8::Object> receiver = isolate->GetCurrentContext()->Global();
270
271 value = V8ScriptRunner::callFunction(value.As<v8::Function>(), getScriptExec utionContext(), receiver, WTF_ARRAY_LENGTH(argv), argv);
272 ASSERT(!value.IsEmpty());
273 ASSERT(value->IsFunction());
274 return value.As<v8::Function>();
275 }
276
277 } // namespace
278
43 void V8Promise::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& arg s) 279 void V8Promise::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& arg s)
44 { 280 {
45 v8SetReturnValue(args, v8::Local<v8::Value>()); 281 v8SetReturnValue(args, v8::Local<v8::Value>());
46 v8::Isolate* isolate = args.GetIsolate(); 282 v8::Isolate* isolate = args.GetIsolate();
47 if (!args.Length() || args[0].IsEmpty() || !args[0]->IsFunction()) { 283 if (!args.Length() || args[0].IsEmpty() || !args[0]->IsFunction()) {
48 throwTypeError("Promise constructor takes a function argument", isolate) ; 284 throwTypeError("Promise constructor takes a function argument", isolate) ;
49 return; 285 return;
50 } 286 }
51 v8::Handle<v8::Function> init = args[0].As<v8::Function>(); 287 v8::Local<v8::Function> init = args[0].As<v8::Function>();
52 v8::Local<v8::ObjectTemplate> internalTemplate = v8::ObjectTemplate::New(); 288 v8::Local<v8::Object> promise, resolver;
53 internalTemplate->SetInternalFieldCount(V8PromiseCustom::InternalFieldCount) ; 289 V8PromiseCustom::createPromise(args.Holder(), &promise, &resolver, isolate);
54 v8::Local<v8::Object> internal = internalTemplate->NewInstance();
55 v8::Local<v8::Object> promise = V8DOMWrapper::createWrapper(args.Holder(), & V8Promise::info, 0, isolate);
56 v8::Local<v8::Object> promiseResolver = V8DOMWrapper::createWrapper(args.Hol der(), &V8PromiseResolver::info, 0, isolate);
57
58 internal->SetInternalField(V8PromiseCustom::InternalStateIndex, v8::NumberOb ject::New(V8PromiseCustom::Pending));
59 internal->SetInternalField(V8PromiseCustom::InternalResultIndex, v8::Undefin ed());
60 internal->SetInternalField(V8PromiseCustom::InternalFulfillCallbackIndex, v8 ::Array::New());
61 internal->SetInternalField(V8PromiseCustom::InternalRejectCallbackIndex, v8: :Array::New());
62
63 promise->SetInternalField(v8DOMWrapperObjectIndex, internal);
64 promiseResolver->SetInternalField(v8DOMWrapperObjectIndex, internal);
65
66 v8::Handle<v8::Value> argv[] = { 290 v8::Handle<v8::Value> argv[] = {
67 promiseResolver, 291 resolver,
68 }; 292 };
69 v8::TryCatch trycatch; 293 v8::TryCatch trycatch;
70 if (V8ScriptRunner::callFunction(init, getScriptExecutionContext(), promise, WTF_ARRAY_LENGTH(argv), argv).IsEmpty()) { 294 if (V8ScriptRunner::callFunction(init, getScriptExecutionContext(), promise, WTF_ARRAY_LENGTH(argv), argv).IsEmpty()) {
71 // FIXME: An exception is thrown. Reject the promise. 295 // An exception is thrown. Reject the promise.
296 V8PromiseCustom::rejectResolver(resolver, trycatch.Exception(), V8Promis eCustom::Asynchronous, isolate);
72 } 297 }
73 v8SetReturnValue(args, promise); 298 v8SetReturnValue(args, promise);
74 return; 299 return;
75 } 300 }
76 301
302 void V8Promise::thenMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args )
303 {
304 v8::Isolate* isolate = args.GetIsolate();
305 v8SetReturnValue(args, v8::Local<v8::Value>());
306 v8::Local<v8::Function> fulfillWrapper, rejectWrapper;
307 v8::Local<v8::Object> promise, resolver;
308 V8PromiseCustom::createPromise(args.Holder(), &promise, &resolver, isolate);
309 if (args.Length() > 0 && !args[0].IsEmpty() && !args[0]->IsUndefined()) {
310 if (!args[0]->IsFunction()) {
311 throwTypeError("fulfillCallback must be a function or undefined", is olate);
312 return;
313 }
314 fulfillWrapper = wrapperCallback(promise, resolver, args[0].As<v8::Funct ion>(), isolate);
315 } else {
316 fulfillWrapper = promiseCallback(resolver, V8PromiseCustom::FulfillAlgor ithm, isolate);
317 }
318 if (args.Length() > 1 && !args[1].IsEmpty() && !args[1]->IsUndefined()) {
319 if (!args[1]->IsFunction()) {
320 throwTypeError("rejectCallback must be a function or undefined", iso late);
321 return;
322 }
323 rejectWrapper = wrapperCallback(promise, resolver, args[1].As<v8::Functi on>(), isolate);
324 } else {
325 rejectWrapper = promiseCallback(resolver, V8PromiseCustom::RejectAlgorit hm, isolate);
326 }
327 V8PromiseCustom::append(args.Holder(), fulfillWrapper, rejectWrapper, isolat e);
328 v8SetReturnValue(args, promise);
329 }
330
331 void V8Promise::catchMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& arg s)
332 {
333 v8::Isolate* isolate = args.GetIsolate();
334 v8SetReturnValue(args, v8::Local<v8::Value>());
335 v8::Local<v8::Function> fulfillWrapper, rejectWrapper;
336 v8::Local<v8::Object> promise, resolver;
337 V8PromiseCustom::createPromise(args.Holder(), &promise, &resolver, isolate);
338
339 if (args.Length() > 0 && !args[0].IsEmpty() && !args[0]->IsUndefined()) {
340 if (!args[0]->IsFunction()) {
341 throwTypeError("rejectCallback must be a function or undefined", iso late);
342 return;
343 }
344 rejectWrapper = wrapperCallback(promise, resolver, args[0].As<v8::Functi on>(), isolate);
345 } else {
346 rejectWrapper = promiseCallback(resolver, V8PromiseCustom::RejectAlgorit hm, isolate);
347 }
348 fulfillWrapper = promiseCallback(resolver, V8PromiseCustom::FulfillAlgorithm , isolate);
349 V8PromiseCustom::append(args.Holder(), fulfillWrapper, rejectWrapper, isolat e);
350 v8SetReturnValue(args, promise);
351 }
352
353 //
354 // -- V8PromiseCustom --
355 void V8PromiseCustom::createPromise(v8::Handle<v8::Object> creationContext, v8:: Local<v8::Object>* promise, v8::Local<v8::Object>* resolver, v8::Isolate* isolat e)
356 {
357 // FIXME: v8::ObjectTemplate::New should be cached.
358 v8::Local<v8::ObjectTemplate> internalTemplate = v8::ObjectTemplate::New();
359 internalTemplate->SetInternalFieldCount(InternalFieldCount);
360 v8::Local<v8::Object> internal = internalTemplate->NewInstance();
361 *promise = V8DOMWrapper::createWrapper(creationContext, &V8Promise::info, 0, isolate);
362 *resolver = V8DOMWrapper::createWrapper(creationContext, &V8PromiseResolver: :info, 0, isolate);
363
364 clearInternal(internal, V8PromiseCustom::Pending, v8::Undefined(isolate));
365
366 (*promise)->SetInternalField(v8DOMWrapperObjectIndex, internal);
367 (*resolver)->SetInternalField(v8DOMWrapperObjectIndex, internal);
368 }
369
370 void V8PromiseCustom::fulfillResolver(v8::Handle<v8::Object> resolver, v8::Handl e<v8::Value> result, SynchronousMode mode, v8::Isolate* isolate)
371 {
372 ASSERT(!resolver.IsEmpty());
373 ASSERT(!result.IsEmpty());
374 v8::Local<v8::Object> internal = getInternal(resolver);
375 if (internal.IsEmpty() || getState(internal) != Pending) {
376 // The resolver is already fulfilled or rejected.
377 return;
378 }
379
380 v8::Local<v8::Value> value;
381 value = internal->GetInternalField(V8PromiseCustom::InternalFulfillCallbackI ndex);
382 ASSERT(!value.IsEmpty());
383 ASSERT(value->IsArray());
384 v8::Local<v8::Array> callbacks = value.As<v8::Array>();
385 clearInternal(internal, Fulfilled, result);
386 // The internal object is no more needed in this PromiseResolver.
387 resolver->SetInternalField(v8DOMWrapperObjectIndex, v8::Null(isolate));
388
389 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global();
390 for (uint32_t i = 0, length = callbacks->Length(); i < length; ++i) {
391 value = callbacks->Get(i);
392 ASSERT(!value.IsEmpty());
393 ASSERT(value->IsFunction());
394 v8::Local<v8::Function> callback = value.As<v8::Function>();
395 call(callback, global, result, mode, isolate);
396 }
397 }
398
399 void V8PromiseCustom::resolveResolver(v8::Handle<v8::Object> resolver, v8::Handl e<v8::Value> result, SynchronousMode mode, v8::Isolate* isolate)
400 {
401 ASSERT(!resolver.IsEmpty());
402 ASSERT(!result.IsEmpty());
403 v8::Local<v8::Object> internal = getInternal(resolver);
404 if (internal.IsEmpty() || getState(internal) != Pending) {
405 // The resolver is already fulfilled or rejected.
406 return;
407 }
408
409 v8::Local<v8::Value> then;
410 if (result->IsObject()) {
411 v8::TryCatch trycatch;
412 then = result.As<v8::Object>()->Get(v8::String::New("then"));
413 if (then.IsEmpty()) {
414 // If calling the [[Get]] internal method threw an exception, catch it and run reject.
415 rejectResolver(resolver, trycatch.Exception(), mode, isolate);
416 return;
417 }
418 }
419
420 if (!then.IsEmpty() && then->IsFunction()) {
421 ASSERT(result->IsObject());
422 v8::TryCatch trycatch;
423 v8::Handle<v8::Value> argv[] = {
424 promiseCallback(resolver, ResolveAlgorithm, isolate),
425 promiseCallback(resolver, RejectAlgorithm, isolate),
426 };
427 if (V8ScriptRunner::callFunction(then.As<v8::Function>(), getScriptExecu tionContext(), result.As<v8::Object>(), WTF_ARRAY_LENGTH(argv), argv).IsEmpty())
428 rejectResolver(resolver, trycatch.Exception(), mode, isolate);
429 return;
430 }
431 fulfillResolver(resolver, result, mode, isolate);
432 }
433
434 void V8PromiseCustom::rejectResolver(v8::Handle<v8::Object> resolver, v8::Handle <v8::Value> result, SynchronousMode mode, v8::Isolate* isolate)
435 {
436 ASSERT(!resolver.IsEmpty());
437 ASSERT(!result.IsEmpty());
438 v8::Local<v8::Object> internal = getInternal(resolver);
439 if (internal.IsEmpty() || getState(internal) != Pending) {
440 // The resolver is already fulfilled or rejected.
441 return;
442 }
443
444 v8::Local<v8::Value> value;
445 value = internal->GetInternalField(V8PromiseCustom::InternalRejectCallbackIn dex);
446 ASSERT(!value.IsEmpty());
447 ASSERT(value->IsArray());
448 v8::Local<v8::Array> callbacks = value.As<v8::Array>();
449 clearInternal(internal, Rejected, result);
450 // The internal object is no more needed from this PromiseResolver.
451 resolver->SetInternalField(v8DOMWrapperObjectIndex, v8::Null(isolate));
452
453 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global();
454 for (uint32_t i = 0, length = callbacks->Length(); i < length; ++i) {
455 value = callbacks->Get(i);
456 ASSERT(!value.IsEmpty());
457 ASSERT(value->IsFunction());
458 v8::Local<v8::Function> callback = value.As<v8::Function>();
459 call(callback, global, result, mode, isolate);
460 }
461 }
462
463 void V8PromiseCustom::append(v8::Handle<v8::Object> promise, v8::Handle<v8::Func tion> fulfillCallback, v8::Handle<v8::Function> rejectCallback, v8::Isolate* iso late)
464 {
465 v8::Local<v8::Object> internal = getInternal(promise);
466 ASSERT(!internal.IsEmpty());
467
468 PromiseState state = getState(internal);
469 if (state == Fulfilled) {
470 if (!fulfillCallback.IsEmpty()) {
471 v8::Local<v8::Value> result = internal->GetInternalField(V8PromiseCu stom::InternalResultIndex);
472 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global( );
473 call(fulfillCallback, global, result, Asynchronous, isolate);
474 }
475 return;
476 }
477 if (state == Rejected) {
478 if (!rejectCallback.IsEmpty()) {
479 v8::Local<v8::Value> result = internal->GetInternalField(V8PromiseCu stom::InternalResultIndex);
480 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global( );
481 call(rejectCallback, global, result, Asynchronous, isolate);
482 }
483 return;
484 }
485
486 ASSERT(state == Pending);
487 if (!fulfillCallback.IsEmpty()) {
488 v8::Local<v8::Value> value = internal->GetInternalField(InternalFulfillC allbackIndex);
489 ASSERT(!value.IsEmpty());
490 ASSERT(value->IsArray());
491 v8::Local<v8::Array> callbacks = value.As<v8::Array>();
492 callbacks->Set(callbacks->Length(), fulfillCallback);
493 }
494 if (!rejectCallback.IsEmpty()) {
495 v8::Local<v8::Value> value = internal->GetInternalField(InternalRejectCa llbackIndex);
496 ASSERT(!value.IsEmpty());
497 ASSERT(value->IsArray());
498 v8::Local<v8::Array> callbacks = value.As<v8::Array>();
499 callbacks->Set(callbacks->Length(), rejectCallback);
500 }
501 }
502
503 v8::Local<v8::Object> V8PromiseCustom::getInternal(v8::Handle<v8::Object> promis eOrPromiseResolver)
504 {
505 ASSERT(!promiseOrPromiseResolver.IsEmpty());
506 v8::Local<v8::Value> value = promiseOrPromiseResolver->GetInternalField(v8DO MWrapperObjectIndex);
507 ASSERT(!value.IsEmpty());
508 if (value->IsNull())
509 return v8::Local<v8::Object>();
510 ASSERT(value->IsObject());
511 return value.As<v8::Object>();
512 }
513
514 void V8PromiseCustom::clearInternal(v8::Handle<v8::Object> internal, PromiseStat e state, v8::Handle<v8::Value> value)
515 {
516 ASSERT(!internal.IsEmpty());
517
518 setState(internal, state);
519 internal->SetInternalField(V8PromiseCustom::InternalResultIndex, value);
520 internal->SetInternalField(V8PromiseCustom::InternalFulfillCallbackIndex, v8 ::Array::New());
521 internal->SetInternalField(V8PromiseCustom::InternalRejectCallbackIndex, v8: :Array::New());
522 }
523
524 V8PromiseCustom::PromiseState V8PromiseCustom::getState(v8::Handle<v8::Object> i nternal)
525 {
526 ASSERT(!internal.IsEmpty());
527 v8::Handle<v8::Value> value = internal->GetInternalField(V8PromiseCustom::In ternalStateIndex);
528 ASSERT(!value.IsEmpty());
529 ASSERT(value->IsNumber());
530 double number = value.As<v8::Number>()->Value();
531 ASSERT(number == Pending || number == Fulfilled || number == Rejected);
532 return static_cast<PromiseState>(number);
533 }
534
535 void V8PromiseCustom::setState(v8::Handle<v8::Object> internal, PromiseState sta te)
536 {
537 ASSERT(!internal.IsEmpty());
538 ASSERT(state == Pending || state == Fulfilled || state == Rejected);
539 internal->SetInternalField(V8PromiseCustom::InternalStateIndex, v8::Number:: New(state));
540 }
541
542 void V8PromiseCustom::call(v8::Handle<v8::Function> function, v8::Handle<v8::Obj ect> receiver, v8::Handle<v8::Value> result, SynchronousMode mode, v8::Isolate* isolate)
543 {
544 ASSERT(!function.IsEmpty());
545 ASSERT(!receiver.IsEmpty());
546 if (mode == Synchronous) {
547 v8::TryCatch trycatch;
548 V8ScriptRunner::callFunction(function, getScriptExecutionContext(), rece iver, 1, &result);
549 } else {
550 ASSERT(mode == Asynchronous);
551 postTask(function, receiver, result, isolate);
552 }
553 }
554
77 } // namespace WebCore 555 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/bindings/v8/custom/V8PromiseCustom.h ('k') | Source/bindings/v8/custom/V8PromiseResolverCustom.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698