OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |