New snapshot framework. Doesn't work on ARM yet (code targets
authorerik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 27 Oct 2009 11:54:01 +0000 (11:54 +0000)
committererik.corry@gmail.com <erik.corry@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 27 Oct 2009 11:54:01 +0000 (11:54 +0000)
are different).  Is able to deserialize the whole heap and run
some stuff.  Not available as the primary snapshot system yet.
Review URL: http://codereview.chromium.org/335009

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3142 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

20 files changed:
include/v8.h
src/arm/assembler-arm.h
src/bootstrapper.cc
src/globals.h
src/heap.cc
src/heap.h
src/ia32/assembler-ia32.h
src/list.h
src/objects-inl.h
src/objects.h
src/serialize.cc
src/serialize.h
src/snapshot-common.cc
src/snapshot.h
src/spaces.cc
src/v8.cc
src/v8.h
src/x64/assembler-x64.h
test/cctest/cctest.status
test/cctest/test-serialize.cc

index b2a3fb748302effec7b78cfe0c1d6b060549555b..5f3b68b2272807206fb2f9592ab8f8ba99e5ec3b 100644 (file)
@@ -452,8 +452,8 @@ class V8EXPORT HandleScope {
   void* operator new(size_t size);
   void operator delete(void*, size_t);
 
-  // This Data class is accessible internally through a typedef in the
-  // ImplementationUtilities class.
+  // This Data class is accessible internally as HandleScopeData through a
+  // typedef in the ImplementationUtilities class.
   class V8EXPORT Data {
    public:
     int extensions;
index d1df08c5712cf3b246ce55ca53c0c96606246d74..f63473c37ac70e9a5186ca71c1d2d12757412f88 100644 (file)
@@ -437,6 +437,11 @@ class Assembler : public Malloced {
   INLINE(static Address target_address_at(Address pc));
   INLINE(static void set_target_address_at(Address pc, Address target));
 
+  // Here we are patching the address in the constant pool, not the actual call
+  // instruction.  The address in the constant pool is the same size as a
+  // pointer.
+  static const int kCallTargetSize = kPointerSize;
+
   // Size of an instruction.
   static const int kInstrSize = sizeof(Instr);
 
index 43aa1a3b8997c64e72a93054dfa27b799fd27ffa..3436b505dc7916adfeab38c729bb5bf1848cdbc8 100644 (file)
@@ -316,8 +316,11 @@ Genesis* Genesis::current_ = NULL;
 
 void Bootstrapper::Iterate(ObjectVisitor* v) {
   natives_cache.Iterate(v);
+  v->Synchronize("NativesCache");
   extensions_cache.Iterate(v);
+  v->Synchronize("Extensions");
   PendingFixups::Iterate(v);
+  v->Synchronize("PendingFixups");
 }
 
 
index 6d8bb63d2fdf061ae92c2df48d7411ff534e71e7..fbb648f5b1ac34a500d84e8fdb302fb3097e57a9 100644 (file)
@@ -248,6 +248,7 @@ class Variable;
 class VariableProxy;
 class RelocInfo;
 class Deserializer;
+class GenericDeserializer;  // TODO(erikcorry): Get rid of this.
 class MessageLocation;
 class ObjectGroup;
 class TickSample;
@@ -272,7 +273,9 @@ enum AllocationSpace {
   LO_SPACE,             // Promoted large objects.
 
   FIRST_SPACE = NEW_SPACE,
-  LAST_SPACE = LO_SPACE
+  LAST_SPACE = LO_SPACE,
+  FIRST_PAGED_SPACE = OLD_POINTER_SPACE,
+  LAST_PAGED_SPACE = CELL_SPACE
 };
 const int kSpaceTagSize = 3;
 const int kSpaceTagMask = (1 << kSpaceTagSize) - 1;
index c05734b6b36f5dbfe7fbf773e6b37678b9ba2c4a..0cfbc5582e59fb58adb4fb3b67d0fff527e305a6 100644 (file)
@@ -114,6 +114,7 @@ int Heap::mc_count_ = 0;
 int Heap::gc_count_ = 0;
 
 int Heap::always_allocate_scope_depth_ = 0;
+int Heap::linear_allocation_scope_depth_ = 0;
 bool Heap::context_disposed_pending_ = false;
 
 #ifdef DEBUG
@@ -3243,60 +3244,53 @@ void Heap::IterateRSet(PagedSpace* space, ObjectSlotCallback copy_object_func) {
 }
 
 
-#ifdef DEBUG
-#define SYNCHRONIZE_TAG(tag) v->Synchronize(tag)
-#else
-#define SYNCHRONIZE_TAG(tag)
-#endif
-
 void Heap::IterateRoots(ObjectVisitor* v) {
   IterateStrongRoots(v);
   v->VisitPointer(reinterpret_cast<Object**>(&roots_[kSymbolTableRootIndex]));
-  SYNCHRONIZE_TAG("symbol_table");
+  v->Synchronize("symbol_table");
 }
 
 
 void Heap::IterateStrongRoots(ObjectVisitor* v) {
   v->VisitPointers(&roots_[0], &roots_[kStrongRootListLength]);
-  SYNCHRONIZE_TAG("strong_root_list");
+  v->Synchronize("strong_root_list");
 
   v->VisitPointer(bit_cast<Object**, String**>(&hidden_symbol_));
-  SYNCHRONIZE_TAG("symbol");
+  v->Synchronize("symbol");
 
   Bootstrapper::Iterate(v);
-  SYNCHRONIZE_TAG("bootstrapper");
+  v->Synchronize("bootstrapper");
   Top::Iterate(v);
-  SYNCHRONIZE_TAG("top");
+  v->Synchronize("top");
   Relocatable::Iterate(v);
-  SYNCHRONIZE_TAG("relocatable");
+  v->Synchronize("relocatable");
 
 #ifdef ENABLE_DEBUGGER_SUPPORT
   Debug::Iterate(v);
 #endif
-  SYNCHRONIZE_TAG("debug");
+  v->Synchronize("debug");
   CompilationCache::Iterate(v);
-  SYNCHRONIZE_TAG("compilationcache");
+  v->Synchronize("compilationcache");
 
   // Iterate over local handles in handle scopes.
   HandleScopeImplementer::Iterate(v);
-  SYNCHRONIZE_TAG("handlescope");
+  v->Synchronize("handlescope");
 
   // Iterate over the builtin code objects and code stubs in the heap. Note
   // that it is not strictly necessary to iterate over code objects on
   // scavenge collections.  We still do it here because this same function
   // is used by the mark-sweep collector and the deserializer.
   Builtins::IterateBuiltins(v);
-  SYNCHRONIZE_TAG("builtins");
+  v->Synchronize("builtins");
 
   // Iterate over global handles.
   GlobalHandles::IterateRoots(v);
-  SYNCHRONIZE_TAG("globalhandles");
+  v->Synchronize("globalhandles");
 
   // Iterate over pointers being held by inactive threads.
   ThreadManager::Iterate(v);
-  SYNCHRONIZE_TAG("threadmanager");
+  v->Synchronize("threadmanager");
 }
-#undef SYNCHRONIZE_TAG
 
 
 // Flag is set when the heap has been configured.  The heap can be repeatedly
index 05be0c4707daa8fd10bfc48775852b2b76717bba..285260594f373230322891b14a22d936456e1a5c 100644 (file)
@@ -38,7 +38,13 @@ namespace internal {
 
 // Defines all the roots in Heap.
 #define UNCONDITIONAL_STRONG_ROOT_LIST(V)                                      \
-  /* Cluster the most popular ones in a few cache lines here at the top. */    \
+  /* Put the byte array map early.  We need it to be in place by the time   */ \
+  /* the deserializer hits the next page, since it wants to put a byte      */ \
+  /* array in the unused space at the end of the page.                      */ \
+  V(Map, byte_array_map, ByteArrayMap)                                         \
+  V(Map, one_pointer_filler_map, OnePointerFillerMap)                          \
+  V(Map, two_pointer_filler_map, TwoPointerFillerMap)                          \
+  /* Cluster the most popular ones in a few cache lines here at the top.    */ \
   V(Smi, stack_limit, StackLimit)                                              \
   V(Object, undefined_value, UndefinedValue)                                   \
   V(Object, the_hole_value, TheHoleValue)                                      \
@@ -109,7 +115,6 @@ namespace internal {
     undetectable_medium_ascii_string_map,                                      \
     UndetectableMediumAsciiStringMap)                                          \
   V(Map, undetectable_long_ascii_string_map, UndetectableLongAsciiStringMap)   \
-  V(Map, byte_array_map, ByteArrayMap)                                         \
   V(Map, pixel_array_map, PixelArrayMap)                                       \
   V(Map, external_byte_array_map, ExternalByteArrayMap)                        \
   V(Map, external_unsigned_byte_array_map, ExternalUnsignedByteArrayMap)       \
@@ -126,8 +131,6 @@ namespace internal {
   V(Map, boilerplate_function_map, BoilerplateFunctionMap)                     \
   V(Map, shared_function_info_map, SharedFunctionInfoMap)                      \
   V(Map, proxy_map, ProxyMap)                                                  \
-  V(Map, one_pointer_filler_map, OnePointerFillerMap)                          \
-  V(Map, two_pointer_filler_map, TwoPointerFillerMap)                          \
   V(Object, nan_value, NanValue)                                               \
   V(Object, minus_zero_value, MinusZeroValue)                                  \
   V(String, empty_string, EmptyString)                                         \
@@ -305,6 +308,9 @@ class Heap : public AllStatic {
   static Address always_allocate_scope_depth_address() {
     return reinterpret_cast<Address>(&always_allocate_scope_depth_);
   }
+  static bool linear_allocation() {
+      return linear_allocation_scope_depth_ != 0;
+  }
 
   static Address* NewSpaceAllocationTopAddress() {
     return new_space_.allocation_top_address();
@@ -750,7 +756,7 @@ class Heap : public AllStatic {
   static bool Contains(HeapObject* value);
 
   // Checks whether an address/object in a space.
-  // Currently used by tests and heap verification only.
+  // Currently used by tests, serialization and heap verification only.
   static bool InSpace(Address addr, AllocationSpace space);
   static bool InSpace(HeapObject* value, AllocationSpace space);
 
@@ -921,6 +927,7 @@ class Heap : public AllStatic {
   static int survived_since_last_expansion_;
 
   static int always_allocate_scope_depth_;
+  static int linear_allocation_scope_depth_;
   static bool context_disposed_pending_;
 
   static const int kMaxMapSpaceSize = 8*MB;
@@ -1136,6 +1143,7 @@ class Heap : public AllStatic {
   friend class Factory;
   friend class DisallowAllocationFailure;
   friend class AlwaysAllocateScope;
+  friend class LinearAllocationScope;
 };
 
 
@@ -1157,6 +1165,19 @@ class AlwaysAllocateScope {
 };
 
 
+class LinearAllocationScope {
+ public:
+  LinearAllocationScope() {
+    Heap::linear_allocation_scope_depth_++;
+  }
+
+  ~LinearAllocationScope() {
+    Heap::linear_allocation_scope_depth_--;
+    ASSERT(Heap::linear_allocation_scope_depth_ >= 0);
+  }
+};
+
+
 #ifdef DEBUG
 // Visitor class to verify interior pointers that do not have remembered set
 // bits.  All heap object pointers have to point into the heap to a location
index 4d9f08b066a365dcd38b3d916edbcdcd38674bd2..9b2da4156d654751f6ed20d8fb65f69d56fd9e54 100644 (file)
@@ -439,6 +439,8 @@ class Assembler : public Malloced {
   inline static Address target_address_at(Address pc);
   inline static void set_target_address_at(Address pc, Address target);
 
+  static const int kCallTargetSize = kPointerSize;
+
   // Distance between the address of the code target in the call instruction
   // and the return address
   static const int kCallTargetAddressOffset = kPointerSize;
index 25211d9a7b52b1d3ecf7192bb6d42893b0040f14..19dc7337d3ff1d98e51b5003bdd301973e7964dc 100644 (file)
@@ -48,6 +48,7 @@ template <typename T, class P>
 class List {
  public:
 
+  List() { Initialize(0); }
   INLINE(explicit List(int capacity)) { Initialize(capacity); }
   INLINE(~List()) { DeleteData(data_); }
 
index 1ada5839e56a4e3d500c4d8eda9447df62320d42..059f9316a08f1cf5eae873e21fcc23f144548257 100644 (file)
@@ -945,6 +945,25 @@ HeapObject* MapWord::ToForwardingAddress() {
 }
 
 
+bool MapWord::IsSerializationAddress() {
+  return HAS_SMI_TAG(reinterpret_cast<Object*>(value_));
+}
+
+
+MapWord MapWord::FromSerializationAddress(int raw) {
+  // When the map word is being used as a serialization address we Smi-encode
+  // the serialization address (which is always a smallish positive integer).
+  return MapWord(reinterpret_cast<uintptr_t>(Smi::FromInt(raw)));
+}
+
+
+int MapWord::ToSerializationAddress() {
+  // When the map word is being used as a serialization address we treat the
+  // map word as a Smi and get the small integer that it encodes.
+  return reinterpret_cast<Smi*>(value_)->value();
+}
+
+
 bool MapWord::IsMarked() {
   return (value_ & kMarkingMask) == 0;
 }
index 68bed6c6ec65044a9eca7089741b1e876f3b6eaf..ea974f6d61f9d927825e30d533c7a904521c34ff 100644 (file)
@@ -1082,6 +1082,15 @@ class MapWord BASE_EMBEDDED {
   // View this map word as a forwarding address.
   inline HeapObject* ToForwardingAddress();
 
+  // True if this map word is a serialization address.  This will only be the
+  // case during a destructive serialization of the heap.
+  inline bool IsSerializationAddress();
+
+  // Create a map word from a serialization address.
+  static inline MapWord FromSerializationAddress(int raw);
+
+  // View this map word as a serialization address.
+  inline int ToSerializationAddress();
 
   // Marking phase of full collection: the map word of live objects is
   // marked, and may be marked as overflowed (eg, the object is live, its
@@ -5105,6 +5114,8 @@ class ObjectVisitor BASE_EMBEDDED {
   // Intended for serialization/deserialization checking: insert, or
   // check for the presence of, a tag at this position in the stream.
   virtual void Synchronize(const char* tag) {}
+#else
+  inline void Synchronize(const char* tag) {}
 #endif
 };
 
index 6ff1d7f5b0063941ef0b922e993e142b48e5fc07..f2aeb901d29b23ed8fda08c161800a1c587059f7 100644 (file)
@@ -1417,7 +1417,27 @@ void Deserializer::Synchronize(const char* tag) {
 #endif
 
 
+class NoGlobalHandlesChecker : public ObjectVisitor {
+ public:
+  virtual void VisitPointers(Object** start, Object** end) {
+    ASSERT(false);
+  }
+};
+
+
+class GlobalHandleDestroyer : public ObjectVisitor {
+  void VisitPointers(Object**start, Object**end) {
+    while (start < end) {
+      GlobalHandles::Destroy(start++);
+    }
+  }
+};
+
+
 void Deserializer::Deserialize() {
+  // No global handles.
+  NoGlobalHandlesChecker checker;
+  GlobalHandles::IterateRoots(&checker);
   // No active threads.
   ASSERT_EQ(NULL, ThreadState::FirstInUse());
   // No active handles.
@@ -1428,6 +1448,10 @@ void Deserializer::Deserialize() {
   GetHeader();
   Heap::IterateRoots(this);
   GetContextStack();
+  // Any global handles that have been set up by deserialization are leaked
+  // since noone is keeping track of them.  So we discard them now.
+  GlobalHandleDestroyer destroyer;
+  GlobalHandles::IterateRoots(&destroyer);
 }
 
 
@@ -1740,4 +1764,486 @@ Object* Deserializer::Resolve(Address encoded) {
 }
 
 
+Deserializer2::Deserializer2(SnapshotByteSource* source)
+    : source_(source),
+      external_reference_decoder_(NULL) {
+  for (int i = 0; i <= LAST_SPACE; i++) {
+    fullness_[i] = 0;
+  }
+}
+
+
+// This routine both allocates a new object, and also keeps
+// track of where objects have been allocated so that we can
+// fix back references when deserializing.
+Address Deserializer2::Allocate(int space_index, int size) {
+  HeapObject* new_object;
+  int old_fullness = CurrentAllocationAddress(space_index);
+  // When we start a new page we need to record its location.
+  bool record_page = (old_fullness == 0);
+  if (SpaceIsPaged(space_index)) {
+    PagedSpace* space;
+    switch (space_index) {
+      case OLD_DATA_SPACE: space = Heap::old_data_space(); break;
+      case OLD_POINTER_SPACE: space = Heap::old_pointer_space(); break;
+      case MAP_SPACE: space = Heap::map_space(); break;
+      case CODE_SPACE: space = Heap::code_space(); break;
+      case CELL_SPACE: space = Heap::cell_space(); break;
+      default: UNREACHABLE(); space = NULL; break;
+    }
+    ASSERT(size <= Page::kPageSize - Page::kObjectStartOffset);
+    int current_page = old_fullness >> Page::kPageSizeBits;
+    int new_fullness = old_fullness + size;
+    int new_page = new_fullness >> Page::kPageSizeBits;
+    // What is our new position within the current page.
+    int intra_page_offset = new_fullness - current_page * Page::kPageSize;
+    if (intra_page_offset > Page::kPageSize - Page::kObjectStartOffset) {
+      // This object will not fit in a page and we have to move to the next.
+      new_page = current_page + 1;
+      old_fullness = new_page << Page::kPageSizeBits;
+      new_fullness = old_fullness + size;
+      record_page = true;
+    }
+    fullness_[space_index] = new_fullness;
+    Object* new_allocation = space->AllocateRaw(size);
+    new_object = HeapObject::cast(new_allocation);
+    ASSERT(!new_object->IsFailure());
+    ASSERT((reinterpret_cast<intptr_t>(new_object->address()) &
+            Page::kPageAlignmentMask) ==
+           (old_fullness & Page::kPageAlignmentMask) +
+            Page::kObjectStartOffset);
+  } else if (SpaceIsLarge(space_index)) {
+    ASSERT(size > Page::kPageSize - Page::kObjectStartOffset);
+    fullness_[LO_SPACE]++;
+    LargeObjectSpace* lo_space = Heap::lo_space();
+    Object* new_allocation;
+    if (space_index == kLargeData) {
+      new_allocation = lo_space->AllocateRaw(size);
+    } else if (space_index == kLargeFixedArray) {
+      new_allocation = lo_space->AllocateRawFixedArray(size);
+    } else {
+      ASSERT(space_index == kLargeCode);
+      new_allocation = lo_space->AllocateRawCode(size);
+    }
+    ASSERT(!new_allocation->IsFailure());
+    new_object = HeapObject::cast(new_allocation);
+    record_page = true;
+    // The page recording below records all large objects in the same space.
+    space_index = LO_SPACE;
+  } else {
+    ASSERT(space_index == NEW_SPACE);
+    Object* new_allocation = Heap::new_space()->AllocateRaw(size);
+    fullness_[space_index] += size;
+    ASSERT(!new_allocation->IsFailure());
+    new_object = HeapObject::cast(new_allocation);
+  }
+  Address address = new_object->address();
+  if (record_page) {
+    pages_[space_index].Add(address);
+  }
+  return address;
+}
+
+
+// This returns the address of an object that has been described in the
+// snapshot as being offset bytes back in a particular space.
+HeapObject* Deserializer2::GetAddress(int space) {
+  int offset = source_->GetInt();
+  if (SpaceIsLarge(space)) {
+    // Large spaces have one object per 'page'.
+    return HeapObject::FromAddress(
+        pages_[LO_SPACE][fullness_[LO_SPACE] - offset]);
+  }
+  offset <<= kObjectAlignmentBits;
+  if (space == NEW_SPACE) {
+    // New space has only one space - numbered 0.
+    return HeapObject::FromAddress(
+        pages_[space][0] + fullness_[space] - offset);
+  }
+  ASSERT(SpaceIsPaged(space));
+  int virtual_address = fullness_[space] - offset;
+  int page_of_pointee = (virtual_address) >> Page::kPageSizeBits;
+  Address object_address = pages_[space][page_of_pointee] +
+                           (virtual_address & Page::kPageAlignmentMask);
+  return HeapObject::FromAddress(object_address);
+}
+
+
+void Deserializer2::Deserialize() {
+  // Don't GC while deserializing - just expand the heap.
+  AlwaysAllocateScope always_allocate;
+  // Don't use the free lists while deserializing.
+  LinearAllocationScope allocate_linearly;
+  // No active threads.
+  ASSERT_EQ(NULL, ThreadState::FirstInUse());
+  // No active handles.
+  ASSERT(HandleScopeImplementer::instance()->blocks()->is_empty());
+  ASSERT(external_reference_decoder_ == NULL);
+  external_reference_decoder_ = new ExternalReferenceDecoder();
+  Heap::IterateRoots(this);
+  ASSERT(source_->AtEOF());
+  delete external_reference_decoder_;
+  external_reference_decoder_ = NULL;
+}
+
+
+// This is called on the roots.  It is the driver of the deserialization
+// process.
+void Deserializer2::VisitPointers(Object** start, Object** end) {
+  for (Object** current = start; current < end; current++) {
+    DataType data = static_cast<DataType>(source_->Get());
+    if (data == SMI_SERIALIZATION) {
+      *current = Smi::FromInt(source_->GetInt() - kSmiBias);
+    } else if (data == BACKREF_SERIALIZATION) {
+      int space = source_->Get();
+      *current = GetAddress(space);
+    } else {
+      ASSERT(data == OBJECT_SERIALIZATION);
+      ReadObject(current);
+    }
+  }
+}
+
+
+// This routine writes the new object into the pointer provided and then
+// returns true if the new object was in young space and false otherwise.
+// The reason for this strange interface is that otherwise the object is
+// written very late, which means the ByteArray map is not set up by the
+// time we need to use it to mark the space at the end of a page free (by
+// making it into a byte array).
+bool Deserializer2::ReadObject(Object** write_back) {
+  int space = source_->Get();
+  int size = source_->GetInt() << kObjectAlignmentBits;
+  Address address = Allocate(space, size);
+  *write_back = HeapObject::FromAddress(address);
+  Object** current = reinterpret_cast<Object**>(address);
+  Object** limit = current + (size >> kPointerSizeLog2);
+  while (current < limit) {
+    DataType data = static_cast<DataType>(source_->Get());
+    switch (data) {
+      case SMI_SERIALIZATION:
+        *current++ = Smi::FromInt(source_->GetInt() - kSmiBias);
+        break;
+      case RAW_DATA_SERIALIZATION: {
+        int size = source_->GetInt();
+        byte* raw_data_out = reinterpret_cast<byte*>(current);
+        for (int j = 0; j < size; j++) {
+          *raw_data_out++ = source_->Get();
+        }
+        current = reinterpret_cast<Object**>(raw_data_out);
+        break;
+      }
+      case OBJECT_SERIALIZATION: {
+        // Recurse to unpack an object that is forward-referenced from here.
+        bool in_new_space = ReadObject(current);
+        if (in_new_space && space != NEW_SPACE) {
+          Heap::RecordWrite(address,
+                            reinterpret_cast<Address>(current) - address);
+        }
+        current++;
+        break;
+      }
+      case CODE_OBJECT_SERIALIZATION: {
+        Object* new_code_object = NULL;
+        ReadObject(&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_address_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 BACKREF_SERIALIZATION: {
+        // Write a backreference to an object we unpacked earlier.
+        int backref_space = source_->Get();
+        if (backref_space == NEW_SPACE && space != NEW_SPACE) {
+          Heap::RecordWrite(address,
+                            reinterpret_cast<Address>(current) - address);
+        }
+        *current++ = GetAddress(backref_space);
+        break;
+      }
+      case CODE_BACKREF_SERIALIZATION: {
+        int backref_space = source_->Get();
+        // Can't use Code::cast because heap is not set up yet and assertions
+        // will fail.
+        Code* code_object = reinterpret_cast<Code*>(GetAddress(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_address_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;
+      }
+      default:
+        UNREACHABLE();
+    }
+  }
+  ASSERT(current == limit);
+  return space == NEW_SPACE;
+}
+
+
+void SnapshotByteSink::PutInt(uintptr_t integer, const char* description) {
+  const int max_shift = ((kPointerSize * kBitsPerByte) / 7) * 7;
+  for (int shift = max_shift; shift > 0; shift -= 7) {
+    if (integer >= 1u << shift) {
+      Put(((integer >> shift) & 0x7f) | 0x80, "intpart");
+    }
+  }
+  Put(integer & 0x7f, "intlastpart");
+}
+
+#ifdef DEBUG
+
+void Deserializer2::Synchronize(const char* tag) {
+  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(data == SYNCHRONIZE);
+  do {
+    int character = source_->Get();
+    if (character == 0) break;
+    if (FLAG_debug_serialization) {
+      PrintF("%c", character);
+    }
+  } while (true);
+  if (FLAG_debug_serialization) {
+    PrintF("\n");
+  }
+}
+
+
+void Serializer2::Synchronize(const char* tag) {
+  sink_->Put(SYNCHRONIZE, tag);
+  int character;
+  do {
+    character = *tag++;
+    sink_->Put(character, "tagcharacter");
+  } while (character != 0);
+}
+
+#endif
+
+Serializer2::Serializer2(SnapshotByteSink* sink)
+    : sink_(sink),
+      current_root_index_(0),
+      external_reference_encoder_(NULL) {
+  for (int i = 0; i <= LAST_SPACE; i++) {
+    fullness_[i] = 0;
+  }
+}
+
+
+void Serializer2::Serialize() {
+  // No active threads.
+  CHECK_EQ(NULL, ThreadState::FirstInUse());
+  // No active or weak handles.
+  CHECK(HandleScopeImplementer::instance()->blocks()->is_empty());
+  CHECK_EQ(0, GlobalHandles::NumberOfWeakHandles());
+  ASSERT(external_reference_encoder_ == NULL);
+  external_reference_encoder_ = new ExternalReferenceEncoder();
+  Heap::IterateRoots(this);
+  delete external_reference_encoder_;
+  external_reference_encoder_ = NULL;
+}
+
+
+void Serializer2::VisitPointers(Object** start, Object** end) {
+  for (Object** current = start; current < end; current++) {
+    SerializeObject(*current, TAGGED_REPRESENTATION);
+  }
+}
+
+
+void Serializer2::SerializeObject(
+    Object* o,
+    ReferenceRepresentation reference_representation) {
+  if (o->IsHeapObject()) {
+    HeapObject* heap_object = HeapObject::cast(o);
+    MapWord map_word = heap_object->map_word();
+    if (map_word.IsSerializationAddress()) {
+      int space = SpaceOfAlreadySerializedObject(heap_object);
+      int offset =
+          CurrentAllocationAddress(space) - map_word.ToSerializationAddress();
+      // 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)) offset >>= kObjectAlignmentBits;
+      if (reference_representation == CODE_TARGET_REPRESENTATION) {
+        sink_->Put(CODE_BACKREF_SERIALIZATION, "BackRefCodeSerialization");
+      } else {
+        ASSERT(reference_representation == TAGGED_REPRESENTATION);
+        sink_->Put(BACKREF_SERIALIZATION, "BackRefSerialization");
+      }
+      sink_->Put(space, "space");
+      sink_->PutInt(offset, "offset");
+    } else {
+      // Object has not yet been serialized.  Serialize it here.
+      ObjectSerializer serializer(this,
+                                  heap_object,
+                                  sink_,
+                                  reference_representation);
+      serializer.Serialize();
+    }
+  } else {
+    // Serialize a Smi.
+    unsigned int value = Smi::cast(o)->value() + kSmiBias;
+    sink_->Put(SMI_SERIALIZATION, "SmiSerialization");
+    sink_->PutInt(value, "smi");
+  }
+}
+
+
+void Serializer2::ObjectSerializer::Serialize() {
+  int space = Serializer2::SpaceOfObject(object_);
+  int size = object_->Size();
+
+  if (reference_representation_ == TAGGED_REPRESENTATION) {
+    sink_->Put(OBJECT_SERIALIZATION, "ObjectSerialization");
+  } else {
+    ASSERT(reference_representation_ == CODE_TARGET_REPRESENTATION);
+    sink_->Put(CODE_OBJECT_SERIALIZATION, "ObjectSerialization");
+  }
+  sink_->Put(space, "space");
+  sink_->PutInt(size >> kObjectAlignmentBits, "Size in words");
+
+  // Get the map before overwriting it.
+  Map* map = object_->map();
+  // Mark this object as already serialized.
+  object_->set_map_word(
+      MapWord::FromSerializationAddress(serializer_->Allocate(space, size)));
+
+  // Serialize the map (first word of the object).
+  serializer_->SerializeObject(map, TAGGED_REPRESENTATION);
+
+  // Serialize the rest of the object.
+  ASSERT(bytes_processed_so_far_ == 0);
+  bytes_processed_so_far_ = kPointerSize;
+  object_->IterateBody(map->instance_type(), size, this);
+  OutputRawData(object_->address() + size);
+}
+
+
+void Serializer2::ObjectSerializer::VisitPointers(Object** start,
+                                                  Object** end) {
+  Address pointers_start = reinterpret_cast<Address>(start);
+  OutputRawData(pointers_start);
+
+  for (Object** current = start; current < end; current++) {
+    serializer_->SerializeObject(*current, TAGGED_REPRESENTATION);
+  }
+  bytes_processed_so_far_ += (end - start) * kPointerSize;
+}
+
+
+void Serializer2::ObjectSerializer::VisitExternalReferences(Address* start,
+                                                            Address* end) {
+  Address references_start = reinterpret_cast<Address>(start);
+  OutputRawData(references_start);
+
+  for (Address* current = start; current < end; current++) {
+    sink_->Put(EXTERNAL_REFERENCE_SERIALIZATION, "External reference");
+    int reference_id = serializer_->EncodeExternalReference(*current);
+    sink_->PutInt(reference_id, "reference id");
+  }
+  bytes_processed_so_far_ += (end - start) * kPointerSize;
+}
+
+
+void Serializer2::ObjectSerializer::VisitCodeTarget(RelocInfo* rinfo) {
+  ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
+  Address target_start = rinfo->target_address_address();
+  OutputRawData(target_start);
+  Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
+  serializer_->SerializeObject(target, CODE_TARGET_REPRESENTATION);
+  bytes_processed_so_far_ += Assembler::kCallTargetSize;
+}
+
+
+void Serializer2::ObjectSerializer::OutputRawData(Address up_to) {
+  Address object_start = object_->address();
+  int up_to_offset = up_to - object_start;
+  int skipped = up_to_offset - bytes_processed_so_far_;
+  ASSERT(skipped >= 0);
+  if (skipped != 0) {
+    sink_->Put(RAW_DATA_SERIALIZATION, "raw data");
+    sink_->PutInt(skipped, "length");
+    for (int i = 0; i < skipped; i++) {
+      unsigned int data = object_start[bytes_processed_so_far_ + i];
+      sink_->Put(data, "byte");
+    }
+  }
+  bytes_processed_so_far_ += skipped;
+}
+
+
+int Serializer2::SpaceOfObject(HeapObject* object) {
+  for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
+    AllocationSpace s = static_cast<AllocationSpace>(i);
+    if (Heap::InSpace(object, s)) {
+      if (i == LO_SPACE) {
+        if (object->IsCode()) {
+          return kLargeCode;
+        } else if (object->IsFixedArray()) {
+          return kLargeFixedArray;
+        } else {
+          return kLargeData;
+        }
+      }
+      return i;
+    }
+  }
+  UNREACHABLE();
+  return 0;
+}
+
+
+int Serializer2::SpaceOfAlreadySerializedObject(HeapObject* object) {
+  for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
+    AllocationSpace s = static_cast<AllocationSpace>(i);
+    if (Heap::InSpace(object, s)) {
+      return i;
+    }
+  }
+  UNREACHABLE();
+  return 0;
+}
+
+
+int Serializer2::Allocate(int space, int size) {
+  ASSERT(space >= 0 && space < kNumberOfSpaces);
+  if (SpaceIsLarge(space)) {
+    // In large object space we merely number the objects instead of trying to
+    // determine some sort of address.
+    return fullness_[LO_SPACE]++;
+  }
+  if (SpaceIsPaged(space)) {
+    // Paged spaces are a little special.  We encode their addresses as if the
+    // pages were all contiguous and each page were filled up in the range
+    // 0 - Page::kObjectAreaSize.  In practice the pages may not be contiguous
+    // and allocation does not start at offset 0 in the page, but this scheme
+    // means the deserializer can get the page number quickly by shifting the
+    // serialized address.
+    ASSERT(IsPowerOf2(Page::kPageSize));
+    int used_in_this_page = (fullness_[space] & (Page::kPageSize - 1));
+    ASSERT(size <= Page::kObjectAreaSize);
+    if (used_in_this_page + size > Page::kObjectAreaSize) {
+      fullness_[space] = RoundUp(fullness_[space], Page::kPageSize);
+    }
+  }
+  int allocation_address = fullness_[space];
+  fullness_[space] = allocation_address + size;
+  return allocation_address;
+}
+
+
 } }  // namespace v8::internal
index c901480fe59684af8ffff32473e525c4d9b8fe87..cefff78cac7fcbabd6c9ac568b4f9f9c2c34631c 100644 (file)
@@ -262,7 +262,18 @@ class SnapshotReader {
 
 // A Deserializer reads a snapshot and reconstructs the Object graph it defines.
 
-class Deserializer: public ObjectVisitor {
+
+// TODO(erikcorry): Get rid of this superclass when we are using the new
+// snapshot code exclusively.
+class GenericDeserializer: public ObjectVisitor {
+ public:
+  virtual void GetLog() = 0;
+  virtual void Deserialize() = 0;
+};
+
+
+// TODO(erikcorry): Get rid of this class.
+class Deserializer: public GenericDeserializer {
  public:
   // Create a deserializer. The snapshot is held in str and has size len.
   Deserializer(const byte* str, int len);
@@ -339,6 +350,223 @@ class Deserializer: public ObjectVisitor {
   DISALLOW_COPY_AND_ASSIGN(Deserializer);
 };
 
+
+class SnapshotByteSource {
+ public:
+  SnapshotByteSource(const byte* array, int length)
+    : data_(array), length_(length), position_(0) { }
+
+  bool HasMore() { return position_ < length_; }
+
+  int Get() {
+    ASSERT(position_ < length_);
+    return data_[position_++];
+  }
+
+  int GetInt() {
+    // A little unwind to catch the really small ints.
+    int snapshot_byte = Get();
+    if ((snapshot_byte & 0x80) == 0) {
+      return snapshot_byte;
+    }
+    uintptr_t accumulator = (snapshot_byte & 0x7f) << 7;
+    while (true) {
+      snapshot_byte = Get();
+      if ((snapshot_byte & 0x80) == 0) {
+        return accumulator | snapshot_byte;
+      }
+      accumulator = (accumulator | (snapshot_byte & 0x7f)) << 7;
+    }
+    UNREACHABLE();
+    return accumulator;
+  }
+
+  bool AtEOF() {
+    return position_ == length_;
+  }
+
+ private:
+  const byte* data_;
+  int length_;
+  int position_;
+};
+
+
+// The SerDes class is a common superclass for Serializer2 and Deserializer2
+// which is used to store common constants and methods used by both.
+// TODO(erikcorry): This should inherit from ObjectVisitor.
+class SerDes: public GenericDeserializer {
+ protected:
+  enum DataType {
+    SMI_SERIALIZATION,
+    RAW_DATA_SERIALIZATION,
+    OBJECT_SERIALIZATION,
+    CODE_OBJECT_SERIALIZATION,
+    BACKREF_SERIALIZATION,
+    CODE_BACKREF_SERIALIZATION,
+    EXTERNAL_REFERENCE_SERIALIZATION,
+    SYNCHRONIZE
+  };
+  // Our Smi encoding is much more efficient for small positive integers than it
+  // is for negative numbers so we add a bias before encoding and subtract it
+  // after encoding so that popular small negative Smis are efficiently encoded.
+  static const int kSmiBias = 16;
+  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 inline bool SpaceIsLarge(int space) { return space >= kLargeData; }
+  static inline bool SpaceIsPaged(int space) {
+    return space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE;
+  }
+};
+
+
+
+// A Deserializer reads a snapshot and reconstructs the Object graph it defines.
+class Deserializer2: public SerDes {
+ public:
+  // Create a deserializer from a snapshot byte source.
+  explicit Deserializer2(SnapshotByteSource* source);
+
+  virtual ~Deserializer2() { }
+
+  // Deserialize the snapshot into an empty heap.
+  void Deserialize();
+  void GetLog() { }   // TODO(erikcorry): Get rid of this.
+#ifdef DEBUG
+  virtual void Synchronize(const char* tag);
+#endif
+
+ private:
+  virtual void VisitPointers(Object** start, Object** end);
+
+  virtual void VisitExternalReferences(Address* start, Address* end) {
+    UNREACHABLE();
+  }
+
+  virtual void VisitRuntimeEntry(RelocInfo* rinfo) {
+    UNREACHABLE();
+  }
+
+  int CurrentAllocationAddress(int space) {
+    // The three different kinds of large objects have different tags in the
+    // snapshot so the deserializer knows which kind of object to allocate,
+    // but they share a fullness_ entry.
+    if (SpaceIsLarge(space)) space = LO_SPACE;
+    return fullness_[space];
+  }
+
+  HeapObject* GetAddress(int space);
+  Address Allocate(int space, int size);
+  bool ReadObject(Object** write_back);
+
+  // Keep track of the pages in the paged spaces.
+  // (In large object space we are keeping track of individual objects
+  // rather than pages.)  In new space we just need the address of the
+  // first object and the others will flow from that.
+  List<Address> pages_[SerDes::kNumberOfSpaces];
+
+  SnapshotByteSource* source_;
+  ExternalReferenceDecoder* external_reference_decoder_;
+  // Keep track of the fullness of each space in order to generate
+  // relative addresses for back references.  Large objects are
+  // just numbered sequentially since relative addresses make no
+  // sense in large object space.
+  int fullness_[LAST_SPACE + 1];
+
+  DISALLOW_COPY_AND_ASSIGN(Deserializer2);
+};
+
+
+class SnapshotByteSink {
+ public:
+  virtual ~SnapshotByteSink() { }
+  virtual void Put(int byte, const char* description) = 0;
+  void PutInt(uintptr_t integer, const char* description);
+};
+
+
+class Serializer2 : public SerDes {
+ public:
+  explicit Serializer2(SnapshotByteSink* sink);
+  // Serialize the current state of the heap. This operation destroys the
+  // heap contents.
+  void Serialize();
+  void VisitPointers(Object** start, Object** end);
+  void GetLog() { }       // TODO(erikcorry): Get rid of this.
+  void Deserialize() { }  // TODO(erikcorry): Get rid of this.
+#ifdef DEBUG
+  virtual void Synchronize(const char* tag);
+#endif
+
+ private:
+  enum ReferenceRepresentation {
+    TAGGED_REPRESENTATION,      // A tagged object reference.
+    CODE_TARGET_REPRESENTATION  // A reference to first instruction in target.
+  };
+  class ObjectSerializer : public ObjectVisitor {
+   public:
+    ObjectSerializer(Serializer2* serializer,
+                     Object* o,
+                     SnapshotByteSink* sink,
+                     ReferenceRepresentation representation)
+      : serializer_(serializer),
+        object_(HeapObject::cast(o)),
+        sink_(sink),
+        reference_representation_(representation),
+        bytes_processed_so_far_(0) { }
+    void Serialize();
+    void VisitPointers(Object** start, Object** end);
+    void VisitExternalReferences(Address* start, Address* end);
+    void VisitCodeTarget(RelocInfo* target);
+
+   private:
+    void OutputRawData(Address up_to);
+
+    Serializer2* serializer_;
+    HeapObject* object_;
+    SnapshotByteSink* sink_;
+    ReferenceRepresentation reference_representation_;
+    int bytes_processed_so_far_;
+  };
+
+  void SerializeObject(Object* o, ReferenceRepresentation representation);
+  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
+  // to indicate to the deserializer what kind of large object allocation
+  // to make.
+  static int SpaceOfObject(HeapObject* object);
+  // This just returns the space of the object.  It will return LO_SPACE
+  // for all large objects since you can't check the type of the object
+  // once the map has been used for the serialization address.
+  static int SpaceOfAlreadySerializedObject(HeapObject* object);
+  int Allocate(int space, int size);
+  int CurrentAllocationAddress(int space) {
+    if (SpaceIsLarge(space)) space = LO_SPACE;
+    return fullness_[space];
+  }
+  int EncodeExternalReference(Address addr) {
+    return external_reference_encoder_->Encode(addr);
+  }
+
+  // Keep track of the fullness of each space in order to generate
+  // relative addresses for back references.  Large objects are
+  // just numbered sequentially since relative addresses make no
+  // sense in large object space.
+  int fullness_[LAST_SPACE + 1];
+  SnapshotByteSink* sink_;
+  int current_root_index_;
+  ExternalReferenceEncoder* external_reference_encoder_;
+
+  friend class ObjectSerializer;
+  friend class Deserializer2;
+
+  DISALLOW_COPY_AND_ASSIGN(Serializer2);
+};
+
 } }  // namespace v8::internal
 
 #endif  // V8_SERIALIZE_H_
index 9c66a5037413d0d052b842e830cdc4d06ea45326..010648b12dcb6c556be36fa8cce2eaddfcdc72ff 100644 (file)
@@ -43,6 +43,13 @@ bool Snapshot::Deserialize(const byte* content, int len) {
 }
 
 
+bool Snapshot::Deserialize2(const byte* content, int len) {
+  SnapshotByteSource source(content, len);
+  Deserializer2 deserializer(&source);
+  return V8::Initialize(&deserializer);
+}
+
+
 bool Snapshot::Initialize(const char* snapshot_file) {
   if (snapshot_file) {
     int len;
@@ -58,6 +65,20 @@ bool Snapshot::Initialize(const char* snapshot_file) {
 }
 
 
+bool Snapshot::Initialize2(const char* snapshot_file) {
+  if (snapshot_file) {
+    int len;
+    byte* str = ReadBytes(snapshot_file, &len);
+    if (!str) return false;
+    Deserialize2(str, len);
+    DeleteArray(str);
+  } else if (size_ > 0) {
+    Deserialize2(data_, size_);
+  }
+  return true;
+}
+
+
 bool Snapshot::WriteToFile(const char* snapshot_file) {
   Serializer ser;
   ser.Serialize();
@@ -72,4 +93,38 @@ bool Snapshot::WriteToFile(const char* snapshot_file) {
 }
 
 
+class FileByteSink : public SnapshotByteSink {
+ public:
+  explicit FileByteSink(const char* snapshot_file) {
+    fp_ = fopen(snapshot_file, "wb");
+    if (fp_ == NULL) {
+      PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file);
+      exit(1);
+    }
+  }
+  virtual ~FileByteSink() {
+    if (fp_ != NULL) {
+      fclose(fp_);
+    }
+  }
+  virtual void Put(int byte, const char* description) {
+    if (fp_ != NULL) {
+      fputc(byte, fp_);
+    }
+  }
+
+ private:
+  FILE* fp_;
+};
+
+
+bool Snapshot::WriteToFile2(const char* snapshot_file) {
+  FileByteSink file(snapshot_file);
+  Serializer2 ser(&file);
+  ser.Serialize();
+  return true;
+}
+
+
+
 } }  // namespace v8::internal
index 88ba8db30e5e1ca672093a9870f2128158ed5962..a3a3867d052764c5af73acab9c509a955811bdb8 100644 (file)
@@ -37,6 +37,7 @@ class Snapshot {
   // NULL, use the internal snapshot instead. Returns false if no snapshot
   // could be found.
   static bool Initialize(const char* snapshot_file = NULL);
+  static bool Initialize2(const char* snapshot_file = NULL);
 
   // Returns whether or not the snapshot is enabled.
   static bool IsEnabled() { return size_ != 0; }
@@ -44,12 +45,14 @@ class Snapshot {
   // Write snapshot to the given file. Returns true if snapshot was written
   // successfully.
   static bool WriteToFile(const char* snapshot_file);
+  static bool WriteToFile2(const char* snapshot_file);
 
  private:
   static const byte data_[];
   static int size_;
 
   static bool Deserialize(const byte* content, int len);
+  static bool Deserialize2(const byte* content, int len);
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(Snapshot);
 };
index bd58742ebaebff65d50532569616d907cf982c13..c69579a9d8319bc6d6ba97b07273eff96d471e9c 100644 (file)
@@ -1527,7 +1527,9 @@ void FreeListNode::set_size(int size_in_bytes) {
   // correct size.
   if (size_in_bytes > ByteArray::kAlignedSize) {
     set_map(Heap::raw_unchecked_byte_array_map());
-    ByteArray::cast(this)->set_length(ByteArray::LengthFor(size_in_bytes));
+    // Can't use ByteArray::cast because it fails during deserialization.
+    ByteArray* this_as_byte_array = reinterpret_cast<ByteArray*>(this);
+    this_as_byte_array->set_length(ByteArray::LengthFor(size_in_bytes));
   } else if (size_in_bytes == kPointerSize) {
     set_map(Heap::raw_unchecked_one_pointer_filler_map());
   } else if (size_in_bytes == 2 * kPointerSize) {
@@ -1535,7 +1537,8 @@ void FreeListNode::set_size(int size_in_bytes) {
   } else {
     UNREACHABLE();
   }
-  ASSERT(Size() == size_in_bytes);
+  // We would like to ASSERT(Size() == size_in_bytes) but this would fail during
+  // deserialization because the byte array map is not done yet.
 }
 
 
@@ -1828,13 +1831,16 @@ HeapObject* OldSpace::SlowAllocateRaw(int size_in_bytes) {
     return AllocateInNextPage(current_page, size_in_bytes);
   }
 
-  // There is no next page in this space.  Try free list allocation.
-  int wasted_bytes;
-  Object* result = free_list_.Allocate(size_in_bytes, &wasted_bytes);
-  accounting_stats_.WasteBytes(wasted_bytes);
-  if (!result->IsFailure()) {
-    accounting_stats_.AllocateBytes(size_in_bytes);
-    return HeapObject::cast(result);
+  // There is no next page in this space.  Try free list allocation unless that
+  // is currently forbidden.
+  if (!Heap::linear_allocation()) {
+    int wasted_bytes;
+    Object* result = free_list_.Allocate(size_in_bytes, &wasted_bytes);
+    accounting_stats_.WasteBytes(wasted_bytes);
+    if (!result->IsFailure()) {
+      accounting_stats_.AllocateBytes(size_in_bytes);
+      return HeapObject::cast(result);
+    }
   }
 
   // Free list allocation failed and there is no next page.  Fail if we have
@@ -2230,10 +2236,10 @@ HeapObject* FixedSpace::SlowAllocateRaw(int size_in_bytes) {
     return AllocateInNextPage(current_page, size_in_bytes);
   }
 
-  // There is no next page in this space.  Try free list allocation.
-  // The fixed space free list implicitly assumes that all free blocks
-  // are of the fixed size.
-  if (size_in_bytes == object_size_in_bytes_) {
+  // There is no next page in this space.  Try free list allocation unless
+  // that is currently forbidden.  The fixed space free list implicitly assumes
+  // that all free blocks are of the fixed size.
+  if (!Heap::linear_allocation()) {
     Object* result = free_list_.Allocate();
     if (!result->IsFailure()) {
       accounting_stats_.AllocateBytes(size_in_bytes);
index 3c70ee96b0b57146ad44776c164b990911fc8a8b..fe21b3ba6feda9f68aec72b5b88e0408b16268f1 100644 (file)
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -45,7 +45,7 @@ bool V8::has_been_setup_ = false;
 bool V8::has_been_disposed_ = false;
 bool V8::has_fatal_error_ = false;
 
-bool V8::Initialize(Deserializer *des) {
+bool V8::Initialize(GenericDeserializer *des) {
   bool create_heap_objects = des == NULL;
   if (has_been_disposed_ || has_fatal_error_) return false;
   if (IsRunning()) return true;
index 106ae612c1fee54f7496e5e8ded1ae5598695bd4..6c5546c631067cefd487248d239098cc9ed5f929 100644 (file)
--- a/src/v8.h
+++ b/src/v8.h
@@ -80,7 +80,7 @@ class V8 : public AllStatic {
   // created from scratch. If a non-null Deserializer is given, the
   // initial state is created by reading the deserialized data into an
   // empty heap.
-  static bool Initialize(Deserializer* des);
+  static bool Initialize(GenericDeserializer* des);
   static void TearDown();
   static bool IsRunning() { return is_running_; }
   // To be dead you have to have lived
index 4fabc1f18a8f851fa3891590f22fec024aa807e5..00d6248add159e6c0b5590d09b24fd71f3215c49 100644 (file)
@@ -459,6 +459,8 @@ class Assembler : public Malloced {
   static inline Address target_address_at(Address pc);
   static inline void set_target_address_at(Address pc, Address target);
   inline Handle<Object> code_target_object_handle_at(Address pc);
+  // Number of bytes taken up by the branch target in the code.
+  static const int kCallTargetSize = 4;  // Use 32-bit displacement.
   // Distance between the address of the code target in the call instruction
   // and the return address pushed on the stack.
   static const int kCallTargetAddressOffset = 4;  // Use 32-bit displacement.
index b43cd6437a2e053676215d0e2bae289dedb72bfa..6ce241ff1e08e940b36a54ed4f5f25fc593ac1fd 100644 (file)
@@ -47,6 +47,10 @@ test-serialize/DependentTestThatAlwaysFails: FAIL
 
 [ $arch == arm ]
 
+# New serialization doesn't work on ARM yet.
+test-serialize/Deserialize2: SKIP
+test-serialize/DeserializeAndRunScript2: SKIP
+
 # BUG(113): Test seems flaky on ARM.
 test-spaces/LargeObjectSpace: PASS || FAIL
 
index db37eb3433b681db09d21e2da28d19f0b600fc20..01e07157a1029c6548c0d27524cc1988377f14df 100644 (file)
@@ -185,6 +185,18 @@ static void Serialize() {
 }
 
 
+static void Serialize2() {
+  Serializer::Enable();
+  // We have to create one context.  One reason for this is so that the builtins
+  // can be loaded from v8natives.js and their addresses can be processed.  This
+  // will clear the pending fixups array, which would otherwise contain GC roots
+  // that would confuse the serialization/deserialization process.
+  v8::Persistent<v8::Context> env = v8::Context::New();
+  env.Dispose();
+  Snapshot::WriteToFile2(FLAG_testing_serialization_file);
+}
+
+
 // Test that the whole heap can be serialized when running from the
 // internal snapshot.
 // (Smoke test.)
@@ -203,6 +215,13 @@ TEST(Serialize) {
 }
 
 
+// Test that the whole heap can be serialized.
+TEST(Serialize2) {
+  v8::V8::Initialize();
+  Serialize2();
+}
+
+
 // Test that the heap isn't destroyed after a serialization.
 TEST(SerializeNondestructive) {
   if (Snapshot::IsEnabled()) return;
@@ -230,6 +249,11 @@ static void Deserialize() {
 }
 
 
+static void Deserialize2() {
+  CHECK(Snapshot::Initialize2(FLAG_testing_serialization_file));
+}
+
+
 static void SanityCheck() {
   v8::HandleScope scope;
 #ifdef DEBUG
@@ -251,6 +275,21 @@ DEPENDENT_TEST(Deserialize, Serialize) {
   SanityCheck();
 }
 
+
+DEPENDENT_TEST(Deserialize2, Serialize2) {
+  v8::HandleScope scope;
+
+  Deserialize2();
+
+  fflush(stdout);
+
+  v8::Persistent<v8::Context> env = v8::Context::New();
+  env->Enter();
+
+  SanityCheck();
+}
+
+
 DEPENDENT_TEST(DeserializeAndRunScript, Serialize) {
   v8::HandleScope scope;
 
@@ -263,6 +302,21 @@ DEPENDENT_TEST(DeserializeAndRunScript, Serialize) {
 }
 
 
+DEPENDENT_TEST(DeserializeAndRunScript2, Serialize2) {
+  v8::HandleScope scope;
+
+  Deserialize2();
+
+  v8::Persistent<v8::Context> env = v8::Context::New();
+  env->Enter();
+
+  const char* c_source = "\"1234\".length";
+  v8::Local<v8::String> source = v8::String::New(c_source);
+  v8::Local<v8::Script> script = v8::Script::Compile(source);
+  CHECK_EQ(4, script->Run()->Int32Value());
+}
+
+
 DEPENDENT_TEST(DeserializeNatives, Serialize) {
   v8::HandleScope scope;
 
@@ -288,9 +342,6 @@ DEPENDENT_TEST(DeserializeExtensions, Serialize) {
 }
 
 
-extern "C" void V8_Fatal(const char* file, int line, const char* format, ...);
-
-
 TEST(TestThatAlwaysSucceeds) {
 }