Chromium Code Reviews| 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 15 matching lines...) Expand all Loading... | |
| 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 class PromiseTask : public ScriptExecutionContext::Task { | |
| 55 public: | |
| 56 PromiseTask(v8::Handle<v8::Function> callback, v8::Handle<v8::Object> receiv er, v8::Handle<v8::Value> result) | |
| 57 : m_callback(callback) | |
| 58 , m_receiver(receiver) | |
| 59 , m_result(result) | |
| 60 { | |
| 61 ASSERT(!m_callback.isEmpty()); | |
| 62 ASSERT(!m_receiver.isEmpty()); | |
| 63 ASSERT(!m_result.isEmpty()); | |
| 64 } | |
| 65 virtual ~PromiseTask() { } | |
| 66 | |
| 67 virtual void performTask(ScriptExecutionContext*) OVERRIDE; | |
| 68 | |
| 69 private: | |
| 70 ScopedPersistent<v8::Function> m_callback; | |
| 71 ScopedPersistent<v8::Object> m_receiver; | |
| 72 ScopedPersistent<v8::Value> m_result; | |
| 73 }; | |
| 74 | |
| 75 void PromiseTask::performTask(ScriptExecutionContext* context) | |
| 76 { | |
| 77 ASSERT(context && context->isDocument()); | |
| 78 if (context->activeDOMObjectsAreStopped()) | |
| 79 return; | |
| 80 ScriptState* state = mainWorldScriptState(static_cast<Document*>(context)->f rame()); | |
| 81 v8::HandleScope handleScope; | |
| 82 ASSERT(state); | |
| 83 v8::Handle<v8::Context> v8Context = state->context(); | |
| 84 v8::Context::Scope scope(v8Context); | |
| 85 v8::Isolate* isolate = v8Context->GetIsolate(); | |
| 86 v8::Handle<v8::Value> args[] = { m_result.newLocal(isolate) }; | |
| 87 V8ScriptRunner::callFunction(m_callback.newLocal(isolate), context, m_receiv er.newLocal(isolate), WTF_ARRAY_LENGTH(args), args); | |
| 88 }; | |
| 89 | |
| 90 v8::Handle<v8::Value> postTask(v8::Handle<v8::Function> callback, v8::Handle<v8: :Object> receiver, v8::Handle<v8::Value> value, v8::Isolate* isolate) | |
| 91 { | |
| 92 DOMWindow* window = activeDOMWindow(); | |
| 93 ASSERT(window); | |
| 94 Document* document = window->document(); | |
| 95 ASSERT(document); | |
| 96 document->postTask(adoptPtr(new PromiseTask(callback, receiver, value))); | |
| 97 return v8::Undefined(isolate); | |
| 98 } | |
| 99 | |
| 100 void callCallbacks(v8::Handle<v8::Array> callbacks, v8::Handle<v8::Value> result , V8PromiseCustom::SynchronousMode mode, v8::Isolate* isolate) | |
| 101 { | |
| 102 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global(); | |
| 103 for (uint32_t i = 0, length = callbacks->Length(); i < length; ++i) { | |
| 104 v8::Local<v8::Value> value = callbacks->Get(i); | |
| 105 v8::Local<v8::Function> callback = value.As<v8::Function>(); | |
| 106 V8PromiseCustom::call(callback, global, result, mode, isolate); | |
| 107 } | |
| 108 } | |
| 109 | |
| 110 } // namespace | |
| 111 | |
| 43 void V8Promise::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& arg s) | 112 void V8Promise::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& arg s) |
| 44 { | 113 { |
| 45 v8SetReturnValue(args, v8::Local<v8::Value>()); | 114 v8SetReturnValue(args, v8::Local<v8::Value>()); |
| 46 v8::Isolate* isolate = args.GetIsolate(); | 115 v8::Isolate* isolate = args.GetIsolate(); |
| 47 if (!args.Length() || args[0].IsEmpty() || !args[0]->IsFunction()) { | 116 if (!args.Length() || !args[0]->IsFunction()) { |
| 48 throwTypeError("Promise constructor takes a function argument", isolate) ; | 117 throwTypeError("Promise constructor takes a function argument", isolate) ; |
| 49 return; | 118 return; |
| 50 } | 119 } |
| 51 v8::Handle<v8::Function> init = args[0].As<v8::Function>(); | 120 v8::Local<v8::Function> init = args[0].As<v8::Function>(); |
| 52 v8::Local<v8::ObjectTemplate> internalTemplate = v8::ObjectTemplate::New(); | 121 v8::Local<v8::Object> promise, resolver; |
| 53 internalTemplate->SetInternalFieldCount(V8PromiseCustom::InternalFieldCount) ; | 122 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[] = { | 123 v8::Handle<v8::Value> argv[] = { |
| 67 promiseResolver, | 124 resolver, |
| 68 }; | 125 }; |
| 69 v8::TryCatch trycatch; | 126 v8::TryCatch trycatch; |
| 70 if (V8ScriptRunner::callFunction(init, getScriptExecutionContext(), promise, WTF_ARRAY_LENGTH(argv), argv).IsEmpty()) { | 127 if (V8ScriptRunner::callFunction(init, getScriptExecutionContext(), promise, WTF_ARRAY_LENGTH(argv), argv).IsEmpty()) { |
| 71 // FIXME: An exception is thrown. Reject the promise. | 128 // An exception is thrown. Reject the promise. |
| 129 V8PromiseCustom::rejectResolver(resolver, trycatch.Exception(), V8Promis eCustom::Asynchronous, isolate); | |
| 72 } | 130 } |
| 73 v8SetReturnValue(args, promise); | 131 v8SetReturnValue(args, promise); |
| 74 return; | 132 return; |
| 75 } | 133 } |
| 76 | 134 |
| 135 // | |
| 136 // -- V8PromiseCustom -- | |
| 137 void V8PromiseCustom::createPromise(v8::Handle<v8::Object> creationContext, v8:: Local<v8::Object>* promise, v8::Local<v8::Object>* resolver, v8::Isolate* isolat e) | |
| 138 { | |
| 139 // FIXME: v8::ObjectTemplate::New should be cached. | |
| 140 v8::Local<v8::ObjectTemplate> internalTemplate = v8::ObjectTemplate::New(); | |
| 141 internalTemplate->SetInternalFieldCount(InternalFieldCount); | |
| 142 v8::Local<v8::Object> internal = internalTemplate->NewInstance(); | |
| 143 *promise = V8DOMWrapper::createWrapper(creationContext, &V8Promise::info, 0, isolate); | |
| 144 *resolver = V8DOMWrapper::createWrapper(creationContext, &V8PromiseResolver: :info, 0, isolate); | |
| 145 | |
| 146 clearInternal(internal, V8PromiseCustom::Pending, v8::Undefined(isolate)); | |
| 147 | |
| 148 (*promise)->SetInternalField(v8DOMWrapperObjectIndex, internal); | |
| 149 (*resolver)->SetInternalField(v8DOMWrapperObjectIndex, internal); | |
| 150 } | |
| 151 | |
| 152 void V8PromiseCustom::fulfillResolver(v8::Handle<v8::Object> resolver, v8::Handl e<v8::Value> result, SynchronousMode mode, v8::Isolate* isolate) | |
| 153 { | |
| 154 if (isInternalDetached(resolver)) | |
| 155 return; | |
| 156 v8::Local<v8::Object> internal = getInternal(resolver); | |
| 157 if (getState(internal) != Pending) | |
| 158 return; | |
| 159 | |
| 160 v8::Local<v8::Array> callbacks = internal->GetInternalField(V8PromiseCustom: :InternalFulfillCallbackIndex).As<v8::Array>(); | |
| 161 clearInternal(internal, Fulfilled, result); | |
| 162 detachInternal(resolver, isolate); | |
| 163 | |
| 164 callCallbacks(callbacks, result, mode, isolate); | |
| 165 } | |
| 166 | |
| 167 void V8PromiseCustom::rejectResolver(v8::Handle<v8::Object> resolver, v8::Handle <v8::Value> result, SynchronousMode mode, v8::Isolate* isolate) | |
| 168 { | |
| 169 if (isInternalDetached(resolver)) | |
| 170 return; | |
| 171 v8::Local<v8::Object> internal = getInternal(resolver); | |
| 172 if (getState(internal) != Pending) | |
| 173 return; | |
| 174 | |
| 175 v8::Local<v8::Array> callbacks = internal->GetInternalField(V8PromiseCustom: :InternalRejectCallbackIndex).As<v8::Array>(); | |
| 176 clearInternal(internal, Rejected, result); | |
| 177 detachInternal(resolver, isolate); | |
| 178 | |
| 179 callCallbacks(callbacks, result, mode, isolate); | |
| 180 } | |
| 181 | |
| 182 void V8PromiseCustom::append(v8::Handle<v8::Object> promise, v8::Handle<v8::Func tion> fulfillCallback, v8::Handle<v8::Function> rejectCallback, v8::Isolate* iso late) | |
| 183 { | |
| 184 // fulfillCallback and rejectCallback can be empty. | |
| 185 v8::Local<v8::Object> internal = getInternal(promise).As<v8::Object>(); | |
| 186 | |
| 187 PromiseState state = getState(internal); | |
| 188 if (state == Fulfilled) { | |
| 189 if (!fulfillCallback.IsEmpty()) { | |
| 190 v8::Local<v8::Value> result = internal->GetInternalField(V8PromiseCu stom::InternalResultIndex); | |
| 191 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global( ); | |
| 192 call(fulfillCallback, global, result, Asynchronous, isolate); | |
| 193 } | |
| 194 return; | |
| 195 } | |
| 196 if (state == Rejected) { | |
| 197 if (!rejectCallback.IsEmpty()) { | |
| 198 v8::Local<v8::Value> result = internal->GetInternalField(V8PromiseCu stom::InternalResultIndex); | |
| 199 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global( ); | |
| 200 call(rejectCallback, global, result, Asynchronous, isolate); | |
| 201 } | |
| 202 return; | |
| 203 } | |
| 204 | |
| 205 ASSERT(state == Pending); | |
| 206 if (!fulfillCallback.IsEmpty()) { | |
| 207 v8::Local<v8::Array> callbacks = internal->GetInternalField(InternalFulf illCallbackIndex).As<v8::Array>(); | |
| 208 callbacks->Set(callbacks->Length(), fulfillCallback); | |
| 209 } | |
| 210 if (!rejectCallback.IsEmpty()) { | |
| 211 v8::Local<v8::Array> callbacks = internal->GetInternalField(InternalReje ctCallbackIndex).As<v8::Array>(); | |
| 212 callbacks->Set(callbacks->Length(), rejectCallback); | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 v8::Local<v8::Object> V8PromiseCustom::getInternal(v8::Handle<v8::Object> promis eOrResolver) | |
| 217 { | |
| 218 v8::Local<v8::Value> value = promiseOrResolver->GetInternalField(v8DOMWrappe rObjectIndex); | |
| 219 // This function cannot be called when the internal object is detached, so t he value must be an object. | |
| 220 return value.As<v8::Object>(); | |
| 221 } | |
| 222 | |
| 223 bool V8PromiseCustom::isInternalDetached(v8::Handle<v8::Object> resolver) | |
| 224 { | |
| 225 v8::Local<v8::Value> value = resolver->GetInternalField(v8DOMWrapperObjectIn dex); | |
| 226 return value->IsUndefined(); | |
|
haraken
2013/06/27 10:36:29
You might want to add ASSERT(!value.IsEmpty()) jus
yhirano
2013/06/28 00:47:18
Done.
| |
| 227 } | |
| 228 | |
| 229 void V8PromiseCustom::detachInternal(v8::Handle<v8::Object> resolver, v8::Isolat e* isolate) | |
| 230 { | |
| 231 resolver->SetInternalField(v8DOMWrapperObjectIndex, v8::Undefined(isolate)); | |
| 232 } | |
| 233 | |
| 234 void V8PromiseCustom::clearInternal(v8::Handle<v8::Object> internal, PromiseStat e state, v8::Handle<v8::Value> value) | |
| 235 { | |
| 236 setState(internal, state); | |
| 237 internal->SetInternalField(V8PromiseCustom::InternalResultIndex, value); | |
| 238 internal->SetInternalField(V8PromiseCustom::InternalFulfillCallbackIndex, v8 ::Array::New()); | |
| 239 internal->SetInternalField(V8PromiseCustom::InternalRejectCallbackIndex, v8: :Array::New()); | |
| 240 } | |
| 241 | |
| 242 V8PromiseCustom::PromiseState V8PromiseCustom::getState(v8::Handle<v8::Object> i nternal) | |
| 243 { | |
| 244 v8::Handle<v8::Value> value = internal->GetInternalField(V8PromiseCustom::In ternalStateIndex); | |
| 245 bool ok = false; | |
| 246 uint32_t number = toInt32(value, ok); | |
| 247 ASSERT(ok && (number == Pending || number == Fulfilled || number == Rejected )); | |
| 248 return static_cast<PromiseState>(number); | |
| 249 } | |
| 250 | |
| 251 void V8PromiseCustom::setState(v8::Handle<v8::Object> internal, PromiseState sta te) | |
| 252 { | |
| 253 ASSERT(state == Pending || state == Fulfilled || state == Rejected); | |
| 254 internal->SetInternalField(V8PromiseCustom::InternalStateIndex, v8::Integer: :New(state)); | |
| 255 } | |
| 256 | |
| 257 void V8PromiseCustom::call(v8::Handle<v8::Function> function, v8::Handle<v8::Obj ect> receiver, v8::Handle<v8::Value> result, SynchronousMode mode, v8::Isolate* isolate) | |
| 258 { | |
| 259 if (mode == Synchronous) { | |
| 260 // If an exception is thrown, catch it and do nothing. | |
| 261 v8::TryCatch trycatch; | |
| 262 v8::Handle<v8::Value> args[] = { result }; | |
| 263 V8ScriptRunner::callFunction(function, getScriptExecutionContext(), rece iver, WTF_ARRAY_LENGTH(args), args); | |
|
haraken
2013/06/27 10:36:29
Are you sure that you've entered the context? If y
yhirano
2013/06/28 00:47:18
Done.
| |
| 264 } else { | |
| 265 ASSERT(mode == Asynchronous); | |
| 266 postTask(function, receiver, result, isolate); | |
| 267 } | |
| 268 } | |
| 269 | |
| 77 } // namespace WebCore | 270 } // namespace WebCore |
| OLD | NEW |