Commit 7819c593 authored by yangguo's avatar yangguo Committed by Commit bot

Add payload checksum to code cache data.

R=jochen@chromium.org
BUG=chromium:441896
LOG=N

Review URL: https://codereview.chromium.org/907013002

Cr-Commit-Position: refs/heads/master@{#26529}
parent 6f97beb5
......@@ -2157,6 +2157,10 @@ void Serializer::Pad() {
for (unsigned i = 0; i < sizeof(int32_t) - 1; i++) {
sink_->Put(kNop, "Padding");
}
// Pad up to pointer size for checksum.
while (!IsAligned(sink_->Position(), kPointerAlignment)) {
sink_->Put(kNop, "Padding");
}
}
......@@ -2482,6 +2486,41 @@ Vector<const byte> SnapshotData::Payload() const {
}
class Checksum {
public:
explicit Checksum(Vector<const byte> payload) {
// Fletcher's checksum. Modified to reduce 64-bit sums to 32-bit.
uintptr_t a = 1;
uintptr_t b = 0;
const uintptr_t* cur = reinterpret_cast<const uintptr_t*>(payload.start());
DCHECK(IsAligned(payload.length(), kIntptrSize));
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);
};
SerializedCodeData::SerializedCodeData(const List<byte>& payload,
const CodeSerializer& cs) {
DisallowHeapAllocation no_gc;
......@@ -2510,6 +2549,10 @@ SerializedCodeData::SerializedCodeData(const List<byte>& payload,
SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
SetHeaderValue(kPayloadLengthOffset, payload.length());
Checksum checksum(payload.ToConstVector());
SetHeaderValue(kChecksum1Offset, checksum.a());
SetHeaderValue(kChecksum2Offset, checksum.b());
// Copy reservation chunk sizes.
CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
reservation_size);
......@@ -2524,13 +2567,14 @@ SerializedCodeData::SerializedCodeData(const List<byte>& payload,
}
bool SerializedCodeData::IsSane(String* source) {
bool SerializedCodeData::IsSane(String* source) const {
return GetHeaderValue(kVersionHashOffset) == Version::Hash() &&
GetHeaderValue(kSourceHashOffset) == SourceHash(source) &&
GetHeaderValue(kCpuFeaturesOffset) ==
static_cast<uint32_t>(CpuFeatures::SupportedFeatures()) &&
GetHeaderValue(kFlagHashOffset) == FlagList::Hash() &&
Payload().length() >= SharedFunctionInfo::kSize;
Checksum(Payload()).Check(GetHeaderValue(kChecksum1Offset),
GetHeaderValue(kChecksum2Offset));
}
......
......@@ -946,9 +946,9 @@ class SerializedCodeData : public SerializedData {
explicit SerializedCodeData(ScriptData* data)
: SerializedData(const_cast<byte*>(data->data()), data->length()) {}
bool IsSane(String* source);
bool IsSane(String* source) const;
uint32_t SourceHash(String* source) { return source->length(); }
uint32_t SourceHash(String* source) const { return source->length(); }
// The data header consists of int-sized entries:
// [0] version hash
......@@ -967,7 +967,10 @@ class SerializedCodeData : public SerializedData {
static const int kReservationsOffset = 5;
static const int kNumCodeStubKeysOffset = 6;
static const int kPayloadLengthOffset = 7;
static const int kHeaderSize = (kPayloadLengthOffset + 1) * kIntSize;
static const int kChecksum1Offset = 8;
static const int kChecksum2Offset = 9;
static const int kHeaderSize =
POINTER_SIZE_ALIGN((kChecksum2Offset + 1) * kIntSize);
};
} } // namespace v8::internal
......
......@@ -1244,12 +1244,8 @@ static void SerializerCodeEventListener(const v8::JitCodeEvent* event) {
}
TEST(SerializeToplevelIsolates) {
FLAG_serialize_toplevel = true;
const char* source = "function f() { return 'abc'; }; f() + 'def'";
v8::ScriptCompiler::CachedData* ProduceCache(const char* source) {
v8::ScriptCompiler::CachedData* cache;
v8::Isolate* isolate1 = v8::Isolate::New();
{
v8::Isolate::Scope iscope(isolate1);
......@@ -1274,6 +1270,15 @@ TEST(SerializeToplevelIsolates) {
CHECK(result->ToString(isolate1)->Equals(v8_str("abcdef")));
}
isolate1->Dispose();
return cache;
}
TEST(SerializeToplevelIsolates) {
FLAG_serialize_toplevel = true;
const char* source = "function f() { return 'abc'; }; f() + 'def'";
v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
v8::Isolate* isolate2 = v8::Isolate::New();
isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
......@@ -1307,35 +1312,37 @@ TEST(SerializeToplevelFlagChange) {
FLAG_serialize_toplevel = true;
const char* source = "function f() { return 'abc'; }; f() + 'def'";
v8::ScriptCompiler::CachedData* cache;
v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
v8::Isolate* isolate1 = v8::Isolate::New();
v8::Isolate* isolate2 = v8::Isolate::New();
FLAG_allow_natives_syntax = true; // Flag change should trigger cache reject.
{
v8::Isolate::Scope iscope(isolate1);
v8::HandleScope scope(isolate1);
v8::Local<v8::Context> context = v8::Context::New(isolate1);
v8::Isolate::Scope iscope(isolate2);
v8::HandleScope scope(isolate2);
v8::Local<v8::Context> context = v8::Context::New(isolate2);
v8::Context::Scope context_scope(context);
v8::Local<v8::String> source_str = v8_str(source);
v8::ScriptOrigin origin(v8_str("test"));
v8::ScriptCompiler::Source source(source_str, origin);
v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
CHECK(data);
// Persist cached data.
uint8_t* buffer = NewArray<uint8_t>(data->length);
MemCopy(buffer, data->data, data->length);
cache = new v8::ScriptCompiler::CachedData(
buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
CHECK(result->ToString(isolate1)->Equals(v8_str("abcdef")));
v8::ScriptCompiler::Source source(source_str, origin, cache);
v8::ScriptCompiler::CompileUnbound(isolate2, &source,
v8::ScriptCompiler::kConsumeCodeCache);
CHECK(cache->rejected);
}
isolate1->Dispose();
isolate2->Dispose();
}
TEST(SerializeToplevelBitFlip) {
FLAG_serialize_toplevel = true;
const char* source = "function f() { return 'abc'; }; f() + 'def'";
v8::ScriptCompiler::CachedData* cache = ProduceCache(source);
// Random bit flip.
const_cast<uint8_t*>(cache->data)[337] ^= 0x40;
v8::Isolate* isolate2 = v8::Isolate::New();
FLAG_allow_natives_syntax = true; // Flag change should trigger cache reject.
{
v8::Isolate::Scope iscope(isolate2);
v8::HandleScope scope(isolate2);
......
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