Fix bugs in IfBuilder and improve functionality
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
This commit is contained in:
parent
c47af882ba
commit
fded35e019
@ -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.
|
||||
|
@ -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();
|
||||
|
||||
|
385
src/hydrogen.cc
385
src/hydrogen.cc
@ -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);
|
||||
builder_->set_current_block(first_true_block_);
|
||||
return compare;
|
||||
needs_compare_ = false;
|
||||
}
|
||||
|
||||
|
||||
void HGraphBuilder::IfBuilder::BeginElse() {
|
||||
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_);
|
||||
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::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());
|
||||
}
|
||||
|
193
src/hydrogen.h
193
src/hydrogen.h
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user