Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "web/SuspendableScriptExecutor.h" | 5 #include "web/SuspendableScriptExecutor.h" |
| 6 | 6 |
| 7 #include "bindings/core/v8/ScriptController.h" | 7 #include "bindings/core/v8/ScriptController.h" |
| 8 #include "bindings/core/v8/ScriptSourceCode.h" | 8 #include "bindings/core/v8/ScriptSourceCode.h" |
| 9 #include "bindings/core/v8/V8PersistentValueVector.h" | 9 #include "bindings/core/v8/V8PersistentValueVector.h" |
| 10 #include "bindings/core/v8/WindowProxy.h" | |
| 10 #include "core/dom/Document.h" | 11 #include "core/dom/Document.h" |
| 11 #include "core/dom/DocumentUserGestureToken.h" | 12 #include "core/dom/DocumentUserGestureToken.h" |
| 12 #include "core/frame/LocalFrame.h" | 13 #include "core/frame/LocalFrame.h" |
| 13 #include "platform/UserGestureIndicator.h" | 14 #include "platform/UserGestureIndicator.h" |
| 14 #include "public/platform/WebVector.h" | 15 #include "public/platform/WebVector.h" |
| 15 #include "public/web/WebScriptExecutionCallback.h" | 16 #include "public/web/WebScriptExecutionCallback.h" |
| 16 #include "wtf/PtrUtil.h" | 17 #include "wtf/PtrUtil.h" |
| 17 #include "wtf/Vector.h" | 18 #include "wtf/Vector.h" |
| 18 #include <memory> | 19 #include <memory> |
| 19 | 20 |
| 20 namespace blink { | 21 namespace blink { |
| 21 | 22 |
| 22 namespace { | 23 namespace { |
| 23 | 24 |
| 24 class WebScriptExecutor : public SuspendableScriptExecutor::Executor { | 25 class WebScriptExecutor : public SuspendableScriptExecutor::Executor { |
| 25 public: | 26 public: |
| 26 WebScriptExecutor(const HeapVector<ScriptSourceCode>& sources, | 27 WebScriptExecutor(const HeapVector<ScriptSourceCode>& sources, |
| 27 int worldID, | 28 int worldID, |
| 28 int extensionGroup, | 29 int extensionGroup, |
| 29 bool userGesture); | 30 bool userGesture); |
| 30 | 31 |
| 31 Vector<v8::Local<v8::Value>> execute(LocalFrame*) override; | 32 Vector<v8::Local<v8::Value>> execute(LocalFrame*) override; |
| 33 ScriptState* getScriptState(LocalFrame*) override; | |
| 32 | 34 |
| 33 DEFINE_INLINE_VIRTUAL_TRACE() { | 35 DEFINE_INLINE_VIRTUAL_TRACE() { |
| 34 visitor->trace(m_sources); | 36 visitor->trace(m_sources); |
| 35 SuspendableScriptExecutor::Executor::trace(visitor); | 37 SuspendableScriptExecutor::Executor::trace(visitor); |
| 36 } | 38 } |
| 37 | 39 |
| 38 private: | 40 private: |
| 39 HeapVector<ScriptSourceCode> m_sources; | 41 HeapVector<ScriptSourceCode> m_sources; |
| 40 int m_worldID; | 42 int m_worldID; |
| 41 int m_extensionGroup; | 43 int m_extensionGroup; |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 67 } else { | 69 } else { |
| 68 v8::Local<v8::Value> scriptValue = | 70 v8::Local<v8::Value> scriptValue = |
| 69 frame->script().executeScriptInMainWorldAndReturnValue( | 71 frame->script().executeScriptInMainWorldAndReturnValue( |
| 70 m_sources.first()); | 72 m_sources.first()); |
| 71 results.append(scriptValue); | 73 results.append(scriptValue); |
| 72 } | 74 } |
| 73 | 75 |
| 74 return results; | 76 return results; |
| 75 } | 77 } |
| 76 | 78 |
| 79 ScriptState* WebScriptExecutor::getScriptState(LocalFrame* frame) { | |
| 80 return ScriptState::forWorld( | |
| 81 frame, DOMWrapperWorld::fromWorldId(v8::Isolate::GetCurrent(), m_worldID, | |
| 82 m_extensionGroup)); | |
| 83 } | |
| 84 | |
| 77 class V8FunctionExecutor : public SuspendableScriptExecutor::Executor { | 85 class V8FunctionExecutor : public SuspendableScriptExecutor::Executor { |
| 78 public: | 86 public: |
| 79 V8FunctionExecutor(v8::Isolate*, | 87 V8FunctionExecutor(v8::Isolate*, |
| 80 ScriptState*, | 88 ScriptState*, |
| 81 v8::Local<v8::Function>, | 89 v8::Local<v8::Function>, |
| 82 v8::Local<v8::Value> receiver, | 90 v8::Local<v8::Value> receiver, |
| 83 int argc, | 91 int argc, |
| 84 v8::Local<v8::Value> argv[]); | 92 v8::Local<v8::Value> argv[]); |
| 85 | 93 |
| 86 Vector<v8::Local<v8::Value>> execute(LocalFrame*) override; | 94 Vector<v8::Local<v8::Value>> execute(LocalFrame*) override; |
| 95 ScriptState* getScriptState(LocalFrame*) override { | |
| 96 return m_scriptState.get(); | |
| 97 } | |
| 87 | 98 |
| 88 private: | 99 private: |
| 89 ScopedPersistent<v8::Function> m_function; | 100 ScopedPersistent<v8::Function> m_function; |
| 90 ScopedPersistent<v8::Value> m_receiver; | 101 ScopedPersistent<v8::Value> m_receiver; |
| 91 V8PersistentValueVector<v8::Value> m_args; | 102 V8PersistentValueVector<v8::Value> m_args; |
| 92 RefPtr<ScriptState> m_scriptState; | 103 RefPtr<ScriptState> m_scriptState; |
| 104 RefPtr<UserGestureToken> m_gestureToken; | |
| 93 }; | 105 }; |
| 94 | 106 |
| 95 V8FunctionExecutor::V8FunctionExecutor(v8::Isolate* isolate, | 107 V8FunctionExecutor::V8FunctionExecutor(v8::Isolate* isolate, |
| 96 ScriptState* scriptState, | 108 ScriptState* scriptState, |
| 97 v8::Local<v8::Function> function, | 109 v8::Local<v8::Function> function, |
| 98 v8::Local<v8::Value> receiver, | 110 v8::Local<v8::Value> receiver, |
| 99 int argc, | 111 int argc, |
| 100 v8::Local<v8::Value> argv[]) | 112 v8::Local<v8::Value> argv[]) |
| 101 : m_function(isolate, function), | 113 : m_function(isolate, function), |
| 102 m_receiver(isolate, receiver), | 114 m_receiver(isolate, receiver), |
| 103 m_args(isolate), | 115 m_args(isolate), |
| 104 m_scriptState(scriptState) { | 116 m_scriptState(scriptState), |
| 117 m_gestureToken(UserGestureIndicator::currentToken()) { | |
| 105 m_args.ReserveCapacity(argc); | 118 m_args.ReserveCapacity(argc); |
| 106 for (int i = 0; i < argc; ++i) | 119 for (int i = 0; i < argc; ++i) |
| 107 m_args.Append(argv[i]); | 120 m_args.Append(argv[i]); |
| 108 } | 121 } |
| 109 | 122 |
| 110 Vector<v8::Local<v8::Value>> V8FunctionExecutor::execute(LocalFrame* frame) { | 123 Vector<v8::Local<v8::Value>> V8FunctionExecutor::execute(LocalFrame* frame) { |
| 111 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 124 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 112 Vector<v8::Local<v8::Value>> results; | 125 Vector<v8::Local<v8::Value>> results; |
| 113 if (!m_scriptState->contextIsValid()) | 126 DCHECK(m_scriptState->contextIsValid()); |
| 114 return results; | |
| 115 ScriptState::Scope scope(m_scriptState.get()); | |
| 116 v8::Local<v8::Value> singleResult; | 127 v8::Local<v8::Value> singleResult; |
| 117 Vector<v8::Local<v8::Value>> args; | 128 Vector<v8::Local<v8::Value>> args; |
| 118 args.reserveCapacity(m_args.Size()); | 129 args.reserveCapacity(m_args.Size()); |
| 119 for (size_t i = 0; i < m_args.Size(); ++i) | 130 for (size_t i = 0; i < m_args.Size(); ++i) |
| 120 args.append(m_args.Get(i)); | 131 args.append(m_args.Get(i)); |
| 121 if (V8ScriptRunner::callFunction(m_function.newLocal(isolate), | 132 { |
| 122 frame->document(), | 133 std::unique_ptr<UserGestureIndicator> gestureIndicator; |
| 123 m_receiver.newLocal(isolate), args.size(), | 134 // It's important that we don't pass the gesture if it's already the |
|
Nate Chapin
2016/11/01 17:40:18
Oops, you found a bug in UserGestureIndicator. Rat
Devlin
2016/11/01 17:56:10
sgtm. I'll do that in a separate CL and send it y
| |
| 124 args.data(), toIsolate(frame)) | 135 // current token, because otherwise once this goes out of scope, the gesture |
| 125 .ToLocal(&singleResult)) | 136 // is removed and is no longer considered to be processing. Thus, if |
| 126 results.append(singleResult); | 137 // execute() were called re-entrantly, we would lose the gesture while it |
| 138 // should still be being processed. | |
| 139 if (m_gestureToken && | |
| 140 UserGestureIndicator::currentToken() != m_gestureToken) { | |
| 141 gestureIndicator = | |
| 142 wrapUnique(new UserGestureIndicator(m_gestureToken.release())); | |
| 143 } | |
| 144 if (V8ScriptRunner::callFunction(m_function.newLocal(isolate), | |
| 145 frame->document(), | |
| 146 m_receiver.newLocal(isolate), args.size(), | |
| 147 args.data(), toIsolate(frame)) | |
| 148 .ToLocal(&singleResult)) | |
| 149 results.append(singleResult); | |
| 150 } | |
| 127 return results; | 151 return results; |
| 128 } | 152 } |
| 129 | 153 |
| 130 } // namespace | 154 } // namespace |
| 131 | 155 |
| 132 void SuspendableScriptExecutor::createAndRun( | 156 void SuspendableScriptExecutor::createAndRun( |
| 133 LocalFrame* frame, | 157 LocalFrame* frame, |
| 134 int worldID, | 158 int worldID, |
| 135 const HeapVector<ScriptSourceCode>& sources, | 159 const HeapVector<ScriptSourceCode>& sources, |
| 136 int extensionGroup, | 160 int extensionGroup, |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 192 if (!context->activeDOMObjectsAreSuspended()) { | 216 if (!context->activeDOMObjectsAreSuspended()) { |
| 193 suspendIfNeeded(); | 217 suspendIfNeeded(); |
| 194 executeAndDestroySelf(); | 218 executeAndDestroySelf(); |
| 195 return; | 219 return; |
| 196 } | 220 } |
| 197 startOneShot(0, BLINK_FROM_HERE); | 221 startOneShot(0, BLINK_FROM_HERE); |
| 198 suspendIfNeeded(); | 222 suspendIfNeeded(); |
| 199 } | 223 } |
| 200 | 224 |
| 201 void SuspendableScriptExecutor::executeAndDestroySelf() { | 225 void SuspendableScriptExecutor::executeAndDestroySelf() { |
| 202 v8::HandleScope scope(v8::Isolate::GetCurrent()); | 226 ScriptState* scriptState = m_executor->getScriptState(m_frame); |
| 203 Vector<v8::Local<v8::Value>> results = m_executor->execute(m_frame); | 227 // TODO(devlin): Is it possible to get here without a valid ScriptState? It's |
| 228 // a SuspendableTimer, which shouldn't execute if the tracked context is | |
| 229 // destroyed. | |
| 230 if (scriptState && scriptState->contextIsValid()) { | |
|
dcheng
2016/11/01 00:14:05
Are we planning on merging these patches? If not,
Devlin
2016/11/03 01:17:08
Sounds reasonable, CHECK()ing (given the ambiguity
| |
| 231 ScriptState::Scope scriptScope(scriptState); | |
| 232 Vector<v8::Local<v8::Value>> results = m_executor->execute(m_frame); | |
| 204 | 233 |
| 205 // The script may have removed the frame, in which case contextDestroyed() | 234 // The script may have removed the frame, in which case contextDestroyed() |
| 206 // will have handled the disposal/callback. | 235 // will have handled the disposal/callback. |
| 207 if (!m_frame->client()) | 236 if (!lifecycleContext()) |
| 208 return; | 237 return; |
| 209 | 238 |
| 210 if (m_callback) | 239 // We need to call the callback before scriptScope goes out of scope. |
| 211 m_callback->completed(results); | 240 if (m_callback) |
| 241 m_callback->completed(results); | |
| 242 } else { | |
| 243 if (m_callback) | |
| 244 m_callback->completed(Vector<v8::Local<v8::Value>>()); | |
| 245 } | |
| 246 | |
| 212 dispose(); | 247 dispose(); |
| 213 } | 248 } |
| 214 | 249 |
| 215 void SuspendableScriptExecutor::dispose() { | 250 void SuspendableScriptExecutor::dispose() { |
| 216 // Remove object as a ContextLifecycleObserver. | 251 // Remove object as a ContextLifecycleObserver. |
| 217 ActiveDOMObject::clearContext(); | 252 ActiveDOMObject::clearContext(); |
| 218 m_keepAlive.clear(); | 253 m_keepAlive.clear(); |
| 219 stop(); | 254 stop(); |
| 220 } | 255 } |
| 221 | 256 |
| 222 DEFINE_TRACE(SuspendableScriptExecutor) { | 257 DEFINE_TRACE(SuspendableScriptExecutor) { |
| 223 visitor->trace(m_frame); | 258 visitor->trace(m_frame); |
| 224 visitor->trace(m_executor); | 259 visitor->trace(m_executor); |
| 225 SuspendableTimer::trace(visitor); | 260 SuspendableTimer::trace(visitor); |
| 226 } | 261 } |
| 227 | 262 |
| 228 } // namespace blink | 263 } // namespace blink |
| OLD | NEW |