| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/text/CompressibleString.h" | 5 #include "platform/text/CompressibleString.h" |
| 6 | 6 |
| 7 #include "platform/Histogram.h" | 7 #include "platform/Histogram.h" |
| 8 #include "public/platform/Platform.h" |
| 9 #include "third_party/zlib/google/compression_utils.h" |
| 8 #include "wtf/Assertions.h" | 10 #include "wtf/Assertions.h" |
| 9 #include "wtf/WTFThreadData.h" | 11 #include "wtf/WTFThreadData.h" |
| 10 #include "wtf/text/WTFString.h" | 12 #include "wtf/text/WTFString.h" |
| 11 | 13 |
| 12 namespace blink { | 14 namespace blink { |
| 13 | 15 |
| 14 class CompressibleStringTable { | 16 class CompressibleStringTable { |
| 15 WTF_MAKE_NONCOPYABLE(CompressibleStringTable); | 17 WTF_MAKE_NONCOPYABLE(CompressibleStringTable); |
| 16 public: | 18 public: |
| 17 static CompressibleStringTable* create(WTFThreadData& data) | 19 static CompressibleStringTable* create(WTFThreadData& data) |
| 18 { | 20 { |
| 19 data.m_compressibleStringTable = new CompressibleStringTable; | 21 data.m_compressibleStringTable = new CompressibleStringTable; |
| 20 data.m_compressibleStringTableDestructor = CompressibleStringTable::dest
roy; | 22 data.m_compressibleStringTableDestructor = CompressibleStringTable::dest
roy; |
| 21 return data.m_compressibleStringTable; | 23 return data.m_compressibleStringTable; |
| 22 } | 24 } |
| 23 | 25 |
| 24 void add(CompressibleStringImpl* string) | 26 void add(CompressibleStringImpl* string) |
| 25 { | 27 { |
| 26 ASSERT(!m_table.contains(string)); | 28 DCHECK(!m_table.contains(string)); |
| 27 m_table.add(string); | 29 m_table.add(string); |
| 28 } | 30 } |
| 29 | 31 |
| 30 bool contains(CompressibleStringImpl* string) const | 32 bool contains(CompressibleStringImpl* string) const |
| 31 { | 33 { |
| 32 return m_table.contains(string); | 34 return m_table.contains(string); |
| 33 } | 35 } |
| 34 | 36 |
| 35 void remove(CompressibleStringImpl* string) | 37 void remove(CompressibleStringImpl* string) |
| 36 { | 38 { |
| 37 ASSERT(m_table.contains(string)); | 39 DCHECK(m_table.contains(string)); |
| 38 m_table.remove(string); | 40 m_table.remove(string); |
| 39 } | 41 } |
| 40 | 42 |
| 41 void compressAll() | 43 void compressAll() |
| 42 { | 44 { |
| 43 HashSet<CompressibleStringImpl*>::iterator end = m_table.end(); | 45 HashSet<CompressibleStringImpl*>::iterator end = m_table.end(); |
| 44 for (HashSet<CompressibleStringImpl*>::iterator iter = m_table.begin();
iter != end; ++iter) { | 46 for (HashSet<CompressibleStringImpl*>::iterator iter = m_table.begin();
iter != end; ++iter) { |
| 45 CompressibleStringImpl* string = *iter; | 47 CompressibleStringImpl* string = *iter; |
| 46 if (!string->isCompressed()) | 48 if (!string->isCompressed()) |
| 47 string->compressString(); | 49 string->compressString(); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 70 | 72 |
| 71 static const unsigned CompressibleStringImplSizeThrehold = 100000; | 73 static const unsigned CompressibleStringImplSizeThrehold = 100000; |
| 72 | 74 |
| 73 void CompressibleStringImpl::compressAll() | 75 void CompressibleStringImpl::compressAll() |
| 74 { | 76 { |
| 75 compressibleStringTable().compressAll(); | 77 compressibleStringTable().compressAll(); |
| 76 } | 78 } |
| 77 | 79 |
| 78 CompressibleStringImpl::CompressibleStringImpl(PassRefPtr<StringImpl> impl) | 80 CompressibleStringImpl::CompressibleStringImpl(PassRefPtr<StringImpl> impl) |
| 79 : m_string(impl) | 81 : m_string(impl) |
| 80 , m_isCompressed(false) | 82 , m_originalLength(m_string.length()) |
| 83 , m_compressedData(nullptr) |
| 84 , m_compressedDataSize(0) |
| 81 { | 85 { |
| 82 if (originalContentSizeInBytes() > CompressibleStringImplSizeThrehold) | 86 if (originalContentSizeInBytes() > CompressibleStringImplSizeThrehold) |
| 83 compressibleStringTable().add(this); | 87 compressibleStringTable().add(this); |
| 84 } | 88 } |
| 85 | 89 |
| 86 CompressibleStringImpl::~CompressibleStringImpl() | 90 CompressibleStringImpl::~CompressibleStringImpl() |
| 87 { | 91 { |
| 88 if (originalContentSizeInBytes() > CompressibleStringImplSizeThrehold) | 92 if (originalContentSizeInBytes() > CompressibleStringImplSizeThrehold) |
| 89 compressibleStringTable().remove(this); | 93 compressibleStringTable().remove(this); |
| 90 } | 94 } |
| 91 | 95 |
| 92 enum CompressibleStringCountType { | 96 enum CompressibleStringCountType { |
| 93 StringWasCompressedInBackgroundTab, | 97 StringWasCompressedInBackgroundTab, |
| 94 StringWasDecompressed, | 98 StringWasDecompressed, |
| 95 CompressibleStringCountTypeMax = StringWasDecompressed, | 99 CompressibleStringCountTypeMax = StringWasDecompressed, |
| 96 }; | 100 }; |
| 97 | 101 |
| 98 static void recordCompressibleStringCount(CompressibleStringCountType type) | 102 static void recordCompressibleStringCount(CompressibleStringCountType type) |
| 99 { | 103 { |
| 100 DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, sringTypeHistogram, ne
w EnumerationHistogram("Memory.CompressibleStringCount", CompressibleStringCount
TypeMax + 1)); | 104 DEFINE_THREAD_SAFE_STATIC_LOCAL(EnumerationHistogram, sringTypeHistogram, ne
w EnumerationHistogram("Memory.CompressibleStringCount", CompressibleStringCount
TypeMax + 1)); |
| 101 sringTypeHistogram.count(type); | 105 sringTypeHistogram.count(type); |
| 102 } | 106 } |
| 103 | 107 |
| 104 // compressString does nothing but collect UMA so far. | |
| 105 // TODO(hajimehoshi): Implement this. | |
| 106 void CompressibleStringImpl::compressString() | 108 void CompressibleStringImpl::compressString() |
| 107 { | 109 { |
| 108 recordCompressibleStringCount(StringWasCompressedInBackgroundTab); | 110 recordCompressibleStringCount(StringWasCompressedInBackgroundTab); |
| 109 ASSERT(!isCompressed()); | 111 DCHECK(!isCompressed()); |
| 110 m_isCompressed = true; | 112 DCHECK(!m_compressedData); |
| 113 DCHECK(!m_compressedDataSize); |
| 114 |
| 115 // TODO(hajimehoshi): Now components offers funcitons accepting only |
| 116 // std::strings. This is not efficient. We should offer char* version. |
| 117 std::string in, out; |
| 118 if (m_string.is8Bit()) { |
| 119 in = std::string(reinterpret_cast<const char*>(m_string.characters8()),
originalContentSizeInBytes()); |
| 120 m_string = emptyString(); |
| 121 } else { |
| 122 in = std::string(reinterpret_cast<const char*>(m_string.characters16()),
originalContentSizeInBytes()); |
| 123 m_string = emptyString16Bit(); |
| 124 } |
| 125 compression::GzipCompress(in, &out); |
| 126 |
| 127 m_compressedData = WTF::Partitions::fastMalloc(out.size(), "CompressibleStri
ng"); |
| 128 memcpy(m_compressedData, out.c_str(), out.size()); |
| 129 m_compressedDataSize = out.size(); |
| 111 } | 130 } |
| 112 | 131 |
| 113 // decompressString does nothing but collect UMA so far. | |
| 114 // TODO(hajimehoshi): Implement this. | |
| 115 void CompressibleStringImpl::decompressString() | 132 void CompressibleStringImpl::decompressString() |
| 116 { | 133 { |
| 117 // TODO(hajimehoshi): We wanted to tell whether decompressing in a | 134 // TODO(hajimehoshi): We wanted to tell whether decompressing in a |
| 118 // background tab or a foreground tab, but this was impossible. For example, | 135 // background tab or a foreground tab, but this was impossible. For example, |
| 119 // one renderer process of a new tab page is used for multiple tabs. | 136 // one renderer process of a new tab page is used for multiple tabs. |
| 120 // Another example is that reloading a page will re-use the process with a | 137 // Another example is that reloading a page will re-use the process with a |
| 121 // new Page object and updating a static variable along with reloading will | 138 // new Page object and updating a static variable along with reloading will |
| 122 // be complex. See also crbug/581266. We will revisit when the situation | 139 // be complex. See also crbug/581266. We will revisit when the situation |
| 123 // changes. | 140 // changes. |
| 124 recordCompressibleStringCount(StringWasDecompressed); | 141 recordCompressibleStringCount(StringWasDecompressed); |
| 125 ASSERT(isCompressed()); | 142 DCHECK(isCompressed()); |
| 126 m_isCompressed = false; | 143 DCHECK(m_compressedData); |
| 144 DCHECK(m_compressedDataSize); |
| 145 |
| 146 std::string in(static_cast<const char*>(m_compressedData), m_compressedDataS
ize); |
| 147 std::string out; |
| 148 compression::GzipUncompress(in, &out); |
| 149 |
| 150 if (is8Bit()) { |
| 151 LChar* data = nullptr; |
| 152 m_string = StringImpl::createUninitialized(out.size() / sizeof(LChar), d
ata); |
| 153 memcpy(data, out.c_str(), out.size()); |
| 154 } else { |
| 155 UChar* data = nullptr; |
| 156 m_string = StringImpl::createUninitialized(out.size() / sizeof(UChar), d
ata); |
| 157 memcpy(data, out.c_str(), out.size()); |
| 158 } |
| 159 |
| 160 WTF::Partitions::fastFree(m_compressedData); |
| 161 m_compressedData = nullptr; |
| 162 m_compressedDataSize = 0; |
| 163 DCHECK(m_originalLength == m_string.length()); |
| 127 } | 164 } |
| 128 | 165 |
| 129 } // namespace blink | 166 } // namespace blink |
| OLD | NEW |