The gc should be able to traverse all AllocationSites for decision making. The sites...
authormvstanton@chromium.org <mvstanton@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 17 Jul 2013 11:50:24 +0000 (11:50 +0000)
committermvstanton@chromium.org <mvstanton@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 17 Jul 2013 11:50:24 +0000 (11:50 +0000)
* Allocations of AllocationSites occur in generated code, so generated code needs to be able to add to the list. For now I have a special hydrogen instruction, though it would be nice to use general purpose instructions.
* The snapshot contains AllocationSites, and these need to be re-threaded into the list on deserialization.

Something nice is that the AllocationSites are only created in old space, so a special new space visitor isn't required.

BUG=
R=mstarzinger@chromium.org

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

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

25 files changed:
src/arm/lithium-arm.cc
src/arm/lithium-arm.h
src/arm/lithium-codegen-arm.cc
src/assembler.cc
src/assembler.h
src/code-stubs-hydrogen.cc
src/heap.cc
src/heap.h
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/objects-inl.h
src/objects-printer.cc
src/objects-visiting-inl.h
src/objects-visiting.cc
src/objects-visiting.h
src/objects.cc
src/objects.h
src/serialize.cc
src/serialize.h
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
src/x64/lithium-x64.h

index d614bd0..b68d22f 100644 (file)
@@ -272,6 +272,24 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) {
 }
 
 
+ExternalReference LLinkObjectInList::GetReference(Isolate* isolate) {
+  switch (hydrogen()->known_list()) {
+    case HLinkObjectInList::ALLOCATION_SITE_LIST:
+      return ExternalReference::allocation_sites_list_address(isolate);
+  }
+
+  UNREACHABLE();
+  // Return a dummy value
+  return ExternalReference::isolate_address(isolate);
+}
+
+
+void LLinkObjectInList::PrintDataTo(StringStream* stream) {
+  object()->PrintTo(stream);
+  stream->Add(" offset %d", hydrogen()->store_field().offset());
+}
+
+
 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
   context()->PrintTo(stream);
   stream->Add("[%d]", slot_index());
@@ -2113,6 +2131,13 @@ LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
 }
 
 
+LInstruction* LChunkBuilder::DoLinkObjectInList(HLinkObjectInList* instr) {
+  LOperand* object = UseRegister(instr->value());
+  LLinkObjectInList* result = new(zone()) LLinkObjectInList(object);
+  return result;
+}
+
+
 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
   LOperand* context = UseRegisterAtStart(instr->value());
   LInstruction* result =
index a628d5a..5165f1b 100644 (file)
@@ -120,6 +120,7 @@ class LCodeGen;
   V(IsUndetectableAndBranch)                    \
   V(Label)                                      \
   V(LazyBailout)                                \
+  V(LinkObjectInList)                           \
   V(LoadContextSlot)                            \
   V(LoadExternalArrayPointer)                   \
   V(LoadFunctionPrototype)                      \
@@ -1683,6 +1684,23 @@ class LStoreGlobalGeneric: public LTemplateInstruction<0, 2, 0> {
 };
 
 
+class LLinkObjectInList: public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LLinkObjectInList(LOperand* object) {
+    inputs_[0] = object;
+  }
+
+  LOperand* object() { return inputs_[0]; }
+
+  ExternalReference GetReference(Isolate* isolate);
+
+  DECLARE_CONCRETE_INSTRUCTION(LinkObjectInList, "link-object-in-list")
+  DECLARE_HYDROGEN_ACCESSOR(LinkObjectInList)
+
+  virtual void PrintDataTo(StringStream* stream);
+};
+
+
 class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LLoadContextSlot(LOperand* context) {
index e21a1bb..9900a1e 100644 (file)
@@ -2928,6 +2928,19 @@ void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
 }
 
 
+void LCodeGen::DoLinkObjectInList(LLinkObjectInList* instr) {
+  Register object = ToRegister(instr->object());
+  ExternalReference sites_list_address = instr->GetReference(isolate());
+
+  __ mov(ip, Operand(sites_list_address));
+  __ ldr(ip, MemOperand(ip));
+  __ str(ip, FieldMemOperand(object,
+                             instr->hydrogen()->store_field().offset()));
+  __ mov(ip, Operand(sites_list_address));
+  __ str(object, MemOperand(ip));
+}
+
+
 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register result = ToRegister(instr->result());
index 16a73a7..82c3c83 100644 (file)
@@ -1125,6 +1125,12 @@ ExternalReference ExternalReference::roots_array_start(Isolate* isolate) {
 }
 
 
+ExternalReference ExternalReference::allocation_sites_list_address(
+    Isolate* isolate) {
+  return ExternalReference(isolate->heap()->allocation_sites_list_address());
+}
+
+
 ExternalReference ExternalReference::address_of_stack_limit(Isolate* isolate) {
   return ExternalReference(isolate->stack_guard()->address_of_jslimit());
 }
index 95853e8..5cdddeb 100644 (file)
@@ -747,6 +747,9 @@ class ExternalReference BASE_EMBEDDED {
   // Static variable Heap::roots_array_start()
   static ExternalReference roots_array_start(Isolate* isolate);
 
+  // Static variable Heap::allocation_sites_list_address()
+  static ExternalReference allocation_sites_list_address(Isolate* isolate);
+
   // Static variable StackGuard::address_of_jslimit()
   static ExternalReference address_of_stack_limit(Isolate* isolate);
 
index 25715cb..531c25c 100644 (file)
@@ -445,8 +445,12 @@ HValue* CodeStubGraphBuilder<CreateAllocationSiteStub>::BuildCodeStub() {
   // Store the payload (smi elements kind)
   HValue* initial_elements_kind = AddInstruction(new(zone) HConstant(
       GetInitialFastElementsKind()));
-  AddInstruction(new(zone) HStoreNamedField(object,
-      HObjectAccess::ForAllocationSiteTransitionInfo(), initial_elements_kind));
+  Add<HStoreNamedField>(object,
+                        HObjectAccess::ForAllocationSiteTransitionInfo(),
+                        initial_elements_kind);
+
+  Add<HLinkObjectInList>(object, HObjectAccess::ForAllocationSiteWeakNext(),
+                         HLinkObjectInList::ALLOCATION_SITE_LIST);
 
   // We use a hammer (SkipWriteBarrier()) to indicate that we know the input
   // cell is really a Cell, and so no write barrier is needed.
index 792178e..97c1d41 100644 (file)
@@ -182,6 +182,7 @@ Heap::Heap()
   memset(roots_, 0, sizeof(roots_[0]) * kRootListLength);
   native_contexts_list_ = NULL;
   array_buffers_list_ = Smi::FromInt(0);
+  allocation_sites_list_ = Smi::FromInt(0);
   mark_compact_collector_.heap_ = this;
   external_string_table_.heap_ = this;
   // Put a dummy entry in the remembered pages so we can find the list the
@@ -1664,6 +1665,7 @@ void Heap::ProcessWeakReferences(WeakObjectRetainer* retainer) {
       mark_compact_collector()->is_compacting();
   ProcessArrayBuffers(retainer, record_slots);
   ProcessNativeContexts(retainer, record_slots);
+  ProcessAllocationSites(retainer, record_slots);
 }
 
 void Heap::ProcessNativeContexts(WeakObjectRetainer* retainer,
@@ -1757,6 +1759,39 @@ void Heap::TearDownArrayBuffers() {
 }
 
 
+template<>
+struct WeakListVisitor<AllocationSite> {
+  static void SetWeakNext(AllocationSite* obj, Object* next) {
+    obj->set_weak_next(next);
+  }
+
+  static Object* WeakNext(AllocationSite* obj) {
+    return obj->weak_next();
+  }
+
+  static void VisitLiveObject(Heap* heap,
+                              AllocationSite* array_buffer,
+                              WeakObjectRetainer* retainer,
+                              bool record_slots) {}
+
+  static void VisitPhantomObject(Heap* heap, AllocationSite* phantom) {}
+
+  static int WeakNextOffset() {
+    return AllocationSite::kWeakNextOffset;
+  }
+};
+
+
+void Heap::ProcessAllocationSites(WeakObjectRetainer* retainer,
+                                  bool record_slots) {
+  Object* allocation_site_obj =
+      VisitWeakList<AllocationSite>(this,
+                                    allocation_sites_list(),
+                                    retainer, record_slots);
+  set_allocation_sites_list(allocation_site_obj);
+}
+
+
 void Heap::VisitExternalResources(v8::ExternalResourceVisitor* visitor) {
   DisallowHeapAllocation no_allocation;
 
@@ -2887,7 +2922,12 @@ MaybeObject* Heap::AllocateAllocationSite() {
   MaybeObject* maybe_result = Allocate(allocation_site_map(),
                                        OLD_POINTER_SPACE);
   if (!maybe_result->ToObject(&result)) return maybe_result;
-  AllocationSite::cast(result)->Initialize();
+  AllocationSite* site = AllocationSite::cast(result);
+  site->Initialize();
+
+  // Link the site
+  site->set_weak_next(allocation_sites_list());
+  set_allocation_sites_list(site);
   return result;
 }
 
@@ -6889,6 +6929,7 @@ bool Heap::CreateHeapObjects() {
 
   native_contexts_list_ = undefined_value();
   array_buffers_list_ = undefined_value();
+  allocation_sites_list_ = undefined_value();
   return true;
 }
 
index 2c97faf..6d12208 100644 (file)
@@ -1376,6 +1376,11 @@ class Heap {
   }
   Object* array_buffers_list() { return array_buffers_list_; }
 
+  void set_allocation_sites_list(Object* object) {
+    allocation_sites_list_ = object;
+  }
+  Object* allocation_sites_list() { return allocation_sites_list_; }
+  Object** allocation_sites_list_address() { return &allocation_sites_list_; }
 
   // Number of mark-sweeps.
   unsigned int ms_count() { return ms_count_; }
@@ -2045,9 +2050,10 @@ class Heap {
   // last GC.
   bool old_gen_exhausted_;
 
+  // Weak list heads, threaded through the objects.
   Object* native_contexts_list_;
-
   Object* array_buffers_list_;
+  Object* allocation_sites_list_;
 
   StoreBufferRebuilder store_buffer_rebuilder_;
 
@@ -2197,6 +2203,7 @@ class Heap {
 
   void ProcessNativeContexts(WeakObjectRetainer* retainer, bool record_slots);
   void ProcessArrayBuffers(WeakObjectRetainer* retainer, bool record_slots);
+  void ProcessAllocationSites(WeakObjectRetainer* retainer, bool record_slots);
 
   // Called on heap tear-down.
   void TearDownArrayBuffers();
index e99f909..16f502d 100644 (file)
@@ -3059,6 +3059,12 @@ void HStoreGlobalGeneric::PrintDataTo(StringStream* stream) {
 }
 
 
+void HLinkObjectInList::PrintDataTo(StringStream* stream) {
+  value()->PrintNameTo(stream);
+  stream->Add(" offset %d", store_field_.offset());
+}
+
+
 void HLoadContextSlot::PrintDataTo(StringStream* stream) {
   value()->PrintNameTo(stream);
   stream->Add("[%d]", slot_index());
index 2fb18fd..a006c44 100644 (file)
@@ -131,6 +131,7 @@ class LChunkBuilder;
   V(IsSmiAndBranch)                            \
   V(IsUndetectableAndBranch)                   \
   V(LeaveInlined)                              \
+  V(LinkObjectInList)                          \
   V(LoadContextSlot)                           \
   V(LoadExternalArrayPointer)                  \
   V(LoadFunctionPrototype)                     \
@@ -5332,6 +5333,10 @@ class HObjectAccess {
     return HObjectAccess(kInobject, AllocationSite::kTransitionInfoOffset);
   }
 
+  static HObjectAccess ForAllocationSiteWeakNext() {
+    return HObjectAccess(kInobject, AllocationSite::kWeakNextOffset);
+  }
+
   static HObjectAccess ForFixedArrayLength() {
     return HObjectAccess(kArrayLengths, FixedArray::kLengthOffset);
   }
@@ -5422,6 +5427,38 @@ class HObjectAccess {
 };
 
 
+class HLinkObjectInList: public HUnaryOperation {
+ public:
+  // There needs to be a mapping from every KnownList to an external reference
+  enum KnownList {
+    ALLOCATION_SITE_LIST
+  };
+
+  HLinkObjectInList(HValue* object, HObjectAccess store_field,
+                    KnownList known_list)
+      : HUnaryOperation(object),
+        store_field_(store_field),
+        known_list_(known_list) {
+    set_representation(Representation::Tagged());
+  }
+
+  HObjectAccess store_field() const { return store_field_; }
+  KnownList known_list() const { return known_list_; }
+
+  virtual Representation RequiredInputRepresentation(int index) {
+    return Representation::Tagged();
+  }
+
+  virtual void PrintDataTo(StringStream* stream);
+
+  DECLARE_CONCRETE_INSTRUCTION(LinkObjectInList)
+
+ private:
+  HObjectAccess store_field_;
+  KnownList known_list_;
+};
+
+
 class HLoadNamedField: public HTemplateInstruction<2> {
  public:
   HLoadNamedField(HValue* object,
index 770cecb..8b7a494 100644 (file)
@@ -2992,6 +2992,20 @@ void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
 }
 
 
+void LCodeGen::DoLinkObjectInList(LLinkObjectInList* instr) {
+  Register object = ToRegister(instr->object());
+  Register temp = ToRegister(instr->temp());
+  ExternalReference sites_list_address = instr->GetReference(isolate());
+
+  __ mov(temp, Immediate(sites_list_address));
+  __ mov(temp, Operand(temp, 0));
+  __ mov(FieldOperand(object, instr->hydrogen()->store_field().offset()),
+         temp);
+  __ mov(temp, Immediate(sites_list_address));
+  __ mov(Operand(temp, 0), object);
+}
+
+
 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register result = ToRegister(instr->result());
index 24ee7bf..aebe26b 100644 (file)
@@ -302,6 +302,24 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) {
 }
 
 
+ExternalReference LLinkObjectInList::GetReference(Isolate* isolate) {
+  switch (hydrogen()->known_list()) {
+    case HLinkObjectInList::ALLOCATION_SITE_LIST:
+      return ExternalReference::allocation_sites_list_address(isolate);
+  }
+
+  UNREACHABLE();
+  // Return a dummy value
+  return ExternalReference::isolate_address(isolate);
+}
+
+
+void LLinkObjectInList::PrintDataTo(StringStream* stream) {
+  object()->PrintTo(stream);
+  stream->Add(" offset %d", hydrogen()->store_field().offset());
+}
+
+
 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
   context()->PrintTo(stream);
   stream->Add("[%d]", slot_index());
@@ -2162,6 +2180,14 @@ LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
 }
 
 
+LInstruction* LChunkBuilder::DoLinkObjectInList(HLinkObjectInList* instr) {
+  LOperand* object = UseRegister(instr->value());
+  LOperand* temp = TempRegister();
+  LLinkObjectInList* result = new(zone()) LLinkObjectInList(object, temp);
+  return result;
+}
+
+
 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
   LOperand* context = UseRegisterAtStart(instr->value());
   LInstruction* result =
index 4dcc95a..a938ee5 100644 (file)
@@ -115,6 +115,7 @@ class LCodeGen;
   V(IsUndetectableAndBranch)                    \
   V(Label)                                      \
   V(LazyBailout)                                \
+  V(LinkObjectInList)                           \
   V(LoadContextSlot)                            \
   V(LoadExternalArrayPointer)                   \
   V(LoadFunctionPrototype)                      \
@@ -1706,6 +1707,25 @@ class LStoreGlobalGeneric: public LTemplateInstruction<0, 3, 0> {
 };
 
 
+class LLinkObjectInList: public LTemplateInstruction<0, 1, 1> {
+ public:
+  explicit LLinkObjectInList(LOperand* object, LOperand* temp) {
+    inputs_[0] = object;
+    temps_[0] = temp;
+  }
+
+  LOperand* object() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  ExternalReference GetReference(Isolate* isolate);
+
+  DECLARE_CONCRETE_INSTRUCTION(LinkObjectInList, "link-object-in-list")
+  DECLARE_HYDROGEN_ACCESSOR(LinkObjectInList)
+
+  virtual void PrintDataTo(StringStream* stream);
+};
+
+
 class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LLoadContextSlot(LOperand* context) {
index 091a0eb..ca3486f 100644 (file)
@@ -4450,6 +4450,7 @@ ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
 ACCESSORS(TypeSwitchInfo, types, Object, kTypesOffset)
 
 ACCESSORS(AllocationSite, transition_info, Object, kTransitionInfoOffset)
+ACCESSORS(AllocationSite, weak_next, Object, kWeakNextOffset)
 ACCESSORS(AllocationSiteInfo, allocation_site, Object, kAllocationSiteOffset)
 
 ACCESSORS(Script, source, Object, kSourceOffset)
index db324d0..0ed737b 100644 (file)
@@ -1119,6 +1119,10 @@ void TypeSwitchInfo::TypeSwitchInfoPrint(FILE* out) {
 
 void AllocationSite::AllocationSitePrint(FILE* out) {
   HeapObject::PrintHeader(out, "AllocationSite");
+  PrintF(out, " - weak_next: ");
+  weak_next()->ShortPrint(out);
+  PrintF(out, "\n");
+
   PrintF(out, " - transition_info: ");
   if (transition_info()->IsCell()) {
     Cell* cell = Cell::cast(transition_info());
index 612f937..29abbe2 100644 (file)
@@ -185,6 +185,11 @@ void StaticMarkingVisitor<StaticVisitor>::Initialize() {
 
   table_.Register(kVisitNativeContext, &VisitNativeContext);
 
+  table_.Register(kVisitAllocationSite,
+                  &FixedBodyVisitor<StaticVisitor,
+                  AllocationSite::BodyDescriptor,
+                  void>::Visit);
+
   table_.Register(kVisitByteArray, &DataObjectVisitor::Visit);
 
   table_.Register(kVisitFreeSpace, &DataObjectVisitor::Visit);
index 6502209..484bb88 100644 (file)
@@ -182,6 +182,10 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
         case NAME##_TYPE:
       STRUCT_LIST(MAKE_STRUCT_CASE)
 #undef MAKE_STRUCT_CASE
+          if (instance_type == ALLOCATION_SITE_TYPE) {
+            return kVisitAllocationSite;
+          }
+
           return GetVisitorIdForSize(kVisitStruct,
                                      kVisitStructGeneric,
                                      instance_size);
index c2ab45d..de5ad82 100644 (file)
@@ -55,6 +55,7 @@ class StaticVisitorBase : public AllStatic {
   V(FixedArray)               \
   V(FixedDoubleArray)         \
   V(NativeContext)            \
+  V(AllocationSite)           \
   V(DataObject2)              \
   V(DataObject3)              \
   V(DataObject4)              \
index 0c31df3..241da74 100644 (file)
@@ -1706,7 +1706,11 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
         case NAME##_TYPE:
       STRUCT_LIST(MAKE_STRUCT_CASE)
 #undef MAKE_STRUCT_CASE
-      StructBodyDescriptor::IterateBody(this, object_size, v);
+      if (type == ALLOCATION_SITE_TYPE) {
+        AllocationSite::BodyDescriptor::IterateBody(this, v);
+      } else {
+        StructBodyDescriptor::IterateBody(this, object_size, v);
+      }
       break;
     default:
       PrintF("Unknown type: %d\n", type);
index 2cc232c..9530e4d 100644 (file)
@@ -7474,11 +7474,10 @@ enum AllocationSiteMode {
 
 class AllocationSite: public Struct {
  public:
-  static const int kTransitionInfoOffset = HeapObject::kHeaderSize;
-  static const int kSize = kTransitionInfoOffset + kPointerSize;
   static const uint32_t kMaximumArrayBytesToPretransition = 8 * 1024;
 
   DECL_ACCESSORS(transition_info, Object)
+  DECL_ACCESSORS(weak_next, Object)
 
   void Initialize() {
     SetElementsKind(GetInitialFastElementsKind());
@@ -7508,6 +7507,14 @@ class AllocationSite: public Struct {
       ElementsKind boilerplate_elements_kind);
   static inline AllocationSiteMode GetMode(ElementsKind from, ElementsKind to);
 
+  static const int kTransitionInfoOffset = HeapObject::kHeaderSize;
+  static const int kWeakNextOffset = kTransitionInfoOffset + kPointerSize;
+  static const int kSize = kWeakNextOffset + kPointerSize;
+
+  typedef FixedBodyDescriptor<HeapObject::kHeaderSize,
+                              kTransitionInfoOffset + kPointerSize,
+                              kSize> BodyDescriptor;
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(AllocationSite);
 };
index 4e51cd3..ad56d36 100644 (file)
@@ -577,6 +577,10 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
       UNCLASSIFIED,
       62,
       "Heap::NewSpaceAllocationLimitAddress");
+  Add(ExternalReference::allocation_sites_list_address(isolate).address(),
+      UNCLASSIFIED,
+      63,
+      "Heap::allocation_sites_list_address()");
 
   // Add a small set of deopt entry addresses to encoder without generating the
   // deopt table code, which isn't possible at deserialization time.
@@ -587,7 +591,7 @@ void ExternalReferenceTable::PopulateTable(Isolate* isolate) {
         entry,
         Deoptimizer::LAZY,
         Deoptimizer::CALCULATE_ENTRY_ADDRESS);
-    Add(address, LAZY_DEOPTIMIZATION, 63 + entry, "lazy_deopt");
+    Add(address, LAZY_DEOPTIMIZATION, 64 + entry, "lazy_deopt");
   }
 }
 
@@ -690,6 +694,13 @@ void Deserializer::Deserialize() {
   isolate_->heap()->set_array_buffers_list(
       isolate_->heap()->undefined_value());
 
+  // The allocation site list is build during root iteration, but if no sites
+  // were encountered then it needs to be initialized to undefined.
+  if (isolate_->heap()->allocation_sites_list() == Smi::FromInt(0)) {
+    isolate_->heap()->set_allocation_sites_list(
+        isolate_->heap()->undefined_value());
+  }
+
   // Update data pointers to the external strings containing natives sources.
   for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
     Object* source = isolate_->heap()->natives_source_cache()->get(i);
@@ -745,6 +756,16 @@ void Deserializer::VisitPointers(Object** start, Object** end) {
 }
 
 
+void Deserializer::RelinkAllocationSite(AllocationSite* site) {
+  if (isolate_->heap()->allocation_sites_list() == Smi::FromInt(0)) {
+    site->set_weak_next(isolate_->heap()->undefined_value());
+  } else {
+    site->set_weak_next(isolate_->heap()->allocation_sites_list());
+  }
+  isolate_->heap()->set_allocation_sites_list(site);
+}
+
+
 // 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
@@ -754,16 +775,25 @@ void Deserializer::ReadObject(int space_number,
                               Object** write_back) {
   int size = source_->GetInt() << kObjectAlignmentBits;
   Address address = Allocate(space_number, size);
-  *write_back = HeapObject::FromAddress(address);
+  HeapObject* obj = HeapObject::FromAddress(address);
+  *write_back = obj;
   Object** current = reinterpret_cast<Object**>(address);
   Object** limit = current + (size >> kPointerSizeLog2);
   if (FLAG_log_snapshot_positions) {
     LOG(isolate_, SnapshotPositionEvent(address, source_->position()));
   }
   ReadChunk(current, limit, space_number, address);
+
+  // TODO(mvstanton): consider treating the heap()->allocation_sites_list()
+  // as a (weak) root. If this root is relocated correctly,
+  // RelinkAllocationSite() isn't necessary.
+  if (obj->IsAllocationSite()) {
+    RelinkAllocationSite(AllocationSite::cast(obj));
+  }
+
 #ifdef DEBUG
   bool is_codespace = (space_number == CODE_SPACE);
-  ASSERT(HeapObject::FromAddress(address)->IsCode() == is_codespace);
+  ASSERT(obj->IsCode() == is_codespace);
 #endif
 }
 
index a6099af..283c1b7 100644 (file)
@@ -347,6 +347,10 @@ class Deserializer: public SerializerDeserializer {
     UNREACHABLE();
   }
 
+  // Allocation sites are present in the snapshot, and must be linked into
+  // a list at deserialization time.
+  void RelinkAllocationSite(AllocationSite* site);
+
   // Fills in some heap data in an area from start to end (non-inclusive).  The
   // space id is used for the write barrier.  The object_address is the address
   // of the object we are writing into, or NULL if we are not writing into an
index ab51b91..e52dfff 100644 (file)
@@ -2603,6 +2603,16 @@ void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
 }
 
 
+void LCodeGen::DoLinkObjectInList(LLinkObjectInList* instr) {
+  Register object = ToRegister(instr->object());
+  ExternalReference sites_list_address = instr->GetReference(isolate());
+  __ Load(kScratchRegister, sites_list_address);
+  __ movq(FieldOperand(object, instr->hydrogen()->store_field().offset()),
+          kScratchRegister);
+  __ Store(sites_list_address, object);
+}
+
+
 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
   Register context = ToRegister(instr->context());
   Register result = ToRegister(instr->result());
index 945d002..2cec68b 100644 (file)
@@ -275,6 +275,24 @@ void LCallConstantFunction::PrintDataTo(StringStream* stream) {
 }
 
 
+ExternalReference LLinkObjectInList::GetReference(Isolate* isolate) {
+  switch (hydrogen()->known_list()) {
+    case HLinkObjectInList::ALLOCATION_SITE_LIST:
+      return ExternalReference::allocation_sites_list_address(isolate);
+  }
+
+  UNREACHABLE();
+  // Return a dummy value
+  return ExternalReference::isolate_address(isolate);
+}
+
+
+void LLinkObjectInList::PrintDataTo(StringStream* stream) {
+  object()->PrintTo(stream);
+  stream->Add(" offset %d", hydrogen()->store_field().offset());
+}
+
+
 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
   context()->PrintTo(stream);
   stream->Add("[%d]", slot_index());
@@ -2028,6 +2046,13 @@ LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) {
 }
 
 
+LInstruction* LChunkBuilder::DoLinkObjectInList(HLinkObjectInList* instr) {
+  LOperand* object = UseRegister(instr->value());
+  LLinkObjectInList* result = new(zone()) LLinkObjectInList(object);
+  return result;
+}
+
+
 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
   LOperand* context = UseRegisterAtStart(instr->value());
   LInstruction* result =
index 62f65ae..32ee0b9 100644 (file)
@@ -121,6 +121,7 @@ class LCodeGen;
   V(IsUndetectableAndBranch)                    \
   V(Label)                                      \
   V(LazyBailout)                                \
+  V(LinkObjectInList)                           \
   V(LoadContextSlot)                            \
   V(LoadExternalArrayPointer)                   \
   V(LoadFunctionPrototype)                      \
@@ -1620,6 +1621,23 @@ class LStoreGlobalGeneric: public LTemplateInstruction<0, 2, 0> {
 };
 
 
+class LLinkObjectInList: public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LLinkObjectInList(LOperand* object) {
+    inputs_[0] = object;
+  }
+
+  LOperand* object() { return inputs_[0]; }
+
+  ExternalReference GetReference(Isolate* isolate);
+
+  DECLARE_CONCRETE_INSTRUCTION(LinkObjectInList, "link-object-in-list")
+  DECLARE_HYDROGEN_ACCESSOR(LinkObjectInList)
+
+  virtual void PrintDataTo(StringStream* stream);
+};
+
+
 class LLoadContextSlot: public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LLoadContextSlot(LOperand* context) {