Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index f62a2835fcca26a4e8a75f1ee2ef31d5e19486a0..00207c142f44d528805a7172698ae09cf21388a2 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(); |
+ HEnvironment* true_env = env->Copy(); |
+ HEnvironment* false_env = env->Copy(); |
+ HEnvironment* 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(); |
+ HEnvironment* body_env = env->Copy(); |
+ HEnvironment* 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_); |
+ } |
+ |
+ builder_->environment()->Push(increment_); |
+ 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,109 @@ 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<Map> map = IsFastDoubleElementsKind(kind) |
+ ? factory->fixed_double_array_map() |
+ : factory->fixed_array_map(); |
+ BuildStoreMap(elements, map, BailoutId::StubEntry()); |
+ |
+ 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; |
+} |
+ |
+ |
+HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, |
+ HValue* map, |
+ BailoutId id) { |
+ Zone* zone = this->zone(); |
+ Isolate* isolate = graph()->isolate(); |
+ Factory* factory = isolate->factory(); |
+ Handle<String> map_field_name = factory->map_field_symbol(); |
+ HInstruction* store_map = |
+ new(zone) HStoreNamedField(object, map_field_name, map, |
+ true, JSObject::kMapOffset); |
+ store_map->SetGVNFlag(kChangesMaps); |
+ AddInstruction(store_map); |
+ AddSimulate(id, FIXED_SIMULATE); |
+ return store_map; |
+} |
+ |
+ |
+HInstruction* HGraphBuilder::BuildStoreMap(HValue* object, |
+ Handle<Map> map, |
+ BailoutId id) { |
+ Zone* zone = this->zone(); |
+ HValue* map_constant = |
+ AddInstruction(new(zone) HConstant(map, Representation::Tagged())); |
+ return BuildStoreMap(object, map_constant, id); |
+} |
+ |
+ |
+void HGraphBuilder::BuildCopyElements(HContext* context, |
+ 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 +2505,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 +3757,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 +3827,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); |
@@ -4201,22 +4453,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); |
@@ -6538,8 +6774,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; |
@@ -9791,7 +10028,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), |
@@ -9846,6 +10083,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_; |
} |