Commit dc836462 authored by marja@chromium.org's avatar marja@chromium.org

Reland: Script streaming: Add an option to make the main thread block (wait for parsing)

This makes the main thread block and wait for the parser thread when all the
script data has arrived. The goal is to ensure that the script (which can now be
compiled) will get the main thread's attention as soon as possible.

This feature is temporary: The usefulness of blocking will be evaluated with
Finch, and this option will be removed (blocking will be always enabled or never
enabled, based on which option turns out to be better).

Previous version: https://codereview.chromium.org/651163002/

R=haraken@chromium.org
BUG=

Review URL: https://codereview.chromium.org/674133002

git-svn-id: svn://svn.chromium.org/blink/trunk@184361 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent af176916
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "core/fetch/ScriptResource.h" #include "core/fetch/ScriptResource.h"
#include "core/frame/Settings.h" #include "core/frame/Settings.h"
#include "platform/SharedBuffer.h" #include "platform/SharedBuffer.h"
#include "platform/TraceEvent.h"
#include "public/platform/Platform.h" #include "public/platform/Platform.h"
#include "wtf/MainThread.h" #include "wtf/MainThread.h"
#include "wtf/text/TextEncodingRegistry.h" #include "wtf/text/TextEncodingRegistry.h"
...@@ -224,28 +225,23 @@ void ScriptStreamer::startStreaming(PendingScript& script, Settings* settings, S ...@@ -224,28 +225,23 @@ void ScriptStreamer::startStreaming(PendingScript& script, Settings* settings, S
blink::Platform::current()->histogramEnumeration(startedStreamingHistogramName(scriptType), 0, 2); blink::Platform::current()->histogramEnumeration(startedStreamingHistogramName(scriptType), 0, 2);
} }
void ScriptStreamer::streamingComplete() void ScriptStreamer::streamingCompleteOnBackgroundThread()
{ {
ASSERT(isMainThread()); ASSERT(!isMainThread());
// It's possible that the corresponding Resource was deleted before V8 MutexLocker locker(m_mutex);
// finished streaming. In that case, the data or the notification is not
// needed. In addition, if the streaming is suppressed, the non-streaming
// code path will resume after the resource has loaded, before the
// background task finishes.
if (m_detached || m_streamingSuppressed) {
deref();
return;
}
// We have now streamed the whole script to V8 and it has parsed the
// script. We're ready for the next step: compiling and executing the
// script.
m_parsingFinished = true; m_parsingFinished = true;
// In the blocking case, the main thread is normally waiting at this
notifyFinishedToClient(); // point, but it can also happen that the load is not yet finished
// (e.g., a parse error). In that case, notifyFinished will be called
// The background thread no longer holds an implicit reference. // eventually and it will not wait on m_parsingFinishedCondition.
deref();
// In the non-blocking case, notifyFinished might already be called, or it
// might be called in the future. In any case, do the cleanup here.
if (m_mainThreadWaitingForParserThread) {
m_parsingFinishedCondition.signal();
} else {
callOnMainThread(WTF::bind(&ScriptStreamer::streamingComplete, this));
}
} }
void ScriptStreamer::cancel() void ScriptStreamer::cancel()
...@@ -262,8 +258,10 @@ void ScriptStreamer::cancel() ...@@ -262,8 +258,10 @@ void ScriptStreamer::cancel()
void ScriptStreamer::suppressStreaming() void ScriptStreamer::suppressStreaming()
{ {
ASSERT(!m_parsingFinished); MutexLocker locker(m_mutex);
ASSERT(!m_loadingFinished); ASSERT(!m_loadingFinished);
// It can be that the parsing task has already finished (e.g., if there was
// a parse error).
m_streamingSuppressed = true; m_streamingSuppressed = true;
} }
...@@ -271,8 +269,11 @@ void ScriptStreamer::notifyAppendData(ScriptResource* resource) ...@@ -271,8 +269,11 @@ void ScriptStreamer::notifyAppendData(ScriptResource* resource)
{ {
ASSERT(isMainThread()); ASSERT(isMainThread());
ASSERT(m_resource == resource); ASSERT(m_resource == resource);
if (m_streamingSuppressed) {
return; MutexLocker locker(m_mutex);
if (m_streamingSuppressed)
return;
}
if (!m_haveEnoughDataForStreaming) { if (!m_haveEnoughDataForStreaming) {
// Even if the first data chunk is small, the script can still be big // Even if the first data chunk is small, the script can still be big
// enough - wait until the next data chunk comes before deciding whether // enough - wait until the next data chunk comes before deciding whether
...@@ -294,7 +295,8 @@ void ScriptStreamer::notifyAppendData(ScriptResource* resource) ...@@ -294,7 +295,8 @@ void ScriptStreamer::notifyAppendData(ScriptResource* resource)
ASSERT(m_task); ASSERT(m_task);
// ScriptStreamer needs to stay alive as long as the background task is // ScriptStreamer needs to stay alive as long as the background task is
// running. This is taken care of with a manual ref() & deref() pair; // running. This is taken care of with a manual ref() & deref() pair;
// the corresponding deref() is in streamingComplete. // the corresponding deref() is in streamingComplete or in
// notifyFinished.
ref(); ref();
ScriptStreamingTask* task = new ScriptStreamingTask(m_task.release(), this); ScriptStreamingTask* task = new ScriptStreamingTask(m_task.release(), this);
ScriptStreamerThread::shared()->postTask(task); ScriptStreamerThread::shared()->postTask(task);
...@@ -318,10 +320,40 @@ void ScriptStreamer::notifyFinished(Resource* resource) ...@@ -318,10 +320,40 @@ void ScriptStreamer::notifyFinished(Resource* resource)
} }
m_stream->didFinishLoading(); m_stream->didFinishLoading();
m_loadingFinished = true; m_loadingFinished = true;
if (shouldBlockMainThread()) {
// Make the main thead wait until the streaming is complete, to make
// sure that the script gets the main thread's attention as early as
// possible (for possible compiling, if the client wants to do it
// right away). Note that blocking here is not any worse than the
// non-streaming code path where the main thread eventually blocks
// to parse the script.
TRACE_EVENT0("v8", "v8.mainThreadWaitingForParserThread");
MutexLocker locker(m_mutex);
while (!isFinished()) {
ASSERT(!m_parsingFinished);
ASSERT(!m_streamingSuppressed);
m_mainThreadWaitingForParserThread = true;
m_parsingFinishedCondition.wait(m_mutex);
}
}
// Calling notifyFinishedToClient can result into the upper layers dropping
// references to ScriptStreamer. Keep it alive until this function ends.
RefPtr<ScriptStreamer> protect(this);
notifyFinishedToClient(); notifyFinishedToClient();
if (m_mainThreadWaitingForParserThread) {
ASSERT(m_parsingFinished);
ASSERT(!m_streamingSuppressed);
// streamingComplete won't be called, so do the ramp-down work
// here.
deref();
}
} }
ScriptStreamer::ScriptStreamer(ScriptResource* resource, v8::ScriptCompiler::StreamedSource::Encoding encoding, PendingScript::Type scriptType) ScriptStreamer::ScriptStreamer(ScriptResource* resource, v8::ScriptCompiler::StreamedSource::Encoding encoding, PendingScript::Type scriptType, ScriptStreamingMode mode)
: m_resource(resource) : m_resource(resource)
, m_detached(false) , m_detached(false)
, m_stream(new SourceStream(this)) , m_stream(new SourceStream(this))
...@@ -332,7 +364,34 @@ ScriptStreamer::ScriptStreamer(ScriptResource* resource, v8::ScriptCompiler::Str ...@@ -332,7 +364,34 @@ ScriptStreamer::ScriptStreamer(ScriptResource* resource, v8::ScriptCompiler::Str
, m_haveEnoughDataForStreaming(false) , m_haveEnoughDataForStreaming(false)
, m_streamingSuppressed(false) , m_streamingSuppressed(false)
, m_scriptType(scriptType) , m_scriptType(scriptType)
, m_scriptStreamingMode(mode)
, m_mainThreadWaitingForParserThread(false)
{
}
void ScriptStreamer::streamingComplete()
{ {
// The background task is completed; do the necessary ramp-down in the main
// thread.
ASSERT(isMainThread());
// It's possible that the corresponding Resource was deleted before V8
// finished streaming. In that case, the data or the notification is not
// needed. In addition, if the streaming is suppressed, the non-streaming
// code path will resume after the resource has loaded, before the
// background task finishes.
if (m_detached || m_streamingSuppressed) {
deref();
return;
}
// We have now streamed the whole script to V8 and it has parsed the
// script. We're ready for the next step: compiling and executing the
// script.
notifyFinishedToClient();
// The background thread no longer holds an implicit reference.
deref();
} }
void ScriptStreamer::notifyFinishedToClient() void ScriptStreamer::notifyFinishedToClient()
...@@ -346,7 +405,12 @@ void ScriptStreamer::notifyFinishedToClient() ...@@ -346,7 +405,12 @@ void ScriptStreamer::notifyFinishedToClient()
// function calling notifyFinishedToClient was already scheduled in the task // function calling notifyFinishedToClient was already scheduled in the task
// queue and the upper layer decided that it's not interested in the script // queue and the upper layer decided that it's not interested in the script
// and called removeClient. // and called removeClient.
if (isFinished() && m_client) {
MutexLocker locker(m_mutex);
if (!isFinished())
return;
}
if (m_client)
m_client->notifyFinished(m_resource); m_client->notifyFinished(m_resource);
} }
...@@ -374,6 +438,10 @@ bool ScriptStreamer::startStreamingInternal(PendingScript& script, Settings* set ...@@ -374,6 +438,10 @@ bool ScriptStreamer::startStreamingInternal(PendingScript& script, Settings* set
ASSERT(isMainThread()); ASSERT(isMainThread());
if (!settings || !settings->v8ScriptStreamingEnabled()) if (!settings || !settings->v8ScriptStreamingEnabled())
return false; return false;
if (settings->v8ScriptStreamingMode() == ScriptStreamingModeOnlyAsyncAndDefer
&& scriptType == PendingScript::ParsingBlocking)
return false;
ScriptResource* resource = script.resource(); ScriptResource* resource = script.resource();
ASSERT(!resource->isLoaded()); ASSERT(!resource->isLoaded());
if (!resource->url().protocolIsInHTTPFamily()) if (!resource->url().protocolIsInHTTPFamily())
...@@ -415,7 +483,7 @@ bool ScriptStreamer::startStreamingInternal(PendingScript& script, Settings* set ...@@ -415,7 +483,7 @@ bool ScriptStreamer::startStreamingInternal(PendingScript& script, Settings* set
// The Resource might go out of scope if the script is no longer needed. We // The Resource might go out of scope if the script is no longer needed. We
// will soon call PendingScript::setStreamer, which makes the PendingScript // will soon call PendingScript::setStreamer, which makes the PendingScript
// notify the ScriptStreamer when it is destroyed. // notify the ScriptStreamer when it is destroyed.
RefPtr<ScriptStreamer> streamer = adoptRef(new ScriptStreamer(resource, encoding, scriptType)); RefPtr<ScriptStreamer> streamer = adoptRef(new ScriptStreamer(resource, encoding, scriptType, settings->v8ScriptStreamingMode()));
// Decide what kind of cached data we should produce while streaming. By // Decide what kind of cached data we should produce while streaming. By
// default, we generate the parser cache for streamed scripts, to emulate // default, we generate the parser cache for streamed scripts, to emulate
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef ScriptStreamer_h #ifndef ScriptStreamer_h
#define ScriptStreamer_h #define ScriptStreamer_h
#include "bindings/core/v8/ScriptStreamingMode.h"
#include "core/dom/PendingScript.h" #include "core/dom/PendingScript.h"
#include "wtf/RefCounted.h" #include "wtf/RefCounted.h"
...@@ -82,7 +83,7 @@ public: ...@@ -82,7 +83,7 @@ public:
// Called by ScriptStreamingTask when it has streamed all data to V8 and V8 // Called by ScriptStreamingTask when it has streamed all data to V8 and V8
// has processed it. // has processed it.
void streamingComplete(); void streamingCompleteOnBackgroundThread();
static void setSmallScriptThresholdForTesting(size_t threshold) static void setSmallScriptThresholdForTesting(size_t threshold)
{ {
...@@ -96,10 +97,16 @@ private: ...@@ -96,10 +97,16 @@ private:
// streamed. Non-const for testing. // streamed. Non-const for testing.
static size_t kSmallScriptThreshold; static size_t kSmallScriptThreshold;
ScriptStreamer(ScriptResource*, v8::ScriptCompiler::StreamedSource::Encoding, PendingScript::Type); ScriptStreamer(ScriptResource*, v8::ScriptCompiler::StreamedSource::Encoding, PendingScript::Type, ScriptStreamingMode);
void streamingComplete();
void notifyFinishedToClient(); void notifyFinishedToClient();
bool shouldBlockMainThread() const
{
return m_scriptStreamingMode == ScriptStreamingModeAllPlusBlockParsingBlocking && m_scriptType == PendingScript::ParsingBlocking;
}
static const char* startedStreamingHistogramName(PendingScript::Type); static const char* startedStreamingHistogramName(PendingScript::Type);
static bool startStreamingInternal(PendingScript&, Settings*, ScriptState*, PendingScript::Type); static bool startStreamingInternal(PendingScript&, Settings*, ScriptState*, PendingScript::Type);
...@@ -118,12 +125,14 @@ private: ...@@ -118,12 +125,14 @@ private:
ScriptResourceClient* m_client; ScriptResourceClient* m_client;
WTF::OwnPtr<v8::ScriptCompiler::ScriptStreamingTask> m_task; WTF::OwnPtr<v8::ScriptCompiler::ScriptStreamingTask> m_task;
bool m_loadingFinished; // Whether loading from the network is done. bool m_loadingFinished; // Whether loading from the network is done.
bool m_parsingFinished; // Whether the V8 side processing is done. // Whether the V8 side processing is done. Will be used by the main thread
// and the streamer thread; guarded by m_mutex.
bool m_parsingFinished;
// Whether we have received enough data to start the streaming. // Whether we have received enough data to start the streaming.
bool m_haveEnoughDataForStreaming; bool m_haveEnoughDataForStreaming;
// Whether the script source code should be retrieved from the Resource // Whether the script source code should be retrieved from the Resource
// instead of the ScriptStreamer. // instead of the ScriptStreamer; guarded by m_mutex.
bool m_streamingSuppressed; bool m_streamingSuppressed;
// What kind of cached data V8 produces during streaming. // What kind of cached data V8 produces during streaming.
...@@ -131,6 +140,18 @@ private: ...@@ -131,6 +140,18 @@ private:
// For recording metrics for different types of scripts separately. // For recording metrics for different types of scripts separately.
PendingScript::Type m_scriptType; PendingScript::Type m_scriptType;
// Streaming mode defines whether the main thread should block and wait for
// the parsing to complete after the load has finished. See
// ScriptStreamer::notifyFinished for more information.
ScriptStreamingMode m_scriptStreamingMode;
Mutex m_mutex;
ThreadCondition m_parsingFinishedCondition;
// Whether the main thread is currently waiting on the parser thread in
// notifyFinished(). This also defines which thread should do the cleanup of
// the parsing task: if the main thread is waiting, the main thread should
// do it, otherwise the parser thread should do it. Guarded by m_mutex.
bool m_mainThreadWaitingForParserThread;
}; };
} // namespace blink } // namespace blink
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "bindings/core/v8/ScriptSourceCode.h" #include "bindings/core/v8/ScriptSourceCode.h"
#include "bindings/core/v8/ScriptStreamerThread.h" #include "bindings/core/v8/ScriptStreamerThread.h"
#include "bindings/core/v8/ScriptStreamingMode.h"
#include "bindings/core/v8/V8Binding.h" #include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8ScriptRunner.h" #include "bindings/core/v8/V8ScriptRunner.h"
#include "core/dom/PendingScript.h" #include "core/dom/PendingScript.h"
...@@ -58,7 +59,9 @@ private: ...@@ -58,7 +59,9 @@ private:
PendingScript m_pendingScript; PendingScript m_pendingScript;
}; };
class ScriptStreamingTest : public testing::Test { // The bool param for ScriptStreamingTest controls whether to make the main
// thread block and wait for parsing.
class ScriptStreamingTest : public testing::TestWithParam<bool> {
public: public:
ScriptStreamingTest() ScriptStreamingTest()
: m_scope(v8::Isolate::GetCurrent()) : m_scope(v8::Isolate::GetCurrent())
...@@ -68,6 +71,8 @@ public: ...@@ -68,6 +71,8 @@ public:
, m_pendingScript(PendingScriptWrapper::create(0, m_resource)) // Takes ownership of m_resource. , m_pendingScript(PendingScriptWrapper::create(0, m_resource)) // Takes ownership of m_resource.
{ {
m_settings->setV8ScriptStreamingEnabled(true); m_settings->setV8ScriptStreamingEnabled(true);
if (GetParam())
m_settings->setV8ScriptStreamingMode(ScriptStreamingModeAllPlusBlockParsingBlocking);
m_resource->setLoading(true); m_resource->setLoading(true);
ScriptStreamer::setSmallScriptThresholdForTesting(0); ScriptStreamer::setSmallScriptThresholdForTesting(0);
} }
...@@ -140,7 +145,7 @@ private: ...@@ -140,7 +145,7 @@ private:
bool m_finished; bool m_finished;
}; };
TEST_F(ScriptStreamingTest, CompilingStreamedScript) TEST_P(ScriptStreamingTest, CompilingStreamedScript)
{ {
// Test that we can successfully compile a streamed script. // Test that we can successfully compile a streamed script.
ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.scriptState(), PendingScript::ParsingBlocking); ScriptStreamer::startStreaming(pendingScript(), m_settings.get(), m_scope.scriptState(), PendingScript::ParsingBlocking);
...@@ -169,7 +174,7 @@ TEST_F(ScriptStreamingTest, CompilingStreamedScript) ...@@ -169,7 +174,7 @@ TEST_F(ScriptStreamingTest, CompilingStreamedScript)
EXPECT_FALSE(tryCatch.HasCaught()); EXPECT_FALSE(tryCatch.HasCaught());
} }
TEST_F(ScriptStreamingTest, CompilingStreamedScriptWithParseError) TEST_P(ScriptStreamingTest, CompilingStreamedScriptWithParseError)
{ {
// Test that scripts with parse errors are handled properly. In those cases, // Test that scripts with parse errors are handled properly. In those cases,
// the V8 side typically finished before loading finishes: make sure we // the V8 side typically finished before loading finishes: make sure we
...@@ -202,7 +207,7 @@ TEST_F(ScriptStreamingTest, CompilingStreamedScriptWithParseError) ...@@ -202,7 +207,7 @@ TEST_F(ScriptStreamingTest, CompilingStreamedScriptWithParseError)
EXPECT_TRUE(tryCatch.HasCaught()); EXPECT_TRUE(tryCatch.HasCaught());
} }
TEST_F(ScriptStreamingTest, CancellingStreaming) TEST_P(ScriptStreamingTest, CancellingStreaming)
{ {
// Test that the upper layers (PendingScript and up) can be ramped down // Test that the upper layers (PendingScript and up) can be ramped down
// while streaming is ongoing, and ScriptStreamer handles it gracefully. // while streaming is ongoing, and ScriptStreamer handles it gracefully.
...@@ -229,7 +234,7 @@ TEST_F(ScriptStreamingTest, CancellingStreaming) ...@@ -229,7 +234,7 @@ TEST_F(ScriptStreamingTest, CancellingStreaming)
EXPECT_FALSE(client.finished()); EXPECT_FALSE(client.finished());
} }
TEST_F(ScriptStreamingTest, SuppressingStreaming) TEST_P(ScriptStreamingTest, SuppressingStreaming)
{ {
// If we notice during streaming that there is a code cache, streaming // 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 // is suppressed (V8 doesn't parse while the script is loading), and the
...@@ -257,7 +262,7 @@ TEST_F(ScriptStreamingTest, SuppressingStreaming) ...@@ -257,7 +262,7 @@ TEST_F(ScriptStreamingTest, SuppressingStreaming)
EXPECT_FALSE(sourceCode.streamer()); EXPECT_FALSE(sourceCode.streamer());
} }
TEST_F(ScriptStreamingTest, EmptyScripts) TEST_P(ScriptStreamingTest, EmptyScripts)
{ {
// Empty scripts should also be streamed properly, that is, the upper layer // Empty scripts should also be streamed properly, that is, the upper layer
// (ScriptResourceClient) should be notified when an empty script has been // (ScriptResourceClient) should be notified when an empty script has been
...@@ -278,7 +283,7 @@ TEST_F(ScriptStreamingTest, EmptyScripts) ...@@ -278,7 +283,7 @@ TEST_F(ScriptStreamingTest, EmptyScripts)
EXPECT_FALSE(sourceCode.streamer()); EXPECT_FALSE(sourceCode.streamer());
} }
TEST_F(ScriptStreamingTest, SmallScripts) TEST_P(ScriptStreamingTest, SmallScripts)
{ {
// Small scripts shouldn't be streamed. // Small scripts shouldn't be streamed.
ScriptStreamer::setSmallScriptThresholdForTesting(100); ScriptStreamer::setSmallScriptThresholdForTesting(100);
...@@ -301,7 +306,7 @@ TEST_F(ScriptStreamingTest, SmallScripts) ...@@ -301,7 +306,7 @@ TEST_F(ScriptStreamingTest, SmallScripts)
EXPECT_FALSE(sourceCode.streamer()); EXPECT_FALSE(sourceCode.streamer());
} }
TEST_F(ScriptStreamingTest, ScriptsWithSmallFirstChunk) TEST_P(ScriptStreamingTest, ScriptsWithSmallFirstChunk)
{ {
// If a script is long enough, if should be streamed, even if the first data // If a script is long enough, if should be streamed, even if the first data
// chunk is small. // chunk is small.
...@@ -331,6 +336,8 @@ TEST_F(ScriptStreamingTest, ScriptsWithSmallFirstChunk) ...@@ -331,6 +336,8 @@ TEST_F(ScriptStreamingTest, ScriptsWithSmallFirstChunk)
EXPECT_FALSE(tryCatch.HasCaught()); EXPECT_FALSE(tryCatch.HasCaught());
} }
INSTANTIATE_TEST_CASE_P(ScriptStreamingInstantiation, ScriptStreamingTest, ::testing::Values(false, true));
} // namespace } // namespace
} // namespace blink } // namespace blink
...@@ -67,9 +67,7 @@ void ScriptStreamingTask::run() ...@@ -67,9 +67,7 @@ void ScriptStreamingTask::run()
// Running the task can and will block: SourceStream::GetSomeData will get // Running the task can and will block: SourceStream::GetSomeData will get
// called and it will block and wait for data from the network. // called and it will block and wait for data from the network.
m_v8Task->Run(); m_v8Task->Run();
// Post a task to the main thread to signal that V8 has completed the m_streamer->streamingCompleteOnBackgroundThread();
// streaming.
callOnMainThread(WTF::bind(&ScriptStreamer::streamingComplete, m_streamer));
ScriptStreamerThread::shared()->taskDone(); ScriptStreamerThread::shared()->taskDone();
} }
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ScriptStreamingMode_h
#define ScriptStreamingMode_h
// ScriptStreamingModes are used for evaluating different heuristics for when we
// should start streaming.
namespace blink {
enum ScriptStreamingMode {
// Stream all scripts
ScriptStreamingModeAll,
// Stream only async and deferred scripts
ScriptStreamingModeOnlyAsyncAndDefer,
// Stream all scripts, block the main thread after loading when streaming
// parser blocking scripts.
ScriptStreamingModeAllPlusBlockParsingBlocking
};
} // namespace blink
#endif // ScriptStreamingMode_h
...@@ -90,6 +90,7 @@ ...@@ -90,6 +90,7 @@
'ScriptStreamer.h', 'ScriptStreamer.h',
'ScriptStreamerThread.cpp', 'ScriptStreamerThread.cpp',
'ScriptStreamerThread.h', 'ScriptStreamerThread.h',
'ScriptStreamingMode.h',
'ScriptString.cpp', 'ScriptString.cpp',
'ScriptString.h', 'ScriptString.h',
'ScriptValue.cpp', 'ScriptValue.cpp',
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#ifndef Settings_h #ifndef Settings_h
#define Settings_h #define Settings_h
#include "bindings/core/v8/ScriptStreamingMode.h"
#include "bindings/core/v8/V8CacheOptions.h" #include "bindings/core/v8/V8CacheOptions.h"
#include "core/SettingsMacros.h" #include "core/SettingsMacros.h"
#include "core/css/PointerProperties.h" #include "core/css/PointerProperties.h"
......
...@@ -281,6 +281,7 @@ fullscreenSupported initial=true ...@@ -281,6 +281,7 @@ fullscreenSupported initial=true
v8CacheOptions type=V8CacheOptions, initial=V8CacheOptionsOff v8CacheOptions type=V8CacheOptions, initial=V8CacheOptionsOff
v8ScriptStreamingEnabled initial=false v8ScriptStreamingEnabled initial=false
v8ScriptStreamingMode type=ScriptStreamingMode, initial=ScriptStreamingModeAll
# These values are bit fields for the properties of available pointing devices # These values are bit fields for the properties of available pointing devices
# and may take on multiple values (e.g. laptop with touchpad and touchscreen # and may take on multiple values (e.g. laptop with touchpad and touchscreen
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment