Revision: 17473
Author:   [email protected]
Date:     Tue Nov  5 10:14:48 2013 UTC
Log:      Make snapshots reproducible.

To keep the structure of the serializer more or less untouched, we use
some ingenious Corry-approved(TM) 3-step technology (a.k.a. "hack"):

   * Create copies of code objects.
   * Wipe out all absolute addresses in these copies.
   * Write out the cleaned copies instead of the originals.

In conjunction with --random-seed, our snapshots are reproducible now.

BUG=v8:2885
[email protected], [email protected]

Review URL: https://codereview.chromium.org/54823002
http://code.google.com/p/v8/source/detail?r=17473

Modified:
 /branches/bleeding_edge/src/arm/assembler-arm-inl.h
 /branches/bleeding_edge/src/assembler.h
 /branches/bleeding_edge/src/ia32/assembler-ia32-inl.h
 /branches/bleeding_edge/src/mips/assembler-mips-inl.h
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/serialize.cc
 /branches/bleeding_edge/src/x64/assembler-x64-inl.h

=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm-inl.h Tue Nov 5 09:40:36 2013 UTC +++ /branches/bleeding_edge/src/arm/assembler-arm-inl.h Tue Nov 5 10:14:48 2013 UTC
@@ -256,6 +256,15 @@
          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
   return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
 }
+
+
+void RelocInfo::WipeOut() {
+  ASSERT(IsEmbeddedObject(rmode_) ||
+         IsCodeTarget(rmode_) ||
+         IsRuntimeEntry(rmode_) ||
+         IsExternalReference(rmode_));
+  Assembler::set_target_pointer_at(pc_, NULL);
+}


 bool RelocInfo::IsPatchedReturnSequence() {
=======================================
--- /branches/bleeding_edge/src/assembler.h     Tue Nov  5 09:40:36 2013 UTC
+++ /branches/bleeding_edge/src/assembler.h     Tue Nov  5 10:14:48 2013 UTC
@@ -435,6 +435,10 @@
   INLINE(void set_call_object(Object* target));
   INLINE(Object** call_object_address());

+  // Wipe out a relocation to a fixed value, used for making snapshots
+  // reproducible.
+  INLINE(void WipeOut());
+
   template<typename StaticVisitor> inline void Visit(Heap* heap);
   inline void Visit(Isolate* isolate, ObjectVisitor* v);

=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32-inl.h Tue Nov 5 09:40:36 2013 UTC +++ /branches/bleeding_edge/src/ia32/assembler-ia32-inl.h Tue Nov 5 10:14:48 2013 UTC
@@ -241,6 +241,18 @@
          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
   return reinterpret_cast<Object**>(pc_ + 1);
 }
+
+
+void RelocInfo::WipeOut() {
+  if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_)) {
+    Memory::Address_at(pc_) = NULL;
+  } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
+    // Effectively write zero into the relocation.
+    Assembler::set_target_address_at(pc_, pc_ + sizeof(int32_t));
+  } else {
+    UNREACHABLE();
+  }
+}


 bool RelocInfo::IsPatchedReturnSequence() {
=======================================
--- /branches/bleeding_edge/src/mips/assembler-mips-inl.h Tue Nov 5 09:40:36 2013 UTC +++ /branches/bleeding_edge/src/mips/assembler-mips-inl.h Tue Nov 5 10:14:48 2013 UTC
@@ -313,6 +313,15 @@
 void RelocInfo::set_call_object(Object* target) {
   *call_object_address() = target;
 }
+
+
+void RelocInfo::WipeOut() {
+  ASSERT(IsEmbeddedObject(rmode_) ||
+         IsCodeTarget(rmode_) ||
+         IsRuntimeEntry(rmode_) ||
+         IsExternalReference(rmode_));
+  Assembler::set_target_address_at(pc_, NULL);
+}


 bool RelocInfo::IsPatchedReturnSequence() {
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Tue Nov  5 10:05:03 2013 UTC
+++ /branches/bleeding_edge/src/objects-inl.h   Tue Nov  5 10:14:48 2013 UTC
@@ -5323,6 +5323,17 @@
 ACCESSORS(Code, raw_type_feedback_info, Object, kTypeFeedbackInfoOffset)


+void Code::WipeOutHeader() {
+  WRITE_FIELD(this, kRelocationInfoOffset, NULL);
+  WRITE_FIELD(this, kHandlerTableOffset, NULL);
+  WRITE_FIELD(this, kDeoptimizationDataOffset, NULL);
+  // Do not wipe out e.g. a minor key.
+  if (!READ_FIELD(this, kTypeFeedbackInfoOffset)->IsSmi()) {
+    WRITE_FIELD(this, kTypeFeedbackInfoOffset, NULL);
+  }
+}
+
+
 Object* Code::type_feedback_info() {
   ASSERT(kind() == FUNCTION);
   return raw_type_feedback_info();
=======================================
--- /branches/bleeding_edge/src/objects.h       Tue Nov  5 10:05:03 2013 UTC
+++ /branches/bleeding_edge/src/objects.h       Tue Nov  5 10:14:48 2013 UTC
@@ -5198,6 +5198,15 @@

   void ReplaceNthCell(int n, Cell* replace_with);

+  // The entire code object including its header is copied verbatim to the
+  // snapshot so that it can be written in one, fast, memcpy during
+  // deserialization. The deserializer will overwrite some pointers, rather
+  // like a runtime linker, but the random allocation addresses used in the
+ // mksnapshot process would still be present in the unlinked snapshot data, + // which would make snapshot production non-reproducible. This method wipes
+  // out the to-be-overwritten header data for reproducible snapshots.
+  inline void WipeOutHeader();
+
   class ExtraICStateStrictMode: public BitField<StrictModeFlag, 0, 1> {};
   class ExtraICStateKeyedAccessStoreMode:
       public BitField<KeyedAccessStoreMode, 1, 4> {};  // NOLINT
=======================================
--- /branches/bleeding_edge/src/serialize.cc    Tue Nov  5 09:40:36 2013 UTC
+++ /branches/bleeding_edge/src/serialize.cc    Tue Nov  5 10:14:48 2013 UTC
@@ -1774,12 +1774,31 @@
   // can't serialize any other kinds of external strings.
   UNREACHABLE();
 }
+
+
+static Code* CloneCodeObject(HeapObject* code) {
+  Address copy = new byte[code->Size()];
+  OS::MemCopy(copy, code->address(), code->Size());
+  return Code::cast(HeapObject::FromAddress(copy));
+}
+
+
+static void WipeOutRelocations(Code* code) {
+  int mode_mask =
+      RelocInfo::kCodeTargetMask |
+      RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
+      RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) |
+      RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
+  for (RelocIterator it(code, mode_mask); !it.done(); it.next()) {
+    it.rinfo()->WipeOut();
+  }
+}


 int Serializer::ObjectSerializer::OutputRawData(
     Address up_to, Serializer::ObjectSerializer::ReturnSkip return_skip) {
   Address object_start = object_->address();
-  Address base = object_start + bytes_processed_so_far_;
+  int base = bytes_processed_so_far_;
   int up_to_offset = static_cast<int>(up_to - object_start);
   int to_skip = up_to_offset - bytes_processed_so_far_;
   int bytes_to_output = to_skip;
@@ -1809,10 +1828,22 @@
       sink_->Put(kRawData, "RawData");
       sink_->PutInt(bytes_to_output, "length");
     }
+
+ // To make snapshots reproducible, we need to wipe out all pointers in code.
+    if (code_object_) {
+      Code* code = CloneCodeObject(object_);
+      WipeOutRelocations(code);
+      // We need to wipe out the header fields *after* wiping out the
+ // relocations, because some of these fields are needed for the latter.
+      code->WipeOutHeader();
+      object_start = code->address();
+    }
+
+    const char* description = code_object_ ? "Code" : "Byte";
     for (int i = 0; i < bytes_to_output; i++) {
-      unsigned int data = base[i];
-      sink_->PutSection(data, "Byte");
+      sink_->PutSection(object_start[base + i], description);
     }
+    if (code_object_) delete[] object_start;
   }
   if (to_skip != 0 && return_skip == kIgnoringReturn) {
     sink_->Put(kSkip, "Skip");
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64-inl.h Tue Nov 5 09:40:36 2013 UTC +++ /branches/bleeding_edge/src/x64/assembler-x64-inl.h Tue Nov 5 10:14:48 2013 UTC
@@ -362,6 +362,18 @@
         host(), NULL, cell);
   }
 }
+
+
+void RelocInfo::WipeOut() {
+  if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_)) {
+    Memory::Address_at(pc_) = NULL;
+  } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
+    // Effectively write zero into the relocation.
+    Assembler::set_target_address_at(pc_, pc_ + sizeof(int32_t));
+  } else {
+    UNREACHABLE();
+  }
+}


 bool RelocInfo::IsPatchedReturnSequence() {

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to