}
-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;
last_environment_ = last_environment()->DiscardInlined(drop_extra);
}
- AddSimulate(BailoutId::None());
+ if (add_simulate) AddSimulate(BailoutId::None());
HGoto* instr = new(zone()) HGoto(block);
Finish(instr);
}
#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;
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;
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;
}
}
- 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;
}
-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,
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);
+ needs_compare_ = false;
+}
+
+
+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_);
- return compare;
+ 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::BeginElse() {
+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;
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();
// 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
ASSERT(current_block() != NULL);
ASSERT(no_side_effects_scope_count_ == 0);
current_block()->AddSimulate(id, removable);
- environment()->set_ast_id(id);
}
}
+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,
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();
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();
length_store->SetGVNFlag(kChangesArrayLengths);
}
- length_checker.BeginElse();
+ length_checker.Else();
AddBoundsCheck(key, length, ALLOW_SMI_KEY);
environment()->Push(elements);
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);
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();
HValue* HGraphBuilder::BuildAllocateElements(HValue* context,
ElementsKind kind,
- HValue* capacity,
- BailoutId ast_id) {
+ HValue* capacity) {
Zone* zone = this->zone();
int elements_size = IsFastDoubleElementsKind(kind)
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;
}
HValue* elements,
ElementsKind kind,
HValue* length,
- HValue* new_capacity,
- BailoutId ast_id) {
+ HValue* new_capacity) {
Zone* zone = this->zone();
HValue* context = environment()->LookupContext();
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(
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();
: 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);
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);
// 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);
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);
}
}
}
+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)) {
}
+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();
}
+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
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());
}
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,
ARGUMENTS_ALLOWED
};
+
+class HIfContinuation;
+
// This class is not BASE_EMBEDDED because our inlining implementation uses
// new and delete.
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_; }
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);
};
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; }
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());
};
+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)
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,
class CheckBuilder {
public:
- explicit CheckBuilder(HGraphBuilder* builder, BailoutId id);
+ explicit CheckBuilder(HGraphBuilder* builder);
~CheckBuilder() {
if (!finished_) End();
}
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 {
LoopBuilder(HGraphBuilder* builder,
HValue* context,
- Direction direction,
- BailoutId id);
+ Direction direction);
~LoopBuilder() {
ASSERT(finished_);
}
HBasicBlock* body_block_;
HBasicBlock* exit_block_;
Direction direction_;
- BailoutId id_;
bool finished_;
};
HValue* BuildAllocateElements(HValue* context,
ElementsKind kind,
- HValue* capacity,
- BailoutId ast_id);
+ HValue* capacity);
void BuildInitializeElements(HValue* elements,
ElementsKind kind,
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,
HValue* to_elements,
ElementsKind to_elements_kind,
HValue* length,
- HValue* capacity,
- BailoutId ast_id);
+ HValue* capacity);
HValue* BuildCloneShallowArray(HContext* context,
HValue* boilerplate,