blob: 38e6c09f41e1978f53a41ac1f73072b8307fd3ce [file] [log] [blame]
// 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 "platform/text/CompressibleString.h"
#include "public/platform/Platform.h"
#include "wtf/Assertions.h"
#include "wtf/WTFThreadData.h"
#include "wtf/text/WTFString.h"
namespace blink {
class CompressibleStringTable {
WTF_MAKE_NONCOPYABLE(CompressibleStringTable);
public:
static CompressibleStringTable* create(WTFThreadData& data)
{
data.m_compressibleStringTable = new CompressibleStringTable;
data.m_compressibleStringTableDestructor = CompressibleStringTable::destroy;
return data.m_compressibleStringTable;
}
void add(CompressibleStringImpl* string)
{
ASSERT(!m_table.contains(string));
m_table.add(string);
}
bool contains(CompressibleStringImpl* string) const
{
return m_table.contains(string);
}
void remove(CompressibleStringImpl* string)
{
ASSERT(m_table.contains(string));
m_table.remove(string);
}
void compressAll()
{
HashSet<CompressibleStringImpl*>::iterator end = m_table.end();
for (HashSet<CompressibleStringImpl*>::iterator iter = m_table.begin(); iter != end; ++iter) {
CompressibleStringImpl* string = *iter;
if (!string->isCompressed())
string->compressString();
}
}
private:
CompressibleStringTable() { }
static void destroy(CompressibleStringTable* table)
{
delete table;
}
HashSet<CompressibleStringImpl*> m_table;
};
static inline CompressibleStringTable& compressibleStringTable()
{
WTFThreadData& data = wtfThreadData();
CompressibleStringTable* table = data.compressibleStringTable();
if (UNLIKELY(!table))
table = CompressibleStringTable::create(data);
return *table;
}
static const unsigned CompressibleStringImplSizeThrehold = 100000;
void CompressibleStringImpl::compressAll()
{
compressibleStringTable().compressAll();
}
CompressibleStringImpl::CompressibleStringImpl(PassRefPtr<StringImpl> impl)
: m_string(impl)
, m_isCompressed(false)
{
if (originalContentSizeInBytes() > CompressibleStringImplSizeThrehold)
compressibleStringTable().add(this);
}
CompressibleStringImpl::~CompressibleStringImpl()
{
if (originalContentSizeInBytes() > CompressibleStringImplSizeThrehold)
compressibleStringTable().remove(this);
}
enum CompressibleStringCountType {
StringWasCompressedInBackgroundTab,
StringWasDecompressed,
CompressibleStringCountTypeMax = StringWasDecompressed,
};
static void recordCompressibleStringCount(CompressibleStringCountType type)
{
Platform::current()->histogramEnumeration("Memory.CompressibleStringCount", type, CompressibleStringCountTypeMax + 1);
}
// compressString does nothing but collect UMA so far.
// TODO(hajimehoshi): Implement this.
void CompressibleStringImpl::compressString()
{
recordCompressibleStringCount(StringWasCompressedInBackgroundTab);
ASSERT(!isCompressed());
m_isCompressed = true;
}
// decompressString does nothing but collect UMA so far.
// TODO(hajimehoshi): Implement this.
void CompressibleStringImpl::decompressString()
{
// TODO(hajimehoshi): We wanted to tell whether decompressing in a
// background tab or a foreground tab, but this was impossible. For example,
// one renderer process of a new tab page is used for multiple tabs.
// Another example is that reloading a page will re-use the process with a
// new Page object and updating a static variable along with reloading will
// be complex. See also crbug/581266. We will revisit when the situation
// changes.
recordCompressibleStringCount(StringWasDecompressed);
ASSERT(isCompressed());
m_isCompressed = false;
}
} // namespace blink