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 | 5 |
6 #include "config.h" | 6 #include "config.h" |
7 #include "bindings/core/v8/ScriptStreamer.h" | 7 #include "bindings/core/v8/ScriptStreamer.h" |
8 | 8 |
9 #include "bindings/core/v8/ScriptStreamerThread.h" | 9 #include "bindings/core/v8/ScriptStreamerThread.h" |
10 #include "bindings/core/v8/V8Binding.h" | 10 #include "bindings/core/v8/V8Binding.h" |
11 #include "bindings/core/v8/V8ScriptRunner.h" | 11 #include "bindings/core/v8/V8ScriptRunner.h" |
12 #include "core/dom/PendingScript.h" | 12 #include "core/dom/PendingScript.h" |
13 #include "core/frame/Settings.h" | 13 #include "core/frame/Settings.h" |
14 #include "platform/Task.h" | 14 #include "platform/Task.h" |
| 15 #include "platform/heap/Handle.h" |
15 #include "public/platform/Platform.h" | 16 #include "public/platform/Platform.h" |
16 | 17 |
17 #include <gtest/gtest.h> | 18 #include <gtest/gtest.h> |
18 #include <v8.h> | 19 #include <v8.h> |
19 | 20 |
20 namespace blink { | 21 namespace blink { |
21 | 22 |
22 namespace { | 23 namespace { |
23 | 24 |
| 25 // For the benefit of Oilpan, put the part object PendingScript inside |
| 26 // a wrapper that's on the Oilpan heap and hold a reference to that wrapper |
| 27 // from ScriptStreamingTest. |
| 28 class PendingScriptWrapper : public NoBaseWillBeGarbageCollectedFinalized<Pendin
gScriptWrapper> { |
| 29 public: |
| 30 static PassOwnPtrWillBeRawPtr<PendingScriptWrapper> create() |
| 31 { |
| 32 return adoptPtrWillBeNoop(new PendingScriptWrapper()); |
| 33 } |
| 34 |
| 35 static PassOwnPtrWillBeRawPtr<PendingScriptWrapper> create(Element* element,
ScriptResource* resource) |
| 36 { |
| 37 return adoptPtrWillBeNoop(new PendingScriptWrapper(element, resource)); |
| 38 } |
| 39 |
| 40 PendingScript& get() { return m_pendingScript; } |
| 41 |
| 42 void trace(Visitor* visitor) |
| 43 { |
| 44 visitor->trace(m_pendingScript); |
| 45 } |
| 46 |
| 47 private: |
| 48 PendingScriptWrapper() |
| 49 { |
| 50 } |
| 51 |
| 52 PendingScriptWrapper(Element* element, ScriptResource* resource) |
| 53 : m_pendingScript(PendingScript(element, resource)) |
| 54 { |
| 55 } |
| 56 |
| 57 PendingScript m_pendingScript; |
| 58 }; |
| 59 |
24 class ScriptStreamingTest : public testing::Test { | 60 class ScriptStreamingTest : public testing::Test { |
25 public: | 61 public: |
26 ScriptStreamingTest() | 62 ScriptStreamingTest() |
27 : m_scope(v8::Isolate::GetCurrent()) | 63 : m_scope(v8::Isolate::GetCurrent()) |
28 , m_settings(Settings::create()) | 64 , m_settings(Settings::create()) |
29 , m_resourceRequest("http://www.streaming-test.com/") | 65 , m_resourceRequest("http://www.streaming-test.com/") |
30 , m_resource(new ScriptResource(m_resourceRequest, "text/utf-8")) | 66 , m_resource(new ScriptResource(m_resourceRequest, "text/utf-8")) |
31 , m_pendingScript(0, m_resource) // Takes ownership of m_resource. | 67 , m_pendingScript(PendingScriptWrapper::create(0, m_resource)) // Takes
ownership of m_resource. |
32 { | 68 { |
33 m_settings->setV8ScriptStreamingEnabled(true); | 69 m_settings->setV8ScriptStreamingEnabled(true); |
34 m_resource->setLoading(true); | 70 m_resource->setLoading(true); |
35 } | 71 } |
36 | 72 |
37 ScriptState* scriptState() const { return m_scope.scriptState(); } | 73 ScriptState* scriptState() const { return m_scope.scriptState(); } |
38 v8::Isolate* isolate() const { return m_scope.isolate(); } | 74 v8::Isolate* isolate() const { return m_scope.isolate(); } |
39 | 75 |
40 void trace(Visitor* visitor) | 76 PendingScript& pendingScript() const { return m_pendingScript->get(); } |
41 { | |
42 visitor->trace(m_pendingScript); | |
43 } | |
44 | 77 |
45 protected: | 78 protected: |
46 void appendData(const char* data) | 79 void appendData(const char* data) |
47 { | 80 { |
48 m_resource->appendData(data, strlen(data)); | 81 m_resource->appendData(data, strlen(data)); |
49 // Yield control to the background thread, so that V8 gets a change to | 82 // Yield control to the background thread, so that V8 gets a change to |
50 // process the data before the main thread adds more. Note that we | 83 // process the data before the main thread adds more. Note that we |
51 // cannot fully control in what kind of chunks the data is passed to V8 | 84 // cannot fully control in what kind of chunks the data is passed to V8 |
52 // (if the V8 is not requesting more data between two appendData calls, | 85 // (if the V8 is not requesting more data between two appendData calls, |
53 // V8 will get both chunks together). | 86 // V8 will get both chunks together). |
(...skipping 24 matching lines...) Expand all Loading... |
78 } | 111 } |
79 } | 112 } |
80 | 113 |
81 V8TestingScope m_scope; | 114 V8TestingScope m_scope; |
82 OwnPtr<Settings> m_settings; | 115 OwnPtr<Settings> m_settings; |
83 // The Resource and PendingScript where we stream from. These don't really | 116 // The Resource and PendingScript where we stream from. These don't really |
84 // fetch any data outside the test; the test controls the data by calling | 117 // fetch any data outside the test; the test controls the data by calling |
85 // ScriptResource::appendData. | 118 // ScriptResource::appendData. |
86 ResourceRequest m_resourceRequest; | 119 ResourceRequest m_resourceRequest; |
87 ScriptResource* m_resource; | 120 ScriptResource* m_resource; |
88 PendingScript m_pendingScript; | 121 OwnPtrWillBePersistent<PendingScriptWrapper> m_pendingScript; |
89 }; | 122 }; |
90 | 123 |
91 class TestScriptResourceClient : public ScriptResourceClient { | 124 class TestScriptResourceClient : public ScriptResourceClient { |
92 public: | 125 public: |
93 TestScriptResourceClient() | 126 TestScriptResourceClient() |
94 : m_finished(false) { } | 127 : m_finished(false) { } |
95 | 128 |
96 virtual void notifyFinished(Resource*) OVERRIDE { m_finished = true; } | 129 virtual void notifyFinished(Resource*) OVERRIDE { m_finished = true; } |
97 | 130 |
98 bool finished() const { return m_finished; } | 131 bool finished() const { return m_finished; } |
99 | 132 |
100 private: | 133 private: |
101 bool m_finished; | 134 bool m_finished; |
102 }; | 135 }; |
103 | 136 |
104 TEST_F(ScriptStreamingTest, CompilingStreamedScript) | 137 TEST_F(ScriptStreamingTest, CompilingStreamedScript) |
105 { | 138 { |
106 // Test that we can successfully compile a streamed script. | 139 // Test that we can successfully compile a streamed script. |
107 bool started = ScriptStreamer::startStreaming(m_pendingScript, m_settings.ge
t(), m_scope.scriptState()); | 140 bool started = ScriptStreamer::startStreaming(pendingScript(), m_settings.ge
t(), m_scope.scriptState()); |
108 TestScriptResourceClient client; | 141 TestScriptResourceClient client; |
109 m_pendingScript.watchForLoad(&client); | 142 pendingScript().watchForLoad(&client); |
110 EXPECT_TRUE(started); | 143 EXPECT_TRUE(started); |
111 | 144 |
112 appendData("function foo() {"); | 145 appendData("function foo() {"); |
113 appendPadding(); | 146 appendPadding(); |
114 appendData("return 5; }"); | 147 appendData("return 5; }"); |
115 appendPadding(); | 148 appendPadding(); |
116 appendData("foo();"); | 149 appendData("foo();"); |
117 EXPECT_FALSE(client.finished()); | 150 EXPECT_FALSE(client.finished()); |
118 finish(); | 151 finish(); |
119 | 152 |
120 // Process tasks on the main thread until the streaming background thread | 153 // Process tasks on the main thread until the streaming background thread |
121 // has completed its tasks. | 154 // has completed its tasks. |
122 processTasksUntilStreamingComplete(); | 155 processTasksUntilStreamingComplete(); |
123 EXPECT_TRUE(client.finished()); | 156 EXPECT_TRUE(client.finished()); |
124 bool errorOccurred = false; | 157 bool errorOccurred = false; |
125 ScriptSourceCode sourceCode = m_pendingScript.getSource(KURL(), errorOccurre
d); | 158 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre
d); |
126 EXPECT_FALSE(errorOccurred); | 159 EXPECT_FALSE(errorOccurred); |
127 EXPECT_TRUE(sourceCode.streamer()); | 160 EXPECT_TRUE(sourceCode.streamer()); |
128 v8::TryCatch tryCatch; | 161 v8::TryCatch tryCatch; |
129 v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, is
olate()); | 162 v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, is
olate()); |
130 EXPECT_FALSE(script.IsEmpty()); | 163 EXPECT_FALSE(script.IsEmpty()); |
131 EXPECT_FALSE(tryCatch.HasCaught()); | 164 EXPECT_FALSE(tryCatch.HasCaught()); |
132 } | 165 } |
133 | 166 |
134 TEST_F(ScriptStreamingTest, CompilingStreamedScriptWithParseError) | 167 TEST_F(ScriptStreamingTest, CompilingStreamedScriptWithParseError) |
135 { | 168 { |
136 // Test that scripts with parse errors are handled properly. In those cases, | 169 // Test that scripts with parse errors are handled properly. In those cases, |
137 // the V8 side typically finished before loading finishes: make sure we | 170 // the V8 side typically finished before loading finishes: make sure we |
138 // handle it gracefully. | 171 // handle it gracefully. |
139 bool started = ScriptStreamer::startStreaming(m_pendingScript, m_settings.ge
t(), m_scope.scriptState()); | 172 bool started = ScriptStreamer::startStreaming(pendingScript(), m_settings.ge
t(), m_scope.scriptState()); |
140 TestScriptResourceClient client; | 173 TestScriptResourceClient client; |
141 m_pendingScript.watchForLoad(&client); | 174 pendingScript().watchForLoad(&client); |
142 EXPECT_TRUE(started); | 175 EXPECT_TRUE(started); |
143 appendData("function foo() {"); | 176 appendData("function foo() {"); |
144 appendData("this is the part which will be a parse error"); | 177 appendData("this is the part which will be a parse error"); |
145 // V8 won't realize the parse error until it actually starts parsing the | 178 // V8 won't realize the parse error until it actually starts parsing the |
146 // script, and this happens only when its buffer is filled. | 179 // script, and this happens only when its buffer is filled. |
147 appendPadding(); | 180 appendPadding(); |
148 | 181 |
149 EXPECT_FALSE(client.finished()); | 182 EXPECT_FALSE(client.finished()); |
150 | 183 |
151 // Force the V8 side to finish before the loading. | 184 // Force the V8 side to finish before the loading. |
152 processTasksUntilStreamingComplete(); | 185 processTasksUntilStreamingComplete(); |
153 EXPECT_FALSE(client.finished()); | 186 EXPECT_FALSE(client.finished()); |
154 | 187 |
155 finish(); | 188 finish(); |
156 EXPECT_TRUE(client.finished()); | 189 EXPECT_TRUE(client.finished()); |
157 | 190 |
158 bool errorOccurred = false; | 191 bool errorOccurred = false; |
159 ScriptSourceCode sourceCode = m_pendingScript.getSource(KURL(), errorOccurre
d); | 192 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre
d); |
160 EXPECT_FALSE(errorOccurred); | 193 EXPECT_FALSE(errorOccurred); |
161 EXPECT_TRUE(sourceCode.streamer()); | 194 EXPECT_TRUE(sourceCode.streamer()); |
162 v8::TryCatch tryCatch; | 195 v8::TryCatch tryCatch; |
163 v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, is
olate()); | 196 v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, is
olate()); |
164 EXPECT_TRUE(script.IsEmpty()); | 197 EXPECT_TRUE(script.IsEmpty()); |
165 EXPECT_TRUE(tryCatch.HasCaught()); | 198 EXPECT_TRUE(tryCatch.HasCaught()); |
166 } | 199 } |
167 | 200 |
168 TEST_F(ScriptStreamingTest, CancellingStreaming) | 201 TEST_F(ScriptStreamingTest, CancellingStreaming) |
169 { | 202 { |
170 // Test that the upper layers (PendingScript and up) can be ramped down | 203 // Test that the upper layers (PendingScript and up) can be ramped down |
171 // while streaming is ongoing, and ScriptStreamer handles it gracefully. | 204 // while streaming is ongoing, and ScriptStreamer handles it gracefully. |
172 bool started = ScriptStreamer::startStreaming(m_pendingScript, m_settings.ge
t(), m_scope.scriptState()); | 205 bool started = ScriptStreamer::startStreaming(pendingScript(), m_settings.ge
t(), m_scope.scriptState()); |
173 TestScriptResourceClient client; | 206 TestScriptResourceClient client; |
174 m_pendingScript.watchForLoad(&client); | 207 pendingScript().watchForLoad(&client); |
175 EXPECT_TRUE(started); | 208 EXPECT_TRUE(started); |
176 appendData("function foo() {"); | 209 appendData("function foo() {"); |
177 | 210 |
178 // In general, we cannot control what the background thread is doing | 211 // In general, we cannot control what the background thread is doing |
179 // (whether it's parsing or waiting for more data). In this test, we have | 212 // (whether it's parsing or waiting for more data). In this test, we have |
180 // given it so little data that it's surely waiting for more. | 213 // given it so little data that it's surely waiting for more. |
181 | 214 |
182 // Simulate cancelling the network load (e.g., because the user navigated | 215 // Simulate cancelling the network load (e.g., because the user navigated |
183 // away). | 216 // away). |
184 EXPECT_FALSE(client.finished()); | 217 EXPECT_FALSE(client.finished()); |
185 m_pendingScript.stopWatchingForLoad(&client); | 218 pendingScript().stopWatchingForLoad(&client); |
186 m_pendingScript = PendingScript(); // This will destroy m_resource. | 219 m_pendingScript = PendingScriptWrapper::create(); // This will destroy m_res
ource. |
187 m_resource = 0; | 220 m_resource = 0; |
188 | 221 |
189 // The V8 side will complete too. This should not crash. We don't receive | 222 // The V8 side will complete too. This should not crash. We don't receive |
190 // any results from the streaming and the client doesn't get notified. | 223 // any results from the streaming and the client doesn't get notified. |
191 processTasksUntilStreamingComplete(); | 224 processTasksUntilStreamingComplete(); |
192 EXPECT_FALSE(client.finished()); | 225 EXPECT_FALSE(client.finished()); |
193 } | 226 } |
194 | 227 |
195 TEST_F(ScriptStreamingTest, SuppressingStreaming) | 228 TEST_F(ScriptStreamingTest, SuppressingStreaming) |
196 { | 229 { |
197 // If we notice during streaming that there is a code cache, streaming | 230 // If we notice during streaming that there is a code cache, streaming |
198 // is suppressed (V8 doesn't parse while the script is loading), and the | 231 // is suppressed (V8 doesn't parse while the script is loading), and the |
199 // upper layer (ScriptResourceClient) should get a notification when the | 232 // upper layer (ScriptResourceClient) should get a notification when the |
200 // script is loaded. | 233 // script is loaded. |
201 bool started = ScriptStreamer::startStreaming(m_pendingScript, m_settings.ge
t(), m_scope.scriptState()); | 234 bool started = ScriptStreamer::startStreaming(pendingScript(), m_settings.ge
t(), m_scope.scriptState()); |
202 TestScriptResourceClient client; | 235 TestScriptResourceClient client; |
203 m_pendingScript.watchForLoad(&client); | 236 pendingScript().watchForLoad(&client); |
204 EXPECT_TRUE(started); | 237 EXPECT_TRUE(started); |
205 appendData("function foo() {"); | 238 appendData("function foo() {"); |
206 appendPadding(); | 239 appendPadding(); |
207 | 240 |
208 m_resource->setCachedMetadata(V8ScriptRunner::tagForCodeCache(), "X", 1, Res
ource::CacheLocally); | 241 m_resource->setCachedMetadata(V8ScriptRunner::tagForCodeCache(), "X", 1, Res
ource::CacheLocally); |
209 | 242 |
210 appendPadding(); | 243 appendPadding(); |
211 finish(); | 244 finish(); |
212 processTasksUntilStreamingComplete(); | 245 processTasksUntilStreamingComplete(); |
213 EXPECT_TRUE(client.finished()); | 246 EXPECT_TRUE(client.finished()); |
214 | 247 |
215 bool errorOccurred = false; | 248 bool errorOccurred = false; |
216 ScriptSourceCode sourceCode = m_pendingScript.getSource(KURL(), errorOccurre
d); | 249 ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurre
d); |
217 EXPECT_FALSE(errorOccurred); | 250 EXPECT_FALSE(errorOccurred); |
218 // ScriptSourceCode doesn't refer to the streamer, since we have suppressed | 251 // ScriptSourceCode doesn't refer to the streamer, since we have suppressed |
219 // the streaming and resumed the non-streaming code path for script | 252 // the streaming and resumed the non-streaming code path for script |
220 // compilation. | 253 // compilation. |
221 EXPECT_FALSE(sourceCode.streamer()); | 254 EXPECT_FALSE(sourceCode.streamer()); |
222 } | 255 } |
223 | 256 |
224 } // namespace | 257 } // namespace |
225 | 258 |
226 } // namespace blink | 259 } // namespace blink |
OLD | NEW |