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

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/ScriptFunctionCall.h"
37 #include "bindings/v8/ScriptValue.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> templ = v8::FunctionTemplate::New(callback) ;
71 data->templateMap(worldType).add(tag, UnsafePersistent<v8::FunctionTemplate> (isolate, templ));
72 return handleScope.Close(templ)->GetFunction();
abarth-chromium 2013/06/27 03:25:16 Don't you mean: return handleScope.Close(templ->G
yhirano 2013/06/27 05:40:34 Done.
73 }
74
75 class PromiseTask : public ScriptExecutionContext::Task {
76 public:
77 PromiseTask(v8::Handle<v8::Function> callback, v8::Handle<v8::Value> receive r, v8::Handle<v8::Value> result)
78 : m_callback(callback), m_receiver(receiver), m_result(result)
abarth-chromium 2013/06/27 03:25:16 Please split these up on to separate lines.
yhirano 2013/06/27 05:40:34 Done.
79 {
80 ASSERT(!callback.IsEmpty());
81 ASSERT(!receiver.IsEmpty());
82 ASSERT(!result.IsEmpty());
83 }
84 virtual ~PromiseTask() { }
85
86 virtual void performTask(ScriptExecutionContext*) OVERRIDE;
87
88 private:
89 ScriptValue m_callback;
90 ScriptValue m_receiver;
91 ScriptValue m_result;
abarth-chromium 2013/06/27 03:25:16 You can use ScopedPersistent rather than ScriptVal
yhirano 2013/06/27 05:40:34 Done.
92 };
93
94 void PromiseTask::performTask(ScriptExecutionContext* context)
95 {
96 ASSERT(context->isDocument());
97 ScriptState* state = mainWorldScriptState(static_cast<Document*>(context)->f rame());
abarth-chromium 2013/06/27 03:25:16 We should ask the Document whether ActiveDOMObject
yhirano 2013/06/27 05:40:34 Done.
98 v8::HandleScope handleScope;
99 if (!state) {
100 // We can't execute the task. Ignore it.
101 return;
102 }
abarth-chromium 2013/06/27 03:25:16 Can this occur? If not we shouldn't handle this c
yhirano 2013/06/27 05:40:34 Done.
103 v8::Handle<v8::Context> v8Context = state->context();
104 if (v8Context.IsEmpty()) {
105 // We can't execute the task. Ignore it.
106 return;
107 }
abarth-chromium 2013/06/27 03:25:16 Can this occur? If not we shouldn't handle this c
yhirano 2013/06/27 05:40:34 Done.
108 v8::Context::Scope scope(v8Context);
109 v8::Handle<v8::Value> result = m_result.v8Value();
110 ASSERT(!m_callback.v8Value().IsEmpty());
111 ASSERT(m_callback.v8Value()->IsFunction());
112 v8::Local<v8::Function> callback = m_callback.v8Value().As<v8::Function>();
113 ASSERT(!m_receiver.v8Value().IsEmpty());
114 ASSERT(m_receiver.v8Value()->IsObject());
115 v8::Local<v8::Object> receiver =m_receiver.v8Value().As<v8::Object>();
abarth-chromium 2013/06/27 03:25:16 You're missing a = before m_receiver.
yhirano 2013/06/27 05:40:34 Done.
116 ASSERT(!result.IsEmpty());
117 v8::Local<v8::Value> v = V8ScriptRunner::callFunction(callback, context, rec eiver, 1, &result);
abarth-chromium 2013/06/27 03:25:16 You don't need |v| here. You can just ignore the
yhirano 2013/06/27 05:40:34 Done.
118 };
119
120 v8::Handle<v8::Value> postTask(v8::Handle<v8::Function> callback, v8::Handle<v8: :Value> receiver, v8::Handle<v8::Value> value, v8::Isolate* isolate)
121 {
122 DOMWindow* window = activeDOMWindow();
123 if (!window)
124 return setDOMException(INVALID_STATE_ERR, isolate);
abarth-chromium 2013/06/27 03:25:16 Can this occur? If not, we shouldn't handle this
yhirano 2013/06/27 05:40:34 Done.
125 Document* document = window->document();
126 if (!document)
127 return setDOMException(INVALID_STATE_ERR, isolate);
abarth-chromium 2013/06/27 03:25:16 This cannot occur.
yhirano 2013/06/27 05:40:34 Done.
128 document->postTask(adoptPtr(new PromiseTask(callback, receiver, value)));
129 return v8::Undefined();
abarth-chromium 2013/06/27 03:25:16 v8::Undefined(isolate) ?
yhirano 2013/06/27 05:40:34 Done.
130 }
131
132 void wrapperCallbackRaw(const v8::FunctionCallbackInfo<v8::Value>& args)
133 {
134 v8::Isolate* isolate = args.GetIsolate();
135 v8SetReturnValue(args, v8::Undefined());
abarth-chromium 2013/06/27 03:25:16 v8::Undefined(isolate) ?
yhirano 2013/06/27 05:40:34 Done.
136 v8::Local<v8::Object> environment;
137 v8::Local<v8::Value> result = v8::Undefined();
abarth-chromium 2013/06/27 03:25:16 v8::Undefined(isolate) ?
yhirano 2013/06/27 05:40:34 Done.
138 if (args.Length() > 0 && !args[0].IsEmpty() && args[0]->IsObject())
139 environment = args[0].As<v8::Object>();
140 if (args.Length() > 1 && !args[1].IsEmpty())
141 result = args[1];
142 ASSERT(!environment.IsEmpty());
abarth-chromium 2013/06/27 03:25:16 Why is this ASSERT valid? If we don't execute lin
yhirano 2013/06/27 05:40:34 Done.
143
144 v8::Local<v8::Value> value;
145
146 value = environment->GetInternalField(V8PromiseCustom::WrapperCallbackEnviro nmentPromiseIndex);
147 ASSERT(!value.IsEmpty());
148 ASSERT(value->IsObject());
149 v8::Local<v8::Object> promise = value.As<v8::Object>();
150
151 value = environment->GetInternalField(V8PromiseCustom::WrapperCallbackEnviro nmentPromiseResolverIndex);
152 ASSERT(!value.IsEmpty());
153 ASSERT(value->IsObject());
154 v8::Local<v8::Object> resolver = value.As<v8::Object>();
155
156 value = environment->GetInternalField(V8PromiseCustom::WrapperCallbackEnviro nmentCallbackIndex);
157 ASSERT(!value.IsEmpty());
158 ASSERT(value->IsFunction());
159 v8::Local<v8::Function> callback = value.As<v8::Function>();
160
161 v8::TryCatch trycatch;
162 result = V8ScriptRunner::callFunction(callback, getScriptExecutionContext(), promise, 1, &result);
163 if (result.IsEmpty()) {
164 V8PromiseCustom::rejectResolver(resolver, trycatch.Exception(), true, is olate);
165 return;
166 }
167 V8PromiseCustom::resolveResolver(resolver, result, true, isolate);
168 }
169
170 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)
171 {
172 ASSERT(!promise.IsEmpty());
173 ASSERT(!resolver.IsEmpty());
174 ASSERT(!callback.IsEmpty());
175 // FIXME: v8::ObjectTemplate::New should be cached.
176 v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
abarth-chromium 2013/06/27 03:25:16 tmpl -> template (please use complete words in va
yhirano 2013/06/27 05:40:34 Done.
177 tmpl->SetInternalFieldCount(V8PromiseCustom::WrapperCallbackEnvironmentField Count);
178 v8::Local<v8::Object> env = tmpl->NewInstance();
abarth-chromium 2013/06/27 03:25:16 env -> ??? (please use complete words in variabl
yhirano 2013/06/27 05:40:34 Done.
179 env->SetInternalField(V8PromiseCustom::WrapperCallbackEnvironmentPromiseInde x, promise);
180 env->SetInternalField(V8PromiseCustom::WrapperCallbackEnvironmentPromiseReso lverIndex, resolver);
181 env->SetInternalField(V8PromiseCustom::WrapperCallbackEnvironmentCallbackInd ex, callback);
182
183 // FIXME: If there is a way to bind an object to a function other than evalu ate a JavaScript, it will be preferable.
184 // FIXME: script compilation should be cached.
185 // We should not depend on the global context that user can change, such as accessing a property, calling a method or so.
186 v8::Local<v8::String> script = v8::String::New("(function(f, v1) { return fu nction(v2) { return f(v1, v2); }; })");
187 v8::Local<v8::Value> value = V8ScriptRunner::compileAndRunInternalScript(scr ipt, isolate);
abarth-chromium 2013/06/27 03:25:16 There's got to be a better way to do this.
188 ASSERT(!value.IsEmpty());
189 ASSERT(value->IsFunction());
190
191 v8::Local<v8::Value> argv[] = {
192 getFunction(wrapperCallbackRaw, &wrapperCallbackTag, isolate),
193 env,
194 };
195 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global();
abarth-chromium 2013/06/27 03:25:16 Why do you need to get the global? Doesn't callFu
196
197 value = V8ScriptRunner::callFunction(value.As<v8::Function>(), getScriptExec utionContext(), global, WTF_ARRAY_LENGTH(argv), argv);
198 ASSERT(!value.IsEmpty());
199 ASSERT(value->IsFunction());
200 return value.As<v8::Function>();
201 }
202
203 void promiseFulfillCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
204 {
205 v8::Local<v8::Object> resolver;
206 v8::Local<v8::Value> result = v8::Undefined();
207 if (args.Length() > 0 && !args[0].IsEmpty() && args[0]->IsObject())
208 resolver = args[0].As<v8::Object>();
209 if (args.Length() > 1 && !args[1].IsEmpty())
210 result = args[1];
211
212 ASSERT(!resolver.IsEmpty());
abarth-chromium 2013/06/27 03:25:16 Again, why do we have this ASSERT and the branch o
yhirano 2013/06/27 05:40:34 Done.
213 V8PromiseCustom::fulfillResolver(resolver, result, true, args.GetIsolate());
214 }
215
216 void promiseResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
217 {
218 v8::Local<v8::Object> resolver;
219 v8::Local<v8::Value> result = v8::Undefined();
220 if (args.Length() > 0 && !args[0].IsEmpty() && args[0]->IsObject())
221 resolver = args[0].As<v8::Object>();
222 if (args.Length() > 1 && !args[1].IsEmpty())
223 result = args[1];
224
225 ASSERT(!resolver.IsEmpty());
226 V8PromiseCustom::resolveResolver(resolver, result, true, args.GetIsolate());
227 }
228
229 void promiseRejectCallback(const v8::FunctionCallbackInfo<v8::Value>& args)
230 {
231 v8::Local<v8::Object> resolver;
232 v8::Local<v8::Value> result = v8::Undefined();
233 if (args.Length() > 0 && !args[0].IsEmpty() && args[0]->IsObject())
234 resolver = args[0].As<v8::Object>();
235 if (args.Length() > 1 && !args[1].IsEmpty())
236 result = args[1];
237
238 ASSERT(!resolver.IsEmpty());
239 V8PromiseCustom::rejectResolver(resolver, result, true, args.GetIsolate());
240 }
241
242 v8::Local<v8::Function> promiseCallback(v8::Handle<v8::Object> resolver, V8Promi seCustom::PromiseAlgorithm algorithm, v8::Isolate* isolate)
243 {
244 ASSERT(!resolver.IsEmpty());
245 v8::Local<v8::Function> callback;
246 switch (algorithm) {
247 case V8PromiseCustom::FulfillAlgorithm:
248 callback = getFunction(promiseFulfillCallback, &promiseFulfillCallbackTa g, isolate);
249 break;
250 case V8PromiseCustom::ResolveAlgorithm:
251 callback = getFunction(promiseResolveCallback, &promiseResolveCallbackTa g, isolate);
252 break;
253 case V8PromiseCustom::RejectAlgorithm:
254 callback = getFunction(promiseRejectCallback, &promiseRejectCallbackTag, isolate);
255 break;
256 default:
257 ASSERT(0);
258 }
259
260 // FIXME: If there is a way to bind an object to a function other than evalu ate a JavaScript, it will be preferable.
261 // FIXME: script compilation should be cached.
262 // We should not depend on the global context that user can change, such as accessing a property, calling a method or so.
263 v8::Local<v8::String> script = v8::String::New("(function(f, v1) { return fu nction(v2) { return f(v1, v2); }; })");
264 v8::Local<v8::Value> value = V8ScriptRunner::compileAndRunInternalScript(scr ipt, isolate);
265 ASSERT(!value.IsEmpty());
266 ASSERT(value->IsFunction());
267
268 v8::Local<v8::Value> argv[] = {
269 callback,
270 resolver,
271 };
272 v8::Local<v8::Object> receiver = isolate->GetCurrentContext()->Global();
273
274 value = V8ScriptRunner::callFunction(value.As<v8::Function>(), getScriptExec utionContext(), receiver, WTF_ARRAY_LENGTH(argv), argv);
275 ASSERT(!value.IsEmpty());
276 ASSERT(value->IsFunction());
277 return value.As<v8::Function>();
278 }
279
280 } // namespace
281
43 void V8Promise::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& arg s) 282 void V8Promise::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& arg s)
44 { 283 {
45 v8SetReturnValue(args, v8::Local<v8::Value>()); 284 v8SetReturnValue(args, v8::Local<v8::Value>());
46 v8::Isolate* isolate = args.GetIsolate(); 285 v8::Isolate* isolate = args.GetIsolate();
47 if (!args.Length() || args[0].IsEmpty() || !args[0]->IsFunction()) { 286 if (!args.Length() || args[0].IsEmpty() || !args[0]->IsFunction()) {
48 throwTypeError("Promise constructor takes a function argument", isolate) ; 287 throwTypeError("Promise constructor takes a function argument", isolate) ;
49 return; 288 return;
50 } 289 }
51 v8::Handle<v8::Function> init = args[0].As<v8::Function>(); 290 v8::Local<v8::Function> init = args[0].As<v8::Function>();
52 v8::Local<v8::ObjectTemplate> internalTemplate = v8::ObjectTemplate::New(); 291 v8::Local<v8::Object> promise, resolver;
53 internalTemplate->SetInternalFieldCount(V8PromiseCustom::InternalFieldCount) ; 292 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[] = { 293 v8::Handle<v8::Value> argv[] = {
67 promiseResolver, 294 resolver,
68 }; 295 };
69 v8::TryCatch trycatch; 296 v8::TryCatch trycatch;
70 if (V8ScriptRunner::callFunction(init, getScriptExecutionContext(), promise, WTF_ARRAY_LENGTH(argv), argv).IsEmpty()) { 297 if (V8ScriptRunner::callFunction(init, getScriptExecutionContext(), promise, WTF_ARRAY_LENGTH(argv), argv).IsEmpty()) {
71 // FIXME: An exception is thrown. Reject the promise. 298 // An exception is thrown. Reject the promise.
299 V8PromiseCustom::rejectResolver(resolver, trycatch.Exception(), false, i solate);
72 } 300 }
73 v8SetReturnValue(args, promise); 301 v8SetReturnValue(args, promise);
74 return; 302 return;
75 } 303 }
76 304
305 void V8Promise::thenMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args )
306 {
307 v8::Isolate* isolate = args.GetIsolate();
308 v8SetReturnValue(args, v8::Local<v8::Value>());
309 v8::Local<v8::Function> fulfillWrapper, rejectWrapper;
310 v8::Local<v8::Object> promise, resolver;
311 V8PromiseCustom::createPromise(args.Holder(), &promise, &resolver, isolate);
312 if (args.Length() > 0 && !args[0].IsEmpty() && !args[0]->IsUndefined()) {
313 if (!args[0]->IsFunction()) {
314 throwTypeError("fulfillCallback must be a function or undefined", is olate);
315 return;
316 }
317 fulfillWrapper = wrapperCallback(promise, resolver, args[0].As<v8::Funct ion>(), isolate);
318 } else {
319 fulfillWrapper = promiseCallback(resolver, V8PromiseCustom::FulfillAlgor ithm, isolate);
320 }
321 if (args.Length() > 1 && !args[1].IsEmpty() && !args[1]->IsUndefined()) {
322 if (!args[1]->IsFunction()) {
323 throwTypeError("rejectCallback must be a function or undefined", iso late);
324 return;
325 }
326 rejectWrapper = wrapperCallback(promise, resolver, args[1].As<v8::Functi on>(), isolate);
327 } else {
328 rejectWrapper = promiseCallback(resolver, V8PromiseCustom::RejectAlgorit hm, isolate);
329 }
330 V8PromiseCustom::append(args.Holder(), fulfillWrapper, rejectWrapper, isolat e);
331 v8SetReturnValue(args, promise);
332 }
333
334 void V8Promise::catchMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& arg s)
335 {
336 v8::Isolate* isolate = args.GetIsolate();
337 v8SetReturnValue(args, v8::Local<v8::Value>());
338 v8::Local<v8::Function> fulfillWrapper, rejectWrapper;
339 v8::Local<v8::Object> promise, resolver;
340 V8PromiseCustom::createPromise(args.Holder(), &promise, &resolver, isolate);
341
342 if (args.Length() > 0 && !args[0].IsEmpty() && !args[0]->IsUndefined()) {
343 if (!args[0]->IsFunction()) {
344 throwTypeError("rejectCallback must be a function or undefined", iso late);
345 return;
346 }
347 rejectWrapper = wrapperCallback(promise, resolver, args[0].As<v8::Functi on>(), isolate);
348 } else {
349 rejectWrapper = promiseCallback(resolver, V8PromiseCustom::RejectAlgorit hm, isolate);
350 }
351 fulfillWrapper = promiseCallback(resolver, V8PromiseCustom::FulfillAlgorithm , isolate);
352 V8PromiseCustom::append(args.Holder(), fulfillWrapper, rejectWrapper, isolat e);
353 v8SetReturnValue(args, promise);
354 }
355
356 //
357 // -- V8PromiseCustom --
358 void V8PromiseCustom::createPromise(v8::Handle<v8::Object> creationContext, v8:: Local<v8::Object>* promise, v8::Local<v8::Object>* resolver, v8::Isolate* isolat e)
359 {
360 // FIXME: v8::ObjectTemplate::New should be cached.
361 v8::Local<v8::ObjectTemplate> internalTemplate = v8::ObjectTemplate::New();
362 internalTemplate->SetInternalFieldCount(InternalFieldCount);
363 v8::Local<v8::Object> internal = internalTemplate->NewInstance();
364 *promise = V8DOMWrapper::createWrapper(creationContext, &V8Promise::info, 0, isolate);
365 *resolver = V8DOMWrapper::createWrapper(creationContext, &V8PromiseResolver: :info, 0, isolate);
366
367 clearInternal(internal, V8PromiseCustom::Pending, v8::Undefined());
368
369 (*promise)->SetInternalField(v8DOMWrapperObjectIndex, internal);
370 (*resolver)->SetInternalField(v8DOMWrapperObjectIndex, internal);
371 }
372
373 void V8PromiseCustom::fulfillResolver(v8::Handle<v8::Object> resolver, v8::Handl e<v8::Value> result, bool synchronous, v8::Isolate* isolate)
374 {
375 ASSERT(!resolver.IsEmpty());
376 ASSERT(!result.IsEmpty());
377 v8::Local<v8::Object> internal = getInternal(resolver);
378 if (internal.IsEmpty() || getState(internal) != Pending) {
379 // The resolver is already fulfilled or rejected.
380 return;
381 }
382
383 v8::Local<v8::Value> value;
384 value = internal->GetInternalField(V8PromiseCustom::InternalFulfillCallbackI ndex);
385 ASSERT(!value.IsEmpty());
386 ASSERT(value->IsArray());
387 v8::Local<v8::Array> callbacks = value.As<v8::Array>();
388 clearInternal(internal, Fulfilled, result);
389 // The internal object is no more needed in this PromiseResolver.
390 resolver->SetInternalField(v8DOMWrapperObjectIndex, v8::Null());
391
392 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global();
393 for (uint32_t i = 0, length = callbacks->Length(); i < length; ++i) {
394 value = callbacks->Get(i);
395 ASSERT(!value.IsEmpty());
396 ASSERT(value->IsFunction());
397 v8::Local<v8::Function> callback = value.As<v8::Function>();
398 call(callback, global, result, synchronous, isolate);
399 }
400 }
401
402 void V8PromiseCustom::resolveResolver(v8::Handle<v8::Object> resolver, v8::Handl e<v8::Value> result, bool synchronous, v8::Isolate* isolate)
403 {
404 ASSERT(!resolver.IsEmpty());
405 ASSERT(!result.IsEmpty());
406 v8::Local<v8::Object> internal = getInternal(resolver);
407 if (internal.IsEmpty() || getState(internal) != Pending) {
408 // The resolver is already fulfilled or rejected.
409 return;
410 }
411
412 v8::Local<v8::Value> then;
413 if (result->IsObject()) {
414 v8::TryCatch trycatch;
415 then = result.As<v8::Object>()->Get(v8::String::New("then"));
416 if (then.IsEmpty()) {
417 // If calling the [[Get]] internal method threw an exception, catch it and run reject.
418 rejectResolver(resolver, trycatch.Exception(), synchronous, isolate) ;
419 return;
420 }
421 }
422
423 if (!then.IsEmpty() && then->IsFunction()) {
424 ASSERT(result->IsObject());
425 v8::TryCatch trycatch;
426 v8::Handle<v8::Value> argv[] = {
427 promiseCallback(resolver, ResolveAlgorithm, isolate),
428 promiseCallback(resolver, RejectAlgorithm, isolate),
429 };
430 if (V8ScriptRunner::callFunction(then.As<v8::Function>(), getScriptExecu tionContext(), result.As<v8::Object>(), WTF_ARRAY_LENGTH(argv), argv).IsEmpty())
431 rejectResolver(resolver, trycatch.Exception(), synchronous, isolate) ;
432 return;
433 }
434 fulfillResolver(resolver, result, synchronous, isolate);
435 }
436
437 void V8PromiseCustom::rejectResolver(v8::Handle<v8::Object> resolver, v8::Handle <v8::Value> result, bool synchronous, v8::Isolate* isolate)
438 {
439 ASSERT(!resolver.IsEmpty());
440 ASSERT(!result.IsEmpty());
441 v8::Local<v8::Object> internal = getInternal(resolver);
442 if (internal.IsEmpty() || getState(internal) != Pending) {
443 // The resolver is already fulfilled or rejected.
444 return;
445 }
446
447 v8::Local<v8::Value> value;
448 value = internal->GetInternalField(V8PromiseCustom::InternalRejectCallbackIn dex);
449 ASSERT(!value.IsEmpty());
450 ASSERT(value->IsArray());
451 v8::Local<v8::Array> callbacks = value.As<v8::Array>();
452 clearInternal(internal, Rejected, result);
453 // The internal object is no more needed from this PromiseResolver.
454 resolver->SetInternalField(v8DOMWrapperObjectIndex, v8::Null());
455
456 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global();
457 for (uint32_t i = 0, length = callbacks->Length(); i < length; ++i) {
458 value = callbacks->Get(i);
459 ASSERT(!value.IsEmpty());
460 ASSERT(value->IsFunction());
461 v8::Local<v8::Function> callback = value.As<v8::Function>();
462 call(callback, global, result, synchronous, isolate);
463 }
464 }
465
466 void V8PromiseCustom::append(v8::Handle<v8::Object> promise, v8::Handle<v8::Func tion> fulfillCallback, v8::Handle<v8::Function> rejectCallback, v8::Isolate* iso late)
467 {
468 v8::Local<v8::Object> internal = getInternal(promise);
469 ASSERT(!internal.IsEmpty());
470
471 PromiseState state = getState(internal);
472 if (state == Fulfilled) {
473 if (!fulfillCallback.IsEmpty()) {
474 v8::Local<v8::Value> result = internal->GetInternalField(V8PromiseCu stom::InternalResultIndex);
475 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global( );
476 call(fulfillCallback, global, result, false, isolate);
477 }
478 return;
479 }
480 if (state == Rejected) {
481 if (!rejectCallback.IsEmpty()) {
482 v8::Local<v8::Value> result = internal->GetInternalField(V8PromiseCu stom::InternalResultIndex);
483 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global( );
484 call(rejectCallback, global, result, false, isolate);
485 }
486 return;
487 }
488
489 ASSERT(state == Pending);
490 if (!fulfillCallback.IsEmpty()) {
491 v8::Local<v8::Value> value = internal->GetInternalField(InternalFulfillC allbackIndex);
492 ASSERT(!value.IsEmpty());
493 ASSERT(value->IsArray());
494 v8::Local<v8::Array> callbacks = value.As<v8::Array>();
495 callbacks->Set(callbacks->Length(), fulfillCallback);
496 }
497 if (!rejectCallback.IsEmpty()) {
498 v8::Local<v8::Value> value = internal->GetInternalField(InternalRejectCa llbackIndex);
499 ASSERT(!value.IsEmpty());
500 ASSERT(value->IsArray());
501 v8::Local<v8::Array> callbacks = value.As<v8::Array>();
502 callbacks->Set(callbacks->Length(), rejectCallback);
503 }
504 }
505
506 v8::Local<v8::Object> V8PromiseCustom::getInternal(v8::Handle<v8::Object> promis eOrPromiseResolver)
507 {
508 ASSERT(!promiseOrPromiseResolver.IsEmpty());
509 v8::Local<v8::Value> value = promiseOrPromiseResolver->GetInternalField(v8DO MWrapperObjectIndex);
510 ASSERT(!value.IsEmpty());
511 if (value->IsNull())
512 return v8::Local<v8::Object>();
513 ASSERT(value->IsObject());
514 return value.As<v8::Object>();
515 }
516
517 void V8PromiseCustom::clearInternal(v8::Handle<v8::Object> internal, PromiseStat e state, v8::Handle<v8::Value> value)
518 {
519 ASSERT(!internal.IsEmpty());
520
521 setState(internal, state);
522 internal->SetInternalField(V8PromiseCustom::InternalResultIndex, value);
523 internal->SetInternalField(V8PromiseCustom::InternalFulfillCallbackIndex, v8 ::Array::New());
524 internal->SetInternalField(V8PromiseCustom::InternalRejectCallbackIndex, v8: :Array::New());
525 }
526
527 V8PromiseCustom::PromiseState V8PromiseCustom::getState(v8::Handle<v8::Object> i nternal)
528 {
529 ASSERT(!internal.IsEmpty());
530 v8::Handle<v8::Value> value = internal->GetInternalField(V8PromiseCustom::In ternalStateIndex);
531 ASSERT(!value.IsEmpty());
532 ASSERT(value->IsNumber());
533 double number = value.As<v8::Number>()->Value();
534 ASSERT(number == Pending || number == Fulfilled || number == Rejected);
535 return static_cast<PromiseState>(number);
536 }
537
538 void V8PromiseCustom::setState(v8::Handle<v8::Object> internal, PromiseState sta te)
539 {
540 ASSERT(!internal.IsEmpty());
541 ASSERT(state == Pending || state == Fulfilled || state == Rejected);
542 internal->SetInternalField(V8PromiseCustom::InternalStateIndex, v8::Number:: New(state));
543 }
544
545 void V8PromiseCustom::call(v8::Handle<v8::Function> function, v8::Handle<v8::Obj ect> receiver, v8::Handle<v8::Value> result, bool synchronous, v8::Isolate* isol ate)
546 {
547 ASSERT(!function.IsEmpty());
548 ASSERT(!receiver.IsEmpty());
549 if (synchronous) {
550 v8::TryCatch trycatch;
551 V8ScriptRunner::callFunction(function, getScriptExecutionContext(), rece iver, 1, &result);
552 } else {
553 postTask(function, receiver, result, isolate);
554 }
555 }
556
77 } // namespace WebCore 557 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698