1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
// 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 ScriptStreamer_h
#define ScriptStreamer_h
#include "bindings/core/v8/ScriptStreamingMode.h"
#include "core/dom/PendingScript.h"
#include "wtf/RefCounted.h"
#include <v8.h>
namespace blink {
class PendingScript;
class Resource;
class ScriptResource;
class ScriptResourceClient;
class ScriptState;
class Settings;
class SourceStream;
// ScriptStreamer streams incomplete script data to V8 so that it can be parsed
// while it's loaded. PendingScript holds a reference to ScriptStreamer. At the
// moment, ScriptStreamer is only used for parser blocking scripts; this means
// that the Document stays stable and no other scripts are executing while we're
// streaming. It is possible, though, that Document and the PendingScript are
// destroyed while the streaming is in progress, and ScriptStreamer handles it
// gracefully.
class ScriptStreamer : public RefCounted<ScriptStreamer> {
WTF_MAKE_NONCOPYABLE(ScriptStreamer);
public:
// Launches a task (on a background thread) which will stream the given
// PendingScript into V8 as it loads. It's also possible that V8 cannot
// stream the given script; in that case this function returns
// false. Internally, this constructs a ScriptStreamer and attaches it to
// the PendingScript. Use ScriptStreamer::addClient to get notified when the
// streaming finishes.
static void startStreaming(PendingScript&, Settings*, ScriptState*, PendingScript::Type);
// Returns false if we cannot stream the given encoding.
static bool convertEncoding(const char* encodingName, v8::ScriptCompiler::StreamedSource::Encoding*);
bool isFinished() const
{
return m_loadingFinished && (m_parsingFinished || m_streamingSuppressed);
}
v8::ScriptCompiler::StreamedSource* source() { return m_source.get(); }
ScriptResource* resource() const { return m_resource; }
// Called when the script is not needed any more (e.g., loading was
// cancelled). After calling cancel, PendingScript can drop its reference to
// ScriptStreamer, and ScriptStreamer takes care of eventually deleting
// itself (after the V8 side has finished too).
void cancel();
// When the streaming is suppressed, the data is not given to V8, but
// ScriptStreamer still watches the resource load and notifies the upper
// layers when loading is finished. It is used in situations when we have
// started streaming but then we detect we don't want to stream (e.g., when
// we have the code cache for the script) and we still want to parse and
// execute it when it has finished loading.
void suppressStreaming();
bool streamingSuppressed() const { return m_streamingSuppressed; }
v8::ScriptCompiler::CompileOptions compileOptions() const
{
return m_compileOptions;
}
void addClient(ScriptResourceClient* client)
{
ASSERT(!m_client);
m_client = client;
notifyFinishedToClient();
}
void removeClient(ScriptResourceClient* client)
{
ASSERT(m_client == client);
m_client = 0;
}
// Called by PendingScript when data arrives from the network.
void notifyAppendData(ScriptResource*);
void notifyFinished(Resource*);
// Called by ScriptStreamingTask when it has streamed all data to V8 and V8
// has processed it.
void streamingCompleteOnBackgroundThread();
v8::ScriptCompiler::StreamedSource::Encoding encoding() const { return m_encoding; }
static void setSmallScriptThresholdForTesting(size_t threshold)
{
kSmallScriptThreshold = threshold;
}
static size_t smallScriptThreshold() { return kSmallScriptThreshold; }
private:
// Scripts whose first data chunk is smaller than this constant won't be
// streamed. Non-const for testing.
static size_t kSmallScriptThreshold;
ScriptStreamer(ScriptResource*, PendingScript::Type, ScriptStreamingMode, ScriptState*, v8::ScriptCompiler::CompileOptions);
void streamingComplete();
void notifyFinishedToClient();
bool shouldBlockMainThread() const
{
return m_scriptStreamingMode == ScriptStreamingModeAllPlusBlockParsingBlocking && m_scriptType == PendingScript::ParsingBlocking;
}
static const char* startedStreamingHistogramName(PendingScript::Type);
static bool startStreamingInternal(PendingScript&, Settings*, ScriptState*, PendingScript::Type);
// This pointer is weak. If PendingScript and its Resource are deleted
// before ScriptStreamer, PendingScript will notify ScriptStreamer of its
// deletion by calling cancel().
ScriptResource* m_resource;
// Whether ScriptStreamer is detached from the Resource. In those cases, the
// script data is not needed any more, and the client won't get notified
// when the loading and streaming are done.
bool m_detached;
SourceStream* m_stream;
OwnPtr<v8::ScriptCompiler::StreamedSource> m_source;
ScriptResourceClient* m_client;
bool m_loadingFinished; // Whether loading from the network 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.
bool m_haveEnoughDataForStreaming;
// Whether the script source code should be retrieved from the Resource
// instead of the ScriptStreamer; guarded by m_mutex.
bool m_streamingSuppressed;
// What kind of cached data V8 produces during streaming.
v8::ScriptCompiler::CompileOptions m_compileOptions;
RefPtr<ScriptState> m_scriptState;
// For recording metrics for different types of scripts separately.
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;
// Encoding of the streamed script. Saved for sanity checking purposes.
v8::ScriptCompiler::StreamedSource::Encoding m_encoding;
};
} // namespace blink
#endif // ScriptStreamer_h
|