Chromium Code Reviews| Index: src/hydrogen.cc |
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
| index e567e1cdb193bd7720bf8d6787e693ff9f53b89b..81acb15938c517a361bc6603ee48077425813ab7 100644 |
| --- a/src/hydrogen.cc |
| +++ b/src/hydrogen.cc |
| @@ -221,8 +221,9 @@ void HBasicBlock::SetJoinId(BailoutId ast_id) { |
| HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); |
| // We only need to verify the ID once. |
| ASSERT(i != 0 || |
| - predecessor->last_environment()->closure()->shared() |
| - ->VerifyBailoutId(ast_id)); |
| + (predecessor->last_environment()->closure().is_null() || |
| + predecessor->last_environment()->closure()->shared() |
| + ->VerifyBailoutId(ast_id))); |
| simulate->set_ast_id(ast_id); |
| } |
| } |
| @@ -602,6 +603,11 @@ HConstant* HGraph::GetConstantInt32(SetOncePointer<HConstant>* pointer, |
| } |
| +HConstant* HGraph::GetConstant0() { |
| + return GetConstantInt32(&constant_0_, 0); |
| +} |
| + |
| + |
| HConstant* HGraph::GetConstant1() { |
| return GetConstantInt32(&constant_1_, 1); |
| } |
| @@ -627,6 +633,128 @@ HConstant* HGraph::GetConstantHole() { |
| } |
| +HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, BailoutId id) |
| + : builder_(builder), |
| + finished_(false), |
| + id_(id) { |
| + HEnvironment* env = builder->environment(); |
| + true_env_ = env->Copy(); |
|
Michael Starzinger
2013/02/01 13:15:08
I think it is safer not to preserve these environm
danno
2013/02/02 17:56:21
Done.
|
| + false_env_ = env->Copy(); |
| + merge_env_ = env->Copy(); |
| + true_block_ = builder->CreateBasicBlock(true_env_); |
| + false_block_ = builder->CreateBasicBlock(false_env_); |
| + merge_block_ = builder->CreateBasicBlock(merge_env_); |
| +} |
| + |
| + |
| +void HGraphBuilder::IfBuilder::BeginTrue(HValue* left, |
| + HValue* right, |
| + Token::Value token) { |
| + HCompareIDAndBranch* compare = |
| + new(zone()) HCompareIDAndBranch(left, right, token); |
| + compare->ChangeRepresentation(Representation::Integer32()); |
| + compare->SetSuccessorAt(0, true_block_); |
| + compare->SetSuccessorAt(1, false_block_); |
| + builder_->current_block()->Finish(compare); |
| + builder_->set_current_block(true_block_); |
| +} |
| + |
| + |
| +void HGraphBuilder::IfBuilder::BeginFalse() { |
| + builder_->current_block()->Goto(merge_block_); |
| + builder_->set_current_block(false_block_); |
| +} |
| + |
| + |
| +void HGraphBuilder::IfBuilder::End() { |
| + ASSERT(!finished_); |
| + builder_->current_block()->Goto(merge_block_); |
| + builder_->set_current_block(merge_block_); |
| + merge_block_->SetJoinId(id_); |
| + finished_ = true; |
| +} |
| + |
| + |
| +HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, |
| + HValue* context, |
| + LoopBuilder::Direction direction, |
| + BailoutId id) |
| + : builder_(builder), |
| + context_(context), |
| + direction_(direction), |
| + id_(id), |
| + finished_(false) { |
| + HEnvironment* env = builder_->environment(); |
| + body_env_ = env->Copy(); |
|
Michael Starzinger
2013/02/01 13:15:08
Likewise.
danno
2013/02/02 17:56:21
Done.
|
| + exit_env_ = env->Copy(); |
| + header_block_ = builder->CreateLoopHeaderBlock(); |
| + body_block_ = builder->CreateBasicBlock(body_env_); |
| + exit_block_ = builder->CreateBasicBlock(exit_env_); |
| +} |
| + |
| + |
| +HValue* HGraphBuilder::LoopBuilder::BeginBody(HValue* initial, |
| + HValue* terminating, |
| + Token::Value token) { |
| + phi_ = new(zone()) HPhi(0, zone()); |
| + header_block_->AddPhi(phi_); |
| + phi_->AddInput(initial); |
| + phi_->ChangeRepresentation(Representation::Integer32()); |
| + HEnvironment* env = builder_->environment(); |
| + env->Push(initial); |
| + builder_->current_block()->Goto(header_block_); |
| + builder_->set_current_block(header_block_); |
| + |
| + builder_->set_current_block(header_block_); |
| + HCompareIDAndBranch* compare = |
| + new(zone()) HCompareIDAndBranch(phi_, terminating, token); |
| + compare->ChangeRepresentation(Representation::Integer32()); |
| + compare->SetSuccessorAt(0, body_block_); |
| + compare->SetSuccessorAt(1, exit_block_); |
| + builder_->current_block()->Finish(compare); |
| + |
| + builder_->set_current_block(body_block_); |
| + if (direction_ == kPreIncrement || direction_ == kPreDecrement) { |
| + HValue* one = builder_->graph()->GetConstant1(); |
| + if (direction_ == kPreIncrement) { |
| + increment_ = new(zone()) HAdd(context_, phi_, one); |
| + } else { |
| + increment_ = new(zone()) HSub(context_, phi_, one); |
| + } |
| + increment_->ClearFlag(HValue::kCanOverflow); |
| + increment_->ChangeRepresentation(Representation::Integer32()); |
| + builder_->AddInstruction(increment_); |
| + return increment_; |
| + } else { |
| + return phi_; |
| + } |
| +} |
| + |
| + |
| +void HGraphBuilder::LoopBuilder::EndBody() { |
| + ASSERT(!finished_); |
| + |
| + if (direction_ == kPostIncrement || direction_ == kPostDecrement) { |
| + HValue* one = builder_->graph()->GetConstant1(); |
| + if (direction_ == kPostIncrement) { |
| + increment_ = new(zone()) HAdd(context_, phi_, one); |
| + } else { |
| + increment_ = new(zone()) HSub(context_, phi_, one); |
| + } |
| + increment_->ClearFlag(HValue::kCanOverflow); |
| + increment_->ChangeRepresentation(Representation::Integer32()); |
| + builder_->AddInstruction(increment_); |
| + } |
| + |
| + body_env_->Push(increment_); |
|
Michael Starzinger
2013/02/01 13:15:08
The body_env_ might be a stale environment in case
danno
2013/02/02 17:56:21
Done.
|
| + builder_->current_block()->Goto(header_block_); |
| + header_block_->loop_information()->RegisterBackEdge(body_block_); |
| + header_block_->SetJoinId(BailoutId::StubEntry()); |
| + builder_->set_current_block(exit_block_); |
| + finished_ = true; |
| +} |
| + |
| + |
| HGraph* HGraphBuilder::CreateGraph() { |
| graph_ = new(zone()) HGraph(info_); |
| if (FLAG_hydrogen_stats) HStatistics::Instance()->Initialize(info_); |
| @@ -651,6 +779,22 @@ void HGraphBuilder::AddSimulate(BailoutId id, |
| } |
| +HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { |
| + HBasicBlock* b = graph()->CreateBasicBlock(); |
| + b->SetInitialEnvironment(env); |
| + return b; |
| +} |
| + |
| + |
| +HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { |
| + HBasicBlock* header = graph()->CreateBasicBlock(); |
| + HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); |
| + header->SetInitialEnvironment(entry_env); |
| + header->AttachLoopInformation(); |
| + return header; |
| +} |
| + |
| + |
| HInstruction* HGraphBuilder::BuildExternalArrayElementAccess( |
| HValue* external_elements, |
| HValue* checked_key, |
| @@ -799,6 +943,89 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
| } |
| +HValue* HGraphBuilder::BuildAllocateElements(HContext* context, |
| + ElementsKind kind, |
| + HValue* capacity) { |
| + Zone* zone = this->zone(); |
| + |
| + int elements_size = IsFastDoubleElementsKind(kind) |
| + ? kDoubleSize : kPointerSize; |
| + HConstant* elements_size_value = |
| + new(zone) HConstant(elements_size, Representation::Integer32()); |
| + AddInstruction(elements_size_value); |
| + HValue* mul = AddInstruction( |
| + new(zone) HMul(context, capacity, elements_size_value)); |
| + mul->ChangeRepresentation(Representation::Integer32()); |
| + mul->ClearFlag(HValue::kCanOverflow); |
| + |
| + HConstant* header_size = |
| + new(zone) HConstant(FixedArray::kHeaderSize, Representation::Integer32()); |
| + AddInstruction(header_size); |
| + HValue* total_size = AddInstruction( |
| + new(zone) HAdd(context, mul, header_size)); |
| + total_size->ChangeRepresentation(Representation::Integer32()); |
| + total_size->ClearFlag(HValue::kCanOverflow); |
| + |
| + HAllocate::Flags flags = HAllocate::CAN_ALLOCATE_IN_NEW_SPACE; |
| + if (IsFastDoubleElementsKind(kind)) { |
| + flags = static_cast<HAllocate::Flags>( |
| + flags | HAllocate::ALLOCATE_DOUBLE_ALIGNED); |
| + } |
| + |
| + HValue* elements = |
| + AddInstruction(new(zone) HAllocate(context, total_size, |
| + HType::JSArray(), flags)); |
| + Isolate* isolate = graph()->isolate(); |
| + |
| + Factory* factory = isolate->factory(); |
| + Handle<String> map_field_name = factory->map_field_symbol(); |
| + Handle<Map> map = IsFastDoubleElementsKind(kind) |
| + ? factory->fixed_double_array_map() |
| + : factory->fixed_array_map(); |
| + HValue* map_constant = |
| + AddInstruction(new(zone) HConstant(map, Representation::Tagged())); |
| + HInstruction* store_map = |
| + new(zone) HStoreNamedField(elements, map_field_name, map_constant, |
|
Michael Starzinger
2013/02/01 13:15:08
Strictly speaking this store needs to have the kCh
danno
2013/02/02 17:56:21
Done.
|
| + true, JSObject::kMapOffset); |
| + AddInstruction(store_map); |
| + AddSimulate(BailoutId::StubEntry(), FIXED_SIMULATE); |
| + |
| + Handle<String> fixed_array_length_field_name = |
| + isolate->factory()->length_field_symbol(); |
| + HInstruction* store_length = |
| + new(zone) HStoreNamedField(elements, fixed_array_length_field_name, |
| + capacity, true, FixedArray::kLengthOffset); |
| + AddInstruction(store_length); |
| + AddSimulate(BailoutId::StubEntry(), FIXED_SIMULATE); |
| + |
| + return elements; |
| +} |
| + |
| + |
| +void HGraphBuilder::BuildCopyElements(HContext* context, |
|
Michael Starzinger
2013/02/01 13:15:08
Beautifully simple, me gusta!
danno
2013/02/02 17:56:21
Done.
|
| + HValue* from_elements, |
| + ElementsKind from_elements_kind, |
| + HValue* to_elements, |
| + ElementsKind to_elements_kind, |
| + HValue* length) { |
| + LoopBuilder builder(this, context, LoopBuilder::kPostIncrement); |
| + |
| + HValue* key = builder.BeginBody(graph()->GetConstant0(), |
| + length, Token::LT); |
| + |
| + HValue* element = |
| + AddInstruction(new(zone()) HLoadKeyed(from_elements, key, NULL, |
| + from_elements_kind, |
| + ALLOW_RETURN_HOLE)); |
| + |
| + AddInstruction(new(zone()) HStoreKeyed(to_elements, key, element, |
| + to_elements_kind)); |
| + AddSimulate(BailoutId::StubEntry(), REMOVABLE_SIMULATE); |
| + |
| + builder.EndBody(); |
| +} |
| + |
| + |
| HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info, |
| TypeFeedbackOracle* oracle) |
| : HGraphBuilder(info), |
| @@ -2258,7 +2485,7 @@ void HGlobalValueNumberer::ProcessLoopBlock( |
| bool HGlobalValueNumberer::AllowCodeMotion() { |
| - return info()->opt_count() + 1 < FLAG_max_opt_count; |
| + return info()->IsStub() || info()->opt_count() + 1 < FLAG_max_opt_count; |
| } |
| @@ -3510,6 +3737,23 @@ bool HOptimizedGraphBuilder::BuildGraph() { |
| } |
| +void HGraph::GlobalValueNumbering() { |
| + // Perform common subexpression elimination and loop-invariant code motion. |
| + if (FLAG_use_gvn) { |
| + HPhase phase("H_Global value numbering", this); |
| + HGlobalValueNumberer gvn(this, info()); |
| + bool removed_side_effects = gvn.Analyze(); |
| + // Trigger a second analysis pass to further eliminate duplicate values that |
| + // could only be discovered by removing side-effect-generating instructions |
| + // during the first pass. |
| + if (FLAG_smi_only_arrays && removed_side_effects) { |
| + removed_side_effects = gvn.Analyze(); |
| + ASSERT(!removed_side_effects); |
| + } |
| + } |
| +} |
| + |
| + |
| bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) { |
| *bailout_reason = SmartArrayPointer<char>(); |
| OrderBlocks(); |
| @@ -3563,19 +3807,7 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) { |
| Canonicalize(); |
| - // Perform common subexpression elimination and loop-invariant code motion. |
| - if (FLAG_use_gvn) { |
| - HPhase phase("H_Global value numbering", this); |
| - HGlobalValueNumberer gvn(this, info()); |
| - bool removed_side_effects = gvn.Analyze(); |
| - // Trigger a second analysis pass to further eliminate duplicate values that |
| - // could only be discovered by removing side-effect-generating instructions |
| - // during the first pass. |
| - if (FLAG_smi_only_arrays && removed_side_effects) { |
| - removed_side_effects = gvn.Analyze(); |
| - ASSERT(!removed_side_effects); |
| - } |
| - } |
| + GlobalValueNumbering(); |
| if (FLAG_use_range) { |
| HRangeAnalysis rangeAnalysis(this); |
| @@ -4165,22 +4397,6 @@ void HOptimizedGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) { |
| } |
| -HBasicBlock* HOptimizedGraphBuilder::CreateBasicBlock(HEnvironment* env) { |
| - HBasicBlock* b = graph()->CreateBasicBlock(); |
| - b->SetInitialEnvironment(env); |
| - return b; |
| -} |
| - |
| - |
| -HBasicBlock* HOptimizedGraphBuilder::CreateLoopHeaderBlock() { |
| - HBasicBlock* header = graph()->CreateBasicBlock(); |
| - HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); |
| - header->SetInitialEnvironment(entry_env); |
| - header->AttachLoopInformation(); |
| - return header; |
| -} |
| - |
| - |
| void HOptimizedGraphBuilder::VisitBlock(Block* stmt) { |
| ASSERT(!HasStackOverflow()); |
| ASSERT(current_block() != NULL); |
| @@ -6502,8 +6718,9 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( |
| ASSERT(Map::IsValidElementsTransition( |
| map->elements_kind(), |
| transition_target.at(i)->elements_kind())); |
| + HValue* context = environment()->LookupContext(); |
| transition = new(zone()) HTransitionElementsKind( |
| - object, map, transition_target.at(i)); |
| + context, object, map, transition_target.at(i)); |
| AddInstruction(transition); |
| } else { |
| type_todo[map->elements_kind()] = true; |
| @@ -9755,7 +9972,7 @@ HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone) |
| : values_(0, zone), |
| frame_type_(JS_FUNCTION), |
| parameter_count_(0), |
| - specials_count_(1), |
| + specials_count_(0), |
| local_count_(0), |
| outer_(NULL), |
| entry_(NULL), |
| @@ -9810,6 +10027,7 @@ void HEnvironment::Initialize(const HEnvironment* other) { |
| entry_ = other->entry_; |
| pop_count_ = other->pop_count_; |
| push_count_ = other->push_count_; |
| + specials_count_ = other->specials_count_; |
| ast_id_ = other->ast_id_; |
| } |