Reviewers: Toon Verwaest,

Message:
Hi Toon, here is the issue we worked on, thanks!
--Michael

Description:
Fix for V8 issue 2795: Check fails with deopt for mjsunit/array-store-and-grow
(https://code.google.com/p/v8/issues/detail?id=2795)

The reason is when allocating and building arrays in hydrogen we need to ensure we do any int32-to-smi conversions BEFORE the allocation. These conversions can at least theoretically deoptimize. If this happens before all the fields of the
newly allocated object are filled in, we will have a corrupted heap.

BUG=

Please review this at https://codereview.chromium.org/20726002/

SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge

Affected files:
  M src/hydrogen-instructions.h
  M src/hydrogen.cc


Index: src/hydrogen-instructions.h
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index bf59159164c53b4e41ae52ee2d48d76625017a1b..e6a618375a0db024bb7d25e5cb71d7f8404a3843 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -5583,9 +5583,11 @@ class HObjectAccess {

   static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
     return HObjectAccess(
-        kArrayLengths, JSArray::kLengthOffset,
-        IsFastElementsKind(elements_kind) && FLAG_track_fields ?
-        Representation::Smi() : Representation::Tagged());
+        kArrayLengths,
+        JSArray::kLengthOffset,
+        IsFastElementsKind(elements_kind) &&
+            FLAG_track_fields
+                ? Representation::Smi() : Representation::Tagged());
   }

   static HObjectAccess ForAllocationSiteTransitionInfo() {
@@ -5598,9 +5600,9 @@ class HObjectAccess {

   static HObjectAccess ForFixedArrayLength() {
     return HObjectAccess(
-        kArrayLengths, FixedArray::kLengthOffset,
-        FLAG_track_fields ?
-        Representation::Smi() : Representation::Tagged());
+        kArrayLengths,
+        FixedArray::kLengthOffset,
+ FLAG_track_fields ? Representation::Smi() : Representation::Tagged());
   }

   static HObjectAccess ForPropertiesPointer() {
Index: src/hydrogen.cc
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 853c0c0aafd321cb8b7163403a09cd5daeedda04..0433951a678a26f50c6a9a285eb0d530ae78de37 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -1078,8 +1078,16 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object,

   HValue* context = environment()->LookupContext();

-  HValue* new_capacity = BuildNewElementsCapacity(context, key);
+ HValue* max_gap = Add<HConstant>(static_cast<int32_t>(JSObject::kMaxGap));
+  HValue* max_capacity = AddInstruction(
+      HAdd::New(zone, context, current_capacity, max_gap));
+  IfBuilder key_checker(this);
+  key_checker.If<HCompareNumericAndBranch>(key, max_capacity, Token::LT);
+  key_checker.Then();
+  key_checker.ElseDeopt();
+  key_checker.End();

+  HValue* new_capacity = BuildNewElementsCapacity(context, key);
   HValue* new_elements = BuildGrowElementsCapacity(object, elements,
                                                    kind, kind, length,
                                                    new_capacity);
@@ -1337,6 +1345,9 @@ HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader(
     HValue* context,
     ElementsKind kind,
     HValue* capacity) {
+  // The HForceRepresentation is to prevent possible deopt on int-smi
+  // conversion after allocation but before the new object fields are set.
+  capacity = Add<HForceRepresentation>(capacity, Representation::Smi());
   HValue* new_elements = BuildAllocateElements(context, kind, capacity);
   BuildInitializeElementsHeader(new_elements, kind, capacity);
   return new_elements;
@@ -1474,7 +1485,6 @@ HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* context,
   HValue* half_old_capacity =
       AddInstruction(HShr::New(zone, context, old_capacity,
                                graph_->GetConstant1()));
-  half_old_capacity->ClearFlag(HValue::kCanOverflow);

   HValue* new_capacity = AddInstruction(
       HAdd::New(zone, context, half_old_capacity, old_capacity));
@@ -1497,8 +1507,6 @@ void HGraphBuilder::BuildNewSpaceArrayCheck(HValue* length, ElementsKind kind) {
   int max_size = heap->MaxRegularSpaceAllocationSize() / element_size;
   max_size -= JSArray::kSize / element_size;
   HConstant* max_size_constant = Add<HConstant>(max_size);
-  // Since we're forcing Integer32 representation for this HBoundsCheck,
-  // there's no need to Smi-check the index.
   Add<HBoundsCheck>(length, max_size_constant);
 }

@@ -1927,6 +1935,14 @@ HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes,
                                                      bool fill_with_hole) {
   HValue* context = builder()->environment()->LookupContext();

+ // These HForceRepresentations are because we store these as fields in the
+  // objects we construct, and an int32-to-smi HChange could deopt. Accept
+  // the deopt possibility now, before allocation occurs.
+  capacity = builder()->Add<HForceRepresentation>(capacity,
+                                                  Representation::Smi());
+  length_field = builder()->Add<HForceRepresentation>(length_field,
+ Representation::Smi());
+
   // Allocate (dealing with failure appropriately)
   HAllocate::Flags flags = HAllocate::DefaultFlags(kind_);
   HAllocate* new_object = builder()->Add<HAllocate>(context, size_in_bytes,


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to