Revision: 10651
Author:   [email protected]
Date:     Thu Feb  9 00:58:19 2012
Log:      Improve GVN handling of ElementTransitions.

BUG=
TEST=

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

Added:
 /branches/bleeding_edge/test/mjsunit/elements-transition-hoisting.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/src/hydrogen.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/elements-transition-hoisting.js Thu Feb 9 00:58:19 2012
@@ -0,0 +1,168 @@
+// Copyright 2011 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 --smi-only-arrays
+
+// Ensure that ElementsKind transitions in various situations are hoisted (or +// not hoisted) correctly, don't change the semantics programs and don't trigger
+// deopt through hoisting in important situations.
+
+support_smi_only_arrays = %HasFastSmiOnlyElements(new Array(1,2,3,4,5,6));
+
+if (support_smi_only_arrays) {
+  print("Tests include smi-only arrays.");
+} else {
+  print("Tests do NOT include smi-only arrays.");
+}
+
+if (support_smi_only_arrays) {
+ // Make sure that a simple elements array transitions inside a loop before + // stores to an array gets hoisted in a way that doesn't generate a deopt in
+  // simple cases.}
+  function testDoubleConversion4(a) {
+    var object = new Object();
+    a[0] = 0;
+    var count = 3;
+    do {
+      a[0] = object;
+    } while (--count > 0);
+  }
+
+  testDoubleConversion4(new Array(5));
+  %OptimizeFunctionOnNextCall(testDoubleConversion4);
+  testDoubleConversion4(new Array(5));
+  testDoubleConversion4(new Array(5));
+  assertTrue(2 != %GetOptimizationStatus(testDoubleConversion4));
+
+  // Make sure that non-element related map checks that are not preceded by
+ // transitions in a loop still get hoisted in a way that doesn't generate a
+  // deopt in simple cases.
+  function testExactMapHoisting(a) {
+    var object = new Object();
+    a.foo = 0;
+    a[0] = 0;
+    a[1] = 1;
+    var count = 3;
+    do {
+      a.foo = object; // This map check should be hoistable
+      a[1] = object;
+      result = a.foo == object && a[1] == object;
+    } while (--count > 0);
+  }
+
+  testExactMapHoisting(new Array(5));
+  %OptimizeFunctionOnNextCall(testExactMapHoisting);
+  testExactMapHoisting(new Array(5));
+  testExactMapHoisting(new Array(5));
+  assertTrue(2 != %GetOptimizationStatus(testExactMapHoisting));
+
+ // Make sure that non-element related map checks do NOT get hoisted if they + // depend on an elements transition before them and it's not possible to hoist
+  // that transition.
+  function testExactMapHoisting2(a) {
+    var object = new Object();
+    a.foo = 0;
+    a[0] = 0;
+    a[1] = 1;
+    var count = 3;
+    do {
+      if (a.bar === undefined) {
+        a[1] = 2.5;
+      }
+      a.foo = object; // This map check should NOT be hoistable because it
+ // includes a check for the FAST_ELEMENTS map as well as
+                      // the FAST_DOUBLE_ELEMENTS map, which depends on the
+                      // double transition above in the if, which cannot be
+                      // hoisted.
+    } while (--count > 0);
+  }
+
+  testExactMapHoisting2(new Array(5));
+  %OptimizeFunctionOnNextCall(testExactMapHoisting2);
+  testExactMapHoisting2(new Array(5));
+  testExactMapHoisting2(new Array(5));
+  assertTrue(2 != %GetOptimizationStatus(testExactMapHoisting2));
+
+ // Make sure that non-element related map checks do get hoisted if they use + // the transitioned map for the check and all transitions that they depend
+  // upon can hoisted, too.
+  function testExactMapHoisting3(a) {
+    var object = new Object();
+    a.foo = 0;
+    a[0] = 0;
+    a[1] = 1;
+    var count = 3;
+    do {
+      a[1] = 2.5;
+ a.foo = object; // This map check should be hoistable because all elements
+                      // transitions in the loop can also be hoisted.
+    } while (--count > 0);
+  }
+
+  var add_transition = new Array(5);
+  add_transition.foo = 0;
+ add_transition[0] = new Object(); // For FAST_ELEMENT transition to be created
+  testExactMapHoisting3(new Array(5));
+  %OptimizeFunctionOnNextCall(testExactMapHoisting3);
+  testExactMapHoisting3(new Array(5));
+  testExactMapHoisting3(new Array(5));
+  assertTrue(2 != %GetOptimizationStatus(testExactMapHoisting3));
+
+  function testDominatingTransitionHoisting1(a) {
+    var object = new Object();
+    a[0] = 0;
+    var count = 3;
+    do {
+      if (a.baz != true) {
+        a[1] = 2.5;
+      }
+      a[0] = object;
+    } while (--count > 3);
+  }
+
+  testDominatingTransitionHoisting1(new Array(5));
+  %OptimizeFunctionOnNextCall(testDominatingTransitionHoisting1);
+  testDominatingTransitionHoisting1(new Array(5));
+  testDominatingTransitionHoisting1(new Array(5));
+ assertTrue(2 != %GetOptimizationStatus(testDominatingTransitionHoisting1));
+
+  function testHoistingWithSideEffect(a) {
+    var object = new Object();
+    a[0] = 0;
+    var count = 3;
+    do {
+      assertTrue(true);
+      a[0] = object;
+    } while (--count > 3);
+  }
+
+  testHoistingWithSideEffect(new Array(5));
+  %OptimizeFunctionOnNextCall(testHoistingWithSideEffect);
+  testHoistingWithSideEffect(new Array(5));
+  testHoistingWithSideEffect(new Array(5));
+  assertTrue(2 != %GetOptimizationStatus(testHoistingWithSideEffect));
+}
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Wed Feb 1 00:49:18 2012 +++ /branches/bleeding_edge/src/hydrogen-instructions.cc Thu Feb 9 00:58:19 2012
@@ -893,6 +893,13 @@
 void HCheckMap::PrintDataTo(StringStream* stream) {
   value()->PrintNameTo(stream);
   stream->Add(" %p", *map());
+  if (mode() == REQUIRE_EXACT_MAP) {
+    stream->Add(" [EXACT]");
+  } else if (!has_element_transitions_) {
+    stream->Add(" [EXACT*]");
+  } else {
+    stream->Add(" [MATCH ELEMENTS]");
+  }
 }


=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Wed Feb 1 00:49:18 2012 +++ /branches/bleeding_edge/src/hydrogen-instructions.h Thu Feb 9 00:58:19 2012
@@ -186,6 +186,7 @@
   V(InobjectFields)                            \
   V(BackingStoreFields)                        \
   V(ElementsKind)                              \
+  V(ElementsPointer)                           \
   V(ArrayElements)                             \
   V(DoubleArrayElements)                       \
   V(SpecializedArrayElements)                  \
@@ -645,6 +646,18 @@
   bool HasObservableSideEffects() const {
     return gvn_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
   }
+
+  GVNFlagSet DependsOnFlags() const {
+    GVNFlagSet result = gvn_flags_;
+    result.Intersect(AllDependsOnFlagSet());
+    return result;
+  }
+
+  GVNFlagSet SideEffectFlags() const {
+    GVNFlagSet result = gvn_flags_;
+    result.Intersect(AllSideEffectsFlagSet());
+    return result;
+  }

   GVNFlagSet ChangesFlags() const {
     GVNFlagSet result = gvn_flags_;
@@ -721,6 +734,15 @@
     ASSERT(representation_.IsNone() && !r.IsNone());
     representation_ = r;
   }
+
+  static GVNFlagSet AllDependsOnFlagSet() {
+    GVNFlagSet result;
+    // Create changes mask.
+#define ADD_FLAG(type) result.Add(kDependsOn##type);
+  GVN_FLAG_LIST(ADD_FLAG)
+#undef ADD_FLAG
+    return result;
+  }

   static GVNFlagSet AllChangesFlagSet() {
     GVNFlagSet result;
@@ -743,6 +765,8 @@
   static GVNFlagSet AllObservableSideEffectsFlagSet() {
     GVNFlagSet result = AllChangesFlagSet();
     result.Remove(kChangesElementsKind);
+    result.Remove(kChangesElementsPointer);
+    result.Remove(kChangesMaps);
     return result;
   }

@@ -1920,8 +1944,7 @@
   explicit HLoadElements(HValue* value) : HUnaryOperation(value) {
     set_representation(Representation::Tagged());
     SetFlag(kUseGVN);
-    SetGVNFlag(kDependsOnMaps);
-    SetGVNFlag(kDependsOnElementsKind);
+    SetGVNFlag(kDependsOnElementsPointer);
   }

   virtual Representation RequiredInputRepresentation(int index) {
@@ -1972,6 +1995,11 @@
     set_representation(Representation::Tagged());
     SetFlag(kUseGVN);
     SetGVNFlag(kDependsOnMaps);
+ // If the map to check doesn't have the untransitioned elements, it must not
+    // be hoisted above TransitionElements instructions.
+    if (mode == REQUIRE_EXACT_MAP || !map->has_fast_smi_only_elements()) {
+      SetGVNFlag(kDependsOnElementsKind);
+    }
     has_element_transitions_ =
map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL) != NULL ||
         map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL) != NULL;
@@ -4135,7 +4163,17 @@
         transitioned_map_(transitioned_map) {
     SetOperandAt(0, object);
     SetFlag(kUseGVN);
+    SetGVNFlag(kDependsOnMaps);
     SetGVNFlag(kChangesElementsKind);
+    if (original_map->has_fast_double_elements()) {
+      SetGVNFlag(kChangesElementsPointer);
+      SetGVNFlag(kDependsOnElementsPointer);
+      SetGVNFlag(kDependsOnDoubleArrayElements);
+    } else if (transitioned_map->has_fast_double_elements()) {
+      SetGVNFlag(kChangesElementsPointer);
+      SetGVNFlag(kDependsOnElementsPointer);
+      SetGVNFlag(kDependsOnArrayElements);
+    }
     set_representation(Representation::Tagged());
   }

=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Wed Feb  8 07:39:41 2012
+++ /branches/bleeding_edge/src/hydrogen.cc     Thu Feb  9 00:58:19 2012
@@ -70,7 +70,8 @@
       deleted_phis_(4),
       parent_loop_header_(NULL),
       is_inline_return_target_(false),
-      is_deoptimizing_(false) { }
+      is_deoptimizing_(false),
+      dominates_loop_successors_(false) { }


 void HBasicBlock::AttachLoopInformation() {
@@ -313,6 +314,62 @@
     }
   }
 }
+
+
+void HBasicBlock::AssignLoopSuccessorDominators() {
+  // Mark blocks that dominate all subsequent reachable blocks inside their
+ // loop. Exploit the fact that blocks are sorted in reverse post order. When
+  // the loop is visited in increasing block id order, if the number of
+ // non-loop-exiting successor edges at the dominator_candidate block doesn't + // exceed the number of previously encountered predecessor edges, there is no
+  // path from the loop header to any block with higher id that doesn't go
+  // through the dominator_candidate block. In this case, the
+ // dominator_candidate block is guaranteed to dominate all blocks reachable
+  // from it with higher ids.
+  HBasicBlock* last = loop_information()->GetLastBackEdge();
+  int outstanding_successors = 1;  // one edge from the pre-header
+  // Header always dominates everything.
+  MarkAsLoopSuccessorDominator();
+  for (int j = block_id(); j <= last->block_id(); ++j) {
+    HBasicBlock* dominator_candidate = graph_->blocks()->at(j);
+    for (HPredecessorIterator it(dominator_candidate); !it.Done();
+         it.Advance()) {
+      HBasicBlock* predecessor = it.Current();
+      // Don't count back edges.
+      if (predecessor->block_id() < dominator_candidate->block_id()) {
+        outstanding_successors--;
+      }
+    }
+
+ // If more successors than predecessors have been seen in the loop up to
+    // now, it's not possible to guarantee that the current block dominates
+ // all of the blocks with higher IDs. In this case, assume conservatively + // that those paths through loop that don't go through the current block
+    // contain all of the loop's dependencies. Also be careful to record
+    // dominator information about the current loop that's being processed,
+    // and not nested loops, which will be processed when
+    // AssignLoopSuccessorDominators gets called on their header.
+    ASSERT(outstanding_successors >= 0);
+ HBasicBlock* parent_loop_header = dominator_candidate->parent_loop_header();
+    if (outstanding_successors == 0 &&
+ (parent_loop_header == this && !dominator_candidate->IsLoopHeader())) {
+      dominator_candidate->MarkAsLoopSuccessorDominator();
+    }
+    HControlInstruction* end = dominator_candidate->end();
+    for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
+      HBasicBlock* successor = it.Current();
+ // Only count successors that remain inside the loop and don't loop back
+      // to a loop header.
+      if (successor->block_id() > dominator_candidate->block_id() &&
+          successor->block_id() <= last->block_id()) {
+        // Backwards edges must land on loop headers.
+        ASSERT(successor->block_id() > dominator_candidate->block_id() ||
+               successor->IsLoopHeader());
+        outstanding_successors++;
+      }
+    }
+  }
+}


 int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const {
@@ -750,10 +807,12 @@
 void HGraph::AssignDominators() {
   HPhase phase("Assign dominators", this);
   for (int i = 0; i < blocks_.length(); ++i) {
-    if (blocks_[i]->IsLoopHeader()) {
+    HBasicBlock* block = blocks_[i];
+    if (block->IsLoopHeader()) {
// Only the first predecessor of a loop header is from outside the loop. // All others are back edges, and thus cannot dominate the loop header. - blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->first());
+      block->AssignCommonDominator(block->predecessors()->first());
+      block->AssignLoopSuccessorDominators();
     } else {
       for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) {
blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j));
@@ -1371,7 +1430,8 @@
   void LoopInvariantCodeMotion();
   void ProcessLoopBlock(HBasicBlock* block,
                         HBasicBlock* before_loop,
-                        GVNFlagSet loop_kills);
+                        GVNFlagSet loop_kills,
+                        GVNFlagSet* accumulated_first_time_depends);
   bool AllowCodeMotion();
   bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header);

@@ -1396,6 +1456,7 @@


 bool HGlobalValueNumberer::Analyze() {
+  removed_side_effects_ = false;
   ComputeBlockSideEffects();
   if (FLAG_loop_invariant_code_motion) {
     LoopInvariantCodeMotion();
@@ -1407,6 +1468,12 @@


 void HGlobalValueNumberer::ComputeBlockSideEffects() {
+  // The Analyze phase of GVN can be called multiple times. Clear loop side
+ // effects before computing them to erase the contents from previous Analyze
+  // passes.
+  for (int i = 0; i < loop_side_effects_.length(); ++i) {
+    loop_side_effects_[i].RemoveAll();
+  }
   for (int i = graph_->blocks()->length() - 1; i >= 0; --i) {
     // Compute side effects for the block.
     HBasicBlock* block = graph_->blocks()->at(i);
@@ -1444,18 +1511,22 @@
                block->block_id(),
                side_effects.ToIntegral());

+      GVNFlagSet accumulated_first_time_depends;
       HBasicBlock* last = block->loop_information()->GetLastBackEdge();
       for (int j = block->block_id(); j <= last->block_id(); ++j) {
-        ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects);
+        ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects,
+                         &accumulated_first_time_depends);
       }
     }
   }
 }


-void HGlobalValueNumberer::ProcessLoopBlock(HBasicBlock* block,
-                                            HBasicBlock* loop_header,
-                                            GVNFlagSet loop_kills) {
+void HGlobalValueNumberer::ProcessLoopBlock(
+    HBasicBlock* block,
+    HBasicBlock* loop_header,
+    GVNFlagSet loop_kills,
+    GVNFlagSet* accumulated_first_time_depends) {
   HBasicBlock* pre_header = loop_header->predecessors()->at(0);
GVNFlagSet depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills);
   TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n",
@@ -1464,25 +1535,65 @@
   HInstruction* instr = block->first();
   while (instr != NULL) {
     HInstruction* next = instr->next();
-    if (instr->CheckFlag(HValue::kUseGVN) &&
-        !instr->gvn_flags().ContainsAnyOf(depends_flags)) {
-      TraceGVN("Checking instruction %d (%s)\n",
+    bool hoisted = false;
+    if (instr->CheckFlag(HValue::kUseGVN)) {
+      TraceGVN("Checking instruction %d (%s) instruction GVN flags 0x%X, "
+               "loop kills 0x%X\n",
                instr->id(),
-               instr->Mnemonic());
-      bool inputs_loop_invariant = true;
-      for (int i = 0; i < instr->OperandCount(); ++i) {
-        if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) {
-          inputs_loop_invariant = false;
-        }
+               instr->Mnemonic(),
+               instr->gvn_flags().ToIntegral(),
+               depends_flags.ToIntegral());
+      bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags);
+      if (!can_hoist && instr->IsTransitionElementsKind()) {
+ // It's only possible to hoist one time side effects if there are no + // dependencies on their changes from the loop header to the current
+        // instruction.
+        GVNFlagSet converted_changes =
+            HValue::ConvertChangesToDependsFlags(instr->ChangesFlags());
+        TraceGVN("Checking dependencies on one-time instruction %d (%s) "
+                 "converted changes 0x%X, accumulated depends 0x%X\n",
+                 instr->id(),
+                 instr->Mnemonic(),
+                 converted_changes.ToIntegral(),
+                 accumulated_first_time_depends->ToIntegral());
+ // It's possible to hoist one-time side effects from the current loop + // loop only if they dominate all of the successor blocks in the same + // loop and there are not any instructions that have Changes/DependsOn
+        // that intervene between it and the beginning of the loop header.
+        bool in_nested_loop = block != loop_header &&
+            ((block->parent_loop_header() != loop_header) ||
+             block->IsLoopHeader());
+        can_hoist = !in_nested_loop &&
+            block->IsLoopSuccessorDominator() &&
+            !accumulated_first_time_depends->ContainsAnyOf(converted_changes);
       }

-      if (inputs_loop_invariant && ShouldMove(instr, loop_header)) {
-        TraceGVN("Found loop invariant instruction %d\n", instr->id());
-        // Move the instruction out of the loop.
-        instr->Unlink();
-        instr->InsertBefore(pre_header->end());
+      if (can_hoist) {
+        bool inputs_loop_invariant = true;
+        for (int i = 0; i < instr->OperandCount(); ++i) {
+          if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) {
+            inputs_loop_invariant = false;
+          }
+        }
+
+        if (inputs_loop_invariant && ShouldMove(instr, loop_header)) {
+ TraceGVN("Hoisting loop invariant instruction %d\n", instr->id());
+          // Move the instruction out of the loop.
+          instr->Unlink();
+          instr->InsertBefore(pre_header->end());
+          if (instr->HasSideEffects()) removed_side_effects_ = true;
+          hoisted = true;
+        }
       }
     }
+    if (!hoisted) {
+      // If an instruction is not hoisted, we have to account for its side
+      // effects when hoisting later HTransitionElementsKind instructions.
+      accumulated_first_time_depends->Add(instr->DependsOnFlags());
+      GVNFlagSet converted_changes =
+          HValue::ConvertChangesToDependsFlags(instr->SideEffectFlags());
+      accumulated_first_time_depends->Add(converted_changes);
+    }
     instr = next;
   }
 }
@@ -2390,7 +2501,8 @@
// could only be discovered by removing side-effect-generating instructions
     // during the first pass.
     if (FLAG_smi_only_arrays && removed_side_effects) {
-      gvn.Analyze();
+      removed_side_effects = gvn.Analyze();
+      ASSERT(!removed_side_effects);
     }
   }

@@ -7260,7 +7372,10 @@
     }

     PrintEmptyProperty("xhandlers");
-    PrintEmptyProperty("flags");
+    const char* flags = current->IsLoopSuccessorDominator()
+        ? "dom-loop-succ"
+        : "";
+    PrintStringProperty("flags", flags);

     if (current->dominator() != NULL) {
       PrintBlockProperty("dominator", current->dominator()->block_id());
=======================================
--- /branches/bleeding_edge/src/hydrogen.h      Wed Feb  8 04:08:46 2012
+++ /branches/bleeding_edge/src/hydrogen.h      Thu Feb  9 00:58:19 2012
@@ -126,6 +126,7 @@
   int PredecessorIndexOf(HBasicBlock* predecessor) const;
   void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); }
   void AssignCommonDominator(HBasicBlock* other);
+  void AssignLoopSuccessorDominators();

   void FinishExitWithDeoptimization(HDeoptimize::UseEnvironment has_uses) {
     FinishExit(CreateDeoptimize(has_uses));
@@ -148,6 +149,13 @@

   bool IsDeoptimizing() const { return is_deoptimizing_; }
   void MarkAsDeoptimizing() { is_deoptimizing_ = true; }
+
+  bool IsLoopSuccessorDominator() const {
+    return dominates_loop_successors_;
+  }
+  void MarkAsLoopSuccessorDominator() {
+    dominates_loop_successors_ = true;
+  }

   inline Zone* zone();

@@ -182,6 +190,22 @@
   HBasicBlock* parent_loop_header_;
   bool is_inline_return_target_;
   bool is_deoptimizing_;
+  bool dominates_loop_successors_;
+};
+
+
+class HPredecessorIterator BASE_EMBEDDED {
+ public:
+  explicit HPredecessorIterator(HBasicBlock* block)
+      : predecessor_list_(block->predecessors()), current_(0) { }
+
+  bool Done() { return current_ >= predecessor_list_->length(); }
+  HBasicBlock* Current() { return predecessor_list_->at(current_); }
+  void Advance() { current_++; }
+
+ private:
+  const ZoneList<HBasicBlock*>* predecessor_list_;
+  int current_;
 };


=======================================
--- /branches/bleeding_edge/src/objects.cc      Tue Feb  7 23:23:14 2012
+++ /branches/bleeding_edge/src/objects.cc      Thu Feb  9 00:58:19 2012
@@ -5511,7 +5511,7 @@
     for (int i = 0; i < maps_->length(); ++i) {
       bool match_found = false;
       for (int j = 0; j < other_maps.length(); ++j) {
-        if (maps_->at(i)->EquivalentTo(*other_maps.at(j))) {
+        if (*(maps_->at(i)) == *(other_maps.at(j))) {
           match_found = true;
           break;
         }
=======================================
--- /branches/bleeding_edge/src/objects.h       Wed Feb  8 01:56:33 2012
+++ /branches/bleeding_edge/src/objects.h       Thu Feb  9 00:58:19 2012
@@ -4695,12 +4695,6 @@
   // it had exactly zero inobject properties.
   // The "shared" flags of both this map and |other| are ignored.
bool EquivalentToForNormalization(Map* other, PropertyNormalizationMode mode);
-
-  // Returns true if this map and |other| describe equivalent objects.
-  // The "shared" flags of both this map and |other| are ignored.
-  bool EquivalentTo(Map* other) {
-    return EquivalentToForNormalization(other, KEEP_INOBJECT_PROPERTIES);
-  }

// Returns the contents of this map's descriptor array for the given string.
   // May return NULL. |safe_to_add_transition| is set to false and NULL

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to