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 "config.h" | 5 #include "config.h" |
6 #include "bindings/core/v8/ScriptStreamer.h" | 6 #include "bindings/core/v8/ScriptStreamer.h" |
7 | 7 |
8 #include "bindings/core/v8/ScriptStreamerThread.h" | 8 #include "bindings/core/v8/ScriptStreamerThread.h" |
9 #include "bindings/core/v8/V8ScriptRunner.h" | 9 #include "bindings/core/v8/V8ScriptRunner.h" |
10 #include "core/dom/Document.h" | 10 #include "core/dom/Document.h" |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 }; | 82 }; |
83 | 83 |
84 | 84 |
85 // SourceStream implements the streaming interface towards V8. The main | 85 // SourceStream implements the streaming interface towards V8. The main |
86 // functionality is preparing the data to give to V8 on main thread, and | 86 // functionality is preparing the data to give to V8 on main thread, and |
87 // actually giving the data (via GetMoreData which is called on a background | 87 // actually giving the data (via GetMoreData which is called on a background |
88 // thread). | 88 // thread). |
89 class SourceStream : public v8::ScriptCompiler::ExternalSourceStream { | 89 class SourceStream : public v8::ScriptCompiler::ExternalSourceStream { |
90 WTF_MAKE_NONCOPYABLE(SourceStream); | 90 WTF_MAKE_NONCOPYABLE(SourceStream); |
91 public: | 91 public: |
92 SourceStream(ScriptStreamer* streamer) | 92 SourceStream() |
93 : v8::ScriptCompiler::ExternalSourceStream() | 93 : v8::ScriptCompiler::ExternalSourceStream() |
94 , m_streamer(streamer) | |
95 , m_cancelled(false) | 94 , m_cancelled(false) |
96 , m_dataPosition(0) { } | 95 , m_dataPosition(0) { } |
97 | 96 |
98 virtual ~SourceStream() { } | 97 virtual ~SourceStream() { } |
99 | 98 |
100 // Called by V8 on a background thread. Should block until we can return | 99 // Called by V8 on a background thread. Should block until we can return |
101 // some data. | 100 // some data. |
102 virtual size_t GetMoreData(const uint8_t** src) override | 101 virtual size_t GetMoreData(const uint8_t** src) override |
103 { | 102 { |
104 ASSERT(!isMainThread()); | 103 ASSERT(!isMainThread()); |
(...skipping 12 matching lines...) Expand all Loading... |
117 } | 116 } |
118 return length; | 117 return length; |
119 } | 118 } |
120 | 119 |
121 void didFinishLoading() | 120 void didFinishLoading() |
122 { | 121 { |
123 ASSERT(isMainThread()); | 122 ASSERT(isMainThread()); |
124 m_dataQueue.finish(); | 123 m_dataQueue.finish(); |
125 } | 124 } |
126 | 125 |
127 void didReceiveData(size_t lengthOfBOM) | 126 void didReceiveData(ScriptStreamer* streamer, size_t lengthOfBOM) |
128 { | 127 { |
129 ASSERT(isMainThread()); | 128 ASSERT(isMainThread()); |
130 prepareDataOnMainThread(lengthOfBOM); | 129 prepareDataOnMainThread(streamer, lengthOfBOM); |
131 } | 130 } |
132 | 131 |
133 void cancel() | 132 void cancel() |
134 { | 133 { |
135 ASSERT(isMainThread()); | 134 ASSERT(isMainThread()); |
136 // The script is no longer needed by the upper layers. Stop streaming | 135 // The script is no longer needed by the upper layers. Stop streaming |
137 // it. The next time GetMoreData is called (or woken up), it will return | 136 // it. The next time GetMoreData is called (or woken up), it will return |
138 // 0, which will be interpreted as EOS by V8 and the parsing will | 137 // 0, which will be interpreted as EOS by V8 and the parsing will |
139 // fail. ScriptStreamer::streamingComplete will be called, and at that | 138 // fail. ScriptStreamer::streamingComplete will be called, and at that |
140 // point we will release the references to SourceStream. | 139 // point we will release the references to SourceStream. |
141 { | 140 { |
142 MutexLocker locker(m_mutex); | 141 MutexLocker locker(m_mutex); |
143 m_cancelled = true; | 142 m_cancelled = true; |
144 } | 143 } |
145 m_dataQueue.finish(); | 144 m_dataQueue.finish(); |
146 } | 145 } |
147 | 146 |
148 private: | 147 private: |
149 void prepareDataOnMainThread(size_t lengthOfBOM) | 148 void prepareDataOnMainThread(ScriptStreamer* streamer, size_t lengthOfBOM) |
150 { | 149 { |
151 ASSERT(isMainThread()); | 150 ASSERT(isMainThread()); |
152 // The Resource must still be alive; otherwise we should've cancelled | 151 // The Resource must still be alive; otherwise we should've cancelled |
153 // the streaming (if we have cancelled, the background thread is not | 152 // the streaming (if we have cancelled, the background thread is not |
154 // waiting). | 153 // waiting). |
155 ASSERT(m_streamer->resource()); | 154 ASSERT(streamer->resource()); |
156 | 155 |
157 // BOM can only occur at the beginning of the data. | 156 // BOM can only occur at the beginning of the data. |
158 ASSERT(lengthOfBOM == 0 || m_dataPosition == 0); | 157 ASSERT(lengthOfBOM == 0 || m_dataPosition == 0); |
159 | 158 |
160 if (m_streamer->resource()->cachedMetadata(V8ScriptRunner::tagForCodeCac
he(m_streamer->resource()))) { | 159 if (streamer->resource()->cachedMetadata(V8ScriptRunner::tagForCodeCache
(streamer->resource()))) { |
161 // The resource has a code cache, so it's unnecessary to stream and | 160 // The resource has a code cache, so it's unnecessary to stream and |
162 // parse the code. Cancel the streaming and resume the non-streaming | 161 // parse the code. Cancel the streaming and resume the non-streaming |
163 // code path. | 162 // code path. |
164 m_streamer->suppressStreaming(); | 163 streamer->suppressStreaming(); |
165 { | 164 { |
166 MutexLocker locker(m_mutex); | 165 MutexLocker locker(m_mutex); |
167 m_cancelled = true; | 166 m_cancelled = true; |
168 } | 167 } |
169 m_dataQueue.finish(); | 168 m_dataQueue.finish(); |
170 return; | 169 return; |
171 } | 170 } |
172 | 171 |
173 if (!m_resourceBuffer) { | 172 if (!m_resourceBuffer) { |
174 // We don't have a buffer yet. Try to get it from the resource. | 173 // We don't have a buffer yet. Try to get it from the resource. |
175 SharedBuffer* buffer = m_streamer->resource()->resourceBuffer(); | 174 SharedBuffer* buffer = streamer->resource()->resourceBuffer(); |
176 m_resourceBuffer = RefPtr<SharedBuffer>(buffer); | 175 m_resourceBuffer = RefPtr<SharedBuffer>(buffer); |
177 } | 176 } |
178 | 177 |
179 // Get as much data from the ResourceBuffer as we can. | 178 // Get as much data from the ResourceBuffer as we can. |
180 const char* data = 0; | 179 const char* data = 0; |
181 Vector<const char*> chunks; | 180 Vector<const char*> chunks; |
182 Vector<unsigned> chunkLengths; | 181 Vector<unsigned> chunkLengths; |
183 size_t dataLength = 0; | 182 size_t dataLength = 0; |
184 while (unsigned length = m_resourceBuffer->getSomeData(data, m_dataPosit
ion)) { | 183 while (unsigned length = m_resourceBuffer->getSomeData(data, m_dataPosit
ion)) { |
185 // FIXME: Here we can limit based on the total length, if it turns | 184 // FIXME: Here we can limit based on the total length, if it turns |
(...skipping 13 matching lines...) Expand all Loading... |
199 for (size_t i = 0; i < chunks.size(); ++i) { | 198 for (size_t i = 0; i < chunks.size(); ++i) { |
200 memcpy(copiedData + offset, chunks[i] + lengthOfBOM, chunkLength
s[i] - lengthOfBOM); | 199 memcpy(copiedData + offset, chunks[i] + lengthOfBOM, chunkLength
s[i] - lengthOfBOM); |
201 offset += chunkLengths[i] - lengthOfBOM; | 200 offset += chunkLengths[i] - lengthOfBOM; |
202 // BOM is only in the first chunk | 201 // BOM is only in the first chunk |
203 lengthOfBOM = 0; | 202 lengthOfBOM = 0; |
204 } | 203 } |
205 m_dataQueue.produce(copiedData, dataLength); | 204 m_dataQueue.produce(copiedData, dataLength); |
206 } | 205 } |
207 } | 206 } |
208 | 207 |
209 ScriptStreamer* m_streamer; | |
210 | |
211 // For coordinating between the main thread and background thread tasks. | 208 // For coordinating between the main thread and background thread tasks. |
212 // Guarded by m_mutex. | 209 // Guarded by m_mutex. |
213 bool m_cancelled; | 210 bool m_cancelled; |
214 Mutex m_mutex; | 211 Mutex m_mutex; |
215 | 212 |
216 unsigned m_dataPosition; // Only used by the main thread. | 213 unsigned m_dataPosition; // Only used by the main thread. |
217 RefPtr<SharedBuffer> m_resourceBuffer; // Only used by the main thread. | 214 RefPtr<SharedBuffer> m_resourceBuffer; // Only used by the main thread. |
218 SourceStreamDataQueue m_dataQueue; // Thread safe. | 215 SourceStreamDataQueue m_dataQueue; // Thread safe. |
219 }; | 216 }; |
220 | 217 |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 } | 341 } |
345 | 342 |
346 if (!m_scriptState->contextIsValid()) { | 343 if (!m_scriptState->contextIsValid()) { |
347 suppressStreaming(); | 344 suppressStreaming(); |
348 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2
); | 345 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2
); |
349 return; | 346 return; |
350 } | 347 } |
351 | 348 |
352 ASSERT(!m_stream); | 349 ASSERT(!m_stream); |
353 ASSERT(!m_source); | 350 ASSERT(!m_source); |
354 m_stream = new SourceStream(this); | 351 m_stream = new SourceStream(); |
355 // m_source takes ownership of m_stream. | 352 // m_source takes ownership of m_stream. |
356 m_source = adoptPtr(new v8::ScriptCompiler::StreamedSource(m_stream, m_e
ncoding)); | 353 m_source = adoptPtr(new v8::ScriptCompiler::StreamedSource(m_stream, m_e
ncoding)); |
357 | 354 |
358 ScriptState::Scope scope(m_scriptState.get()); | 355 ScriptState::Scope scope(m_scriptState.get()); |
359 WTF::OwnPtr<v8::ScriptCompiler::ScriptStreamingTask> scriptStreamingTask
(adoptPtr(v8::ScriptCompiler::StartStreamingScript(m_scriptState->isolate(), m_s
ource.get(), m_compileOptions))); | 356 WTF::OwnPtr<v8::ScriptCompiler::ScriptStreamingTask> scriptStreamingTask
(adoptPtr(v8::ScriptCompiler::StartStreamingScript(m_scriptState->isolate(), m_s
ource.get(), m_compileOptions))); |
360 if (!scriptStreamingTask) { | 357 if (!scriptStreamingTask) { |
361 // V8 cannot stream the script. | 358 // V8 cannot stream the script. |
362 suppressStreaming(); | 359 suppressStreaming(); |
363 m_stream = 0; | 360 m_stream = 0; |
364 m_source.clear(); | 361 m_source.clear(); |
365 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2
); | 362 blink::Platform::current()->histogramEnumeration(histogramName, 0, 2
); |
366 return; | 363 return; |
367 } | 364 } |
368 | 365 |
369 // ScriptStreamer needs to stay alive as long as the background task is | 366 // ScriptStreamer needs to stay alive as long as the background task is |
370 // running. This is taken care of with a manual ref() & deref() pair; | 367 // running. This is taken care of with a manual ref() & deref() pair; |
371 // the corresponding deref() is in streamingComplete or in | 368 // the corresponding deref() is in streamingComplete or in |
372 // notifyFinished. | 369 // notifyFinished. |
373 ref(); | 370 ref(); |
374 ScriptStreamingTask* task = new ScriptStreamingTask(scriptStreamingTask.
release(), this); | 371 ScriptStreamingTask* task = new ScriptStreamingTask(scriptStreamingTask.
release(), this); |
375 ScriptStreamerThread::shared()->postTask(task); | 372 ScriptStreamerThread::shared()->postTask(task); |
376 blink::Platform::current()->histogramEnumeration(histogramName, 1, 2); | 373 blink::Platform::current()->histogramEnumeration(histogramName, 1, 2); |
377 } | 374 } |
378 if (m_stream) | 375 if (m_stream) |
379 m_stream->didReceiveData(lengthOfBOM); | 376 m_stream->didReceiveData(this, lengthOfBOM); |
380 } | 377 } |
381 | 378 |
382 void ScriptStreamer::notifyFinished(Resource* resource) | 379 void ScriptStreamer::notifyFinished(Resource* resource) |
383 { | 380 { |
384 ASSERT(isMainThread()); | 381 ASSERT(isMainThread()); |
385 ASSERT(m_resource == resource); | 382 ASSERT(m_resource == resource); |
386 // A special case: empty and small scripts. We didn't receive enough data to | 383 // A special case: empty and small scripts. We didn't receive enough data to |
387 // start the streaming before this notification. In that case, there won't | 384 // start the streaming before this notification. In that case, there won't |
388 // be a "parsing complete" notification either, and we should not wait for | 385 // be a "parsing complete" notification either, and we should not wait for |
389 // it. | 386 // it. |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 | 543 |
547 // The Resource might go out of scope if the script is no longer | 544 // The Resource might go out of scope if the script is no longer |
548 // needed. This makes PendingScript notify the ScriptStreamer when it is | 545 // needed. This makes PendingScript notify the ScriptStreamer when it is |
549 // destroyed. | 546 // destroyed. |
550 script.setStreamer(adoptRef(new ScriptStreamer(resource, scriptType, setting
s->v8ScriptStreamingMode(), scriptState, compileOption))); | 547 script.setStreamer(adoptRef(new ScriptStreamer(resource, scriptType, setting
s->v8ScriptStreamingMode(), scriptState, compileOption))); |
551 | 548 |
552 return true; | 549 return true; |
553 } | 550 } |
554 | 551 |
555 } // namespace blink | 552 } // namespace blink |
OLD | NEW |