| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 #include "bindings/core/v8/RejectedPromises.h" | 6 #include "bindings/core/v8/RejectedPromises.h" |
| 7 | 7 |
| 8 #include "bindings/core/v8/ScopedPersistent.h" | 8 #include "bindings/core/v8/ScopedPersistent.h" |
| 9 #include "bindings/core/v8/ScriptState.h" | 9 #include "bindings/core/v8/ScriptState.h" |
| 10 #include "bindings/core/v8/ScriptValue.h" | 10 #include "bindings/core/v8/ScriptValue.h" |
| 11 #include "bindings/core/v8/V8Binding.h" | 11 #include "bindings/core/v8/V8Binding.h" |
| 12 #include "core/dom/ExecutionContext.h" | 12 #include "core/dom/ExecutionContext.h" |
| 13 #include "core/events/EventTarget.h" | 13 #include "core/events/EventTarget.h" |
| 14 #include "core/events/PromiseRejectionEvent.h" | 14 #include "core/events/PromiseRejectionEvent.h" |
| 15 #include "core/inspector/ConsoleMessage.h" | 15 #include "core/inspector/ConsoleMessage.h" |
| 16 #include "core/inspector/ScriptArguments.h" | 16 #include "core/inspector/ScriptArguments.h" |
| 17 #include "platform/RuntimeEnabledFeatures.h" | 17 #include "platform/RuntimeEnabledFeatures.h" |
| 18 #include "platform/Task.h" | |
| 19 #include "public/platform/Platform.h" | |
| 20 #include "public/platform/WebScheduler.h" | |
| 21 #include "public/platform/WebTaskRunner.h" | |
| 22 #include "public/platform/WebThread.h" | |
| 23 #include "wtf/Functional.h" | |
| 24 | 18 |
| 25 namespace blink { | 19 namespace blink { |
| 26 | 20 |
| 27 static const unsigned maxReportedHandlersPendingResolution = 1000; | 21 static const unsigned maxReportedHandlersPendingResolution = 1000; |
| 28 | 22 |
| 29 class RejectedPromises::Message final : public NoBaseWillBeGarbageCollectedFinal
ized<RejectedPromises::Message> { | 23 class RejectedPromises::Message final : public NoBaseWillBeGarbageCollectedFinal
ized<RejectedPromises::Message> { |
| 30 public: | 24 public: |
| 31 static PassOwnPtrWillBeRawPtr<Message> create(ScriptState* scriptState, v8::
Local<v8::Promise> promise, const ScriptValue& exception, const String& errorMes
sage, const String& resourceName, int scriptId, int lineNumber, int columnNumber
, PassRefPtrWillBeRawPtr<ScriptCallStack> callStack) | 25 static PassOwnPtrWillBeRawPtr<Message> create(ScriptState* scriptState, v8::
Local<v8::Promise> promise, const ScriptValue& exception, const String& errorMes
sage, const String& resourceName, int scriptId, int lineNumber, int columnNumber
, PassRefPtrWillBeRawPtr<ScriptCallStack> callStack) |
| 32 { | 26 { |
| 33 return adoptPtrWillBeNoop(new Message(scriptState, promise, exception, e
rrorMessage, resourceName, scriptId, lineNumber, columnNumber, callStack)); | 27 return adoptPtrWillBeNoop(new Message(scriptState, promise, exception, e
rrorMessage, resourceName, scriptId, lineNumber, columnNumber, callStack)); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 58 return; | 52 return; |
| 59 ExecutionContext* executionContext = m_scriptState->executionContext(); | 53 ExecutionContext* executionContext = m_scriptState->executionContext(); |
| 60 if (!executionContext) | 54 if (!executionContext) |
| 61 return; | 55 return; |
| 62 | 56 |
| 63 ScriptState::Scope scope(m_scriptState); | 57 ScriptState::Scope scope(m_scriptState); |
| 64 v8::Local<v8::Value> value = m_promise.newLocal(m_scriptState->isolate()
); | 58 v8::Local<v8::Value> value = m_promise.newLocal(m_scriptState->isolate()
); |
| 65 // Either collected or https://crbug.com/450330 | 59 // Either collected or https://crbug.com/450330 |
| 66 if (value.IsEmpty() || !value->IsPromise()) | 60 if (value.IsEmpty() || !value->IsPromise()) |
| 67 return; | 61 return; |
| 68 ASSERT(!hasHandler()); | 62 ASSERT(!v8::Local<v8::Promise>::Cast(value)->HasHandler()); |
| 69 | 63 |
| 70 EventTarget* target = executionContext->errorEventTarget(); | 64 EventTarget* target = executionContext->errorEventTarget(); |
| 71 if (RuntimeEnabledFeatures::promiseRejectionEventEnabled() && target) { | 65 if (RuntimeEnabledFeatures::promiseRejectionEventEnabled() && target) { |
| 72 PromiseRejectionEventInit init; | 66 PromiseRejectionEventInit init; |
| 73 init.setPromise(ScriptPromise(m_scriptState, value)); | 67 init.setPromise(ScriptPromise(m_scriptState, value)); |
| 74 init.setReason(m_exception); | 68 init.setReason(m_exception); |
| 75 init.setCancelable(true); | 69 init.setCancelable(true); |
| 76 RefPtrWillBeRawPtr<PromiseRejectionEvent> event = PromiseRejectionEv
ent::create(m_scriptState, EventTypeNames::unhandledrejection, init); | 70 RefPtrWillBeRawPtr<PromiseRejectionEvent> event = PromiseRejectionEv
ent::create(m_scriptState, EventTypeNames::unhandledrejection, init); |
| 77 // Log to console if event was not preventDefault()'ed. | 71 // Log to console if event was not preventDefault()'ed. |
| 78 m_shouldLogToConsole = target->dispatchEvent(event); | 72 m_shouldLogToConsole = target->dispatchEvent(event); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 target->dispatchEvent(event); | 117 target->dispatchEvent(event); |
| 124 } | 118 } |
| 125 | 119 |
| 126 if (m_shouldLogToConsole) { | 120 if (m_shouldLogToConsole) { |
| 127 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::
create(JSMessageSource, RevokedErrorMessageLevel, "Handler added to rejected pro
mise"); | 121 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::
create(JSMessageSource, RevokedErrorMessageLevel, "Handler added to rejected pro
mise"); |
| 128 consoleMessage->setRelatedMessageId(m_consoleMessageId); | 122 consoleMessage->setRelatedMessageId(m_consoleMessageId); |
| 129 executionContext->addConsoleMessage(consoleMessage.release()); | 123 executionContext->addConsoleMessage(consoleMessage.release()); |
| 130 } | 124 } |
| 131 } | 125 } |
| 132 | 126 |
| 133 void makePromiseWeak() | |
| 134 { | |
| 135 ASSERT(!m_promise.isEmpty() && !m_promise.isWeak()); | |
| 136 m_promise.setWeak(this, &Message::didCollectPromise); | |
| 137 } | |
| 138 | |
| 139 void makePromiseStrong() | |
| 140 { | |
| 141 ASSERT(!m_promise.isEmpty() && m_promise.isWeak()); | |
| 142 m_promise.clearWeak(); | |
| 143 } | |
| 144 | |
| 145 bool hasHandler() | |
| 146 { | |
| 147 if (isCollected()) | |
| 148 return false; | |
| 149 ScriptState::Scope scope(m_scriptState); | |
| 150 v8::Local<v8::Value> value = m_promise.newLocal(m_scriptState->isolate()
); | |
| 151 return v8::Local<v8::Promise>::Cast(value)->HasHandler(); | |
| 152 } | |
| 153 | |
| 154 private: | 127 private: |
| 155 Message(ScriptState* scriptState, v8::Local<v8::Promise> promise, const Scri
ptValue& exception, const String& errorMessage, const String& resourceName, int
scriptId, int lineNumber, int columnNumber, PassRefPtrWillBeRawPtr<ScriptCallSta
ck> callStack) | 128 Message(ScriptState* scriptState, v8::Local<v8::Promise> promise, const Scri
ptValue& exception, const String& errorMessage, const String& resourceName, int
scriptId, int lineNumber, int columnNumber, PassRefPtrWillBeRawPtr<ScriptCallSta
ck> callStack) |
| 156 : m_scriptState(scriptState) | 129 : m_scriptState(scriptState) |
| 157 , m_promise(scriptState->isolate(), promise) | 130 , m_promise(scriptState->isolate(), promise) |
| 158 , m_exception(exception) | 131 , m_exception(exception) |
| 159 , m_errorMessage(errorMessage) | 132 , m_errorMessage(errorMessage) |
| 160 , m_resourceName(resourceName) | 133 , m_resourceName(resourceName) |
| 161 , m_scriptId(scriptId) | 134 , m_scriptId(scriptId) |
| 162 , m_lineNumber(lineNumber) | 135 , m_lineNumber(lineNumber) |
| 163 , m_columnNumber(columnNumber) | 136 , m_columnNumber(columnNumber) |
| 164 , m_callStack(callStack) | 137 , m_callStack(callStack) |
| 165 , m_consoleMessageId(0) | 138 , m_consoleMessageId(0) |
| 166 , m_collected(false) | 139 , m_collected(false) |
| 167 , m_shouldLogToConsole(true) | 140 , m_shouldLogToConsole(true) |
| 168 { | 141 { |
| 142 m_promise.setWeak(this, &Message::didCollectPromise); |
| 169 } | 143 } |
| 170 | 144 |
| 171 static void didCollectPromise(const v8::WeakCallbackInfo<Message>& data) | 145 static void didCollectPromise(const v8::WeakCallbackInfo<Message>& data) |
| 172 { | 146 { |
| 173 data.GetParameter()->m_collected = true; | 147 data.GetParameter()->m_collected = true; |
| 174 data.GetParameter()->m_promise.clear(); | 148 data.GetParameter()->m_promise.clear(); |
| 175 } | 149 } |
| 176 | 150 |
| 177 ScriptState* m_scriptState; | 151 ScriptState* m_scriptState; |
| 178 ScopedPersistent<v8::Promise> m_promise; | 152 ScopedPersistent<v8::Promise> m_promise; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 if (!(*it)->isCollected() && (*it)->hasPromise(data.GetPromise())) { | 186 if (!(*it)->isCollected() && (*it)->hasPromise(data.GetPromise())) { |
| 213 m_queue.remove(it); | 187 m_queue.remove(it); |
| 214 return; | 188 return; |
| 215 } | 189 } |
| 216 } | 190 } |
| 217 | 191 |
| 218 // Then look it up in the reported errors. | 192 // Then look it up in the reported errors. |
| 219 for (size_t i = 0; i < m_reportedAsErrors.size(); ++i) { | 193 for (size_t i = 0; i < m_reportedAsErrors.size(); ++i) { |
| 220 auto& message = m_reportedAsErrors.at(i); | 194 auto& message = m_reportedAsErrors.at(i); |
| 221 if (!message->isCollected() && message->hasPromise(data.GetPromise())) { | 195 if (!message->isCollected() && message->hasPromise(data.GetPromise())) { |
| 222 message->makePromiseStrong(); | 196 message->revoke(); |
| 223 Platform::current()->currentThread()->scheduler()->timerTaskRunner()
->postTask(FROM_HERE, new Task(bind(&RejectedPromises::revokeNow, this, message.
release()))); | |
| 224 m_reportedAsErrors.remove(i); | 197 m_reportedAsErrors.remove(i); |
| 225 return; | 198 return; |
| 226 } | 199 } |
| 227 } | 200 } |
| 228 } | 201 } |
| 229 | 202 |
| 230 void RejectedPromises::dispose() | 203 void RejectedPromises::dispose() |
| 231 { | 204 { |
| 232 if (!m_queue.isEmpty()) { | 205 processQueue(); |
| 233 OwnPtrWillBeRawPtr<WillBeHeapDeque<OwnPtrWillBeMember<Message>>> queue =
adoptPtr(new WillBeHeapDeque<OwnPtrWillBeMember<Message>>()); | |
| 234 queue->swap(m_queue); | |
| 235 processQueueNow(queue.release()); | |
| 236 } | |
| 237 } | 206 } |
| 238 | 207 |
| 239 void RejectedPromises::processQueue() | 208 void RejectedPromises::processQueue() |
| 240 { | 209 { |
| 241 if (m_queue.isEmpty()) | |
| 242 return; | |
| 243 OwnPtrWillBeRawPtr<WillBeHeapDeque<OwnPtrWillBeMember<Message>>> queue = ado
ptPtr(new WillBeHeapDeque<OwnPtrWillBeMember<Message>>()); | |
| 244 queue->swap(m_queue); | |
| 245 Platform::current()->currentThread()->scheduler()->timerTaskRunner()->postTa
sk(FROM_HERE, new Task(bind(&RejectedPromises::processQueueNow, this, queue.rele
ase()))); | |
| 246 } | |
| 247 | |
| 248 void RejectedPromises::processQueueNow(PassOwnPtrWillBeRawPtr<WillBeHeapDeque<Ow
nPtrWillBeMember<Message>>> queue) | |
| 249 { | |
| 250 // Remove collected handlers. | 210 // Remove collected handlers. |
| 251 for (size_t i = 0; i < m_reportedAsErrors.size();) { | 211 for (size_t i = 0; i < m_reportedAsErrors.size();) { |
| 252 if (m_reportedAsErrors.at(i)->isCollected()) | 212 if (m_reportedAsErrors.at(i)->isCollected()) |
| 253 m_reportedAsErrors.remove(i); | 213 m_reportedAsErrors.remove(i); |
| 254 else | 214 else |
| 255 ++i; | 215 ++i; |
| 256 } | 216 } |
| 257 | 217 |
| 258 while (!queue->isEmpty()) { | 218 while (!m_queue.isEmpty()) { |
| 259 OwnPtrWillBeRawPtr<Message> message = queue->takeFirst(); | 219 OwnPtrWillBeRawPtr<Message> message = m_queue.takeFirst(); |
| 260 if (!message->hasHandler()) { | 220 if (message->isCollected()) |
| 261 message->report(); | 221 continue; |
| 262 message->makePromiseWeak(); | 222 |
| 263 m_reportedAsErrors.append(message.release()); | 223 message->report(); |
| 264 if (m_reportedAsErrors.size() > maxReportedHandlersPendingResolution
) | 224 m_reportedAsErrors.append(message.release()); |
| 265 m_reportedAsErrors.remove(0, maxReportedHandlersPendingResolutio
n / 10); | 225 if (m_reportedAsErrors.size() > maxReportedHandlersPendingResolution) |
| 266 } | 226 m_reportedAsErrors.remove(0, maxReportedHandlersPendingResolution /
10); |
| 267 } | 227 } |
| 268 } | 228 } |
| 269 | 229 |
| 270 void RejectedPromises::revokeNow(PassOwnPtrWillBeRawPtr<Message> message) | |
| 271 { | |
| 272 message->revoke(); | |
| 273 } | |
| 274 | |
| 275 } // namespace blink | 230 } // namespace blink |
| OLD | NEW |