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

Unified Diff: src/hydrogen.cc

Issue 6529032: Merge 6168:6800 from bleeding_edge to experimental/gc branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
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 6800)
+++ src/hydrogen.cc (working copy)
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -34,6 +34,7 @@
#include "lithium-allocator.h"
#include "parser.h"
#include "scopes.h"
+#include "stub-cache.h"
#if V8_TARGET_ARCH_IA32
#include "ia32/lithium-codegen-ia32.h"
@@ -64,6 +65,7 @@
first_instruction_index_(-1),
last_instruction_index_(-1),
deleted_phis_(4),
+ parent_loop_header_(NULL),
is_inline_return_target_(false) {
}
@@ -104,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();
@@ -176,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()
@@ -292,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
@@ -504,19 +484,15 @@
void HSubgraph::AppendOptional(HSubgraph* graph,
bool on_true_branch,
- HValue* boolean_value) {
+ HValue* value) {
ASSERT(HasExit() && graph->HasExit());
HBasicBlock* other_block = graph_->CreateBasicBlock();
HBasicBlock* join_block = graph_->CreateBasicBlock();
- HBasicBlock* true_branch = other_block;
- HBasicBlock* false_branch = graph->entry_block();
- if (on_true_branch) {
- true_branch = graph->entry_block();
- false_branch = other_block;
- }
-
- exit_block_->Finish(new HBranch(true_branch, false_branch, boolean_value));
+ 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;
@@ -687,6 +663,11 @@
}
+bool HGraph::AllowCodeMotion() const {
+ return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount;
+}
+
+
Handle<Code> HGraph::Compile() {
int values = GetMaximumValueID();
if (values > LAllocator::max_initial_value_ids()) {
@@ -868,13 +849,11 @@
}
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());
}
@@ -929,7 +908,7 @@
private:
void TraceRange(const char* msg, ...);
void Analyze(HBasicBlock* block);
- void InferControlFlowRange(HBranch* branch, HBasicBlock* dest);
+ void InferControlFlowRange(HTest* test, HBasicBlock* dest);
void InferControlFlowRange(Token::Value op, HValue* value, HValue* other);
void InferPhiRange(HPhi* phi);
void InferRange(HValue* value);
@@ -965,8 +944,8 @@
// Infer range based on control flow.
if (block->predecessors()->length() == 1) {
HBasicBlock* pred = block->predecessors()->first();
- if (pred->end()->IsBranch()) {
- InferControlFlowRange(HBranch::cast(pred->end()), block);
+ if (pred->end()->IsTest()) {
+ InferControlFlowRange(HTest::cast(pred->end()), block);
}
}
@@ -992,14 +971,12 @@
}
-void HRangeAnalysis::InferControlFlowRange(HBranch* branch, HBasicBlock* dest) {
- ASSERT(branch->FirstSuccessor() == dest || branch->SecondSuccessor() == dest);
- ASSERT(branch->FirstSuccessor() != dest || branch->SecondSuccessor() != dest);
-
- if (branch->value()->IsCompare()) {
- HCompare* compare = HCompare::cast(branch->value());
+void HRangeAnalysis::InferControlFlowRange(HTest* test, HBasicBlock* dest) {
+ ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest));
+ if (test->value()->IsCompare()) {
+ HCompare* compare = HCompare::cast(test->value());
Token::Value op = compare->token();
- if (branch->SecondSuccessor() == dest) {
+ if (test->SecondSuccessor() == dest) {
op = Token::NegateCompareOp(op);
}
Token::Value inverted_op = Token::InvertCompareOp(op);
@@ -1446,15 +1423,23 @@
}
}
-// Only move instructions that postdominate the loop header (i.e. are
-// always executed inside the loop). This is to avoid unnecessary
-// deoptimizations assuming the loop is executed at least once.
-// TODO(fschneider): Better type feedback should give us information
-// about code that was never executed.
+
bool HGlobalValueNumberer::ShouldMove(HInstruction* instr,
HBasicBlock* loop_header) {
- if (!instr->IsChange() &&
- FLAG_aggressive_loop_invariant_motion) return true;
+ // If we've disabled code motion, don't move any instructions.
+ if (!graph_->AllowCodeMotion()) return false;
+
+ // If --aggressive-loop-invariant-motion, move everything except change
+ // instructions.
+ if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) {
+ return true;
+ }
+
+ // Otherwise only move instructions that postdominate the loop header
+ // (i.e. are always executed inside the loop). This is to avoid
+ // unnecessary deoptimizations assuming the loop is executed at least
+ // once. TODO(fschneider): Better type feedback should give us
+ // information about code that was never executed.
HBasicBlock* block = instr->block();
bool result = true;
if (block != loop_header) {
@@ -1805,28 +1790,17 @@
HValue* use,
Representation to,
bool is_truncating) {
- // Propagate flags for negative zero checks upwards from conversions
- // int32-to-tagged and int32-to-double.
- Representation from = value->representation();
- if (from.IsInteger32()) {
- ASSERT(to.IsTagged() || to.IsDouble());
- BitVector visited(GetMaximumValueID());
- PropagateMinusZeroChecks(value, &visited);
- }
-
// 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
@@ -1976,6 +1950,30 @@
}
+void HGraph::ComputeMinusZeroChecks() {
+ BitVector visited(GetMaximumValueID());
+ for (int i = 0; i < blocks_.length(); ++i) {
+ for (HInstruction* current = blocks_[i]->first();
+ current != NULL;
+ current = current->next()) {
+ if (current->IsChange()) {
+ HChange* change = HChange::cast(current);
+ // Propagate flags for negative zero checks upwards from conversions
+ // int32-to-tagged and int32-to-double.
+ Representation from = change->value()->representation();
+ ASSERT(from.Equals(change->from()));
+ if (from.IsInteger32()) {
+ ASSERT(change->to().IsTagged() || change->to().IsDouble());
+ ASSERT(visited.IsEmpty());
+ PropagateMinusZeroChecks(change->value(), &visited);
+ visited.Clear();
+ }
+ }
+ }
+ }
+}
+
+
// Implementation of utility classes to represent an expression's context in
// the AST.
AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind)
@@ -2058,8 +2056,8 @@
HGraphBuilder* builder = owner();
HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
- HBranch* branch = new HBranch(empty_true, empty_false, value);
- builder->CurrentBlock()->Finish(branch);
+ HTest* test = new HTest(value, empty_true, empty_false);
+ builder->CurrentBlock()->Finish(test);
HValue* const no_return_value = NULL;
HBasicBlock* true_target = if_true();
@@ -2174,10 +2172,8 @@
}
-HValue* HGraphBuilder::VisitArgument(Expression* expr) {
+void HGraphBuilder::VisitArgument(Expression* expr) {
VisitForValue(expr);
- if (HasStackOverflow() || !subgraph()->HasExit()) return NULL;
- return environment()->Top();
}
@@ -2235,6 +2231,7 @@
graph_->InitializeInferredTypes();
graph_->Canonicalize();
graph_->InsertRepresentationChanges();
+ graph_->ComputeMinusZeroChecks();
// Eliminate redundant stack checks on backwards branches.
HStackCheckEliminator sce(graph_);
@@ -2295,30 +2292,16 @@
}
-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();
+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 < 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));
- }
}
@@ -2587,9 +2570,9 @@
prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block()));
} else {
HBasicBlock* empty = graph()->CreateBasicBlock();
- prev_graph->exit_block()->Finish(new HBranch(empty,
- subgraph->entry_block(),
- prev_compare_inst));
+ prev_graph->exit_block()->Finish(new HTest(prev_compare_inst,
+ empty,
+ subgraph->entry_block()));
}
// Build instructions for current subgraph.
@@ -2608,9 +2591,9 @@
if (prev_graph != current_subgraph_) {
last_false_block = graph()->CreateBasicBlock();
HBasicBlock* empty = graph()->CreateBasicBlock();
- prev_graph->exit_block()->Finish(new HBranch(empty,
- last_false_block,
- prev_compare_inst));
+ prev_graph->exit_block()->Finish(new HTest(prev_compare_inst,
+ empty,
+ last_false_block));
}
// If we have a non-smi compare clause, we deoptimize after trying
@@ -2693,8 +2676,8 @@
HBasicBlock* non_osr_entry = graph()->CreateBasicBlock();
HBasicBlock* osr_entry = graph()->CreateBasicBlock();
HValue* true_value = graph()->GetConstantTrue();
- HBranch* branch = new HBranch(non_osr_entry, osr_entry, true_value);
- exit_block()->Finish(branch);
+ HTest* test = new HTest(true_value, non_osr_entry, osr_entry);
+ exit_block()->Finish(test);
HBasicBlock* loop_predecessor = graph()->CreateBasicBlock();
non_osr_entry->Goto(loop_predecessor);
@@ -2928,9 +2911,25 @@
if (is_store && lookup->IsReadOnly()) {
BAILOUT("read-only global variable");
}
+ if (lookup->holder() != *global) {
+ BAILOUT("global property on prototype of global object");
+ }
}
+HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) {
+ ASSERT(var->IsContextSlot());
+ HInstruction* context = new HContext;
+ AddInstruction(context);
+ int length = graph()->info()->scope()->ContextChainLength(var->scope());
+ while (length-- > 0) {
+ context = new HOuterContext(context);
+ AddInstruction(context);
+ }
+ return context;
+}
+
+
void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
Variable* variable = expr->AsVariable();
if (variable == NULL) {
@@ -2940,6 +2939,14 @@
BAILOUT("unsupported context for arguments object");
}
ast_context()->ReturnValue(environment()->Lookup(variable));
+ } else if (variable->IsContextSlot()) {
+ if (variable->mode() == Variable::CONST) {
+ BAILOUT("reference to const context slot");
+ }
+ HValue* context = BuildContextChainWalk(variable);
+ int index = variable->AsSlot()->index();
+ HLoadContextSlot* instr = new HLoadContextSlot(context, index);
+ ast_context()->ReturnInstruction(instr, expr->id());
} else if (variable->is_global()) {
LookupResult lookup;
LookupGlobalPropertyCell(variable, &lookup, false);
@@ -2956,7 +2963,7 @@
HLoadGlobal* instr = new HLoadGlobal(cell, check_hole);
ast_context()->ReturnInstruction(instr, expr->id());
} else {
- BAILOUT("reference to non-stack-allocated/non-global variable");
+ BAILOUT("reference to a variable which requires dynamic lookup");
}
}
@@ -2976,7 +2983,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()));
@@ -3003,7 +3013,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);
@@ -3066,46 +3078,47 @@
}
-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();
- current_subgraph_->exit_block()->Finish(
- new HCompareMapAndBranch(receiver,
- maps->at(i),
- subgraphs->at(i)->entry_block(),
- else_subgraph->entry_block()));
- 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());
+ subgraph()->exit_block()->Finish(compare);
+
+ 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.
+ if (ast_context()->IsEffect()) {
+ if_true->exit_block()->last_environment()->Drop(1);
+ }
+ if_true->exit_block()->Goto(join_block);
+ }
+
+ subgraph()->set_exit_block(if_false->exit_block());
}
- // 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();
- current_subgraph_->exit_block()->Finish(
- new HCompareMapAndBranch(receiver,
- Handle<Map>(maps->first()),
- subgraphs->first()->entry_block(),
- else_subgraph->entry_block()));
-
- // 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) {
- if (subgraphs->at(i)->HasExit()) {
- subgraphs->at(i)->exit_block()->Goto(join_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;
@@ -3176,7 +3189,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);
}
@@ -3209,7 +3224,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.
@@ -3221,7 +3236,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 =
@@ -3229,6 +3243,7 @@
Push(value);
instr->set_position(expr->position());
AddInstruction(instr);
+ maps.Add(map);
subgraphs.Add(subgraph);
} else {
needs_generic = true;
@@ -3238,33 +3253,35 @@
// 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);
- if (instr->HasSideEffects()) AddSimulate(expr->id());
+ if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
+ 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->AssignmentId());
+ 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.
+ if (subgraph()->HasExit() && !ast_context()->IsEffect()) {
+ ast_context()->ReturnValue(Pop());
+ }
}
-
- if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop());
}
@@ -3298,7 +3315,7 @@
return;
} else {
- instr = new HStoreNamedGeneric(object, name, value);
+ instr = BuildStoreNamedGeneric(object, name, value);
}
} else {
@@ -3336,9 +3353,10 @@
LookupGlobalPropertyCell(var, &lookup, true);
CHECK_BAILOUT;
+ bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly();
Handle<GlobalObject> global(graph()->info()->global_object());
Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
- HInstruction* instr = new HStoreGlobal(value, cell);
+ HInstruction* instr = new HStoreGlobal(value, cell, check_hole);
instr->set_position(position);
AddInstruction(instr);
if (instr->HasSideEffects()) AddSimulate(ast_id);
@@ -3355,13 +3373,8 @@
// We have a second position recorded in the FullCodeGenerator to have
// type feedback for the binary operation.
BinaryOperation* operation = expr->binary_operation();
- operation->RecordTypeFeedback(oracle());
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()) {
@@ -3369,8 +3382,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());
@@ -3418,7 +3439,6 @@
bool is_fast_elements = prop->IsMonomorphic() &&
prop->GetMonomorphicReceiverType()->has_fast_elements();
-
HInstruction* load = is_fast_elements
? BuildLoadKeyedFastElement(obj, key, prop)
: BuildLoadKeyedGeneric(obj, key);
@@ -3465,33 +3485,48 @@
if (proxy->IsArguments()) BAILOUT("assignment to arguments");
// Handle the assignment.
- if (var->is_global()) {
+ if (var->IsStackAllocated()) {
+ HValue* value = NULL;
+ // Handle stack-allocated variables on the right-hand side directly.
+ // We do not allow the arguments object to occur in a context where it
+ // may escape, but assignments to stack-allocated locals are
+ // permitted. Handling such assignments here bypasses the check for
+ // the arguments object in VisitVariableProxy.
+ Variable* rhs_var = expr->value()->AsVariableProxy()->AsVariable();
+ if (rhs_var != NULL && rhs_var->IsStackAllocated()) {
+ value = environment()->Lookup(rhs_var);
+ } else {
+ VISIT_FOR_VALUE(expr->value());
+ value = Pop();
+ }
+ Bind(var, value);
+ ast_context()->ReturnValue(value);
+
+ } else if (var->IsContextSlot() && var->mode() != Variable::CONST) {
VISIT_FOR_VALUE(expr->value());
+ HValue* context = BuildContextChainWalk(var);
+ int index = var->AsSlot()->index();
+ HStoreContextSlot* instr = new HStoreContextSlot(context, index, Top());
+ AddInstruction(instr);
+ if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId());
+ ast_context()->ReturnValue(Pop());
+
+ } else if (var->is_global()) {
+ VISIT_FOR_VALUE(expr->value());
HandleGlobalVariableAssignment(var,
Top(),
expr->position(),
expr->AssignmentId());
+ ast_context()->ReturnValue(Pop());
+
} else {
- // We allow reference to the arguments object only in assignemtns
- // to local variables to make sure that the arguments object does
- // not escape and is not modified.
- VariableProxy* rhs = expr->value()->AsVariableProxy();
- if (rhs != NULL &&
- rhs->var()->IsStackAllocated() &&
- environment()->Lookup(rhs->var())->CheckFlag(HValue::kIsArguments)) {
- Push(environment()->Lookup(rhs->var()));
- } else {
- VISIT_FOR_VALUE(expr->value());
- }
- Bind(proxy->var(), Top());
+ BAILOUT("assignment to LOOKUP or const CONTEXT variable");
}
- // Return the value.
- ast_context()->ReturnValue(Pop());
} else if (prop != NULL) {
HandlePropertyAssignment(expr);
} else {
- BAILOUT("unsupported invalid lhs");
+ BAILOUT("invalid left-hand side in assignment");
}
}
@@ -3504,9 +3539,11 @@
VISIT_FOR_VALUE(expr->exception());
HValue* value = environment()->Pop();
- HControlInstruction* instr = new HThrow(value);
+ HThrow* instr = new HThrow(value);
instr->set_position(expr->position());
- current_subgraph_->FinishExit(instr);
+ AddInstruction(instr);
+ AddSimulate(expr->id());
+ current_subgraph_->FinishExit(new HAbnormalExit);
}
@@ -3516,7 +3553,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.
@@ -3529,7 +3566,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 =
@@ -3537,6 +3573,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;
@@ -3548,29 +3585,29 @@
if (maps.length() == 0) {
HInstruction* instr = BuildLoadNamedGeneric(object, expr);
instr->set_position(expr->position());
- PushAndAdd(instr);
- if (instr->HasSideEffects()) AddSimulate(expr->id());
+ 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.
+ if (subgraph()->HasExit() && !ast_context()->IsEffect()) {
+ ast_context()->ReturnValue(Pop());
+ }
}
-
- if (subgraph()->HasExit()) ast_context()->ReturnValue(Pop());
}
@@ -3602,7 +3639,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);
}
@@ -3631,7 +3670,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);
}
@@ -3659,10 +3700,34 @@
}
+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);
}
@@ -3732,6 +3797,14 @@
AddInstruction(new HCheckInstanceType(array, JS_ARRAY_TYPE, JS_ARRAY_TYPE));
instr = new HJSArrayLength(array);
+ } else if (expr->IsStringLength()) {
+ HValue* string = Pop();
+ AddInstruction(new HCheckNonSmi(string));
+ AddInstruction(new HCheckInstanceType(string,
+ FIRST_STRING_TYPE,
+ LAST_STRING_TYPE));
+ instr = new HStringLength(string);
+
} else if (expr->IsFunctionPrototype()) {
HValue* function = Pop();
AddInstruction(new HCheckNonSmi(function));
@@ -3758,12 +3831,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());
@@ -3782,9 +3863,9 @@
AddInstruction(new HCheckMap(receiver, receiver_map));
}
if (!expr->holder().is_null()) {
- AddInstruction(new HCheckPrototypeMaps(receiver,
- expr->holder(),
- receiver_map));
+ AddInstruction(new HCheckPrototypeMaps(
+ Handle<JSObject>(JSObject::cast(receiver_map->prototype())),
+ expr->holder()));
}
}
@@ -3796,7 +3877,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.
@@ -3807,7 +3888,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);
@@ -3821,9 +3901,10 @@
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;
@@ -3833,30 +3914,36 @@
// 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);
- if (new_exit_block != NULL) ast_context()->ReturnValue(Pop());
+ // 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()) {
+ ast_context()->ReturnValue(Pop());
+ }
}
}
@@ -3914,10 +4001,12 @@
int count_before = AstNode::Count();
// Parse and allocate variables.
- Handle<SharedFunctionInfo> shared(target->shared());
- CompilationInfo inner_info(shared);
+ 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();
@@ -3938,9 +4027,10 @@
// Don't inline functions that uses the arguments object or that
// have a mismatching number of parameters.
+ Handle<SharedFunctionInfo> shared(target->shared());
int arity = expr->arguments()->length();
if (function->scope()->arguments() != NULL ||
- arity != target->shared()->formal_parameter_count()) {
+ arity != shared->formal_parameter_count()) {
return false;
}
@@ -3992,7 +4082,9 @@
function_return_->MarkAsInlineReturnTarget();
}
call_context_ = ast_context();
- TypeFeedbackOracle new_oracle(Handle<Code>(shared->code()));
+ TypeFeedbackOracle new_oracle(
+ Handle<Code>(shared->code()),
+ Handle<Context>(target->context()->global_context()));
oracle_ = &new_oracle;
graph()->info()->SetOsrAstId(AstNode::kNoNumber);
@@ -4030,9 +4122,8 @@
// TODO(3168478): refactor to avoid this.
HBasicBlock* empty_true = graph()->CreateBasicBlock();
HBasicBlock* empty_false = graph()->CreateBasicBlock();
- HBranch* branch =
- new HBranch(empty_true, empty_false, return_value);
- body->exit_block()->Finish(branch);
+ HTest* test = new HTest(return_value, empty_true, empty_false);
+ body->exit_block()->Finish(test);
HValue* const no_return_value = NULL;
empty_true->AddLeaveInlined(no_return_value, test_context->if_true());
@@ -4101,12 +4192,29 @@
}
-bool HGraphBuilder::TryMathFunctionInline(Call* expr) {
+bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr,
+ HValue* receiver,
+ Handle<Map> receiver_map,
+ CheckType check_type) {
+ ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null());
// Try to inline calls like Math.* as operations in the calling function.
- if (!expr->target()->shared()->IsBuiltinMathFunction()) return false;
+ if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
switch (id) {
+ case kStringCharCodeAt:
+ if (argument_count == 2 && check_type == STRING_CHECK) {
+ HValue* index = Pop();
+ HValue* string = Pop();
+ ASSERT(!expr->holder().is_null());
+ AddInstruction(new HCheckPrototypeMaps(
+ oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK),
+ expr->holder()));
+ HStringCharCodeAt* result = BuildStringCharCodeAt(string, index);
+ ast_context()->ReturnInstruction(result, expr->id());
+ return true;
+ }
+ break;
case kMathRound:
case kMathFloor:
case kMathAbs:
@@ -4114,7 +4222,8 @@
case kMathLog:
case kMathSin:
case kMathCos:
- if (argument_count == 2) {
+ if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
+ AddCheckConstantFunction(expr, receiver, receiver_map, true);
HValue* argument = Pop();
Drop(1); // Receiver.
HUnaryMathOperation* op = new HUnaryMathOperation(argument, id);
@@ -4124,7 +4233,8 @@
}
break;
case kMathPow:
- if (argument_count == 3) {
+ if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
+ AddCheckConstantFunction(expr, receiver, receiver_map, true);
HValue* right = Pop();
HValue* left = Pop();
Pop(); // Pop receiver.
@@ -4134,8 +4244,6 @@
double exponent = HConstant::cast(right)->DoubleValue();
if (exponent == 0.5) {
result = new HUnaryMathOperation(left, kMathPowHalf);
- ast_context()->ReturnInstruction(result, expr->id());
- return true;
} else if (exponent == -0.5) {
HConstant* double_one =
new HConstant(Handle<Object>(Smi::FromInt(1)),
@@ -4148,22 +4256,18 @@
// an environment simulation here.
ASSERT(!square_root->HasSideEffects());
result = new HDiv(double_one, square_root);
- ast_context()->ReturnInstruction(result, expr->id());
- return true;
} else if (exponent == 2.0) {
result = new HMul(left, left);
- ast_context()->ReturnInstruction(result, expr->id());
- return true;
}
} else if (right->IsConstant() &&
- HConstant::cast(right)->HasInteger32Value() &&
- HConstant::cast(right)->Integer32Value() == 2) {
+ HConstant::cast(right)->HasInteger32Value() &&
+ HConstant::cast(right)->Integer32Value() == 2) {
result = new HMul(left, left);
- ast_context()->ReturnInstruction(result, expr->id());
- return true;
}
- result = new HPower(left, right);
+ if (result == NULL) {
+ result = new HPower(left, right);
+ }
ast_context()->ReturnInstruction(result, expr->id());
return true;
}
@@ -4194,7 +4298,8 @@
HValue* arg_two_value = environment()->Lookup(arg_two->var());
if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
- if (!expr->IsMonomorphic()) return false;
+ if (!expr->IsMonomorphic() ||
+ expr->check_type() != RECEIVER_MAP_CHECK) return false;
// Found pattern f.apply(receiver, arguments).
VisitForValue(prop->obj());
@@ -4217,6 +4322,13 @@
}
+static bool HasCustomCallGenerator(Handle<JSFunction> function) {
+ SharedFunctionInfo* info = function->shared();
+ return info->HasBuiltinFunctionId() &&
+ CallStubCompiler::HasCustomCallGenerator(info->builtin_function_id());
+}
+
+
void HGraphBuilder::VisitCall(Call* expr) {
Expression* callee = expr->expression();
int argument_count = expr->arguments()->length() + 1; // Plus receiver.
@@ -4239,9 +4351,11 @@
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;
@@ -4253,7 +4367,7 @@
if (TryCallApply(expr)) return;
CHECK_BAILOUT;
- HValue* receiver = VisitArgument(prop->obj());
+ VisitArgument(prop->obj());
CHECK_BAILOUT;
VisitArgumentList(expr->arguments());
CHECK_BAILOUT;
@@ -4263,36 +4377,57 @@
expr->RecordTypeFeedback(oracle());
ZoneMapList* types = expr->GetReceiverTypes();
+ HValue* receiver =
+ environment()->ExpressionStackAt(expr->arguments()->length());
if (expr->IsMonomorphic()) {
- AddCheckConstantFunction(expr, receiver, types->first(), true);
+ Handle<Map> receiver_map =
+ (types == NULL) ? Handle<Map>::null() : types->first();
+ if (TryInlineBuiltinFunction(expr,
+ receiver,
+ receiver_map,
+ expr->check_type())) {
+ return;
+ }
- if (TryMathFunctionInline(expr)) {
- return;
- } else if (TryInline(expr)) {
- if (subgraph()->HasExit()) {
- 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
- // predecessor blocks. Those environments contain the return
- // value on top and do not correspond to any actual state of the
- // unoptimized code.
- if (ast_context()->IsEffect()) AddSimulate(expr->id());
- ast_context()->ReturnValue(return_value);
+ if (HasCustomCallGenerator(expr->target()) ||
+ expr->check_type() != RECEIVER_MAP_CHECK) {
+ // 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.
+ HContext* context = new HContext;
+ AddInstruction(context);
+ call = new HCallNamed(context, name, argument_count);
+ } else {
+ AddCheckConstantFunction(expr, receiver, receiver_map, true);
+
+ if (TryInline(expr)) {
+ if (subgraph()->HasExit()) {
+ 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
+ // predecessor blocks. Those environments contain the return
+ // value on top and do not correspond to any actual state of the
+ // unoptimized code.
+ if (ast_context()->IsEffect()) AddSimulate(expr->id());
+ ast_context()->ReturnValue(return_value);
+ }
+ return;
+ } else {
+ // 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);
}
- return;
- } else {
- // 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);
}
-
} else if (types != NULL && types->length() > 1) {
+ ASSERT(expr->check_type() == RECEIVER_MAP_CHECK);
HandlePolymorphicCallNamed(expr, receiver, types, name);
return;
} else {
- call = new HCallNamed(name, argument_count);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ call = new HCallNamed(context, name, argument_count);
}
} else {
@@ -4317,7 +4452,10 @@
if (known_global_function) {
// Push the global object instead of the global receiver because
// code generated by the full code generator expects it.
- PushAndAdd(new HGlobalObject);
+ HContext* context = new HContext;
+ HGlobalObject* global_object = new HGlobalObject(context);
+ AddInstruction(context);
+ PushAndAdd(global_object);
VisitArgumentList(expr->arguments());
CHECK_BAILOUT;
@@ -4326,7 +4464,7 @@
AddInstruction(new HCheckFunction(function, expr->target()));
// Replace the global object with the global receiver.
- HGlobalReceiver* global_receiver = new HGlobalReceiver;
+ HGlobalReceiver* global_receiver = new HGlobalReceiver(global_object);
// Index of the receiver from the top of the expression stack.
const int receiver_index = argument_count - 1;
AddInstruction(global_receiver);
@@ -4353,24 +4491,30 @@
call = new HCallKnownGlobal(expr->target(), argument_count);
} else {
- PushAndAdd(new HGlobalObject);
+ HContext* context = new HContext;
+ AddInstruction(context);
+ PushAndAdd(new HGlobalObject(context));
VisitArgumentList(expr->arguments());
CHECK_BAILOUT;
- call = new HCallGlobal(var->name(), argument_count);
+ call = new HCallGlobal(context, var->name(), argument_count);
}
} else {
- PushAndAdd(new HGlobalReceiver);
+ HContext* context = new HContext;
+ HGlobalObject* global_object = new HGlobalObject(context);
+ AddInstruction(context);
+ AddInstruction(global_object);
+ PushAndAdd(new HGlobalReceiver(global_object));
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());
}
@@ -4383,10 +4527,16 @@
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());
}
@@ -4440,7 +4590,7 @@
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());
}
}
@@ -4467,12 +4617,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 {
@@ -4552,10 +4708,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
@@ -4571,9 +4723,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);
@@ -4652,7 +4811,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
@@ -4673,6 +4832,18 @@
}
+HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string,
+ HValue* index) {
+ AddInstruction(new HCheckNonSmi(string));
+ AddInstruction(new HCheckInstanceType(
+ string, FIRST_STRING_TYPE, LAST_STRING_TYPE));
+ HStringLength* length = new HStringLength(string);
+ AddInstruction(length);
+ AddInstruction(new HBoundsCheck(index, length));
+ return new HStringCharCodeAt(string, index);
+}
+
+
HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr,
HValue* left,
HValue* right) {
@@ -4714,7 +4885,7 @@
default:
UNREACHABLE();
}
- TypeInfo info = oracle()->BinaryType(expr, TypeFeedbackOracle::RESULT);
+ TypeInfo info = oracle()->BinaryType(expr);
// If we hit an uninitialized binary op stub we will get type info
// for a smi operation. If one of the operands is a constant string
// do not generate code assuming it is a smi operation.
@@ -4726,7 +4897,12 @@
if (FLAG_trace_representation) {
PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic());
}
- AssumeRepresentation(instr, ToRepresentation(info));
+ Representation rep = ToRepresentation(info);
+ // We only generate either int32 or generic tagged bitwise operations.
+ if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) {
+ rep = Representation::Integer32();
+ }
+ AssumeRepresentation(instr, rep);
return instr;
}
@@ -4807,7 +4983,8 @@
graph_->GetMaximumValueID());
}
value->ChangeRepresentation(r);
- // The representation of the value is dictated by type feedback.
+ // The representation of the value is dictated by type feedback and
+ // will not be changed later.
value->ClearFlag(HValue::kFlexibleRepresentation);
} else if (FLAG_trace_representation) {
PrintF("No representation assumed\n");
@@ -4859,10 +5036,45 @@
HValue* left = Pop();
Token::Value op = expr->op();
- TypeInfo info = oracle()->CompareType(expr, TypeFeedbackOracle::RESULT);
+ TypeInfo info = oracle()->CompareType(expr);
HInstruction* instr = NULL;
if (op == Token::INSTANCEOF) {
- instr = new HInstanceOf(left, right);
+ // Check to see if the rhs of the instanceof is a global function not
+ // residing in new space. If it is we assume that the function will stay the
+ // same.
+ Handle<JSFunction> target = Handle<JSFunction>::null();
+ Variable* var = expr->right()->AsVariableProxy()->AsVariable();
+ bool global_function = (var != NULL) && var->is_global() && !var->is_this();
+ CompilationInfo* info = graph()->info();
+ if (global_function &&
+ info->has_global_object() &&
+ !info->global_object()->IsAccessCheckNeeded()) {
+ Handle<String> name = var->name();
+ Handle<GlobalObject> global(info->global_object());
+ LookupResult lookup;
+ global->Lookup(*name, &lookup);
+ if (lookup.IsProperty() &&
+ lookup.type() == NORMAL &&
+ lookup.GetValue()->IsJSFunction()) {
+ Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue()));
+ // If the function is in new space we assume it's more likely to
+ // change and thus prefer the general IC code.
+ if (!Heap::InNewSpace(*candidate)) {
+ target = candidate;
+ }
+ }
+ }
+
+ // 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()) {
+ HContext* context = new HContext;
+ AddInstruction(context);
+ instr = new HInstanceOf(context, left, right);
+ } else {
+ AddInstruction(new HCheckFunction(right, target));
+ instr = new HInstanceOfKnownGlobal(left, target);
+ }
} else if (op == Token::IN) {
BAILOUT("Unsupported comparison: in");
} else if (info.IsNonPrimitive()) {
@@ -5001,9 +5213,10 @@
}
- // 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);
}
@@ -5049,7 +5262,11 @@
// Fast support for charCodeAt(n).
void HGraphBuilder::GenerateStringCharCodeAt(int argument_count, int ast_id) {
- BAILOUT("inlined runtime function: StringCharCodeAt");
+ ASSERT(argument_count == 2);
+ HValue* index = Pop();
+ HValue* string = Pop();
+ HStringCharCodeAt* result = BuildStringCharCodeAt(string, index);
+ ast_context()->ReturnInstruction(result, ast_id);
}
@@ -5063,8 +5280,11 @@
// 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);
}
@@ -5093,8 +5313,11 @@
// 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);
}
@@ -5102,8 +5325,11 @@
// 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);
}
@@ -5111,8 +5337,11 @@
// 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);
}
@@ -5120,8 +5349,11 @@
// 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);
}
@@ -5130,9 +5362,11 @@
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);
}
@@ -5146,8 +5380,11 @@
// 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);
}
@@ -5178,30 +5415,36 @@
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);
}
@@ -5663,31 +5906,40 @@
PrintF("%30s", names_[i]);
double ms = static_cast<double>(timing_[i]) / 1000;
double percent = static_cast<double>(timing_[i]) * 100 / sum;
- PrintF(" - %0.3f ms / %0.3f %% \n", ms, percent);
+ PrintF(" - %7.3f ms / %4.1f %% ", ms, percent);
+
+ unsigned size = sizes_[i];
+ double size_percent = static_cast<double>(size) * 100 / total_size_;
+ PrintF(" %8u bytes / %4.1f %%\n", size, size_percent);
}
- PrintF("%30s - %0.3f ms \n", "Sum", static_cast<double>(sum) / 1000);
+ PrintF("%30s - %7.3f ms %8u bytes\n", "Sum",
+ static_cast<double>(sum) / 1000,
+ total_size_);
PrintF("---------------------------------------------------------------\n");
- PrintF("%30s - %0.3f ms (%0.1f times slower than full code gen)\n",
+ PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n",
"Total",
static_cast<double>(total_) / 1000,
static_cast<double>(total_) / full_code_gen_);
}
-void HStatistics::SaveTiming(const char* name, int64_t ticks) {
+void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) {
if (name == HPhase::kFullCodeGen) {
full_code_gen_ += ticks;
} else if (name == HPhase::kTotal) {
total_ += ticks;
} else {
+ total_size_ += size;
for (int i = 0; i < names_.length(); ++i) {
if (names_[i] == name) {
timing_[i] += ticks;
+ sizes_[i] += size;
return;
}
}
names_.Add(name);
timing_.Add(ticks);
+ sizes_.Add(size);
}
}
@@ -5708,13 +5960,15 @@
chunk_ = allocator->chunk();
}
if (FLAG_time_hydrogen) start_ = OS::Ticks();
+ start_allocation_size_ = Zone::allocation_size_;
}
void HPhase::End() const {
if (FLAG_time_hydrogen) {
int64_t end = OS::Ticks();
- HStatistics::Instance()->SaveTiming(name_, end - start_);
+ unsigned size = Zone::allocation_size_ - start_allocation_size_;
+ HStatistics::Instance()->SaveTiming(name_, end - start_, size);
}
if (FLAG_trace_hydrogen) {
@@ -5727,7 +5981,6 @@
#ifdef DEBUG
if (graph_ != NULL) graph_->Verify();
- if (chunk_ != NULL) chunk_->Verify();
if (allocator_ != NULL) allocator_->Verify();
#endif
}
« 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