Add hash fields to code cache header.
authoryangguo <yangguo@chromium.org>
Fri, 6 Feb 2015 15:20:40 +0000 (07:20 -0800)
committerCommit bot <commit-bot@chromium.org>
Fri, 6 Feb 2015 15:20:52 +0000 (15:20 +0000)
R=jochen@chromium.org
BUG=chromium:441896
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#26490}

src/flags.cc
src/serialize.cc
src/serialize.h
src/version.h
test/cctest/test-api.cc
test/cctest/test-serialize.cc

index 2aa4e6b..5e33bda 100644 (file)
@@ -556,6 +556,7 @@ uint32_t FlagList::Hash() {
   for (size_t i = 0; i < num_flags; ++i) {
     Flag* current = &flags[i];
     if (!current->IsDefault()) {
+      modified_args_as_string << i;
       modified_args_as_string << *current;
     }
   }
index 0b9e938..1423b23 100644 (file)
@@ -2500,7 +2500,11 @@ SerializedCodeData::SerializedCodeData(const List<byte>& payload,
   AllocateData(size);
 
   // Set header values.
-  SetHeaderValue(kCheckSumOffset, CheckSum(cs.source()));
+  SetHeaderValue(kVersionHashOffset, Version::Hash());
+  SetHeaderValue(kSourceHashOffset, SourceHash(cs.source()));
+  SetHeaderValue(kCpuFeaturesOffset,
+                 static_cast<uint32_t>(CpuFeatures::SupportedFeatures()));
+  SetHeaderValue(kFlagHashOffset, FlagList::Hash());
   SetHeaderValue(kNumInternalizedStringsOffset, cs.num_internalized_strings());
   SetHeaderValue(kReservationsOffset, reservations.length());
   SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
@@ -2521,16 +2525,15 @@ SerializedCodeData::SerializedCodeData(const List<byte>& payload,
 
 
 bool SerializedCodeData::IsSane(String* source) {
-  return GetHeaderValue(kCheckSumOffset) == CheckSum(source) &&
+  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;
 }
 
 
-int SerializedCodeData::CheckSum(String* string) {
-  return Version::Hash() ^ string->length();
-}
-
-
 // Return ScriptData object and relinquish ownership over it to the caller.
 ScriptData* SerializedCodeData::GetScriptData() {
   DCHECK(owns_data_);
index 9aaf381..444e881 100644 (file)
@@ -494,12 +494,12 @@ class SerializedData {
   class IsLastChunkBits : public BitField<bool, 31, 1> {};
 
  protected:
-  void SetHeaderValue(int offset, int value) {
-    memcpy(reinterpret_cast<int*>(data_) + offset, &value, sizeof(value));
+  void SetHeaderValue(int offset, uint32_t value) {
+    memcpy(reinterpret_cast<uint32_t*>(data_) + offset, &value, sizeof(value));
   }
 
-  int GetHeaderValue(int offset) const {
-    int value;
+  uint32_t GetHeaderValue(int offset) const {
+    uint32_t value;
     memcpy(&value, reinterpret_cast<int*>(data_) + offset, sizeof(value));
     return value;
   }
@@ -948,19 +948,25 @@ class SerializedCodeData : public SerializedData {
 
   bool IsSane(String* source);
 
-  int CheckSum(String* source);
+  uint32_t SourceHash(String* source) { return source->length(); }
 
   // The data header consists of int-sized entries:
   // [0] version hash
-  // [1] number of internalized strings
-  // [2] number of code stub keys
-  // [3] number of reservation size entries
-  // [4] payload length
-  static const int kCheckSumOffset = 0;
-  static const int kNumInternalizedStringsOffset = 1;
-  static const int kReservationsOffset = 2;
-  static const int kNumCodeStubKeysOffset = 3;
-  static const int kPayloadLengthOffset = 4;
+  // [1] source hash
+  // [2] cpu features
+  // [3] flag hash
+  // [4] number of internalized strings
+  // [5] number of code stub keys
+  // [6] number of reservation size entries
+  // [7] payload length
+  static const int kVersionHashOffset = 0;
+  static const int kSourceHashOffset = 1;
+  static const int kCpuFeaturesOffset = 2;
+  static const int kFlagHashOffset = 3;
+  static const int kNumInternalizedStringsOffset = 4;
+  static const int kReservationsOffset = 5;
+  static const int kNumCodeStubKeysOffset = 6;
+  static const int kPayloadLengthOffset = 7;
   static const int kHeaderSize = (kPayloadLengthOffset + 1) * kIntSize;
 };
 } }  // namespace v8::internal
index 008ed27..dbcec1b 100644 (file)
@@ -18,8 +18,9 @@ class Version {
   static int GetBuild() { return build_; }
   static int GetPatch() { return patch_; }
   static bool IsCandidate() { return candidate_; }
-  static int Hash() {
-    return static_cast<int>(base::hash_combine(major_, minor_, build_, patch_));
+  static uint32_t Hash() {
+    return static_cast<uint32_t>(
+        base::hash_combine(major_, minor_, build_, patch_));
   }
 
   // Calculate the V8 version string.
index 742ccd8..753b471 100644 (file)
@@ -21765,7 +21765,7 @@ TEST(StreamingWithHarmonyScopes) {
 
 
 void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
-  const char* garbage = "garbage garbage garbage garbage.";
+  const char* garbage = "garbage garbage garbage garbage garbage garbage";
   const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
   int length = 16;
   v8::ScriptCompiler::CachedData* cached_data =
index ef01325..85729cc 100644 (file)
@@ -1317,6 +1317,56 @@ TEST(SerializeToplevelIsolates) {
 }
 
 
+TEST(SerializeToplevelFlagChange) {
+  FLAG_serialize_toplevel = true;
+
+  const char* source = "function f() { return 'abc'; }; f() + 'def'";
+  v8::ScriptCompiler::CachedData* cache;
+
+  v8::Isolate* isolate1 = v8::Isolate::New();
+  {
+    v8::Isolate::Scope iscope(isolate1);
+    v8::HandleScope scope(isolate1);
+    v8::Local<v8::Context> context = v8::Context::New(isolate1);
+    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")));
+  }
+  isolate1->Dispose();
+
+  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);
+    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, cache);
+    v8::ScriptCompiler::CompileUnbound(isolate2, &source,
+                                       v8::ScriptCompiler::kConsumeCodeCache);
+    CHECK(cache->rejected);
+  }
+  isolate2->Dispose();
+}
+
+
 TEST(SerializeWithHarmonyScoping) {
   FLAG_serialize_toplevel = true;
   FLAG_harmony_scoping = true;