Merged r14169 into 3.17 branch.
Fix worst-case behavior of MergeRemovableSimulates().
BUG=v8:2612
R=jkummerow@chromium.org
Review URL: https://chromiumcodereview.appspot.com/14472003
git-svn-id: http://v8.googlecode.com/svn/branches/3.17@14418 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index aef227f..0f42e40 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -579,7 +579,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();
}
}
@@ -1749,20 +1749,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();
}
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index d2b3fc5..ea54621 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -1696,7 +1696,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)
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 4d9bc9b..ef5de6b 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -2971,10 +2971,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;
@@ -2985,33 +2986,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()) {
+ 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());
}
- if (!current_simulate->is_candidate_for_removal()) {
- continue;
- }
- 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);
}
}
}
diff --git a/src/version.cc b/src/version.cc
index f7fb1ee..f53a8a4 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -35,7 +35,7 @@
#define MAJOR_VERSION 3
#define MINOR_VERSION 17
#define BUILD_NUMBER 6
-#define PATCH_LEVEL 9
+#define PATCH_LEVEL 10
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index 26c8359..2dd43d9 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -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
##############################################################################
# These use a built-in that's only present in debug mode. They take
diff --git a/test/mjsunit/regress/regress-2612.js b/test/mjsunit/regress/regress-2612.js
new file mode 100644
index 0000000..06db077
--- /dev/null
+++ b/test/mjsunit/regress/regress-2612.js
@@ -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();
+