|
|
@ -65,6 +65,7 @@ HBasicBlock::HBasicBlock(HGraph* graph) |
|
|
|
first_instruction_index_(-1), |
|
|
|
last_instruction_index_(-1), |
|
|
|
deleted_phis_(4), |
|
|
|
parent_loop_header_(NULL), |
|
|
|
is_inline_return_target_(false) { |
|
|
|
} |
|
|
|
|
|
|
@ -105,18 +106,10 @@ void HBasicBlock::AddInstruction(HInstruction* instr) { |
|
|
|
if (first_ == NULL) { |
|
|
|
HBlockEntry* entry = new HBlockEntry(); |
|
|
|
entry->InitializeAsFirst(this); |
|
|
|
first_ = entry; |
|
|
|
first_ = last_ = entry; |
|
|
|
} |
|
|
|
instr->InsertAfter(GetLastInstruction()); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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_; |
|
|
|
instr->InsertAfter(last_); |
|
|
|
last_ = instr; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -177,7 +170,7 @@ void HBasicBlock::SetJoinId(int id) { |
|
|
|
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 @@ void HBasicBlock::Verify() { |
|
|
|
// 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 |
|
|
|
|
|
|
@ -870,13 +849,11 @@ void HGraph::EliminateRedundantPhis() { |
|
|
|
} |
|
|
|
uses_to_replace.Rewind(0); |
|
|
|
block->RemovePhi(phi); |
|
|
|
} else if (phi->HasNoUses() && |
|
|
|
!phi->HasReceiverOperand() && |
|
|
|
FLAG_eliminate_dead_phis) { |
|
|
|
// We can't eliminate phis that have the receiver as an operand
|
|
|
|
// because in case of throwing an error we need the correct
|
|
|
|
// receiver value in the environment to construct a corrent
|
|
|
|
// stack trace.
|
|
|
|
} else if (FLAG_eliminate_dead_phis && phi->HasNoUses() && |
|
|
|
!phi->IsReceiver()) { |
|
|
|
// We can't eliminate phis in the receiver position in the environment
|
|
|
|
// because in case of throwing an error we need this value to
|
|
|
|
// construct a stack trace.
|
|
|
|
block->RemovePhi(phi); |
|
|
|
block->RecordDeletedPhi(phi->merged_index()); |
|
|
|
} |
|
|
@ -1815,17 +1792,15 @@ void HGraph::InsertRepresentationChangeForUse(HValue* value, |
|
|
|
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
|
|
|
@ -2197,10 +2172,8 @@ void HGraphBuilder::VisitForControl(Expression* expr, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
HValue* HGraphBuilder::VisitArgument(Expression* expr) { |
|
|
|
void HGraphBuilder::VisitArgument(Expression* expr) { |
|
|
|
VisitForValue(expr); |
|
|
|
if (HasStackOverflow() || !subgraph()->HasExit()) return NULL; |
|
|
|
return environment()->Top(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -2319,29 +2292,15 @@ void HGraphBuilder::PushAndAdd(HInstruction* instr) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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(); |
|
|
|
} |
|
|
|
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); |
|
|
|
void HGraphBuilder::PreProcessCall(HCall* 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 < call->argument_count(); ++i) { |
|
|
|
AddInstruction(call->PushArgumentAt(i)); |
|
|
|
while (!arguments.is_empty()) { |
|
|
|
AddInstruction(new HPushArgument(arguments.RemoveLast())); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -2952,6 +2911,9 @@ void HGraphBuilder::LookupGlobalPropertyCell(Variable* var, |
|
|
|
if (is_store && lookup->IsReadOnly()) { |
|
|
|
BAILOUT("read-only global variable"); |
|
|
|
} |
|
|
|
if (lookup->holder() != *global) { |
|
|
|
BAILOUT("global property on prototype of global object"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -3021,7 +2983,10 @@ void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { |
|
|
|
|
|
|
|
|
|
|
|
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())); |
|
|
@ -3048,7 +3013,9 @@ void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
|
|
|
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); |
|
|
@ -3111,53 +3078,47 @@ void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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, |
|
|
|
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), |
|
|
|
subgraphs->at(i)->entry_block(), |
|
|
|
else_subgraph->entry_block()); |
|
|
|
current_subgraph_->exit_block()->Finish(compare); |
|
|
|
map_compare_subgraphs.Add(subgraph); |
|
|
|
} |
|
|
|
if_true->entry_block(), |
|
|
|
if_false->entry_block()); |
|
|
|
subgraph()->exit_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->HasExit()) { |
|
|
|
// 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); |
|
|
|
} |
|
|
|
|
|
|
|
subgraph()->set_exit_block(if_false->exit_block()); |
|
|
|
} |
|
|
|
|
|
|
|
// Connect the default if necessary.
|
|
|
|
if (subgraph()->HasExit()) { |
|
|
|
if (ast_context()->IsEffect()) { |
|
|
|
environment()->Drop(1); |
|
|
|
} |
|
|
|
subgraph()->exit_block()->Goto(join_block); |
|
|
|
} |
|
|
|
|
|
|
|
if (join_block->predecessors()->is_empty()) return NULL; |
|
|
@ -3228,7 +3189,9 @@ HInstruction* HGraphBuilder::BuildStoreNamedField(HValue* object, |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -3261,7 +3224,7 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
|
|
|
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.
|
|
|
@ -3273,7 +3236,6 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
|
|
|
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 = |
|
|
@ -3281,6 +3243,7 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
|
|
|
Push(value); |
|
|
|
instr->set_position(expr->position()); |
|
|
|
AddInstruction(instr); |
|
|
|
maps.Add(map); |
|
|
|
subgraphs.Add(subgraph); |
|
|
|
} else { |
|
|
|
needs_generic = true; |
|
|
@ -3290,7 +3253,7 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
|
|
|
// 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); |
|
|
@ -3298,22 +3261,20 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
|
|
|
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->FinishExit(new HDeoptimize()); |
|
|
|
} 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()); |
|
|
|
BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); |
|
|
|
subgraph()->set_exit_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.
|
|
|
@ -3354,7 +3315,7 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
|
|
|
return; |
|
|
|
|
|
|
|
} else { |
|
|
|
instr = new HStoreNamedGeneric(object, name, value); |
|
|
|
instr = BuildStoreNamedGeneric(object, name, value); |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
@ -3414,10 +3375,6 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
|
|
|
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()) { |
|
|
@ -3425,8 +3382,16 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
|
|
|
Top(), |
|
|
|
expr->position(), |
|
|
|
expr->AssignmentId()); |
|
|
|
} else { |
|
|
|
} 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 { |
|
|
|
BAILOUT("compound assignment to lookup slot"); |
|
|
|
} |
|
|
|
ast_context()->ReturnValue(Pop()); |
|
|
|
|
|
|
@ -3474,7 +3439,6 @@ void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
|
|
|
|
|
|
|
bool is_fast_elements = prop->IsMonomorphic() && |
|
|
|
prop->GetMonomorphicReceiverType()->has_fast_elements(); |
|
|
|
|
|
|
|
HInstruction* load = is_fast_elements |
|
|
|
? BuildLoadKeyedFastElement(obj, key, prop) |
|
|
|
: BuildLoadKeyedGeneric(obj, key); |
|
|
@ -3589,7 +3553,7 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
|
|
|
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.
|
|
|
@ -3602,7 +3566,6 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
|
|
|
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 = |
|
|
@ -3610,6 +3573,7 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
|
|
|
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; |
|
|
@ -3624,21 +3588,19 @@ void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
|
|
|
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->FinishExit(new HDeoptimize()); |
|
|
|
} 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()); |
|
|
|
BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); |
|
|
|
subgraph()->set_exit_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.
|
|
|
@ -3677,7 +3639,9 @@ HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* obj, |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -3706,7 +3670,9 @@ HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj, |
|
|
|
|
|
|
|
HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
|
|
|
HValue* key) { |
|
|
|
return new HLoadKeyedGeneric(object, key); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
return new HLoadKeyedGeneric(context, object, key); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -3734,10 +3700,34 @@ HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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 = AddInstruction(new HPixelArrayLength(elements)); |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -3841,12 +3831,20 @@ void HGraphBuilder::VisitProperty(Property* expr) { |
|
|
|
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()); |
|
|
@ -3879,7 +3877,7 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
|
|
|
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.
|
|
|
@ -3890,7 +3888,6 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
|
|
|
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); |
|
|
@ -3904,9 +3901,10 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
|
|
|
CHECK_BAILOUT; |
|
|
|
HCall* 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; |
|
|
@ -3916,28 +3914,30 @@ void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
|
|
|
// 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); |
|
|
|
HCall* 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->FinishExit(new HDeoptimize()); |
|
|
|
} else { |
|
|
|
HCall* call = new HCallNamed(name, argument_count); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
HCall* 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()); |
|
|
|
BuildTypeSwitch(receiver, &maps, &subgraphs, default_graph, expr->id()); |
|
|
|
subgraph()->set_exit_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.
|
|
|
@ -4004,6 +4004,9 @@ bool HGraphBuilder::TryInline(Call* expr) { |
|
|
|
CompilationInfo inner_info(target); |
|
|
|
if (!ParserApi::Parse(&inner_info) || |
|
|
|
!Scope::Analyze(&inner_info)) { |
|
|
|
if (Top::has_pending_exception()) { |
|
|
|
SetStackOverflow(); |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
FunctionLiteral* function = inner_info.function(); |
|
|
@ -4348,9 +4351,11 @@ void HGraphBuilder::VisitCall(Call* expr) { |
|
|
|
VisitArgumentList(expr->arguments()); |
|
|
|
CHECK_BAILOUT; |
|
|
|
|
|
|
|
call = new HCallKeyed(key, argument_count); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
call = new HCallKeyed(context, key, argument_count); |
|
|
|
call->set_position(expr->position()); |
|
|
|
ProcessCall(call); |
|
|
|
PreProcessCall(call); |
|
|
|
Drop(1); // Key.
|
|
|
|
ast_context()->ReturnInstruction(call, expr->id()); |
|
|
|
return; |
|
|
@ -4362,7 +4367,7 @@ void HGraphBuilder::VisitCall(Call* expr) { |
|
|
|
if (TryCallApply(expr)) return; |
|
|
|
CHECK_BAILOUT; |
|
|
|
|
|
|
|
HValue* receiver = VisitArgument(prop->obj()); |
|
|
|
VisitArgument(prop->obj()); |
|
|
|
CHECK_BAILOUT; |
|
|
|
VisitArgumentList(expr->arguments()); |
|
|
|
CHECK_BAILOUT; |
|
|
@ -4372,6 +4377,8 @@ void HGraphBuilder::VisitCall(Call* expr) { |
|
|
|
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(); |
|
|
@ -4387,7 +4394,9 @@ void HGraphBuilder::VisitCall(Call* expr) { |
|
|
|
// 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 = new HCallNamed(context, name, argument_count); |
|
|
|
} else { |
|
|
|
AddCheckConstantFunction(expr, receiver, receiver_map, true); |
|
|
|
|
|
|
@ -4416,7 +4425,9 @@ void HGraphBuilder::VisitCall(Call* expr) { |
|
|
|
return; |
|
|
|
|
|
|
|
} else { |
|
|
|
call = new HCallNamed(name, argument_count); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
call = new HCallNamed(context, name, argument_count); |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
@ -4486,7 +4497,7 @@ void HGraphBuilder::VisitCall(Call* expr) { |
|
|
|
VisitArgumentList(expr->arguments()); |
|
|
|
CHECK_BAILOUT; |
|
|
|
|
|
|
|
call = new HCallGlobal(var->name(), argument_count); |
|
|
|
call = new HCallGlobal(context, var->name(), argument_count); |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
@ -4498,12 +4509,12 @@ void HGraphBuilder::VisitCall(Call* expr) { |
|
|
|
VisitArgumentList(expr->arguments()); |
|
|
|
CHECK_BAILOUT; |
|
|
|
|
|
|
|
call = new HCallFunction(argument_count); |
|
|
|
call = new HCallFunction(context, argument_count); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
call->set_position(expr->position()); |
|
|
|
ProcessCall(call); |
|
|
|
PreProcessCall(call); |
|
|
|
ast_context()->ReturnInstruction(call, expr->id()); |
|
|
|
} |
|
|
|
|
|
|
@ -4516,10 +4527,16 @@ void HGraphBuilder::VisitCallNew(CallNew* expr) { |
|
|
|
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); |
|
|
|
HCall* call = new HCallNew(context, constructor, arg_count); |
|
|
|
call->set_position(expr->position()); |
|
|
|
ProcessCall(call); |
|
|
|
PreProcessCall(call); |
|
|
|
ast_context()->ReturnInstruction(call, expr->id()); |
|
|
|
} |
|
|
|
|
|
|
@ -4573,7 +4590,7 @@ void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { |
|
|
|
ASSERT(function->intrinsic_type == Runtime::RUNTIME); |
|
|
|
HCall* call = new HCallRuntime(name, expr->function(), argument_count); |
|
|
|
call->set_position(RelocInfo::kNoPosition); |
|
|
|
ProcessCall(call); |
|
|
|
PreProcessCall(call); |
|
|
|
ast_context()->ReturnInstruction(call, expr->id()); |
|
|
|
} |
|
|
|
} |
|
|
@ -4600,12 +4617,18 @@ void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { |
|
|
|
// The subexpression does not have side effects.
|
|
|
|
ast_context()->ReturnValue(graph()->GetConstantFalse()); |
|
|
|
} else if (prop != NULL) { |
|
|
|
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(); |
|
|
|
ast_context()->ReturnInstruction(new HDeleteProperty(obj, key), |
|
|
|
expr->id()); |
|
|
|
HDeleteProperty* instr = new HDeleteProperty(obj, key); |
|
|
|
ast_context()->ReturnInstruction(instr, expr->id()); |
|
|
|
} |
|
|
|
} else if (var->is_global()) { |
|
|
|
BAILOUT("delete with global variable"); |
|
|
|
} else { |
|
|
@ -4685,10 +4708,6 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
|
|
|
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
|
|
|
@ -4704,9 +4723,16 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
|
|
|
after, |
|
|
|
expr->position(), |
|
|
|
expr->AssignmentId()); |
|
|
|
} else { |
|
|
|
ASSERT(var->IsStackAllocated()); |
|
|
|
} 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 { |
|
|
|
BAILOUT("lookup variable in count operation"); |
|
|
|
} |
|
|
|
Drop(has_extra ? 2 : 1); |
|
|
|
ast_context()->ReturnValue(expr->is_postfix() ? before : after); |
|
|
@ -4785,7 +4811,7 @@ void HGraphBuilder::VisitCountOperation(CountOperation* expr) { |
|
|
|
|
|
|
|
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
|
|
|
@ -5042,7 +5068,9 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
|
|
|
// 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); |
|
|
@ -5185,9 +5213,10 @@ void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Support for construct call checks.
|
|
|
|
// Support for construct call checks.
|
|
|
|
void HGraphBuilder::GenerateIsConstructCall(int argument_count, int ast_id) { |
|
|
|
BAILOUT("inlined runtime function: IsConstructCall"); |
|
|
|
ASSERT(argument_count == 0); |
|
|
|
ast_context()->ReturnInstruction(new HIsConstructCall, ast_id); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -5251,8 +5280,11 @@ void HGraphBuilder::GenerateStringCharFromCode(int argument_count, |
|
|
|
// 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); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
HCallStub* result = |
|
|
|
new HCallStub(context, CodeStub::StringCharAt, argument_count); |
|
|
|
PreProcessCall(result); |
|
|
|
ast_context()->ReturnInstruction(result, ast_id); |
|
|
|
} |
|
|
|
|
|
|
@ -5281,8 +5313,11 @@ void HGraphBuilder::GenerateRandomHeapNumber(int argument_count, int ast_id) { |
|
|
|
// 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); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
HCallStub* result = |
|
|
|
new HCallStub(context, CodeStub::StringAdd, argument_count); |
|
|
|
PreProcessCall(result); |
|
|
|
ast_context()->ReturnInstruction(result, ast_id); |
|
|
|
} |
|
|
|
|
|
|
@ -5290,8 +5325,11 @@ void HGraphBuilder::GenerateStringAdd(int argument_count, int ast_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); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
HCallStub* result = |
|
|
|
new HCallStub(context, CodeStub::SubString, argument_count); |
|
|
|
PreProcessCall(result); |
|
|
|
ast_context()->ReturnInstruction(result, ast_id); |
|
|
|
} |
|
|
|
|
|
|
@ -5299,8 +5337,11 @@ void HGraphBuilder::GenerateSubString(int argument_count, int ast_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); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
HCallStub* result = |
|
|
|
new HCallStub(context, CodeStub::StringCompare, argument_count); |
|
|
|
PreProcessCall(result); |
|
|
|
ast_context()->ReturnInstruction(result, ast_id); |
|
|
|
} |
|
|
|
|
|
|
@ -5308,8 +5349,11 @@ void HGraphBuilder::GenerateStringCompare(int argument_count, int ast_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); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
HCallStub* result = |
|
|
|
new HCallStub(context, CodeStub::RegExpExec, argument_count); |
|
|
|
PreProcessCall(result); |
|
|
|
ast_context()->ReturnInstruction(result, ast_id); |
|
|
|
} |
|
|
|
|
|
|
@ -5318,9 +5362,11 @@ void HGraphBuilder::GenerateRegExpExec(int argument_count, int ast_id) { |
|
|
|
void HGraphBuilder::GenerateRegExpConstructResult(int argument_count, |
|
|
|
int ast_id) { |
|
|
|
ASSERT_EQ(3, argument_count); |
|
|
|
PushArgumentsForStubCall(argument_count); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
HCallStub* result = |
|
|
|
new HCallStub(CodeStub::RegExpConstructResult, argument_count); |
|
|
|
new HCallStub(context, CodeStub::RegExpConstructResult, argument_count); |
|
|
|
PreProcessCall(result); |
|
|
|
ast_context()->ReturnInstruction(result, ast_id); |
|
|
|
} |
|
|
|
|
|
|
@ -5334,8 +5380,11 @@ void HGraphBuilder::GenerateGetFromCache(int argument_count, int ast_id) { |
|
|
|
// 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); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
HCallStub* result = |
|
|
|
new HCallStub(context, CodeStub::NumberToString, argument_count); |
|
|
|
PreProcessCall(result); |
|
|
|
ast_context()->ReturnInstruction(result, ast_id); |
|
|
|
} |
|
|
|
|
|
|
@ -5366,30 +5415,36 @@ void HGraphBuilder::GenerateMathPow(int argument_count, int ast_id) { |
|
|
|
|
|
|
|
void HGraphBuilder::GenerateMathSin(int argument_count, int ast_id) { |
|
|
|
ASSERT_EQ(1, argument_count); |
|
|
|
PushArgumentsForStubCall(argument_count); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
HCallStub* result = |
|
|
|
new HCallStub(CodeStub::TranscendentalCache, argument_count); |
|
|
|
new HCallStub(context, CodeStub::TranscendentalCache, argument_count); |
|
|
|
result->set_transcendental_type(TranscendentalCache::SIN); |
|
|
|
PreProcessCall(result); |
|
|
|
ast_context()->ReturnInstruction(result, ast_id); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void HGraphBuilder::GenerateMathCos(int argument_count, int ast_id) { |
|
|
|
ASSERT_EQ(1, argument_count); |
|
|
|
PushArgumentsForStubCall(argument_count); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
HCallStub* result = |
|
|
|
new HCallStub(CodeStub::TranscendentalCache, argument_count); |
|
|
|
new HCallStub(context, CodeStub::TranscendentalCache, argument_count); |
|
|
|
result->set_transcendental_type(TranscendentalCache::COS); |
|
|
|
PreProcessCall(result); |
|
|
|
ast_context()->ReturnInstruction(result, ast_id); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void HGraphBuilder::GenerateMathLog(int argument_count, int ast_id) { |
|
|
|
ASSERT_EQ(1, argument_count); |
|
|
|
PushArgumentsForStubCall(argument_count); |
|
|
|
HContext* context = new HContext; |
|
|
|
AddInstruction(context); |
|
|
|
HCallStub* result = |
|
|
|
new HCallStub(CodeStub::TranscendentalCache, argument_count); |
|
|
|
new HCallStub(context, CodeStub::TranscendentalCache, argument_count); |
|
|
|
result->set_transcendental_type(TranscendentalCache::LOG); |
|
|
|
PreProcessCall(result); |
|
|
|
ast_context()->ReturnInstruction(result, ast_id); |
|
|
|
} |
|
|
|
|
|
|
@ -5408,7 +5463,10 @@ void HGraphBuilder::GenerateIsRegExpEquivalent(int argument_count, |
|
|
|
|
|
|
|
void HGraphBuilder::GenerateGetCachedArrayIndex(int argument_count, |
|
|
|
int ast_id) { |
|
|
|
BAILOUT("inlined runtime function: GetCachedArrayIndex"); |
|
|
|
ASSERT(argument_count == 1); |
|
|
|
HValue* value = Pop(); |
|
|
|
HGetCachedArrayIndex* result = new HGetCachedArrayIndex(value); |
|
|
|
ast_context()->ReturnInstruction(result, ast_id); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|