Commit 04f065d8 authored by droger's avatar droger Committed by Commit bot

Renderer-side changes for NoState Prefetch

NoState Prefetch design doc:
https://docs.google.com/document/d/16VCYGGWau483IMSxODpg5faZny1FJ6vNK2v-BuM5EhU

This CL is the first step for NoState Prefetch implementation
in the renderer.

The code added in this CL is not called yet (it will be called
only when the PREFETCH_ONLY enum is sent through IPC).

The prefetching is implemented in the HTMLDocumentParser.
When prefetching, the parser runs in single-thread mode.
When feeded with HTML input, it runs the preload scanner on
it, and stops without actually building or executing the page.

BUG=632361

Review-Url: https://codereview.chromium.org/2172613002
Cr-Commit-Position: refs/heads/master@{#414406}
parent 4cfb70c6
...@@ -170,7 +170,7 @@ void ChromeRenderFrameObserver::OnSetIsPrerendering( ...@@ -170,7 +170,7 @@ void ChromeRenderFrameObserver::OnSetIsPrerendering(
// The PrerenderHelper will destroy itself either after recording histograms // The PrerenderHelper will destroy itself either after recording histograms
// or on destruction of the RenderView. // or on destruction of the RenderView.
new prerender::PrerenderHelper(render_frame()); new prerender::PrerenderHelper(render_frame(), mode);
} }
} }
......
...@@ -34,18 +34,39 @@ void UpdateVisibilityState(content::RenderFrame* render_frame) { ...@@ -34,18 +34,39 @@ void UpdateVisibilityState(content::RenderFrame* render_frame) {
namespace prerender { namespace prerender {
PrerenderHelper::PrerenderHelper(content::RenderFrame* render_frame) PrerenderHelper::PrerenderHelper(content::RenderFrame* render_frame,
PrerenderMode prerender_mode)
: content::RenderFrameObserver(render_frame), : content::RenderFrameObserver(render_frame),
content::RenderFrameObserverTracker<PrerenderHelper>(render_frame) { content::RenderFrameObserverTracker<PrerenderHelper>(render_frame),
prerender_mode_(prerender_mode) {
DCHECK_NE(prerender_mode_, NO_PRERENDER);
UpdateVisibilityState(render_frame); UpdateVisibilityState(render_frame);
} }
PrerenderHelper::PrerenderHelper(content::RenderFrame* sub_frame)
: PrerenderHelper(sub_frame,
GetPrerenderMode(
sub_frame->GetRenderView()->GetMainRenderFrame())) {
DCHECK(!render_frame()->IsMainFrame());
}
PrerenderHelper::~PrerenderHelper() { PrerenderHelper::~PrerenderHelper() {
} }
// static. // static.
bool PrerenderHelper::IsPrerendering(const content::RenderFrame* render_frame) { bool PrerenderHelper::IsPrerendering(const content::RenderFrame* render_frame) {
return PrerenderHelper::Get(render_frame) != NULL; return PrerenderHelper::GetPrerenderMode(render_frame) != NO_PRERENDER;
}
// static.
PrerenderMode PrerenderHelper::GetPrerenderMode(
const content::RenderFrame* render_frame) {
PrerenderHelper* helper = PrerenderHelper::Get(render_frame);
if (!helper)
return NO_PRERENDER;
DCHECK_NE(helper->prerender_mode_, NO_PRERENDER);
return helper->prerender_mode_;
} }
bool PrerenderHelper::OnMessageReceived( bool PrerenderHelper::OnMessageReceived(
......
...@@ -20,12 +20,21 @@ class PrerenderHelper ...@@ -20,12 +20,21 @@ class PrerenderHelper
: public content::RenderFrameObserver, : public content::RenderFrameObserver,
public content::RenderFrameObserverTracker<PrerenderHelper> { public content::RenderFrameObserverTracker<PrerenderHelper> {
public: public:
explicit PrerenderHelper(content::RenderFrame* render_frame); PrerenderHelper(content::RenderFrame* render_frame,
PrerenderMode prerender_mode);
// Must be called on a sub-frame. Inherits the prerender mode from the main
// frame.
explicit PrerenderHelper(content::RenderFrame* sub_frame);
~PrerenderHelper() override; ~PrerenderHelper() override;
// Returns true if |render_view| is currently prerendering. // Returns true if |render_view| is currently prerendering.
static bool IsPrerendering(const content::RenderFrame* render_frame); static bool IsPrerendering(const content::RenderFrame* render_frame);
static PrerenderMode GetPrerenderMode(
const content::RenderFrame* render_frame);
private: private:
// RenderFrameObserver implementation. // RenderFrameObserver implementation.
bool OnMessageReceived(const IPC::Message& message) override; bool OnMessageReceived(const IPC::Message& message) override;
...@@ -33,6 +42,8 @@ class PrerenderHelper ...@@ -33,6 +42,8 @@ class PrerenderHelper
void OnSetIsPrerendering(PrerenderMode mode); void OnSetIsPrerendering(PrerenderMode mode);
PrerenderMode prerender_mode_;
DISALLOW_COPY_AND_ASSIGN(PrerenderHelper); DISALLOW_COPY_AND_ASSIGN(PrerenderHelper);
}; };
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "chrome/renderer/prerender/prerender_extra_data.h" #include "chrome/renderer/prerender/prerender_extra_data.h"
#include "chrome/renderer/prerender/prerender_helper.h"
#include "content/public/renderer/render_view.h" #include "content/public/renderer/render_view.h"
#include "third_party/WebKit/public/web/WebView.h" #include "third_party/WebKit/public/web/WebView.h"
...@@ -34,6 +35,11 @@ void PrerendererClient::willAddPrerender( ...@@ -34,6 +35,11 @@ void PrerendererClient::willAddPrerender(
render_view()->GetSize())); render_view()->GetSize()));
} }
bool PrerendererClient::isPrefetchOnly() {
return PrerenderHelper::GetPrerenderMode(
render_view()->GetMainRenderFrame()) == PREFETCH_ONLY;
}
void PrerendererClient::OnDestruct() { void PrerendererClient::OnDestruct() {
delete this; delete this;
} }
......
...@@ -24,6 +24,7 @@ class PrerendererClient : public content::RenderViewObserver, ...@@ -24,6 +24,7 @@ class PrerendererClient : public content::RenderViewObserver,
// Implements blink::WebPrerendererClient // Implements blink::WebPrerendererClient
void willAddPrerender(blink::WebPrerender* prerender) override; void willAddPrerender(blink::WebPrerender* prerender) override;
bool isPrefetchOnly() override;
}; };
} // namespace prerender } // namespace prerender
......
...@@ -4211,6 +4211,7 @@ ...@@ -4211,6 +4211,7 @@
'html/forms/StepRangeTest.cpp', 'html/forms/StepRangeTest.cpp',
'html/parser/AtomicHTMLTokenTest.cpp', 'html/parser/AtomicHTMLTokenTest.cpp',
'html/parser/CompactHTMLTokenTest.cpp', 'html/parser/CompactHTMLTokenTest.cpp',
'html/parser/HTMLDocumentParserTest.cpp',
'html/parser/HTMLEntityParserTest.cpp', 'html/parser/HTMLEntityParserTest.cpp',
'html/parser/HTMLParserIdiomsTest.cpp', 'html/parser/HTMLParserIdiomsTest.cpp',
'html/parser/HTMLParserThreadTest.cpp', 'html/parser/HTMLParserThreadTest.cpp',
......
...@@ -26,13 +26,14 @@ ...@@ -26,13 +26,14 @@
#ifndef DecodedDataDocumentParser_h #ifndef DecodedDataDocumentParser_h
#define DecodedDataDocumentParser_h #define DecodedDataDocumentParser_h
#include "core/CoreExport.h"
#include "core/dom/DocumentParser.h" #include "core/dom/DocumentParser.h"
#include <memory> #include <memory>
namespace blink { namespace blink {
class TextResourceDecoder; class TextResourceDecoder;
class DecodedDataDocumentParser : public DocumentParser { class CORE_EXPORT DecodedDataDocumentParser : public DocumentParser {
public: public:
// Only used by the XMLDocumentParser to communicate back to // Only used by the XMLDocumentParser to communicate back to
// XMLHttpRequest if the responseXML was well formed. // XMLHttpRequest if the responseXML was well formed.
......
...@@ -194,6 +194,7 @@ ...@@ -194,6 +194,7 @@
#include "core/loader/FrameLoaderClient.h" #include "core/loader/FrameLoaderClient.h"
#include "core/loader/ImageLoader.h" #include "core/loader/ImageLoader.h"
#include "core/loader/NavigationScheduler.h" #include "core/loader/NavigationScheduler.h"
#include "core/loader/PrerendererClient.h"
#include "core/loader/appcache/ApplicationCacheHost.h" #include "core/loader/appcache/ApplicationCacheHost.h"
#include "core/observer/ResizeObserverController.h" #include "core/observer/ResizeObserverController.h"
#include "core/page/ChromeClient.h" #include "core/page/ChromeClient.h"
...@@ -1326,6 +1327,15 @@ PageVisibilityState Document::pageVisibilityState() const ...@@ -1326,6 +1327,15 @@ PageVisibilityState Document::pageVisibilityState() const
return m_frame->page()->visibilityState(); return m_frame->page()->visibilityState();
} }
bool Document::isPrefetchOnly() const
{
if (!m_frame || !m_frame->page())
return false;
PrerendererClient* prerendererClient = PrerendererClient::from(m_frame->page());
return prerendererClient && prerendererClient->isPrefetchOnly();
}
String Document::visibilityState() const String Document::visibilityState() const
{ {
return pageVisibilityStateString(pageVisibilityState()); return pageVisibilityStateString(pageVisibilityState());
...@@ -2436,8 +2446,12 @@ DocumentParser* Document::implicitOpen(ParserSynchronizationPolicy parserSyncPol ...@@ -2436,8 +2446,12 @@ DocumentParser* Document::implicitOpen(ParserSynchronizationPolicy parserSyncPol
setCompatibilityMode(NoQuirksMode); setCompatibilityMode(NoQuirksMode);
if (!threadedParsingEnabledForTesting()) if (!threadedParsingEnabledForTesting()) {
parserSyncPolicy = ForceSynchronousParsing; parserSyncPolicy = ForceSynchronousParsing;
} else if (parserSyncPolicy == AllowAsynchronousParsing && isPrefetchOnly()) {
// Prefetch must be synchronous.
parserSyncPolicy = ForceSynchronousParsing;
}
m_parserSyncPolicy = parserSyncPolicy; m_parserSyncPolicy = parserSyncPolicy;
m_parser = createParser(); m_parser = createParser();
......
...@@ -355,6 +355,11 @@ public: ...@@ -355,6 +355,11 @@ public:
bool hidden() const; bool hidden() const;
void didChangeVisibilityState(); void didChangeVisibilityState();
// If the document is "prefetch only", it will not be fully contstructed,
// and should never be displayed. Only a few resources will be loaded and
// scanned, in order to warm up caches.
bool isPrefetchOnly() const;
Node* adoptNode(Node* source, ExceptionState&); Node* adoptNode(Node* source, ExceptionState&);
HTMLCollection* images(); HTMLCollection* images();
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#ifndef DocumentParser_h #ifndef DocumentParser_h
#define DocumentParser_h #define DocumentParser_h
#include "core/CoreExport.h"
#include "platform/heap/Handle.h" #include "platform/heap/Handle.h"
#include "wtf/Forward.h" #include "wtf/Forward.h"
#include <memory> #include <memory>
...@@ -36,7 +37,7 @@ class SegmentedString; ...@@ -36,7 +37,7 @@ class SegmentedString;
class ScriptableDocumentParser; class ScriptableDocumentParser;
class TextResourceDecoder; class TextResourceDecoder;
class DocumentParser : public GarbageCollectedFinalized<DocumentParser> { class CORE_EXPORT DocumentParser : public GarbageCollectedFinalized<DocumentParser> {
public: public:
virtual ~DocumentParser(); virtual ~DocumentParser();
DECLARE_VIRTUAL_TRACE(); DECLARE_VIRTUAL_TRACE();
......
...@@ -26,13 +26,14 @@ ...@@ -26,13 +26,14 @@
#ifndef ScriptableDocumentParser_h #ifndef ScriptableDocumentParser_h
#define ScriptableDocumentParser_h #define ScriptableDocumentParser_h
#include "core/CoreExport.h"
#include "core/dom/DecodedDataDocumentParser.h" #include "core/dom/DecodedDataDocumentParser.h"
#include "core/dom/ParserContentPolicy.h" #include "core/dom/ParserContentPolicy.h"
#include "wtf/text/TextPosition.h" #include "wtf/text/TextPosition.h"
namespace blink { namespace blink {
class ScriptableDocumentParser : public DecodedDataDocumentParser { class CORE_EXPORT ScriptableDocumentParser : public DecodedDataDocumentParser {
public: public:
// Only used by Document::open for deciding if its safe to act on a // Only used by Document::open for deciding if its safe to act on a
// JavaScript document.open() call right now, or it should be ignored. // JavaScript document.open() call right now, or it should be ignored.
......
...@@ -131,6 +131,9 @@ HTMLDocumentParser::HTMLDocumentParser(Document& document, ParserContentPolicy c ...@@ -131,6 +131,9 @@ HTMLDocumentParser::HTMLDocumentParser(Document& document, ParserContentPolicy c
, m_triedLoadingLinkHeaders(false) , m_triedLoadingLinkHeaders(false)
{ {
ASSERT(shouldUseThreading() || (m_token && m_tokenizer)); ASSERT(shouldUseThreading() || (m_token && m_tokenizer));
// Threading is not allowed in prefetch mode.
DCHECK(!document.isPrefetchOnly() || !shouldUseThreading());
ThreadState::current()->registerPreFinalizer(this); ThreadState::current()->registerPreFinalizer(this);
} }
...@@ -816,6 +819,18 @@ void HTMLDocumentParser::append(const String& inputSource) ...@@ -816,6 +819,18 @@ void HTMLDocumentParser::append(const String& inputSource)
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), "HTMLDocumentParser::append", "size", inputSource.length()); TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.debug"), "HTMLDocumentParser::append", "size", inputSource.length());
const SegmentedString source(inputSource); const SegmentedString source(inputSource);
if (document()->isPrefetchOnly()) {
if (!m_preloadScanner)
m_preloadScanner = createPreloadScanner();
m_preloadScanner->appendToEnd(source);
// TODO(droger): Set the LOAD_PREFETCH flags on the requests.
m_preloadScanner->scanAndPreload(m_preloader.get(), document()->validBaseElementURL(), nullptr);
// Return after the preload scanner, do not actually parse the document.
return;
}
if (m_preloadScanner) { if (m_preloadScanner) {
if (m_input.current().isEmpty() && !isWaitingForScripts()) { if (m_input.current().isEmpty() && !isWaitingForScripts()) {
// We have parsed until the end of the current input and so are now moving ahead of the preload scanner. // We have parsed until the end of the current input and so are now moving ahead of the preload scanner.
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#define HTMLDocumentParser_h #define HTMLDocumentParser_h
#include "bindings/core/v8/DocumentWriteEvaluator.h" #include "bindings/core/v8/DocumentWriteEvaluator.h"
#include "core/CoreExport.h"
#include "core/dom/ParserContentPolicy.h" #include "core/dom/ParserContentPolicy.h"
#include "core/dom/ScriptableDocumentParser.h" #include "core/dom/ScriptableDocumentParser.h"
#include "core/fetch/ResourceClient.h" #include "core/fetch/ResourceClient.h"
...@@ -69,7 +70,7 @@ class HTMLTreeBuilder; ...@@ -69,7 +70,7 @@ class HTMLTreeBuilder;
class PumpSession; class PumpSession;
class TokenizedChunkQueue; class TokenizedChunkQueue;
class HTMLDocumentParser : public ScriptableDocumentParser, private HTMLScriptRunnerHost { class CORE_EXPORT HTMLDocumentParser : public ScriptableDocumentParser, private HTMLScriptRunnerHost {
USING_GARBAGE_COLLECTED_MIXIN(HTMLDocumentParser); USING_GARBAGE_COLLECTED_MIXIN(HTMLDocumentParser);
USING_PRE_FINALIZER(HTMLDocumentParser, dispose); USING_PRE_FINALIZER(HTMLDocumentParser, dispose);
public: public:
...@@ -88,6 +89,9 @@ public: ...@@ -88,6 +89,9 @@ public:
static void parseDocumentFragment(const String&, DocumentFragment*, Element* contextElement, ParserContentPolicy = AllowScriptingContent); static void parseDocumentFragment(const String&, DocumentFragment*, Element* contextElement, ParserContentPolicy = AllowScriptingContent);
// Exposed for testing.
HTMLScriptRunnerHost* asHTMLScriptRunnerHostForTesting() { return this; }
HTMLTokenizer* tokenizer() const { return m_tokenizer.get(); } HTMLTokenizer* tokenizer() const { return m_tokenizer.get(); }
TextPosition textPosition() const final; TextPosition textPosition() const final;
......
// Copyright 2016 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.
#include "core/html/parser/HTMLDocumentParser.h"
#include "core/html/HTMLDocument.h"
#include "core/html/parser/TextResourceDecoder.h"
#include "core/loader/PrerendererClient.h"
#include "core/loader/TextResourceDecoderBuilder.h"
#include "core/testing/DummyPageHolder.h"
#include "testing/gtest/include/gtest/gtest.h"
#include <memory>
namespace blink {
namespace {
class TestPrerendererClient :
public GarbageCollected<TestPrerendererClient>, public PrerendererClient {
USING_GARBAGE_COLLECTED_MIXIN(TestPrerendererClient);
public:
TestPrerendererClient(bool isPrefetchOnly)
: m_isPrefetchOnly(isPrefetchOnly)
{
}
private:
void willAddPrerender(Prerender*) override {};
bool isPrefetchOnly() override { return m_isPrefetchOnly; }
bool m_isPrefetchOnly;
};
class HTMLDocumentParserTest : public testing::Test {
protected:
HTMLDocumentParserTest()
: m_dummyPageHolder(DummyPageHolder::create())
{
}
HTMLDocumentParser* createParser(HTMLDocument& document)
{
HTMLDocumentParser* parser =
HTMLDocumentParser::create(document, ForceSynchronousParsing);
TextResourceDecoderBuilder decoderBuilder("text/html", nullAtom);
std::unique_ptr<TextResourceDecoder> decoder(
decoderBuilder.buildFor(&document));
parser->setDecoder(std::move(decoder));
return parser;
}
std::unique_ptr<DummyPageHolder> m_dummyPageHolder;
};
} // namespace
TEST_F(HTMLDocumentParserTest, AppendPrefetch)
{
HTMLDocument& document = toHTMLDocument(m_dummyPageHolder->document());
providePrerendererClientTo(*document.page(),
new TestPrerendererClient(true));
EXPECT_TRUE(document.isPrefetchOnly());
HTMLDocumentParser* parser = createParser(document);
const char bytes[] = "<ht";
parser->appendBytes(bytes, sizeof(bytes));
// The bytes are forwarded to the preload scanner, not to the tokenizer.
HTMLScriptRunnerHost* scriptRunnerHost =
parser->asHTMLScriptRunnerHostForTesting();
EXPECT_TRUE(scriptRunnerHost->hasPreloadScanner());
EXPECT_EQ(HTMLTokenizer::DataState, parser->tokenizer()->getState());
}
TEST_F(HTMLDocumentParserTest, AppendNoPrefetch)
{
HTMLDocument& document = toHTMLDocument(m_dummyPageHolder->document());
EXPECT_FALSE(document.isPrefetchOnly());
// Use ForceSynchronousParsing to allow calling append().
HTMLDocumentParser* parser = createParser(document);
const char bytes[] = "<ht";
parser->appendBytes(bytes, sizeof(bytes));
// The bytes are forwarded to the tokenizer.
HTMLScriptRunnerHost* scriptRunnerHost =
parser->asHTMLScriptRunnerHostForTesting();
EXPECT_FALSE(scriptRunnerHost->hasPreloadScanner());
EXPECT_EQ(HTMLTokenizer::TagNameState, parser->tokenizer()->getState());
}
} // namespace blink
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#ifndef HTMLScriptRunnerHost_h #ifndef HTMLScriptRunnerHost_h
#define HTMLScriptRunnerHost_h #define HTMLScriptRunnerHost_h
#include "core/CoreExport.h"
#include "wtf/Forward.h" #include "wtf/Forward.h"
namespace blink { namespace blink {
...@@ -34,7 +35,7 @@ class HTMLInputStream; ...@@ -34,7 +35,7 @@ class HTMLInputStream;
class Resource; class Resource;
class Visitor; class Visitor;
class HTMLScriptRunnerHost : public GarbageCollectedMixin { class CORE_EXPORT HTMLScriptRunnerHost : public GarbageCollectedMixin {
public: public:
virtual ~HTMLScriptRunnerHost() { } virtual ~HTMLScriptRunnerHost() { }
DEFINE_INLINE_VIRTUAL_TRACE() { } DEFINE_INLINE_VIRTUAL_TRACE() { }
......
...@@ -44,6 +44,7 @@ class Prerender; ...@@ -44,6 +44,7 @@ class Prerender;
class CORE_EXPORT PrerendererClient : public Supplement<Page> { class CORE_EXPORT PrerendererClient : public Supplement<Page> {
public: public:
virtual void willAddPrerender(Prerender*) = 0; virtual void willAddPrerender(Prerender*) = 0;
virtual bool isPrefetchOnly() = 0;
static const char* supplementName(); static const char* supplementName();
static PrerendererClient* from(Page*); static PrerendererClient* from(Page*);
......
...@@ -51,4 +51,9 @@ void PrerendererClientImpl::willAddPrerender(Prerender* prerender) ...@@ -51,4 +51,9 @@ void PrerendererClientImpl::willAddPrerender(Prerender* prerender)
m_client->willAddPrerender(&webPrerender); m_client->willAddPrerender(&webPrerender);
} }
bool PrerendererClientImpl::isPrefetchOnly()
{
return m_client && m_client->isPrefetchOnly();
}
} // namespace blink } // namespace blink
...@@ -48,6 +48,7 @@ public: ...@@ -48,6 +48,7 @@ public:
explicit PrerendererClientImpl(WebPrerendererClient*); explicit PrerendererClientImpl(WebPrerendererClient*);
void willAddPrerender(Prerender*) override; void willAddPrerender(Prerender*) override;
bool isPrefetchOnly() override;
DEFINE_INLINE_VIRTUAL_TRACE() { PrerendererClient::trace(visitor); } DEFINE_INLINE_VIRTUAL_TRACE() { PrerendererClient::trace(visitor); }
......
...@@ -98,6 +98,11 @@ private: ...@@ -98,6 +98,11 @@ private:
m_webPrerenders.push_back(*prerender); m_webPrerenders.push_back(*prerender);
} }
bool isPrefetchOnly() override
{
return false;
}
std::unique_ptr<WebPrerender::ExtraData> m_extraData; std::unique_ptr<WebPrerender::ExtraData> m_extraData;
std::list<WebPrerender> m_webPrerenders; std::list<WebPrerender> m_webPrerenders;
}; };
......
...@@ -41,6 +41,7 @@ class WebPrerender; ...@@ -41,6 +41,7 @@ class WebPrerender;
class WebPrerendererClient { class WebPrerendererClient {
public: public:
virtual void willAddPrerender(WebPrerender*) = 0; virtual void willAddPrerender(WebPrerender*) = 0;
virtual bool isPrefetchOnly() = 0;
}; };
} // namespace blink } // namespace blink
......
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