17242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved.
27242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// Use of this source code is governed by a BSD-style license that can be
37242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// found in the LICENSE file.
47242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
57242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#ifndef ScriptStreamer_h
67242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#define ScriptStreamer_h
77242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
87242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "core/dom/PendingScript.h"
97242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include "wtf/RefCounted.h"
107242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
117242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#include <v8.h>
127242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
137242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccinamespace blink {
147242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
157242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciclass PendingScript;
167242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciclass Resource;
177242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciclass ScriptResource;
187242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciclass ScriptResourceClient;
197242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciclass ScriptState;
207242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciclass Settings;
217242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciclass SourceStream;
227242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
237242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// ScriptStreamer streams incomplete script data to V8 so that it can be parsed
247242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// while it's loaded. PendingScript holds a reference to ScriptStreamer. At the
257242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// moment, ScriptStreamer is only used for parser blocking scripts; this means
267242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// that the Document stays stable and no other scripts are executing while we're
277242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// streaming. It is possible, though, that Document and the PendingScript are
287242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// destroyed while the streaming is in progress, and ScriptStreamer handles it
297242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci// gracefully.
307242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciclass ScriptStreamer : public RefCounted<ScriptStreamer> {
317242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    WTF_MAKE_NONCOPYABLE(ScriptStreamer);
327242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tuccipublic:
337242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // Launches a task (on a background thread) which will stream the given
347242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // PendingScript into V8 as it loads. It's also possible that V8 cannot
357242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // stream the given script; in that case this function returns
367242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // false. Internally, this constructs a ScriptStreamer and attaches it to
377242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // the PendingScript. Use ScriptStreamer::addClient to get notified when the
387242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // streaming finishes.
397242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    static void startStreaming(PendingScript&, Settings*, ScriptState*, PendingScript::Type);
407242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
417242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    bool isFinished() const
427242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    {
437242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        return m_loadingFinished && (m_parsingFinished || m_streamingSuppressed);
447242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    }
457242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
467242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    v8::ScriptCompiler::StreamedSource* source() { return &m_source; }
477242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    ScriptResource* resource() const { return m_resource; }
487242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
497242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // Called when the script is not needed any more (e.g., loading was
507242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // cancelled). After calling cancel, PendingScript can drop its reference to
517242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // ScriptStreamer, and ScriptStreamer takes care of eventually deleting
527242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // itself (after the V8 side has finished too).
537242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    void cancel();
547242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
557242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // When the streaming is suppressed, the data is not given to V8, but
567242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // ScriptStreamer still watches the resource load and notifies the upper
577242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // layers when loading is finished. It is used in situations when we have
587242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // started streaming but then we detect we don't want to stream (e.g., when
597242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // we have the code cache for the script) and we still want to parse and
607242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // execute it when it has finished loading.
617242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    void suppressStreaming();
627242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    bool streamingSuppressed() const { return m_streamingSuppressed; }
637242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
647242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    unsigned cachedDataType() const { return m_cachedDataType; }
657242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
667242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    void addClient(ScriptResourceClient* client)
677242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    {
687242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        ASSERT(!m_client);
697242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        ASSERT(!isFinished());
707242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        m_client = client;
717242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    }
727242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
737242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    void removeClient(ScriptResourceClient* client)
747242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    {
757242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        ASSERT(m_client == client);
767242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        m_client = 0;
777242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    }
787242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
797242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // Called by PendingScript when data arrives from the network.
807242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    void notifyAppendData(ScriptResource*);
817242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    void notifyFinished(Resource*);
827242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
837242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // Called by ScriptStreamingTask when it has streamed all data to V8 and V8
847242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // has processed it.
857242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    void streamingComplete();
867242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
877242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    static void removeSmallScriptThresholdForTesting()
887242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    {
897242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci        kSmallScriptThreshold = 0;
907242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    }
917242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
927242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    static size_t smallScriptThreshold() { return kSmallScriptThreshold; }
937242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
947242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucciprivate:
957242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // Scripts whose first data chunk is smaller than this constant won't be
967242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // streamed. Non-const for testing.
977242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    static size_t kSmallScriptThreshold;
987242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
997242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    ScriptStreamer(ScriptResource*, v8::ScriptCompiler::StreamedSource::Encoding, PendingScript::Type);
1007242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1017242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    void notifyFinishedToClient();
1027242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1037242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    static const char* startedStreamingHistogramName(PendingScript::Type);
1047242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1057242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    static bool startStreamingInternal(PendingScript&, Settings*, ScriptState*, PendingScript::Type);
1067242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1077242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // This pointer is weak. If PendingScript and its Resource are deleted
1087242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // before ScriptStreamer, PendingScript will notify ScriptStreamer of its
1097242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // deletion by calling cancel().
1107242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    ScriptResource* m_resource;
1117242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // Whether ScriptStreamer is detached from the Resource. In those cases, the
1127242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // script data is not needed any more, and the client won't get notified
1137242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // when the loading and streaming are done.
1147242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    bool m_detached;
1157242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1167242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    SourceStream* m_stream;
1177242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    v8::ScriptCompiler::StreamedSource m_source;
1187242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    ScriptResourceClient* m_client;
1197242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    v8::ScriptCompiler::ScriptStreamingTask* m_task;
1207242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    bool m_loadingFinished; // Whether loading from the network is done.
1217242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    bool m_parsingFinished; // Whether the V8 side processing is done.
1227242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    bool m_firstDataChunkReceived;
1237242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1247242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // Whether the script source code should be retrieved from the Resource
1257242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // instead of the ScriptStreamer.
1267242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    bool m_streamingSuppressed;
1277242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1287242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // What kind of cached data V8 produces during streaming.
1297242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    unsigned m_cachedDataType;
1307242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1317242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    // For recording metrics for different types of scripts separately.
1327242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci    PendingScript::Type m_scriptType;
1337242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci};
1347242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1357242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci} // namespace blink
1367242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci
1377242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci#endif // ScriptStreamer_h
138