Clear next map word when folding allocations into js arrays.
authorhpayer@chromium.org <hpayer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 28 Aug 2013 08:39:43 +0000 (08:39 +0000)
committerhpayer@chromium.org <hpayer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 28 Aug 2013 08:39:43 +0000 (08:39 +0000)
BUG=
R=mstarzinger@chromium.org, mvstanton@chromium.org

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

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

src/heap.cc
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/objects-inl.h
src/objects.h
test/mjsunit/allocation-folding.js

index ad352bc..b1096b3 100644 (file)
@@ -4971,7 +4971,7 @@ MaybeObject* Heap::CopyJSObjectWithAllocationSite(
   int object_size = map->instance_size();
   Object* clone;
 
-  ASSERT(map->CanTrackAllocationSite());
+  ASSERT(AllocationSite::CanTrack(map->instance_type()));
   ASSERT(map->instance_type() == JS_ARRAY_TYPE);
   WriteBarrierMode wb_mode = UPDATE_WRITE_BARRIER;
 
index 7701b9e..0bd7b79 100644 (file)
@@ -3283,8 +3283,9 @@ void HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
 
   // First update the size of the dominator allocate instruction.
   dominator_size = dominator_allocate->size();
-  int32_t dominator_size_constant =
+  int32_t original_object_size =
       HConstant::cast(dominator_size)->GetInteger32Constant();
+  int32_t dominator_size_constant = original_object_size;
   int32_t current_size_constant =
       HConstant::cast(current_size)->GetInteger32Constant();
   int32_t new_dominator_size = dominator_size_constant + current_size_constant;
@@ -3319,9 +3320,19 @@ void HAllocate::HandleSideEffectDominator(GVNFlag side_effect,
 #ifdef VERIFY_HEAP
   if (FLAG_verify_heap && dominator_allocate->IsNewSpaceAllocation()) {
     dominator_allocate->MakePrefillWithFiller();
+  } else {
+    // TODO(hpayer): This is a short-term hack to make allocation mementos
+    // work again in new space.
+    ClearNextMapWord(original_object_size);
   }
+#else
+  // TODO(hpayer): This is a short-term hack to make allocation mementos
+  // work again in new space.
+  ClearNextMapWord(original_object_size);
 #endif
 
+  dominator_allocate->clear_next_map_word_ = clear_next_map_word_;
+
   // After that replace the dominated allocate instruction.
   HInstruction* dominated_allocate_instr =
       HInnerAllocatedObject::New(zone,
@@ -3457,6 +3468,19 @@ void HAllocate::CreateFreeSpaceFiller(int32_t free_space_size) {
 }
 
 
+void HAllocate::ClearNextMapWord(int offset) {
+  if (clear_next_map_word_) {
+    Zone* zone = block()->zone();
+    HObjectAccess access = HObjectAccess::ForJSObjectOffset(offset);
+    HStoreNamedField* clear_next_map =
+        HStoreNamedField::New(zone, context(), this, access,
+            block()->graph()->GetConstantNull());
+    clear_next_map->ClearAllSideEffects();
+    clear_next_map->InsertAfter(this);
+  }
+}
+
+
 void HAllocate::PrintDataTo(StringStream* stream) {
   size()->PrintNameTo(stream);
   stream->Add(" (");
index 59db99c..8f79edf 100644 (file)
@@ -5166,7 +5166,8 @@ class HAllocate V8_FINAL : public HTemplateInstruction<2> {
             InstanceType instance_type)
       : HTemplateInstruction<2>(type),
         dominating_allocate_(NULL),
-        filler_free_space_size_(NULL) {
+        filler_free_space_size_(NULL),
+        clear_next_map_word_(false) {
     SetOperandAt(0, context);
     SetOperandAt(1, size);
     set_representation(Representation::Tagged());
@@ -5188,6 +5189,8 @@ class HAllocate V8_FINAL : public HTemplateInstruction<2> {
     if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
       flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
     }
+    clear_next_map_word_ = pretenure_flag == NOT_TENURED &&
+        AllocationSite::CanTrack(instance_type);
   }
 
   void UpdateSize(HValue* size) {
@@ -5207,10 +5210,13 @@ class HAllocate V8_FINAL : public HTemplateInstruction<2> {
             allocate->IsOldPointerSpaceAllocation());
   }
 
+  void ClearNextMapWord(int offset);
+
   Flags flags_;
   Handle<Map> known_initial_map_;
   HAllocate* dominating_allocate_;
   HStoreNamedField* filler_free_space_size_;
+  bool clear_next_map_word_;
 };
 
 
index 83f91de..4847f1a 100644 (file)
@@ -8329,7 +8329,7 @@ void HOptimizedGraphBuilder::BuildEmitDeepCopy(
     int* data_offset,
     AllocationSiteMode mode) {
   bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
-      boilerplate_object->map()->CanTrackAllocationSite();
+      AllocationSite::CanTrack(boilerplate_object->map()->instance_type());
 
   // If using allocation sites, then the payload on the site should already
   // be filled in as a valid (boilerplate) array.
@@ -8385,7 +8385,7 @@ void HOptimizedGraphBuilder::BuildEmitDeepCopy(
 
   // Create allocation site info.
   if (mode == TRACK_ALLOCATION_SITE &&
-      boilerplate_object->map()->CanTrackAllocationSite()) {
+      AllocationSite::CanTrack(boilerplate_object->map()->instance_type())) {
     elements_offset += AllocationMemento::kSize;
     *offset += AllocationMemento::kSize;
     BuildCreateAllocationMemento(target, JSArray::kSize, allocation_site);
index 13ae603..b165ad4 100644 (file)
@@ -1312,7 +1312,7 @@ void JSObject::ValidateElements() {
 
 
 bool JSObject::ShouldTrackAllocationInfo() {
-  if (map()->CanTrackAllocationSite()) {
+  if (AllocationSite::CanTrack(map()->instance_type())) {
     if (!IsJSArray()) {
       return true;
     }
@@ -1349,6 +1349,11 @@ AllocationSiteMode AllocationSite::GetMode(ElementsKind from,
 }
 
 
+inline bool AllocationSite::CanTrack(InstanceType type) {
+  return type == JS_ARRAY_TYPE;
+}
+
+
 MaybeObject* JSObject::EnsureCanContainHeapObjectElements() {
   ValidateElements();
   ElementsKind elements_kind = map()->elements_kind();
@@ -3593,11 +3598,6 @@ Code::Flags Code::flags() {
 }
 
 
-inline bool Map::CanTrackAllocationSite() {
-  return instance_type() == JS_ARRAY_TYPE;
-}
-
-
 void Map::set_owns_descriptors(bool is_shared) {
   set_bit_field3(OwnsDescriptors::update(bit_field3(), is_shared));
 }
index 4685dc7..988f1ab 100644 (file)
@@ -5776,7 +5776,6 @@ class Map: public HeapObject {
     set_bit_field3(EnumLengthBits::update(bit_field3(), length));
   }
 
-  inline bool CanTrackAllocationSite();
   inline bool owns_descriptors();
   inline void set_owns_descriptors(bool is_shared);
   inline bool is_observed();
@@ -7845,6 +7844,7 @@ class AllocationSite: public Struct {
   static inline AllocationSiteMode GetMode(
       ElementsKind boilerplate_elements_kind);
   static inline AllocationSiteMode GetMode(ElementsKind from, ElementsKind to);
+  static inline bool CanTrack(InstanceType type);
 
   static const int kTransitionInfoOffset = HeapObject::kHeaderSize;
   static const int kWeakNextOffset = kTransitionInfoOffset + kPointerSize;
index fe5fa6d..ec07392 100644 (file)
@@ -56,7 +56,7 @@ function doubles() {
 
 doubles(); doubles(); doubles();
 %OptimizeFunctionOnNextCall(doubles);
-var result = doubles();
+result = doubles();
 
 gc();
 
@@ -72,8 +72,31 @@ function doubles_int() {
 
 doubles_int(); doubles_int(); doubles_int();
 %OptimizeFunctionOnNextCall(doubles_int);
-var result = doubles_int();
+result = doubles_int();
 
 gc();
 
 assertEquals(result[1], 3.1);
+
+// Test allocation folding over a branch.
+
+function branch_int(left) {
+  var elem1 = [1, 2];
+  var elem2;
+  if (left) {
+    elem2 = [3, 4];
+  } else {
+    elem2 = [5, 6];
+  }
+  return elem2;
+}
+
+branch_int(1); branch_int(1); branch_int(1);
+%OptimizeFunctionOnNextCall(branch_int);
+result = branch_int(1);
+var result2 = branch_int(0);
+
+gc();
+
+assertEquals(result[1], 4);
+assertEquals(result2[1], 6);