Revision: 14169
Author:   [email protected]
Date:     Mon Apr  8 10:37:22 2013
Log:      Fix worst-case behavior of MergeRemovableSimulates().

Currently, when a long series of removable simulates are merged, we do
this by merging them one by one as we find them.  As we merge the value
value lists of the simulates, those lists snowball so that we get a
quadratic complexity wrt runtime and memory consumption.

Instead, we gather simulates that need to be merged, and merge them
backwards starting from the last simulate.

[email protected]
BUG=v8:2612

Review URL: https://chromiumcodereview.appspot.com/13649003
http://code.google.com/p/v8/source/detail?r=14169

Added:
 /branches/bleeding_edge/test/mjsunit/regress/regress-2612.js
Modified:
 /branches/bleeding_edge/src/hydrogen-instructions.cc
 /branches/bleeding_edge/src/hydrogen-instructions.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/test/mjsunit/mjsunit.status

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/regress/regress-2612.js Mon Apr 8 10:37:22 2013
@@ -0,0 +1,76 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --nodead-code-elimination
+// Flags: --nofold-constants --nouse-gvn
+
+// Create a function to get a long series of removable simulates.
+// f() {
+//   var _0 = <random>, _1 = <random>, ... _1000 = <random>,
+//   _1001 = <random var> + <random var>,
+//   _1002 = <random var> + <random var>,
+//   ...
+//   _99999 = <random var> + <random var>,
+//   x = 1;
+//   return _0;
+// }
+
+var seed = 1;
+
+function rand() {
+  seed = seed * 171 % 1337 + 17;
+  return (seed % 1000) / 1000;
+}
+
+function randi(max) {
+  seed = seed * 131 % 1773 + 13;
+  return seed % max;
+}
+
+function varname(i) {
+  return "_" + i;
+}
+
+var source = "var ";
+
+for (var i = 0; i < 1000; i++) {
+  source += [varname(i), "=", rand(), ","].join("");
+}
+
+for (var i = 1000; i < 100000; i++) {
+  source += [varname(i), "=",
+             varname(randi(i)), "+",
+             varname(randi(i)), ","].join("");
+}
+
+source += "x=1; return _0;"
+var f = new Function(source);
+
+f();
+%OptimizeFunctionOnNextCall(f);
+f();
+
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Wed Apr 3 09:25:24 2013 +++ /branches/bleeding_edge/src/hydrogen-instructions.cc Mon Apr 8 10:37:22 2013
@@ -685,7 +685,7 @@
     HValue* operand = OperandAt(i);
     if (operand == NULL) continue;
     HUseListNode* first = operand->use_list_;
-    if (first != NULL && first->value() == this && first->index() == i) {
+    if (first != NULL && first->value()->CheckFlag(kIsDead)) {
       operand->use_list_ = first->tail();
     }
   }
@@ -1980,20 +1980,25 @@
 }


-void HSimulate::MergeInto(HSimulate* other) {
-  for (int i = 0; i < values_.length(); ++i) {
-    HValue* value = values_[i];
-    if (HasAssignedIndexAt(i)) {
-      other->AddAssignedValue(GetAssignedIndexAt(i), value);
-    } else {
-      if (other->pop_count_ > 0) {
-        other->pop_count_--;
+void HSimulate::MergeWith(ZoneList<HSimulate*>* list) {
+  while (!list->is_empty()) {
+    HSimulate* from = list->RemoveLast();
+    ZoneList<HValue*>* from_values = &from->values_;
+    for (int i = 0; i < from_values->length(); ++i) {
+      if (from->HasAssignedIndexAt(i)) {
+        AddAssignedValue(from->GetAssignedIndexAt(i),
+                         from_values->at(i));
       } else {
-        other->AddPushedValue(value);
+        if (pop_count_ > 0) {
+          pop_count_--;
+        } else {
+          AddPushedValue(from_values->at(i));
+        }
       }
     }
+    pop_count_ += from->pop_count_;
+    from->DeleteAndReplaceWith(NULL);
   }
-  other->pop_count_ += pop_count();
 }


=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Wed Apr 3 09:25:24 2013 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Mon Apr 8 10:37:22 2013
@@ -1830,7 +1830,7 @@
     return Representation::None();
   }

-  void MergeInto(HSimulate* other);
+  void MergeWith(ZoneList<HSimulate*>* list);
bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; }

   DECLARE_CONCRETE_INSTRUCTION(Simulate)
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Fri Apr  5 06:01:06 2013
+++ /branches/bleeding_edge/src/hydrogen.cc     Mon Apr  8 10:37:22 2013
@@ -3427,10 +3427,11 @@


 void HGraph::MergeRemovableSimulates() {
+  ZoneList<HSimulate*> mergelist(2, zone());
   for (int i = 0; i < blocks()->length(); ++i) {
     HBasicBlock* block = blocks()->at(i);
-    // Always reset the folding candidate at the start of a block.
-    HSimulate* folding_candidate = NULL;
+    // Make sure the merge list is empty at the start of a block.
+    ASSERT(mergelist.is_empty());
     // Nasty heuristic: Never remove the first simulate in a block. This
     // just so happens to have a beneficial effect on register allocation.
     bool first = true;
@@ -3441,33 +3442,38 @@
         // in the outer environment.
         // (Before each HEnterInlined, there is a non-foldable HSimulate
         // anyway, so we get the barrier in the other direction for free.)
-        if (folding_candidate != NULL) {
-          folding_candidate->DeleteAndReplaceWith(NULL);
+        // Simply remove all accumulated simulates without merging.  This
+        // is safe because simulates after instructions with side effects
+        // are never added to the merge list.
+        while (!mergelist.is_empty()) {
+          mergelist.RemoveLast()->DeleteAndReplaceWith(NULL);
         }
-        folding_candidate = NULL;
         continue;
       }
-      // If we have an HSimulate and a candidate, perform the folding.
+      // Skip the non-simulates and the first simulate.
       if (!current->IsSimulate()) continue;
       if (first) {
         first = false;
         continue;
       }
       HSimulate* current_simulate = HSimulate::cast(current);
-      if (folding_candidate != NULL) {
-        folding_candidate->MergeInto(current_simulate);
-        folding_candidate->DeleteAndReplaceWith(NULL);
-        folding_candidate = NULL;
-      }
-      // Check if the current simulate is a candidate for folding.
-      if (current_simulate->previous()->HasObservableSideEffects() &&
-          !current_simulate->next()->IsSimulate()) {
-        continue;
-      }
-      if (!current_simulate->is_candidate_for_removal()) {
+      if ((current_simulate->previous()->HasObservableSideEffects() &&
+           !current_simulate->next()->IsSimulate()) ||
+          !current_simulate->is_candidate_for_removal()) {
+        // This simulate is not suitable for folding.
+        // Fold the ones accumulated so far.
+        current_simulate->MergeWith(&mergelist);
         continue;
+      } else {
+        // Accumulate this simulate for folding later on.
+        mergelist.Add(current_simulate, zone());
       }
-      folding_candidate = current_simulate;
+    }
+
+    if (!mergelist.is_empty()) {
+      // Merge the accumulated simulates at the end of the block.
+      HSimulate* last = mergelist.RemoveLast();
+      last->MergeWith(&mergelist);
     }
   }
 }
=======================================
--- /branches/bleeding_edge/test/mjsunit/mjsunit.status Thu Apr 4 07:46:18 2013 +++ /branches/bleeding_edge/test/mjsunit/mjsunit.status Mon Apr 8 10:37:22 2013
@@ -49,6 +49,7 @@
 compiler/regress-funcaller: PASS, SKIP if $mode == debug
 regress/regress-2318: PASS, SKIP if $mode == debug
 regress/regress-create-exception: PASS, SKIP if $mode == debug
+regress/regress-2612: PASS, SKIP if $mode == debug

##############################################################################
 # Too slow in debug mode for GC stress mode.

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