Fix bugs in IfBuilder and improve functionality
authordanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 18 Apr 2013 10:51:24 +0000 (10:51 +0000)
committerdanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 18 Apr 2013 10:51:24 +0000 (10:51 +0000)
R=mstarzinger@chromium.org

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

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

src/arm/lithium-arm.cc
src/code-stubs-hydrogen.cc
src/hydrogen.cc
src/hydrogen.h
src/ia32/lithium-ia32.cc
src/x64/lithium-x64.cc

index f6029b5..64083e8 100644 (file)
@@ -823,11 +823,15 @@ void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
     HEnvironment* last_environment = pred->last_environment();
     for (int i = 0; i < block->phis()->length(); ++i) {
       HPhi* phi = block->phis()->at(i);
-      last_environment->SetValueAt(phi->merged_index(), phi);
+      if (phi->merged_index() < last_environment->length()) {
+        last_environment->SetValueAt(phi->merged_index(), phi);
+      }
     }
     for (int i = 0; i < block->deleted_phis()->length(); ++i) {
-      last_environment->SetValueAt(block->deleted_phis()->at(i),
-                                   graph_->GetConstantUndefined());
+      if (block->deleted_phis()->at(i) < last_environment->length()) {
+        last_environment->SetValueAt(block->deleted_phis()->at(i),
+                                     graph_->GetConstantUndefined());
+      }
     }
     block->UpdateEnvironment(last_environment);
     // Pick up the outgoing argument count of one of the predecessors.
index 905c4b7..60ddf9b 100644 (file)
@@ -203,31 +203,32 @@ HValue* CodeStubGraphBuilder<FastCloneShallowArrayStub>::BuildCodeStub() {
                                           NULL,
                                           FAST_ELEMENTS));
 
-  CheckBuilder builder(this, BailoutId::StubEntry());
+  CheckBuilder builder(this);
   builder.CheckNotUndefined(boilerplate);
 
   if (mode == FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS) {
     HValue* elements =
         AddInstruction(new(zone) HLoadElements(boilerplate, NULL));
 
-    IfBuilder if_fixed_cow(this, BailoutId::StubEntry());
-    if_fixed_cow.BeginIfMapEquals(elements, factory->fixed_cow_array_map());
+    IfBuilder if_fixed_cow(this);
+    if_fixed_cow.IfCompareMap(elements, factory->fixed_cow_array_map());
+    if_fixed_cow.Then();
     environment()->Push(BuildCloneShallowArray(context(),
                                                boilerplate,
                                                alloc_site_mode,
                                                FAST_ELEMENTS,
                                                0/*copy-on-write*/));
-    if_fixed_cow.BeginElse();
+    if_fixed_cow.Else();
 
-    IfBuilder if_fixed(this, BailoutId::StubEntry());
-    if_fixed.BeginIfMapEquals(elements, factory->fixed_array_map());
+    IfBuilder if_fixed(this);
+    if_fixed.IfCompareMap(elements, factory->fixed_array_map());
+    if_fixed.Then();
     environment()->Push(BuildCloneShallowArray(context(),
                                                boilerplate,
                                                alloc_site_mode,
                                                FAST_ELEMENTS,
                                                length));
-    if_fixed.BeginElse();
-
+    if_fixed.Else();
     environment()->Push(BuildCloneShallowArray(context(),
                                                boilerplate,
                                                alloc_site_mode,
@@ -264,7 +265,7 @@ HValue* CodeStubGraphBuilder<FastCloneShallowObjectStub>::BuildCodeStub() {
                                           NULL,
                                           FAST_ELEMENTS));
 
-  CheckBuilder builder(this, BailoutId::StubEntry());
+  CheckBuilder builder(this);
   builder.CheckNotUndefined(boilerplate);
 
   int size = JSObject::kHeaderSize + casted_stub()->length() * kPointerSize;
@@ -356,13 +357,14 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
   ElementsKind to_kind = casted_stub()->to_kind();
   BuildNewSpaceArrayCheck(array_length, to_kind);
 
-  IfBuilder if_builder(this, BailoutId::StubEntry());
+  IfBuilder if_builder(this);
 
-  if_builder.BeginIf(array_length, graph()->GetConstant0(), Token::EQ);
+  if_builder.IfCompare(array_length, graph()->GetConstant0(), Token::EQ);
+  if_builder.Then();
 
   // Nothing to do, just change the map.
 
-  if_builder.BeginElse();
+  if_builder.Else();
 
   HInstruction* elements =
       AddInstruction(new(zone) HLoadElements(js_array, js_array));
@@ -375,8 +377,7 @@ HValue* CodeStubGraphBuilder<TransitionElementsKindStub>::BuildCodeStub() {
 
   BuildCopyElements(context(), elements,
                     casted_stub()->from_kind(), new_elements,
-                    to_kind, array_length, elements_length,
-                    BailoutId::StubEntry());
+                    to_kind, array_length, elements_length);
 
   Factory* factory = isolate()->factory();
 
index 09e3fe9..acd2f34 100644 (file)
@@ -183,7 +183,9 @@ void HBasicBlock::Finish(HControlInstruction* end) {
 }
 
 
-void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) {
+void HBasicBlock::Goto(HBasicBlock* block,
+                       FunctionState* state,
+                       bool add_simulate) {
   bool drop_extra = state != NULL &&
       state->inlining_kind() == DROP_EXTRA_ON_RETURN;
 
@@ -192,7 +194,7 @@ void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) {
     last_environment_ = last_environment()->DiscardInlined(drop_extra);
   }
 
-  AddSimulate(BailoutId::None());
+  if (add_simulate) AddSimulate(BailoutId::None());
   HGoto* instr = new(zone()) HGoto(block);
   Finish(instr);
 }
@@ -640,27 +642,26 @@ DEFINE_GET_CONSTANT(Hole, the_hole, HType::Tagged(), false)
 #undef DEFINE_GET_CONSTANT
 
 
-HGraphBuilder::CheckBuilder::CheckBuilder(HGraphBuilder* builder, BailoutId id)
+HGraphBuilder::CheckBuilder::CheckBuilder(HGraphBuilder* builder)
     : builder_(builder),
-      finished_(false),
-      id_(id) {
+      finished_(false) {
   HEnvironment* env = builder->environment();
-  failure_block_ = builder->CreateBasicBlock(env->CopyWithoutHistory());
-  merge_block_ = builder->CreateBasicBlock(env->CopyWithoutHistory());
+  failure_block_ = builder->CreateBasicBlock(env->Copy());
+  merge_block_ = builder->CreateBasicBlock(env->Copy());
 }
 
 
 HValue* HGraphBuilder::CheckBuilder::CheckNotUndefined(HValue* value) {
   HEnvironment* env = builder_->environment();
-  HIsNilAndBranch* compare =
-      new(zone()) HIsNilAndBranch(value, kStrictEquality, kUndefinedValue);
-  HBasicBlock* success_block =
-      builder_->CreateBasicBlock(env->CopyWithoutHistory());
-  HBasicBlock* failure_block =
-      builder_->CreateBasicBlock(env->CopyWithoutHistory());
+  HCompareObjectEqAndBranch* compare =
+      new(zone()) HCompareObjectEqAndBranch(
+          value,
+          builder_->graph()->GetConstantUndefined());
+  HBasicBlock* success_block = builder_->CreateBasicBlock(env->Copy());
+  HBasicBlock* failure_block = builder_->CreateBasicBlock(env->Copy());
   compare->SetSuccessorAt(0, failure_block);
   compare->SetSuccessorAt(1, success_block);
-  failure_block->Goto(failure_block_);
+  failure_block->GotoNoSimulate(failure_block_);
   builder_->current_block()->Finish(compare);
   builder_->set_current_block(success_block);
   return compare;
@@ -674,13 +675,11 @@ HValue* HGraphBuilder::CheckBuilder::CheckIntegerCompare(HValue* left,
   HCompareIDAndBranch* compare =
       new(zone()) HCompareIDAndBranch(left, right, op);
   compare->AssumeRepresentation(Representation::Integer32());
-  HBasicBlock* success_block =
-      builder_->CreateBasicBlock(env->CopyWithoutHistory());
-  HBasicBlock* failure_block =
-      builder_->CreateBasicBlock(env->CopyWithoutHistory());
+  HBasicBlock* success_block = builder_->CreateBasicBlock(env->Copy());
+  HBasicBlock* failure_block = builder_->CreateBasicBlock(env->Copy());
   compare->SetSuccessorAt(0, success_block);
   compare->SetSuccessorAt(1, failure_block);
-  failure_block->Goto(failure_block_);
+  failure_block->GotoNoSimulate(failure_block_);
   builder_->current_block()->Finish(compare);
   builder_->set_current_block(success_block);
   return compare;
@@ -695,11 +694,11 @@ HValue* HGraphBuilder::CheckBuilder::CheckIntegerEq(HValue* left,
 
 void HGraphBuilder::CheckBuilder::End() {
   ASSERT(!finished_);
-  builder_->current_block()->Goto(merge_block_);
-  failure_block_->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
-  failure_block_->SetJoinId(id_);
+  builder_->current_block()->GotoNoSimulate(merge_block_);
+  if (failure_block_->HasPredecessor()) {
+    failure_block_->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
+  }
   builder_->set_current_block(merge_block_);
-  merge_block_->SetJoinId(id_);
   finished_ = true;
 }
 
@@ -709,11 +708,19 @@ HConstant* HGraph::GetInvalidContext() {
 }
 
 
-  HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, BailoutId id)
+HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, int position)
     : builder_(builder),
+      position_(position),
       finished_(false),
+      did_then_(false),
       did_else_(false),
-      id_(id) {
+      deopt_then_(false),
+      deopt_else_(false),
+      did_and_(false),
+      did_or_(false),
+      captured_(false),
+      needs_compare_(true),
+      split_edge_merge_block_(NULL) {
   HEnvironment* env = builder->environment();
   first_true_block_ = builder->CreateBasicBlock(env->Copy());
   last_true_block_ = NULL;
@@ -721,7 +728,31 @@ HConstant* HGraph::GetInvalidContext() {
 }
 
 
-HInstruction* HGraphBuilder::IfBuilder::BeginIf(
+HGraphBuilder::IfBuilder::IfBuilder(
+    HGraphBuilder* builder,
+    HIfContinuation* continuation)
+    : builder_(builder),
+      position_(RelocInfo::kNoPosition),
+      finished_(false),
+      did_then_(false),
+      did_else_(false),
+      deopt_then_(false),
+      deopt_else_(false),
+      did_and_(false),
+      did_or_(false),
+      captured_(false),
+      needs_compare_(false),
+      first_true_block_(NULL),
+      first_false_block_(NULL),
+      split_edge_merge_block_(NULL),
+      merge_block_(NULL) {
+  continuation->Continue(&first_true_block_,
+                         &first_false_block_,
+                         &position_);
+}
+
+
+HInstruction* HGraphBuilder::IfBuilder::IfCompare(
     HValue* left,
     HValue* right,
     Token::Value token,
@@ -731,70 +762,158 @@ HInstruction* HGraphBuilder::IfBuilder::BeginIf(
   compare->set_observed_input_representation(input_representation,
                                              input_representation);
   compare->ChangeRepresentation(input_representation);
-  compare->SetSuccessorAt(0, first_true_block_);
-  compare->SetSuccessorAt(1, first_false_block_);
-  builder_->current_block()->Finish(compare);
-  builder_->set_current_block(first_true_block_);
+  AddCompare(compare);
   return compare;
 }
 
 
-HInstruction* HGraphBuilder::IfBuilder::BeginIfObjectsEqual(
-    HValue* left,
-    HValue* right) {
-  HCompareObjectEqAndBranch* compare =
-      new(zone()) HCompareObjectEqAndBranch(left, right);
-  compare->SetSuccessorAt(0, first_true_block_);
-  compare->SetSuccessorAt(1, first_false_block_);
-  builder_->current_block()->Finish(compare);
-  builder_->set_current_block(first_true_block_);
+HInstruction* HGraphBuilder::IfBuilder::IfCompareMap(HValue* left,
+                                                     Handle<Map> map) {
+  HCompareMap* compare =
+      new(zone()) HCompareMap(left, map,
+                              first_true_block_, first_false_block_);
+  AddCompare(compare);
   return compare;
 }
 
 
-HInstruction* HGraphBuilder::IfBuilder::BeginIfMapEquals(HValue* value,
-                                                         Handle<Map> map) {
-  HCompareMap* compare = new(zone())
-      HCompareMap(value, map, first_true_block_, first_false_block_);
+void HGraphBuilder::IfBuilder::AddCompare(HControlInstruction* compare) {
+  if (split_edge_merge_block_ != NULL) {
+    HEnvironment* env = first_false_block_->last_environment();
+    HBasicBlock* split_edge =
+        builder_->CreateBasicBlock(env->Copy());
+    if (did_or_) {
+      compare->SetSuccessorAt(0, split_edge);
+      compare->SetSuccessorAt(1, first_false_block_);
+    } else {
+      compare->SetSuccessorAt(0, first_true_block_);
+      compare->SetSuccessorAt(1, split_edge);
+    }
+    split_edge->GotoNoSimulate(split_edge_merge_block_);
+  } else {
+    compare->SetSuccessorAt(0, first_true_block_);
+    compare->SetSuccessorAt(1, first_false_block_);
+  }
   builder_->current_block()->Finish(compare);
+  needs_compare_ = false;
+}
+
+
+void HGraphBuilder::IfBuilder::Or() {
+  ASSERT(!did_and_);
+  did_or_ = true;
+  HEnvironment* env = first_false_block_->last_environment();
+  if (split_edge_merge_block_ == NULL) {
+    split_edge_merge_block_ =
+        builder_->CreateBasicBlock(env->Copy());
+    first_true_block_->GotoNoSimulate(split_edge_merge_block_);
+    first_true_block_ = split_edge_merge_block_;
+  }
+  builder_->set_current_block(first_false_block_);
+  first_false_block_ = builder_->CreateBasicBlock(env->Copy());
+}
+
+
+void HGraphBuilder::IfBuilder::And() {
+  ASSERT(!did_or_);
+  did_and_ = true;
+  HEnvironment* env = first_false_block_->last_environment();
+  if (split_edge_merge_block_ == NULL) {
+    split_edge_merge_block_ = builder_->CreateBasicBlock(env->Copy());
+    first_false_block_->GotoNoSimulate(split_edge_merge_block_);
+    first_false_block_ = split_edge_merge_block_;
+  }
   builder_->set_current_block(first_true_block_);
-  return compare;
+  first_true_block_ = builder_->CreateBasicBlock(env->Copy());
+}
+
+
+void HGraphBuilder::IfBuilder::CaptureContinuation(
+    HIfContinuation* continuation) {
+  ASSERT(!finished_);
+  ASSERT(!captured_);
+  HBasicBlock* true_block = last_true_block_ == NULL
+      ? first_true_block_
+      : last_true_block_;
+  HBasicBlock* false_block =
+      did_else_ ? builder_->current_block() : first_false_block_;
+  continuation->Capture(true_block, false_block, position_);
+  captured_ = true;
+  End();
 }
 
 
-void HGraphBuilder::IfBuilder::BeginElse() {
+void HGraphBuilder::IfBuilder::Then() {
+  ASSERT(!captured_);
+  ASSERT(!finished_);
+  did_then_ = true;
+  if (needs_compare_) {
+    // Handle if's without any expressions, they jump directly to the "else"
+    // branch.
+    builder_->current_block()->GotoNoSimulate(first_false_block_);
+    first_true_block_ = NULL;
+  }
+  builder_->set_current_block(first_true_block_);
+}
+
+
+void HGraphBuilder::IfBuilder::Else() {
+  ASSERT(did_then_);
+  ASSERT(!captured_);
+  ASSERT(!finished_);
   last_true_block_ = builder_->current_block();
-  ASSERT(!last_true_block_->IsFinished());
+  ASSERT(first_true_block_ == NULL || !last_true_block_->IsFinished());
   builder_->set_current_block(first_false_block_);
   did_else_ = true;
 }
 
 
+void HGraphBuilder::IfBuilder::Deopt() {
+  ASSERT(!(did_then_ ^ did_else_));
+  HBasicBlock* block = builder_->current_block();
+  block->FinishExitWithDeoptimization(HDeoptimize::kUseAll);
+  if (did_else_) {
+    first_false_block_ = NULL;
+    did_else_ = false;
+  } else {
+    first_true_block_ = NULL;
+  }
+}
+
+
 void HGraphBuilder::IfBuilder::End() {
-  ASSERT(!finished_);
-  if (!did_else_) BeginElse();
-  ASSERT(!last_true_block_->IsFinished());
-  HBasicBlock* last_false_block = builder_->current_block();
-  ASSERT(!last_false_block->IsFinished());
-  HEnvironment* merge_env =
-      last_true_block_->last_environment()->CopyWithoutHistory();
-  merge_block_ = builder_->CreateBasicBlock(merge_env);
-  last_true_block_->Goto(merge_block_);
-  last_false_block->Goto(merge_block_);
-  merge_block_->SetJoinId(id_);
-  builder_->set_current_block(merge_block_);
+  if (!captured_) {
+    ASSERT(did_then_);
+    if (!did_else_) {
+      last_true_block_ = builder_->current_block();
+    }
+    if (first_true_block_ == NULL) {
+      // Deopt on true. Nothing to do, just continue the else block.
+    } else if (first_false_block_ == NULL) {
+      builder_->set_current_block(last_true_block_);
+    } else {
+      HEnvironment* merge_env = last_true_block_->last_environment()->Copy();
+      merge_block_ = builder_->CreateBasicBlock(merge_env);
+      ASSERT(!finished_);
+      if (!did_else_) Else();
+      ASSERT(!last_true_block_->IsFinished());
+      HBasicBlock* last_false_block = builder_->current_block();
+      ASSERT(!last_false_block->IsFinished());
+      last_true_block_->GotoNoSimulate(merge_block_);
+      last_false_block->GotoNoSimulate(merge_block_);
+      builder_->set_current_block(merge_block_);
+    }
+  }
   finished_ = true;
 }
 
 
 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder,
                                         HValue* context,
-                                        LoopBuilder::Direction direction,
-                                        BailoutId id)
+                                        LoopBuilder::Direction direction)
     : builder_(builder),
       context_(context),
       direction_(direction),
-      id_(id),
       finished_(false) {
   header_block_ = builder->CreateLoopHeaderBlock();
   body_block_ = NULL;
@@ -813,7 +932,7 @@ HValue* HGraphBuilder::LoopBuilder::BeginBody(
   phi_->AddInput(initial);
   phi_->ChangeRepresentation(Representation::Integer32());
   env->Push(initial);
-  builder_->current_block()->Goto(header_block_);
+  builder_->current_block()->GotoNoSimulate(header_block_);
 
   HEnvironment* body_env = env->Copy();
   HEnvironment* exit_env = env->Copy();
@@ -867,9 +986,8 @@ void HGraphBuilder::LoopBuilder::EndBody() {
 
   // Push the new increment value on the expression stack to merge into the phi.
   builder_->environment()->Push(increment_);
-  builder_->current_block()->Goto(header_block_);
+  builder_->current_block()->GotoNoSimulate(header_block_);
   header_block_->loop_information()->RegisterBackEdge(body_block_);
-  header_block_->SetJoinId(id_);
 
   builder_->set_current_block(exit_block_);
   // Pop the phi from the expression stack
@@ -904,7 +1022,6 @@ void HGraphBuilder::AddSimulate(BailoutId id,
   ASSERT(current_block() != NULL);
   ASSERT(no_side_effects_scope_count_ == 0);
   current_block()->AddSimulate(id, removable);
-  environment()->set_ast_id(id);
 }
 
 
@@ -955,6 +1072,21 @@ HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
 }
 
 
+HValue* HGraphBuilder::BuildCheckNonSmi(HValue* obj) {
+  HCheckNonSmi* check = new(zone()) HCheckNonSmi(obj);
+  AddInstruction(check);
+  return check;
+}
+
+
+HValue* HGraphBuilder::BuildCheckMap(HValue* obj,
+                                              Handle<Map> map) {
+  HCheckMaps* check = new(zone()) HCheckMaps(obj, map, zone());
+  AddInstruction(check);
+  return check;
+}
+
+
 HInstruction* HGraphBuilder::BuildExternalArrayElementAccess(
     HValue* external_elements,
     HValue* checked_key,
@@ -1049,18 +1181,19 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object,
                                                  HValue* length,
                                                  HValue* key,
                                                  bool is_js_array) {
-  BailoutId ast_id = environment()->ast_id();
   Zone* zone = this->zone();
-  IfBuilder length_checker(this, ast_id);
+  IfBuilder length_checker(this);
 
-  length_checker.BeginIf(length, key, Token::EQ);
+  length_checker.IfCompare(length, key, Token::EQ);
+  length_checker.Then();
 
   HValue* current_capacity =
       AddInstruction(new(zone) HFixedArrayBaseLength(elements));
 
-  IfBuilder capacity_checker(this, ast_id);
+  IfBuilder capacity_checker(this);
 
-  capacity_checker.BeginIf(length, current_capacity, Token::EQ);
+  capacity_checker.IfCompare(length, current_capacity, Token::EQ);
+  capacity_checker.Then();
 
   HValue* context = environment()->LookupContext();
 
@@ -1069,10 +1202,10 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object,
 
   HValue* new_elements = BuildGrowElementsCapacity(object, elements,
                                                    kind, length,
-                                                   new_capacity, ast_id);
+                                                   new_capacity);
 
   environment()->Push(new_elements);
-  capacity_checker.BeginElse();
+  capacity_checker.Else();
 
   environment()->Push(elements);
   capacity_checker.End();
@@ -1092,7 +1225,7 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object,
     length_store->SetGVNFlag(kChangesArrayLengths);
   }
 
-  length_checker.BeginElse();
+  length_checker.Else();
 
   AddBoundsCheck(key, length, ALLOW_SMI_KEY);
   environment()->Push(elements);
@@ -1107,25 +1240,24 @@ HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object,
                                                 HValue* elements,
                                                 ElementsKind kind,
                                                 HValue* length) {
-  BailoutId ast_id = environment()->ast_id();
   Zone* zone = this->zone();
   Heap* heap = isolate()->heap();
 
-  IfBuilder cow_checker(this, ast_id);
+  IfBuilder cow_checker(this);
 
-  cow_checker.BeginIfMapEquals(elements,
-                               Handle<Map>(heap->fixed_cow_array_map()));
+  cow_checker.IfCompareMap(elements,
+                           Handle<Map>(heap->fixed_cow_array_map()));
+  cow_checker.Then();
 
   HValue* capacity =
       AddInstruction(new(zone) HFixedArrayBaseLength(elements));
 
   HValue* new_elements = BuildGrowElementsCapacity(object, elements,
-                                                   kind, length,
-                                                   capacity, ast_id);
+                                                   kind, length, capacity);
 
   environment()->Push(new_elements);
 
-  cow_checker.BeginElse();
+  cow_checker.Else();
 
   environment()->Push(elements);
 
@@ -1180,14 +1312,14 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
   HValue* checked_key = NULL;
   if (IsExternalArrayElementsKind(elements_kind)) {
     if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
+      NoObservableSideEffectsScope no_effects(this);
       HLoadExternalArrayPointer* external_elements =
           new(zone) HLoadExternalArrayPointer(elements);
       AddInstruction(external_elements);
-      BailoutId previous_id = environment()->ast_id();
-      ASSERT(!previous_id.IsNone());
-      IfBuilder length_checker(this, previous_id);
-      length_checker.BeginIf(key, length, Token::LT);
-      CheckBuilder negative_checker(this, previous_id);
+      IfBuilder length_checker(this);
+      length_checker.IfCompare(key, length, Token::LT);
+      length_checker.Then();
+      CheckBuilder negative_checker(this);
       HValue* bounds_check = negative_checker.CheckIntegerCompare(
           key, graph()->GetConstant0(), Token::GTE);
       negative_checker.End();
@@ -1250,8 +1382,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
 
 HValue* HGraphBuilder::BuildAllocateElements(HValue* context,
                                              ElementsKind kind,
-                                             HValue* capacity,
-                                             BailoutId ast_id) {
+                                             HValue* capacity) {
   Zone* zone = this->zone();
 
   int elements_size = IsFastDoubleElementsKind(kind)
@@ -1315,9 +1446,7 @@ void HGraphBuilder::BuildInitializeElements(HValue* elements,
 HValue* HGraphBuilder::BuildAllocateAndInitializeElements(HValue* context,
                                                           ElementsKind kind,
                                                           HValue* capacity) {
-  BailoutId ast_id = environment()->ast_id();
-  HValue* new_elements =
-      BuildAllocateElements(context, kind, capacity, ast_id);
+  HValue* new_elements = BuildAllocateElements(context, kind, capacity);
   BuildInitializeElements(new_elements, kind, capacity);
   return new_elements;
 }
@@ -1394,8 +1523,7 @@ HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
                                                  HValue* elements,
                                                  ElementsKind kind,
                                                  HValue* length,
-                                                 HValue* new_capacity,
-                                                 BailoutId ast_id) {
+                                                 HValue* new_capacity) {
   Zone* zone = this->zone();
   HValue* context = environment()->LookupContext();
 
@@ -1406,7 +1534,7 @@ HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object,
 
   BuildCopyElements(context, elements, kind,
                     new_elements, kind,
-                    length, new_capacity, ast_id);
+                    length, new_capacity);
 
   Factory* factory = isolate()->factory();
   HInstruction* elements_store = AddInstruction(new(zone) HStoreNamedField(
@@ -1424,8 +1552,7 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* context,
                                               HValue* elements,
                                               ElementsKind elements_kind,
                                               HValue* from,
-                                              HValue* to,
-                                              BailoutId ast_id) {
+                                              HValue* to) {
   // Fast elements kinds need to be initialized in case statements below cause
   // a garbage collection.
   Factory* factory = isolate()->factory();
@@ -1438,7 +1565,7 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* context,
       : AddInstruction(new(zone) HConstant(nan_double,
                                            Representation::Double()));
 
-  LoopBuilder builder(this, context, LoopBuilder::kPostIncrement, ast_id);
+  LoopBuilder builder(this, context, LoopBuilder::kPostIncrement);
 
   HValue* key = builder.BeginBody(from, to, Token::LT);
 
@@ -1454,8 +1581,7 @@ void HGraphBuilder::BuildCopyElements(HValue* context,
                                       HValue* to_elements,
                                       ElementsKind to_elements_kind,
                                       HValue* length,
-                                      HValue* capacity,
-                                      BailoutId ast_id) {
+                                      HValue* capacity) {
   bool pre_fill_with_holes =
       IsFastDoubleElementsKind(from_elements_kind) &&
       IsFastObjectElementsKind(to_elements_kind);
@@ -1465,10 +1591,10 @@ void HGraphBuilder::BuildCopyElements(HValue* context,
     // pre-initialized with holes to make sure that it's always in a consistent
     // state.
     BuildFillElementsWithHole(context, to_elements, to_elements_kind,
-                              graph()->GetConstant0(), capacity, ast_id);
+                              graph()->GetConstant0(), capacity);
   }
 
-  LoopBuilder builder(this, context, LoopBuilder::kPostIncrement, ast_id);
+  LoopBuilder builder(this, context, LoopBuilder::kPostIncrement);
 
   HValue* key = builder.BeginBody(graph()->GetConstant0(), length, Token::LT);
 
@@ -1485,7 +1611,7 @@ void HGraphBuilder::BuildCopyElements(HValue* context,
   if (!pre_fill_with_holes && length != capacity) {
     // Fill unused capacity with the hole.
     BuildFillElementsWithHole(context, to_elements, to_elements_kind,
-                              key, capacity, ast_id);
+                              key, capacity);
   }
 }
 
@@ -4111,6 +4237,22 @@ void EffectContext::ReturnControl(HControlInstruction* instr,
 }
 
 
+void EffectContext::ReturnContinuation(HIfContinuation* continuation,
+                                       BailoutId ast_id) {
+  HBasicBlock* true_branch = NULL;
+  HBasicBlock* false_branch = NULL;
+  continuation->Continue(&true_branch, &false_branch, NULL);
+  if (!continuation->IsTrueReachable()) {
+    owner()->set_current_block(false_branch);
+  } else if (!continuation->IsFalseReachable()) {
+    owner()->set_current_block(true_branch);
+  } else {
+    HBasicBlock* join = owner()->CreateJoin(true_branch, false_branch, ast_id);
+    owner()->set_current_block(join);
+  }
+}
+
+
 void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
   ASSERT(!instr->IsControlInstruction());
   if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) {
@@ -4144,6 +4286,29 @@ void ValueContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
 }
 
 
+void ValueContext::ReturnContinuation(HIfContinuation* continuation,
+                                      BailoutId ast_id) {
+  HBasicBlock* materialize_true = NULL;
+  HBasicBlock* materialize_false = NULL;
+  continuation->Continue(&materialize_true, &materialize_false, NULL);
+  if (continuation->IsTrueReachable()) {
+    owner()->set_current_block(materialize_true);
+    owner()->Push(owner()->graph()->GetConstantTrue());
+    owner()->set_current_block(materialize_true);
+  }
+  if (continuation->IsFalseReachable()) {
+    owner()->set_current_block(materialize_false);
+    owner()->Push(owner()->graph()->GetConstantFalse());
+    owner()->set_current_block(materialize_false);
+  }
+  if (continuation->TrueAndFalseReachable()) {
+    HBasicBlock* join =
+        owner()->CreateJoin(materialize_true, materialize_false, ast_id);
+    owner()->set_current_block(join);
+  }
+}
+
+
 void TestContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) {
   ASSERT(!instr->IsControlInstruction());
   HOptimizedGraphBuilder* builder = owner();
@@ -4172,6 +4337,21 @@ void TestContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
 }
 
 
+void TestContext::ReturnContinuation(HIfContinuation* continuation,
+                                     BailoutId ast_id) {
+  HBasicBlock* true_branch = NULL;
+  HBasicBlock* false_branch = NULL;
+  continuation->Continue(&true_branch, &false_branch, NULL);
+  if (continuation->IsTrueReachable()) {
+    true_branch->Goto(if_true(), owner()->function_state());
+  }
+  if (continuation->IsFalseReachable()) {
+    false_branch->Goto(if_false(), owner()->function_state());
+  }
+  owner()->set_current_block(NULL);
+}
+
+
 void TestContext::BuildBranch(HValue* value) {
   // We expect the graph to be in edge-split form: there is no edge that
   // connects a branch node to a join node.  We conservatively ensure that
@@ -6815,7 +6995,6 @@ void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
                              true,  // is_store
                              &has_side_effects);
     Push(value);
-    ASSERT(has_side_effects);  // Stores always have side effects.
     AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE);
     return ast_context()->ReturnValue(Pop());
   }
index a8c3c5f..809942b 100644 (file)
@@ -125,7 +125,12 @@ class HBasicBlock: public ZoneObject {
 
   void Finish(HControlInstruction* last);
   void FinishExit(HControlInstruction* instruction);
-  void Goto(HBasicBlock* block, FunctionState* state = NULL);
+  void Goto(HBasicBlock* block,
+            FunctionState* state = NULL,
+            bool add_simulate = true);
+  void GotoNoSimulate(HBasicBlock* block) {
+    Goto(block, NULL, false);
+  }
 
   int PredecessorIndexOf(HBasicBlock* predecessor) const;
   void AddSimulate(BailoutId ast_id,
@@ -675,6 +680,9 @@ enum ArgumentsAllowedFlag {
   ARGUMENTS_ALLOWED
 };
 
+
+class HIfContinuation;
+
 // This class is not BASE_EMBEDDED because our inlining implementation uses
 // new and delete.
 class AstContext {
@@ -700,6 +708,13 @@ class AstContext {
   // expressions.
   virtual void ReturnControl(HControlInstruction* instr, BailoutId ast_id) = 0;
 
+  // Finishes the current basic block and materialize a boolean for
+  // value context, nothing for effect, generate a branch for test context.
+  // Call this function in tail position in the Visit functions for
+  // expressions that use an IfBuilder.
+  virtual void ReturnContinuation(HIfContinuation* continuation,
+                                  BailoutId ast_id) = 0;
+
   void set_for_typeof(bool for_typeof) { for_typeof_ = for_typeof; }
   bool is_for_typeof() { return for_typeof_; }
 
@@ -735,6 +750,8 @@ class EffectContext: public AstContext {
   virtual void ReturnValue(HValue* value);
   virtual void ReturnInstruction(HInstruction* instr, BailoutId ast_id);
   virtual void ReturnControl(HControlInstruction* instr, BailoutId ast_id);
+  virtual void ReturnContinuation(HIfContinuation* continuation,
+                                  BailoutId ast_id);
 };
 
 
@@ -748,6 +765,8 @@ class ValueContext: public AstContext {
   virtual void ReturnValue(HValue* value);
   virtual void ReturnInstruction(HInstruction* instr, BailoutId ast_id);
   virtual void ReturnControl(HControlInstruction* instr, BailoutId ast_id);
+  virtual void ReturnContinuation(HIfContinuation* continuation,
+                                  BailoutId ast_id);
 
   bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; }
 
@@ -773,6 +792,8 @@ class TestContext: public AstContext {
   virtual void ReturnValue(HValue* value);
   virtual void ReturnInstruction(HInstruction* instr, BailoutId ast_id);
   virtual void ReturnControl(HControlInstruction* instr, BailoutId ast_id);
+  virtual void ReturnContinuation(HIfContinuation* continuation,
+                                  BailoutId ast_id);
 
   static TestContext* cast(AstContext* context) {
     ASSERT(context->IsTest());
@@ -860,6 +881,45 @@ class FunctionState {
 };
 
 
+class HIfContinuation {
+ public:
+  HIfContinuation() { continuation_captured_ = false; }
+  ~HIfContinuation() { ASSERT(!continuation_captured_); }
+
+  void Capture(HBasicBlock* true_branch,
+               HBasicBlock* false_branch,
+               int position) {
+    ASSERT(!continuation_captured_);
+    ASSERT(true_branch != NULL || false_branch != NULL);
+    true_branch_ = true_branch;
+    false_branch_ = false_branch;
+    position_ = position;
+    continuation_captured_ = true;
+  }
+
+  void Continue(HBasicBlock** true_branch,
+                HBasicBlock** false_branch,
+                int* position) {
+    ASSERT(continuation_captured_);
+    *true_branch = true_branch_;
+    *false_branch = false_branch_;
+    if (position != NULL) *position = position_;
+    continuation_captured_ = false;
+  }
+
+  bool IsTrueReachable() { return true_branch_ != NULL; }
+  bool IsFalseReachable() { return false_branch_ != NULL; }
+  bool TrueAndFalseReachable() {
+    return IsTrueReachable() || IsFalseReachable();
+  }
+
+  bool continuation_captured_;
+  HBasicBlock* true_branch_;
+  HBasicBlock* false_branch_;
+  int position_;
+};
+
+
 class HGraphBuilder {
  public:
   explicit HGraphBuilder(CompilationInfo* info)
@@ -903,9 +963,12 @@ class HGraphBuilder {
  protected:
   virtual bool BuildGraph() = 0;
 
-  HBasicBlock* CreateBasicBlock(HEnvironment* envy);
+  HBasicBlock* CreateBasicBlock(HEnvironment* env);
   HBasicBlock* CreateLoopHeaderBlock();
 
+  HValue* BuildCheckNonSmi(HValue* object);
+  HValue* BuildCheckMap(HValue* obj, Handle<Map> map);
+
   // Building common constructs
   HInstruction* BuildExternalArrayElementAccess(
       HValue* external_elements,
@@ -952,7 +1015,7 @@ class HGraphBuilder {
 
   class CheckBuilder {
    public:
-    explicit CheckBuilder(HGraphBuilder* builder, BailoutId id);
+    explicit CheckBuilder(HGraphBuilder* builder);
     ~CheckBuilder() {
       if (!finished_) End();
     }
@@ -969,37 +1032,127 @@ class HGraphBuilder {
     bool finished_;
     HBasicBlock* failure_block_;
     HBasicBlock* merge_block_;
-    BailoutId id_;
   };
 
   class IfBuilder {
    public:
-    explicit IfBuilder(HGraphBuilder* builder, BailoutId id);
+    explicit IfBuilder(HGraphBuilder* builder,
+                       int position = RelocInfo::kNoPosition);
+    IfBuilder(HGraphBuilder* builder,
+              HIfContinuation* continuation);
+
     ~IfBuilder() {
       if (!finished_) End();
     }
 
-    HInstruction* BeginIf(
+    HInstruction* IfCompare(
         HValue* left,
         HValue* right,
         Token::Value token,
         Representation input_representation = Representation::Integer32());
-    HInstruction* BeginIfObjectsEqual(HValue* left, HValue* right);
-    HInstruction* BeginIfMapEquals(HValue* value, Handle<Map> map);
-    void BeginElse();
+
+    HInstruction* IfCompareMap(HValue* left, Handle<Map> map);
+
+    template<class Condition>
+    HInstruction* If(HValue *p) {
+      HControlInstruction* compare = new(zone()) Condition(p);
+      AddCompare(compare);
+      return compare;
+    }
+
+    template<class Condition, class P2>
+    HInstruction* If(HValue* p1, P2 p2) {
+      HControlInstruction* compare = new(zone()) Condition(p1, p2);
+      AddCompare(compare);
+      return compare;
+    }
+
+    template<class Condition>
+    HInstruction* OrIfCompare(
+        HValue* p1,
+        HValue* p2,
+        Token::Value token,
+        Representation input_representation = Representation::Integer32()) {
+      Or();
+      return IfCompare(p1, p2, token, input_representation);
+    }
+
+    HInstruction* OrIfCompareMap(HValue* left, Handle<Map> map) {
+      Or();
+      return IfCompareMap(left, map);
+    }
+
+    template<class Condition>
+    HInstruction* OrIf(HValue *p) {
+      Or();
+      return If<Condition>(p);
+    }
+
+    template<class Condition, class P2>
+    HInstruction* OrIf(HValue* p1, P2 p2) {
+      Or();
+      return If<Condition>(p1, p2);
+    }
+
+    template<class Condition>
+    HInstruction* AndIfCompare(
+        HValue* p1,
+        HValue* p2,
+        Token::Value token,
+        Representation input_representation = Representation::Integer32()) {
+      And();
+      return IfCompare(p1, p2, token, input_representation);
+    }
+
+    HInstruction* AndIfCompareMap(HValue* left, Handle<Map> map) {
+      And();
+      return IfCompareMap(left, map);
+    }
+
+    template<class Condition>
+    HInstruction* AndIf(HValue *p) {
+      And();
+      return If<Condition>(p);
+    }
+
+    template<class Condition, class P2>
+    HInstruction* AndIf(HValue* p1, P2 p2) {
+      And();
+      return If<Condition>(p1, p2);
+    }
+
+    void Or();
+    void And();
+
+    void CaptureContinuation(HIfContinuation* continuation);
+
+    void Then();
+    void Else();
     void End();
 
+    void Deopt();
+
    private:
+    void AddCompare(HControlInstruction* compare);
+
     Zone* zone() { return builder_->zone(); }
 
     HGraphBuilder* builder_;
-    bool finished_;
-    bool did_else_;
+    int position_;
+    bool finished_ : 1;
+    bool did_then_ : 1;
+    bool did_else_ : 1;
+    bool deopt_then_ : 1;
+    bool deopt_else_ : 1;
+    bool did_and_ : 1;
+    bool did_or_ : 1;
+    bool captured_ : 1;
+    bool needs_compare_ : 1;
     HBasicBlock* first_true_block_;
     HBasicBlock* last_true_block_;
     HBasicBlock* first_false_block_;
+    HBasicBlock* split_edge_merge_block_;
     HBasicBlock* merge_block_;
-    BailoutId id_;
   };
 
   class LoopBuilder {
@@ -1013,8 +1166,7 @@ class HGraphBuilder {
 
     LoopBuilder(HGraphBuilder* builder,
                 HValue* context,
-                Direction direction,
-                BailoutId id);
+                Direction direction);
     ~LoopBuilder() {
       ASSERT(finished_);
     }
@@ -1037,7 +1189,6 @@ class HGraphBuilder {
     HBasicBlock* body_block_;
     HBasicBlock* exit_block_;
     Direction direction_;
-    BailoutId id_;
     bool finished_;
   };
 
@@ -1063,8 +1214,7 @@ class HGraphBuilder {
 
   HValue* BuildAllocateElements(HValue* context,
                                 ElementsKind kind,
-                                HValue* capacity,
-                                BailoutId ast_id);
+                                HValue* capacity);
 
   void BuildInitializeElements(HValue* elements,
                                ElementsKind kind,
@@ -1078,15 +1228,13 @@ class HGraphBuilder {
                                     HValue* elements,
                                     ElementsKind kind,
                                     HValue* length,
-                                    HValue* new_capacity,
-                                    BailoutId ast_id);
+                                    HValue* new_capacity);
 
   void BuildFillElementsWithHole(HValue* context,
                                  HValue* elements,
                                  ElementsKind elements_kind,
                                  HValue* from,
-                                 HValue* to,
-                                 BailoutId ast_id);
+                                 HValue* to);
 
   void BuildCopyElements(HValue* context,
                          HValue* from_elements,
@@ -1094,8 +1242,7 @@ class HGraphBuilder {
                          HValue* to_elements,
                          ElementsKind to_elements_kind,
                          HValue* length,
-                         HValue* capacity,
-                         BailoutId ast_id);
+                         HValue* capacity);
 
   HValue* BuildCloneShallowArray(HContext* context,
                                  HValue* boilerplate,
index aa1d5c9..c4a8be1 100644 (file)
@@ -884,11 +884,15 @@ void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
     HEnvironment* last_environment = pred->last_environment();
     for (int i = 0; i < block->phis()->length(); ++i) {
       HPhi* phi = block->phis()->at(i);
-      last_environment->SetValueAt(phi->merged_index(), phi);
+      if (phi->merged_index() < last_environment->length()) {
+        last_environment->SetValueAt(phi->merged_index(), phi);
+      }
     }
     for (int i = 0; i < block->deleted_phis()->length(); ++i) {
-      last_environment->SetValueAt(block->deleted_phis()->at(i),
-                                   graph_->GetConstantUndefined());
+      if (block->deleted_phis()->at(i) < last_environment->length()) {
+        last_environment->SetValueAt(block->deleted_phis()->at(i),
+                                     graph_->GetConstantUndefined());
+      }
     }
     block->UpdateEnvironment(last_environment);
     // Pick up the outgoing argument count of one of the predecessors.
index fe494f2..1d42455 100644 (file)
@@ -831,11 +831,15 @@ void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
     HEnvironment* last_environment = pred->last_environment();
     for (int i = 0; i < block->phis()->length(); ++i) {
       HPhi* phi = block->phis()->at(i);
-      last_environment->SetValueAt(phi->merged_index(), phi);
+      if (phi->merged_index() < last_environment->length()) {
+        last_environment->SetValueAt(phi->merged_index(), phi);
+      }
     }
     for (int i = 0; i < block->deleted_phis()->length(); ++i) {
-      last_environment->SetValueAt(block->deleted_phis()->at(i),
-                                   graph_->GetConstantUndefined());
+      if (block->deleted_phis()->at(i) < last_environment->length()) {
+        last_environment->SetValueAt(block->deleted_phis()->at(i),
+                                     graph_->GetConstantUndefined());
+      }
     }
     block->UpdateEnvironment(last_environment);
     // Pick up the outgoing argument count of one of the predecessors.