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

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

Issue 18113004: Implement Promise.prototype.then and Promise.prototype.catch (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 7 years, 5 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/dom/Promise.idl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 #include "core/page/DOMWindow.h" 44 #include "core/page/DOMWindow.h"
45 #include "core/platform/Task.h" 45 #include "core/platform/Task.h"
46 #include "wtf/Functional.h" 46 #include "wtf/Functional.h"
47 #include "wtf/PassOwnPtr.h" 47 #include "wtf/PassOwnPtr.h"
48 #include <v8.h> 48 #include <v8.h>
49 49
50 namespace WebCore { 50 namespace WebCore {
51 51
52 namespace { 52 namespace {
53 53
54 int wrapperCallbackTag = 0;
54 int promiseFulfillCallbackTag = 0; 55 int promiseFulfillCallbackTag = 0;
55 int promiseResolveCallbackTag = 0; 56 int promiseResolveCallbackTag = 0;
56 int promiseRejectCallbackTag = 0; 57 int promiseRejectCallbackTag = 0;
57 58
58 v8::Local<v8::Function> getFunction(v8::FunctionCallback callback, int* tag, v8: :Isolate* isolate) 59 v8::Local<v8::Function> getFunction(v8::FunctionCallback callback, int* tag, v8: :Isolate* isolate)
59 { 60 {
60 // tag must be a pointer of one of the above tags. 61 // tag must be a pointer of one of the above tags.
61 ASSERT(tag == &promiseFulfillCallbackTag 62 ASSERT(tag == &wrapperCallbackTag
63 || tag == &promiseFulfillCallbackTag
62 || tag == &promiseResolveCallbackTag 64 || tag == &promiseResolveCallbackTag
63 || tag == &promiseRejectCallbackTag); 65 || tag == &promiseRejectCallbackTag);
64 WrapperWorldType worldType = WebCore::worldType(isolate); 66 WrapperWorldType worldType = WebCore::worldType(isolate);
65 V8PerIsolateData* data = V8PerIsolateData::from(isolate); 67 V8PerIsolateData* data = V8PerIsolateData::from(isolate);
66 ASSERT(data); 68 ASSERT(data);
67 V8PerIsolateData::TemplateMap::iterator result = data->templateMap(worldType ).find(tag); 69 V8PerIsolateData::TemplateMap::iterator result = data->templateMap(worldType ).find(tag);
68 if (result != data->templateMap(worldType).end()) 70 if (result != data->templateMap(worldType).end())
69 return result->value.newLocal(isolate)->GetFunction(); 71 return result->value.newLocal(isolate)->GetFunction();
70 72
71 v8::Handle<v8::FunctionTemplate> functionTemplate = v8::FunctionTemplate::Ne w(callback); 73 v8::Handle<v8::FunctionTemplate> functionTemplate = v8::FunctionTemplate::Ne w(callback);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 v8::Handle<v8::Value> postTask(v8::Handle<v8::Function> callback, v8::Handle<v8: :Object> receiver, v8::Handle<v8::Value> value, v8::Isolate* isolate) 114 v8::Handle<v8::Value> postTask(v8::Handle<v8::Function> callback, v8::Handle<v8: :Object> receiver, v8::Handle<v8::Value> value, v8::Isolate* isolate)
113 { 115 {
114 DOMWindow* window = activeDOMWindow(); 116 DOMWindow* window = activeDOMWindow();
115 ASSERT(window); 117 ASSERT(window);
116 Document* document = window->document(); 118 Document* document = window->document();
117 ASSERT(document); 119 ASSERT(document);
118 document->postTask(adoptPtr(new PromiseTask(callback, receiver, value))); 120 document->postTask(adoptPtr(new PromiseTask(callback, receiver, value)));
119 return v8::Undefined(isolate); 121 return v8::Undefined(isolate);
120 } 122 }
121 123
122 // This function must have the resolver as the first argument when called 124 // This function must have an environment object as the first argument
125 // when called.
126 // See wrapperCallback.
127 void wrapperCallbackRaw(const v8::FunctionCallbackInfo<v8::Value>& args)
128 {
129 v8::Isolate* isolate = args.GetIsolate();
130 v8::Local<v8::Object> environment;
131 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate());
132 ASSERT(args.Length() > 0);
133 environment = args[0].As<v8::Object>();
134 if (args.Length() > 1)
135 result = args[1];
136
137 v8::Local<v8::Object> promise = environment->GetInternalField(V8PromiseCusto m::WrapperCallbackEnvironmentPromiseIndex).As<v8::Object>();
138 v8::Local<v8::Object> resolver = environment->GetInternalField(V8PromiseCust om::WrapperCallbackEnvironmentPromiseResolverIndex).As<v8::Object>();
139 v8::Local<v8::Function> callback = environment->GetInternalField(V8PromiseCu stom::WrapperCallbackEnvironmentCallbackIndex).As<v8::Function>();
140
141 v8::Local<v8::Value> argv[] = {
142 result,
143 };
144 v8::TryCatch trycatch;
145 result = V8ScriptRunner::callFunction(callback, getScriptExecutionContext(), promise, WTF_ARRAY_LENGTH(argv), argv);
146 if (result.IsEmpty()) {
147 V8PromiseCustom::rejectResolver(resolver, trycatch.Exception(), V8Promis eCustom::Synchronous, isolate);
148 return;
149 }
150 V8PromiseCustom::resolveResolver(resolver, result, V8PromiseCustom::Synchron ous, isolate);
151 }
152
153 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)
154 {
155 // FIXME: v8::ObjectTemplate::New should be cached.
156 v8::Local<v8::ObjectTemplate> objectTemplate = v8::ObjectTemplate::New();
157 objectTemplate->SetInternalFieldCount(V8PromiseCustom::WrapperCallbackEnviro nmentFieldCount);
158 v8::Local<v8::Object> environment = objectTemplate->NewInstance();
159 environment->SetInternalField(V8PromiseCustom::WrapperCallbackEnvironmentPro miseIndex, promise);
160 environment->SetInternalField(V8PromiseCustom::WrapperCallbackEnvironmentPro miseResolverIndex, resolver);
161 environment->SetInternalField(V8PromiseCustom::WrapperCallbackEnvironmentCal lbackIndex, callback);
162
163 // We bind |environment| to wrapperCallbackRaw
164 //
165 // wrapperCallback(result) will be evaluated as
166 // wrapperCallbackRaw(environment, result).
167
168 // FIXME: If there is a way to bind an object to a function other than evalu ate a JavaScript, it will be preferable.
169 // We should not depend on the global context that user can change, such as accessing a property, calling a method or so.
170 v8::Local<v8::String> script = v8::String::New("(function(f, v1) { return fu nction(v2) { return f(v1, v2); }; })");
171 v8::Local<v8::Value> value = V8ScriptRunner::compileAndRunInternalScript(scr ipt, isolate);
abarth-chromium 2013/07/01 05:49:38 This is kind of ugly....
yhirano 2013/07/01 06:58:54 We have to bind an environment object to the funct
172 ASSERT(!value.IsEmpty());
173
174 v8::Local<v8::Value> argv[] = {
175 getFunction(wrapperCallbackRaw, &wrapperCallbackTag, isolate),
176 environment,
177 };
178 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global();
179
180 value = V8ScriptRunner::callFunction(value.As<v8::Function>(), getScriptExec utionContext(), global, WTF_ARRAY_LENGTH(argv), argv);
181 ASSERT(!value.IsEmpty());
182 return value.As<v8::Function>();
183 }
184
185 // This function must have the resolver as the first argument when called.
123 // See promiseCallback. 186 // See promiseCallback.
124 void promiseFulfillCallback(const v8::FunctionCallbackInfo<v8::Value>& args) 187 void promiseFulfillCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
125 { 188 {
126 v8::Local<v8::Object> resolver; 189 v8::Local<v8::Object> resolver;
127 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate()); 190 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate());
128 ASSERT(args.Length() > 0); 191 ASSERT(args.Length() > 0);
129 resolver = args[0].As<v8::Object>(); 192 resolver = args[0].As<v8::Object>();
130 if (args.Length() > 1) 193 if (args.Length() > 1)
131 result = args[1]; 194 result = args[1];
132 195
133 V8PromiseCustom::fulfillResolver(resolver, result, V8PromiseCustom::Synchron ous, args.GetIsolate()); 196 V8PromiseCustom::fulfillResolver(resolver, result, V8PromiseCustom::Synchron ous, args.GetIsolate());
134 } 197 }
135 198
136 // This function must be bound with the resolver as the first argument. 199 // This function must have the resolver as the first argument when called.
137 // See promiseCallback. 200 // See promiseCallback.
138 void promiseResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& args) 201 void promiseResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
139 { 202 {
140 v8::Local<v8::Object> resolver; 203 v8::Local<v8::Object> resolver;
141 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate()); 204 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate());
142 ASSERT(args.Length() > 0); 205 ASSERT(args.Length() > 0);
143 resolver = args[0].As<v8::Object>(); 206 resolver = args[0].As<v8::Object>();
144 if (args.Length() > 1) 207 if (args.Length() > 1)
145 result = args[1]; 208 result = args[1];
146 209
147 V8PromiseCustom::resolveResolver(resolver, result, V8PromiseCustom::Synchron ous, args.GetIsolate()); 210 V8PromiseCustom::resolveResolver(resolver, result, V8PromiseCustom::Synchron ous, args.GetIsolate());
148 } 211 }
149 212
150 // This function must be bound with the resolver as the first argument. 213 // This function must have the resolver as the first argument when called.
151 // See promiseCallback. 214 // See promiseCallback.
152 void promiseRejectCallback(const v8::FunctionCallbackInfo<v8::Value>& args) 215 void promiseRejectCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
153 { 216 {
154 v8::Local<v8::Object> resolver; 217 v8::Local<v8::Object> resolver;
155 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate()); 218 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate());
156 ASSERT(args.Length() > 0); 219 ASSERT(args.Length() > 0);
157 resolver = args[0].As<v8::Object>(); 220 resolver = args[0].As<v8::Object>();
158 if (args.Length() > 1) 221 if (args.Length() > 1)
159 result = args[1]; 222 result = args[1];
160 223
(...skipping 19 matching lines...) Expand all
180 // We bind |resolver| to promise{Fulfill, Resolve, Reject}Callback. 243 // We bind |resolver| to promise{Fulfill, Resolve, Reject}Callback.
181 // 244 //
182 // promiseCallback(result) will be evaluated as 245 // promiseCallback(result) will be evaluated as
183 // promiseFulfillCallback(resolver, result), 246 // promiseFulfillCallback(resolver, result),
184 // if algorithm is FulfillAlgorithm. 247 // if algorithm is FulfillAlgorithm.
185 248
186 // FIXME: If there is a way to bind an object to a function other than evalu ate a JavaScript, it will be preferable. 249 // FIXME: If there is a way to bind an object to a function other than evalu ate a JavaScript, it will be preferable.
187 // We should not depend on the global context that user can change, such as accessing a property, calling a method or so. 250 // We should not depend on the global context that user can change, such as accessing a property, calling a method or so.
188 v8::Local<v8::String> script = v8String("(function(f, v1) { return function( v2) { return f(v1, v2); }; })", isolate); 251 v8::Local<v8::String> script = v8String("(function(f, v1) { return function( v2) { return f(v1, v2); }; })", isolate);
189 v8::Local<v8::Value> value = V8ScriptRunner::compileAndRunInternalScript(scr ipt, isolate); 252 v8::Local<v8::Value> value = V8ScriptRunner::compileAndRunInternalScript(scr ipt, isolate);
253 ASSERT(!value.IsEmpty());
190 254
191 v8::Local<v8::Value> argv[] = { 255 v8::Local<v8::Value> argv[] = {
192 callback, 256 callback,
193 resolver, 257 resolver,
194 }; 258 };
195 v8::Local<v8::Object> receiver = isolate->GetCurrentContext()->Global(); 259 v8::Local<v8::Object> receiver = isolate->GetCurrentContext()->Global();
196 260
197 value = V8ScriptRunner::callFunction(value.As<v8::Function>(), getScriptExec utionContext(), receiver, WTF_ARRAY_LENGTH(argv), argv); 261 value = V8ScriptRunner::callFunction(value.As<v8::Function>(), getScriptExec utionContext(), receiver, WTF_ARRAY_LENGTH(argv), argv);
198 ASSERT(!value.IsEmpty()); 262 ASSERT(!value.IsEmpty());
199 return value.As<v8::Function>(); 263 return value.As<v8::Function>();
(...skipping 28 matching lines...) Expand all
228 v8::TryCatch trycatch; 292 v8::TryCatch trycatch;
229 if (V8ScriptRunner::callFunction(init, getScriptExecutionContext(), promise, WTF_ARRAY_LENGTH(argv), argv).IsEmpty()) { 293 if (V8ScriptRunner::callFunction(init, getScriptExecutionContext(), promise, WTF_ARRAY_LENGTH(argv), argv).IsEmpty()) {
230 // An exception is thrown. Reject the promise if its resolved flag is un set. 294 // An exception is thrown. Reject the promise if its resolved flag is un set.
231 if (!V8PromiseCustom::isInternalDetached(resolver) && V8PromiseCustom::g etState(V8PromiseCustom::getInternal(resolver)) == V8PromiseCustom::Pending) 295 if (!V8PromiseCustom::isInternalDetached(resolver) && V8PromiseCustom::g etState(V8PromiseCustom::getInternal(resolver)) == V8PromiseCustom::Pending)
232 V8PromiseCustom::rejectResolver(resolver, trycatch.Exception(), V8Pr omiseCustom::Asynchronous, isolate); 296 V8PromiseCustom::rejectResolver(resolver, trycatch.Exception(), V8Pr omiseCustom::Asynchronous, isolate);
233 } 297 }
234 v8SetReturnValue(args, promise); 298 v8SetReturnValue(args, promise);
235 return; 299 return;
236 } 300 }
237 301
302 void V8Promise::thenMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args )
303 {
304 v8::Isolate* isolate = args.GetIsolate();
305 v8::Local<v8::Function> fulfillWrapper, rejectWrapper;
306 v8::Local<v8::Object> promise, resolver;
307 V8PromiseCustom::createPromise(args.Holder(), &promise, &resolver, isolate);
308 if (args.Length() > 0 && !args[0]->IsUndefined()) {
309 if (!args[0]->IsFunction()) {
310 v8SetReturnValue(args, throwTypeError("fulfillCallback must be a fun ction or undefined", isolate));
311 return;
312 }
313 fulfillWrapper = wrapperCallback(promise, resolver, args[0].As<v8::Funct ion>(), isolate);
314 } else {
315 fulfillWrapper = promiseCallback(resolver, V8PromiseCustom::FulfillAlgor ithm, isolate);
316 }
317 if (args.Length() > 1 && !args[1]->IsUndefined()) {
318 if (!args[1]->IsFunction()) {
319 v8SetReturnValue(args, throwTypeError("rejectCallback must be a func tion or undefined", isolate));
320 return;
321 }
322 rejectWrapper = wrapperCallback(promise, resolver, args[1].As<v8::Functi on>(), isolate);
323 } else {
324 rejectWrapper = promiseCallback(resolver, V8PromiseCustom::RejectAlgorit hm, isolate);
325 }
326 V8PromiseCustom::append(args.Holder(), fulfillWrapper, rejectWrapper, isolat e);
327 v8SetReturnValue(args, promise);
328 }
329
330 void V8Promise::catchMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& arg s)
331 {
332 v8::Isolate* isolate = args.GetIsolate();
333 v8::Local<v8::Function> fulfillWrapper, rejectWrapper;
334 v8::Local<v8::Object> promise, resolver;
335 V8PromiseCustom::createPromise(args.Holder(), &promise, &resolver, isolate);
336
337 if (args.Length() > 0 && !args[0]->IsUndefined()) {
338 if (!args[0]->IsFunction()) {
339 v8SetReturnValue(args, throwTypeError("rejectCallback must be a func tion or undefined", isolate));
340 return;
341 }
342 rejectWrapper = wrapperCallback(promise, resolver, args[0].As<v8::Functi on>(), isolate);
343 } else {
344 rejectWrapper = promiseCallback(resolver, V8PromiseCustom::RejectAlgorit hm, isolate);
345 }
346 fulfillWrapper = promiseCallback(resolver, V8PromiseCustom::FulfillAlgorithm , isolate);
347 V8PromiseCustom::append(args.Holder(), fulfillWrapper, rejectWrapper, isolat e);
348 v8SetReturnValue(args, promise);
349 }
350
238 // 351 //
239 // -- V8PromiseCustom -- 352 // -- V8PromiseCustom --
240 void V8PromiseCustom::createPromise(v8::Handle<v8::Object> creationContext, v8:: Local<v8::Object>* promise, v8::Local<v8::Object>* resolver, v8::Isolate* isolat e) 353 void V8PromiseCustom::createPromise(v8::Handle<v8::Object> creationContext, v8:: Local<v8::Object>* promise, v8::Local<v8::Object>* resolver, v8::Isolate* isolat e)
241 { 354 {
242 // FIXME: v8::ObjectTemplate::New should be cached. 355 // FIXME: v8::ObjectTemplate::New should be cached.
243 v8::Local<v8::ObjectTemplate> internalTemplate = v8::ObjectTemplate::New(); 356 v8::Local<v8::ObjectTemplate> internalTemplate = v8::ObjectTemplate::New();
244 internalTemplate->SetInternalFieldCount(InternalFieldCount); 357 internalTemplate->SetInternalFieldCount(InternalFieldCount);
245 v8::Local<v8::Object> internal = internalTemplate->NewInstance(); 358 v8::Local<v8::Object> internal = internalTemplate->NewInstance();
246 *promise = V8DOMWrapper::createWrapper(creationContext, &V8Promise::info, 0, isolate); 359 *promise = V8DOMWrapper::createWrapper(creationContext, &V8Promise::info, 0, isolate);
247 *resolver = V8DOMWrapper::createWrapper(creationContext, &V8PromiseResolver: :info, 0, isolate); 360 *resolver = V8DOMWrapper::createWrapper(creationContext, &V8PromiseResolver: :info, 0, isolate);
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 v8::TryCatch trycatch; 504 v8::TryCatch trycatch;
392 v8::Handle<v8::Value> args[] = { result }; 505 v8::Handle<v8::Value> args[] = { result };
393 V8ScriptRunner::callFunction(function, getScriptExecutionContext(), rece iver, WTF_ARRAY_LENGTH(args), args); 506 V8ScriptRunner::callFunction(function, getScriptExecutionContext(), rece iver, WTF_ARRAY_LENGTH(args), args);
394 } else { 507 } else {
395 ASSERT(mode == Asynchronous); 508 ASSERT(mode == Asynchronous);
396 postTask(function, receiver, result, isolate); 509 postTask(function, receiver, result, isolate);
397 } 510 }
398 } 511 }
399 512
400 } // namespace WebCore 513 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/bindings/v8/custom/V8PromiseCustom.h ('k') | Source/core/dom/Promise.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698