Changing checksum implementation to use zlib's adler32

adler32 is strictly faster than the old checksum - see this doc:
https://docs.google.com/document/d/1fFhuShavlUwf0FqTc-6L3XLYbAVe0DhpmHSv4oenZL8/edit?pli=1#heading=h.ojvfq6akbz5f

adler32 also no longer requires alignment to be maintained.

Bug: chromium:833361
Change-Id: I3dbfa699b712aa908c87e6f8261756a4a1209df4
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1925562
Commit-Queue: Sam Maier <smaier@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65160}
This commit is contained in:
Sam Maier 2019-11-25 10:29:12 -05:00 committed by Commit Bot
parent 5f14396489
commit 082e56fe5a
14 changed files with 45 additions and 88 deletions

View File

@ -3301,6 +3301,8 @@ v8_source_set("v8_base_without_compiler") {
]
}
deps += [ "//third_party/zlib" ]
if (v8_postmortem_support) {
sources += [ "$target_gen_dir/debug-support.cc" ]
deps += [ ":postmortem-metadata" ]

2
DEPS
View File

@ -256,6 +256,8 @@ deps = {
Var('android_url') + '/platform/external/perfetto.git' + '@' + '12dc10e0278cded35205cf84f80a821348cb6c56',
'v8/third_party/protobuf':
Var('chromium_url') + '/external/github.com/google/protobuf'+ '@' + 'b68a347f56137b4b1a746e8c7438495a6ac1bd91',
'v8/third_party/zlib':
Var('chromium_url') + '/chromium/src/third_party/zlib.git'+ '@' + 'e5c4d8c45ed18f84ea68f5029c9bceb1f67268b8',
}
include_rules = [

View File

@ -29,7 +29,7 @@ void ReadOnlyHeap::SetUp(Isolate* isolate, ReadOnlyDeserializer* des) {
DCHECK_NOT_NULL(isolate);
#ifdef V8_SHARED_RO_HEAP
bool call_once_ran = false;
base::Optional<Checksum> des_checksum;
base::Optional<uint32_t> des_checksum;
#ifdef DEBUG
if (des != nullptr) des_checksum = des->GetChecksum();
#endif // DEBUG
@ -50,7 +50,7 @@ void ReadOnlyHeap::SetUp(Isolate* isolate, ReadOnlyDeserializer* des) {
USE(call_once_ran);
USE(des_checksum);
#ifdef DEBUG
const base::Optional<Checksum> last_checksum =
const base::Optional<uint32_t> last_checksum =
shared_ro_heap_->read_only_blob_checksum_;
if (last_checksum || des_checksum) {
// The read-only heap was set up from a snapshot. Make sure it's the always

View File

@ -66,8 +66,6 @@ class ReadOnlyHeap final {
ReadOnlySpace* read_only_space() const { return read_only_space_; }
private:
using Checksum = std::pair<uint32_t, uint32_t>;
// Creates a new read-only heap and attaches it to the provided isolate.
static ReadOnlyHeap* CreateAndAttachToIsolate(Isolate* isolate);
// Runs the read-only deserailizer and calls InitFromIsolate to complete
@ -86,7 +84,7 @@ class ReadOnlyHeap final {
#ifdef V8_SHARED_RO_HEAP
#ifdef DEBUG
// The checksum of the blob the read-only heap was deserialized from, if any.
base::Optional<Checksum> read_only_blob_checksum_;
base::Optional<uint32_t> read_only_blob_checksum_;
#endif // DEBUG
Address read_only_roots_[kEntriesCount];

View File

@ -2,4 +2,7 @@ specific_include_rules = {
"mksnapshot\.cc": [
"+include/libplatform/libplatform.h",
],
"serializer-common.cc": [
"+third_party/zlib",
],
}

View File

@ -403,9 +403,7 @@ SerializedCodeData::SerializedCodeData(const std::vector<byte>* payload,
CopyBytes(data_ + padded_payload_offset, payload->data(),
static_cast<size_t>(payload->size()));
Checksum checksum(ChecksummedContent());
SetHeaderValue(kChecksumPartAOffset, checksum.a());
SetHeaderValue(kChecksumPartBOffset, checksum.b());
SetHeaderValue(kChecksumOffset, Checksum(ChecksummedContent()));
}
SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
@ -417,8 +415,7 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
uint32_t c1 = GetHeaderValue(kChecksumPartAOffset);
uint32_t c2 = GetHeaderValue(kChecksumPartBOffset);
uint32_t c = GetHeaderValue(kChecksumOffset);
if (version_hash != Version::Hash()) return VERSION_MISMATCH;
if (source_hash != expected_source_hash) return SOURCE_MISMATCH;
if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
@ -427,7 +424,7 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
POINTER_SIZE_ALIGN(kHeaderSize +
GetHeaderValue(kNumReservationsOffset) * kInt32Size);
if (payload_length > max_payload_length) return LENGTH_MISMATCH;
if (!Checksum(ChecksummedContent()).Check(c1, c2)) return CHECKSUM_MISMATCH;
if (Checksum(ChecksummedContent()) != c) return CHECKSUM_MISMATCH;
return CHECK_SUCCESS;
}

View File

@ -94,8 +94,7 @@ class SerializedCodeData : public SerializedData {
// [3] flag hash
// [4] number of reservation size entries
// [5] payload length
// [6] payload checksum part A
// [7] payload checksum part B
// [6] payload checksum
// ... reservations
// ... code stub keys
// ... serialized payload
@ -105,12 +104,8 @@ class SerializedCodeData : public SerializedData {
static const uint32_t kNumReservationsOffset = kFlagHashOffset + kUInt32Size;
static const uint32_t kPayloadLengthOffset =
kNumReservationsOffset + kUInt32Size;
static const uint32_t kChecksumPartAOffset =
kPayloadLengthOffset + kUInt32Size;
static const uint32_t kChecksumPartBOffset =
kChecksumPartAOffset + kUInt32Size;
static const uint32_t kUnalignedHeaderSize =
kChecksumPartBOffset + kUInt32Size;
static const uint32_t kChecksumOffset = kPayloadLengthOffset + kUInt32Size;
static const uint32_t kUnalignedHeaderSize = kChecksumOffset + kUInt32Size;
static const uint32_t kHeaderSize = POINTER_SIZE_ALIGN(kUnalignedHeaderSize);
// Used when consuming.

View File

@ -41,9 +41,7 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
~Deserializer() override;
void SetRehashability(bool v) { can_rehash_ = v; }
std::pair<uint32_t, uint32_t> GetChecksum() const {
return source_.GetChecksum();
}
uint32_t GetChecksum() const { return source_.GetChecksum(); }
protected:
// Create a deserializer from a snapshot byte source.

View File

@ -8,6 +8,7 @@
#include "src/objects/foreign-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/slots.h"
#include "third_party/zlib/zlib.h"
namespace v8 {
namespace internal {
@ -145,5 +146,16 @@ void SerializerDeserializer::RestoreExternalReferenceRedirectors(
}
}
V8_EXPORT_PRIVATE extern uint32_t Checksum(Vector<const byte> payload) {
#ifdef MEMORY_SANITIZER
// Computing the checksum includes padding bytes for objects like strings.
// Mark every object as initialized in the code serializer.
MSAN_MEMORY_IS_INITIALIZED(payload.begin(), payload.length());
#endif // MEMORY_SANITIZER
// Priming the adler32 call so it can see what CPU features are available.
adler32(0, NULL, 0);
return static_cast<uint32_t>(adler32(0, payload.begin(), payload.length()));
}
} // namespace internal
} // namespace v8

View File

@ -358,50 +358,7 @@ class SerializedData {
DISALLOW_COPY_AND_ASSIGN(SerializedData);
};
class Checksum {
public:
explicit Checksum(Vector<const byte> payload) {
#ifdef MEMORY_SANITIZER
// Computing the checksum includes padding bytes for objects like strings.
// Mark every object as initialized in the code serializer.
MSAN_MEMORY_IS_INITIALIZED(payload.begin(), payload.length());
#endif // MEMORY_SANITIZER
// Fletcher's checksum. Modified to reduce 64-bit sums to 32-bit.
uintptr_t a = 1;
uintptr_t b = 0;
// TODO(jgruber, v8:9171): The following DCHECK should ideally hold since we
// access payload through an uintptr_t pointer later on; and some
// architectures, e.g. arm, may generate instructions that expect correct
// alignment. However, we do not control alignment for external snapshots.
// DCHECK(IsAligned(reinterpret_cast<intptr_t>(payload.begin()),
// kIntptrSize));
DCHECK(IsAligned(payload.length(), kIntptrSize));
const uintptr_t* cur = reinterpret_cast<const uintptr_t*>(payload.begin());
const uintptr_t* end = cur + payload.length() / kIntptrSize;
while (cur < end) {
// Unsigned overflow expected and intended.
a += *cur++;
b += a;
}
#if V8_HOST_ARCH_64_BIT
a ^= a >> 32;
b ^= b >> 32;
#endif // V8_HOST_ARCH_64_BIT
a_ = static_cast<uint32_t>(a);
b_ = static_cast<uint32_t>(b);
}
bool Check(uint32_t a, uint32_t b) const { return a == a_ && b == b_; }
uint32_t a() const { return a_; }
uint32_t b() const { return b_; }
private:
uint32_t a_;
uint32_t b_;
DISALLOW_COPY_AND_ASSIGN(Checksum);
};
V8_EXPORT_PRIVATE uint32_t Checksum(Vector<const byte> payload);
} // namespace internal
} // namespace v8

View File

@ -192,9 +192,7 @@ v8::StartupData Snapshot::CreateSnapshotBlob(
DCHECK_EQ(total_length, payload_offset);
v8::StartupData result = {data, static_cast<int>(total_length)};
Checksum checksum(ChecksummedContent(&result));
SetHeaderValue(data, kChecksumPartAOffset, checksum.a());
SetHeaderValue(data, kChecksumPartBOffset, checksum.b());
SetHeaderValue(data, kChecksumOffset, Checksum(ChecksummedContent(&result)));
return result;
}
@ -208,14 +206,13 @@ uint32_t Snapshot::ExtractNumContexts(const v8::StartupData* data) {
bool Snapshot::VerifyChecksum(const v8::StartupData* data) {
base::ElapsedTimer timer;
if (FLAG_profile_deserialization) timer.Start();
uint32_t expected_a = GetHeaderValue(data, kChecksumPartAOffset);
uint32_t expected_b = GetHeaderValue(data, kChecksumPartBOffset);
Checksum checksum(ChecksummedContent(data));
uint32_t expected = GetHeaderValue(data, kChecksumOffset);
uint32_t result = Checksum(ChecksummedContent(data));
if (FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF();
PrintF("[Verifying snapshot checksum took %0.3f ms]\n", ms);
}
return checksum.Check(expected_a, expected_b);
return result == expected;
}
uint32_t Snapshot::ExtractContextOffset(const v8::StartupData* data,

View File

@ -87,9 +87,8 @@ class SnapshotByteSource final {
int position() { return position_; }
void set_position(int position) { position_ = position; }
std::pair<uint32_t, uint32_t> GetChecksum() const {
Checksum checksum(Vector<const byte>(data_, length_));
return {checksum.a(), checksum.b()};
uint32_t GetChecksum() const {
return Checksum(Vector<const byte>(data_, length_));
}
private:

View File

@ -111,12 +111,11 @@ class Snapshot : public AllStatic {
// Snapshot blob layout:
// [0] number of contexts N
// [1] rehashability
// [2] checksum part A
// [3] checksum part B
// [4] (128 bytes) version string
// [5] offset to readonly
// [6] offset to context 0
// [7] offset to context 1
// [2] checksum
// [3] (128 bytes) version string
// [4] offset to readonly
// [5] offset to context 0
// [6] offset to context 1
// ...
// ... offset to context N - 1
// ... startup snapshot data
@ -128,12 +127,8 @@ class Snapshot : public AllStatic {
// TODO(yangguo): generalize rehashing, and remove this flag.
static const uint32_t kRehashabilityOffset =
kNumberOfContextsOffset + kUInt32Size;
static const uint32_t kChecksumPartAOffset =
kRehashabilityOffset + kUInt32Size;
static const uint32_t kChecksumPartBOffset =
kChecksumPartAOffset + kUInt32Size;
static const uint32_t kVersionStringOffset =
kChecksumPartBOffset + kUInt32Size;
static const uint32_t kChecksumOffset = kRehashabilityOffset + kUInt32Size;
static const uint32_t kVersionStringOffset = kChecksumOffset + kUInt32Size;
static const uint32_t kVersionStringLength = 64;
static const uint32_t kReadOnlyOffsetOffset =
kVersionStringOffset + kVersionStringLength;
@ -141,6 +136,7 @@ class Snapshot : public AllStatic {
kReadOnlyOffsetOffset + kUInt32Size;
static Vector<const byte> ChecksummedContent(const v8::StartupData* data) {
STATIC_ASSERT(kVersionStringOffset == kChecksumOffset + kUInt32Size);
const uint32_t kChecksumStart = kVersionStringOffset;
return Vector<const byte>(
reinterpret_cast<const byte*>(data->data + kChecksumStart),

View File

@ -31,6 +31,7 @@ group("v8_run_gcmole") {
"../../third_party/icu/source/",
"../../third_party/wasm-api/wasm.h",
"../../third_party/wasm-api/wasm.hh",
"../../third_party/zlib/",
"../../third_party/inspector_protocol/",
"$target_gen_dir/../../",
"$target_gen_dir/../../torque-generated/",