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