Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(384)

Unified Diff: src/hydrogen.cc

Issue 6614010: [Isolates] Merge 6700:7030 from bleeding_edge to isolates. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/isolates/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/hydrogen.cc
===================================================================
--- src/hydrogen.cc (revision 7031)
+++ src/hydrogen.cc (working copy)
@@ -65,6 +65,7 @@
first_instruction_index_(-1),
last_instruction_index_(-1),
deleted_phis_(4),
+ parent_loop_header_(NULL),
is_inline_return_target_(false) {
}
@@ -105,21 +106,13 @@
if (first_ == NULL) {
HBlockEntry* entry = new HBlockEntry();
entry->InitializeAsFirst(this);
- first_ = entry;
+ first_ = last_ = entry;
}
- instr->InsertAfter(GetLastInstruction());
+ instr->InsertAfter(last_);
+ last_ = instr;
}
-HInstruction* HBasicBlock::GetLastInstruction() {
- if (end_ != NULL) return end_->previous();
- if (first_ == NULL) return NULL;
- if (last_ == NULL) last_ = first_;
- while (last_->next() != NULL) last_ = last_->next();
- return last_;
-}
-
-
HSimulate* HBasicBlock::CreateSimulate(int id) {
ASSERT(HasEnvironment());
HEnvironment* environment = last_environment();
@@ -177,7 +170,7 @@
for (int i = 0; i < length; i++) {
HBasicBlock* predecessor = predecessors_[i];
ASSERT(predecessor->end()->IsGoto());
- HSimulate* simulate = HSimulate::cast(predecessor->GetLastInstruction());
+ HSimulate* simulate = HSimulate::cast(predecessor->end()->previous());
// We only need to verify the ID once.
ASSERT(i != 0 ||
predecessor->last_environment()->closure()->shared()
@@ -293,20 +286,6 @@
// Check that every block is finished.
ASSERT(IsFinished());
ASSERT(block_id() >= 0);
-
- // Verify that all blocks targetting a branch target, have the same boolean
- // value on top of their expression stack.
- if (!cond().is_null()) {
- ASSERT(predecessors()->length() > 0);
- for (int i = 1; i < predecessors()->length(); i++) {
- HBasicBlock* pred = predecessors()->at(i);
- HValue* top = pred->last_environment()->Top();
- ASSERT(top->IsConstant());
- Object* a = *HConstant::cast(top)->handle();
- Object* b = *cond();
- ASSERT(a == b);
- }
- }
}
#endif
@@ -503,175 +482,57 @@
}
-void HSubgraph::AppendOptional(HSubgraph* graph,
- bool on_true_branch,
- HValue* value) {
- ASSERT(HasExit() && graph->HasExit());
- HBasicBlock* other_block = graph_->CreateBasicBlock();
- HBasicBlock* join_block = graph_->CreateBasicBlock();
-
- HTest* test = on_true_branch
- ? new HTest(value, graph->entry_block(), other_block)
- : new HTest(value, other_block, graph->entry_block());
- exit_block_->Finish(test);
- other_block->Goto(join_block);
- graph->exit_block()->Goto(join_block);
- exit_block_ = join_block;
-}
-
-
-void HSubgraph::AppendJoin(HSubgraph* then_graph,
- HSubgraph* else_graph,
- AstNode* node) {
- if (then_graph->HasExit() && else_graph->HasExit()) {
- // We need to merge, create new merge block.
+HBasicBlock* HGraphBuilder::CreateJoin(HBasicBlock* first,
+ HBasicBlock* second,
+ int join_id) {
+ if (first == NULL) {
+ return second;
+ } else if (second == NULL) {
+ return first;
+ } else {
HBasicBlock* join_block = graph_->CreateBasicBlock();
- then_graph->exit_block()->Goto(join_block);
- else_graph->exit_block()->Goto(join_block);
- join_block->SetJoinId(node->id());
- exit_block_ = join_block;
- } else if (then_graph->HasExit()) {
- exit_block_ = then_graph->exit_block_;
- } else if (else_graph->HasExit()) {
- exit_block_ = else_graph->exit_block_;
- } else {
- exit_block_ = NULL;
+ first->Goto(join_block);
+ second->Goto(join_block);
+ join_block->SetJoinId(join_id);
+ return join_block;
}
}
-void HSubgraph::ResolveContinue(IterationStatement* statement) {
- HBasicBlock* continue_block = BundleContinue(statement);
+HBasicBlock* HGraphBuilder::JoinContinue(IterationStatement* statement,
+ HBasicBlock* exit_block,
+ HBasicBlock* continue_block) {
if (continue_block != NULL) {
- exit_block_ = JoinBlocks(exit_block(),
- continue_block,
- statement->ContinueId());
+ if (exit_block != NULL) exit_block->Goto(continue_block);
+ continue_block->SetJoinId(statement->ContinueId());
+ return continue_block;
}
+ return exit_block;
}
-HBasicBlock* HSubgraph::BundleBreak(BreakableStatement* statement) {
- return BundleBreakContinue(statement, false, statement->ExitId());
-}
-
-
-HBasicBlock* HSubgraph::BundleContinue(IterationStatement* statement) {
- return BundleBreakContinue(statement, true, statement->ContinueId());
-}
-
-
-HBasicBlock* HSubgraph::BundleBreakContinue(BreakableStatement* statement,
- bool is_continue,
- int join_id) {
- HBasicBlock* result = NULL;
- const ZoneList<BreakContinueInfo*>* infos = break_continue_info();
- for (int i = 0; i < infos->length(); ++i) {
- BreakContinueInfo* info = infos->at(i);
- if (info->is_continue() == is_continue &&
- info->target() == statement &&
- !info->IsResolved()) {
- if (result == NULL) {
- result = graph_->CreateBasicBlock();
- }
- info->block()->Goto(result);
- info->Resolve();
- }
+HBasicBlock* HGraphBuilder::CreateLoop(IterationStatement* statement,
+ HBasicBlock* loop_entry,
+ HBasicBlock* body_exit,
+ HBasicBlock* loop_successor,
+ HBasicBlock* break_block) {
+ if (body_exit != NULL) body_exit->Goto(loop_entry, true);
+ loop_entry->PostProcessLoopHeader(statement);
+ if (break_block != NULL) {
+ if (loop_successor != NULL) loop_successor->Goto(break_block);
+ break_block->SetJoinId(statement->ExitId());
+ return break_block;
}
-
- if (result != NULL) result->SetJoinId(join_id);
-
- return result;
+ return loop_successor;
}
-HBasicBlock* HSubgraph::JoinBlocks(HBasicBlock* a, HBasicBlock* b, int id) {
- if (a == NULL) return b;
- if (b == NULL) return a;
- HBasicBlock* target = graph_->CreateBasicBlock();
- a->Goto(target);
- b->Goto(target);
- target->SetJoinId(id);
- return target;
+void HBasicBlock::FinishExit(HControlInstruction* instruction) {
+ Finish(instruction);
+ ClearEnvironment();
}
-void HSubgraph::AppendEndless(HSubgraph* body, IterationStatement* statement) {
- ConnectExitTo(body->entry_block());
- body->ResolveContinue(statement);
- body->ConnectExitTo(body->entry_block(), true);
- exit_block_ = body->BundleBreak(statement);
- body->entry_block()->PostProcessLoopHeader(statement);
-}
-
-
-void HSubgraph::AppendDoWhile(HSubgraph* body,
- IterationStatement* statement,
- HSubgraph* go_back,
- HSubgraph* exit) {
- ConnectExitTo(body->entry_block());
- go_back->ConnectExitTo(body->entry_block(), true);
-
- HBasicBlock* break_block = body->BundleBreak(statement);
- exit_block_ =
- JoinBlocks(exit->exit_block(), break_block, statement->ExitId());
- body->entry_block()->PostProcessLoopHeader(statement);
-}
-
-
-void HSubgraph::AppendWhile(HSubgraph* condition,
- HSubgraph* body,
- IterationStatement* statement,
- HSubgraph* continue_subgraph,
- HSubgraph* exit) {
- ConnectExitTo(condition->entry_block());
-
- HBasicBlock* break_block = body->BundleBreak(statement);
- exit_block_ =
- JoinBlocks(exit->exit_block(), break_block, statement->ExitId());
-
- if (continue_subgraph != NULL) {
- body->ConnectExitTo(continue_subgraph->entry_block(), true);
- continue_subgraph->entry_block()->SetJoinId(statement->EntryId());
- exit_block_ = JoinBlocks(exit_block_,
- continue_subgraph->exit_block(),
- statement->ExitId());
- } else {
- body->ConnectExitTo(condition->entry_block(), true);
- }
- condition->entry_block()->PostProcessLoopHeader(statement);
-}
-
-
-void HSubgraph::Append(HSubgraph* next, BreakableStatement* stmt) {
- exit_block_->Goto(next->entry_block());
- exit_block_ = next->exit_block_;
-
- if (stmt != NULL) {
- next->entry_block()->SetJoinId(stmt->EntryId());
- HBasicBlock* break_block = next->BundleBreak(stmt);
- exit_block_ = JoinBlocks(exit_block(), break_block, stmt->ExitId());
- }
-}
-
-
-void HSubgraph::FinishExit(HControlInstruction* instruction) {
- ASSERT(HasExit());
- exit_block_->Finish(instruction);
- exit_block_->ClearEnvironment();
- exit_block_ = NULL;
-}
-
-
-void HSubgraph::FinishBreakContinue(BreakableStatement* target,
- bool is_continue) {
- ASSERT(!exit_block_->IsFinished());
- BreakContinueInfo* info = new BreakContinueInfo(target, exit_block_,
- is_continue);
- break_continue_info_.Add(info);
- exit_block_ = NULL;
-}
-
-
HGraph::HGraph(CompilationInfo* info)
: HSubgraph(this),
next_block_id_(0),
@@ -739,20 +600,14 @@
void HGraph::Canonicalize() {
+ if (!FLAG_use_canonicalizing) return;
HPhase phase("Canonicalize", this);
- if (FLAG_use_canonicalizing) {
- for (int i = 0; i < blocks()->length(); ++i) {
- HBasicBlock* b = blocks()->at(i);
- for (HInstruction* insn = b->first(); insn != NULL; insn = insn->next()) {
- HValue* value = insn->Canonicalize();
- if (value != insn) {
- if (value != NULL) {
- insn->ReplaceAndDelete(value);
- } else {
- insn->Delete();
- }
- }
- }
+ for (int i = 0; i < blocks()->length(); ++i) {
+ HInstruction* instr = blocks()->at(i)->first();
+ while (instr != NULL) {
+ HValue* value = instr->Canonicalize();
+ if (value != instr) instr->ReplaceAndDelete(value);
+ instr = instr->next();
}
}
}
@@ -1508,8 +1363,7 @@
instr->Mnemonic(),
other->id(),
other->Mnemonic());
- instr->ReplaceValue(other);
- instr->Delete();
+ instr->ReplaceAndDelete(other);
} else {
map->Add(instr);
}
@@ -1813,17 +1667,15 @@
bool is_truncating) {
// Insert the representation change right before its use. For phi-uses we
// insert at the end of the corresponding predecessor.
- HBasicBlock* insert_block = use->block();
+ HInstruction* next = NULL;
if (use->IsPhi()) {
int index = 0;
while (use->OperandAt(index) != value) ++index;
- insert_block = insert_block->predecessors()->at(index);
+ next = use->block()->predecessors()->at(index)->end();
+ } else {
+ next = HInstruction::cast(use);
}
- HInstruction* next = (insert_block == use->block())
- ? HInstruction::cast(use)
- : insert_block->end();
-
// For constants we try to make the representation change at compile
// time. When a representation change is not possible without loss of
// information we treat constants like normal instructions and insert the
@@ -2015,14 +1867,14 @@
EffectContext::~EffectContext() {
ASSERT(owner()->HasStackOverflow() ||
- !owner()->subgraph()->HasExit() ||
+ owner()->current_block() == NULL ||
owner()->environment()->length() == original_length_);
}
ValueContext::~ValueContext() {
ASSERT(owner()->HasStackOverflow() ||
- !owner()->subgraph()->HasExit() ||
+ owner()->current_block() == NULL ||
owner()->environment()->length() == original_length_ + 1);
}
@@ -2080,7 +1932,7 @@
HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
HTest* test = new HTest(value, empty_true, empty_false);
- builder->CurrentBlock()->Finish(test);
+ builder->current_block()->Finish(test);
HValue* const no_return_value = NULL;
HBasicBlock* true_target = if_true();
@@ -2096,7 +1948,7 @@
} else {
empty_false->Goto(false_target);
}
- builder->subgraph()->set_exit_block(NULL);
+ builder->set_current_block(NULL);
}
@@ -2153,7 +2005,6 @@
}
~SubgraphScope() {
- old_subgraph_->AddBreakContinueInfo(subgraph_);
builder_->current_subgraph_ = old_subgraph_;
}
@@ -2195,81 +2046,108 @@
}
-HValue* HGraphBuilder::VisitArgument(Expression* expr) {
- VisitForValue(expr);
- if (HasStackOverflow() || !subgraph()->HasExit()) return NULL;
- return environment()->Top();
+void HGraphBuilder::VisitArgument(Expression* expr) {
+ VISIT_FOR_VALUE(expr);
+ Push(AddInstruction(new HPushArgument(Pop())));
}
void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) {
for (int i = 0; i < arguments->length(); i++) {
VisitArgument(arguments->at(i));
- if (HasStackOverflow() || !current_subgraph_->HasExit()) return;
+ if (HasStackOverflow() || current_block() == NULL) return;
}
}
+void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) {
+ for (int i = 0; i < exprs->length(); ++i) {
+ VISIT_FOR_VALUE(exprs->at(i));
+ }
+}
+
+
HGraph* HGraphBuilder::CreateGraph(CompilationInfo* info) {
- ASSERT(current_subgraph_ == NULL);
+ ASSERT(subgraph() == NULL);
graph_ = new HGraph(info);
{
HPhase phase("Block building");
- graph_->Initialize(CreateBasicBlock(graph_->start_environment()));
- current_subgraph_ = graph_;
+ graph()->Initialize(CreateBasicBlock(graph()->start_environment()));
+ current_subgraph_ = graph();
Scope* scope = info->scope();
+ if (scope->HasIllegalRedeclaration()) {
+ Bailout("function with illegal redeclaration");
+ return NULL;
+ }
SetupScope(scope);
VisitDeclarations(scope->declarations());
-
AddInstruction(new HStackCheck());
- ZoneList<Statement*>* stmts = info->function()->body();
- HSubgraph* body = CreateGotoSubgraph(environment());
- AddToSubgraph(body, stmts);
+ // Add an edge to the body entry. This is warty: the graph's start
+ // environment will be used by the Lithium translation as the initial
+ // environment on graph entry, but it has now been mutated by the
+ // Hydrogen translation of the instructions in the start block. This
+ // environment uses values which have not been defined yet. These
+ // Hydrogen instructions will then be replayed by the Lithium
+ // translation, so they cannot have an environment effect. The edge to
+ // the body's entry block (along with some special logic for the start
+ // block in HInstruction::InsertAfter) seals the start block from
+ // getting unwanted instructions inserted.
+ //
+ // TODO(kmillikin): Fix this. Stop mutating the initial environment.
+ // Make the Hydrogen instructions in the initial block into Hydrogen
+ // values (but not instructions), present in the initial environment and
+ // not replayed by the Lithium translation.
+ HEnvironment* initial_env = environment()->CopyWithoutHistory();
+ HBasicBlock* body_entry = CreateBasicBlock(initial_env);
+ current_block()->Goto(body_entry);
+ body_entry->SetJoinId(info->function()->id());
+ set_current_block(body_entry);
+ VisitStatements(info->function()->body());
if (HasStackOverflow()) return NULL;
- current_subgraph_->Append(body, NULL);
- body->entry_block()->SetJoinId(info->function()->id());
- if (graph_->HasExit()) {
- graph_->FinishExit(new HReturn(graph_->GetConstantUndefined()));
+ if (current_block() != NULL) {
+ HReturn* instr = new HReturn(graph()->GetConstantUndefined());
+ current_block()->FinishExit(instr);
+ set_current_block(NULL);
}
}
- graph_->OrderBlocks();
- graph_->AssignDominators();
- graph_->EliminateRedundantPhis();
- if (!graph_->CollectPhis()) {
+ graph()->OrderBlocks();
+ graph()->AssignDominators();
+ graph()->EliminateRedundantPhis();
+ if (!graph()->CollectPhis()) {
Bailout("Phi-use of arguments object");
return NULL;
}
- HInferRepresentation rep(graph_);
+ HInferRepresentation rep(graph());
rep.Analyze();
if (FLAG_use_range) {
- HRangeAnalysis rangeAnalysis(graph_);
+ HRangeAnalysis rangeAnalysis(graph());
rangeAnalysis.Analyze();
}
- graph_->InitializeInferredTypes();
- graph_->Canonicalize();
- graph_->InsertRepresentationChanges();
- graph_->ComputeMinusZeroChecks();
+ graph()->InitializeInferredTypes();
+ graph()->Canonicalize();
+ graph()->InsertRepresentationChanges();
+ graph()->ComputeMinusZeroChecks();
// Eliminate redundant stack checks on backwards branches.
- HStackCheckEliminator sce(graph_);
+ HStackCheckEliminator sce(graph());
sce.Process();
// Perform common subexpression elimination and loop-invariant code motion.
if (FLAG_use_gvn) {
- HPhase phase("Global value numbering", graph_);
- HGlobalValueNumberer gvn(graph_);
+ HPhase phase("Global value numbering", graph());
+ HGlobalValueNumberer gvn(graph());
gvn.Analyze();
}
- return graph_;
+ return graph();
}
@@ -2293,21 +2171,21 @@
HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
- ASSERT(current_subgraph_->HasExit());
- current_subgraph_->exit_block()->AddInstruction(instr);
+ ASSERT(current_block() != NULL);
+ current_block()->AddInstruction(instr);
return instr;
}
void HGraphBuilder::AddSimulate(int id) {
- ASSERT(current_subgraph_->HasExit());
- current_subgraph_->exit_block()->AddSimulate(id);
+ ASSERT(current_block() != NULL);
+ current_block()->AddSimulate(id);
}
void HGraphBuilder::AddPhi(HPhi* instr) {
- ASSERT(current_subgraph_->HasExit());
- current_subgraph_->exit_block()->AddPhi(instr);
+ ASSERT(current_block() != NULL);
+ current_block()->AddPhi(instr);
}
@@ -2317,30 +2195,18 @@
}
-void HGraphBuilder::PushArgumentsForStubCall(int argument_count) {
- const int kMaxStubArguments = 4;
- ASSERT_GE(kMaxStubArguments, argument_count);
- // Push the arguments on the stack.
- HValue* arguments[kMaxStubArguments];
- for (int i = argument_count - 1; i >= 0; i--) {
- arguments[i] = Pop();
+template <int V>
+HInstruction* HGraphBuilder::PreProcessCall(HCall<V>* call) {
+ int count = call->argument_count();
+ ZoneList<HValue*> arguments(count);
+ for (int i = 0; i < count; ++i) {
+ arguments.Add(Pop());
}
- for (int i = 0; i < argument_count; i++) {
- AddInstruction(new HPushArgument(arguments[i]));
- }
-}
-
-void HGraphBuilder::ProcessCall(HCall* call) {
- for (int i = call->argument_count() - 1; i >= 0; --i) {
- HValue* value = Pop();
- HPushArgument* push = new HPushArgument(value);
- call->SetArgumentAt(i, push);
+ while (!arguments.is_empty()) {
+ AddInstruction(new HPushArgument(arguments.RemoveLast()));
}
-
- for (int i = 0; i < call->argument_count(); ++i) {
- AddInstruction(call->PushArgumentAt(i));
- }
+ return call;
}
@@ -2348,9 +2214,6 @@
// We don't yet handle the function name for named function expressions.
if (scope->function() != NULL) BAILOUT("named function expression");
- // We can't handle heap-allocated locals.
- if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals");
-
HConstant* undefined_constant =
new HConstant(FACTORY->undefined_value(), Representation::Tagged());
AddInstruction(undefined_constant);
@@ -2372,6 +2235,10 @@
// Handle the arguments and arguments shadow variables specially (they do
// not have declarations).
if (scope->arguments() != NULL) {
+ if (!scope->arguments()->IsStackAllocated() ||
+ !scope->arguments_shadow()->IsStackAllocated()) {
+ BAILOUT("context-allocated arguments");
+ }
HArgumentsObject* object = new HArgumentsObject;
AddInstruction(object);
graph()->SetArgumentsObject(object);
@@ -2384,7 +2251,7 @@
void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) {
for (int i = 0; i < statements->length(); i++) {
Visit(statements->at(i));
- if (HasStackOverflow() || !current_subgraph_->HasExit()) break;
+ if (HasStackOverflow() || current_block() == NULL) break;
}
}
@@ -2408,14 +2275,6 @@
}
-HSubgraph* HGraphBuilder::CreateGotoSubgraph(HEnvironment* env) {
- HSubgraph* subgraph = new HSubgraph(graph());
- HEnvironment* new_env = env->CopyWithoutHistory();
- subgraph->Initialize(CreateBasicBlock(new_env));
- return subgraph;
-}
-
-
HSubgraph* HGraphBuilder::CreateEmptySubgraph() {
HSubgraph* subgraph = new HSubgraph(graph());
subgraph->Initialize(graph()->CreateBasicBlock());
@@ -2431,25 +2290,27 @@
}
-HSubgraph* HGraphBuilder::CreateLoopHeaderSubgraph(HEnvironment* env) {
- HSubgraph* subgraph = new HSubgraph(graph());
- HBasicBlock* block = graph()->CreateBasicBlock();
- HEnvironment* new_env = env->CopyAsLoopHeader(block);
- block->SetInitialEnvironment(new_env);
- subgraph->Initialize(block);
- subgraph->entry_block()->AttachLoopInformation();
- return subgraph;
+HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
+ HBasicBlock* header = graph()->CreateBasicBlock();
+ HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
+ header->SetInitialEnvironment(entry_env);
+ header->AttachLoopInformation();
+ return header;
}
void HGraphBuilder::VisitBlock(Block* stmt) {
- if (stmt->labels() != NULL) {
- HSubgraph* block_graph = CreateGotoSubgraph(environment());
- ADD_TO_SUBGRAPH(block_graph, stmt->statements());
- current_subgraph_->Append(block_graph, stmt);
- } else {
+ BreakAndContinueInfo break_info(stmt);
+ { BreakAndContinueScope push(&break_info, this);
VisitStatements(stmt->statements());
+ CHECK_BAILOUT;
}
+ HBasicBlock* break_block = break_info.break_block();
+ if (break_block != NULL) {
+ if (current_block() != NULL) current_block()->Goto(break_block);
+ break_block->SetJoinId(stmt->ExitId());
+ set_current_block(break_block);
+ }
}
@@ -2470,30 +2331,69 @@
AddSimulate(stmt->ElseId());
Visit(stmt->else_statement());
} else {
- HSubgraph* then_graph = CreateEmptySubgraph();
- HSubgraph* else_graph = CreateEmptySubgraph();
- VISIT_FOR_CONTROL(stmt->condition(),
- then_graph->entry_block(),
- else_graph->entry_block());
+ HBasicBlock* cond_true = graph()->CreateBasicBlock();
+ HBasicBlock* cond_false = graph()->CreateBasicBlock();
+ VISIT_FOR_CONTROL(stmt->condition(), cond_true, cond_false);
+ cond_true->SetJoinId(stmt->ThenId());
+ cond_false->SetJoinId(stmt->ElseId());
- then_graph->entry_block()->SetJoinId(stmt->ThenId());
- ADD_TO_SUBGRAPH(then_graph, stmt->then_statement());
+ set_current_block(cond_true);
+ Visit(stmt->then_statement());
+ CHECK_BAILOUT;
+ HBasicBlock* other = current_block();
- else_graph->entry_block()->SetJoinId(stmt->ElseId());
- ADD_TO_SUBGRAPH(else_graph, stmt->else_statement());
+ set_current_block(cond_false);
+ Visit(stmt->else_statement());
+ CHECK_BAILOUT;
- current_subgraph_->AppendJoin(then_graph, else_graph, stmt);
+ HBasicBlock* join = CreateJoin(other, current_block(), stmt->id());
+ set_current_block(join);
}
}
+HBasicBlock* HGraphBuilder::BreakAndContinueScope::Get(
+ BreakableStatement* stmt,
+ BreakType type) {
+ BreakAndContinueScope* current = this;
+ while (current != NULL && current->info()->target() != stmt) {
+ current = current->next();
+ }
+ ASSERT(current != NULL); // Always found (unless stack is malformed).
+ HBasicBlock* block = NULL;
+ switch (type) {
+ case BREAK:
+ block = current->info()->break_block();
+ if (block == NULL) {
+ block = current->owner()->graph()->CreateBasicBlock();
+ current->info()->set_break_block(block);
+ }
+ break;
+
+ case CONTINUE:
+ block = current->info()->continue_block();
+ if (block == NULL) {
+ block = current->owner()->graph()->CreateBasicBlock();
+ current->info()->set_continue_block(block);
+ }
+ break;
+ }
+
+ return block;
+}
+
+
void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
- current_subgraph_->FinishBreakContinue(stmt->target(), true);
+ HBasicBlock* continue_block = break_scope()->Get(stmt->target(), CONTINUE);
+ current_block()->Goto(continue_block);
+ set_current_block(NULL);
}
void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
- current_subgraph_->FinishBreakContinue(stmt->target(), false);
+ HBasicBlock* break_block = break_scope()->Get(stmt->target(), BREAK);
+ current_block()->Goto(break_block);
+ set_current_block(NULL);
}
@@ -2503,7 +2403,8 @@
// Not an inlined return, so an actual one.
VISIT_FOR_VALUE(stmt->expression());
HValue* result = environment()->Pop();
- subgraph()->FinishExit(new HReturn(result));
+ current_block()->FinishExit(new HReturn(result));
+ set_current_block(NULL);
} else {
// Return from an inlined function, visit the subexpression in the
// expression context of the call.
@@ -2522,9 +2423,9 @@
VISIT_FOR_VALUE(stmt->expression());
return_value = environment()->Pop();
}
- subgraph()->exit_block()->AddLeaveInlined(return_value,
- function_return_);
- subgraph()->set_exit_block(NULL);
+ current_block()->AddLeaveInlined(return_value,
+ function_return_);
+ set_current_block(NULL);
}
}
}
@@ -2545,7 +2446,7 @@
CaseClause* clause) {
AddToSubgraph(subgraph, clause->label());
if (HasStackOverflow()) return NULL;
- HValue* clause_value = subgraph->environment()->Pop();
+ HValue* clause_value = subgraph->exit_block()->last_environment()->Pop();
HCompare* compare = new HCompare(switch_value,
clause_value,
Token::EQ_STRICT);
@@ -2626,7 +2527,7 @@
// last_false_block is the (empty) false-block of the last comparison. If
// there are no comparisons at all (a single default clause), it is just
// the last block of the current subgraph.
- HBasicBlock* last_false_block = current_subgraph_->exit_block();
+ HBasicBlock* last_false_block = current_block();
if (prev_graph != current_subgraph_) {
last_false_block = graph()->CreateBasicBlock();
HBasicBlock* empty = graph()->CreateBasicBlock();
@@ -2669,18 +2570,21 @@
}
// Check for fall-through from previous statement block.
- if (previous_subgraph != NULL && previous_subgraph->HasExit()) {
+ if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) {
if (subgraph == NULL) subgraph = CreateEmptySubgraph();
previous_subgraph->exit_block()->
Finish(new HGoto(subgraph->entry_block()));
}
if (subgraph != NULL) {
- ADD_TO_SUBGRAPH(subgraph, clause->statements());
- HBasicBlock* break_block = subgraph->BundleBreak(stmt);
- if (break_block != NULL) {
- break_block->Finish(new HGoto(single_exit_block));
+ BreakAndContinueInfo break_info(stmt);
+ { BreakAndContinueScope push(&break_info, this);
+ ADD_TO_SUBGRAPH(subgraph, clause->statements());
}
+ if (break_info.break_block() != NULL) {
+ break_info.break_block()->SetJoinId(stmt->ExitId());
+ break_info.break_block()->Finish(new HGoto(single_exit_block));
+ }
}
previous_subgraph = subgraph;
@@ -2688,7 +2592,7 @@
// If the last statement block has a fall-through, connect it to the
// single exit block.
- if (previous_subgraph != NULL && previous_subgraph->HasExit()) {
+ if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) {
previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block));
}
@@ -2698,9 +2602,9 @@
}
if (single_exit_block->HasPredecessor()) {
- current_subgraph_->set_exit_block(single_exit_block);
+ set_current_block(single_exit_block);
} else {
- current_subgraph_->set_exit_block(NULL);
+ set_current_block(NULL);
}
}
@@ -2709,170 +2613,149 @@
}
-void HSubgraph::PreProcessOsrEntry(IterationStatement* statement) {
+void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) {
if (!graph()->HasOsrEntryAt(statement)) return;
HBasicBlock* non_osr_entry = graph()->CreateBasicBlock();
HBasicBlock* osr_entry = graph()->CreateBasicBlock();
HValue* true_value = graph()->GetConstantTrue();
HTest* test = new HTest(true_value, non_osr_entry, osr_entry);
- exit_block()->Finish(test);
+ current_block()->Finish(test);
HBasicBlock* loop_predecessor = graph()->CreateBasicBlock();
non_osr_entry->Goto(loop_predecessor);
+ set_current_block(osr_entry);
int osr_entry_id = statement->OsrEntryId();
// We want the correct environment at the OsrEntry instruction. Build
// it explicitly. The expression stack should be empty.
- int count = osr_entry->last_environment()->length();
- ASSERT(count == (osr_entry->last_environment()->parameter_count() +
- osr_entry->last_environment()->local_count()));
+ int count = environment()->length();
+ ASSERT(count ==
+ (environment()->parameter_count() + environment()->local_count()));
for (int i = 0; i < count; ++i) {
HUnknownOSRValue* unknown = new HUnknownOSRValue;
- osr_entry->AddInstruction(unknown);
- osr_entry->last_environment()->Bind(i, unknown);
+ AddInstruction(unknown);
+ environment()->Bind(i, unknown);
}
- osr_entry->AddSimulate(osr_entry_id);
- osr_entry->AddInstruction(new HOsrEntry(osr_entry_id));
- osr_entry->Goto(loop_predecessor);
+ AddSimulate(osr_entry_id);
+ AddInstruction(new HOsrEntry(osr_entry_id));
+ current_block()->Goto(loop_predecessor);
loop_predecessor->SetJoinId(statement->EntryId());
- set_exit_block(loop_predecessor);
+ set_current_block(loop_predecessor);
}
void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
- ASSERT(subgraph()->HasExit());
- subgraph()->PreProcessOsrEntry(stmt);
+ ASSERT(current_block() != NULL);
+ PreProcessOsrEntry(stmt);
+ HBasicBlock* loop_entry = CreateLoopHeaderBlock();
+ current_block()->Goto(loop_entry, false);
+ set_current_block(loop_entry);
- HSubgraph* body_graph = CreateLoopHeaderSubgraph(environment());
- ADD_TO_SUBGRAPH(body_graph, stmt->body());
- body_graph->ResolveContinue(stmt);
-
- if (!body_graph->HasExit() || stmt->cond()->ToBooleanIsTrue()) {
- current_subgraph_->AppendEndless(body_graph, stmt);
- } else {
- HSubgraph* go_back = CreateEmptySubgraph();
- HSubgraph* exit = CreateEmptySubgraph();
- {
- SubgraphScope scope(this, body_graph);
- VISIT_FOR_CONTROL(stmt->cond(),
- go_back->entry_block(),
- exit->entry_block());
- go_back->entry_block()->SetJoinId(stmt->BackEdgeId());
- exit->entry_block()->SetJoinId(stmt->ExitId());
- }
- current_subgraph_->AppendDoWhile(body_graph, stmt, go_back, exit);
+ BreakAndContinueInfo break_info(stmt);
+ { BreakAndContinueScope push(&break_info, this);
+ Visit(stmt->body());
+ CHECK_BAILOUT;
}
+ HBasicBlock* body_exit =
+ JoinContinue(stmt, current_block(), break_info.continue_block());
+ HBasicBlock* loop_successor = NULL;
+ if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) {
+ set_current_block(body_exit);
+ // The block for a true condition, the actual predecessor block of the
+ // back edge.
+ body_exit = graph()->CreateBasicBlock();
+ loop_successor = graph()->CreateBasicBlock();
+ VISIT_FOR_CONTROL(stmt->cond(), body_exit, loop_successor);
+ body_exit->SetJoinId(stmt->BackEdgeId());
+ loop_successor->SetJoinId(stmt->ExitId());
+ }
+ HBasicBlock* loop_exit = CreateLoop(stmt,
+ loop_entry,
+ body_exit,
+ loop_successor,
+ break_info.break_block());
+ set_current_block(loop_exit);
}
-bool HGraphBuilder::ShouldPeel(HSubgraph* cond, HSubgraph* body) {
- return FLAG_use_peeling;
-}
-
-
void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
- ASSERT(subgraph()->HasExit());
- subgraph()->PreProcessOsrEntry(stmt);
+ ASSERT(current_block() != NULL);
+ PreProcessOsrEntry(stmt);
+ HBasicBlock* loop_entry = CreateLoopHeaderBlock();
+ current_block()->Goto(loop_entry, false);
+ set_current_block(loop_entry);
- HSubgraph* cond_graph = NULL;
- HSubgraph* body_graph = NULL;
- HSubgraph* exit_graph = NULL;
-
- // If the condition is constant true, do not generate a condition subgraph.
- if (stmt->cond()->ToBooleanIsTrue()) {
- body_graph = CreateLoopHeaderSubgraph(environment());
- ADD_TO_SUBGRAPH(body_graph, stmt->body());
- } else {
- cond_graph = CreateLoopHeaderSubgraph(environment());
- body_graph = CreateEmptySubgraph();
- exit_graph = CreateEmptySubgraph();
- {
- SubgraphScope scope(this, cond_graph);
- VISIT_FOR_CONTROL(stmt->cond(),
- body_graph->entry_block(),
- exit_graph->entry_block());
- body_graph->entry_block()->SetJoinId(stmt->BodyId());
- exit_graph->entry_block()->SetJoinId(stmt->ExitId());
- }
- ADD_TO_SUBGRAPH(body_graph, stmt->body());
+ // If the condition is constant true, do not generate a branch.
+ HBasicBlock* loop_successor = NULL;
+ if (!stmt->cond()->ToBooleanIsTrue()) {
+ HBasicBlock* body_entry = graph()->CreateBasicBlock();
+ loop_successor = graph()->CreateBasicBlock();
+ VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor);
+ body_entry->SetJoinId(stmt->BodyId());
+ loop_successor->SetJoinId(stmt->ExitId());
+ set_current_block(body_entry);
}
- body_graph->ResolveContinue(stmt);
-
- if (cond_graph != NULL) {
- AppendPeeledWhile(stmt, cond_graph, body_graph, exit_graph);
- } else {
- // TODO(fschneider): Implement peeling for endless loops as well.
- current_subgraph_->AppendEndless(body_graph, stmt);
+ BreakAndContinueInfo break_info(stmt);
+ { BreakAndContinueScope push(&break_info, this);
+ Visit(stmt->body());
+ CHECK_BAILOUT;
}
+ HBasicBlock* body_exit =
+ JoinContinue(stmt, current_block(), break_info.continue_block());
+ HBasicBlock* loop_exit = CreateLoop(stmt,
+ loop_entry,
+ body_exit,
+ loop_successor,
+ break_info.break_block());
+ set_current_block(loop_exit);
}
-void HGraphBuilder::AppendPeeledWhile(IterationStatement* stmt,
- HSubgraph* cond_graph,
- HSubgraph* body_graph,
- HSubgraph* exit_graph) {
- HSubgraph* loop = NULL;
- if (body_graph->HasExit() && stmt != peeled_statement_ &&
- ShouldPeel(cond_graph, body_graph)) {
- // Save the last peeled iteration statement to prevent infinite recursion.
- IterationStatement* outer_peeled_statement = peeled_statement_;
- peeled_statement_ = stmt;
- loop = CreateGotoSubgraph(body_graph->environment());
- ADD_TO_SUBGRAPH(loop, stmt);
- peeled_statement_ = outer_peeled_statement;
- }
- current_subgraph_->AppendWhile(cond_graph, body_graph, stmt, loop,
- exit_graph);
-}
-
-
void HGraphBuilder::VisitForStatement(ForStatement* stmt) {
- // Only visit the init statement in the peeled part of the loop.
- if (stmt->init() != NULL && peeled_statement_ != stmt) {
+ if (stmt->init() != NULL) {
Visit(stmt->init());
CHECK_BAILOUT;
}
- ASSERT(subgraph()->HasExit());
- subgraph()->PreProcessOsrEntry(stmt);
+ ASSERT(current_block() != NULL);
+ PreProcessOsrEntry(stmt);
+ HBasicBlock* loop_entry = CreateLoopHeaderBlock();
+ current_block()->Goto(loop_entry, false);
+ set_current_block(loop_entry);
- HSubgraph* cond_graph = NULL;
- HSubgraph* body_graph = NULL;
- HSubgraph* exit_graph = NULL;
+ HBasicBlock* loop_successor = NULL;
if (stmt->cond() != NULL) {
- cond_graph = CreateLoopHeaderSubgraph(environment());
- body_graph = CreateEmptySubgraph();
- exit_graph = CreateEmptySubgraph();
- {
- SubgraphScope scope(this, cond_graph);
- VISIT_FOR_CONTROL(stmt->cond(),
- body_graph->entry_block(),
- exit_graph->entry_block());
- body_graph->entry_block()->SetJoinId(stmt->BodyId());
- exit_graph->entry_block()->SetJoinId(stmt->ExitId());
- }
- } else {
- body_graph = CreateLoopHeaderSubgraph(environment());
+ HBasicBlock* body_entry = graph()->CreateBasicBlock();
+ loop_successor = graph()->CreateBasicBlock();
+ VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor);
+ body_entry->SetJoinId(stmt->BodyId());
+ loop_successor->SetJoinId(stmt->ExitId());
+ set_current_block(body_entry);
}
- ADD_TO_SUBGRAPH(body_graph, stmt->body());
- HSubgraph* next_graph = NULL;
- body_graph->ResolveContinue(stmt);
+ BreakAndContinueInfo break_info(stmt);
+ { BreakAndContinueScope push(&break_info, this);
+ Visit(stmt->body());
+ CHECK_BAILOUT;
+ }
+ HBasicBlock* body_exit =
+ JoinContinue(stmt, current_block(), break_info.continue_block());
- if (stmt->next() != NULL && body_graph->HasExit()) {
- next_graph = CreateGotoSubgraph(body_graph->environment());
- ADD_TO_SUBGRAPH(next_graph, stmt->next());
- body_graph->Append(next_graph, NULL);
- next_graph->entry_block()->SetJoinId(stmt->ContinueId());
+ if (stmt->next() != NULL && body_exit != NULL) {
+ set_current_block(body_exit);
+ Visit(stmt->next());
+ CHECK_BAILOUT;
+ body_exit = current_block();
}
- if (cond_graph != NULL) {
- AppendPeeledWhile(stmt, cond_graph, body_graph, exit_graph);
- } else {
- current_subgraph_->AppendEndless(body_graph, stmt);
- }
+ HBasicBlock* loop_exit = CreateLoop(stmt,
+ loop_entry,
+ body_exit,
+ loop_successor,
+ break_info.break_block());
+ set_current_block(loop_exit);
}
@@ -2913,19 +2796,23 @@
void HGraphBuilder::VisitConditional(Conditional* expr) {
- HSubgraph* then_graph = CreateEmptySubgraph();
- HSubgraph* else_graph = CreateEmptySubgraph();
- VISIT_FOR_CONTROL(expr->condition(),
- then_graph->entry_block(),
- else_graph->entry_block());
+ HBasicBlock* cond_true = graph()->CreateBasicBlock();
+ HBasicBlock* cond_false = graph()->CreateBasicBlock();
+ VISIT_FOR_CONTROL(expr->condition(), cond_true, cond_false);
+ cond_true->SetJoinId(expr->ThenId());
+ cond_false->SetJoinId(expr->ElseId());
- then_graph->entry_block()->SetJoinId(expr->ThenId());
- ADD_TO_SUBGRAPH(then_graph, expr->then_expression());
+ // TOOD(kmillikin): Visit the subexpressions in the same AST context as
+ // the whole expression.
+ set_current_block(cond_true);
+ VISIT_FOR_VALUE(expr->then_expression());
+ HBasicBlock* other = current_block();
- else_graph->entry_block()->SetJoinId(expr->ElseId());
- ADD_TO_SUBGRAPH(else_graph, expr->else_expression());
+ set_current_block(cond_false);
+ VISIT_FOR_VALUE(expr->else_expression());
- current_subgraph_->AppendJoin(then_graph, else_graph, expr);
+ HBasicBlock* join = CreateJoin(other, current_block(), expr->id());
+ set_current_block(join);
ast_context()->ReturnValue(Pop());
}
@@ -3022,7 +2909,10 @@
void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
- HObjectLiteral* literal = (new HObjectLiteral(expr->constant_properties(),
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HObjectLiteral* literal = (new HObjectLiteral(context,
+ expr->constant_properties(),
expr->fast_elements(),
expr->literal_index(),
expr->depth()));
@@ -3049,7 +2939,9 @@
VISIT_FOR_VALUE(value);
HValue* value = Pop();
Handle<String> name = Handle<String>::cast(key->handle());
- AddInstruction(new HStoreNamedGeneric(literal, name, value));
+ HStoreNamedGeneric* store =
+ new HStoreNamedGeneric(context, literal, name, value);
+ AddInstruction(store);
AddSimulate(key->id());
} else {
VISIT_FOR_EFFECT(value);
@@ -3112,55 +3004,49 @@
}
-HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps,
- ZoneList<HSubgraph*>* subgraphs,
- HValue* receiver,
+HBasicBlock* HGraphBuilder::BuildTypeSwitch(HValue* receiver,
+ ZoneMapList* maps,
+ ZoneList<HSubgraph*>* body_graphs,
+ HSubgraph* default_graph,
int join_id) {
- ASSERT(subgraphs->length() == (maps->length() + 1));
+ ASSERT(maps->length() == body_graphs->length());
+ HBasicBlock* join_block = graph()->CreateBasicBlock();
+ AddInstruction(new HCheckNonSmi(receiver));
- // Build map compare subgraphs for all but the first map.
- ZoneList<HSubgraph*> map_compare_subgraphs(maps->length() - 1);
- for (int i = maps->length() - 1; i > 0; --i) {
- HSubgraph* subgraph = CreateBranchSubgraph(environment());
- SubgraphScope scope(this, subgraph);
- HSubgraph* else_subgraph =
- (i == (maps->length() - 1))
- ? subgraphs->last()
- : map_compare_subgraphs.last();
- HCompareMap* compare = new HCompareMap(receiver,
- maps->at(i),
- subgraphs->at(i)->entry_block(),
- else_subgraph->entry_block());
- current_subgraph_->exit_block()->Finish(compare);
- map_compare_subgraphs.Add(subgraph);
- }
+ for (int i = 0; i < maps->length(); ++i) {
+ // Build the branches, connect all the target subgraphs to the join
+ // block. Use the default as a target of the last branch.
+ HSubgraph* if_true = body_graphs->at(i);
+ HSubgraph* if_false = (i == maps->length() - 1)
+ ? default_graph
+ : CreateBranchSubgraph(environment());
+ HCompareMap* compare =
+ new HCompareMap(receiver,
+ maps->at(i),
+ if_true->entry_block(),
+ if_false->entry_block());
+ current_block()->Finish(compare);
- // Generate first map check to end the current block.
- AddInstruction(new HCheckNonSmi(receiver));
- HSubgraph* else_subgraph =
- (maps->length() == 1) ? subgraphs->at(1) : map_compare_subgraphs.last();
- HCompareMap* compare = new HCompareMap(receiver,
- Handle<Map>(maps->first()),
- subgraphs->first()->entry_block(),
- else_subgraph->entry_block());
- current_subgraph_->exit_block()->Finish(compare);
-
- // Join all the call subgraphs in a new basic block and make
- // this basic block the current basic block.
- HBasicBlock* join_block = graph_->CreateBasicBlock();
- for (int i = 0; i < subgraphs->length(); ++i) {
- HSubgraph* subgraph = subgraphs->at(i);
- if (subgraph->HasExit()) {
+ if (if_true->exit_block() != NULL) {
// In an effect context the value of the type switch is not needed.
// There is no need to merge it at the join block only to discard it.
- HBasicBlock* subgraph_exit = subgraph->exit_block();
if (ast_context()->IsEffect()) {
- subgraph_exit->last_environment()->Drop(1);
+ if_true->exit_block()->last_environment()->Drop(1);
}
- subgraph_exit->Goto(join_block);
+ if_true->exit_block()->Goto(join_block);
}
+
+ set_current_block(if_false->exit_block());
}
+ // Connect the default if necessary.
+ if (current_block() != NULL) {
+ if (ast_context()->IsEffect()) {
+ environment()->Drop(1);
+ }
+ current_block()->Goto(join_block);
+ }
+
if (join_block->predecessors()->is_empty()) return NULL;
join_block->SetJoinId(join_id);
return join_block;
@@ -3229,7 +3115,9 @@
HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object,
Handle<String> name,
HValue* value) {
- return new HStoreNamedGeneric(object, name, value);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ return new HStoreNamedGeneric(context, object, name, value);
}
@@ -3262,7 +3150,7 @@
Handle<String> name) {
int number_of_types = Min(types->length(), kMaxStorePolymorphism);
ZoneMapList maps(number_of_types);
- ZoneList<HSubgraph*> subgraphs(number_of_types + 1);
+ ZoneList<HSubgraph*> subgraphs(number_of_types);
bool needs_generic = (types->length() > kMaxStorePolymorphism);
// Build subgraphs for each of the specific maps.
@@ -3274,7 +3162,6 @@
Handle<Map> map = types->at(i);
LookupResult lookup;
if (ComputeStoredField(map, name, &lookup)) {
- maps.Add(map);
HSubgraph* subgraph = CreateBranchSubgraph(environment());
SubgraphScope scope(this, subgraph);
HInstruction* instr =
@@ -3282,6 +3169,7 @@
Push(value);
instr->set_position(expr->position());
AddInstruction(instr);
+ maps.Add(map);
subgraphs.Add(subgraph);
} else {
needs_generic = true;
@@ -3291,7 +3179,7 @@
// If none of the properties were named fields we generate a
// generic store.
if (maps.length() == 0) {
- HInstruction* instr = new HStoreNamedGeneric(object, name, value);
+ HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
Push(value);
instr->set_position(expr->position());
AddInstruction(instr);
@@ -3299,26 +3187,25 @@
ast_context()->ReturnValue(Pop());
} else {
// Build subgraph for generic store through IC.
- {
- HSubgraph* subgraph = CreateBranchSubgraph(environment());
- SubgraphScope scope(this, subgraph);
+ HSubgraph* default_graph = CreateBranchSubgraph(environment());
+ { SubgraphScope scope(this, default_graph);
if (!needs_generic && FLAG_deoptimize_uncommon_cases) {
- subgraph->FinishExit(new HDeoptimize());
+ default_graph->exit_block()->FinishExit(new HDeoptimize());
+ default_graph->set_exit_block(NULL);
} else {
- HInstruction* instr = new HStoreNamedGeneric(object, name, value);
+ HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
Push(value);
instr->set_position(expr->position());
AddInstruction(instr);
}
- subgraphs.Add(subgraph);
}
HBasicBlock* new_exit_block =
- BuildTypeSwitch(&maps, &subgraphs, object, expr->id());
- subgraph()->set_exit_block(new_exit_block);
+ BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id());
+ set_current_block(new_exit_block);
// In an effect context, we did not materialized the value in the
// predecessor environments so there's no need to handle it here.
- if (subgraph()->HasExit() && !ast_context()->IsEffect()) {
+ if (current_block() != NULL && !ast_context()->IsEffect()) {
ast_context()->ReturnValue(Pop());
}
}
@@ -3355,7 +3242,7 @@
return;
} else {
- instr = new HStoreNamedGeneric(object, name, value);
+ instr = BuildStoreNamedGeneric(object, name, value);
}
} else {
@@ -3366,12 +3253,20 @@
HValue* key = Pop();
HValue* object = Pop();
- bool is_fast_elements = expr->IsMonomorphic() &&
- expr->GetMonomorphicReceiverType()->has_fast_elements();
-
- instr = is_fast_elements
- ? BuildStoreKeyedFastElement(object, key, value, expr)
- : BuildStoreKeyedGeneric(object, key, value);
+ if (expr->IsMonomorphic()) {
+ Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
+ // An object has either fast elements or pixel array elements, but never
+ // both. Pixel array maps that are assigned to pixel array elements are
+ // always created with the fast elements flag cleared.
+ if (receiver_type->has_pixel_array_elements()) {
+ instr = BuildStoreKeyedPixelArrayElement(object, key, value, expr);
+ } else if (receiver_type->has_fast_elements()) {
+ instr = BuildStoreKeyedFastElement(object, key, value, expr);
+ }
+ }
+ if (instr == NULL) {
+ instr = BuildStoreKeyedGeneric(object, key, value);
+ }
}
Push(value);
@@ -3415,10 +3310,6 @@
BinaryOperation* operation = expr->binary_operation();
if (var != NULL) {
- if (!var->is_global() && !var->IsStackAllocated()) {
- BAILOUT("non-stack/non-global in compound assignment");
- }
-
VISIT_FOR_VALUE(operation);
if (var->is_global()) {
@@ -3426,8 +3317,16 @@
Top(),
expr->position(),
expr->AssignmentId());
+ } else if (var->IsStackAllocated()) {
+ Bind(var, Top());
+ } else if (var->IsContextSlot()) {
+ HValue* context = BuildContextChainWalk(var);
+ int index = var->AsSlot()->index();
+ HStoreContextSlot* instr = new HStoreContextSlot(context, index, Top());
+ AddInstruction(instr);
+ if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
} else {
- Bind(var, Top());
+ BAILOUT("compound assignment to lookup slot");
}
ast_context()->ReturnValue(Pop());
@@ -3475,7 +3374,6 @@
bool is_fast_elements = prop->IsMonomorphic() &&
prop->GetMonomorphicReceiverType()->has_fast_elements();
-
HInstruction* load = is_fast_elements
? BuildLoadKeyedFastElement(obj, key, prop)
: BuildLoadKeyedGeneric(obj, key);
@@ -3580,7 +3478,8 @@
instr->set_position(expr->position());
AddInstruction(instr);
AddSimulate(expr->id());
- current_subgraph_->FinishExit(new HAbnormalExit);
+ current_block()->FinishExit(new HAbnormalExit);
+ set_current_block(NULL);
}
@@ -3590,7 +3489,7 @@
Handle<String> name) {
int number_of_types = Min(types->length(), kMaxLoadPolymorphism);
ZoneMapList maps(number_of_types);
- ZoneList<HSubgraph*> subgraphs(number_of_types + 1);
+ ZoneList<HSubgraph*> subgraphs(number_of_types);
bool needs_generic = (types->length() > kMaxLoadPolymorphism);
// Build subgraphs for each of the specific maps.
@@ -3603,7 +3502,6 @@
LookupResult lookup;
map->LookupInDescriptors(NULL, *name, &lookup);
if (lookup.IsProperty() && lookup.type() == FIELD) {
- maps.Add(map);
HSubgraph* subgraph = CreateBranchSubgraph(environment());
SubgraphScope scope(this, subgraph);
HLoadNamedField* instr =
@@ -3611,6 +3509,7 @@
instr->set_position(expr->position());
instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads.
PushAndAdd(instr);
+ maps.Add(map);
subgraphs.Add(subgraph);
} else {
needs_generic = true;
@@ -3625,25 +3524,24 @@
ast_context()->ReturnInstruction(instr, expr->id());
} else {
// Build subgraph for generic load through IC.
- {
- HSubgraph* subgraph = CreateBranchSubgraph(environment());
- SubgraphScope scope(this, subgraph);
+ HSubgraph* default_graph = CreateBranchSubgraph(environment());
+ { SubgraphScope scope(this, default_graph);
if (!needs_generic && FLAG_deoptimize_uncommon_cases) {
- subgraph->FinishExit(new HDeoptimize());
+ default_graph->exit_block()->FinishExit(new HDeoptimize());
+ default_graph->set_exit_block(NULL);
} else {
HInstruction* instr = BuildLoadNamedGeneric(object, expr);
instr->set_position(expr->position());
PushAndAdd(instr);
}
- subgraphs.Add(subgraph);
}
HBasicBlock* new_exit_block =
- BuildTypeSwitch(&maps, &subgraphs, object, expr->id());
- subgraph()->set_exit_block(new_exit_block);
+ BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id());
+ set_current_block(new_exit_block);
// In an effect context, we did not materialized the value in the
// predecessor environments so there's no need to handle it here.
- if (subgraph()->HasExit() && !ast_context()->IsEffect()) {
+ if (current_block() != NULL && !ast_context()->IsEffect()) {
ast_context()->ReturnValue(Pop());
}
}
@@ -3678,7 +3576,9 @@
Property* expr) {
ASSERT(expr->key()->IsPropertyName());
Handle<Object> name = expr->key()->AsLiteral()->handle();
- return new HLoadNamedGeneric(obj, name);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ return new HLoadNamedGeneric(context, obj, name);
}
@@ -3707,7 +3607,9 @@
HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
HValue* key) {
- return new HLoadKeyedGeneric(object, key);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ return new HLoadKeyedGeneric(context, object, key);
}
@@ -3735,10 +3637,35 @@
}
+HInstruction* HGraphBuilder::BuildLoadKeyedPixelArrayElement(HValue* object,
+ HValue* key,
+ Property* expr) {
+ ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic());
+ AddInstruction(new HCheckNonSmi(object));
+ Handle<Map> map = expr->GetMonomorphicReceiverType();
+ ASSERT(!map->has_fast_elements());
+ ASSERT(map->has_pixel_array_elements());
+ AddInstruction(new HCheckMap(object, map));
+ HLoadElements* elements = new HLoadElements(object);
+ AddInstruction(elements);
+ HInstruction* length = new HPixelArrayLength(elements);
+ AddInstruction(length);
+ AddInstruction(new HBoundsCheck(key, length));
+ HLoadPixelArrayExternalPointer* external_elements =
+ new HLoadPixelArrayExternalPointer(elements);
+ AddInstruction(external_elements);
+ HLoadPixelArrayElement* pixel_array_value =
+ new HLoadPixelArrayElement(external_elements, key);
+ return pixel_array_value;
+}
+
+
HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object,
HValue* key,
HValue* value) {
- return new HStoreKeyedGeneric(object, key, value);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ return new HStoreKeyedGeneric(context, object, key, value);
}
@@ -3765,6 +3692,28 @@
}
+HInstruction* HGraphBuilder::BuildStoreKeyedPixelArrayElement(
+ HValue* object,
+ HValue* key,
+ HValue* val,
+ Expression* expr) {
+ ASSERT(expr->IsMonomorphic());
+ AddInstruction(new HCheckNonSmi(object));
+ Handle<Map> map = expr->GetMonomorphicReceiverType();
+ ASSERT(!map->has_fast_elements());
+ ASSERT(map->has_pixel_array_elements());
+ AddInstruction(new HCheckMap(object, map));
+ HLoadElements* elements = new HLoadElements(object);
+ AddInstruction(elements);
+ HInstruction* length = AddInstruction(new HPixelArrayLength(elements));
+ AddInstruction(new HBoundsCheck(key, length));
+ HLoadPixelArrayExternalPointer* external_elements =
+ new HLoadPixelArrayExternalPointer(elements);
+ AddInstruction(external_elements);
+ return new HStorePixelArrayElement(external_elements, key, val);
+}
+
+
bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
VariableProxy* proxy = expr->obj()->AsVariableProxy();
if (proxy == NULL) return false;
@@ -3780,9 +3729,11 @@
HInstruction* elements = AddInstruction(new HArgumentsElements);
result = new HArgumentsLength(elements);
} else {
+ Push(graph()->GetArgumentsObject());
VisitForValue(expr->key());
if (HasStackOverflow()) return false;
HValue* key = Pop();
+ Drop(1); // Arguments object.
HInstruction* elements = AddInstruction(new HArgumentsElements);
HInstruction* length = AddInstruction(new HArgumentsLength(elements));
AddInstruction(new HBoundsCheck(key, length));
@@ -3842,12 +3793,20 @@
HValue* key = Pop();
HValue* obj = Pop();
- bool is_fast_elements = expr->IsMonomorphic() &&
- expr->GetMonomorphicReceiverType()->has_fast_elements();
-
- instr = is_fast_elements
- ? BuildLoadKeyedFastElement(obj, key, expr)
- : BuildLoadKeyedGeneric(obj, key);
+ if (expr->IsMonomorphic()) {
+ Handle<Map> receiver_type(expr->GetMonomorphicReceiverType());
+ // An object has either fast elements or pixel array elements, but never
+ // both. Pixel array maps that are assigned to pixel array elements are
+ // always created with the fast elements flag cleared.
+ if (receiver_type->has_pixel_array_elements()) {
+ instr = BuildLoadKeyedPixelArrayElement(obj, key, expr);
+ } else if (receiver_type->has_fast_elements()) {
+ instr = BuildLoadKeyedFastElement(obj, key, expr);
+ }
+ }
+ if (instr == NULL) {
+ instr = BuildLoadKeyedGeneric(obj, key);
+ }
}
instr->set_position(expr->position());
ast_context()->ReturnInstruction(instr, expr->id());
@@ -3880,7 +3839,7 @@
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
int number_of_types = Min(types->length(), kMaxCallPolymorphism);
ZoneMapList maps(number_of_types);
- ZoneList<HSubgraph*> subgraphs(number_of_types + 1);
+ ZoneList<HSubgraph*> subgraphs(number_of_types);
bool needs_generic = (types->length() > kMaxCallPolymorphism);
// Build subgraphs for each of the specific maps.
@@ -3891,7 +3850,6 @@
for (int i = 0; i < number_of_types; ++i) {
Handle<Map> map = types->at(i);
if (expr->ComputeTarget(map, name)) {
- maps.Add(map);
HSubgraph* subgraph = CreateBranchSubgraph(environment());
SubgraphScope scope(this, subgraph);
AddCheckConstantFunction(expr, receiver, map, false);
@@ -3903,11 +3861,13 @@
// Check for bailout, as trying to inline might fail due to bailout
// during hydrogen processing.
CHECK_BAILOUT;
- HCall* call = new HCallConstantFunction(expr->target(), argument_count);
+ HCallConstantFunction* call =
+ new HCallConstantFunction(expr->target(), argument_count);
call->set_position(expr->position());
- ProcessCall(call);
+ PreProcessCall(call);
PushAndAdd(call);
}
+ maps.Add(map);
subgraphs.Add(subgraph);
} else {
needs_generic = true;
@@ -3917,29 +3877,32 @@
// If we couldn't compute the target for any of the maps just perform an
// IC call.
if (maps.length() == 0) {
- HCall* call = new HCallNamed(name, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallNamed* call = new HCallNamed(context, name, argument_count);
call->set_position(expr->position());
- ProcessCall(call);
+ PreProcessCall(call);
ast_context()->ReturnInstruction(call, expr->id());
} else {
// Build subgraph for generic call through IC.
- {
- HSubgraph* subgraph = CreateBranchSubgraph(environment());
- SubgraphScope scope(this, subgraph);
+ HSubgraph* default_graph = CreateBranchSubgraph(environment());
+ { SubgraphScope scope(this, default_graph);
if (!needs_generic && FLAG_deoptimize_uncommon_cases) {
- subgraph->FinishExit(new HDeoptimize());
+ default_graph->exit_block()->FinishExit(new HDeoptimize());
+ default_graph->set_exit_block(NULL);
} else {
- HCall* call = new HCallNamed(name, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallNamed* call = new HCallNamed(context, name, argument_count);
call->set_position(expr->position());
- ProcessCall(call);
+ PreProcessCall(call);
PushAndAdd(call);
}
- subgraphs.Add(subgraph);
}
HBasicBlock* new_exit_block =
- BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id());
- subgraph()->set_exit_block(new_exit_block);
+ BuildTypeSwitch(receiver, &maps, &subgraphs, default_graph, expr->id());
+ set_current_block(new_exit_block);
// In an effect context, we did not materialized the value in the
// predecessor environments so there's no need to handle it here.
if (new_exit_block != NULL && !ast_context()->IsEffect()) {
@@ -4005,8 +3968,14 @@
CompilationInfo inner_info(target);
if (!ParserApi::Parse(&inner_info) ||
!Scope::Analyze(&inner_info)) {
+ if (inner_info.isolate()->has_pending_exception()) {
+ SetStackOverflow();
+ // Stop trying to optimize and inline this function.
+ target->shared()->set_optimization_disabled(true);
+ }
return false;
}
+ if (inner_info.scope()->num_heap_slots() > 0) return false;
FunctionLiteral* function = inner_info.function();
// Count the number of AST nodes added by inlining this call.
@@ -4046,10 +4015,7 @@
if (!FullCodeGenerator::MakeCode(&inner_info)) return false;
shared->EnableDeoptimizationSupport(*inner_info.code());
Compiler::RecordFunctionCompilation(
- Logger::FUNCTION_TAG,
- Handle<String>(shared->DebugName()),
- shared->start_position(),
- &inner_info);
+ Logger::FUNCTION_TAG, &inner_info, shared);
}
// Save the pending call context and type feedback oracle. Set up new ones
@@ -4105,7 +4071,7 @@
if (FLAG_trace_inlining) TraceInline(target, true);
- if (body->HasExit()) {
+ if (body->exit_block() != NULL) {
// Add a return of undefined if control can fall off the body. In a
// test context, undefined is false.
HValue* return_value = graph()->GetConstantUndefined();
@@ -4134,7 +4100,7 @@
AddSimulate(expr->ReturnId());
// Jump to the function entry (without re-recording the environment).
- subgraph()->exit_block()->Finish(new HGoto(body->entry_block()));
+ current_block()->Finish(new HGoto(body->entry_block()));
// Fix up the function exits.
if (test_context != NULL) {
@@ -4164,11 +4130,11 @@
// TODO(kmillikin): Come up with a better way to handle this. It is too
// subtle. NULL here indicates that the enclosing context has no control
// flow to handle.
- subgraph()->set_exit_block(NULL);
+ set_current_block(NULL);
} else {
function_return_->SetJoinId(expr->id());
- subgraph()->set_exit_block(function_return_);
+ set_current_block(function_return_);
}
call_context_ = saved_call_context;
@@ -4330,14 +4296,13 @@
void HGraphBuilder::VisitCall(Call* expr) {
Expression* callee = expr->expression();
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
- HCall* call = NULL;
+ HInstruction* call = NULL;
Property* prop = callee->AsProperty();
if (prop != NULL) {
if (!prop->key()->IsPropertyName()) {
// Keyed function call.
- VisitArgument(prop->obj());
- CHECK_BAILOUT;
+ VISIT_FOR_VALUE(prop->obj());
VISIT_FOR_VALUE(prop->key());
// Push receiver and key like the non-optimized code generator expects it.
@@ -4346,12 +4311,13 @@
Push(key);
Push(receiver);
- VisitArgumentList(expr->arguments());
+ VisitExpressions(expr->arguments());
CHECK_BAILOUT;
- call = new HCallKeyed(key, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ call = PreProcessCall(new HCallKeyed(context, key, argument_count));
call->set_position(expr->position());
- ProcessCall(call);
Drop(1); // Key.
ast_context()->ReturnInstruction(call, expr->id());
return;
@@ -4363,16 +4329,17 @@
if (TryCallApply(expr)) return;
CHECK_BAILOUT;
- HValue* receiver = VisitArgument(prop->obj());
+ VISIT_FOR_VALUE(prop->obj());
+ VisitExpressions(expr->arguments());
CHECK_BAILOUT;
- VisitArgumentList(expr->arguments());
- CHECK_BAILOUT;
Handle<String> name = prop->key()->AsLiteral()->AsPropertyName();
expr->RecordTypeFeedback(oracle());
ZoneMapList* types = expr->GetReceiverTypes();
+ HValue* receiver =
+ environment()->ExpressionStackAt(expr->arguments()->length());
if (expr->IsMonomorphic()) {
Handle<Map> receiver_map =
(types == NULL) ? Handle<Map>::null() : types->first();
@@ -4388,12 +4355,14 @@
// When the target has a custom call IC generator, use the IC,
// because it is likely to generate better code. Also use the
// IC when a primitive receiver check is required.
- call = new HCallNamed(name, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ call = PreProcessCall(new HCallNamed(context, name, argument_count));
} else {
AddCheckConstantFunction(expr, receiver, receiver_map, true);
if (TryInline(expr)) {
- if (subgraph()->HasExit()) {
+ if (current_block() != NULL) {
HValue* return_value = Pop();
// If we inlined a function in a test context then we need to emit
// a simulate here to shadow the ones at the end of the
@@ -4408,7 +4377,8 @@
// Check for bailout, as the TryInline call in the if condition above
// might return false due to bailout during hydrogen processing.
CHECK_BAILOUT;
- call = new HCallConstantFunction(expr->target(), argument_count);
+ call = PreProcessCall(new HCallConstantFunction(expr->target(),
+ argument_count));
}
}
} else if (types != NULL && types->length() > 1) {
@@ -4417,7 +4387,9 @@
return;
} else {
- call = new HCallNamed(name, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ call = PreProcessCall(new HCallNamed(context, name, argument_count));
}
} else {
@@ -4426,8 +4398,7 @@
if (!global_call) {
++argument_count;
- VisitArgument(expr->expression());
- CHECK_BAILOUT;
+ VISIT_FOR_VALUE(expr->expression());
}
if (global_call) {
@@ -4446,7 +4417,7 @@
HGlobalObject* global_object = new HGlobalObject(context);
AddInstruction(context);
PushAndAdd(global_object);
- VisitArgumentList(expr->arguments());
+ VisitExpressions(expr->arguments());
CHECK_BAILOUT;
VISIT_FOR_VALUE(expr->expression());
@@ -4463,7 +4434,7 @@
environment()->SetExpressionStackAt(receiver_index, global_receiver);
if (TryInline(expr)) {
- if (subgraph()->HasExit()) {
+ if (current_block() != NULL) {
HValue* return_value = Pop();
// If we inlined a function in a test context then we need to
// emit a simulate here to shadow the ones at the end of the
@@ -4479,15 +4450,18 @@
// during hydrogen processing.
CHECK_BAILOUT;
- call = new HCallKnownGlobal(expr->target(), argument_count);
+ call = PreProcessCall(new HCallKnownGlobal(expr->target(),
+ argument_count));
} else {
HContext* context = new HContext;
AddInstruction(context);
PushAndAdd(new HGlobalObject(context));
- VisitArgumentList(expr->arguments());
+ VisitExpressions(expr->arguments());
CHECK_BAILOUT;
- call = new HCallGlobal(var->name(), argument_count);
+ call = PreProcessCall(new HCallGlobal(context,
+ var->name(),
+ argument_count));
}
} else {
@@ -4496,15 +4470,14 @@
AddInstruction(context);
AddInstruction(global_object);
PushAndAdd(new HGlobalReceiver(global_object));
- VisitArgumentList(expr->arguments());
+ VisitExpressions(expr->arguments());
CHECK_BAILOUT;
- call = new HCallFunction(argument_count);
+ call = PreProcessCall(new HCallFunction(context, argument_count));
}
}
call->set_position(expr->position());
- ProcessCall(call);
ast_context()->ReturnInstruction(call, expr->id());
}
@@ -4512,15 +4485,20 @@
void HGraphBuilder::VisitCallNew(CallNew* expr) {
// The constructor function is also used as the receiver argument to the
// JS construct call builtin.
- VisitArgument(expr->expression());
+ VISIT_FOR_VALUE(expr->expression());
+ VisitExpressions(expr->arguments());
CHECK_BAILOUT;
- VisitArgumentList(expr->arguments());
- CHECK_BAILOUT;
- int argument_count = expr->arguments()->length() + 1; // Plus constructor.
- HCall* call = new HCallNew(argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+
+ // The constructor is both an operand to the instruction and an argument
+ // to the construct call.
+ int arg_count = expr->arguments()->length() + 1; // Plus constructor.
+ HValue* constructor = environment()->ExpressionStackAt(arg_count - 1);
+ HCallNew* call = new HCallNew(context, constructor, arg_count);
call->set_position(expr->position());
- ProcessCall(call);
+ PreProcessCall(call);
ast_context()->ReturnInstruction(call, expr->id());
}
@@ -4541,25 +4519,15 @@
void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
- Handle<String> name = expr->name();
- if (name->IsEqualTo(CStrVector("_Log"))) {
- ast_context()->ReturnValue(graph()->GetConstantUndefined());
- return;
+ if (expr->is_jsruntime()) {
+ BAILOUT("call to a JavaScript runtime function");
}
const Runtime::Function* function = expr->function();
- if (expr->is_jsruntime()) {
- BAILOUT("call to a JavaScript runtime function");
- }
ASSERT(function != NULL);
-
- VisitArgumentList(expr->arguments());
- CHECK_BAILOUT;
-
- int argument_count = expr->arguments()->length();
if (function->intrinsic_type == Runtime::INLINE) {
- ASSERT(name->length() > 0);
- ASSERT(name->Get(0) == '_');
+ ASSERT(expr->name()->length() > 0);
+ ASSERT(expr->name()->Get(0) == '_');
// Call to an inline function.
int lookup_index = static_cast<int>(function->function_id) -
static_cast<int>(Runtime::kFirstInlineFunction);
@@ -4569,12 +4537,17 @@
InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index];
// Call the inline code generator using the pointer-to-member.
- (this->*generator)(argument_count, expr->id());
+ (this->*generator)(expr);
} else {
ASSERT(function->intrinsic_type == Runtime::RUNTIME);
- HCall* call = new HCallRuntime(name, expr->function(), argument_count);
+ VisitArgumentList(expr->arguments());
+ CHECK_BAILOUT;
+
+ Handle<String> name = expr->name();
+ int argument_count = expr->arguments()->length();
+ HCallRuntime* call = new HCallRuntime(name, function, argument_count);
call->set_position(RelocInfo::kNoPosition);
- ProcessCall(call);
+ Drop(argument_count);
ast_context()->ReturnInstruction(call, expr->id());
}
}
@@ -4601,12 +4574,18 @@
// The subexpression does not have side effects.
ast_context()->ReturnValue(graph()->GetConstantFalse());
} else if (prop != NULL) {
- VISIT_FOR_VALUE(prop->obj());
- VISIT_FOR_VALUE(prop->key());
- HValue* key = Pop();
- HValue* obj = Pop();
- ast_context()->ReturnInstruction(new HDeleteProperty(obj, key),
- expr->id());
+ if (prop->is_synthetic()) {
+ // Result of deleting parameters is false, even when they rewrite
+ // to accesses on the arguments object.
+ ast_context()->ReturnValue(graph()->GetConstantFalse());
+ } else {
+ VISIT_FOR_VALUE(prop->obj());
+ VISIT_FOR_VALUE(prop->key());
+ HValue* key = Pop();
+ HValue* obj = Pop();
+ HDeleteProperty* instr = new HDeleteProperty(obj, key);
+ ast_context()->ReturnInstruction(instr, expr->id());
+ }
} else if (var->is_global()) {
BAILOUT("delete with global variable");
} else {
@@ -4618,21 +4597,29 @@
VisitForControl(expr->expression(),
context->if_false(),
context->if_true());
- } else {
- HSubgraph* true_graph = CreateEmptySubgraph();
- HSubgraph* false_graph = CreateEmptySubgraph();
+ } else if (ast_context()->IsValue()) {
+ HBasicBlock* materialize_false = graph()->CreateBasicBlock();
+ HBasicBlock* materialize_true = graph()->CreateBasicBlock();
VISIT_FOR_CONTROL(expr->expression(),
- false_graph->entry_block(),
- true_graph->entry_block());
- true_graph->entry_block()->SetJoinId(expr->expression()->id());
- true_graph->environment()->Push(graph_->GetConstantTrue());
+ materialize_false,
+ materialize_true);
+ materialize_false->SetJoinId(expr->expression()->id());
+ materialize_true->SetJoinId(expr->expression()->id());
- false_graph->entry_block()->SetJoinId(expr->expression()->id());
- false_graph->environment()->Push(graph_->GetConstantFalse());
+ set_current_block(materialize_false);
+ Push(graph()->GetConstantFalse());
+ set_current_block(materialize_true);
+ Push(graph()->GetConstantTrue());
- current_subgraph_->AppendJoin(true_graph, false_graph, expr);
+ HBasicBlock* join =
+ CreateJoin(materialize_false, materialize_true, expr->id());
+ set_current_block(join);
ast_context()->ReturnValue(Pop());
+ } else {
+ ASSERT(ast_context()->IsEffect());
+ VisitForEffect(expr->expression());
}
+
} else if (op == Token::BIT_NOT || op == Token::SUB) {
VISIT_FOR_VALUE(expr->expression());
HValue* value = Pop();
@@ -4686,10 +4673,6 @@
bool inc = expr->op() == Token::INC;
if (var != NULL) {
- if (!var->is_global() && !var->IsStackAllocated()) {
- BAILOUT("non-stack/non-global variable in count operation");
- }
-
VISIT_FOR_VALUE(target);
// Match the full code generator stack by simulating an extra stack
@@ -4705,9 +4688,16 @@
after,
expr->position(),
expr->AssignmentId());
+ } else if (var->IsStackAllocated()) {
+ Bind(var, after);
+ } else if (var->IsContextSlot()) {
+ HValue* context = BuildContextChainWalk(var);
+ int index = var->AsSlot()->index();
+ HStoreContextSlot* instr = new HStoreContextSlot(context, index, after);
+ AddInstruction(instr);
+ if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
} else {
- ASSERT(var->IsStackAllocated());
- Bind(var, after);
+ BAILOUT("lookup variable in count operation");
}
Drop(has_extra ? 2 : 1);
ast_context()->ReturnValue(expr->is_postfix() ? before : after);
@@ -4786,7 +4776,7 @@
HInstruction* store = is_fast_elements
? BuildStoreKeyedFastElement(obj, key, after, prop)
- : new HStoreKeyedGeneric(obj, key, after);
+ : BuildStoreKeyedGeneric(obj, key, after);
AddInstruction(store);
// Drop the key from the bailout environment. Overwrite the receiver
@@ -4918,12 +4908,12 @@
// Translate right subexpression by visiting it in the same AST
// context as the entire expression.
- subgraph()->set_exit_block(eval_right);
+ set_current_block(eval_right);
Visit(expr->right());
- } else {
+ } else if (ast_context()->IsValue()) {
VISIT_FOR_VALUE(expr->left());
- ASSERT(current_subgraph_->HasExit());
+ ASSERT(current_block() != NULL);
HValue* left = Top();
HEnvironment* environment_copy = environment()->Copy();
@@ -4931,9 +4921,51 @@
HSubgraph* right_subgraph;
right_subgraph = CreateBranchSubgraph(environment_copy);
ADD_TO_SUBGRAPH(right_subgraph, expr->right());
- current_subgraph_->AppendOptional(right_subgraph, is_logical_and, left);
- current_subgraph_->exit_block()->SetJoinId(expr->id());
+
+ ASSERT(current_block() != NULL &&
+ right_subgraph->exit_block() != NULL);
+ // We need an extra block to maintain edge-split form.
+ HBasicBlock* empty_block = graph()->CreateBasicBlock();
+ HBasicBlock* join_block = graph()->CreateBasicBlock();
+
+ HTest* test = is_logical_and
+ ? new HTest(left, right_subgraph->entry_block(), empty_block)
+ : new HTest(left, empty_block, right_subgraph->entry_block());
+ current_block()->Finish(test);
+ empty_block->Goto(join_block);
+ right_subgraph->exit_block()->Goto(join_block);
+ join_block->SetJoinId(expr->id());
+ set_current_block(join_block);
ast_context()->ReturnValue(Pop());
+ } else {
+ ASSERT(ast_context()->IsEffect());
+ // In an effect context, we don't need the value of the left
+ // subexpression, only its control flow and side effects. We need an
+ // extra block to maintain edge-split form.
+ HBasicBlock* empty_block = graph()->CreateBasicBlock();
+ HBasicBlock* right_block = graph()->CreateBasicBlock();
+ HBasicBlock* join_block = graph()->CreateBasicBlock();
+ if (is_logical_and) {
+ VISIT_FOR_CONTROL(expr->left(), right_block, empty_block);
+ } else {
+ VISIT_FOR_CONTROL(expr->left(), empty_block, right_block);
+ }
+ // TODO(kmillikin): Find a way to fix this. It's ugly that there are
+ // actually two empty blocks (one here and one inserted by
+ // TestContext::BuildBranch, and that they both have an HSimulate
+ // though the second one is not a merge node, and that we really have
+ // no good AST ID to put on that first HSimulate.
+ empty_block->SetJoinId(expr->id());
+ right_block->SetJoinId(expr->RightId());
+ set_current_block(right_block);
+ VISIT_FOR_EFFECT(expr->right());
+
+ empty_block->Goto(join_block);
+ current_block()->Goto(join_block);
+ join_block->SetJoinId(expr->id());
+ set_current_block(join_block);
+ // We did not materialize any value in the predecessor environments,
+ // so there is no need to handle it here.
}
} else {
@@ -5043,7 +5075,9 @@
// If the target is not null we have found a known global function that is
// assumed to stay the same for this instanceof.
if (target.is_null()) {
- instr = new HInstanceOf(left, right);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ instr = new HInstanceOf(context, left, right);
} else {
AddInstruction(new HCheckFunction(right, target));
instr = new HInstanceOfKnownGlobal(left, target);
@@ -5108,314 +5142,361 @@
// Generators for inline runtime functions.
// Support for types.
-void HGraphBuilder::GenerateIsSmi(int argument_count, int ast_id) {
- ASSERT(argument_count == 1);
+void HGraphBuilder::GenerateIsSmi(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 1);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
HValue* value = Pop();
HIsSmi* result = new HIsSmi(value);
- ast_context()->ReturnInstruction(result, ast_id);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateIsSpecObject(int argument_count, int ast_id) {
- ASSERT(argument_count == 1);
+void HGraphBuilder::GenerateIsSpecObject(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 1);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
HValue* value = Pop();
HHasInstanceType* result =
new HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE);
- ast_context()->ReturnInstruction(result, ast_id);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateIsFunction(int argument_count, int ast_id) {
- ASSERT(argument_count == 1);
+void HGraphBuilder::GenerateIsFunction(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 1);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
HValue* value = Pop();
HHasInstanceType* result = new HHasInstanceType(value, JS_FUNCTION_TYPE);
- ast_context()->ReturnInstruction(result, ast_id);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateHasCachedArrayIndex(int argument_count,
- int ast_id) {
- ASSERT(argument_count == 1);
+void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 1);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
HValue* value = Pop();
HHasCachedArrayIndex* result = new HHasCachedArrayIndex(value);
- ast_context()->ReturnInstruction(result, ast_id);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateIsArray(int argument_count, int ast_id) {
- ASSERT(argument_count == 1);
+void HGraphBuilder::GenerateIsArray(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 1);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
HValue* value = Pop();
HHasInstanceType* result = new HHasInstanceType(value, JS_ARRAY_TYPE);
- ast_context()->ReturnInstruction(result, ast_id);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateIsRegExp(int argument_count, int ast_id) {
- ASSERT(argument_count == 1);
+void HGraphBuilder::GenerateIsRegExp(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 1);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
HValue* value = Pop();
HHasInstanceType* result = new HHasInstanceType(value, JS_REGEXP_TYPE);
- ast_context()->ReturnInstruction(result, ast_id);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateIsObject(int argument_count, int ast_id) {
- ASSERT(argument_count == 1);
-
+void HGraphBuilder::GenerateIsObject(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 1);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
HValue* value = Pop();
HIsObject* test = new HIsObject(value);
- ast_context()->ReturnInstruction(test, ast_id);
+ ast_context()->ReturnInstruction(test, call->id());
}
-void HGraphBuilder::GenerateIsNonNegativeSmi(int argument_count,
- int ast_id) {
+void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
BAILOUT("inlined runtime function: IsNonNegativeSmi");
}
-void HGraphBuilder::GenerateIsUndetectableObject(int argument_count,
- int ast_id) {
+void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
BAILOUT("inlined runtime function: IsUndetectableObject");
}
void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf(
- int argument_count,
- int ast_id) {
+ CallRuntime* call) {
BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf");
}
// Support for construct call checks.
-void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) {
- ASSERT(argument_count == 0);
- ast_context()->ReturnInstruction(new HIsConstructCall, ast_id);
+void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 0);
+ ast_context()->ReturnInstruction(new HIsConstructCall, call->id());
}
// Support for arguments.length and arguments[?].
-void HGraphBuilder::GenerateArgumentsLength(int argument_count, int ast_id) {
- ASSERT(argument_count == 0);
+void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 0);
HInstruction* elements = AddInstruction(new HArgumentsElements);
HArgumentsLength* result = new HArgumentsLength(elements);
- ast_context()->ReturnInstruction(result, ast_id);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateArguments(int argument_count, int ast_id) {
- ASSERT(argument_count == 1);
+void HGraphBuilder::GenerateArguments(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 1);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
HValue* index = Pop();
HInstruction* elements = AddInstruction(new HArgumentsElements);
HInstruction* length = AddInstruction(new HArgumentsLength(elements));
HAccessArgumentsAt* result = new HAccessArgumentsAt(elements, length, index);
- ast_context()->ReturnInstruction(result, ast_id);
+ ast_context()->ReturnInstruction(result, call->id());
}
// Support for accessing the class and value fields of an object.
-void HGraphBuilder::GenerateClassOf(int argument_count, int ast_id) {
+void HGraphBuilder::GenerateClassOf(CallRuntime* call) {
// The special form detected by IsClassOfTest is detected before we get here
// and does not cause a bailout.
BAILOUT("inlined runtime function: ClassOf");
}
-void HGraphBuilder::GenerateValueOf(int argument_count, int ast_id) {
- ASSERT(argument_count == 1);
+void HGraphBuilder::GenerateValueOf(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 1);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
HValue* value = Pop();
HValueOf* result = new HValueOf(value);
- ast_context()->ReturnInstruction(result, ast_id);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateSetValueOf(int argument_count, int ast_id) {
+void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
BAILOUT("inlined runtime function: SetValueOf");
}
// Fast support for charCodeAt(n).
-void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) {
- ASSERT(argument_count == 2);
+void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 2);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
+ VISIT_FOR_VALUE(call->arguments()->at(1));
HValue* index = Pop();
HValue* string = Pop();
HStringCharCodeAt* result = BuildStringCharCodeAt(string, index);
- ast_context()->ReturnInstruction(result, ast_id);
+ ast_context()->ReturnInstruction(result, call->id());
}
// Fast support for string.charAt(n) and string[n].
-void HGraphBuilder::GenerateStringCharFromCode(int argument_count,
- int ast_id) {
+void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
BAILOUT("inlined runtime function: StringCharFromCode");
}
// Fast support for string.charAt(n) and string[n].
-void HGraphBuilder::GenerateStringCharAt(int argument_count, int ast_id) {
- ASSERT_EQ(2, argument_count);
- PushArgumentsForStubCall(argument_count);
- HCallStub* result = new HCallStub(CodeStub::StringCharAt, argument_count);
- ast_context()->ReturnInstruction(result, ast_id);
+void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
+ ASSERT_EQ(2, call->arguments()->length());
+ VisitArgumentList(call->arguments());
+ CHECK_BAILOUT;
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result = new HCallStub(context, CodeStub::StringCharAt, 2);
+ Drop(2);
+ ast_context()->ReturnInstruction(result, call->id());
}
// Fast support for object equality testing.
-void HGraphBuilder::GenerateObjectEquals(int argument_count, int ast_id) {
- ASSERT(argument_count == 2);
+void HGraphBuilder::GenerateObjectEquals(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 2);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
+ VISIT_FOR_VALUE(call->arguments()->at(1));
HValue* right = Pop();
HValue* left = Pop();
HCompareJSObjectEq* result = new HCompareJSObjectEq(left, right);
- ast_context()->ReturnInstruction(result, ast_id);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateLog(int argument_count, int ast_id) {
- UNREACHABLE(); // We caught this in VisitCallRuntime.
+void HGraphBuilder::GenerateLog(CallRuntime* call) {
+ // %_Log is ignored in optimized code.
+ ast_context()->ReturnValue(graph()->GetConstantUndefined());
}
// Fast support for Math.random().
-void HGraphBuilder::GenerateRandomHeapNumber(int argument_count, int ast_id) {
+void HGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) {
BAILOUT("inlined runtime function: RandomHeapNumber");
}
// Fast support for StringAdd.
-void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_id) {
- ASSERT_EQ(2, argument_count);
- PushArgumentsForStubCall(argument_count);
- HCallStub* result = new HCallStub(CodeStub::StringAdd, argument_count);
- ast_context()->ReturnInstruction(result, ast_id);
+void HGraphBuilder::GenerateStringAdd(CallRuntime* call) {
+ ASSERT_EQ(2, call->arguments()->length());
+ VisitArgumentList(call->arguments());
+ CHECK_BAILOUT;
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result = new HCallStub(context, CodeStub::StringAdd, 2);
+ Drop(2);
+ ast_context()->ReturnInstruction(result, call->id());
}
// Fast support for SubString.
-void HGraphBuilder::GenerateSubString(int argument_count, int ast_id) {
- ASSERT_EQ(3, argument_count);
- PushArgumentsForStubCall(argument_count);
- HCallStub* result = new HCallStub(CodeStub::SubString, argument_count);
- ast_context()->ReturnInstruction(result, ast_id);
+void HGraphBuilder::GenerateSubString(CallRuntime* call) {
+ ASSERT_EQ(3, call->arguments()->length());
+ VisitArgumentList(call->arguments());
+ CHECK_BAILOUT;
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result = new HCallStub(context, CodeStub::SubString, 3);
+ Drop(3);
+ ast_context()->ReturnInstruction(result, call->id());
}
// Fast support for StringCompare.
-void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_id) {
- ASSERT_EQ(2, argument_count);
- PushArgumentsForStubCall(argument_count);
- HCallStub* result = new HCallStub(CodeStub::StringCompare, argument_count);
- ast_context()->ReturnInstruction(result, ast_id);
+void HGraphBuilder::GenerateStringCompare(CallRuntime* call) {
+ ASSERT_EQ(2, call->arguments()->length());
+ VisitArgumentList(call->arguments());
+ CHECK_BAILOUT;
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result = new HCallStub(context, CodeStub::StringCompare, 2);
+ Drop(2);
+ ast_context()->ReturnInstruction(result, call->id());
}
// Support for direct calls from JavaScript to native RegExp code.
-void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) {
- ASSERT_EQ(4, argument_count);
- PushArgumentsForStubCall(argument_count);
- HCallStub* result = new HCallStub(CodeStub::RegExpExec, argument_count);
- ast_context()->ReturnInstruction(result, ast_id);
+void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
+ ASSERT_EQ(4, call->arguments()->length());
+ VisitArgumentList(call->arguments());
+ CHECK_BAILOUT;
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result = new HCallStub(context, CodeStub::RegExpExec, 4);
+ Drop(4);
+ ast_context()->ReturnInstruction(result, call->id());
}
// Construct a RegExp exec result with two in-object properties.
-void HGraphBuilder::GenerateRegExpConstructResult(int argument_count,
- int ast_id) {
- ASSERT_EQ(3, argument_count);
- PushArgumentsForStubCall(argument_count);
+void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
+ ASSERT_EQ(3, call->arguments()->length());
+ VisitArgumentList(call->arguments());
+ CHECK_BAILOUT;
+ HContext* context = new HContext;
+ AddInstruction(context);
HCallStub* result =
- new HCallStub(CodeStub::RegExpConstructResult, argument_count);
- ast_context()->ReturnInstruction(result, ast_id);
+ new HCallStub(context, CodeStub::RegExpConstructResult, 3);
+ Drop(3);
+ ast_context()->ReturnInstruction(result, call->id());
}
// Support for fast native caches.
-void HGraphBuilder::GenerateGetFromCache(int argument_count, int ast_id) {
+void HGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
BAILOUT("inlined runtime function: GetFromCache");
}
// Fast support for number to string.
-void HGraphBuilder::GenerateNumberToString(int argument_count, int ast_id) {
- ASSERT_EQ(1, argument_count);
- PushArgumentsForStubCall(argument_count);
- HCallStub* result = new HCallStub(CodeStub::NumberToString, argument_count);
- ast_context()->ReturnInstruction(result, ast_id);
+void HGraphBuilder::GenerateNumberToString(CallRuntime* call) {
+ ASSERT_EQ(1, call->arguments()->length());
+ VisitArgumentList(call->arguments());
+ CHECK_BAILOUT;
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result = new HCallStub(context, CodeStub::NumberToString, 1);
+ Drop(1);
+ ast_context()->ReturnInstruction(result, call->id());
}
// Fast swapping of elements. Takes three expressions, the object and two
// indices. This should only be used if the indices are known to be
// non-negative and within bounds of the elements array at the call site.
-void HGraphBuilder::GenerateSwapElements(int argument_count, int ast_id) {
+void HGraphBuilder::GenerateSwapElements(CallRuntime* call) {
BAILOUT("inlined runtime function: SwapElements");
}
// Fast call for custom callbacks.
-void HGraphBuilder::GenerateCallFunction(int argument_count, int ast_id) {
+void HGraphBuilder::GenerateCallFunction(CallRuntime* call) {
BAILOUT("inlined runtime function: CallFunction");
}
// Fast call to math functions.
-void HGraphBuilder::GenerateMathPow(int argument_count, int ast_id) {
- ASSERT_EQ(2, argument_count);
+void HGraphBuilder::GenerateMathPow(CallRuntime* call) {
+ ASSERT_EQ(2, call->arguments()->length());
+ VISIT_FOR_VALUE(call->arguments()->at(0));
+ VISIT_FOR_VALUE(call->arguments()->at(1));
HValue* right = Pop();
HValue* left = Pop();
HPower* result = new HPower(left, right);
- ast_context()->ReturnInstruction(result, ast_id);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) {
- ASSERT_EQ(1, argument_count);
- PushArgumentsForStubCall(argument_count);
- HCallStub* result =
- new HCallStub(CodeStub::TranscendentalCache, argument_count);
+void HGraphBuilder::GenerateMathSin(CallRuntime* call) {
+ ASSERT_EQ(1, call->arguments()->length());
+ VisitArgumentList(call->arguments());
+ CHECK_BAILOUT;
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result = new HCallStub(context, CodeStub::TranscendentalCache, 1);
result->set_transcendental_type(TranscendentalCache::SIN);
- ast_context()->ReturnInstruction(result, ast_id);
+ Drop(1);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) {
- ASSERT_EQ(1, argument_count);
- PushArgumentsForStubCall(argument_count);
- HCallStub* result =
- new HCallStub(CodeStub::TranscendentalCache, argument_count);
+void HGraphBuilder::GenerateMathCos(CallRuntime* call) {
+ ASSERT_EQ(1, call->arguments()->length());
+ VisitArgumentList(call->arguments());
+ CHECK_BAILOUT;
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result = new HCallStub(context, CodeStub::TranscendentalCache, 1);
result->set_transcendental_type(TranscendentalCache::COS);
- ast_context()->ReturnInstruction(result, ast_id);
+ Drop(1);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) {
- ASSERT_EQ(1, argument_count);
- PushArgumentsForStubCall(argument_count);
- HCallStub* result =
- new HCallStub(CodeStub::TranscendentalCache, argument_count);
+void HGraphBuilder::GenerateMathLog(CallRuntime* call) {
+ ASSERT_EQ(1, call->arguments()->length());
+ VisitArgumentList(call->arguments());
+ CHECK_BAILOUT;
+ HContext* context = new HContext;
+ AddInstruction(context);
+ HCallStub* result = new HCallStub(context, CodeStub::TranscendentalCache, 1);
result->set_transcendental_type(TranscendentalCache::LOG);
- ast_context()->ReturnInstruction(result, ast_id);
+ Drop(1);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateMathSqrt(int argument_count, int ast_id) {
+void HGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
BAILOUT("inlined runtime function: MathSqrt");
}
// Check whether two RegExps are equivalent
-void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count,
- int ast_id) {
+void HGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) {
BAILOUT("inlined runtime function: IsRegExpEquivalent");
}
-void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count,
- int ast_id) {
- BAILOUT("inlined runtime function: GetCachedArrayIndex");
+void HGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 1);
+ VISIT_FOR_VALUE(call->arguments()->at(0));
+ HValue* value = Pop();
+ HGetCachedArrayIndex* result = new HGetCachedArrayIndex(value);
+ ast_context()->ReturnInstruction(result, call->id());
}
-void HGraphBuilder::GenerateFastAsciiArrayJoin(int argument_count,
- int ast_id) {
+void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) {
BAILOUT("inlined runtime function: FastAsciiArrayJoin");
}
@@ -5816,7 +5897,7 @@
if (op != NULL && op->IsUnallocated()) hint_index = op->VirtualRegister();
trace_.Add(" %d %d", parent_index, hint_index);
UseInterval* cur_interval = range->first_interval();
- while (cur_interval != NULL) {
+ while (cur_interval != NULL && range->Covers(cur_interval->start())) {
trace_.Add(" [%d, %d[",
cur_interval->start().Value(),
cur_interval->end().Value());
@@ -5825,7 +5906,7 @@
UsePosition* current_pos = range->first_pos();
while (current_pos != NULL) {
- if (current_pos->RegisterIsBeneficial()) {
+ if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) {
trace_.Add(" %d M", current_pos->pos().Value());
}
current_pos = current_pos->next();
« no previous file with comments | « src/hydrogen.h ('k') | src/hydrogen-instructions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698