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