| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index b47ec8010d25d10a76a1b203fa4bde3e5f39ba01..c73d8d6d80b394d64085b550ebbfd809b47403d9 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -605,7 +605,8 @@ void HGraph::Verify(bool do_full_verify) const {
|
| block->predecessors()->first()->last_environment()->ast_id();
|
| for (int k = 0; k < block->predecessors()->length(); k++) {
|
| HBasicBlock* predecessor = block->predecessors()->at(k);
|
| - ASSERT(predecessor->end()->IsGoto());
|
| + ASSERT(predecessor->end()->IsGoto() ||
|
| + predecessor->end()->IsDeoptimize());
|
| ASSERT(predecessor->last_environment()->ast_id() == id);
|
| }
|
| }
|
| @@ -745,19 +746,20 @@ bool HGraph::IsStandardConstant(HConstant* constant) {
|
| HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder)
|
| : builder_(builder),
|
| finished_(false),
|
| - deopt_then_(false),
|
| - deopt_else_(false),
|
| did_then_(false),
|
| did_else_(false),
|
| + did_else_if_(false),
|
| did_and_(false),
|
| did_or_(false),
|
| captured_(false),
|
| needs_compare_(true),
|
| + pending_merge_block_(false),
|
| split_edge_merge_block_(NULL),
|
| - merge_block_(NULL) {
|
| + merge_at_join_blocks_(NULL),
|
| + normal_merge_at_join_block_count_(0),
|
| + deopt_merge_at_join_block_count_(0) {
|
| HEnvironment* env = builder->environment();
|
| first_true_block_ = builder->CreateBasicBlock(env->Copy());
|
| - last_true_block_ = NULL;
|
| first_false_block_ = builder->CreateBasicBlock(env->Copy());
|
| }
|
|
|
| @@ -767,19 +769,20 @@ HGraphBuilder::IfBuilder::IfBuilder(
|
| HIfContinuation* continuation)
|
| : builder_(builder),
|
| finished_(false),
|
| - deopt_then_(false),
|
| - deopt_else_(false),
|
| did_then_(false),
|
| did_else_(false),
|
| + did_else_if_(false),
|
| did_and_(false),
|
| did_or_(false),
|
| captured_(false),
|
| needs_compare_(false),
|
| + pending_merge_block_(false),
|
| first_true_block_(NULL),
|
| - last_true_block_(NULL),
|
| first_false_block_(NULL),
|
| split_edge_merge_block_(NULL),
|
| - merge_block_(NULL) {
|
| + merge_at_join_blocks_(NULL),
|
| + normal_merge_at_join_block_count_(0),
|
| + deopt_merge_at_join_block_count_(0) {
|
| continuation->Continue(&first_true_block_,
|
| &first_false_block_);
|
| }
|
| @@ -787,6 +790,20 @@ HGraphBuilder::IfBuilder::IfBuilder(
|
|
|
| HControlInstruction* HGraphBuilder::IfBuilder::AddCompare(
|
| HControlInstruction* compare) {
|
| + ASSERT(did_then_ == did_else_);
|
| + if (did_else_) {
|
| + // Handle if-then-elseif
|
| + did_else_if_ = true;
|
| + did_else_ = false;
|
| + did_then_ = false;
|
| + did_and_ = false;
|
| + did_or_ = false;
|
| + pending_merge_block_ = false;
|
| + split_edge_merge_block_ = NULL;
|
| + HEnvironment* env = builder_->environment();
|
| + first_true_block_ = builder_->CreateBasicBlock(env->Copy());
|
| + first_false_block_ = builder_->CreateBasicBlock(env->Copy());
|
| + }
|
| if (split_edge_merge_block_ != NULL) {
|
| HEnvironment* env = first_false_block_->last_environment();
|
| HBasicBlock* split_edge =
|
| @@ -842,29 +859,30 @@ void HGraphBuilder::IfBuilder::And() {
|
|
|
| void HGraphBuilder::IfBuilder::CaptureContinuation(
|
| HIfContinuation* continuation) {
|
| + ASSERT(!did_else_if_);
|
| ASSERT(!finished_);
|
| ASSERT(!captured_);
|
| - HBasicBlock* true_block = last_true_block_ == NULL
|
| - ? first_true_block_
|
| - : last_true_block_;
|
| - HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL)
|
| - ? builder_->current_block()
|
| - : first_false_block_;
|
| +
|
| + HBasicBlock* true_block = NULL;
|
| + HBasicBlock* false_block = NULL;
|
| + Finish(&true_block, &false_block);
|
| + ASSERT(true_block != NULL);
|
| + ASSERT(false_block != NULL);
|
| continuation->Capture(true_block, false_block);
|
| captured_ = true;
|
| + builder_->set_current_block(NULL);
|
| End();
|
| }
|
|
|
|
|
| void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) {
|
| + ASSERT(!did_else_if_);
|
| ASSERT(!finished_);
|
| ASSERT(!captured_);
|
| - ASSERT(did_then_);
|
| - if (!did_else_) Else();
|
| - HBasicBlock* true_block = last_true_block_ == NULL
|
| - ? first_true_block_
|
| - : last_true_block_;
|
| - HBasicBlock* false_block = builder_->current_block();
|
| + HBasicBlock* true_block = NULL;
|
| + HBasicBlock* false_block = NULL;
|
| + Finish(&true_block, &false_block);
|
| + merge_at_join_blocks_ = NULL;
|
| if (true_block != NULL && !true_block->IsFinished()) {
|
| ASSERT(continuation->IsTrueReachable());
|
| builder_->GotoNoSimulate(true_block, continuation->true_branch());
|
| @@ -895,6 +913,7 @@ void HGraphBuilder::IfBuilder::Then() {
|
| builder_->FinishCurrentBlock(branch);
|
| }
|
| builder_->set_current_block(first_true_block_);
|
| + pending_merge_block_ = true;
|
| }
|
|
|
|
|
| @@ -902,20 +921,17 @@ void HGraphBuilder::IfBuilder::Else() {
|
| ASSERT(did_then_);
|
| ASSERT(!captured_);
|
| ASSERT(!finished_);
|
| - last_true_block_ = builder_->current_block();
|
| + AddMergeAtJoinBlock(false);
|
| builder_->set_current_block(first_false_block_);
|
| + pending_merge_block_ = true;
|
| did_else_ = true;
|
| }
|
|
|
|
|
| void HGraphBuilder::IfBuilder::Deopt(const char* reason) {
|
| ASSERT(did_then_);
|
| - if (did_else_) {
|
| - deopt_else_ = true;
|
| - } else {
|
| - deopt_then_ = true;
|
| - }
|
| builder_->Add<HDeoptimize>(reason, Deoptimizer::EAGER);
|
| + AddMergeAtJoinBlock(true);
|
| }
|
|
|
|
|
| @@ -923,51 +939,99 @@ void HGraphBuilder::IfBuilder::Return(HValue* value) {
|
| HValue* parameter_count = builder_->graph()->GetConstantMinus1();
|
| builder_->FinishExitCurrentBlock(
|
| builder_->New<HReturn>(value, parameter_count));
|
| - if (did_else_) {
|
| - first_false_block_ = NULL;
|
| - } else {
|
| - first_true_block_ = NULL;
|
| + AddMergeAtJoinBlock(false);
|
| +}
|
| +
|
| +
|
| +void HGraphBuilder::IfBuilder::AddMergeAtJoinBlock(bool deopt) {
|
| + if (!pending_merge_block_) return;
|
| + HBasicBlock* block = builder_->current_block();
|
| + ASSERT(block == NULL || !block->IsFinished());
|
| + MergeAtJoinBlock* record =
|
| + new(builder_->zone()) MergeAtJoinBlock(block, deopt,
|
| + merge_at_join_blocks_);
|
| + merge_at_join_blocks_ = record;
|
| + if (block != NULL) {
|
| + ASSERT(block->end() == NULL);
|
| + if (deopt) {
|
| + normal_merge_at_join_block_count_++;
|
| + } else {
|
| + deopt_merge_at_join_block_count_++;
|
| + }
|
| }
|
| + builder_->set_current_block(NULL);
|
| + pending_merge_block_ = false;
|
| +}
|
| +
|
| +
|
| +void HGraphBuilder::IfBuilder::Finish() {
|
| + ASSERT(!finished_);
|
| + if (!did_then_) {
|
| + Then();
|
| + }
|
| + AddMergeAtJoinBlock(false);
|
| + if (!did_else_) {
|
| + Else();
|
| + AddMergeAtJoinBlock(false);
|
| + }
|
| + finished_ = true;
|
| +}
|
| +
|
| +
|
| +void HGraphBuilder::IfBuilder::Finish(HBasicBlock** then_continuation,
|
| + HBasicBlock** else_continuation) {
|
| + Finish();
|
| +
|
| + MergeAtJoinBlock* else_record = merge_at_join_blocks_;
|
| + if (else_continuation != NULL) {
|
| + *else_continuation = else_record->block_;
|
| + }
|
| + MergeAtJoinBlock* then_record = else_record->next_;
|
| + if (then_continuation != NULL) {
|
| + *then_continuation = then_record->block_;
|
| + }
|
| + ASSERT(then_record->next_ == NULL);
|
| }
|
|
|
|
|
| void HGraphBuilder::IfBuilder::End() {
|
| - if (!captured_) {
|
| - ASSERT(did_then_);
|
| - if (!did_else_) {
|
| - last_true_block_ = builder_->current_block();
|
| - }
|
| - if (last_true_block_ == NULL || last_true_block_->IsFinished()) {
|
| - ASSERT(did_else_);
|
| - // Return on true. Nothing to do, just continue the false block.
|
| - } else if (first_false_block_ == NULL ||
|
| - (did_else_ && builder_->current_block()->IsFinished())) {
|
| - // Deopt on false. Nothing to do except switching to the true block.
|
| - builder_->set_current_block(last_true_block_);
|
| - } else {
|
| - merge_block_ = builder_->graph()->CreateBasicBlock();
|
| - ASSERT(!finished_);
|
| - if (!did_else_) Else();
|
| - ASSERT(!last_true_block_->IsFinished());
|
| - HBasicBlock* last_false_block = builder_->current_block();
|
| - ASSERT(!last_false_block->IsFinished());
|
| - if (deopt_then_) {
|
| - builder_->GotoNoSimulate(last_false_block, merge_block_);
|
| - builder_->PadEnvironmentForContinuation(last_true_block_,
|
| - merge_block_);
|
| - builder_->GotoNoSimulate(last_true_block_, merge_block_);
|
| - } else {
|
| - builder_->GotoNoSimulate(last_true_block_, merge_block_);
|
| - if (deopt_else_) {
|
| - builder_->PadEnvironmentForContinuation(last_false_block,
|
| - merge_block_);
|
| - }
|
| - builder_->GotoNoSimulate(last_false_block, merge_block_);
|
| + if (captured_) return;
|
| + Finish();
|
| +
|
| + int total_merged_blocks = normal_merge_at_join_block_count_ +
|
| + deopt_merge_at_join_block_count_;
|
| + ASSERT(total_merged_blocks >= 1);
|
| + HBasicBlock* merge_block = total_merged_blocks == 1
|
| + ? NULL : builder_->graph()->CreateBasicBlock();
|
| +
|
| + // Merge non-deopt blocks first to ensure environment has right size for
|
| + // padding.
|
| + MergeAtJoinBlock* current = merge_at_join_blocks_;
|
| + while (current != NULL) {
|
| + if (!current->deopt_ && current->block_ != NULL) {
|
| + // If there is only one block that makes it through to the end of the
|
| + // if, then just set it as the current block and continue rather then
|
| + // creating an unnecessary merge block.
|
| + if (total_merged_blocks == 1) {
|
| + builder_->set_current_block(current->block_);
|
| + return;
|
| }
|
| - builder_->set_current_block(merge_block_);
|
| + builder_->GotoNoSimulate(current->block_, merge_block);
|
| }
|
| + current = current->next_;
|
| }
|
| - finished_ = true;
|
| +
|
| + // Merge deopt blocks, padding when necessary.
|
| + current = merge_at_join_blocks_;
|
| + while (current != NULL) {
|
| + if (current->deopt_ && current->block_ != NULL) {
|
| + builder_->PadEnvironmentForContinuation(current->block_,
|
| + merge_block);
|
| + builder_->GotoNoSimulate(current->block_, merge_block);
|
| + }
|
| + current = current->next_;
|
| + }
|
| + builder_->set_current_block(merge_block);
|
| }
|
|
|
|
|
| @@ -1051,6 +1115,7 @@ void HGraphBuilder::LoopBuilder::Break() {
|
| }
|
|
|
| builder_->GotoNoSimulate(exit_trampoline_block_);
|
| + builder_->set_current_block(NULL);
|
| }
|
|
|
|
|
| @@ -1859,6 +1924,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
|
| HInstruction* result = AddElementAccess(
|
| external_elements, key, val, bounds_check, elements_kind, is_store);
|
| negative_checker.ElseDeopt("Negative key encountered");
|
| + negative_checker.End();
|
| length_checker.End();
|
| return result;
|
| } else {
|
| @@ -1940,9 +2006,10 @@ HValue* HGraphBuilder::BuildAllocateArrayFromLength(
|
| IsFastPackedElementsKind(array_builder->kind())) {
|
| // We'll come back later with better (holey) feedback.
|
| if_builder.Deopt("Holey array despite packed elements_kind feedback");
|
| + } else {
|
| + Push(checked_length); // capacity
|
| + Push(checked_length); // length
|
| }
|
| - Push(checked_length); // capacity
|
| - Push(checked_length); // length
|
| if_builder.End();
|
|
|
| // Figure out total size
|
|
|