Commit fc4e797b authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

Cache code for inline scripts

This enables code caching for <script> tags whose source code is embedded
in the HTML. External scripts store their cached code on metadata
associated with the external script resource; now, inline scripts store
their cached code on metadata associated with the HTML document's
RawResource.

To allow multiple inline scripts per HTML page, the RawResource metadata
can hold multiple code caches. These are keyed by the SHA-256 hash of the
script's source, which is a large enough hash that we don't have to worry
about collisions, and thus don't have to store the script's source in the
cache.

The multi-script metadata has a simple serialization format optimized for
easy serialize/deserialize:

    marker (uint32)
    num_entries (int)
    key 1 (Key type)
    len data 1 (size_t)
    type data 1
    data for key 1
    ...
    key N (Key type)
    len data N (size_t)
    type data N
    data for key N

Inline scripts receive a CachedMetadataHandler implementation which is a
view onto this multi-script handler.

Bug: chromium:823663
Change-Id: Ib14edfaf460aa8bfc90cfe12b8a6b4b7af050de7
Reviewed-on: https://chromium-review.googlesource.com/893401
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: default avatarHiroshige Hayashizaki <hiroshige@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarKouhei Ueno <kouhei@chromium.org>
Cr-Commit-Position: refs/heads/master@{#547671}
parent b5ebd0c6
......@@ -99,8 +99,10 @@ namespace content {
namespace {
// V8ScriptRunner::setCacheTimeStamp() stores 12 byte data (tag + timestamp).
const int kV8CacheTimeStampDataSize = sizeof(unsigned) + sizeof(double);
// V8ScriptRunner::setCacheTimeStamp() stores 16 byte data (marker + tag +
// timestamp).
const int kV8CacheTimeStampDataSize =
sizeof(uint32_t) + sizeof(uint32_t) + sizeof(double);
struct FetchResult {
ServiceWorkerStatusCode status;
......
......@@ -427,6 +427,9 @@ void SetRuntimeFeaturesDefaultsAndUpdateFromArgs(
WebRuntimeFeatures::EnableCodeCacheAfterExecute(
base::FeatureList::IsEnabled(features::kCodeCacheAfterExecute));
WebRuntimeFeatures::EnableCacheInlineScriptCode(
base::FeatureList::IsEnabled(features::kCacheInlineScriptCode));
if (base::FeatureList::IsEnabled(features::kUnifiedTouchAdjustment))
WebRuntimeFeatures::EnableUnifiedTouchAdjustment(true);
......
......@@ -46,6 +46,10 @@ const base::Feature kBlockCredentialedSubresources{
const base::Feature kBrotliEncoding{"brotli-encoding",
base::FEATURE_ENABLED_BY_DEFAULT};
// Enables code caching for inline scripts.
const base::Feature kCacheInlineScriptCode{"CacheInlineScriptCode",
base::FEATURE_DISABLED_BY_DEFAULT};
// If Canvas2D Image Chromium is allowed, this feature controls whether it is
// enabled.
const base::Feature kCanvas2DImageChromium {
......
......@@ -24,6 +24,7 @@ CONTENT_EXPORT extern const base::Feature kAsmJsToWebAssembly;
CONTENT_EXPORT extern const base::Feature kAsyncWheelEvents;
CONTENT_EXPORT extern const base::Feature kBlockCredentialedSubresources;
CONTENT_EXPORT extern const base::Feature kBrotliEncoding;
CONTENT_EXPORT extern const base::Feature kCacheInlineScriptCode;
CONTENT_EXPORT extern const base::Feature kCanvas2DImageChromium;
CONTENT_EXPORT extern const base::Feature kCheckerImaging;
CONTENT_EXPORT extern const base::Feature kCodeCacheAfterExecute;
......
......@@ -10,6 +10,9 @@ namespace blink {
// An enumeration for reporting the source of javascript source code. Only used
// for logging/stats purposes, and shouldn't be used for behavioural differences
// to avoid layer violations.
// TODO(leszeks): This is actually being used for affecting the behaviour of
// inline script caching currently, we should either update this documentation
// or remove that usage.
enum class ScriptSourceLocationType {
// An unknown or unspecified source.
kUnknown,
......
......@@ -173,7 +173,8 @@ uint32_t CacheTag(CacheTagKind kind, const String& encoding) {
// about encodings, but the cached data is specific to one encoding. If we
// later load the script from the cache and interpret it with a different
// encoding, the cached data is not valid for that encoding.
return (v8_cache_data_version | kind) + StringHash::GetHash(encoding);
return (v8_cache_data_version | kind) +
(encoding.IsNull() ? 0 : StringHash::GetHash(encoding));
}
// Check previously stored timestamp.
......
......@@ -27,6 +27,7 @@
#include "core/dom/Document.h"
#include "core/frame/Settings.h"
#include "platform/loader/fetch/SourceKeyedCachedMetadataHandler.h"
namespace blink {
......@@ -41,4 +42,9 @@ bool ScriptableDocumentParser::IsParsingAtLineNumber() const {
return IsParsing() && !IsWaitingForScripts() && !IsExecutingScript();
}
void ScriptableDocumentParser::Trace(blink::Visitor* visitor) {
visitor->Trace(inline_script_cache_handler_);
DecodedDataDocumentParser::Trace(visitor);
}
} // namespace blink
......@@ -33,8 +33,12 @@
namespace blink {
class SourceKeyedCachedMetadataHandler;
class CORE_EXPORT ScriptableDocumentParser : public DecodedDataDocumentParser {
public:
void Trace(blink::Visitor*) override;
// 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.
virtual bool IsExecutingScript() const { return false; }
......@@ -61,6 +65,14 @@ class CORE_EXPORT ScriptableDocumentParser : public DecodedDataDocumentParser {
return parser_content_policy_;
}
void SetInlineScriptCacheHandler(
SourceKeyedCachedMetadataHandler* cache_handler) {
inline_script_cache_handler_ = cache_handler;
}
SourceKeyedCachedMetadataHandler* GetInlineScriptCacheHandler() const {
return inline_script_cache_handler_;
}
protected:
explicit ScriptableDocumentParser(
Document&,
......@@ -69,6 +81,8 @@ class CORE_EXPORT ScriptableDocumentParser : public DecodedDataDocumentParser {
private:
ScriptableDocumentParser* AsScriptableDocumentParser() final { return this; }
Member<SourceKeyedCachedMetadataHandler> inline_script_cache_handler_;
// http://www.whatwg.org/specs/web-apps/current-work/#script-created-parser
bool was_created_by_script_;
ParserContentPolicy parser_content_policy_;
......
......@@ -32,6 +32,7 @@
#include <memory>
#include "core/dom/Document.h"
#include "core/dom/DocumentParser.h"
#include "core/dom/ScriptableDocumentParser.h"
#include "core/dom/UserGestureIndicator.h"
#include "core/dom/WeakIdentifierMap.h"
#include "core/dom/events/Event.h"
......@@ -1104,6 +1105,15 @@ void DocumentLoader::InstallNewDocument(
parser_ = document->OpenForNavigation(parsing_policy, mime_type, encoding);
// If this is a scriptable parser and there is a resource, register the
// resource's cache handler with the parser.
ScriptableDocumentParser* scriptable_parser =
parser_->AsScriptableDocumentParser();
if (scriptable_parser && GetResource()) {
scriptable_parser->SetInlineScriptCacheHandler(
ToRawResource(GetResource())->CacheHandler());
}
// FeaturePolicy is reset in the browser process on commit, so this needs to
// be initialized and replicated to the browser process after commit messages
// are sent in didCommitNavigation().
......
......@@ -8,14 +8,21 @@
#include "bindings/core/v8/ScriptStreamer.h"
#include "bindings/core/v8/V8BindingForCore.h"
#include "core/dom/Document.h"
#include "core/dom/ScriptableDocumentParser.h"
#include "core/frame/LocalFrame.h"
#include "core/loader/AllowedByNosniff.h"
#include "core/loader/DocumentLoader.h"
#include "core/loader/SubresourceIntegrityHelper.h"
#include "core/loader/resource/ScriptResource.h"
#include "core/script/DocumentWriteIntervention.h"
#include "core/script/ScriptLoader.h"
#include "platform/bindings/ScriptState.h"
#include "platform/loader/fetch/CachedMetadata.h"
#include "platform/loader/fetch/MemoryCache.h"
#include "platform/loader/fetch/RawResource.h"
#include "platform/loader/fetch/ResourceClient.h"
#include "platform/loader/fetch/SourceKeyedCachedMetadataHandler.h"
#include "platform/runtime_enabled_features.h"
#include "public/platform/TaskType.h"
namespace blink {
......@@ -226,6 +233,20 @@ bool ClassicPendingScript::CheckMIMETypeBeforeRunScript(
GetResource()->GetResponse());
}
static SingleCachedMetadataHandler* GetInlineCacheHandler(const String& source,
Document& document) {
if (!RuntimeEnabledFeatures::CacheInlineScriptCodeEnabled())
return nullptr;
SourceKeyedCachedMetadataHandler* document_cache_handler =
document.GetScriptableDocumentParser()->GetInlineScriptCacheHandler();
if (!document_cache_handler)
return nullptr;
return document_cache_handler->HandlerForSource(source);
}
ClassicScript* ClassicPendingScript::GetSource(const KURL& document_url,
bool& error_occurred) const {
CheckState();
......@@ -233,9 +254,22 @@ ClassicScript* ClassicPendingScript::GetSource(const KURL& document_url,
error_occurred = ErrorOccurred();
if (!is_external_) {
ScriptSourceCode source_code(
GetElement()->TextFromChildren(), source_location_type_,
nullptr /* cache_handler */, document_url, StartingPosition());
SingleCachedMetadataHandler* cache_handler = nullptr;
String source = GetElement()->TextFromChildren();
// We only create an inline cache handler for html-embedded scripts, not
// for scripts produced by document.write, or not parser-inserted. This is
// because we expect those to be too dynamic to benefit from caching.
// TODO(leszeks): ScriptSourceLocationType was previously only used for UMA,
// so it's a bit of a layer violation to use it for affecting cache
// behaviour. We should decide whether it is ok for this parameter to be
// used for behavioural changes (and if yes, update its documentation), or
// otherwise trigger this behaviour differently.
if (source_location_type_ == ScriptSourceLocationType::kInline) {
cache_handler =
GetInlineCacheHandler(source, GetElement()->GetDocument());
}
ScriptSourceCode source_code(source, source_location_type_, cache_handler,
document_url, StartingPosition());
return ClassicScript::Create(source_code, base_url_for_inline_script_,
options_, kSharableCrossOrigin);
}
......
......@@ -88,6 +88,10 @@ void WebRuntimeFeatures::EnableAudioOutputDevices(bool enable) {
RuntimeEnabledFeatures::SetAudioOutputDevicesEnabled(enable);
}
void WebRuntimeFeatures::EnableCacheInlineScriptCode(bool enable) {
RuntimeEnabledFeatures::SetCacheInlineScriptCodeEnabled(enable);
}
void WebRuntimeFeatures::EnableCanvas2dImageChromium(bool enable) {
RuntimeEnabledFeatures::SetCanvas2dImageChromiumEnabled(enable);
}
......
......@@ -73,6 +73,8 @@ blink_platform_sources("loader") {
"fetch/ResourceTimingInfo.h",
"fetch/ScriptFetchOptions.cpp",
"fetch/ScriptFetchOptions.h",
"fetch/SourceKeyedCachedMetadataHandler.cpp",
"fetch/SourceKeyedCachedMetadataHandler.h",
"fetch/SubstituteData.h",
"fetch/TextResourceDecoderOptions.cpp",
"fetch/TextResourceDecoderOptions.h",
......@@ -114,6 +116,7 @@ jumbo_source_set("unit_tests") {
"fetch/ResourceRequestTest.cpp",
"fetch/ResourceResponseTest.cpp",
"fetch/ResourceTest.cpp",
"fetch/SourceKeyedCachedMetadataHandlerTest.cpp",
]
configs += [ "//third_party/WebKit/Source/platform:blink_platform_config" ]
......
......@@ -4,12 +4,32 @@
#include "platform/loader/fetch/CachedMetadata.h"
#include "platform/loader/fetch/CachedMetadataHandler.h"
namespace blink {
scoped_refptr<CachedMetadata> CachedMetadata::CreateFromSerializedData(
const char* data,
size_t size) {
// Ensure the data is big enough, otherwise discard the data.
if (size < kCachedMetaDataStart) {
return nullptr;
}
// Ensure the marker matches, otherwise discard the data.
if (*reinterpret_cast<const uint32_t*>(data) !=
CachedMetadataHandler::kSingleEntry) {
return nullptr;
}
return base::AdoptRef(new CachedMetadata(data, size));
}
CachedMetadata::CachedMetadata(const char* data, size_t size) {
// Serialized metadata should have non-empty data.
DCHECK_GT(size, kCachedMetaDataStart);
DCHECK(data);
// Make sure that the first int in the data is the single entry marker.
CHECK_EQ(*reinterpret_cast<const uint32_t*>(data),
CachedMetadataHandler::kSingleEntry);
serialized_data_.ReserveInitialCapacity(size);
serialized_data_.Append(data, size);
......@@ -22,7 +42,10 @@ CachedMetadata::CachedMetadata(uint32_t data_type_id,
DCHECK(data_type_id);
DCHECK(data);
serialized_data_.ReserveInitialCapacity(sizeof(uint32_t) + size);
serialized_data_.ReserveInitialCapacity(kCachedMetaDataStart + size);
uint32_t marker = CachedMetadataHandler::kSingleEntry;
serialized_data_.Append(reinterpret_cast<const char*>(&marker),
sizeof(uint32_t));
serialized_data_.Append(reinterpret_cast<const char*>(&data_type_id),
sizeof(uint32_t));
serialized_data_.Append(data, size);
......
......@@ -40,8 +40,10 @@
namespace blink {
// |m_serializedData| consists of 32 bits type ID and and actual data.
constexpr size_t kCachedMetaDataStart = sizeof(uint32_t);
// |m_serializedData| consists of a 32 bit marker, 32 bits type ID, and actual
// data.
constexpr size_t kCacheDataTypeStart = sizeof(uint32_t);
constexpr size_t kCachedMetaDataStart = kCacheDataTypeStart + sizeof(uint32_t);
// Metadata retrieved from the embedding application's cache.
//
......@@ -57,9 +59,7 @@ class PLATFORM_EXPORT CachedMetadata : public RefCounted<CachedMetadata> {
static scoped_refptr<CachedMetadata> CreateFromSerializedData(
const char* data,
size_t size) {
return base::AdoptRef(new CachedMetadata(data, size));
}
size_t);
~CachedMetadata() = default;
......@@ -68,7 +68,7 @@ class PLATFORM_EXPORT CachedMetadata : public RefCounted<CachedMetadata> {
uint32_t DataTypeID() const {
DCHECK_GE(serialized_data_.size(), kCachedMetaDataStart);
return *reinterpret_cast_ptr<uint32_t*>(
const_cast<char*>(serialized_data_.data()));
const_cast<char*>(serialized_data_.data() + kCacheDataTypeStart));
}
const char* Data() const {
......
......@@ -21,6 +21,15 @@ class CachedMetadataHandler
kSendToPlatform, // send cache data to blink::Platform::cacheMetadata
kCacheLocally // cache only in Resource's member variables
};
// Enum for marking serialized cached metadatas so that the deserializers
// do not conflict.
enum CachedMetadataType : uint32_t {
kSingleEntry, // the metadata is a single CachedMetadata entry
kSourceKeyedMap // the metadata is multiple CachedMetadata entries keyed by
// a source string.
};
virtual ~CachedMetadataHandler() = default;
virtual void Trace(blink::Visitor* visitor) {}
......
......@@ -31,6 +31,7 @@
#include "platform/loader/fetch/MemoryCache.h"
#include "platform/loader/fetch/ResourceClientWalker.h"
#include "platform/loader/fetch/ResourceFetcher.h"
#include "platform/loader/fetch/SourceKeyedCachedMetadataHandler.h"
#include "platform/network/http_names.h"
#include "platform/scheduler/child/web_scheduler.h"
#include "public/platform/Platform.h"
......@@ -192,6 +193,11 @@ void RawResource::WillNotFollowRedirect() {
c->RedirectBlocked();
}
SourceKeyedCachedMetadataHandler* RawResource::CacheHandler() {
return static_cast<SourceKeyedCachedMetadataHandler*>(
Resource::CacheHandler());
}
void RawResource::ResponseReceived(
const ResourceResponse& response,
std::unique_ptr<WebDataConsumerHandle> handle) {
......@@ -218,8 +224,20 @@ void RawResource::ResponseReceived(
}
}
CachedMetadataHandler* RawResource::CreateCachedMetadataHandler(
std::unique_ptr<CachedMetadataSender> send_callback) {
return new SourceKeyedCachedMetadataHandler(Encoding(),
std::move(send_callback));
}
void RawResource::SetSerializedCachedMetadata(const char* data, size_t size) {
Resource::SetSerializedCachedMetadata(data, size);
SourceKeyedCachedMetadataHandler* cache_handler = CacheHandler();
if (cache_handler) {
cache_handler->SetSerializedCachedMetadata(data, size);
}
ResourceClientWalker<RawResourceClient> w(Clients());
while (RawResourceClient* c = w.Next())
c->SetSerializedCachedMetadata(this, data, size);
......
......@@ -39,6 +39,7 @@ class FetchParameters;
class RawResourceClient;
class ResourceFetcher;
class SubstituteData;
class SourceKeyedCachedMetadataHandler;
class PLATFORM_EXPORT RawResource final : public Resource {
public:
......@@ -83,6 +84,13 @@ class PLATFORM_EXPORT RawResource final : public Resource {
bool WillFollowRedirect(const ResourceRequest&,
const ResourceResponse&) override;
void SetSerializedCachedMetadata(const char*, size_t) override;
// Used for code caching of scripts with source code inline in the HTML.
// Returns a cache handler which can store multiple cache metadata entries,
// keyed by the source code of the script.
SourceKeyedCachedMetadataHandler* CacheHandler();
WTF::Optional<int64_t> DownloadedFileLength() const {
return downloaded_file_length_;
}
......@@ -90,6 +98,10 @@ class PLATFORM_EXPORT RawResource final : public Resource {
return downloaded_blob_;
}
protected:
CachedMetadataHandler* CreateCachedMetadataHandler(
std::unique_ptr<CachedMetadataSender> send_callback) override;
private:
class RawResourceFactory : public NonTextResourceFactory {
public:
......@@ -113,7 +125,6 @@ class PLATFORM_EXPORT RawResource final : public Resource {
void WillNotFollowRedirect() override;
void ResponseReceived(const ResourceResponse&,
std::unique_ptr<WebDataConsumerHandle>) override;
void SetSerializedCachedMetadata(const char*, size_t) override;
void DidSendData(unsigned long long bytes_sent,
unsigned long long total_bytes_to_be_sent) override;
void DidDownloadData(int) override;
......
// Copyright 2018 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 "platform/loader/fetch/SourceKeyedCachedMetadataHandler.h"
#include "base/bit_cast.h"
#include "platform/Crypto.h"
#include "platform/loader/fetch/CachedMetadata.h"
#include "platform/wtf/StringHasher.h"
#include "platform/wtf/text/WTFString.h"
namespace blink {
// Defined here for storage/ODR reasons, but initialized in the header.
const size_t SourceKeyedCachedMetadataHandler::kKeySize;
class SourceKeyedCachedMetadataHandler::SingleKeyHandler final
: public SingleCachedMetadataHandler {
public:
void Trace(Visitor* visitor) override {
visitor->Trace(parent_);
SingleCachedMetadataHandler::Trace(visitor);
}
SingleKeyHandler(SourceKeyedCachedMetadataHandler* parent, Key key)
: parent_(parent), key_(key) {}
void SetCachedMetadata(uint32_t data_type_id,
const char* data,
size_t size,
CacheType cache_type) override {
DCHECK(!parent_->cached_metadata_map_.Contains(key_));
parent_->cached_metadata_map_.insert(
key_, CachedMetadata::Create(data_type_id, data, size));
if (cache_type == CachedMetadataHandler::kSendToPlatform)
parent_->SendToPlatform();
}
void ClearCachedMetadata(CacheType cache_type) override {
parent_->cached_metadata_map_.erase(key_);
if (cache_type == CachedMetadataHandler::kSendToPlatform)
parent_->SendToPlatform();
}
scoped_refptr<CachedMetadata> GetCachedMetadata(
uint32_t data_type_id) const override {
scoped_refptr<CachedMetadata> cached_metadata =
parent_->cached_metadata_map_.at(key_);
if (!cached_metadata || cached_metadata->DataTypeID() != data_type_id)
return nullptr;
return cached_metadata;
}
String Encoding() const override { return parent_->Encoding(); }
bool IsServedFromCacheStorage() const override {
return parent_->IsServedFromCacheStorage();
}
private:
Member<SourceKeyedCachedMetadataHandler> parent_;
Key key_;
};
class SourceKeyedCachedMetadataHandler::KeyHash {
public:
static unsigned GetHash(const Key& key) {
return StringHasher::ComputeHash(key.data(), key.size());
}
static bool Equal(const Key& a, const Key& b) { return a == b; }
static const bool safe_to_compare_to_empty_or_deleted = true;
};
SingleCachedMetadataHandler* SourceKeyedCachedMetadataHandler::HandlerForSource(
const String& source) {
DigestValue digest_value;
if (!ComputeDigest(kHashAlgorithmSha256,
static_cast<const char*>(source.Bytes()),
source.CharactersSizeInBytes(), digest_value))
return nullptr;
Key key;
DCHECK_EQ(digest_value.size(), kKeySize);
memcpy(key.data(), digest_value.data(), kKeySize);
return new SingleKeyHandler(this, key);
}
void SourceKeyedCachedMetadataHandler::ClearCachedMetadata(
CachedMetadataHandler::CacheType cache_type) {
cached_metadata_map_.clear();
if (cache_type == CachedMetadataHandler::kSendToPlatform)
SendToPlatform();
};
String SourceKeyedCachedMetadataHandler::Encoding() const {
return String(encoding_.GetName());
}
// Encoding of keyed map:
// - marker: CachedMetadataHandler::kSourceKeyedMap (uint32_t)
// - num_entries (int)
// - key 1 (Key type)
// - len data 1 (size_t)
// - type data 1
// - data for key 1
// ...
// - key N (Key type)
// - len data N (size_t)
// - type data N
// - data for key N
namespace {
// Reading a value from a char buffer without using reinterpret cast. This
// should inline and optimize to the same code as *reinterpret_cast<T>(data),
// but without the risk of undefined behaviour.
template <typename T>
T ReadVal(const char* data) {
static_assert(base::is_trivially_copyable<T>::value,
"ReadVal requires the value type to be copyable");
T ret;
memcpy(&ret, data, sizeof(T));
return ret;
}
} // namespace
void SourceKeyedCachedMetadataHandler::SetSerializedCachedMetadata(
const char* data,
size_t size) {
// We only expect to receive cached metadata from the platform once. If this
// triggers, it indicates an efficiency problem which is most likely
// unexpected in code designed to improve performance.
DCHECK(cached_metadata_map_.IsEmpty());
// Ensure we have a marker.
if (size < sizeof(uint32_t))
return;
uint32_t marker = ReadVal<uint32_t>(data);
// Check for our marker to avoid conflicts with other kinds of cached
// metadata.
if (marker != CachedMetadataHandler::kSourceKeyedMap) {
return;
}
data += sizeof(uint32_t);
size -= sizeof(uint32_t);
// Ensure we have a length.
if (size < sizeof(int))
return;
int num_entries = ReadVal<int>(data);
data += sizeof(int);
size -= sizeof(int);
for (int i = 0; i < num_entries; ++i) {
// Ensure we have an entry key and size.
if (size < kKeySize + sizeof(size_t)) {
cached_metadata_map_.clear();
return;
}
Key key;
std::copy(data, data + kKeySize, std::begin(key));
data += kKeySize;
size_t entry_size = ReadVal<size_t>(data);
data += sizeof(size_t);
size -= kKeySize + sizeof(size_t);
// Ensure we have enough data for this entry.
if (size < entry_size) {
cached_metadata_map_.clear();
return;
}
if (scoped_refptr<CachedMetadata> deserialized_entry =
CachedMetadata::CreateFromSerializedData(data, entry_size)) {
// Only insert the deserialized entry if it deserialized correctly.
cached_metadata_map_.insert(key, std::move(deserialized_entry));
}
data += entry_size;
size -= entry_size;
}
// Ensure we have no more data.
if (size > 0) {
cached_metadata_map_.clear();
}
};
void SourceKeyedCachedMetadataHandler::SendToPlatform() {
if (!sender_)
return;
if (cached_metadata_map_.IsEmpty()) {
sender_->Send(nullptr, 0);
} else {
Vector<char> serialized_data;
uint32_t marker = CachedMetadataHandler::kSourceKeyedMap;
serialized_data.Append(reinterpret_cast<char*>(&marker), sizeof(marker));
int num_entries = cached_metadata_map_.size();
serialized_data.Append(reinterpret_cast<char*>(&num_entries),
sizeof(num_entries));
for (const auto& metadata : cached_metadata_map_) {
serialized_data.Append(metadata.key.data(), kKeySize);
size_t entry_size = metadata.value->SerializedData().size();
serialized_data.Append(reinterpret_cast<const char*>(&entry_size),
sizeof(entry_size));
serialized_data.AppendVector(metadata.value->SerializedData());
}
sender_->Send(serialized_data.data(), serialized_data.size());
}
}
} // namespace blink
// Copyright 2018 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 SourceKeyedCachedMetadataHandler_h
#define SourceKeyedCachedMetadataHandler_h
#include <stdint.h>
#include <array>
#include "platform/loader/fetch/CachedMetadata.h"
#include "platform/loader/fetch/CachedMetadataHandler.h"
#include "platform/loader/fetch/Resource.h"
#include "platform/wtf/HashMap.h"
namespace blink {
// An implementation of CachedMetadataHandler which can hold multiple
// CachedMetadata entries. These entries are keyed by a cryptograph hash of the
// source code which produced them.
//
// This is used to store cached metadata for multiple inline scripts on a single
// HTML document's resource.
class PLATFORM_EXPORT SourceKeyedCachedMetadataHandler final
: public CachedMetadataHandler {
public:
SourceKeyedCachedMetadataHandler(
WTF::TextEncoding encoding,
std::unique_ptr<CachedMetadataSender> send_callback)
: sender_(std::move(send_callback)), encoding_(encoding) {}
// Produce a metadata handler for a single cached metadata associated with
// the given source code.
SingleCachedMetadataHandler* HandlerForSource(const String& source);
void ClearCachedMetadata(CachedMetadataHandler::CacheType) override;
String Encoding() const override;
bool IsServedFromCacheStorage() const override {
return sender_->IsServedFromCacheStorage();
}
void SetSerializedCachedMetadata(const char*, size_t);
private:
// Keys are SHA-256, which are 256/8 = 32 bytes.
static constexpr size_t kKeySize = 32;
typedef std::array<uint8_t, kKeySize> Key;
class SingleKeyHandler;
class KeyHash;
class KeyHashTraits : public WTF::GenericHashTraits<Key> {
public:
// Note: This class relies on hashes never being zero or 1 followed by all
// zeros. Practically, our hash space is large enough that the risk of such
// a collision is infinitesimal.
typedef Key EmptyValueType;
static const bool kEmptyValueIsZero = true;
static EmptyValueType EmptyValue() {
// Rely on integer value initialization to zero out the key array.
return Key{};
}
static void ConstructDeletedValue(Key& slot, bool) {
slot = {1}; // Remaining entries are value initialized to 0.
}
static bool IsDeletedValue(const Key& value) { return value == Key{1}; }
};
void SendToPlatform();
// TODO(leszeks): Maybe just store the SingleKeyHandlers directly in here?
WTF::HashMap<Key, scoped_refptr<CachedMetadata>, KeyHash, KeyHashTraits>
cached_metadata_map_;
std::unique_ptr<CachedMetadataSender> sender_;
const WTF::TextEncoding encoding_;
};
} // namespace blink
#endif // SourceKeyedCachedMetadataHandler_h
......@@ -147,6 +147,9 @@
origin_trial_feature_name: "BudgetQuery",
status: "experimental",
},
{
name: "CacheInlineScriptCode"
},
{
name: "CacheStyleSheetWithMediaQueries",
status: "experimental",
......
......@@ -134,6 +134,12 @@ class WTF_EXPORT String {
return impl_->Characters16();
}
ALWAYS_INLINE const void* Bytes() const {
if (!impl_)
return nullptr;
return impl_->Bytes();
}
// Return characters8() or characters16() depending on CharacterType.
template <typename CharacterType>
inline const CharacterType* GetCharacters() const;
......
......@@ -73,6 +73,7 @@ class WebRuntimeFeatures {
BLINK_PLATFORM_EXPORT static void EnableAccelerated2dCanvas(bool);
BLINK_PLATFORM_EXPORT static void EnableAllowActivationDelegationAttr(bool);
BLINK_PLATFORM_EXPORT static void EnableAudioOutputDevices(bool);
BLINK_PLATFORM_EXPORT static void EnableCacheInlineScriptCode(bool);
BLINK_PLATFORM_EXPORT static void EnableCanvas2dImageChromium(bool);
BLINK_PLATFORM_EXPORT static void EnableCSSHexAlphaColor(bool);
BLINK_PLATFORM_EXPORT static void EnableScrollTopLeftInterop(bool);
......
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