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 18 matching lines...) Expand all Loading... |
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 "bindings/v8/ScopedPersistent.h" | 35 #include "bindings/v8/ScopedPersistent.h" |
36 #include "bindings/v8/ScriptFunctionCall.h" | 36 #include "bindings/v8/ScriptFunctionCall.h" |
37 #include "bindings/v8/ScriptState.h" | 37 #include "bindings/v8/ScriptState.h" |
38 #include "bindings/v8/V8Binding.h" | 38 #include "bindings/v8/V8Binding.h" |
| 39 #include "bindings/v8/V8HiddenPropertyName.h" |
39 #include "bindings/v8/V8PerIsolateData.h" | 40 #include "bindings/v8/V8PerIsolateData.h" |
40 #include "bindings/v8/V8ScriptRunner.h" | 41 #include "bindings/v8/V8ScriptRunner.h" |
41 #include "bindings/v8/WrapperTypeInfo.h" | 42 #include "bindings/v8/WrapperTypeInfo.h" |
42 #include "core/dom/Document.h" | 43 #include "core/dom/Document.h" |
43 #include "core/page/DOMWindow.h" | 44 #include "core/page/DOMWindow.h" |
44 #include "core/platform/Task.h" | 45 #include "core/platform/Task.h" |
45 #include "core/workers/WorkerGlobalScope.h" | 46 #include "core/workers/WorkerGlobalScope.h" |
| 47 #include "wtf/Deque.h" |
46 #include "wtf/Functional.h" | 48 #include "wtf/Functional.h" |
| 49 #include "wtf/Noncopyable.h" |
47 #include "wtf/PassOwnPtr.h" | 50 #include "wtf/PassOwnPtr.h" |
48 #include <v8.h> | 51 #include <v8.h> |
49 | 52 |
50 namespace WebCore { | 53 namespace WebCore { |
51 | 54 |
52 namespace { | 55 namespace { |
53 | 56 |
54 v8::Local<v8::ObjectTemplate> cachedObjectTemplate(void* privateTemplateUniqueKe
y, int internalFieldCount, v8::Isolate* isolate) | 57 v8::Local<v8::ObjectTemplate> cachedObjectTemplate(void* privateTemplateUniqueKe
y, int internalFieldCount, v8::Isolate* isolate) |
55 { | 58 { |
56 V8PerIsolateData* data = V8PerIsolateData::from(isolate); | 59 V8PerIsolateData* data = V8PerIsolateData::from(isolate); |
57 WrapperWorldType currentWorldType = worldType(isolate); | 60 WrapperWorldType currentWorldType = worldType(isolate); |
58 v8::Handle<v8::FunctionTemplate> functionDescriptor = data->privateTemplateI
fExists(currentWorldType, privateTemplateUniqueKey); | 61 v8::Handle<v8::FunctionTemplate> functionDescriptor = data->privateTemplateI
fExists(currentWorldType, privateTemplateUniqueKey); |
59 if (!functionDescriptor.IsEmpty()) | 62 if (!functionDescriptor.IsEmpty()) |
60 return functionDescriptor->InstanceTemplate(); | 63 return functionDescriptor->InstanceTemplate(); |
61 | 64 |
62 functionDescriptor = v8::FunctionTemplate::New(); | 65 functionDescriptor = v8::FunctionTemplate::New(); |
63 v8::Local<v8::ObjectTemplate> instanceTemplate = functionDescriptor->Instanc
eTemplate(); | 66 v8::Local<v8::ObjectTemplate> instanceTemplate = functionDescriptor->Instanc
eTemplate(); |
64 instanceTemplate->SetInternalFieldCount(internalFieldCount); | 67 instanceTemplate->SetInternalFieldCount(internalFieldCount); |
65 data->setPrivateTemplate(currentWorldType, privateTemplateUniqueKey, functio
nDescriptor); | 68 data->setPrivateTemplate(currentWorldType, privateTemplateUniqueKey, functio
nDescriptor); |
66 return instanceTemplate; | 69 return instanceTemplate; |
67 } | 70 } |
68 | 71 |
69 v8::Local<v8::ObjectTemplate> wrapperCallbackEnvironmentObjectTemplate(v8::Isola
te* isolate) | |
70 { | |
71 // This is only for getting a unique pointer which we can pass to privateTem
plate. | |
72 static int privateTemplateUniqueKey = 0; | |
73 return cachedObjectTemplate(&privateTemplateUniqueKey, V8PromiseCustom::Wrap
perCallbackEnvironmentFieldCount, isolate); | |
74 } | |
75 | |
76 v8::Local<v8::ObjectTemplate> promiseAllEnvironmentObjectTemplate(v8::Isolate* i
solate) | 72 v8::Local<v8::ObjectTemplate> promiseAllEnvironmentObjectTemplate(v8::Isolate* i
solate) |
77 { | 73 { |
78 // This is only for getting a unique pointer which we can pass to privateTem
plate. | 74 // This is only for getting a unique pointer which we can pass to privateTem
plate. |
79 static int privateTemplateUniqueKey = 0; | 75 static int privateTemplateUniqueKey = 0; |
80 return cachedObjectTemplate(&privateTemplateUniqueKey, V8PromiseCustom::Prom
iseAllEnvironmentFieldCount, isolate); | 76 return cachedObjectTemplate(&privateTemplateUniqueKey, V8PromiseCustom::Prom
iseAllEnvironmentFieldCount, isolate); |
81 } | 77 } |
82 | 78 |
83 v8::Local<v8::ObjectTemplate> primitiveWrapperObjectTemplate(v8::Isolate* isolat
e) | 79 v8::Local<v8::ObjectTemplate> primitiveWrapperObjectTemplate(v8::Isolate* isolat
e) |
84 { | 80 { |
85 // This is only for getting a unique pointer which we can pass to privateTem
plate. | 81 // This is only for getting a unique pointer which we can pass to privateTem
plate. |
86 static int privateTemplateUniqueKey = 0; | 82 static int privateTemplateUniqueKey = 0; |
87 return cachedObjectTemplate(&privateTemplateUniqueKey, V8PromiseCustom::Prim
itiveWrapperFieldCount, isolate); | 83 return cachedObjectTemplate(&privateTemplateUniqueKey, V8PromiseCustom::Prim
itiveWrapperFieldCount, isolate); |
88 } | 84 } |
89 | 85 |
90 v8::Local<v8::ObjectTemplate> internalObjectTemplate(v8::Isolate* isolate) | 86 v8::Local<v8::ObjectTemplate> internalObjectTemplate(v8::Isolate* isolate) |
91 { | 87 { |
92 // This is only for getting a unique pointer which we can pass to privateTem
plate. | 88 // This is only for getting a unique pointer which we can pass to privateTem
plate. |
93 static int privateTemplateUniqueKey = 0; | 89 static int privateTemplateUniqueKey = 0; |
94 return cachedObjectTemplate(&privateTemplateUniqueKey, V8PromiseCustom::Inte
rnalFieldCount, isolate); | 90 return cachedObjectTemplate(&privateTemplateUniqueKey, V8PromiseCustom::Inte
rnalFieldCount, isolate); |
95 } | 91 } |
96 | 92 |
97 class PromiseTask : public ScriptExecutionContext::Task { | 93 void promiseResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& args) |
| 94 { |
| 95 ASSERT(!args.Data().IsEmpty()); |
| 96 v8::Local<v8::Object> promise = args.Data().As<v8::Object>(); |
| 97 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate()); |
| 98 if (args.Length() > 0) |
| 99 result = args[0]; |
| 100 |
| 101 V8PromiseCustom::resolve(promise, result, args.GetIsolate()); |
| 102 } |
| 103 |
| 104 void promiseRejectCallback(const v8::FunctionCallbackInfo<v8::Value>& args) |
| 105 { |
| 106 ASSERT(!args.Data().IsEmpty()); |
| 107 v8::Local<v8::Object> promise = args.Data().As<v8::Object>(); |
| 108 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate()); |
| 109 if (args.Length() > 0) |
| 110 result = args[0]; |
| 111 |
| 112 V8PromiseCustom::reject(promise, result, args.GetIsolate()); |
| 113 } |
| 114 |
| 115 void promiseAllFulfillCallback(const v8::FunctionCallbackInfo<v8::Value>& args) |
| 116 { |
| 117 v8::Isolate* isolate = args.GetIsolate(); |
| 118 ASSERT(!args.Data().IsEmpty()); |
| 119 v8::Local<v8::Object> environment = args.Data().As<v8::Object>(); |
| 120 v8::Local<v8::Value> result = v8::Undefined(isolate); |
| 121 if (args.Length() > 0) |
| 122 result = args[0]; |
| 123 |
| 124 v8::Local<v8::Object> promise = environment->GetInternalField(V8PromiseCusto
m::PromiseAllEnvironmentPromiseIndex).As<v8::Object>(); |
| 125 v8::Local<v8::Object> countdownWrapper = environment->GetInternalField(V8Pro
miseCustom::PromiseAllEnvironmentCountdownIndex).As<v8::Object>(); |
| 126 v8::Local<v8::Integer> index = environment->GetInternalField(V8PromiseCustom
::PromiseAllEnvironmentIndexIndex).As<v8::Integer>(); |
| 127 v8::Local<v8::Array> results = environment->GetInternalField(V8PromiseCustom
::PromiseAllEnvironmentResultsIndex).As<v8::Array>(); |
| 128 |
| 129 results->Set(index->Value(), result); |
| 130 |
| 131 v8::Local<v8::Integer> countdown = countdownWrapper->GetInternalField(V8Prom
iseCustom::PrimitiveWrapperPrimitiveIndex).As<v8::Integer>(); |
| 132 ASSERT(countdown->Value() >= 1); |
| 133 if (countdown->Value() == 1) { |
| 134 V8PromiseCustom::resolve(promise, results, isolate); |
| 135 return; |
| 136 } |
| 137 countdownWrapper->SetInternalField(V8PromiseCustom::PrimitiveWrapperPrimitiv
eIndex, v8::Integer::New(countdown->Value() - 1, isolate)); |
| 138 } |
| 139 |
| 140 v8::Local<v8::Object> promiseAllEnvironment(v8::Handle<v8::Object> promise, v8::
Handle<v8::Object> countdownWrapper, int index, v8::Handle<v8::Array> results, v
8::Isolate* isolate) |
| 141 { |
| 142 v8::Local<v8::ObjectTemplate> objectTemplate = promiseAllEnvironmentObjectTe
mplate(isolate); |
| 143 v8::Local<v8::Object> environment = objectTemplate->NewInstance(); |
| 144 |
| 145 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentPromiseI
ndex, promise); |
| 146 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentCountdow
nIndex, countdownWrapper); |
| 147 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentIndexInd
ex, v8::Integer::New(index, isolate)); |
| 148 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentResultsI
ndex, results); |
| 149 return environment; |
| 150 } |
| 151 |
| 152 // Clear |internal|'s derived array. |
| 153 void clearDerived(v8::Handle<v8::Object> internal) |
| 154 { |
| 155 internal->SetInternalField(V8PromiseCustom::InternalFulfillCallbackIndex, v8
::Array::New()); |
| 156 internal->SetInternalField(V8PromiseCustom::InternalRejectCallbackIndex, v8:
:Array::New()); |
| 157 internal->SetInternalField(V8PromiseCustom::InternalDerivedPromiseIndex, v8:
:Array::New()); |
| 158 } |
| 159 |
| 160 // Add a tuple (|derivedPromise|, |onFulfilled|, |onRejected|) to |
| 161 // |internal|'s derived array. |
| 162 // |internal| must be a Promise internal object. |
| 163 // |derivedPromise| must be a Promise instance. |
| 164 // |onFulfilled| and |onRejected| can be an empty value respectively. |
| 165 void addToDerived(v8::Handle<v8::Object> internal, v8::Handle<v8::Object> derive
dPromise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejec
ted, v8::Isolate* isolate) |
| 166 { |
| 167 v8::Local<v8::Array> fulfillCallbacks = internal->GetInternalField(V8Promise
Custom::InternalFulfillCallbackIndex).As<v8::Array>(); |
| 168 v8::Local<v8::Array> rejectCallbacks = internal->GetInternalField(V8PromiseC
ustom::InternalRejectCallbackIndex).As<v8::Array>(); |
| 169 v8::Local<v8::Array> derivedPromises = internal->GetInternalField(V8PromiseC
ustom::InternalDerivedPromiseIndex).As<v8::Array>(); |
| 170 |
| 171 if (onFulfilled.IsEmpty()) { |
| 172 fulfillCallbacks->Set(fulfillCallbacks->Length(), v8::Undefined(isolate)
); |
| 173 } else { |
| 174 fulfillCallbacks->Set(fulfillCallbacks->Length(), onFulfilled); |
| 175 } |
| 176 |
| 177 if (onRejected.IsEmpty()) { |
| 178 rejectCallbacks->Set(rejectCallbacks->Length(), v8::Undefined(isolate)); |
| 179 } else { |
| 180 rejectCallbacks->Set(rejectCallbacks->Length(), onRejected); |
| 181 } |
| 182 |
| 183 ASSERT(!derivedPromise.IsEmpty()); |
| 184 derivedPromises->Set(derivedPromises->Length(), derivedPromise); |
| 185 |
| 186 // Since they are treated as a tuple, |
| 187 // we need to guaranteed that the length of these arrays are same. |
| 188 ASSERT(fulfillCallbacks->Length() == rejectCallbacks->Length() && rejectCall
backs->Length() == derivedPromises->Length()); |
| 189 } |
| 190 |
| 191 class CallHandlerTask : public ScriptExecutionContext::Task { |
98 public: | 192 public: |
99 PromiseTask(v8::Handle<v8::Function> callback, v8::Handle<v8::Object> receiv
er, v8::Handle<v8::Value> result, v8::Isolate* isolate) | 193 CallHandlerTask(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> han
dler, v8::Handle<v8::Value> argument, v8::Isolate* isolate) |
100 : m_callback(isolate, callback) | 194 : m_promise(isolate, promise) |
101 , m_receiver(isolate, receiver) | 195 , m_handler(isolate, handler) |
102 , m_result(isolate, result) | 196 , m_argument(isolate, argument) |
103 { | 197 { |
104 ASSERT(!m_callback.isEmpty()); | 198 ASSERT(!m_promise.isEmpty()); |
105 ASSERT(!m_receiver.isEmpty()); | 199 ASSERT(!m_handler.isEmpty()); |
106 ASSERT(!m_result.isEmpty()); | 200 ASSERT(!m_argument.isEmpty()); |
107 } | 201 } |
108 virtual ~PromiseTask() { } | 202 virtual ~CallHandlerTask() { } |
109 | 203 |
110 virtual void performTask(ScriptExecutionContext*) OVERRIDE; | 204 virtual void performTask(ScriptExecutionContext*) OVERRIDE; |
111 | 205 |
112 private: | 206 private: |
113 ScopedPersistent<v8::Function> m_callback; | 207 ScopedPersistent<v8::Object> m_promise; |
114 ScopedPersistent<v8::Object> m_receiver; | 208 ScopedPersistent<v8::Function> m_handler; |
115 ScopedPersistent<v8::Value> m_result; | 209 ScopedPersistent<v8::Value> m_argument; |
116 }; | 210 }; |
117 | 211 |
118 void PromiseTask::performTask(ScriptExecutionContext* context) | 212 void CallHandlerTask::performTask(ScriptExecutionContext* context) |
119 { | 213 { |
120 ASSERT(context); | 214 ASSERT(context); |
121 if (context->activeDOMObjectsAreStopped()) | 215 if (context->activeDOMObjectsAreStopped()) |
122 return; | 216 return; |
123 | 217 |
124 ScriptState* state = 0; | 218 ScriptState* state = 0; |
125 if (context->isDocument()) { | 219 if (context->isDocument()) { |
126 state = mainWorldScriptState(static_cast<Document*>(context)->frame()); | 220 state = mainWorldScriptState(static_cast<Document*>(context)->frame()); |
127 } else { | 221 } else { |
128 ASSERT(context->isWorkerGlobalScope()); | 222 ASSERT(context->isWorkerGlobalScope()); |
129 state = scriptStateFromWorkerGlobalScope(toWorkerGlobalScope(context)); | 223 state = scriptStateFromWorkerGlobalScope(toWorkerGlobalScope(context)); |
130 } | 224 } |
131 ASSERT(state); | 225 ASSERT(state); |
132 | 226 |
133 v8::Isolate* isolate = state->isolate(); | 227 v8::Isolate* isolate = state->isolate(); |
134 v8::HandleScope handleScope(isolate); | 228 v8::HandleScope handleScope(isolate); |
135 v8::Handle<v8::Context> v8Context = state->context(); | 229 v8::Handle<v8::Context> v8Context = state->context(); |
136 v8::Context::Scope scope(v8Context); | 230 v8::Context::Scope scope(v8Context); |
137 v8::Handle<v8::Value> args[] = { m_result.newLocal(isolate) }; | 231 v8::Handle<v8::Value> args[] = { m_argument.newLocal(isolate) }; |
138 V8ScriptRunner::callFunction(m_callback.newLocal(isolate), context, m_receiv
er.newLocal(isolate), WTF_ARRAY_LENGTH(args), args, isolate); | 232 v8::TryCatch trycatch; |
| 233 v8::Local<v8::Value> value = V8ScriptRunner::callFunction(m_handler.newLocal
(isolate), context, v8::Undefined(isolate), WTF_ARRAY_LENGTH(args), args, isolat
e); |
| 234 if (value.IsEmpty()) { |
| 235 V8PromiseCustom::reject(m_promise.newLocal(isolate), trycatch.Exception(
), isolate); |
| 236 } else { |
| 237 V8PromiseCustom::resolve(m_promise.newLocal(isolate), value, isolate); |
| 238 } |
| 239 } |
| 240 |
| 241 class UpdateDerivedTask : public ScriptExecutionContext::Task { |
| 242 public: |
| 243 UpdateDerivedTask(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> o
nFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> originat
orValueObject, v8::Isolate* isolate) |
| 244 : m_promise(isolate, promise) |
| 245 , m_onFulfilled(isolate, onFulfilled) |
| 246 , m_onRejected(isolate, onRejected) |
| 247 , m_originatorValueObject(isolate, originatorValueObject) |
| 248 { |
| 249 ASSERT(!m_promise.isEmpty()); |
| 250 ASSERT(!m_originatorValueObject.isEmpty()); |
| 251 } |
| 252 virtual ~UpdateDerivedTask() { } |
| 253 |
| 254 virtual void performTask(ScriptExecutionContext*) OVERRIDE; |
| 255 |
| 256 private: |
| 257 ScopedPersistent<v8::Object> m_promise; |
| 258 ScopedPersistent<v8::Function> m_onFulfilled; |
| 259 ScopedPersistent<v8::Function> m_onRejected; |
| 260 ScopedPersistent<v8::Object> m_originatorValueObject; |
139 }; | 261 }; |
140 | 262 |
141 v8::Handle<v8::Value> postTask(v8::Handle<v8::Function> callback, v8::Handle<v8:
:Object> receiver, v8::Handle<v8::Value> value, v8::Isolate* isolate) | 263 void UpdateDerivedTask::performTask(ScriptExecutionContext* context) |
142 { | 264 { |
143 ScriptExecutionContext* scriptExecutionContext = getScriptExecutionContext()
; | 265 ASSERT(context); |
144 ASSERT(scriptExecutionContext && scriptExecutionContext->isContextThread()); | 266 if (context->activeDOMObjectsAreStopped()) |
145 scriptExecutionContext->postTask(adoptPtr(new PromiseTask(callback, receiver
, value, isolate))); | 267 return; |
146 return v8::Undefined(isolate); | 268 |
147 } | 269 ScriptState* state = 0; |
148 | 270 if (context->isDocument()) { |
149 void wrapperCallback(const v8::FunctionCallbackInfo<v8::Value>& args) | 271 state = mainWorldScriptState(static_cast<Document*>(context)->frame()); |
150 { | 272 } else { |
151 v8::Isolate* isolate = args.GetIsolate(); | 273 ASSERT(context->isWorkerGlobalScope()); |
152 ASSERT(!args.Data().IsEmpty()); | 274 state = scriptStateFromWorkerGlobalScope(toWorkerGlobalScope(context)); |
153 v8::Local<v8::Object> environment = args.Data().As<v8::Object>(); | 275 } |
154 v8::Local<v8::Value> result = v8::Undefined(isolate); | 276 ASSERT(state); |
155 if (args.Length() > 0) | 277 |
156 result = args[0]; | 278 v8::Isolate* isolate = state->isolate(); |
157 | 279 v8::HandleScope handleScope(isolate); |
158 v8::Local<v8::Object> promise = environment->GetInternalField(V8PromiseCusto
m::WrapperCallbackEnvironmentPromiseIndex).As<v8::Object>(); | 280 v8::Handle<v8::Context> v8Context = state->context(); |
159 v8::Local<v8::Function> callback = environment->GetInternalField(V8PromiseCu
stom::WrapperCallbackEnvironmentCallbackIndex).As<v8::Function>(); | 281 v8::Context::Scope scope(v8Context); |
160 | 282 |
161 v8::Local<v8::Value> argv[] = { | 283 v8::Local<v8::Object> originatorValueObject = m_originatorValueObject.newLoc
al(isolate); |
162 result, | 284 v8::Local<v8::Value> coercedAlready = originatorValueObject->GetHiddenValue(
V8HiddenPropertyName::thenableHiddenPromise(isolate)); |
| 285 if (!coercedAlready.IsEmpty() && coercedAlready->IsObject()) { |
| 286 ASSERT(V8PromiseCustom::isPromise(coercedAlready.As<v8::Object>(), isola
te)); |
| 287 V8PromiseCustom::updateDerivedFromPromise(m_promise.newLocal(isolate), m
_onFulfilled.newLocal(isolate), m_onRejected.newLocal(isolate), coercedAlready.A
s<v8::Object>(), isolate); |
| 288 return; |
| 289 } |
| 290 |
| 291 v8::Local<v8::Value> then; |
| 292 v8::TryCatch trycatch; |
| 293 then = originatorValueObject->Get(v8::String::NewSymbol("then")); |
| 294 if (then.IsEmpty()) { |
| 295 // If calling the [[Get]] internal method threw an exception, catch it a
nd run updateDerivedFromReason. |
| 296 V8PromiseCustom::updateDerivedFromReason(m_promise.newLocal(isolate), m_
onRejected.newLocal(isolate), trycatch.Exception(), isolate); |
| 297 return; |
| 298 } |
| 299 |
| 300 if (then->IsFunction()) { |
| 301 ASSERT(then->IsObject()); |
| 302 v8::Local<v8::Object> coerced = V8PromiseCustom::coerceThenable(originat
orValueObject, then.As<v8::Function>(), isolate); |
| 303 V8PromiseCustom::updateDerivedFromPromise(m_promise.newLocal(isolate), m
_onFulfilled.newLocal(isolate), m_onRejected.newLocal(isolate), coerced, isolate
); |
| 304 return; |
| 305 } |
| 306 |
| 307 V8PromiseCustom::updateDerivedFromValue(m_promise.newLocal(isolate), m_onFul
filled.newLocal(isolate), originatorValueObject, isolate); |
| 308 } |
| 309 |
| 310 // Since Promises state propagation routines are executed recursively, they caus
e |
| 311 // stack overflow. |
| 312 // (e.g. UpdateDerived -> UpdateDerivedFromValue -> SetValue -> |
| 313 // PropagateToDerived -> UpdateDerived) |
| 314 // |
| 315 // To fix that, we introduce PromisePropagator. It holds the stack. When |
| 316 // propagating the result to the derived tuples, we append the derived tuples |
| 317 // to the stack. After that, we drain the stack to propagate the result to |
| 318 // the stored tuples. |
| 319 // |
| 320 // PromisePropagator should be held on the stack and should not be held |
| 321 // as other object's member. PromisePropagator holds Derived tuples. Since |
| 322 // Derived tuples hold persistent handles to JS objects, retaining |
| 323 // PromisePropagator in the heap causes memory leaks. |
| 324 // |
| 325 class PromisePropagator { |
| 326 WTF_MAKE_NONCOPYABLE(PromisePropagator); |
| 327 public: |
| 328 PromisePropagator() { } |
| 329 |
| 330 void performPropagation(v8::Isolate*); |
| 331 |
| 332 void setValue(v8::Handle<v8::Object> promise, v8::Handle<v8::Value>, v8::Iso
late*); |
| 333 void setReason(v8::Handle<v8::Object> promise, v8::Handle<v8::Value>, v8::Is
olate*); |
| 334 void propagateToDerived(v8::Handle<v8::Object> promise, v8::Isolate*); |
| 335 void updateDerived(v8::Handle<v8::Object> derivedPromise, v8::Handle<v8::Fun
ction> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object>
originator, v8::Isolate*); |
| 336 void updateDerivedFromValue(v8::Handle<v8::Object> derivedPromise, v8::Handl
e<v8::Function> onFulfilled, v8::Handle<v8::Value>, v8::Isolate*); |
| 337 void updateDerivedFromReason(v8::Handle<v8::Object> derivedPromise, v8::Hand
le<v8::Function> onRejected, v8::Handle<v8::Value>, v8::Isolate*); |
| 338 void updateDerivedFromPromise(v8::Handle<v8::Object> derivedPromise, v8::Han
dle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<v
8::Object> promise, v8::Isolate*); |
| 339 |
| 340 private: |
| 341 class Derived { |
| 342 WTF_MAKE_NONCOPYABLE(Derived); |
| 343 public: |
| 344 Derived(v8::Handle<v8::Object> promise, v8::Handle<v8::Function> onFulfi
lled, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Object> originator, v8
::Isolate* isolate) |
| 345 : m_promise(isolate, promise) |
| 346 , m_onFulfilled(isolate, onFulfilled) |
| 347 , m_onRejected(isolate, onRejected) |
| 348 , m_originator(isolate, originator) |
| 349 { |
| 350 ASSERT(!m_promise.isEmpty()); |
| 351 ASSERT(!m_originator.isEmpty()); |
| 352 } |
| 353 |
| 354 static PassOwnPtr<Derived> create(v8::Handle<v8::Object> promise, v8::Ha
ndle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle<
v8::Object> originator, v8::Isolate* isolate) |
| 355 { |
| 356 return adoptPtr(new Derived(promise, onFulfilled, onRejected, origin
ator, isolate)); |
| 357 } |
| 358 |
| 359 v8::Local<v8::Object> promise(v8::Isolate* isolate) const { return m_pro
mise.newLocal(isolate); } |
| 360 v8::Local<v8::Function> onFulfilled(v8::Isolate* isolate) const { return
m_onFulfilled.newLocal(isolate); } |
| 361 v8::Local<v8::Function> onRejected(v8::Isolate* isolate) const { return
m_onRejected.newLocal(isolate); } |
| 362 v8::Local<v8::Object> originator(v8::Isolate* isolate) const { return m_
originator.newLocal(isolate); } |
| 363 |
| 364 private: |
| 365 ScopedPersistent<v8::Object> m_promise; |
| 366 ScopedPersistent<v8::Function> m_onFulfilled; |
| 367 ScopedPersistent<v8::Function> m_onRejected; |
| 368 ScopedPersistent<v8::Object> m_originator; |
163 }; | 369 }; |
164 v8::TryCatch trycatch; | 370 |
165 result = V8ScriptRunner::callFunction(callback, getScriptExecutionContext(),
promise, WTF_ARRAY_LENGTH(argv), argv, isolate); | 371 Deque<OwnPtr<Derived> > m_derivedStack; |
166 if (result.IsEmpty()) { | 372 }; |
167 V8PromiseCustom::reject(promise, trycatch.Exception(), V8PromiseCustom::
Synchronous, isolate); | 373 |
168 return; | 374 void PromisePropagator::performPropagation(v8::Isolate* isolate) |
169 } | 375 { |
170 V8PromiseCustom::resolve(promise, result, V8PromiseCustom::Synchronous, isol
ate); | 376 while (!m_derivedStack.isEmpty()) { |
171 } | 377 v8::HandleScope handleScope(isolate); |
172 | 378 OwnPtr<Derived> derived = m_derivedStack.takeLast(); |
173 v8::Local<v8::Object> wrapperCallbackEnvironment(v8::Handle<v8::Object> promise,
v8::Handle<v8::Function> callback, v8::Isolate* isolate) | 379 updateDerived(derived->promise(isolate), derived->onFulfilled(isolate),
derived->onRejected(isolate), derived->originator(isolate), isolate); |
174 { | 380 } |
175 v8::Local<v8::ObjectTemplate> objectTemplate = wrapperCallbackEnvironmentObj
ectTemplate(isolate); | 381 } |
176 v8::Local<v8::Object> environment = objectTemplate->NewInstance(); | 382 |
177 environment->SetInternalField(V8PromiseCustom::WrapperCallbackEnvironmentPro
miseIndex, promise); | 383 void PromisePropagator::setValue(v8::Handle<v8::Object> promise, v8::Handle<v8::
Value> value, v8::Isolate* isolate) |
178 environment->SetInternalField(V8PromiseCustom::WrapperCallbackEnvironmentCal
lbackIndex, callback); | 384 { |
179 return environment; | 385 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise); |
180 } | 386 ASSERT(V8PromiseCustom::getState(internal) != V8PromiseCustom::Fulfilled &&
V8PromiseCustom::getState(internal) != V8PromiseCustom::Rejected); |
181 | 387 V8PromiseCustom::setState(internal, V8PromiseCustom::Fulfilled, value, isola
te); |
182 void promiseFulfillCallback(const v8::FunctionCallbackInfo<v8::Value>& args) | 388 propagateToDerived(promise, isolate); |
183 { | 389 } |
184 ASSERT(!args.Data().IsEmpty()); | 390 |
185 v8::Local<v8::Object> promise = args.Data().As<v8::Object>(); | 391 void PromisePropagator::setReason(v8::Handle<v8::Object> promise, v8::Handle<v8:
:Value> reason, v8::Isolate* isolate) |
186 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate()); | 392 { |
187 if (args.Length() > 0) | 393 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise); |
188 result = args[0]; | 394 ASSERT(V8PromiseCustom::getState(internal) != V8PromiseCustom::Fulfilled &&
V8PromiseCustom::getState(internal) != V8PromiseCustom::Rejected); |
189 | 395 V8PromiseCustom::setState(internal, V8PromiseCustom::Rejected, reason, isola
te); |
190 V8PromiseCustom::fulfill(promise, result, V8PromiseCustom::Synchronous, args
.GetIsolate()); | 396 propagateToDerived(promise, isolate); |
191 } | 397 } |
192 | 398 |
193 void promiseResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& args) | 399 void PromisePropagator::propagateToDerived(v8::Handle<v8::Object> promise, v8::I
solate* isolate) |
194 { | 400 { |
195 ASSERT(!args.Data().IsEmpty()); | 401 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise); |
196 v8::Local<v8::Object> promise = args.Data().As<v8::Object>(); | 402 ASSERT(V8PromiseCustom::getState(internal) == V8PromiseCustom::Fulfilled ||
V8PromiseCustom::getState(internal) == V8PromiseCustom::Rejected); |
197 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate()); | 403 v8::Local<v8::Array> fulfillCallbacks = internal->GetInternalField(V8Promise
Custom::InternalFulfillCallbackIndex).As<v8::Array>(); |
198 if (args.Length() > 0) | 404 v8::Local<v8::Array> rejectCallbacks = internal->GetInternalField(V8PromiseC
ustom::InternalRejectCallbackIndex).As<v8::Array>(); |
199 result = args[0]; | 405 v8::Local<v8::Array> derivedPromises = internal->GetInternalField(V8PromiseC
ustom::InternalDerivedPromiseIndex).As<v8::Array>(); |
200 | 406 // Since they are treated as a tuple, |
201 V8PromiseCustom::resolve(promise, result, V8PromiseCustom::Synchronous, args
.GetIsolate()); | 407 // we need to guaranteed that the length of these arrays are same. |
202 } | 408 ASSERT(fulfillCallbacks->Length() == rejectCallbacks->Length() && rejectCall
backs->Length() == derivedPromises->Length()); |
203 | 409 |
204 void promiseRejectCallback(const v8::FunctionCallbackInfo<v8::Value>& args) | 410 // Append Derived tuple to the stack in reverse order. |
205 { | 411 for (uint32_t count = 0, length = derivedPromises->Length(); count < length;
++count) { |
206 ASSERT(!args.Data().IsEmpty()); | 412 uint32_t i = length - count - 1; |
207 v8::Local<v8::Object> promise = args.Data().As<v8::Object>(); | 413 v8::Local<v8::Object> derivedPromise = derivedPromises->Get(i).As<v8::Ob
ject>(); |
208 v8::Local<v8::Value> result = v8::Undefined(args.GetIsolate()); | 414 |
209 if (args.Length() > 0) | 415 v8::Local<v8::Function> onFulfilled, onRejected; |
210 result = args[0]; | 416 v8::Local<v8::Value> onFulfilledValue = fulfillCallbacks->Get(i); |
211 | 417 if (onFulfilledValue->IsFunction()) { |
212 V8PromiseCustom::reject(promise, result, V8PromiseCustom::Synchronous, args.
GetIsolate()); | 418 onFulfilled = onFulfilledValue.As<v8::Function>(); |
213 } | 419 } |
214 | 420 v8::Local<v8::Value> onRejectedValue = rejectCallbacks->Get(i); |
215 void callCallbacks(v8::Handle<v8::Array> callbacks, v8::Handle<v8::Value> result
, V8PromiseCustom::SynchronousMode mode, v8::Isolate* isolate) | 421 if (onRejectedValue->IsFunction()) { |
216 { | 422 onRejected = onRejectedValue.As<v8::Function>(); |
217 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global(); | 423 } |
218 for (uint32_t i = 0, length = callbacks->Length(); i < length; ++i) { | 424 |
219 v8::Local<v8::Value> value = callbacks->Get(i); | 425 m_derivedStack.append(Derived::create(derivedPromise, onFulfilled, onRej
ected, promise, isolate)); |
220 v8::Local<v8::Function> callback = value.As<v8::Function>(); | 426 } |
221 V8PromiseCustom::call(callback, global, result, mode, isolate); | 427 clearDerived(internal); |
222 } | 428 } |
223 } | 429 |
224 | 430 void PromisePropagator::updateDerivedFromValue(v8::Handle<v8::Object> derivedPro
mise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Value> value, v8::Iso
late* isolate) |
225 void promiseAllFulfillCallback(const v8::FunctionCallbackInfo<v8::Value>& args) | 431 { |
226 { | 432 if (!onFulfilled.IsEmpty()) { |
227 v8::Isolate* isolate = args.GetIsolate(); | 433 V8PromiseCustom::callHandler(derivedPromise, onFulfilled, value, isolate
); |
228 ASSERT(!args.Data().IsEmpty()); | 434 } else { |
229 v8::Local<v8::Object> environment = args.Data().As<v8::Object>(); | 435 setValue(derivedPromise, value, isolate); |
230 v8::Local<v8::Value> result = v8::Undefined(isolate); | 436 } |
231 if (args.Length() > 0) | 437 } |
232 result = args[0]; | 438 |
233 | 439 void PromisePropagator::updateDerivedFromReason(v8::Handle<v8::Object> derivedPr
omise, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Value> reason, v8::Is
olate* isolate) |
234 v8::Local<v8::Object> promise = environment->GetInternalField(V8PromiseCusto
m::PromiseAllEnvironmentPromiseIndex).As<v8::Object>(); | 440 { |
235 v8::Local<v8::Object> countdownWrapper = environment->GetInternalField(V8Pro
miseCustom::PromiseAllEnvironmentCountdownIndex).As<v8::Object>(); | 441 if (!onRejected.IsEmpty()) { |
236 v8::Local<v8::Integer> index = environment->GetInternalField(V8PromiseCustom
::PromiseAllEnvironmentIndexIndex).As<v8::Integer>(); | 442 V8PromiseCustom::callHandler(derivedPromise, onRejected, reason, isolate
); |
237 v8::Local<v8::Array> results = environment->GetInternalField(V8PromiseCustom
::PromiseAllEnvironmentResultsIndex).As<v8::Array>(); | 443 } else { |
238 | 444 setReason(derivedPromise, reason, isolate); |
239 results->Set(index->Value(), result); | 445 } |
240 | 446 } |
241 v8::Local<v8::Integer> countdown = countdownWrapper->GetInternalField(V8Prom
iseCustom::PrimitiveWrapperPrimitiveIndex).As<v8::Integer>(); | 447 |
242 ASSERT(countdown->Value() >= 1); | 448 void PromisePropagator::updateDerived(v8::Handle<v8::Object> derivedPromise, v8:
:Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Hand
le<v8::Object> originator, v8::Isolate* isolate) |
243 if (countdown->Value() == 1) { | 449 { |
244 V8PromiseCustom::resolve(promise, results, V8PromiseCustom::Synchronous,
isolate); | 450 v8::Local<v8::Object> originatorInternal = V8PromiseCustom::getInternal(orig
inator); |
245 return; | 451 V8PromiseCustom::PromiseState originatorState = V8PromiseCustom::getState(or
iginatorInternal); |
246 } | 452 ASSERT(originatorState == V8PromiseCustom::Fulfilled || originatorState == V
8PromiseCustom::Rejected); |
247 countdownWrapper->SetInternalField(V8PromiseCustom::PrimitiveWrapperPrimitiv
eIndex, v8::Integer::New(countdown->Value() - 1, isolate)); | 453 v8::Local<v8::Value> originatorValue = originatorInternal->GetInternalField(
V8PromiseCustom::InternalResultIndex); |
248 } | 454 if (originatorState == V8PromiseCustom::Fulfilled) { |
249 | 455 if (originatorValue->IsObject()) { |
250 v8::Local<v8::Object> promiseAllEnvironment(v8::Handle<v8::Object> promise, v8::
Handle<v8::Object> countdownWrapper, int index, v8::Handle<v8::Array> results, v
8::Isolate* isolate) | 456 ScriptExecutionContext* scriptExecutionContext = getScriptExecutionC
ontext(); |
251 { | 457 ASSERT(scriptExecutionContext && scriptExecutionContext->isContextTh
read()); |
252 v8::Local<v8::ObjectTemplate> objectTemplate = promiseAllEnvironmentObjectTe
mplate(isolate); | 458 scriptExecutionContext->postTask(adoptPtr(new UpdateDerivedTask(deri
vedPromise, onFulfilled, onRejected, originatorValue.As<v8::Object>(), isolate))
); |
253 v8::Local<v8::Object> environment = objectTemplate->NewInstance(); | 459 } else { |
254 | 460 updateDerivedFromValue(derivedPromise, onFulfilled, originatorValue,
isolate); |
255 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentPromiseI
ndex, promise); | 461 } |
256 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentCountdow
nIndex, countdownWrapper); | 462 } else { |
257 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentIndexInd
ex, v8::Integer::New(index, isolate)); | 463 updateDerivedFromReason(derivedPromise, onRejected, originatorValue, iso
late); |
258 environment->SetInternalField(V8PromiseCustom::PromiseAllEnvironmentResultsI
ndex, results); | 464 } |
259 return environment; | 465 } |
260 } | 466 |
261 | 467 void PromisePropagator::updateDerivedFromPromise(v8::Handle<v8::Object> derivedP
romise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejecte
d, v8::Handle<v8::Object> promise, v8::Isolate* isolate) |
262 void promiseResolve(const v8::FunctionCallbackInfo<v8::Value>& args) | 468 { |
263 { | 469 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise); |
264 v8::Local<v8::Object> promise = args.Data().As<v8::Object>(); | 470 V8PromiseCustom::PromiseState state = V8PromiseCustom::getState(internal); |
265 ASSERT(!promise.IsEmpty()); | 471 if (state == V8PromiseCustom::Fulfilled || state == V8PromiseCustom::Rejecte
d) { |
266 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise); | 472 updateDerived(derivedPromise, onFulfilled, onRejected, promise, isolate)
; |
267 if (V8PromiseCustom::getState(internal) != V8PromiseCustom::Pending) | 473 } else { |
268 return; | 474 addToDerived(internal, derivedPromise, onFulfilled, onRejected, isolate)
; |
269 v8::Isolate* isolate = args.GetIsolate(); | 475 } |
270 V8PromiseCustom::setState(V8PromiseCustom::getInternal(promise), V8PromiseCu
stom::Following, isolate); | |
271 | |
272 v8::Local<v8::Value> result = v8::Undefined(isolate); | |
273 if (args.Length() > 0) | |
274 result = args[0]; | |
275 V8PromiseCustom::resolve(promise, result, V8PromiseCustom::Asynchronous, iso
late); | |
276 } | |
277 | |
278 void promiseReject(const v8::FunctionCallbackInfo<v8::Value>& args) | |
279 { | |
280 v8::Local<v8::Object> promise = args.Data().As<v8::Object>(); | |
281 ASSERT(!promise.IsEmpty()); | |
282 v8::Local<v8::Object> internal = V8PromiseCustom::getInternal(promise); | |
283 if (V8PromiseCustom::getState(internal) != V8PromiseCustom::Pending) | |
284 return; | |
285 v8::Isolate* isolate = args.GetIsolate(); | |
286 V8PromiseCustom::setState(V8PromiseCustom::getInternal(promise), V8PromiseCu
stom::Following, isolate); | |
287 | |
288 v8::Local<v8::Value> result = v8::Undefined(isolate); | |
289 if (args.Length() > 0) | |
290 result = args[0]; | |
291 V8PromiseCustom::reject(promise, result, V8PromiseCustom::Asynchronous, isol
ate); | |
292 } | 476 } |
293 | 477 |
294 } // namespace | 478 } // namespace |
295 | 479 |
296 void V8Promise::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& arg
s) | 480 void V8Promise::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& arg
s) |
297 { | 481 { |
298 v8SetReturnValue(args, v8::Local<v8::Value>()); | 482 v8SetReturnValue(args, v8::Local<v8::Value>()); |
299 v8::Isolate* isolate = args.GetIsolate(); | 483 v8::Isolate* isolate = args.GetIsolate(); |
300 if (!args.Length() || !args[0]->IsFunction()) { | 484 if (!args.Length() || !args[0]->IsFunction()) { |
301 throwTypeError("Promise constructor takes a function argument", isolate)
; | 485 throwTypeError("Promise constructor takes a function argument", isolate)
; |
302 return; | 486 return; |
303 } | 487 } |
304 v8::Local<v8::Function> init = args[0].As<v8::Function>(); | 488 v8::Local<v8::Function> init = args[0].As<v8::Function>(); |
305 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(args.Holder()
, isolate); | 489 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(args.Holder()
, isolate); |
306 v8::Handle<v8::Value> argv[] = { | 490 v8::Handle<v8::Value> argv[] = { |
307 createClosure(promiseResolve, promise, isolate), | 491 createClosure(promiseResolveCallback, promise, isolate), |
308 createClosure(promiseReject, promise, isolate) | 492 createClosure(promiseRejectCallback, promise, isolate) |
309 }; | 493 }; |
310 v8::TryCatch trycatch; | 494 v8::TryCatch trycatch; |
311 if (V8ScriptRunner::callFunction(init, getScriptExecutionContext(), promise,
WTF_ARRAY_LENGTH(argv), argv, isolate).IsEmpty()) { | 495 if (V8ScriptRunner::callFunction(init, getScriptExecutionContext(), v8::Unde
fined(isolate), WTF_ARRAY_LENGTH(argv), argv, isolate).IsEmpty()) { |
312 // An exception is thrown. Reject the promise if its resolved flag is un
set. | 496 // An exception is thrown. Reject the promise if its resolved flag is un
set. |
313 if (V8PromiseCustom::getState(V8PromiseCustom::getInternal(promise)) ==
V8PromiseCustom::Pending) | 497 V8PromiseCustom::reject(promise, trycatch.Exception(), isolate); |
314 V8PromiseCustom::reject(promise, trycatch.Exception(), V8PromiseCust
om::Asynchronous, isolate); | |
315 } | 498 } |
316 v8SetReturnValue(args, promise); | 499 v8SetReturnValue(args, promise); |
317 return; | 500 return; |
318 } | 501 } |
319 | 502 |
320 void V8Promise::thenMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args
) | 503 void V8Promise::thenMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args
) |
321 { | 504 { |
322 v8::Isolate* isolate = args.GetIsolate(); | 505 v8::Isolate* isolate = args.GetIsolate(); |
323 v8::Local<v8::Function> fulfillWrapper, rejectWrapper; | 506 v8::Local<v8::Function> onFulfilled, onRejected; |
324 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(args.Holder()
, isolate); | 507 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(args.Holder()
, isolate); |
325 if (args.Length() > 0 && !args[0]->IsUndefined()) { | 508 if (args.Length() > 0 && !args[0]->IsUndefined()) { |
326 if (!args[0]->IsFunction()) { | 509 if (!args[0]->IsFunction()) { |
327 v8SetReturnValue(args, throwTypeError("fulfillCallback must be a fun
ction or undefined", isolate)); | 510 v8SetReturnValue(args, throwTypeError("onFulfilled must be a functio
n or undefined", isolate)); |
328 return; | 511 return; |
329 } | 512 } |
330 fulfillWrapper = createClosure(wrapperCallback, wrapperCallbackEnvironme
nt(promise, args[0].As<v8::Function>(), isolate), isolate); | 513 onFulfilled = args[0].As<v8::Function>(); |
331 } else { | |
332 fulfillWrapper = createClosure(promiseFulfillCallback, promise, isolate)
; | |
333 } | 514 } |
334 if (args.Length() > 1 && !args[1]->IsUndefined()) { | 515 if (args.Length() > 1 && !args[1]->IsUndefined()) { |
335 if (!args[1]->IsFunction()) { | 516 if (!args[1]->IsFunction()) { |
336 v8SetReturnValue(args, throwTypeError("rejectCallback must be a func
tion or undefined", isolate)); | 517 v8SetReturnValue(args, throwTypeError("onRejected must be a function
or undefined", isolate)); |
337 return; | 518 return; |
338 } | 519 } |
339 rejectWrapper = createClosure(wrapperCallback, wrapperCallbackEnvironmen
t(promise, args[1].As<v8::Function>(), isolate), isolate); | 520 onRejected = args[1].As<v8::Function>(); |
340 } else { | |
341 rejectWrapper = createClosure(promiseRejectCallback, promise, isolate); | |
342 } | 521 } |
343 V8PromiseCustom::append(args.Holder(), fulfillWrapper, rejectWrapper, isolat
e); | 522 v8SetReturnValue(args, V8PromiseCustom::then(args.Holder(), onFulfilled, onR
ejected, isolate)); |
344 v8SetReturnValue(args, promise); | |
345 } | 523 } |
346 | 524 |
347 void V8Promise::castMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args
) | 525 void V8Promise::castMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args
) |
348 { | 526 { |
349 v8::Isolate* isolate = args.GetIsolate(); | 527 v8::Isolate* isolate = args.GetIsolate(); |
350 v8::Local<v8::Value> result = v8::Undefined(isolate); | 528 v8::Local<v8::Value> result = v8::Undefined(isolate); |
351 if (args.Length() > 0) | 529 if (args.Length() > 0) |
352 result = args[0]; | 530 result = args[0]; |
353 | 531 |
354 v8SetReturnValue(args, V8PromiseCustom::toPromise(result, isolate)); | 532 v8SetReturnValue(args, V8PromiseCustom::toPromise(result, isolate)); |
355 } | 533 } |
356 | 534 |
357 void V8Promise::catchMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& arg
s) | 535 void V8Promise::catchMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& arg
s) |
358 { | 536 { |
359 v8::Isolate* isolate = args.GetIsolate(); | 537 v8::Isolate* isolate = args.GetIsolate(); |
360 v8::Local<v8::Function> fulfillWrapper, rejectWrapper; | 538 v8::Local<v8::Function> onFulfilled, onRejected; |
361 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(args.Holder()
, isolate); | |
362 | 539 |
363 if (args.Length() > 0 && !args[0]->IsUndefined()) { | 540 if (args.Length() > 0 && !args[0]->IsUndefined()) { |
364 if (!args[0]->IsFunction()) { | 541 if (!args[0]->IsFunction()) { |
365 v8SetReturnValue(args, throwTypeError("rejectCallback must be a func
tion or undefined", isolate)); | 542 v8SetReturnValue(args, throwTypeError("onRejected must be a function
or undefined", isolate)); |
366 return; | 543 return; |
367 } | 544 } |
368 rejectWrapper = createClosure(wrapperCallback, wrapperCallbackEnvironmen
t(promise, args[0].As<v8::Function>(), isolate), isolate); | 545 onRejected = args[0].As<v8::Function>(); |
369 } else { | |
370 rejectWrapper = createClosure(promiseRejectCallback, promise, isolate); | |
371 } | 546 } |
372 fulfillWrapper = createClosure(promiseFulfillCallback, promise, isolate); | 547 v8SetReturnValue(args, V8PromiseCustom::then(args.Holder(), onFulfilled, onR
ejected, isolate)); |
373 V8PromiseCustom::append(args.Holder(), fulfillWrapper, rejectWrapper, isolat
e); | |
374 v8SetReturnValue(args, promise); | |
375 } | 548 } |
376 | 549 |
377 void V8Promise::resolveMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& a
rgs) | 550 void V8Promise::resolveMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& a
rgs) |
378 { | 551 { |
379 v8::Isolate* isolate = args.GetIsolate(); | 552 v8::Isolate* isolate = args.GetIsolate(); |
380 v8::Local<v8::Value> result = v8::Undefined(isolate); | 553 v8::Local<v8::Value> result = v8::Undefined(isolate); |
381 if (args.Length() > 0) | 554 if (args.Length() > 0) |
382 result = args[0]; | 555 result = args[0]; |
383 | 556 |
384 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(args.Holder()
, isolate); | 557 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(args.Holder()
, isolate); |
385 V8PromiseCustom::resolve(promise, result, V8PromiseCustom::Asynchronous, iso
late); | 558 V8PromiseCustom::resolve(promise, result, isolate); |
386 v8SetReturnValue(args, promise); | 559 v8SetReturnValue(args, promise); |
387 } | 560 } |
388 | 561 |
389 void V8Promise::rejectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& ar
gs) | 562 void V8Promise::rejectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& ar
gs) |
390 { | 563 { |
391 v8::Isolate* isolate = args.GetIsolate(); | 564 v8::Isolate* isolate = args.GetIsolate(); |
392 v8::Local<v8::Value> result = v8::Undefined(isolate); | 565 v8::Local<v8::Value> result = v8::Undefined(isolate); |
393 if (args.Length() > 0) | 566 if (args.Length() > 0) |
394 result = args[0]; | 567 result = args[0]; |
395 | 568 |
396 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(args.Holder()
, isolate); | 569 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(args.Holder()
, isolate); |
397 V8PromiseCustom::reject(promise, result, V8PromiseCustom::Asynchronous, isol
ate); | 570 V8PromiseCustom::reject(promise, result, isolate); |
398 v8SetReturnValue(args, promise); | 571 v8SetReturnValue(args, promise); |
399 } | 572 } |
400 | 573 |
401 void V8Promise::raceMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args
) | 574 void V8Promise::raceMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args
) |
402 { | 575 { |
403 v8::Isolate* isolate = args.GetIsolate(); | 576 v8::Isolate* isolate = args.GetIsolate(); |
404 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(args.Holder()
, isolate); | 577 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(args.Holder()
, isolate); |
405 | 578 |
406 if (!args.Length() || !args[0]->IsArray()) { | 579 if (!args.Length() || !args[0]->IsArray()) { |
407 v8SetReturnValue(args, promise); | 580 v8SetReturnValue(args, promise); |
408 return; | 581 return; |
409 } | 582 } |
410 | 583 |
411 // FIXME: Now we limit the iterable type to the Array type. | 584 // FIXME: Now we limit the iterable type to the Array type. |
412 v8::Local<v8::Array> iterable = args[0].As<v8::Array>(); | 585 v8::Local<v8::Array> iterable = args[0].As<v8::Array>(); |
413 v8::Local<v8::Function> fulfillCallback = createClosure(promiseResolveCallba
ck, promise, isolate); | 586 v8::Local<v8::Function> onFulfilled = createClosure(promiseResolveCallback,
promise, isolate); |
414 v8::Local<v8::Function> rejectCallback = createClosure(promiseRejectCallback
, promise, isolate); | 587 v8::Local<v8::Function> onRejected = createClosure(promiseRejectCallback, pr
omise, isolate); |
415 | 588 |
416 for (unsigned i = 0, length = iterable->Length(); i < length; ++i) { | 589 for (unsigned i = 0, length = iterable->Length(); i < length; ++i) { |
417 // Array-holes should not be skipped by for-of iteration semantics. | 590 // Array-holes should not be skipped by for-of iteration semantics. |
418 V8TRYCATCH_VOID(v8::Local<v8::Value>, nextValue, iterable->Get(i)); | 591 V8TRYCATCH_VOID(v8::Local<v8::Value>, nextValue, iterable->Get(i)); |
419 v8::Local<v8::Object> nextPromise = V8PromiseCustom::toPromise(nextValue
, isolate); | 592 v8::Local<v8::Object> nextPromise = V8PromiseCustom::toPromise(nextValue
, isolate); |
420 V8PromiseCustom::append(nextPromise, fulfillCallback, rejectCallback, is
olate); | 593 V8PromiseCustom::then(nextPromise, onFulfilled, onRejected, isolate); |
421 } | 594 } |
422 v8SetReturnValue(args, promise); | 595 v8SetReturnValue(args, promise); |
423 } | 596 } |
424 | 597 |
425 void V8Promise::allMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) | 598 void V8Promise::allMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args) |
426 { | 599 { |
427 v8::Isolate* isolate = args.GetIsolate(); | 600 v8::Isolate* isolate = args.GetIsolate(); |
428 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(args.Holder()
, isolate); | 601 v8::Local<v8::Object> promise = V8PromiseCustom::createPromise(args.Holder()
, isolate); |
429 v8::Local<v8::Array> results = v8::Array::New(); | 602 v8::Local<v8::Array> results = v8::Array::New(); |
430 | 603 |
431 if (!args.Length() || !args[0]->IsArray()) { | 604 if (!args.Length() || !args[0]->IsArray()) { |
432 V8PromiseCustom::resolve(promise, results, V8PromiseCustom::Asynchronous
, isolate); | 605 V8PromiseCustom::resolve(promise, results, isolate); |
433 v8SetReturnValue(args, promise); | 606 v8SetReturnValue(args, promise); |
434 return; | 607 return; |
435 } | 608 } |
436 | 609 |
437 // FIXME: Now we limit the iterable type to the Array type. | 610 // FIXME: Now we limit the iterable type to the Array type. |
438 v8::Local<v8::Array> iterable = args[0].As<v8::Array>(); | 611 v8::Local<v8::Array> iterable = args[0].As<v8::Array>(); |
439 | 612 |
440 if (!iterable->Length()) { | 613 if (!iterable->Length()) { |
441 V8PromiseCustom::resolve(promise, results, V8PromiseCustom::Asynchronous
, isolate); | 614 V8PromiseCustom::resolve(promise, results, isolate); |
442 v8SetReturnValue(args, promise); | 615 v8SetReturnValue(args, promise); |
443 return; | 616 return; |
444 } | 617 } |
445 | 618 |
446 v8::Local<v8::ObjectTemplate> objectTemplate = primitiveWrapperObjectTemplat
e(isolate); | 619 v8::Local<v8::ObjectTemplate> objectTemplate = primitiveWrapperObjectTemplat
e(isolate); |
447 v8::Local<v8::Object> countdownWrapper = objectTemplate->NewInstance(); | 620 v8::Local<v8::Object> countdownWrapper = objectTemplate->NewInstance(); |
448 countdownWrapper->SetInternalField(V8PromiseCustom::PrimitiveWrapperPrimitiv
eIndex, v8::Integer::New(iterable->Length(), isolate)); | 621 countdownWrapper->SetInternalField(V8PromiseCustom::PrimitiveWrapperPrimitiv
eIndex, v8::Integer::New(iterable->Length(), isolate)); |
449 | 622 |
450 v8::Local<v8::Function> rejectCallback = createClosure(promiseRejectCallback
, promise, isolate); | 623 v8::Local<v8::Function> onRejected = createClosure(promiseRejectCallback, pr
omise, isolate); |
451 for (unsigned i = 0, length = iterable->Length(); i < length; ++i) { | 624 for (unsigned i = 0, length = iterable->Length(); i < length; ++i) { |
452 // Array-holes should not be skipped by for-of iteration semantics. | 625 // Array-holes should not be skipped by for-of iteration semantics. |
453 v8::Local<v8::Object> environment = promiseAllEnvironment(promise, count
downWrapper, i, results, isolate); | 626 v8::Local<v8::Object> environment = promiseAllEnvironment(promise, count
downWrapper, i, results, isolate); |
454 v8::Local<v8::Function> fulfillCallback = createClosure(promiseAllFulfil
lCallback, environment, isolate); | 627 v8::Local<v8::Function> onFulfilled = createClosure(promiseAllFulfillCal
lback, environment, isolate); |
455 V8TRYCATCH_VOID(v8::Local<v8::Value>, nextValue, iterable->Get(i)); | 628 V8TRYCATCH_VOID(v8::Local<v8::Value>, nextValue, iterable->Get(i)); |
456 v8::Local<v8::Object> nextPromise = V8PromiseCustom::toPromise(nextValue
, isolate); | 629 v8::Local<v8::Object> nextPromise = V8PromiseCustom::toPromise(nextValue
, isolate); |
457 V8PromiseCustom::append(nextPromise, fulfillCallback, rejectCallback, is
olate); | 630 V8PromiseCustom::then(nextPromise, onFulfilled, onRejected, isolate); |
458 } | 631 } |
459 v8SetReturnValue(args, promise); | 632 v8SetReturnValue(args, promise); |
460 } | 633 } |
461 | 634 |
462 // | 635 // |
463 // -- V8PromiseCustom -- | 636 // -- V8PromiseCustom -- |
464 v8::Local<v8::Object> V8PromiseCustom::createPromise(v8::Handle<v8::Object> crea
tionContext, v8::Isolate* isolate) | 637 v8::Local<v8::Object> V8PromiseCustom::createPromise(v8::Handle<v8::Object> crea
tionContext, v8::Isolate* isolate) |
465 { | 638 { |
466 v8::Local<v8::ObjectTemplate> internalTemplate = internalObjectTemplate(isol
ate); | 639 v8::Local<v8::ObjectTemplate> internalTemplate = internalObjectTemplate(isol
ate); |
467 v8::Local<v8::Object> internal = internalTemplate->NewInstance(); | 640 v8::Local<v8::Object> internal = internalTemplate->NewInstance(); |
468 v8::Local<v8::Object> promise = V8DOMWrapper::createWrapper(creationContext,
&V8Promise::info, 0, isolate); | 641 v8::Local<v8::Object> promise = V8DOMWrapper::createWrapper(creationContext,
&V8Promise::info, 0, isolate); |
469 | 642 |
470 clearInternal(internal, V8PromiseCustom::Pending, v8::Undefined(isolate), is
olate); | 643 clearDerived(internal); |
| 644 setState(internal, Pending, v8::Undefined(isolate), isolate); |
471 | 645 |
472 promise->SetInternalField(v8DOMWrapperObjectIndex, internal); | 646 promise->SetInternalField(v8DOMWrapperObjectIndex, internal); |
473 return promise; | 647 return promise; |
474 } | 648 } |
475 | 649 |
476 void V8PromiseCustom::fulfill(v8::Handle<v8::Object> promise, v8::Handle<v8::Val
ue> result, SynchronousMode mode, v8::Isolate* isolate) | |
477 { | |
478 v8::Local<v8::Object> internal = getInternal(promise); | |
479 PromiseState state = getState(internal); | |
480 if (state == Fulfilled || state == Rejected) | |
481 return; | |
482 | |
483 ASSERT(state == Pending || state == Following); | |
484 v8::Local<v8::Array> callbacks = internal->GetInternalField(V8PromiseCustom:
:InternalFulfillCallbackIndex).As<v8::Array>(); | |
485 clearInternal(internal, Fulfilled, result, isolate); | |
486 | |
487 callCallbacks(callbacks, result, mode, isolate); | |
488 } | |
489 | |
490 void V8PromiseCustom::resolve(v8::Handle<v8::Object> promise, v8::Handle<v8::Val
ue> result, SynchronousMode mode, v8::Isolate* isolate) | |
491 { | |
492 ASSERT(!result.IsEmpty()); | |
493 | |
494 v8::Local<v8::Value> then; | |
495 if (result->IsObject()) { | |
496 v8::TryCatch trycatch; | |
497 then = result.As<v8::Object>()->Get(v8::String::NewSymbol("then")); | |
498 if (then.IsEmpty()) { | |
499 // If calling the [[Get]] internal method threw an exception, catch
it and run reject. | |
500 reject(promise, trycatch.Exception(), mode, isolate); | |
501 return; | |
502 } | |
503 } | |
504 | |
505 if (!then.IsEmpty() && then->IsFunction()) { | |
506 ASSERT(result->IsObject()); | |
507 v8::TryCatch trycatch; | |
508 v8::Handle<v8::Value> argv[] = { | |
509 createClosure(promiseResolveCallback, promise, isolate), | |
510 createClosure(promiseRejectCallback, promise, isolate), | |
511 }; | |
512 if (V8ScriptRunner::callFunction(then.As<v8::Function>(), getScriptExecu
tionContext(), result.As<v8::Object>(), WTF_ARRAY_LENGTH(argv), argv, isolate).I
sEmpty()) | |
513 reject(promise, trycatch.Exception(), mode, isolate); | |
514 return; | |
515 } | |
516 | |
517 fulfill(promise, result, mode, isolate); | |
518 } | |
519 | |
520 void V8PromiseCustom::reject(v8::Handle<v8::Object> promise, v8::Handle<v8::Valu
e> result, SynchronousMode mode, v8::Isolate* isolate) | |
521 { | |
522 v8::Local<v8::Object> internal = getInternal(promise); | |
523 PromiseState state = getState(internal); | |
524 if (state == Fulfilled || state == Rejected) | |
525 return; | |
526 | |
527 ASSERT(state == Pending || state == Following); | |
528 v8::Local<v8::Array> callbacks = internal->GetInternalField(V8PromiseCustom:
:InternalRejectCallbackIndex).As<v8::Array>(); | |
529 clearInternal(internal, Rejected, result, isolate); | |
530 | |
531 callCallbacks(callbacks, result, mode, isolate); | |
532 } | |
533 | |
534 void V8PromiseCustom::append(v8::Handle<v8::Object> promise, v8::Handle<v8::Func
tion> fulfillCallback, v8::Handle<v8::Function> rejectCallback, v8::Isolate* iso
late) | |
535 { | |
536 // fulfillCallback and rejectCallback can be empty. | |
537 v8::Local<v8::Object> internal = getInternal(promise); | |
538 | |
539 PromiseState state = getState(internal); | |
540 if (state == Fulfilled) { | |
541 if (!fulfillCallback.IsEmpty()) { | |
542 v8::Local<v8::Value> result = internal->GetInternalField(V8PromiseCu
stom::InternalResultIndex); | |
543 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global(
); | |
544 call(fulfillCallback, global, result, Asynchronous, isolate); | |
545 } | |
546 return; | |
547 } | |
548 if (state == Rejected) { | |
549 if (!rejectCallback.IsEmpty()) { | |
550 v8::Local<v8::Value> result = internal->GetInternalField(V8PromiseCu
stom::InternalResultIndex); | |
551 v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global(
); | |
552 call(rejectCallback, global, result, Asynchronous, isolate); | |
553 } | |
554 return; | |
555 } | |
556 | |
557 ASSERT(state == Pending || state == Following); | |
558 if (!fulfillCallback.IsEmpty()) { | |
559 v8::Local<v8::Array> callbacks = internal->GetInternalField(InternalFulf
illCallbackIndex).As<v8::Array>(); | |
560 callbacks->Set(callbacks->Length(), fulfillCallback); | |
561 } | |
562 if (!rejectCallback.IsEmpty()) { | |
563 v8::Local<v8::Array> callbacks = internal->GetInternalField(InternalReje
ctCallbackIndex).As<v8::Array>(); | |
564 callbacks->Set(callbacks->Length(), rejectCallback); | |
565 } | |
566 } | |
567 | |
568 v8::Local<v8::Object> V8PromiseCustom::getInternal(v8::Handle<v8::Object> promis
e) | 650 v8::Local<v8::Object> V8PromiseCustom::getInternal(v8::Handle<v8::Object> promis
e) |
569 { | 651 { |
570 v8::Local<v8::Value> value = promise->GetInternalField(v8DOMWrapperObjectInd
ex); | 652 v8::Local<v8::Value> value = promise->GetInternalField(v8DOMWrapperObjectInd
ex); |
571 return value.As<v8::Object>(); | 653 return value.As<v8::Object>(); |
572 } | 654 } |
573 | 655 |
574 void V8PromiseCustom::clearInternal(v8::Handle<v8::Object> internal, PromiseStat
e state, v8::Handle<v8::Value> value, v8::Isolate* isolate) | |
575 { | |
576 setState(internal, state, isolate); | |
577 internal->SetInternalField(V8PromiseCustom::InternalResultIndex, value); | |
578 internal->SetInternalField(V8PromiseCustom::InternalFulfillCallbackIndex, v8
::Array::New()); | |
579 internal->SetInternalField(V8PromiseCustom::InternalRejectCallbackIndex, v8:
:Array::New()); | |
580 } | |
581 | |
582 V8PromiseCustom::PromiseState V8PromiseCustom::getState(v8::Handle<v8::Object> i
nternal) | 656 V8PromiseCustom::PromiseState V8PromiseCustom::getState(v8::Handle<v8::Object> i
nternal) |
583 { | 657 { |
584 v8::Handle<v8::Value> value = internal->GetInternalField(V8PromiseCustom::In
ternalStateIndex); | 658 v8::Handle<v8::Value> value = internal->GetInternalField(V8PromiseCustom::In
ternalStateIndex); |
585 bool ok = false; | 659 bool ok = false; |
586 uint32_t number = toInt32(value, ok); | 660 uint32_t number = toInt32(value, ok); |
587 ASSERT(ok && (number == Pending || number == Fulfilled || number == Rejected
|| number == Following)); | 661 ASSERT(ok && (number == Pending || number == Fulfilled || number == Rejected
|| number == Following)); |
588 return static_cast<PromiseState>(number); | 662 return static_cast<PromiseState>(number); |
589 } | 663 } |
590 | 664 |
591 void V8PromiseCustom::setState(v8::Handle<v8::Object> internal, PromiseState sta
te, v8::Isolate* isolate) | 665 void V8PromiseCustom::setState(v8::Handle<v8::Object> internal, PromiseState sta
te, v8::Handle<v8::Value> value, v8::Isolate* isolate) |
592 { | 666 { |
| 667 ASSERT(!value.IsEmpty()); |
593 ASSERT(state == Pending || state == Fulfilled || state == Rejected || state
== Following); | 668 ASSERT(state == Pending || state == Fulfilled || state == Rejected || state
== Following); |
594 internal->SetInternalField(V8PromiseCustom::InternalStateIndex, v8::Integer:
:New(state, isolate)); | 669 internal->SetInternalField(InternalStateIndex, v8::Integer::New(state, isola
te)); |
595 } | 670 internal->SetInternalField(InternalResultIndex, value); |
596 | |
597 void V8PromiseCustom::call(v8::Handle<v8::Function> function, v8::Handle<v8::Obj
ect> receiver, v8::Handle<v8::Value> result, SynchronousMode mode, v8::Isolate*
isolate) | |
598 { | |
599 if (mode == Synchronous) { | |
600 v8::Context::Scope scope(isolate->GetCurrentContext()); | |
601 // If an exception is thrown, catch it and do nothing. | |
602 v8::TryCatch trycatch; | |
603 v8::Handle<v8::Value> args[] = { result }; | |
604 V8ScriptRunner::callFunction(function, getScriptExecutionContext(), rece
iver, WTF_ARRAY_LENGTH(args), args, isolate); | |
605 } else { | |
606 ASSERT(mode == Asynchronous); | |
607 postTask(function, receiver, result, isolate); | |
608 } | |
609 } | 671 } |
610 | 672 |
611 bool V8PromiseCustom::isPromise(v8::Handle<v8::Value> maybePromise, v8::Isolate*
isolate) | 673 bool V8PromiseCustom::isPromise(v8::Handle<v8::Value> maybePromise, v8::Isolate*
isolate) |
612 { | 674 { |
613 WrapperWorldType currentWorldType = worldType(isolate); | 675 WrapperWorldType currentWorldType = worldType(isolate); |
614 return V8Promise::GetTemplate(isolate, currentWorldType)->HasInstance(maybeP
romise); | 676 return V8Promise::GetTemplate(isolate, currentWorldType)->HasInstance(maybeP
romise); |
615 } | 677 } |
616 | 678 |
617 v8::Local<v8::Object> V8PromiseCustom::toPromise(v8::Handle<v8::Value> maybeProm
ise, v8::Isolate* isolate) | 679 v8::Local<v8::Object> V8PromiseCustom::toPromise(v8::Handle<v8::Value> maybeProm
ise, v8::Isolate* isolate) |
618 { | 680 { |
619 // FIXME: Currently we dones't check [[PromiseConstructor]] since we limits | 681 // FIXME: Currently we don't check [[PromiseConstructor]] since we limit |
620 // the creation of the promise objects only from the Blink Promise | 682 // the creation of the promise objects only from the Blink Promise |
621 // constructor. | 683 // constructor. |
622 if (isPromise(maybePromise, isolate)) | 684 if (isPromise(maybePromise, isolate)) |
623 return maybePromise.As<v8::Object>(); | 685 return maybePromise.As<v8::Object>(); |
624 | 686 |
625 v8::Local<v8::Object> promise = createPromise(v8::Handle<v8::Object>(), isol
ate); | 687 v8::Local<v8::Object> promise = createPromise(v8::Handle<v8::Object>(), isol
ate); |
626 resolve(promise, maybePromise, Asynchronous, isolate); | 688 resolve(promise, maybePromise, isolate); |
627 return promise; | 689 return promise; |
628 } | 690 } |
629 | 691 |
| 692 void V8PromiseCustom::resolve(v8::Handle<v8::Object> promise, v8::Handle<v8::Val
ue> result, v8::Isolate* isolate) |
| 693 { |
| 694 ASSERT(!result.IsEmpty()); |
| 695 v8::Local<v8::Object> internal = getInternal(promise); |
| 696 PromiseState state = getState(internal); |
| 697 if (state != Pending) |
| 698 return; |
| 699 |
| 700 if (isPromise(result, isolate)) { |
| 701 v8::Local<v8::Object> valuePromise = result.As<v8::Object>(); |
| 702 v8::Local<v8::Object> valueInternal = getInternal(valuePromise); |
| 703 PromiseState valueState = getState(valueInternal); |
| 704 if (promise->SameValue(valuePromise)) { |
| 705 v8::Local<v8::Value> reason = V8ThrowException::createTypeError("Res
olve a promise with itself", isolate); |
| 706 setReason(promise, reason, isolate); |
| 707 } else if (valueState == Following) { |
| 708 v8::Local<v8::Object> valuePromiseFollowing = valueInternal->GetInte
rnalField(InternalResultIndex).As<v8::Object>(); |
| 709 setState(internal, Following, valuePromiseFollowing, isolate); |
| 710 addToDerived(getInternal(valuePromiseFollowing), promise, v8::Handle
<v8::Function>(), v8::Handle<v8::Function>(), isolate); |
| 711 } else if (valueState == Fulfilled) { |
| 712 setValue(promise, valueInternal->GetInternalField(InternalResultInde
x), isolate); |
| 713 } else if (valueState == Rejected) { |
| 714 setReason(promise, valueInternal->GetInternalField(InternalResultInd
ex), isolate); |
| 715 } else { |
| 716 ASSERT(valueState == Pending); |
| 717 setState(internal, Following, valuePromise, isolate); |
| 718 addToDerived(valueInternal, promise, v8::Handle<v8::Function>(), v8:
:Handle<v8::Function>(), isolate); |
| 719 } |
| 720 } else { |
| 721 setValue(promise, result, isolate); |
| 722 } |
| 723 } |
| 724 |
| 725 void V8PromiseCustom::reject(v8::Handle<v8::Object> promise, v8::Handle<v8::Valu
e> reason, v8::Isolate* isolate) |
| 726 { |
| 727 v8::Local<v8::Object> internal = getInternal(promise); |
| 728 PromiseState state = getState(internal); |
| 729 if (state != Pending) |
| 730 return; |
| 731 setReason(promise, reason, isolate); |
| 732 } |
| 733 |
| 734 v8::Local<v8::Object> V8PromiseCustom::then(v8::Handle<v8::Object> promise, v8::
Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Isola
te* isolate) |
| 735 { |
| 736 v8::Handle<v8::Object> internal = getInternal(promise); |
| 737 while (getState(internal) == Following) { |
| 738 promise = internal->GetInternalField(InternalResultIndex).As<v8::Object>
(); |
| 739 internal = getInternal(promise); |
| 740 } |
| 741 // FIXME: Currently we don't lookup "constructor" property since we limit |
| 742 // the creation of the promise objects only from the Blink Promise |
| 743 // constructor. |
| 744 v8::Local<v8::Object> derivedPromise = createPromise(v8::Handle<v8::Object>(
), isolate); |
| 745 updateDerivedFromPromise(derivedPromise, onFulfilled, onRejected, promise, i
solate); |
| 746 return derivedPromise; |
| 747 } |
| 748 |
| 749 void V8PromiseCustom::setValue(v8::Handle<v8::Object> promise, v8::Handle<v8::Va
lue> value, v8::Isolate* isolate) |
| 750 { |
| 751 PromisePropagator propagator; |
| 752 propagator.setValue(promise, value, isolate); |
| 753 propagator.performPropagation(isolate); |
| 754 } |
| 755 |
| 756 void V8PromiseCustom::setReason(v8::Handle<v8::Object> promise, v8::Handle<v8::V
alue> reason, v8::Isolate* isolate) |
| 757 { |
| 758 PromisePropagator propagator; |
| 759 propagator.setReason(promise, reason, isolate); |
| 760 propagator.performPropagation(isolate); |
| 761 } |
| 762 |
| 763 void V8PromiseCustom::propagateToDerived(v8::Handle<v8::Object> promise, v8::Iso
late* isolate) |
| 764 { |
| 765 PromisePropagator propagator; |
| 766 propagator.propagateToDerived(promise, isolate); |
| 767 propagator.performPropagation(isolate); |
| 768 } |
| 769 |
| 770 void V8PromiseCustom::updateDerived(v8::Handle<v8::Object> derivedPromise, v8::H
andle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected, v8::Handle
<v8::Object> originator, v8::Isolate* isolate) |
| 771 { |
| 772 PromisePropagator propagator; |
| 773 propagator.updateDerived(derivedPromise, onFulfilled, onRejected, originator
, isolate); |
| 774 propagator.performPropagation(isolate); |
| 775 } |
| 776 |
| 777 void V8PromiseCustom::updateDerivedFromValue(v8::Handle<v8::Object> derivedPromi
se, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Value> value, v8::Isola
te* isolate) |
| 778 { |
| 779 PromisePropagator propagator; |
| 780 propagator.updateDerivedFromValue(derivedPromise, onFulfilled, value, isolat
e); |
| 781 propagator.performPropagation(isolate); |
| 782 } |
| 783 |
| 784 void V8PromiseCustom::updateDerivedFromReason(v8::Handle<v8::Object> derivedProm
ise, v8::Handle<v8::Function> onRejected, v8::Handle<v8::Value> reason, v8::Isol
ate* isolate) |
| 785 { |
| 786 PromisePropagator propagator; |
| 787 propagator.updateDerivedFromReason(derivedPromise, onRejected, reason, isola
te); |
| 788 propagator.performPropagation(isolate); |
| 789 } |
| 790 |
| 791 void V8PromiseCustom::updateDerivedFromPromise(v8::Handle<v8::Object> derivedPro
mise, v8::Handle<v8::Function> onFulfilled, v8::Handle<v8::Function> onRejected,
v8::Handle<v8::Object> promise, v8::Isolate* isolate) |
| 792 { |
| 793 PromisePropagator propagator; |
| 794 propagator.updateDerivedFromPromise(derivedPromise, onFulfilled, onRejected,
promise, isolate); |
| 795 propagator.performPropagation(isolate); |
| 796 } |
| 797 |
| 798 v8::Local<v8::Object> V8PromiseCustom::coerceThenable(v8::Handle<v8::Object> the
nable, v8::Handle<v8::Function> then, v8::Isolate* isolate) |
| 799 { |
| 800 ASSERT(!thenable.IsEmpty()); |
| 801 ASSERT(!then.IsEmpty()); |
| 802 v8::Local<v8::Object> promise = createPromise(v8::Handle<v8::Object>(), isol
ate); |
| 803 v8::Handle<v8::Value> argv[] = { |
| 804 createClosure(promiseResolveCallback, promise, isolate), |
| 805 createClosure(promiseRejectCallback, promise, isolate) |
| 806 }; |
| 807 v8::TryCatch trycatch; |
| 808 if (V8ScriptRunner::callFunction(then, getScriptExecutionContext(), thenable
, WTF_ARRAY_LENGTH(argv), argv, isolate).IsEmpty()) { |
| 809 reject(promise, trycatch.Exception(), isolate); |
| 810 } |
| 811 thenable->SetHiddenValue(V8HiddenPropertyName::thenableHiddenPromise(isolate
), promise); |
| 812 return promise; |
| 813 } |
| 814 |
| 815 void V8PromiseCustom::callHandler(v8::Handle<v8::Object> promise, v8::Handle<v8:
:Function> handler, v8::Handle<v8::Value> argument, v8::Isolate* isolate) |
| 816 { |
| 817 ScriptExecutionContext* scriptExecutionContext = getScriptExecutionContext()
; |
| 818 ASSERT(scriptExecutionContext && scriptExecutionContext->isContextThread()); |
| 819 scriptExecutionContext->postTask(adoptPtr(new CallHandlerTask(promise, handl
er, argument, isolate))); |
| 820 } |
| 821 |
630 } // namespace WebCore | 822 } // namespace WebCore |
OLD | NEW |