optimized_code = chunk_->Codegen(); if (optimized_code.is_null()) { if (info()->bailout_reason() == kNoReason) { return AbortOptimization(kCodeGenerationFailed); } return FAILED; } RegisterWeakObjectsInOptimizedCode(optimized_code); info()->SetCode(optimized_code); } // Add to the weak list of optimized code objects. info()->context()->native_context()->AddOptimizedCode(*info()->code()); return SUCCEEDED; } HBasicBlock::HBasicBlock(HGraph* graph) : block_id_(graph->GetNextBlockID()), graph_(graph), phis_(4, graph->zone()), first_(NULL), last_(NULL), end_(NULL), loop_information_(NULL), predecessors_(2, graph->zone()), dominator_(NULL), dominated_blocks_(4, graph->zone()), last_environment_(NULL), argument_count_(-1), first_instruction_index_(-1), last_instruction_index_(-1), deleted_phis_(4, graph->zone()), parent_loop_header_(NULL), inlined_entry_block_(NULL), is_inline_return_target_(false), is_reachable_(true), dominates_loop_successors_(false), is_osr_entry_(false), is_ordered_(false) { } Isolate* HBasicBlock::isolate() const { return graph_->isolate(); } void HBasicBlock::MarkUnreachable() { is_reachable_ = false; } void HBasicBlock::AttachLoopInformation() { DCHECK(!IsLoopHeader()); loop_information_ = new(zone()) HLoopInformation(this, zone()); } void HBasicBlock::DetachLoopInformation() { DCHECK(IsLoopHeader()); loop_information_ = NULL; } void HBasicBlock::AddPhi(HPhi* phi) { DCHECK(!IsStartBlock()); phis_.Add(phi, zone()); phi->SetBlock(this); } void HBasicBlock::RemovePhi(HPhi* phi) { DCHECK(phi->block() == this); DCHECK(phis_.Contains(phi)); phi->Kill(); phis_.RemoveElement(phi); phi->SetBlock(NULL); } void HBasicBlock::AddInstruction(HInstruction* instr, SourcePosition position) { DCHECK(!IsStartBlock() || !IsFinished()); DCHECK(!instr->IsLinked()); DCHECK(!IsFinished()); if (position.IsKnown()) { instr->set_position(position); } if (first_ == NULL) { DCHECK(last_environment() != NULL); DCHECK(!last_environment()->ast_id().IsNone()); HBlockEntry* entry = new(zone()) HBlockEntry(); entry->InitializeAsFirst(this); if (position.IsKnown()) { entry->set_position(position); } else { DCHECK(!FLAG_hydrogen_track_positions || !graph()->info()->IsOptimizing() || instr->IsAbnormalExit()); } first_ = last_ = entry; } instr->InsertAfter(last_); } HPhi* HBasicBlock::AddNewPhi(int merged_index) { if (graph()->IsInsideNoSideEffectsScope()) { merged_index = HPhi::kInvalidMergedIndex; } HPhi* phi = new(zone()) HPhi(merged_index, zone()); AddPhi(phi); return phi; } HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id, RemovableSimulate removable) { DCHECK(HasEnvironment()); HEnvironment* environment = last_environment(); DCHECK(ast_id.IsNone() || ast_id == BailoutId::StubEntry() || environment->closure()->shared()->VerifyBailoutId(ast_id)); int push_count = environment->push_count(); int pop_count = environment->pop_count(); HSimulate* instr = new(zone()) HSimulate(ast_id, pop_count, zone(), removable); #ifdef DEBUG instr->set_closure(environment->closure()); #endif // Order of pushed values: newest (top of stack) first. This allows // HSimulate::MergeWith() to easily append additional pushed values // that are older (from further down the stack). for (int i = 0; i < push_count; ++i) { instr->AddPushedValue(environment->ExpressionStackAt(i)); } for (GrowableBitVector::Iterator it(environment->assigned_variables(), zone()); !it.Done(); it.Advance()) { int index = it.Current(); instr->AddAssignedValue(index, environment->Lookup(index)); } environment->ClearHistory(); return instr; } void HBasicBlock::Finish(HControlInstruction* end, SourcePosition position) { DCHECK(!IsFinished()); AddInstruction(end, position); end_ = end; for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { it.Current()->RegisterPredecessor(this); } } void HBasicBlock::Goto(HBasicBlock* block, SourcePosition position, FunctionState* state, bool add_simulate) { bool drop_extra = state != NULL && state->inlining_kind() == NORMAL_RETURN; if (block->IsInlineReturnTarget()) { HEnvironment* env = last_environment(); int argument_count = env->arguments_environment()->parameter_count(); AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count), position); UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); } if (add_simulate) AddNewSimulate(BailoutId::None(), position); HGoto* instr = new(zone()) HGoto(block); Finish(instr, position); } void HBasicBlock::AddLeaveInlined(HValue* return_value, FunctionState* state, SourcePosition position) { HBasicBlock* target = state->function_return(); bool drop_extra = state->inlining_kind() == NORMAL_RETURN; DCHECK(target->IsInlineReturnTarget()); DCHECK(return_value != NULL); HEnvironment* env = last_environment(); int argument_count = env->arguments_environment()->parameter_count(); AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count), position); UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); last_environment()->Push(return_value); AddNewSimulate(BailoutId::None(), position); HGoto* instr = new(zone()) HGoto(target); Finish(instr, position); } void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { DCHECK(!HasEnvironment()); DCHECK(first() == NULL); UpdateEnvironment(env); } void HBasicBlock::UpdateEnvironment(HEnvironment* env) { last_environment_ = env; graph()->update_maximum_environment_size(env->first_expression_index()); } void HBasicBlock::SetJoinId(BailoutId ast_id) { int length = predecessors_.length(); DCHECK(length > 0); for (int i = 0; i < length; i++) { HBasicBlock* predecessor = predecessors_[i]; DCHECK(predecessor->end()->IsGoto()); HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); DCHECK(i != 0 || (predecessor->last_environment()->closure().is_null() || predecessor->last_environment()->closure()->shared() ->VerifyBailoutId(ast_id))); simulate->set_ast_id(ast_id); predecessor->last_environment()->set_ast_id(ast_id); } } bool HBasicBlock::Dominates(HBasicBlock* other) const { HBasicBlock* current = other->dominator(); while (current != NULL) { if (current == this) return true; current = current->dominator(); } return false; } bool HBasicBlock::EqualToOrDominates(HBasicBlock* other) const { if (this == other) return true; return Dominates(other); } int HBasicBlock::LoopNestingDepth() const { const HBasicBlock* current = this; int result = (current->IsLoopHeader()) ? 1 : 0; while (current->parent_loop_header() != NULL) { current = current->parent_loop_header(); result++; } return result; } void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) { DCHECK(IsLoopHeader()); SetJoinId(stmt->EntryId()); if (predecessors()->length() == 1) { // This is a degenerated loop. DetachLoopInformation(); return; } // Only the first entry into the loop is from outside the loop. All other // entries must be back edges. for (int i = 1; i < predecessors()->length(); ++i) { loop_information()->RegisterBackEdge(predecessors()->at(i)); } } void HBasicBlock::MarkSuccEdgeUnreachable(int succ) { DCHECK(IsFinished()); HBasicBlock* succ_block = end()->SuccessorAt(succ); DCHECK(succ_block->predecessors()->length() == 1); succ_block->MarkUnreachable(); } void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) { if (HasPredecessor()) { // Only loop header blocks can have a predecessor added after // instructions have been added to the block (they have phis for all // values in the environment, these phis may be eliminated later). DCHECK(IsLoopHeader() || first_ == NULL); HEnvironment* incoming_env = pred->last_environment(); if (IsLoopHeader()) { DCHECK_EQ(phis()->length(), incoming_env->length()); for (int i = 0; i < phis_.length(); ++i) { phis_[i]->AddInput(incoming_env->values()->at(i)); } } else { last_environment()->AddIncomingEdge(this, pred->last_environment()); } } else if (!HasEnvironment() && !IsFinished()) { DCHECK(!IsLoopHeader()); SetInitialEnvironment(pred->last_environment()->Copy()); } predecessors_.Add(pred, zone()); } void HBasicBlock::AddDominatedBlock(HBasicBlock* block) { DCHECK(!dominated_blocks_.Contains(block)); // Keep the list of dominated blocks sorted such that if there is two // succeeding block in this list, the predecessor is before the successor. int index = 0; while (index < dominated_blocks_.length() && dominated_blocks_[index]->block_id() < block->block_id()) { ++index; } dominated_blocks_.InsertAt(index, block, zone()); } void HBasicBlock::AssignCommonDominator(HBasicBlock* other) { if (dominator_ == NULL) { dominator_ = other; other->AddDominatedBlock(this); } else if (other->dominator() != NULL) { HBasicBlock* first = dominator_; HBasicBlock* second = other; while (first != second) { if (first->block_id() > second->block_id()) { first = first->dominator(); } else { second = second->dominator(); } DCHECK(first != NULL && second != NULL); } if (dominator_ != first) { DCHECK(dominator_->dominated_blocks_.Contains(this)); dominator_->dominated_blocks_.RemoveElement(this); dominator_ = first; first->AddDominatedBlock(this); } } } 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. DCHECK(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. DCHECK(successor->block_id() > dominator_candidate->block_id() || successor->IsLoopHeader()); outstanding_successors++; } } } } int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const { for (int i = 0; i < predecessors_.length(); ++i) { if (predecessors_[i] == predecessor) return i; } UNREACHABLE(); return -1; } #ifdef DEBUG void HBasicBlock::Verify() { // Check that every block is finished. DCHECK(IsFinished()); DCHECK(block_id() >= 0); // Check that the incoming edges are in edge split form. if (predecessors_.length() > 1) { for (int i = 0; i < predecessors_.length(); ++i) { DCHECK(predecessors_[i]->end()->SecondSuccessor() == NULL); } } } #endif void HLoopInformation::RegisterBackEdge(HBasicBlock* block) { this->back_edges_.Add(block, block->zone()); AddBlock(block); } HBasicBlock* HLoopInformation::GetLastBackEdge() const { int max_id = -1; HBasicBlock* result = NULL; for (int i = 0; i < back_edges_.length(); ++i) { HBasicBlock* cur = back_edges_[i]; if (cur->block_id() > max_id) { max_id = cur->block_id(); result = cur; } } return result; } void HLoopInformation::AddBlock(HBasicBlock* block) { if (block == loop_header()) return; if (block->parent_loop_header() == loop_header()) return; if (block->parent_loop_header() != NULL) { AddBlock(block->parent_loop_header()); } else { block->set_parent_loop_header(loop_header()); blocks_.Add(block, block->zone()); for (int i = 0; i < block->predecessors()->length(); ++i) { AddBlock(block->predecessors()->at(i)); } } } #ifdef DEBUG // Checks reachability of the blocks in this graph and stores a bit in // the BitVector "reachable()" for every block that can be reached // from the start block of the graph. If "dont_visit" is non-null, the given // block is treated as if it would not be part of the graph. "visited_count()" // returns the number of reachable blocks. class ReachabilityAnalyzer BASE_EMBEDDED { public: ReachabilityAnalyzer(HBasicBlock* entry_block, int block_count, HBasicBlock* dont_visit) : visited_count_(0), stack_(16, entry_block->zone()), reachable_(block_count, entry_block->zone()), dont_visit_(dont_visit) { PushBlock(entry_block); Analyze(); } int visited_count() const { return visited_count_; } const BitVector* reachable() const { return &reachable_; } private: void PushBlock(HBasicBlock* block) { if (block != NULL && block != dont_visit_ && !reachable_.Contains(block->block_id())) { reachable_.Add(block->block_id()); stack_.Add(block, block->zone()); visited_count_++; } } void Analyze() { while (!stack_.is_empty()) { HControlInstruction* end = stack_.RemoveLast()->end(); for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { PushBlock(it.Current()); } } } int visited_count_; ZoneList stack_; BitVector reachable_; HBasicBlock* dont_visit_; }; void HGraph::Verify(bool do_full_verify) const { Heap::RelocationLock relocation_lock(isolate()->heap()); AllowHandleDereference allow_deref; AllowDeferredHandleDereference allow_deferred_deref; for (int i = 0; i < blocks_.length(); i++) { HBasicBlock* block = blocks_.at(i); block->Verify(); // Check that every block contains at least one node and that only the last // node is a control instruction. HInstruction* current = block->first(); DCHECK(current != NULL && current->IsBlockEntry()); while (current != NULL) { DCHECK((current->next() == NULL) == current->IsControlInstruction()); DCHECK(current->block() == block); current->Verify(); current = current->next(); } // Check that successors are correctly set. HBasicBlock* first = block->end()->FirstSuccessor(); HBasicBlock* second = block->end()->SecondSuccessor(); DCHECK(second == NULL || first != NULL); // Check that the predecessor array is correct. if (first != NULL) { DCHECK(first->predecessors()->Contains(block)); if (second != NULL) { DCHECK(second->predecessors()->Contains(block)); } } // Check that phis have correct arguments. for (int j = 0; j < block->phis()->length(); j++) { HPhi* phi = block->phis()->at(j); phi->Verify(); } // Check that all join blocks have predecessors that end with an // unconditional goto and agree on their environment node id. if (block->predecessors()->length() >= 2) { BailoutId id = block->predecessors()->first()->last_environment()->ast_id(); for (int k = 0; k < block->predecessors()->length(); k++) { HBasicBlock* predecessor = block->predecessors()->at(k); DCHECK(predecessor->end()->IsGoto() || predecessor->end()->IsDeoptimize()); DCHECK(predecessor->last_environment()->ast_id() == id); } } } // Check special property of first block to have no predecessors. DCHECK(blocks_.at(0)->predecessors()->is_empty()); if (do_full_verify) { // Check that the graph is fully connected. ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL); DCHECK(analyzer.visited_count() == blocks_.length()); // Check that entry block dominator is NULL. DCHECK(entry_block_->dominator() == NULL); // Check dominators. for (int i = 0; i < blocks_.length(); ++i) { HBasicBlock* block = blocks_.at(i); if (block->dominator() == NULL) { // Only start block may have no dominator assigned to. DCHECK(i == 0); } else { // Assert that block is unreachable if dominator must not be visited. ReachabilityAnalyzer dominator_analyzer(entry_block_, blocks_.length(), block->dominator()); DCHECK(!dominator_analyzer.reachable()->Contains(block->block_id())); } } } } #endif HConstant* HGraph::GetConstant(SetOncePointer* pointer, int32_t value) { if (!pointer->is_set()) { // Can't pass GetInvalidContext() to HConstant::New, because that will // recursively call GetConstant HConstant* constant = HConstant::New(isolate(), zone(), NULL, value); constant->InsertAfter(entry_block()->first()); pointer->set(constant); return constant; } return ReinsertConstantIfNecessary(pointer->get()); } HConstant* HGraph::ReinsertConstantIfNecessary(HConstant* constant) { if (!constant->IsLinked()) { // The constant was removed from the graph. Reinsert. constant->ClearFlag(HValue::kIsDead); constant->InsertAfter(entry_block()->first()); } return constant; } HConstant* HGraph::GetConstant0() { return GetConstant(&constant_0_, 0); } HConstant* HGraph::GetConstant1() { return GetConstant(&constant_1_, 1); } HConstant* HGraph::GetConstantMinus1() { return GetConstant(&constant_minus1_, -1); } HConstant* HGraph::GetConstantBool(bool value) { return value ? GetConstantTrue() : GetConstantFalse(); } #define DEFINE_GET_CONSTANT(Name, name, constant, type, htype, boolean_value, \ undetectable) \ HConstant* HGraph::GetConstant##Name() { \ if (!constant_##name##_.is_set()) { \ HConstant* constant = new (zone()) HConstant( \ Unique::CreateImmovable(isolate()->factory()->constant()), \ Unique::CreateImmovable(isolate()->factory()->type##_map()), \ false, Representation::Tagged(), htype, true, boolean_value, \ undetectable, ODDBALL_TYPE); \ constant->InsertAfter(entry_block()->first()); \ constant_##name##_.set(constant); \ } \ return ReinsertConstantIfNecessary(constant_##name##_.get()); \ } DEFINE_GET_CONSTANT(Undefined, undefined, undefined_value, undefined, HType::Undefined(), false, true) DEFINE_GET_CONSTANT(True, true, true_value, boolean, HType::Boolean(), true, false) DEFINE_GET_CONSTANT(False, false, false_value, boolean, HType::Boolean(), false, false) DEFINE_GET_CONSTANT(Hole, the_hole, the_hole_value, the_hole, HType::None(), false, false) DEFINE_GET_CONSTANT(Null, null, null_value, null, HType::Null(), false, true) DEFINE_GET_CONSTANT(OptimizedOut, optimized_out, optimized_out, optimized_out, HType::None(), false, false) #undef DEFINE_GET_CONSTANT #define DEFINE_IS_CONSTANT(Name, name) \ bool HGraph::IsConstant##Name(HConstant* constant) { \ return constant_##name##_.is_set() && constant == constant_##name##_.get(); \ } DEFINE_IS_CONSTANT(Undefined, undefined) DEFINE_IS_CONSTANT(0, 0) DEFINE_IS_CONSTANT(1, 1) DEFINE_IS_CONSTANT(Minus1, minus1) DEFINE_IS_CONSTANT(True, true) DEFINE_IS_CONSTANT(False, false) DEFINE_IS_CONSTANT(Hole, the_hole) DEFINE_IS_CONSTANT(Null, null) #undef DEFINE_IS_CONSTANT HConstant* HGraph::GetInvalidContext() { return GetConstant(&constant_invalid_context_, 0xFFFFC0C7); } bool HGraph::IsStandardConstant(HConstant* constant) { if (IsConstantUndefined(constant)) return true; if (IsConstant0(constant)) return true; if (IsConstant1(constant)) return true; if (IsConstantMinus1(constant)) return true; if (IsConstantTrue(constant)) return true; if (IsConstantFalse(constant)) return true; if (IsConstantHole(constant)) return true; if (IsConstantNull(constant)) return true; return false; } HGraphBuilder::IfBuilder::IfBuilder() : builder_(NULL), needs_compare_(true) {} HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder) : needs_compare_(true) { Initialize(builder); } HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, HIfContinuation* continuation) : needs_compare_(false), first_true_block_(NULL), first_false_block_(NULL) { InitializeDontCreateBlocks(builder); continuation->Continue(&first_true_block_, &first_false_block_); } void HGraphBuilder::IfBuilder::InitializeDontCreateBlocks( HGraphBuilder* builder) { builder_ = builder; finished_ = false; did_then_ = false; did_else_ = false; did_else_if_ = false; did_and_ = false; did_or_ = false; captured_ = false; pending_merge_block_ = false; split_edge_merge_block_ = NULL; merge_at_join_blocks_ = NULL; normal_merge_at_join_block_count_ = 0; deopt_merge_at_join_block_count_ = 0; } void HGraphBuilder::IfBuilder::Initialize(HGraphBuilder* builder) { InitializeDontCreateBlocks(builder); HEnvironment* env = builder->environment(); first_true_block_ = builder->CreateBasicBlock(env->Copy()); first_false_block_ = builder->CreateBasicBlock(env->Copy()); } HControlInstruction* HGraphBuilder::IfBuilder::AddCompare( HControlInstruction* compare) { DCHECK(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 = 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); } builder()->GotoNoSimulate(split_edge, split_edge_merge_block_); } else { compare->SetSuccessorAt(0, first_true_block_); compare->SetSuccessorAt(1, first_false_block_); } builder()->FinishCurrentBlock(compare); needs_compare_ = false; return compare; } void HGraphBuilder::IfBuilder::Or() { DCHECK(!needs_compare_); DCHECK(!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()); builder()->GotoNoSimulate(first_true_block_, 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() { DCHECK(!needs_compare_); DCHECK(!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()); builder()->GotoNoSimulate(first_false_block_, split_edge_merge_block_); first_false_block_ = split_edge_merge_block_; } builder()->set_current_block(first_true_block_); first_true_block_ = builder()->CreateBasicBlock(env->Copy()); } void HGraphBuilder::IfBuilder::CaptureContinuation( HIfContinuation* continuation) { DCHECK(!did_else_if_); DCHECK(!finished_); DCHECK(!captured_); HBasicBlock* true_block = NULL; HBasicBlock* false_block = NULL; Finish(&true_block, &false_block); DCHECK(true_block != NULL); DCHECK(false_block != NULL); continuation->Capture(true_block, false_block); captured_ = true; builder()->set_current_block(NULL); End(); } void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) { DCHECK(!did_else_if_); DCHECK(!finished_); DCHECK(!captured_); 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()) { DCHECK(continuation->IsTrueReachable()); builder()->GotoNoSimulate(true_block, continuation->true_branch()); } if (false_block != NULL && !false_block->IsFinished()) { DCHECK(continuation->IsFalseReachable()); builder()->GotoNoSimulate(false_block, continuation->false_branch()); } captured_ = true; End(); } void HGraphBuilder::IfBuilder::Then() { DCHECK(!captured_); DCHECK(!finished_); did_then_ = true; if (needs_compare_) { // Handle if's without any expressions, they jump directly to the "else" // branch. However, we must pretend that the "then" branch is reachable, // so that the graph builder visits it and sees any live range extending // constructs within it. HConstant* constant_false = builder()->graph()->GetConstantFalse(); ToBooleanHints boolean_type = ToBooleanHint::kBoolean; HBranch* branch = builder()->New( constant_false, boolean_type, first_true_block_, first_false_block_); builder()->FinishCurrentBlock(branch); } builder()->set_current_block(first_true_block_); pending_merge_block_ = true; } void HGraphBuilder::IfBuilder::Else() { DCHECK(did_then_); DCHECK(!captured_); DCHECK(!finished_); AddMergeAtJoinBlock(false); builder()->set_current_block(first_false_block_); pending_merge_block_ = true; did_else_ = true; } void HGraphBuilder::IfBuilder::Deopt(DeoptimizeReason reason) { DCHECK(did_then_); builder()->Add(reason, Deoptimizer::EAGER); AddMergeAtJoinBlock(true); } void HGraphBuilder::IfBuilder::Return(HValue* value) { HValue* parameter_count = builder()->graph()->GetConstantMinus1(); builder()->FinishExitCurrentBlock( builder()->New(value, parameter_count)); AddMergeAtJoinBlock(false); } void HGraphBuilder::IfBuilder::AddMergeAtJoinBlock(bool deopt) { if (!pending_merge_block_) return; HBasicBlock* block = builder()->current_block(); DCHECK(block == NULL || !block->IsFinished()); MergeAtJoinBlock* record = new (builder()->zone()) MergeAtJoinBlock(block, deopt, merge_at_join_blocks_); merge_at_join_blocks_ = record; if (block != NULL) { DCHECK(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() { DCHECK(!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_; } DCHECK(then_record->next_ == NULL); } void HGraphBuilder::IfBuilder::EndUnreachable() { if (captured_) return; Finish(); builder()->set_current_block(nullptr); } void HGraphBuilder::IfBuilder::End() { if (captured_) return; Finish(); int total_merged_blocks = normal_merge_at_join_block_count_ + deopt_merge_at_join_block_count_; DCHECK(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()->GotoNoSimulate(current->block_, merge_block); } current = current->next_; } // Merge deopt blocks, padding when necessary. current = merge_at_join_blocks_; while (current != NULL) { if (current->deopt_ && current->block_ != NULL) { current->block_->FinishExit( HAbnormalExit::New(builder()->isolate(), builder()->zone(), NULL), SourcePosition::Unknown()); } current = current->next_; } builder()->set_current_block(merge_block); } HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder) { Initialize(builder, NULL, kWhileTrue, NULL); } HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context, LoopBuilder::Direction direction) { Initialize(builder, context, direction, builder->graph()->GetConstant1()); } HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context, LoopBuilder::Direction direction, HValue* increment_amount) { Initialize(builder, context, direction, increment_amount); increment_amount_ = increment_amount; } void HGraphBuilder::LoopBuilder::Initialize(HGraphBuilder* builder, HValue* context, Direction direction, HValue* increment_amount) { builder_ = builder; context_ = context; direction_ = direction; increment_amount_ = increment_amount; finished_ = false; header_block_ = builder->CreateLoopHeaderBlock(); body_block_ = NULL; exit_block_ = NULL; exit_trampoline_block_ = NULL; } HValue* HGraphBuilder::LoopBuilder::BeginBody( HValue* initial, HValue* terminating, Token::Value token) { DCHECK(direction_ != kWhileTrue); HEnvironment* env = builder_->environment(); phi_ = header_block_->AddNewPhi(env->values()->length()); phi_->AddInput(initial); env->Push(initial); builder_->GotoNoSimulate(header_block_); HEnvironment* body_env = env->Copy(); HEnvironment* exit_env = env->Copy(); // Remove the phi from the expression stack body_env->Pop(); exit_env->Pop(); body_block_ = builder_->CreateBasicBlock(body_env); exit_block_ = builder_->CreateBasicBlock(exit_env); builder_->set_current_block(header_block_); env->Pop(); builder_->FinishCurrentBlock(builder_->New( phi_, terminating, token, body_block_, exit_block_)); builder_->set_current_block(body_block_); if (direction_ == kPreIncrement || direction_ == kPreDecrement) { Isolate* isolate = builder_->isolate(); HValue* one = builder_->graph()->GetConstant1(); if (direction_ == kPreIncrement) { increment_ = HAdd::New(isolate, zone(), context_, phi_, one); } else { increment_ = HSub::New(isolate, zone(), context_, phi_, one); } increment_->ClearFlag(HValue::kCanOverflow); builder_->AddInstruction(increment_); return increment_; } else { return phi_; } } void HGraphBuilder::LoopBuilder::BeginBody(int drop_count) { DCHECK(direction_ == kWhileTrue); HEnvironment* env = builder_->environment(); builder_->GotoNoSimulate(header_block_); builder_->set_current_block(header_block_); env->Drop(drop_count); } void HGraphBuilder::LoopBuilder::Break() { if (exit_trampoline_block_ == NULL) { // Its the first time we saw a break. if (direction_ == kWhileTrue) { HEnvironment* env = builder_->environment()->Copy(); exit_trampoline_block_ = builder_->CreateBasicBlock(env); } else { HEnvironment* env = exit_block_->last_environment()->Copy(); exit_trampoline_block_ = builder_->CreateBasicBlock(env); builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_); } } builder_->GotoNoSimulate(exit_trampoline_block_); builder_->set_current_block(NULL); } void HGraphBuilder::LoopBuilder::EndBody() { DCHECK(!finished_); if (direction_ == kPostIncrement || direction_ == kPostDecrement) { Isolate* isolate = builder_->isolate(); if (direction_ == kPostIncrement) { increment_ = HAdd::New(isolate, zone(), context_, phi_, increment_amount_); } else { increment_ = HSub::New(isolate, zone(), context_, phi_, increment_amount_); } increment_->ClearFlag(HValue::kCanOverflow); builder_->AddInstruction(increment_); } if (direction_ != kWhileTrue) { // Push the new increment value on the expression stack to merge into // the phi. builder_->environment()->Push(increment_); } HBasicBlock* last_block = builder_->current_block(); builder_->GotoNoSimulate(last_block, header_block_); header_block_->loop_information()->RegisterBackEdge(last_block); if (exit_trampoline_block_ != NULL) { builder_->set_current_block(exit_trampoline_block_); } else { builder_->set_current_block(exit_block_); } finished_ = true; } HGraph* HGraphBuilder::CreateGraph() { DCHECK(!FLAG_minimal); graph_ = new (zone()) HGraph(info_, descriptor_); if (FLAG_hydrogen_stats) isolate()->GetHStatistics()->Initialize(info_); if (!info_->IsStub() && is_tracking_positions()) { TraceInlinedFunction(info_->shared_info(), SourcePosition::Unknown(), SourcePosition::kNotInlined); } CompilationPhase phase("H_Block building", info_); set_current_block(graph()->entry_block()); if (!BuildGraph()) return NULL; graph()->FinalizeUniqueness(); return graph_; } void HGraphBuilder::TraceInlinedFunction(Handle shared, SourcePosition position, int inlining_id) { DCHECK(is_tracking_positions()); if (!shared->script()->IsUndefined(isolate())) { Handle 登录后可以享受更多权益 您还没有登录,登录后您可以: 收藏Android系统代码 收藏喜欢的文章 多个平台共享账号 去登录 首次使用?从这里 注册
您还没有登录,登录后您可以:
首次使用?从这里 注册