Revision: 4687
Author: [email protected]
Date: Thu May 20 06:54:31 2010
Log: Orthogonalize the byte codes used for the snapshot so that
the issue of how the pointee is found and how the pointer
is encoded are separated out.  This will make it simpler to
support various pointers from and to code in the future.
Review URL: http://codereview.chromium.org/2069013
http://code.google.com/p/v8/source/detail?r=4687

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

=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Mon May 17 23:38:42 2010 +++ /branches/bleeding_edge/src/arm/assembler-arm.cc Thu May 20 06:54:31 2010
@@ -108,6 +108,15 @@
 const int RelocInfo::kApplyMask = 0;


+bool RelocInfo::IsCodedSpecially() {
+ // The deserializer needs to know whether a pointer is specially coded. Being + // specially coded on ARM means that it is a movw/movt instruction. We don't
+  // generate those yet.
+  return false;
+}
+
+
+
 void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
   // Patch the code at the current address with the supplied instructions.
   Instr* pc = reinterpret_cast<Instr*>(pc_);
=======================================
--- /branches/bleeding_edge/src/assembler.h     Tue May 18 06:39:16 2010
+++ /branches/bleeding_edge/src/assembler.h     Thu May 20 06:54:31 2010
@@ -184,6 +184,11 @@
   // Apply a relocation by delta bytes
   INLINE(void apply(intptr_t delta));

+ // Is the pointer this relocation info refers to coded like a plain pointer
+  // or is it strange in some way (eg relative or patched into a series of
+  // instructions).
+  bool IsCodedSpecially();
+
   // Read/modify the code target in the branch/call instruction
   // this relocation applies to;
   // can only be called if IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY
=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.cc Mon May 17 08:41:35 2010 +++ /branches/bleeding_edge/src/ia32/assembler-ia32.cc Thu May 20 06:54:31 2010
@@ -162,6 +162,15 @@
     1 << RelocInfo::JS_RETURN | 1 << RelocInfo::INTERNAL_REFERENCE;


+bool RelocInfo::IsCodedSpecially() {
+ // The deserializer needs to know whether a pointer is specially coded. Being + // specially coded on IA32 means that it is a relative address, as used by + // branch instructions. These are also the ones that need changing when a
+  // code object moves.
+  return (1 << rmode_) & kApplyMask;
+}
+
+
 void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
   // Patch the code at the current address with the supplied instructions.
   for (int i = 0; i < instruction_count; i++) {
=======================================
--- /branches/bleeding_edge/src/serialize.cc    Thu May  6 06:21:53 2010
+++ /branches/bleeding_edge/src/serialize.cc    Thu May 20 06:54:31 2010
@@ -660,27 +660,164 @@
 }


-#define ONE_CASE_PER_SPACE(base_tag)   \
-  case (base_tag) + NEW_SPACE:         /* NOLINT */ \
-  case (base_tag) + OLD_POINTER_SPACE: /* NOLINT */ \
-  case (base_tag) + OLD_DATA_SPACE:    /* NOLINT */ \
-  case (base_tag) + CODE_SPACE:        /* NOLINT */ \
-  case (base_tag) + MAP_SPACE:         /* NOLINT */ \
-  case (base_tag) + CELL_SPACE:        /* NOLINT */ \
-  case (base_tag) + kLargeData:        /* NOLINT */ \
-  case (base_tag) + kLargeCode:        /* NOLINT */ \
-  case (base_tag) + kLargeFixedArray:  /* NOLINT */
+// This macro is always used with a constant argument so it should all fold
+// away to almost nothing in the generated code. It might be nicer to do this
+// with the ternary operator but there are type issues with that.
+#define ASSIGN_DEST_SPACE(space_number) \ + Space* dest_space; \ + if (space_number == NEW_SPACE) { \ + dest_space = Heap::new_space(); \ + } else if (space_number == OLD_POINTER_SPACE) { \ + dest_space = Heap::old_pointer_space(); \ + } else if (space_number == OLD_DATA_SPACE) { \ + dest_space = Heap::old_data_space(); \ + } else if (space_number == CODE_SPACE) { \ + dest_space = Heap::code_space(); \ + } else if (space_number == MAP_SPACE) { \ + dest_space = Heap::map_space(); \ + } else if (space_number == CELL_SPACE) { \ + dest_space = Heap::cell_space(); \ + } else { \ + ASSERT(space_number >= LO_SPACE); \ + dest_space = Heap::lo_space(); \
+  }
+
+
+static const int kUnknownOffsetFromStart = -1;


 void Deserializer::ReadChunk(Object** current,
                              Object** limit,
-                             int space,
+                             int source_space,
                              Address address) {
   while (current < limit) {
     int data = source_->Get();
     switch (data) {
+#define CASE_STATEMENT(where, how, within, space_number) \ + case where + how + within + space_number: \ + ASSERT((where & ~kPointedToMask) == 0); \ + ASSERT((how & ~kHowToCodeMask) == 0); \ + ASSERT((within & ~kWhereToPointMask) == 0); \
+      ASSERT((space_number & ~kSpaceMask) == 0);
+
+#define CASE_BODY(where, how, within, space_number_if_any, offset_from_start) \ + { \ + bool emit_write_barrier = false; \ + bool current_was_incremented = false; \ + int space_number = space_number_if_any == kAnyOldSpace ? \ + (data & kSpaceMask) : space_number_if_any; \ + if (where == kNewObject && how == kPlain && within == kStartOfObject) {\ + ASSIGN_DEST_SPACE(space_number) \ + ReadObject(space_number, dest_space, current); \ + emit_write_barrier = \ + (space_number == NEW_SPACE && source_space != NEW_SPACE); \ + } else { \ + Object* new_object = NULL; /* May not be a real Object pointer. */ \ + if (where == kNewObject) { \ + ASSIGN_DEST_SPACE(space_number) \ + ReadObject(space_number, dest_space, &new_object); \ + } else if (where == kRootArray) { \ + int root_id = source_->GetInt(); \ + new_object = Heap::roots_address()[root_id]; \ + } else if (where == kPartialSnapshotCache) { \ + int cache_index = source_->GetInt(); \ + new_object = partial_snapshot_cache_[cache_index]; \ + } else if (where == kExternalReference) { \ + int reference_id = source_->GetInt(); \ + Address address = \ + external_reference_decoder_->Decode(reference_id); \ + new_object = reinterpret_cast<Object*>(address); \ + } else if (where == kBackref) { \ + emit_write_barrier = \ + (space_number == NEW_SPACE && source_space != NEW_SPACE); \ + new_object = GetAddressFromEnd(data & kSpaceMask); \ + } else { \ + ASSERT(where == kFromStart); \ + if (offset_from_start == kUnknownOffsetFromStart) { \ + emit_write_barrier = \ + (space_number == NEW_SPACE && source_space != NEW_SPACE); \ + new_object = GetAddressFromStart(data & kSpaceMask); \ + } else { \ + Address object_address = pages_[space_number][0] + \ + (offset_from_start << kObjectAlignmentBits); \ + new_object = HeapObject::FromAddress(object_address); \ + } \ + } \ + if (within == kFirstInstruction) { \ + Code* new_code_object = reinterpret_cast<Code*>(new_object); \ + new_object = reinterpret_cast<Object*>( \ + new_code_object->instruction_start()); \ + } \ + if (how == kFromCode) { \ + Address location_of_branch_data = \ + reinterpret_cast<Address>(current); \ + Assembler::set_target_at(location_of_branch_data, \ + reinterpret_cast<Address>(new_object)); \ + if (within == kFirstInstruction) { \ + location_of_branch_data += Assembler::kCallTargetSize; \ + current = reinterpret_cast<Object**>(location_of_branch_data); \ + current_was_incremented = true; \ + } \ + } else { \ + *current = new_object; \ + } \ + } \ + if (emit_write_barrier) { \ + Heap::RecordWrite(address, static_cast<int>( \ + reinterpret_cast<Address>(current) - address)); \ + } \ + if (!current_was_incremented) { \ + current++; /* Increment current if it wasn't done above. */ \ + } \ + break; \ + } \
+
+// This generates a case and a body for each space. The large object spaces are
+// very rare in snapshots so they are grouped in one body.
+#define ONE_PER_SPACE(where, how, within) \ + CASE_STATEMENT(where, how, within, NEW_SPACE) \ + CASE_BODY(where, how, within, NEW_SPACE, kUnknownOffsetFromStart) \ + CASE_STATEMENT(where, how, within, OLD_DATA_SPACE) \ + CASE_BODY(where, how, within, OLD_DATA_SPACE, kUnknownOffsetFromStart) \ + CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE) \ + CASE_BODY(where, how, within, OLD_POINTER_SPACE, kUnknownOffsetFromStart) \ + CASE_STATEMENT(where, how, within, CODE_SPACE) \ + CASE_BODY(where, how, within, CODE_SPACE, kUnknownOffsetFromStart) \ + CASE_STATEMENT(where, how, within, CELL_SPACE) \ + CASE_BODY(where, how, within, CELL_SPACE, kUnknownOffsetFromStart) \ + CASE_STATEMENT(where, how, within, MAP_SPACE) \ + CASE_BODY(where, how, within, MAP_SPACE, kUnknownOffsetFromStart) \ + CASE_STATEMENT(where, how, within, kLargeData) \ + CASE_STATEMENT(where, how, within, kLargeCode) \ + CASE_STATEMENT(where, how, within, kLargeFixedArray) \
+  CASE_BODY(where, how, within, kAnyOldSpace, kUnknownOffsetFromStart)
+
+// This generates a case and a body for the new space (which has to do extra
+// write barrier handling) and handles the other spaces with 8 fall-through
+// cases and one body.
+#define ALL_SPACES(where, how, within) \ + CASE_STATEMENT(where, how, within, NEW_SPACE) \ + CASE_BODY(where, how, within, NEW_SPACE, kUnknownOffsetFromStart) \ + CASE_STATEMENT(where, how, within, OLD_DATA_SPACE) \ + CASE_STATEMENT(where, how, within, OLD_POINTER_SPACE) \ + CASE_STATEMENT(where, how, within, CODE_SPACE) \ + CASE_STATEMENT(where, how, within, CELL_SPACE) \ + CASE_STATEMENT(where, how, within, MAP_SPACE) \ + CASE_STATEMENT(where, how, within, kLargeData) \ + CASE_STATEMENT(where, how, within, kLargeCode) \ + CASE_STATEMENT(where, how, within, kLargeFixedArray) \
+  CASE_BODY(where, how, within, kAnyOldSpace, kUnknownOffsetFromStart)
+
+#define EMIT_COMMON_REFERENCE_PATTERNS(pseudo_space_number, \ + space_number, \ + offset_from_start) \ + CASE_STATEMENT(kFromStart, kPlain, kStartOfObject, pseudo_space_number) \ + CASE_BODY(kFromStart, kPlain, kStartOfObject, space_number, offset_from_start)
+
+ // We generate 15 cases and bodies that process special tags that combine
+      // the raw data tag and the length into one byte.
 #define RAW_CASE(index, size)                                      \
-      case RAW_DATA_SERIALIZATION + index: {                       \
+      case kRawData + index: {                                     \
         byte* raw_data_out = reinterpret_cast<byte*>(current);     \
         source_->CopyRaw(raw_data_out, size);                      \
         current = reinterpret_cast<Object**>(raw_data_out + size); \
@@ -688,144 +825,77 @@
       }
       COMMON_RAW_LENGTHS(RAW_CASE)
 #undef RAW_CASE
-      case RAW_DATA_SERIALIZATION: {
+
+ // Deserialize a chunk of raw data that doesn't have one of the popular
+      // lengths.
+      case kRawData: {
         int size = source_->GetInt();
         byte* raw_data_out = reinterpret_cast<byte*>(current);
         source_->CopyRaw(raw_data_out, size);
         current = reinterpret_cast<Object**>(raw_data_out + size);
         break;
       }
-      case OBJECT_SERIALIZATION + NEW_SPACE: {
-        ReadObject(NEW_SPACE, Heap::new_space(), current);
-        if (space != NEW_SPACE) {
-          Heap::RecordWrite(address, static_cast<int>(
-              reinterpret_cast<Address>(current) - address));
-        }
-        current++;
-        break;
-      }
-      case OBJECT_SERIALIZATION + OLD_DATA_SPACE:
-        ReadObject(OLD_DATA_SPACE, Heap::old_data_space(), current++);
-        break;
-      case OBJECT_SERIALIZATION + OLD_POINTER_SPACE:
- ReadObject(OLD_POINTER_SPACE, Heap::old_pointer_space(), current++);
-        break;
-      case OBJECT_SERIALIZATION + MAP_SPACE:
-        ReadObject(MAP_SPACE, Heap::map_space(), current++);
-        break;
-      case OBJECT_SERIALIZATION + CODE_SPACE:
-        ReadObject(CODE_SPACE, Heap::code_space(), current++);
-        break;
-      case OBJECT_SERIALIZATION + CELL_SPACE:
-        ReadObject(CELL_SPACE, Heap::cell_space(), current++);
-        break;
-      case OBJECT_SERIALIZATION + kLargeData:
-        ReadObject(kLargeData, Heap::lo_space(), current++);
-        break;
-      case OBJECT_SERIALIZATION + kLargeCode:
-        ReadObject(kLargeCode, Heap::lo_space(), current++);
-        break;
-      case OBJECT_SERIALIZATION + kLargeFixedArray:
-        ReadObject(kLargeFixedArray, Heap::lo_space(), current++);
-        break;
-      case CODE_OBJECT_SERIALIZATION + kLargeCode: {
-        Object* new_code_object = NULL;
-        ReadObject(kLargeCode, Heap::lo_space(), &new_code_object);
-        Code* code_object = reinterpret_cast<Code*>(new_code_object);
-        // Setting a branch/call to another code object from code.
- Address location_of_branch_data = reinterpret_cast<Address>(current);
-        Assembler::set_target_at(location_of_branch_data,
-                                 code_object->instruction_start());
-        location_of_branch_data += Assembler::kCallTargetSize;
-        current = reinterpret_cast<Object**>(location_of_branch_data);
-        break;
-      }
-      case CODE_OBJECT_SERIALIZATION + CODE_SPACE: {
-        Object* new_code_object = NULL;
-        ReadObject(CODE_SPACE, Heap::code_space(), &new_code_object);
-        Code* code_object = reinterpret_cast<Code*>(new_code_object);
-        // Setting a branch/call to another code object from code.
- Address location_of_branch_data = reinterpret_cast<Address>(current);
-        Assembler::set_target_at(location_of_branch_data,
-                                 code_object->instruction_start());
-        location_of_branch_data += Assembler::kCallTargetSize;
-        current = reinterpret_cast<Object**>(location_of_branch_data);
-        break;
-      }
-      ONE_CASE_PER_SPACE(BACKREF_SERIALIZATION) {
-        // Write a backreference to an object we unpacked earlier.
-        int backref_space = (data & kSpaceMask);
-        if (backref_space == NEW_SPACE && space != NEW_SPACE) {
-          Heap::RecordWrite(address, static_cast<int>(
-              reinterpret_cast<Address>(current) - address));
-        }
-        *current++ = GetAddressFromEnd(backref_space);
-        break;
-      }
-      ONE_CASE_PER_SPACE(REFERENCE_SERIALIZATION) {
-        // Write a reference to an object we unpacked earlier.
-        int reference_space = (data & kSpaceMask);
-        if (reference_space == NEW_SPACE && space != NEW_SPACE) {
-          Heap::RecordWrite(address, static_cast<int>(
-              reinterpret_cast<Address>(current) - address));
-        }
-        *current++ = GetAddressFromStart(reference_space);
-        break;
-      }
-#define COMMON_REFS_CASE(index, reference_space, address) \ - case REFERENCE_SERIALIZATION + index: { \ - ASSERT(SpaceIsPaged(reference_space)); \ - Address object_address = \ - pages_[reference_space][0] + (address << kObjectAlignmentBits); \ - *current++ = HeapObject::FromAddress(object_address); \ - break; \
-      }
-      COMMON_REFERENCE_PATTERNS(COMMON_REFS_CASE)
-#undef COMMON_REFS_CASE
-      ONE_CASE_PER_SPACE(CODE_BACKREF_SERIALIZATION) {
-        int backref_space = (data & kSpaceMask);
- // Can't use Code::cast because heap is not set up yet and assertions
-        // will fail.
-        Code* code_object =
-            reinterpret_cast<Code*>(GetAddressFromEnd(backref_space));
- // Setting a branch/call to previously decoded code object from code. - Address location_of_branch_data = reinterpret_cast<Address>(current);
-        Assembler::set_target_at(location_of_branch_data,
-                                 code_object->instruction_start());
-        location_of_branch_data += Assembler::kCallTargetSize;
-        current = reinterpret_cast<Object**>(location_of_branch_data);
-        break;
-      }
-      ONE_CASE_PER_SPACE(CODE_REFERENCE_SERIALIZATION) {
-        int backref_space = (data & kSpaceMask);
- // Can't use Code::cast because heap is not set up yet and assertions
-        // will fail.
-        Code* code_object =
-            reinterpret_cast<Code*>(GetAddressFromStart(backref_space));
- // Setting a branch/call to previously decoded code object from code. - Address location_of_branch_data = reinterpret_cast<Address>(current);
-        Assembler::set_target_at(location_of_branch_data,
-                                 code_object->instruction_start());
-        location_of_branch_data += Assembler::kCallTargetSize;
-        current = reinterpret_cast<Object**>(location_of_branch_data);
-        break;
-      }
-      case EXTERNAL_REFERENCE_SERIALIZATION: {
-        int reference_id = source_->GetInt();
- Address address = external_reference_decoder_->Decode(reference_id);
-        *current++ = reinterpret_cast<Object*>(address);
-        break;
-      }
-      case EXTERNAL_BRANCH_TARGET_SERIALIZATION: {
-        int reference_id = source_->GetInt();
- Address address = external_reference_decoder_->Decode(reference_id); - Address location_of_branch_data = reinterpret_cast<Address>(current); - Assembler::set_external_target_at(location_of_branch_data, address);
-        location_of_branch_data += Assembler::kExternalTargetSize;
-        current = reinterpret_cast<Object**>(location_of_branch_data);
-        break;
-      }
-      case START_NEW_PAGE_SERIALIZATION: {
+
+      // Deserialize a new object and write a pointer to it to the current
+      // object.
+      ONE_PER_SPACE(kNewObject, kPlain, kStartOfObject)
+      // Deserialize a new code object and write a pointer to its first
+      // instruction to the current code object.
+      ONE_PER_SPACE(kNewObject, kFromCode, kFirstInstruction)
+ // Find a recently deserialized object using its offset from the current
+      // allocation point and write a pointer to it to the current object.
+      ALL_SPACES(kBackref, kPlain, kStartOfObject)
+      // Find a recently deserialized code object using its offset from the
+ // current allocation point and write a pointer to its first instruction
+      // to the current code object.
+      ALL_SPACES(kBackref, kFromCode, kFirstInstruction)
+ // Find an already deserialized object using its offset from the start
+      // and write a pointer to it to the current object.
+      ALL_SPACES(kFromStart, kPlain, kStartOfObject)
+      // Find an already deserialized code object using its offset from the
+ // start and write a pointer to its first instruction to the current code
+      // object.
+      ALL_SPACES(kFromStart, kFromCode, kFirstInstruction)
+ // Find an already deserialized object at one of the predetermined popular + // offsets from the start and write a pointer to it in the current object.
+      COMMON_REFERENCE_PATTERNS(EMIT_COMMON_REFERENCE_PATTERNS)
+      // Find an object in the roots array and write a pointer to it to the
+      // current object.
+      CASE_STATEMENT(kRootArray, kPlain, kStartOfObject, 0)
+ CASE_BODY(kRootArray, kPlain, kStartOfObject, 0, kUnknownOffsetFromStart) + // Find an object in the partial snapshots cache and write a pointer to it
+      // to the current object.
+      CASE_STATEMENT(kPartialSnapshotCache, kPlain, kStartOfObject, 0)
+      CASE_BODY(kPartialSnapshotCache,
+                kPlain,
+                kStartOfObject,
+                0,
+                kUnknownOffsetFromStart)
+ // Find an external reference and write a pointer to it to the current
+      // object.
+      CASE_STATEMENT(kExternalReference, kPlain, kStartOfObject, 0)
+      CASE_BODY(kExternalReference,
+                kPlain,
+                kStartOfObject,
+                0,
+                kUnknownOffsetFromStart)
+ // Find an external reference and write a pointer to it in the current
+      // code object.
+      CASE_STATEMENT(kExternalReference, kFromCode, kStartOfObject, 0)
+      CASE_BODY(kExternalReference,
+                kFromCode,
+                kStartOfObject,
+                0,
+                kUnknownOffsetFromStart)
+
+#undef CASE_STATEMENT
+#undef CASE_BODY
+#undef ONE_PER_SPACE
+#undef ALL_SPACES
+#undef EMIT_COMMON_REFERENCE_PATTERNS
+#undef ASSIGN_DEST_SPACE
+
+      case kNewPage: {
         int space = source_->Get();
         pages_[space].Add(last_object_address_);
         if (space == CODE_SPACE) {
@@ -833,7 +903,8 @@
         }
         break;
       }
-      case NATIVES_STRING_RESOURCE: {
+
+      case kNativesStringResource: {
         int index = source_->Get();
         Vector<const char> source_vector = Natives::GetScriptSource(index);
         NativesExternalStringResource* resource =
@@ -841,21 +912,13 @@
         *current++ = reinterpret_cast<Object*>(resource);
         break;
       }
-      case ROOT_SERIALIZATION: {
-        int root_id = source_->GetInt();
-        *current++ = Heap::roots_address()[root_id];
-        break;
-      }
-      case PARTIAL_SNAPSHOT_CACHE_ENTRY: {
-        int cache_index = source_->GetInt();
-        *current++ = partial_snapshot_cache_[cache_index];
-        break;
-      }
-      case SYNCHRONIZE: {
+
+      case kSynchronize: {
// If we get here then that indicates that you have a mismatch between
         // the number of GC roots when serializing and deserializing.
         UNREACHABLE();
       }
+
       default:
         UNREACHABLE();
     }
@@ -880,7 +943,7 @@
   int data = source_->Get();
// If this assert fails then that indicates that you have a mismatch between
   // the number of GC roots when serializing and deserializing.
-  ASSERT_EQ(SYNCHRONIZE, data);
+  ASSERT_EQ(kSynchronize, data);
   do {
     int character = source_->Get();
     if (character == 0) break;
@@ -895,7 +958,7 @@


 void Serializer::Synchronize(const char* tag) {
-  sink_->Put(SYNCHRONIZE, tag);
+  sink_->Put(kSynchronize, tag);
   int character;
   do {
     character = *tag++;
@@ -957,13 +1020,13 @@
 void Serializer::VisitPointers(Object** start, Object** end) {
   for (Object** current = start; current < end; current++) {
     if ((*current)->IsSmi()) {
-      sink_->Put(RAW_DATA_SERIALIZATION, "RawData");
+      sink_->Put(kRawData, "RawData");
       sink_->PutInt(kPointerSize, "length");
       for (int i = 0; i < kPointerSize; i++) {
         sink_->Put(reinterpret_cast<byte*>(current)[i], "Byte");
       }
     } else {
-      SerializeObject(*current, TAGGED_REPRESENTATION);
+      SerializeObject(*current, kPlain, kStartOfObject);
     }
   }
 }
@@ -1033,7 +1096,8 @@
 void Serializer::SerializeReferenceToPreviousObject(
     int space,
     int address,
-    ReferenceRepresentation reference_representation) {
+    HowToCode how_to_code,
+    WhereToPoint where_to_point) {
   int offset = CurrentAllocationAddress(space) - address;
   bool from_start = true;
   if (SpaceIsPaged(space)) {
@@ -1054,43 +1118,30 @@
   // If we are actually dealing with real offsets (and not a numbering of
   // all objects) then we should shift out the bits that are always 0.
   if (!SpaceIsLarge(space)) address >>= kObjectAlignmentBits;
-  // On some architectures references between code objects are encoded
-  // specially (as relative offsets).  Such references have their own
-  // special tags to simplify the deserializer.
-  if (reference_representation == CODE_TARGET_REPRESENTATION) {
-    if (from_start) {
-      sink_->Put(CODE_REFERENCE_SERIALIZATION + space, "RefCodeSer");
-      sink_->PutInt(address, "address");
-    } else {
-      sink_->Put(CODE_BACKREF_SERIALIZATION + space, "BackRefCodeSer");
-      sink_->PutInt(address, "address");
-    }
-  } else {
-    // Regular absolute references.
-    CHECK_EQ(TAGGED_REPRESENTATION, reference_representation);
-    if (from_start) {
- // There are some common offsets that have their own specialized encoding.
-#define COMMON_REFS_CASE(tag, common_space, common_offset)               \
-      if (space == common_space && address == common_offset) {           \
-        sink_->PutSection(tag + REFERENCE_SERIALIZATION, "RefSer");      \
-      } else  /* NOLINT */
-      COMMON_REFERENCE_PATTERNS(COMMON_REFS_CASE)
+  if (from_start) {
+#define COMMON_REFS_CASE(pseudo_space, actual_space, offset) \ + if (space == actual_space && address == offset && \ + how_to_code == kPlain && where_to_point == kStartOfObject) { \ + sink_->Put(kFromStart + how_to_code + where_to_point + \ + pseudo_space, "RefSer"); \
+    } else  /* NOLINT */
+    COMMON_REFERENCE_PATTERNS(COMMON_REFS_CASE)
 #undef COMMON_REFS_CASE
-      {  /* NOLINT */
-        sink_->Put(REFERENCE_SERIALIZATION + space, "RefSer");
-        sink_->PutInt(address, "address");
-      }
-    } else {
-      sink_->Put(BACKREF_SERIALIZATION + space, "BackRefSer");
+    {  /* NOLINT */
+ sink_->Put(kFromStart + how_to_code + where_to_point + space, "RefSer");
       sink_->PutInt(address, "address");
     }
+  } else {
+ sink_->Put(kBackref + how_to_code + where_to_point + space, "BackRefSer");
+    sink_->PutInt(address, "address");
   }
 }


 void StartupSerializer::SerializeObject(
     Object* o,
-    ReferenceRepresentation reference_representation) {
+    HowToCode how_to_code,
+    WhereToPoint where_to_point) {
   CHECK(o->IsHeapObject());
   HeapObject* heap_object = HeapObject::cast(o);

@@ -1099,13 +1150,15 @@
     int address = address_mapper_.MappedTo(heap_object);
     SerializeReferenceToPreviousObject(space,
                                        address,
-                                       reference_representation);
+                                       how_to_code,
+                                       where_to_point);
   } else {
     // Object has not yet been serialized.  Serialize it here.
     ObjectSerializer object_serializer(this,
                                        heap_object,
                                        sink_,
-                                       reference_representation);
+                                       how_to_code,
+                                       where_to_point);
     object_serializer.Serialize();
   }
 }
@@ -1115,7 +1168,7 @@
   for (int i = partial_snapshot_cache_length_;
        i < kPartialSnapshotCacheCapacity;
        i++) {
-    sink_->Put(ROOT_SERIALIZATION, "RootSerialization");
+    sink_->Put(kRootArray + kPlain + kStartOfObject, "RootSerialization");
     sink_->PutInt(Heap::kUndefinedValueRootIndex, "root_index");
   }
   Heap::IterateWeakRoots(this, VISIT_ALL);
@@ -1124,20 +1177,22 @@

 void PartialSerializer::SerializeObject(
     Object* o,
-    ReferenceRepresentation reference_representation) {
+    HowToCode how_to_code,
+    WhereToPoint where_to_point) {
   CHECK(o->IsHeapObject());
   HeapObject* heap_object = HeapObject::cast(o);

   int root_index;
   if ((root_index = RootIndex(heap_object)) != kInvalidRootIndex) {
-    sink_->Put(ROOT_SERIALIZATION, "RootSerialization");
+ sink_->Put(kRootArray + how_to_code + where_to_point, "RootSerialization");
     sink_->PutInt(root_index, "root_index");
     return;
   }

   if (ShouldBeInThePartialSnapshotCache(heap_object)) {
     int cache_index = PartialSnapshotCacheIndex(heap_object);
-    sink_->Put(PARTIAL_SNAPSHOT_CACHE_ENTRY, "PartialSnapshotCache");
+    sink_->Put(kPartialSnapshotCache + how_to_code + where_to_point,
+               "PartialSnapshotCache");
     sink_->PutInt(cache_index, "partial_snapshot_cache_index");
     return;
   }
@@ -1155,13 +1210,15 @@
     int address = address_mapper_.MappedTo(heap_object);
     SerializeReferenceToPreviousObject(space,
                                        address,
-                                       reference_representation);
+                                       how_to_code,
+                                       where_to_point);
   } else {
     // Object has not yet been serialized.  Serialize it here.
     ObjectSerializer serializer(this,
                                 heap_object,
                                 sink_,
-                                reference_representation);
+                                how_to_code,
+                                where_to_point);
     serializer.Serialize();
   }
 }
@@ -1171,12 +1228,8 @@
   int space = Serializer::SpaceOfObject(object_);
   int size = object_->Size();

-  if (reference_representation_ == TAGGED_REPRESENTATION) {
-    sink_->Put(OBJECT_SERIALIZATION + space, "ObjectSerialization");
-  } else {
-    CHECK_EQ(CODE_TARGET_REPRESENTATION, reference_representation_);
-    sink_->Put(CODE_OBJECT_SERIALIZATION + space, "ObjectSerialization");
-  }
+  sink_->Put(kNewObject + reference_representation_ + space,
+             "ObjectSerialization");
   sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");

   LOG(SnapshotPositionEvent(object_->address(), sink_->Position()));
@@ -1186,12 +1239,12 @@
   int offset = serializer_->Allocate(space, size, &start_new_page);
   serializer_->address_mapper()->AddMapping(object_, offset);
   if (start_new_page) {
-    sink_->Put(START_NEW_PAGE_SERIALIZATION, "NewPage");
+    sink_->Put(kNewPage, "NewPage");
     sink_->PutSection(space, "NewPageSpace");
   }

   // Serialize the map (first word of the object).
-  serializer_->SerializeObject(object_->map(), TAGGED_REPRESENTATION);
+  serializer_->SerializeObject(object_->map(), kPlain, kStartOfObject);

   // Serialize the rest of the object.
   CHECK_EQ(0, bytes_processed_so_far_);
@@ -1209,7 +1262,7 @@
     if (current < end) OutputRawData(reinterpret_cast<Address>(current));

     while (current < end && !(*current)->IsSmi()) {
-      serializer_->SerializeObject(*current, TAGGED_REPRESENTATION);
+      serializer_->SerializeObject(*current, kPlain, kStartOfObject);
       bytes_processed_so_far_ += kPointerSize;
       current++;
     }
@@ -1223,7 +1276,7 @@
   OutputRawData(references_start);

   for (Address* current = start; current < end; current++) {
-    sink_->Put(EXTERNAL_REFERENCE_SERIALIZATION, "ExternalReference");
+ sink_->Put(kExternalReference + kPlain + kStartOfObject, "ExternalRef");
     int reference_id = serializer_->EncodeExternalReference(*current);
     sink_->PutInt(reference_id, "reference id");
   }
@@ -1237,7 +1290,14 @@
   Address target = rinfo->target_address();
   uint32_t encoding = serializer_->EncodeExternalReference(target);
   CHECK(target == NULL ? encoding == 0 : encoding != 0);
-  sink_->Put(EXTERNAL_BRANCH_TARGET_SERIALIZATION, "ExternalReference");
+  int representation;
+  // Can't use a ternary operator because of gcc.
+  if (rinfo->IsCodedSpecially()) {
+    representation = kStartOfObject + kFromCode;
+  } else {
+    representation = kStartOfObject + kPlain;
+  }
+  sink_->Put(kExternalReference + representation, "ExternalReference");
   sink_->PutInt(encoding, "reference id");
   bytes_processed_so_far_ += Assembler::kExternalTargetSize;
 }
@@ -1248,7 +1308,7 @@
   Address target_start = rinfo->target_address_address();
   OutputRawData(target_start);
   Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
-  serializer_->SerializeObject(target, CODE_TARGET_REPRESENTATION);
+  serializer_->SerializeObject(target, kFromCode, kFirstInstruction);
   bytes_processed_so_far_ += Assembler::kCallTargetSize;
 }

@@ -1264,7 +1324,7 @@
       typedef v8::String::ExternalAsciiStringResource Resource;
       Resource* resource = string->resource();
       if (resource == *resource_pointer) {
-        sink_->Put(NATIVES_STRING_RESOURCE, "NativesStringResource");
+        sink_->Put(kNativesStringResource, "NativesStringResource");
         sink_->PutSection(i, "NativesStringResourceEnd");
         bytes_processed_so_far_ += sizeof(resource);
         return;
@@ -1288,12 +1348,12 @@
     Address base = object_start + bytes_processed_so_far_;
#define RAW_CASE(index, length) \ if (skipped == length) { \ - sink_->PutSection(RAW_DATA_SERIALIZATION + index, "RawDataFixed"); \ + sink_->PutSection(kRawData + index, "RawDataFixed"); \
     } else  /* NOLINT */
     COMMON_RAW_LENGTHS(RAW_CASE)
 #undef RAW_CASE
     {  /* NOLINT */
-      sink_->Put(RAW_DATA_SERIALIZATION, "RawData");
+      sink_->Put(kRawData, "RawData");
       sink_->PutInt(skipped, "length");
     }
     for (int i = 0; i < skipped; i++) {
=======================================
--- /branches/bleeding_edge/src/serialize.h     Wed Apr 14 13:16:19 2010
+++ /branches/bleeding_edge/src/serialize.h     Thu May 20 06:54:31 2010
@@ -137,17 +137,23 @@
 };


-// It is very common to have a reference to the object at word 10 in space 2, -// the object at word 5 in space 2 and the object at word 28 in space 4. This
-// only works for objects in the first page of a space.
-#define COMMON_REFERENCE_PATTERNS(f)                              \
-  f(kNumberOfSpaces, 2, 10)                                       \
-  f(kNumberOfSpaces + 1, 2, 5)                                    \
-  f(kNumberOfSpaces + 2, 4, 28)                                   \
-  f(kNumberOfSpaces + 3, 2, 21)                                   \
-  f(kNumberOfSpaces + 4, 2, 98)                                   \
-  f(kNumberOfSpaces + 5, 2, 67)                                   \
-  f(kNumberOfSpaces + 6, 4, 132)
+// It is very common to have a reference to objects at certain offsets in the
+// heap.  These offsets have been determined experimentally.  We code
+// references to such objects in a single byte that encodes the way the pointer +// is written (only plain pointers allowed), the space number and the offset. +// This only works for objects in the first page of a space. Don't use this for
+// things in newspace since it bypasses the write barrier.
+
+static const int k64 = (sizeof(uintptr_t) - 4) / 4;
+
+#define COMMON_REFERENCE_PATTERNS(f)                               \
+  f(kNumberOfSpaces, 2, 11 - k64)                                  \
+  f(kNumberOfSpaces + 1, 2, 0)                                     \
+  f(kNumberOfSpaces + 2, 2, 142 - 16 * k64)                        \
+  f(kNumberOfSpaces + 3, 2, 74 - 15 * k64)                         \
+  f(kNumberOfSpaces + 4, 2, 5)                                     \
+  f(kNumberOfSpaces + 5, 1, 135)                                   \
+  f(kNumberOfSpaces + 6, 2, 228 - 39 * k64)

 #define COMMON_RAW_LENGTHS(f)        \
   f(1, 1)  \
@@ -175,37 +181,63 @@
   static void SetSnapshotCacheSize(int size);

  protected:
-  enum DataType {
-    RAW_DATA_SERIALIZATION = 0,
-    // And 15 common raw lengths.
-    OBJECT_SERIALIZATION = 16,
-    // One variant per space.
-    CODE_OBJECT_SERIALIZATION = 25,
-    // One per space (only code spaces in use).
-    EXTERNAL_REFERENCE_SERIALIZATION = 34,
-    EXTERNAL_BRANCH_TARGET_SERIALIZATION = 35,
-    SYNCHRONIZE = 36,
-    START_NEW_PAGE_SERIALIZATION = 37,
-    NATIVES_STRING_RESOURCE = 38,
-    ROOT_SERIALIZATION = 39,
-    PARTIAL_SNAPSHOT_CACHE_ENTRY = 40,
-    // Free: 41-47.
-    BACKREF_SERIALIZATION = 48,
-    // One per space, must be kSpaceMask aligned.
-    // Free: 57-63.
-    REFERENCE_SERIALIZATION = 64,
-    // One per space and common references.  Must be kSpaceMask aligned.
-    CODE_BACKREF_SERIALIZATION = 80,
-    // One per space, must be kSpaceMask aligned.
-    // Free: 89-95.
-    CODE_REFERENCE_SERIALIZATION = 96
-    // One per space, must be kSpaceMask aligned.
-    // Free: 105-255.
+  // Where the pointed-to object can be found:
+  enum Where {
+    kNewObject = 0,                 // Object is next in snapshot.
+    // 1-8                             One per space.
+    kRootArray = 0x9,               // Object is found in root array.
+    kPartialSnapshotCache = 0xa,    // Object is in the cache.
+    kExternalReference = 0xb,       // Pointer to an external reference.
+    // 0xc-0xf                         Free.
+ kBackref = 0x10, // Object is described relative to end.
+    // 0x11-0x18                       One per space.
+    // 0x19-0x1f                       Common backref offsets.
+ kFromStart = 0x20, // Object is described relative to start.
+    // 0x21-0x28                       One per space.
+    // 0x29-0x2f                       Free.
+    // 0x30-0x3f                       Used by misc tags below.
+    kPointedToMask = 0x3f
   };
+
+  // How to code the pointer to the object.
+  enum HowToCode {
+    kPlain = 0,                          // Straight pointer.
+    // What this means depends on the architecture:
+    kFromCode = 0x40,                    // A pointer inlined in code.
+    kHowToCodeMask = 0x40
+  };
+
+  // Where to point within the object.
+  enum WhereToPoint {
+    kStartOfObject = 0,
+    kFirstInstruction = 0x80,
+    kWhereToPointMask = 0x80
+  };
+
+  // Misc.
+  // Raw data to be copied from the snapshot.
+  static const int kRawData = 0x30;
+  // Some common raw lengths: 0x31-0x3f
+ // A tag emitted at strategic points in the snapshot to delineate sections. + // If the deserializer does not find these at the expected moments then it
+  // is an indication that the snapshot and the VM do not fit together.
+  // Examine the build process for architecture, version or configuration
+  // mismatches.
+  static const int kSynchronize = 0x70;
+ // Used for the source code of the natives, which is in the executable, but
+  // is referred to from external strings in the snapshot.
+  static const int kNativesStringResource = 0x71;
+  static const int kNewPage = 0x72;
+  // 0x73-0x7f                            Free.
+  // 0xb0-0xbf                            Free.
+  // 0xf0-0xff                            Free.
+
+
   static const int kLargeData = LAST_SPACE;
   static const int kLargeCode = kLargeData + 1;
   static const int kLargeFixedArray = kLargeCode + 1;
   static const int kNumberOfSpaces = kLargeFixedArray + 1;
+  static const int kAnyOldSpace = -1;

   // A bitmask for getting the space out of an instruction.
   static const int kSpaceMask = 15;
@@ -396,10 +428,6 @@
 #endif

  protected:
-  enum ReferenceRepresentation {
-    TAGGED_REPRESENTATION,      // A tagged object reference.
- CODE_TARGET_REPRESENTATION // A reference to first instruction in target.
-  };
   static const int kInvalidRootIndex = -1;
   virtual int RootIndex(HeapObject* heap_object) = 0;
   virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) = 0;
@@ -409,11 +437,12 @@
     ObjectSerializer(Serializer* serializer,
                      Object* o,
                      SnapshotByteSink* sink,
-                     ReferenceRepresentation representation)
+                     HowToCode how_to_code,
+                     WhereToPoint where_to_point)
       : serializer_(serializer),
         object_(HeapObject::cast(o)),
         sink_(sink),
-        reference_representation_(representation),
+        reference_representation_(how_to_code + where_to_point),
         bytes_processed_so_far_(0) { }
     void Serialize();
     void VisitPointers(Object** start, Object** end);
@@ -435,16 +464,18 @@
     Serializer* serializer_;
     HeapObject* object_;
     SnapshotByteSink* sink_;
-    ReferenceRepresentation reference_representation_;
+    int reference_representation_;
     int bytes_processed_so_far_;
   };

   virtual void SerializeObject(Object* o,
-                               ReferenceRepresentation representation) = 0;
+                               HowToCode how_to_code,
+                               WhereToPoint where_to_point) = 0;
   void SerializeReferenceToPreviousObject(
       int space,
       int address,
-      ReferenceRepresentation reference_representation);
+      HowToCode how_to_code,
+      WhereToPoint where_to_point);
   void InitializeAllocators();
   // This will return the space for an object.  If the object is in large
   // object space it may return kLargeCode or kLargeFixedArray in order
@@ -492,7 +523,8 @@
   // Serialize the objects reachable from a single object pointer.
   virtual void Serialize(Object** o);
   virtual void SerializeObject(Object* o,
-                               ReferenceRepresentation representation);
+                               HowToCode how_to_code,
+                               WhereToPoint where_to_point);

  protected:
   virtual int RootIndex(HeapObject* o);
@@ -528,7 +560,8 @@
   // 3) Weak references (eg the symbol table).
   virtual void SerializeStrongReferences();
   virtual void SerializeObject(Object* o,
-                               ReferenceRepresentation representation);
+                               HowToCode how_to_code,
+                               WhereToPoint where_to_point);
   void SerializeWeakReferences();
   void Serialize() {
     SerializeStrongReferences();
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.cc Wed May 19 01:16:52 2010 +++ /branches/bleeding_edge/src/x64/assembler-x64.cc Thu May 20 06:54:31 2010
@@ -2800,6 +2800,16 @@
                                   1 << RelocInfo::INTERNAL_REFERENCE |
                                   1 << RelocInfo::JS_RETURN;

+
+bool RelocInfo::IsCodedSpecially() {
+ // The deserializer needs to know whether a pointer is specially coded. Being + // specially coded on x64 means that it is a relative 32 bit address, as used
+  // by branch instructions.
+  return (1 << rmode_) & kApplyMask;
+}
+
+
+
 } }  // namespace v8::internal

 #endif  // V8_TARGET_ARCH_X64

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to