| // Copyright 2020 the V8 project 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 "src/snapshot/snapshot-compression.h" |
| |
| #include "src/base/platform/elapsed-timer.h" |
| #include "src/utils/memcopy.h" |
| #include "src/utils/utils.h" |
| #include "third_party/zlib/google/compression_utils_portable.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| uint32_t GetUncompressedSize(const Bytef* compressed_data) { |
| uint32_t size; |
| MemCopy(&size, compressed_data, sizeof(size)); |
| return size; |
| } |
| |
| SnapshotData SnapshotCompression::Compress( |
| const SnapshotData* uncompressed_data) { |
| SnapshotData snapshot_data; |
| base::ElapsedTimer timer; |
| if (FLAG_profile_deserialization) timer.Start(); |
| |
| static_assert(sizeof(Bytef) == 1, ""); |
| const uLongf input_size = |
| static_cast<uLongf>(uncompressed_data->RawData().size()); |
| uint32_t payload_length = |
| static_cast<uint32_t>(uncompressed_data->RawData().size()); |
| |
| uLongf compressed_data_size = compressBound(input_size); |
| |
| // Allocating >= the final amount we will need. |
| snapshot_data.AllocateData( |
| static_cast<uint32_t>(sizeof(payload_length) + compressed_data_size)); |
| |
| byte* compressed_data = const_cast<byte*>(snapshot_data.RawData().begin()); |
| // Since we are doing raw compression (no zlib or gzip headers), we need to |
| // manually store the uncompressed size. |
| MemCopy(compressed_data, &payload_length, sizeof(payload_length)); |
| |
| CHECK_EQ(zlib_internal::CompressHelper( |
| zlib_internal::ZRAW, compressed_data + sizeof(payload_length), |
| &compressed_data_size, |
| bit_cast<const Bytef*>(uncompressed_data->RawData().begin()), |
| input_size, Z_DEFAULT_COMPRESSION, nullptr, nullptr), |
| Z_OK); |
| |
| // Reallocating to exactly the size we need. |
| snapshot_data.Resize(static_cast<uint32_t>(compressed_data_size) + |
| sizeof(payload_length)); |
| DCHECK_EQ(payload_length, |
| GetUncompressedSize(snapshot_data.RawData().begin())); |
| |
| if (FLAG_profile_deserialization) { |
| double ms = timer.Elapsed().InMillisecondsF(); |
| PrintF("[Compressing %d bytes took %0.3f ms]\n", payload_length, ms); |
| } |
| return snapshot_data; |
| } |
| |
| SnapshotData SnapshotCompression::Decompress( |
| Vector<const byte> compressed_data) { |
| SnapshotData snapshot_data; |
| base::ElapsedTimer timer; |
| if (FLAG_profile_deserialization) timer.Start(); |
| |
| const Bytef* input_bytef = bit_cast<const Bytef*>(compressed_data.begin()); |
| |
| // Since we are doing raw compression (no zlib or gzip headers), we need to |
| // manually retrieve the uncompressed size. |
| uint32_t uncompressed_payload_length = GetUncompressedSize(input_bytef); |
| input_bytef += sizeof(uncompressed_payload_length); |
| |
| snapshot_data.AllocateData(uncompressed_payload_length); |
| |
| uLongf uncompressed_size = uncompressed_payload_length; |
| CHECK_EQ(zlib_internal::UncompressHelper( |
| zlib_internal::ZRAW, |
| bit_cast<Bytef*>(snapshot_data.RawData().begin()), |
| &uncompressed_size, input_bytef, |
| static_cast<uLong>(compressed_data.size() - |
| sizeof(uncompressed_payload_length))), |
| Z_OK); |
| |
| if (FLAG_profile_deserialization) { |
| double ms = timer.Elapsed().InMillisecondsF(); |
| PrintF("[Decompressing %d bytes took %0.3f ms]\n", |
| uncompressed_payload_length, ms); |
| } |
| return snapshot_data; |
| } |
| |
| } // namespace internal |
| } // namespace v8 |