TEST_F(ScriptStreamingTest, SuppressingStreaming) { // If we notice during streaming that there is a code cache, streaming // is suppressed (V8 doesn't parse while the script is loading), and the // upper layer (ScriptResourceClient) should get a notification when the // script is loaded. ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.scriptState(), PendingScript::ParsingBlocking); TestScriptResourceClient client; pendingScript().watchForLoad(&client); appendData("function foo() {"); appendPadding(); m_resource->setCachedMetadata(V8ScriptRunner::tagForCodeCache(), "X", 1, Resource::CacheLocally); appendPadding(); finish(); processTasksUntilStreamingComplete(); EXPECT_TRUE(client.finished()); bool errorOccurred = false; ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurred); EXPECT_FALSE(errorOccurred); // ScriptSourceCode doesn't refer to the streamer, since we have suppressed // the streaming and resumed the non-streaming code path for script // compilation. EXPECT_FALSE(sourceCode.streamer()); }
TEST_F(ScriptStreamingTest, CompilingStreamedScript) { // Test that we can successfully compile a streamed script. ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.scriptState(), PendingScript::ParsingBlocking); TestScriptResourceClient client; pendingScript().watchForLoad(&client); appendData("function foo() {"); appendPadding(); appendData("return 5; }"); appendPadding(); appendData("foo();"); EXPECT_FALSE(client.finished()); finish(); // Process tasks on the main thread until the streaming background thread // has completed its tasks. processTasksUntilStreamingComplete(); EXPECT_TRUE(client.finished()); bool errorOccurred = false; ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurred); EXPECT_FALSE(errorOccurred); EXPECT_TRUE(sourceCode.streamer()); v8::TryCatch tryCatch; v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, isolate()); EXPECT_FALSE(script.IsEmpty()); EXPECT_FALSE(tryCatch.HasCaught()); }
TEST_F(ScriptStreamingTest, CompilingStreamedScriptWithParseError) { // Test that scripts with parse errors are handled properly. In those cases, // the V8 side typically finished before loading finishes: make sure we // handle it gracefully. ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.scriptState(), PendingScript::ParsingBlocking); TestScriptResourceClient client; pendingScript().watchForLoad(&client); appendData("function foo() {"); appendData("this is the part which will be a parse error"); // V8 won't realize the parse error until it actually starts parsing the // script, and this happens only when its buffer is filled. appendPadding(); EXPECT_FALSE(client.finished()); // Force the V8 side to finish before the loading. processTasksUntilStreamingComplete(); EXPECT_FALSE(client.finished()); finish(); EXPECT_TRUE(client.finished()); bool errorOccurred = false; ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurred); EXPECT_FALSE(errorOccurred); EXPECT_TRUE(sourceCode.streamer()); v8::TryCatch tryCatch; v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, isolate()); EXPECT_TRUE(script.IsEmpty()); EXPECT_TRUE(tryCatch.HasCaught()); }
TEST_F(ScriptStreamingTest, EmptyScripts) { // Empty scripts should also be streamed properly, that is, the upper layer // (ScriptResourceClient) should be notified when an empty script has been // loaded. ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.scriptState(), PendingScript::ParsingBlocking); TestScriptResourceClient client; pendingScript().watchForLoad(&client); // Finish the script without sending any data. finish(); // The finished notification should arrive immediately and not be cycled // through a background thread. EXPECT_TRUE(client.finished()); bool errorOccurred = false; ScriptSourceCode sourceCode = pendingScript().getSource(KURL(), errorOccurred); EXPECT_FALSE(errorOccurred); EXPECT_FALSE(sourceCode.streamer()); }
v8::MaybeLocal<v8::Script> V8ScriptRunner::compileScript(const ScriptSourceCode& source, v8::Isolate* isolate, AccessControlStatus corsStatus, V8CacheOptions cacheOptions) { if (source.source().length() >= v8::String::kMaxLength) { V8ThrowException::throwGeneralError(isolate, "Source file too large."); return v8::Local<v8::Script>(); } return compileScript(v8String(isolate, source.source()), source.url(), source.sourceMapUrl(), source.startPosition(), isolate, source.resource(), source.streamer(), source.resource() ? source.resource()->cacheHandler() : nullptr, corsStatus, cacheOptions); }