Revision: 3142
Author: [email protected]
Date: Tue Oct 27 04:54:01 2009
Log: New snapshot framework.  Doesn't work on ARM yet (code targets
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
http://code.google.com/p/v8/source/detail?r=3142

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

=======================================
--- /branches/bleeding_edge/include/v8.h        Tue Oct 20 08:26:17 2009
+++ /branches/bleeding_edge/include/v8.h        Tue Oct 27 04:54:01 2009
@@ -452,8 +452,8 @@
    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;
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h     Fri Oct  2 06:36:20 2009
+++ /branches/bleeding_edge/src/arm/assembler-arm.h     Tue Oct 27 04:54:01 2009
@@ -437,6 +437,11 @@
    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);

=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Tue Oct  6 06:59:56 2009
+++ /branches/bleeding_edge/src/bootstrapper.cc Tue Oct 27 04:54:01 2009
@@ -316,8 +316,11 @@

  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");
  }


=======================================
--- /branches/bleeding_edge/src/globals.h       Tue Oct 27 01:13:59 2009
+++ /branches/bleeding_edge/src/globals.h       Tue Oct 27 04:54:01 2009
@@ -248,6 +248,7 @@
  class VariableProxy;
  class RelocInfo;
  class Deserializer;
+class GenericDeserializer;  // TODO(erikcorry): Get rid of this.
  class MessageLocation;
  class ObjectGroup;
  class TickSample;
@@ -272,7 +273,9 @@
    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;
=======================================
--- /branches/bleeding_edge/src/heap.cc Mon Oct 26 05:26:42 2009
+++ /branches/bleeding_edge/src/heap.cc Tue Oct 27 04:54:01 2009
@@ -114,6 +114,7 @@
  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 @@
  }


-#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");
-}
-#undef SYNCHRONIZE_TAG
+  v->Synchronize("threadmanager");
+}


  // Flag is set when the heap has been configured.  The heap can be  
repeatedly
=======================================
--- /branches/bleeding_edge/src/heap.h  Mon Oct 26 03:51:30 2009
+++ /branches/bleeding_edge/src/heap.h  Tue Oct 27 04:54:01 2009
@@ -38,7 +38,13 @@

  // 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 @@
       
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 @@
    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 @@
    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 @@
    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 @@
    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 @@
    friend class Factory;
    friend class DisallowAllocationFailure;
    friend class AlwaysAllocateScope;
+  friend class LinearAllocationScope;
  };


@@ -1157,6 +1165,19 @@
  };


+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
=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.h   Thu Oct 22 07:49:00  
2009
+++ /branches/bleeding_edge/src/ia32/assembler-ia32.h   Tue Oct 27 04:54:01  
2009
@@ -439,6 +439,8 @@
    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;
=======================================
--- /branches/bleeding_edge/src/list.h  Mon Sep 28 06:53:03 2009
+++ /branches/bleeding_edge/src/list.h  Tue Oct 27 04:54:01 2009
@@ -48,6 +48,7 @@
  class List {
   public:

+  List() { Initialize(0); }
    INLINE(explicit List(int capacity)) { Initialize(capacity); }
    INLINE(~List()) { DeleteData(data_); }

=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Mon Oct 26 08:16:42 2009
+++ /branches/bleeding_edge/src/objects-inl.h   Tue Oct 27 04:54:01 2009
@@ -943,6 +943,25 @@
    ASSERT(IsForwardingAddress());
    return HeapObject::FromAddress(reinterpret_cast<Address>(value_));
  }
+
+
+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() {
=======================================
--- /branches/bleeding_edge/src/objects.h       Mon Oct 26 08:16:42 2009
+++ /branches/bleeding_edge/src/objects.h       Tue Oct 27 04:54:01 2009
@@ -1082,6 +1082,15 @@
    // 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 @@
    // 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
  };

=======================================
--- /branches/bleeding_edge/src/serialize.cc    Thu Oct  8 05:36:12 2009
+++ /branches/bleeding_edge/src/serialize.cc    Tue Oct 27 04:54:01 2009
@@ -1417,7 +1417,27 @@
  #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 @@
    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);
  }


@@ -1738,6 +1762,488 @@
    UNREACHABLE();
    return NULL;
  }
+
+
+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
=======================================
--- /branches/bleeding_edge/src/serialize.h     Mon Sep 21 03:35:47 2009
+++ /branches/bleeding_edge/src/serialize.h     Tue Oct 27 04:54:01 2009
@@ -262,7 +262,18 @@

  // 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 @@
    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_
=======================================
--- /branches/bleeding_edge/src/snapshot-common.cc      Mon May 25 03:05:56 2009
+++ /branches/bleeding_edge/src/snapshot-common.cc      Tue Oct 27 04:54:01 2009
@@ -41,6 +41,13 @@
    des.GetFlags();
    return V8::Initialize(&des);
  }
+
+
+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) {
@@ -56,6 +63,20 @@
    }
    return false;
  }
+
+
+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) {
@@ -72,4 +93,38 @@
  }


+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
=======================================
--- /branches/bleeding_edge/src/snapshot.h      Mon May 25 03:05:56 2009
+++ /branches/bleeding_edge/src/snapshot.h      Tue Oct 27 04:54:01 2009
@@ -37,6 +37,7 @@
    // 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 @@
    // 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);
  };
=======================================
--- /branches/bleeding_edge/src/spaces.cc       Wed Oct 21 08:03:34 2009
+++ /branches/bleeding_edge/src/spaces.cc       Tue Oct 27 04:54:01 2009
@@ -1527,7 +1527,9 @@
    // 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 @@
    } 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 @@
      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 @@
      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);
=======================================
--- /branches/bleeding_edge/src/v8.cc   Thu Oct  8 05:36:12 2009
+++ /branches/bleeding_edge/src/v8.cc   Tue Oct 27 04:54:01 2009
@@ -45,7 +45,7 @@
  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;
=======================================
--- /branches/bleeding_edge/src/v8.h    Mon Oct  5 17:06:17 2009
+++ /branches/bleeding_edge/src/v8.h    Tue Oct 27 04:54:01 2009
@@ -80,7 +80,7 @@
    // 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
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.h     Mon Oct 26 07:38:22 2009
+++ /branches/bleeding_edge/src/x64/assembler-x64.h     Tue Oct 27 04:54:01 2009
@@ -459,6 +459,8 @@
    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.
=======================================
--- /branches/bleeding_edge/test/cctest/cctest.status   Thu Oct 22 12:09:09  
2009
+++ /branches/bleeding_edge/test/cctest/cctest.status   Tue Oct 27 04:54:01  
2009
@@ -47,6 +47,10 @@

  [ $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

=======================================
--- /branches/bleeding_edge/test/cctest/test-serialize.cc       Thu Oct 22  
12:09:09 2009
+++ /branches/bleeding_edge/test/cctest/test-serialize.cc       Tue Oct 27  
04:54:01 2009
@@ -183,6 +183,18 @@

    Snapshot::WriteToFile(FLAG_testing_serialization_file);
  }
+
+
+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
@@ -201,6 +213,13 @@
    if (Snapshot::IsEnabled()) return;
    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.
@@ -228,6 +247,11 @@
  #endif
    CHECK(Snapshot::Initialize(FLAG_testing_serialization_file));
  }
+
+
+static void Deserialize2() {
+  CHECK(Snapshot::Initialize2(FLAG_testing_serialization_file));
+}


  static void SanityCheck() {
@@ -250,6 +274,21 @@

    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;
@@ -261,6 +300,21 @@
    v8::Local<v8::Script> script = v8::Script::Compile(source);
    CHECK_EQ(4, script->Run()->Int32Value());
  }
+
+
+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) {
@@ -286,9 +340,6 @@
    v8::Local<v8::Value> value = script->Run();
    CHECK(value->IsUndefined());
  }
-
-
-extern "C" void V8_Fatal(const char* file, int line, const char*  
format, ...);


  TEST(TestThatAlwaysSucceeds) {

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

Reply via email to