summaryrefslogtreecommitdiff
path: root/chromium/v8/src/hydrogen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/v8/src/hydrogen.cc')
-rw-r--r--chromium/v8/src/hydrogen.cc3523
1 files changed, 2316 insertions, 1207 deletions
diff --git a/chromium/v8/src/hydrogen.cc b/chromium/v8/src/hydrogen.cc
index 0b4fb26c199..cdf69e7c72c 100644
--- a/chromium/v8/src/hydrogen.cc
+++ b/chromium/v8/src/hydrogen.cc
@@ -30,21 +30,24 @@
#include <algorithm>
#include "v8.h"
+#include "allocation-site-scopes.h"
#include "codegen.h"
#include "full-codegen.h"
#include "hashmap.h"
#include "hydrogen-bce.h"
#include "hydrogen-bch.h"
#include "hydrogen-canonicalize.h"
+#include "hydrogen-check-elimination.h"
#include "hydrogen-dce.h"
#include "hydrogen-dehoist.h"
-#include "hydrogen-deoptimizing-mark.h"
#include "hydrogen-environment-liveness.h"
#include "hydrogen-escape-analysis.h"
#include "hydrogen-infer-representation.h"
#include "hydrogen-infer-types.h"
+#include "hydrogen-load-elimination.h"
#include "hydrogen-gvn.h"
#include "hydrogen-mark-deoptimize.h"
+#include "hydrogen-mark-unreachable.h"
#include "hydrogen-minus-zero.h"
#include "hydrogen-osr.h"
#include "hydrogen-range-analysis.h"
@@ -55,6 +58,7 @@
#include "hydrogen-uint32-analysis.h"
#include "lithium-allocator.h"
#include "parser.h"
+#include "runtime.h"
#include "scopeinfo.h"
#include "scopes.h"
#include "stub-cache.h"
@@ -94,7 +98,7 @@ HBasicBlock::HBasicBlock(HGraph* graph)
parent_loop_header_(NULL),
inlined_entry_block_(NULL),
is_inline_return_target_(false),
- is_deoptimizing_(false),
+ is_reachable_(true),
dominates_loop_successors_(false),
is_osr_entry_(false) { }
@@ -104,6 +108,11 @@ Isolate* HBasicBlock::isolate() const {
}
+void HBasicBlock::MarkUnreachable() {
+ is_reachable_ = false;
+}
+
+
void HBasicBlock::AttachLoopInformation() {
ASSERT(!IsLoopHeader());
loop_information_ = new(zone()) HLoopInformation(this, zone());
@@ -132,16 +141,25 @@ void HBasicBlock::RemovePhi(HPhi* phi) {
}
-void HBasicBlock::AddInstruction(HInstruction* instr) {
+void HBasicBlock::AddInstruction(HInstruction* instr, int position) {
ASSERT(!IsStartBlock() || !IsFinished());
ASSERT(!instr->IsLinked());
ASSERT(!IsFinished());
+ if (position != RelocInfo::kNoPosition) {
+ instr->set_position(position);
+ }
if (first_ == NULL) {
ASSERT(last_environment() != NULL);
ASSERT(!last_environment()->ast_id().IsNone());
HBlockEntry* entry = new(zone()) HBlockEntry();
entry->InitializeAsFirst(this);
+ if (position != RelocInfo::kNoPosition) {
+ entry->set_position(position);
+ } else {
+ ASSERT(!FLAG_emit_opt_code_positions ||
+ !graph()->info()->IsOptimizing());
+ }
first_ = last_ = entry;
}
instr->InsertAfter(last_);
@@ -192,9 +210,9 @@ HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id,
}
-void HBasicBlock::Finish(HControlInstruction* end) {
+void HBasicBlock::Finish(HControlInstruction* end, int position) {
ASSERT(!IsFinished());
- AddInstruction(end);
+ AddInstruction(end, position);
end_ = end;
for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
it.Current()->RegisterPredecessor(this);
@@ -203,35 +221,44 @@ void HBasicBlock::Finish(HControlInstruction* end) {
void HBasicBlock::Goto(HBasicBlock* block,
+ int position,
FunctionState* state,
bool add_simulate) {
bool drop_extra = state != NULL &&
state->inlining_kind() == DROP_EXTRA_ON_RETURN;
if (block->IsInlineReturnTarget()) {
- AddInstruction(new(zone()) HLeaveInlined());
+ HEnvironment* env = last_environment();
+ int argument_count = env->arguments_environment()->parameter_count();
+ AddInstruction(new(zone())
+ HLeaveInlined(state->entry(), argument_count),
+ position);
UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
}
- if (add_simulate) AddNewSimulate(BailoutId::None());
+ if (add_simulate) AddNewSimulate(BailoutId::None(), position);
HGoto* instr = new(zone()) HGoto(block);
- Finish(instr);
+ Finish(instr, position);
}
void HBasicBlock::AddLeaveInlined(HValue* return_value,
- FunctionState* state) {
+ FunctionState* state,
+ int position) {
HBasicBlock* target = state->function_return();
bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN;
ASSERT(target->IsInlineReturnTarget());
ASSERT(return_value != NULL);
- AddInstruction(new(zone()) HLeaveInlined());
+ HEnvironment* env = last_environment();
+ int argument_count = env->arguments_environment()->parameter_count();
+ AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count),
+ position);
UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
last_environment()->Push(return_value);
- AddNewSimulate(BailoutId::None());
+ AddNewSimulate(BailoutId::None(), position);
HGoto* instr = new(zone()) HGoto(target);
- Finish(instr);
+ Finish(instr, position);
}
@@ -579,7 +606,8 @@ void HGraph::Verify(bool do_full_verify) const {
block->predecessors()->first()->last_environment()->ast_id();
for (int k = 0; k < block->predecessors()->length(); k++) {
HBasicBlock* predecessor = block->predecessors()->at(k);
- ASSERT(predecessor->end()->IsGoto());
+ ASSERT(predecessor->end()->IsGoto() ||
+ predecessor->end()->IsDeoptimize());
ASSERT(predecessor->last_environment()->ast_id() == id);
}
}
@@ -622,10 +650,21 @@ HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer,
// Can't pass GetInvalidContext() to HConstant::New, because that will
// recursively call GetConstant
HConstant* constant = HConstant::New(zone(), NULL, value);
- constant->InsertAfter(GetConstantUndefined());
+ constant->InsertAfter(entry_block()->first());
pointer->set(constant);
+ return constant;
+ }
+ return ReinsertConstantIfNecessary(pointer->get());
+}
+
+
+HConstant* HGraph::ReinsertConstantIfNecessary(HConstant* constant) {
+ if (!constant->IsLinked()) {
+ // The constant was removed from the graph. Reinsert.
+ constant->ClearFlag(HValue::kIsDead);
+ constant->InsertAfter(entry_block()->first());
}
- return pointer->get();
+ return constant;
}
@@ -648,21 +687,21 @@ HConstant* HGraph::GetConstantMinus1() {
HConstant* HGraph::GetConstant##Name() { \
if (!constant_##name##_.is_set()) { \
HConstant* constant = new(zone()) HConstant( \
- isolate()->factory()->name##_value(), \
- UniqueValueId::name##_value(isolate()->heap()), \
+ Unique<Object>::CreateImmovable(isolate()->factory()->name##_value()), \
Representation::Tagged(), \
htype, \
false, \
true, \
false, \
boolean_value); \
- constant->InsertAfter(GetConstantUndefined()); \
+ constant->InsertAfter(entry_block()->first()); \
constant_##name##_.set(constant); \
} \
- return constant_##name##_.get(); \
+ return ReinsertConstantIfNecessary(constant_##name##_.get()); \
}
+DEFINE_GET_CONSTANT(Undefined, undefined, HType::Tagged(), false)
DEFINE_GET_CONSTANT(True, true, HType::Boolean(), true)
DEFINE_GET_CONSTANT(False, false, HType::Boolean(), false)
DEFINE_GET_CONSTANT(Hole, the_hole, HType::Tagged(), false)
@@ -705,23 +744,23 @@ bool HGraph::IsStandardConstant(HConstant* constant) {
}
-HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, int position)
+HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder)
: builder_(builder),
- position_(position),
finished_(false),
- deopt_then_(false),
- deopt_else_(false),
did_then_(false),
did_else_(false),
+ did_else_if_(false),
did_and_(false),
did_or_(false),
captured_(false),
needs_compare_(true),
+ pending_merge_block_(false),
split_edge_merge_block_(NULL),
- merge_block_(NULL) {
+ merge_at_join_blocks_(NULL),
+ normal_merge_at_join_block_count_(0),
+ deopt_merge_at_join_block_count_(0) {
HEnvironment* env = builder->environment();
first_true_block_ = builder->CreateBasicBlock(env->Copy());
- last_true_block_ = NULL;
first_false_block_ = builder->CreateBasicBlock(env->Copy());
}
@@ -730,27 +769,42 @@ HGraphBuilder::IfBuilder::IfBuilder(
HGraphBuilder* builder,
HIfContinuation* continuation)
: builder_(builder),
- position_(RelocInfo::kNoPosition),
finished_(false),
- deopt_then_(false),
- deopt_else_(false),
did_then_(false),
did_else_(false),
+ did_else_if_(false),
did_and_(false),
did_or_(false),
captured_(false),
needs_compare_(false),
+ pending_merge_block_(false),
first_true_block_(NULL),
first_false_block_(NULL),
split_edge_merge_block_(NULL),
- merge_block_(NULL) {
+ merge_at_join_blocks_(NULL),
+ normal_merge_at_join_block_count_(0),
+ deopt_merge_at_join_block_count_(0) {
continuation->Continue(&first_true_block_,
- &first_false_block_,
- &position_);
+ &first_false_block_);
}
-void HGraphBuilder::IfBuilder::AddCompare(HControlInstruction* compare) {
+HControlInstruction* HGraphBuilder::IfBuilder::AddCompare(
+ HControlInstruction* compare) {
+ ASSERT(did_then_ == did_else_);
+ if (did_else_) {
+ // Handle if-then-elseif
+ did_else_if_ = true;
+ did_else_ = false;
+ did_then_ = false;
+ did_and_ = false;
+ did_or_ = false;
+ pending_merge_block_ = false;
+ split_edge_merge_block_ = NULL;
+ HEnvironment* env = builder_->environment();
+ first_true_block_ = builder_->CreateBasicBlock(env->Copy());
+ first_false_block_ = builder_->CreateBasicBlock(env->Copy());
+ }
if (split_edge_merge_block_ != NULL) {
HEnvironment* env = first_false_block_->last_environment();
HBasicBlock* split_edge =
@@ -762,24 +816,26 @@ void HGraphBuilder::IfBuilder::AddCompare(HControlInstruction* compare) {
compare->SetSuccessorAt(0, first_true_block_);
compare->SetSuccessorAt(1, split_edge);
}
- split_edge->GotoNoSimulate(split_edge_merge_block_);
+ builder_->GotoNoSimulate(split_edge, split_edge_merge_block_);
} else {
compare->SetSuccessorAt(0, first_true_block_);
compare->SetSuccessorAt(1, first_false_block_);
}
- builder_->current_block()->Finish(compare);
+ builder_->FinishCurrentBlock(compare);
needs_compare_ = false;
+ return compare;
}
void HGraphBuilder::IfBuilder::Or() {
+ ASSERT(!needs_compare_);
ASSERT(!did_and_);
did_or_ = true;
HEnvironment* env = first_false_block_->last_environment();
if (split_edge_merge_block_ == NULL) {
split_edge_merge_block_ =
builder_->CreateBasicBlock(env->Copy());
- first_true_block_->GotoNoSimulate(split_edge_merge_block_);
+ builder_->GotoNoSimulate(first_true_block_, split_edge_merge_block_);
first_true_block_ = split_edge_merge_block_;
}
builder_->set_current_block(first_false_block_);
@@ -788,12 +844,13 @@ void HGraphBuilder::IfBuilder::Or() {
void HGraphBuilder::IfBuilder::And() {
+ ASSERT(!needs_compare_);
ASSERT(!did_or_);
did_and_ = true;
HEnvironment* env = first_false_block_->last_environment();
if (split_edge_merge_block_ == NULL) {
split_edge_merge_block_ = builder_->CreateBasicBlock(env->Copy());
- first_false_block_->GotoNoSimulate(split_edge_merge_block_);
+ builder_->GotoNoSimulate(first_false_block_, split_edge_merge_block_);
first_false_block_ = split_edge_merge_block_;
}
builder_->set_current_block(first_true_block_);
@@ -803,15 +860,38 @@ void HGraphBuilder::IfBuilder::And() {
void HGraphBuilder::IfBuilder::CaptureContinuation(
HIfContinuation* continuation) {
+ ASSERT(!did_else_if_);
ASSERT(!finished_);
ASSERT(!captured_);
- HBasicBlock* true_block = last_true_block_ == NULL
- ? first_true_block_
- : last_true_block_;
- HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL)
- ? builder_->current_block()
- : first_false_block_;
- continuation->Capture(true_block, false_block, position_);
+
+ HBasicBlock* true_block = NULL;
+ HBasicBlock* false_block = NULL;
+ Finish(&true_block, &false_block);
+ ASSERT(true_block != NULL);
+ ASSERT(false_block != NULL);
+ continuation->Capture(true_block, false_block);
+ captured_ = true;
+ builder_->set_current_block(NULL);
+ End();
+}
+
+
+void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) {
+ ASSERT(!did_else_if_);
+ ASSERT(!finished_);
+ ASSERT(!captured_);
+ HBasicBlock* true_block = NULL;
+ HBasicBlock* false_block = NULL;
+ Finish(&true_block, &false_block);
+ merge_at_join_blocks_ = NULL;
+ if (true_block != NULL && !true_block->IsFinished()) {
+ ASSERT(continuation->IsTrueReachable());
+ builder_->GotoNoSimulate(true_block, continuation->true_branch());
+ }
+ if (false_block != NULL && !false_block->IsFinished()) {
+ ASSERT(continuation->IsFalseReachable());
+ builder_->GotoNoSimulate(false_block, continuation->false_branch());
+ }
captured_ = true;
End();
}
@@ -829,12 +909,12 @@ void HGraphBuilder::IfBuilder::Then() {
HConstant* constant_false = builder_->graph()->GetConstantFalse();
ToBooleanStub::Types boolean_type = ToBooleanStub::Types();
boolean_type.Add(ToBooleanStub::BOOLEAN);
- HBranch* branch =
- new(zone()) HBranch(constant_false, boolean_type, first_true_block_,
- first_false_block_);
- builder_->current_block()->Finish(branch);
+ HBranch* branch = builder()->New<HBranch>(
+ constant_false, boolean_type, first_true_block_, first_false_block_);
+ builder_->FinishCurrentBlock(branch);
}
builder_->set_current_block(first_true_block_);
+ pending_merge_block_ = true;
}
@@ -842,73 +922,117 @@ void HGraphBuilder::IfBuilder::Else() {
ASSERT(did_then_);
ASSERT(!captured_);
ASSERT(!finished_);
- last_true_block_ = builder_->current_block();
+ AddMergeAtJoinBlock(false);
builder_->set_current_block(first_false_block_);
+ pending_merge_block_ = true;
did_else_ = true;
}
void HGraphBuilder::IfBuilder::Deopt(const char* reason) {
ASSERT(did_then_);
- if (did_else_) {
- deopt_else_ = true;
- } else {
- deopt_then_ = true;
- }
builder_->Add<HDeoptimize>(reason, Deoptimizer::EAGER);
+ AddMergeAtJoinBlock(true);
}
void HGraphBuilder::IfBuilder::Return(HValue* value) {
- HBasicBlock* block = builder_->current_block();
HValue* parameter_count = builder_->graph()->GetConstantMinus1();
- block->FinishExit(builder_->New<HReturn>(value, parameter_count));
+ builder_->FinishExitCurrentBlock(
+ builder_->New<HReturn>(value, parameter_count));
+ AddMergeAtJoinBlock(false);
+}
+
+
+void HGraphBuilder::IfBuilder::AddMergeAtJoinBlock(bool deopt) {
+ if (!pending_merge_block_) return;
+ HBasicBlock* block = builder_->current_block();
+ ASSERT(block == NULL || !block->IsFinished());
+ MergeAtJoinBlock* record =
+ new(builder_->zone()) MergeAtJoinBlock(block, deopt,
+ merge_at_join_blocks_);
+ merge_at_join_blocks_ = record;
+ if (block != NULL) {
+ ASSERT(block->end() == NULL);
+ if (deopt) {
+ normal_merge_at_join_block_count_++;
+ } else {
+ deopt_merge_at_join_block_count_++;
+ }
+ }
builder_->set_current_block(NULL);
- if (did_else_) {
- first_false_block_ = NULL;
- } else {
- first_true_block_ = NULL;
+ pending_merge_block_ = false;
+}
+
+
+void HGraphBuilder::IfBuilder::Finish() {
+ ASSERT(!finished_);
+ if (!did_then_) {
+ Then();
+ }
+ AddMergeAtJoinBlock(false);
+ if (!did_else_) {
+ Else();
+ AddMergeAtJoinBlock(false);
+ }
+ finished_ = true;
+}
+
+
+void HGraphBuilder::IfBuilder::Finish(HBasicBlock** then_continuation,
+ HBasicBlock** else_continuation) {
+ Finish();
+
+ MergeAtJoinBlock* else_record = merge_at_join_blocks_;
+ if (else_continuation != NULL) {
+ *else_continuation = else_record->block_;
+ }
+ MergeAtJoinBlock* then_record = else_record->next_;
+ if (then_continuation != NULL) {
+ *then_continuation = then_record->block_;
}
+ ASSERT(then_record->next_ == NULL);
}
void HGraphBuilder::IfBuilder::End() {
- if (!captured_) {
- ASSERT(did_then_);
- if (!did_else_) {
- last_true_block_ = builder_->current_block();
- }
- if (last_true_block_ == NULL || last_true_block_->IsFinished()) {
- ASSERT(did_else_);
- // Return on true. Nothing to do, just continue the false block.
- } else if (first_false_block_ == NULL ||
- (did_else_ && builder_->current_block()->IsFinished())) {
- // Deopt on false. Nothing to do except switching to the true block.
- builder_->set_current_block(last_true_block_);
- } else {
- merge_block_ = builder_->graph()->CreateBasicBlock();
- ASSERT(!finished_);
- if (!did_else_) Else();
- ASSERT(!last_true_block_->IsFinished());
- HBasicBlock* last_false_block = builder_->current_block();
- ASSERT(!last_false_block->IsFinished());
- if (deopt_then_) {
- last_false_block->GotoNoSimulate(merge_block_);
- builder_->PadEnvironmentForContinuation(last_true_block_,
- merge_block_);
- last_true_block_->GotoNoSimulate(merge_block_);
- } else {
- last_true_block_->GotoNoSimulate(merge_block_);
- if (deopt_else_) {
- builder_->PadEnvironmentForContinuation(last_false_block,
- merge_block_);
- }
- last_false_block->GotoNoSimulate(merge_block_);
+ if (captured_) return;
+ Finish();
+
+ int total_merged_blocks = normal_merge_at_join_block_count_ +
+ deopt_merge_at_join_block_count_;
+ ASSERT(total_merged_blocks >= 1);
+ HBasicBlock* merge_block = total_merged_blocks == 1
+ ? NULL : builder_->graph()->CreateBasicBlock();
+
+ // Merge non-deopt blocks first to ensure environment has right size for
+ // padding.
+ MergeAtJoinBlock* current = merge_at_join_blocks_;
+ while (current != NULL) {
+ if (!current->deopt_ && current->block_ != NULL) {
+ // If there is only one block that makes it through to the end of the
+ // if, then just set it as the current block and continue rather then
+ // creating an unnecessary merge block.
+ if (total_merged_blocks == 1) {
+ builder_->set_current_block(current->block_);
+ return;
}
- builder_->set_current_block(merge_block_);
+ builder_->GotoNoSimulate(current->block_, merge_block);
}
+ current = current->next_;
}
- finished_ = true;
+
+ // Merge deopt blocks, padding when necessary.
+ current = merge_at_join_blocks_;
+ while (current != NULL) {
+ if (current->deopt_ && current->block_ != NULL) {
+ builder_->PadEnvironmentForContinuation(current->block_,
+ merge_block);
+ builder_->GotoNoSimulate(current->block_, merge_block);
+ }
+ current = current->next_;
+ }
+ builder_->set_current_block(merge_block);
}
@@ -951,7 +1075,7 @@ HValue* HGraphBuilder::LoopBuilder::BeginBody(
phi_ = header_block_->AddNewPhi(env->values()->length());
phi_->AddInput(initial);
env->Push(initial);
- builder_->current_block()->GotoNoSimulate(header_block_);
+ builder_->GotoNoSimulate(header_block_);
HEnvironment* body_env = env->Copy();
HEnvironment* exit_env = env->Copy();
@@ -963,11 +1087,8 @@ HValue* HGraphBuilder::LoopBuilder::BeginBody(
builder_->set_current_block(header_block_);
env->Pop();
- HCompareNumericAndBranch* compare =
- new(zone()) HCompareNumericAndBranch(phi_, terminating, token);
- compare->SetSuccessorAt(0, body_block_);
- compare->SetSuccessorAt(1, exit_block_);
- builder_->current_block()->Finish(compare);
+ builder_->FinishCurrentBlock(builder_->New<HCompareNumericAndBranch>(
+ phi_, terminating, token, body_block_, exit_block_));
builder_->set_current_block(body_block_);
if (direction_ == kPreIncrement || direction_ == kPreDecrement) {
@@ -991,10 +1112,11 @@ void HGraphBuilder::LoopBuilder::Break() {
// Its the first time we saw a break.
HEnvironment* env = exit_block_->last_environment()->Copy();
exit_trampoline_block_ = builder_->CreateBasicBlock(env);
- exit_block_->GotoNoSimulate(exit_trampoline_block_);
+ builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_);
}
- builder_->current_block()->GotoNoSimulate(exit_trampoline_block_);
+ builder_->GotoNoSimulate(exit_trampoline_block_);
+ builder_->set_current_block(NULL);
}
@@ -1014,7 +1136,7 @@ void HGraphBuilder::LoopBuilder::EndBody() {
// Push the new increment value on the expression stack to merge into the phi.
builder_->environment()->Push(increment_);
HBasicBlock* last_block = builder_->current_block();
- last_block->GotoNoSimulate(header_block_);
+ builder_->GotoNoSimulate(last_block, header_block_);
header_block_->loop_information()->RegisterBackEdge(last_block);
if (exit_trampoline_block_ != NULL) {
@@ -1032,14 +1154,16 @@ HGraph* HGraphBuilder::CreateGraph() {
CompilationPhase phase("H_Block building", info_);
set_current_block(graph()->entry_block());
if (!BuildGraph()) return NULL;
- graph()->FinalizeUniqueValueIds();
+ graph()->FinalizeUniqueness();
return graph_;
}
HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
ASSERT(current_block() != NULL);
- current_block()->AddInstruction(instr);
+ ASSERT(!FLAG_emit_opt_code_positions ||
+ position_ != RelocInfo::kNoPosition || !info_->IsOptimizing());
+ current_block()->AddInstruction(instr, position_);
if (graph()->IsInsideNoSideEffectsScope()) {
instr->SetFlag(HValue::kHasNoObservableSideEffects);
}
@@ -1047,13 +1171,32 @@ HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
}
-void HGraphBuilder::AddIncrementCounter(StatsCounter* counter,
- HValue* context) {
+void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) {
+ ASSERT(!FLAG_emit_opt_code_positions || !info_->IsOptimizing() ||
+ position_ != RelocInfo::kNoPosition);
+ current_block()->Finish(last, position_);
+ if (last->IsReturn() || last->IsAbnormalExit()) {
+ set_current_block(NULL);
+ }
+}
+
+
+void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) {
+ ASSERT(!FLAG_emit_opt_code_positions || !info_->IsOptimizing() ||
+ position_ != RelocInfo::kNoPosition);
+ current_block()->FinishExit(instruction, position_);
+ if (instruction->IsReturn() || instruction->IsAbnormalExit()) {
+ set_current_block(NULL);
+ }
+}
+
+
+void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) {
if (FLAG_native_code_counters && counter->Enabled()) {
HValue* reference = Add<HConstant>(ExternalReference(counter));
HValue* old_value = Add<HLoadNamedField>(reference,
HObjectAccess::ForCounter());
- HValue* new_value = Add<HAdd>(old_value, graph()->GetConstant1());
+ HValue* new_value = AddUncasted<HAdd>(old_value, graph()->GetConstant1());
new_value->ClearFlag(HValue::kCanOverflow); // Ignore counter overflow
Add<HStoreNamedField>(reference, HObjectAccess::ForCounter(),
new_value);
@@ -1096,9 +1239,9 @@ void HGraphBuilder::FinishExitWithHardDeoptimization(
PadEnvironmentForContinuation(current_block(), continuation);
Add<HDeoptimize>(reason, Deoptimizer::EAGER);
if (graph()->IsInsideNoSideEffectsScope()) {
- current_block()->GotoNoSimulate(continuation);
+ GotoNoSimulate(continuation);
} else {
- current_block()->Goto(continuation);
+ Goto(continuation);
}
}
@@ -1131,6 +1274,17 @@ HValue* HGraphBuilder::BuildCheckMap(HValue* obj, Handle<Map> map) {
}
+HValue* HGraphBuilder::BuildCheckString(HValue* string) {
+ if (!string->type().IsString()) {
+ ASSERT(!string->IsConstant() ||
+ !HConstant::cast(string)->HasStringValue());
+ BuildCheckHeapObject(string);
+ return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING);
+ }
+ return string;
+}
+
+
HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) {
if (object->type().IsJSObject()) return object;
return Add<HWrapReceiver>(object, function);
@@ -1143,7 +1297,6 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object,
HValue* length,
HValue* key,
bool is_js_array) {
- Zone* zone = this->zone();
IfBuilder length_checker(this);
Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ;
@@ -1159,10 +1312,8 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object,
Token::GTE);
capacity_checker.Then();
- HValue* context = environment()->context();
-
HValue* max_gap = Add<HConstant>(static_cast<int32_t>(JSObject::kMaxGap));
- HValue* max_capacity = Add<HAdd>(current_capacity, max_gap);
+ HValue* max_capacity = AddUncasted<HAdd>(current_capacity, max_gap);
IfBuilder key_checker(this);
key_checker.If<HCompareNumericAndBranch>(key, max_capacity, Token::LT);
key_checker.Then();
@@ -1181,8 +1332,7 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object,
capacity_checker.End();
if (is_js_array) {
- HValue* new_length = AddInstruction(
- HAdd::New(zone, context, key, graph_->GetConstant1()));
+ HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1());
new_length->ClearFlag(HValue::kCanOverflow);
Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind),
@@ -1267,6 +1417,608 @@ void HGraphBuilder::BuildTransitionElementsKind(HValue* object,
}
+HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoadHelper(
+ HValue* elements,
+ HValue* key,
+ HValue* hash,
+ HValue* mask,
+ int current_probe) {
+ if (current_probe == kNumberDictionaryProbes) {
+ return NULL;
+ }
+
+ int32_t offset = SeededNumberDictionary::GetProbeOffset(current_probe);
+ HValue* raw_index = (current_probe == 0)
+ ? hash
+ : AddUncasted<HAdd>(hash, Add<HConstant>(offset));
+ raw_index = AddUncasted<HBitwise>(Token::BIT_AND, raw_index, mask);
+ int32_t entry_size = SeededNumberDictionary::kEntrySize;
+ raw_index = AddUncasted<HMul>(raw_index, Add<HConstant>(entry_size));
+ raw_index->ClearFlag(HValue::kCanOverflow);
+
+ int32_t base_offset = SeededNumberDictionary::kElementsStartIndex;
+ HValue* key_index = AddUncasted<HAdd>(raw_index, Add<HConstant>(base_offset));
+ key_index->ClearFlag(HValue::kCanOverflow);
+
+ HValue* candidate_key = Add<HLoadKeyed>(elements, key_index,
+ static_cast<HValue*>(NULL),
+ FAST_SMI_ELEMENTS);
+
+ IfBuilder key_compare(this);
+ key_compare.IfNot<HCompareObjectEqAndBranch>(key, candidate_key);
+ key_compare.Then();
+ {
+ // Key at the current probe doesn't match, try at the next probe.
+ HValue* result = BuildUncheckedDictionaryElementLoadHelper(
+ elements, key, hash, mask, current_probe + 1);
+ if (result == NULL) {
+ key_compare.Deopt("probes exhausted in keyed load dictionary lookup");
+ result = graph()->GetConstantUndefined();
+ } else {
+ Push(result);
+ }
+ }
+ key_compare.Else();
+ {
+ // Key at current probe matches. Details must be zero, otherwise the
+ // dictionary element requires special handling.
+ HValue* details_index = AddUncasted<HAdd>(
+ raw_index, Add<HConstant>(base_offset + 2));
+ details_index->ClearFlag(HValue::kCanOverflow);
+
+ HValue* details = Add<HLoadKeyed>(elements, details_index,
+ static_cast<HValue*>(NULL),
+ FAST_SMI_ELEMENTS);
+ IfBuilder details_compare(this);
+ details_compare.If<HCompareNumericAndBranch>(details,
+ graph()->GetConstant0(),
+ Token::NE);
+ details_compare.ThenDeopt("keyed load dictionary element not fast case");
+
+ details_compare.Else();
+ {
+ // Key matches and details are zero --> fast case. Load and return the
+ // value.
+ HValue* result_index = AddUncasted<HAdd>(
+ raw_index, Add<HConstant>(base_offset + 1));
+ result_index->ClearFlag(HValue::kCanOverflow);
+
+ Push(Add<HLoadKeyed>(elements, result_index,
+ static_cast<HValue*>(NULL),
+ FAST_ELEMENTS));
+ }
+ details_compare.End();
+ }
+ key_compare.End();
+
+ return Pop();
+}
+
+
+HValue* HGraphBuilder::BuildElementIndexHash(HValue* index) {
+ int32_t seed_value = static_cast<uint32_t>(isolate()->heap()->HashSeed());
+ HValue* seed = Add<HConstant>(seed_value);
+ HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, index, seed);
+
+ // hash = ~hash + (hash << 15);
+ HValue* shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(15));
+ HValue* not_hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash,
+ graph()->GetConstantMinus1());
+ hash = AddUncasted<HAdd>(shifted_hash, not_hash);
+
+ // hash = hash ^ (hash >> 12);
+ shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(12));
+ hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
+
+ // hash = hash + (hash << 2);
+ shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(2));
+ hash = AddUncasted<HAdd>(hash, shifted_hash);
+
+ // hash = hash ^ (hash >> 4);
+ shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(4));
+ hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
+
+ // hash = hash * 2057;
+ hash = AddUncasted<HMul>(hash, Add<HConstant>(2057));
+ hash->ClearFlag(HValue::kCanOverflow);
+
+ // hash = hash ^ (hash >> 16);
+ shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16));
+ return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash);
+}
+
+
+HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver,
+ HValue* key) {
+ HValue* elements = AddLoadElements(receiver);
+
+ HValue* hash = BuildElementIndexHash(key);
+
+ HValue* capacity = Add<HLoadKeyed>(
+ elements,
+ Add<HConstant>(NameDictionary::kCapacityIndex),
+ static_cast<HValue*>(NULL),
+ FAST_SMI_ELEMENTS);
+
+ HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1());
+ mask->ChangeRepresentation(Representation::Integer32());
+ mask->ClearFlag(HValue::kCanOverflow);
+
+ return BuildUncheckedDictionaryElementLoadHelper(elements, key,
+ hash, mask, 0);
+}
+
+
+HValue* HGraphBuilder::BuildNumberToString(HValue* object,
+ Handle<Type> type) {
+ NoObservableSideEffectsScope scope(this);
+
+ // Convert constant numbers at compile time.
+ if (object->IsConstant() && HConstant::cast(object)->HasNumberValue()) {
+ Handle<Object> number = HConstant::cast(object)->handle(isolate());
+ Handle<String> result = isolate()->factory()->NumberToString(number);
+ return Add<HConstant>(result);
+ }
+
+ // Create a joinable continuation.
+ HIfContinuation found(graph()->CreateBasicBlock(),
+ graph()->CreateBasicBlock());
+
+ // Load the number string cache.
+ HValue* number_string_cache =
+ Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex);
+
+ // Make the hash mask from the length of the number string cache. It
+ // contains two elements (number and string) for each cache entry.
+ HValue* mask = AddLoadFixedArrayLength(number_string_cache);
+ mask->set_type(HType::Smi());
+ mask = AddUncasted<HSar>(mask, graph()->GetConstant1());
+ mask = AddUncasted<HSub>(mask, graph()->GetConstant1());
+
+ // Check whether object is a smi.
+ IfBuilder if_objectissmi(this);
+ if_objectissmi.If<HIsSmiAndBranch>(object);
+ if_objectissmi.Then();
+ {
+ // Compute hash for smi similar to smi_get_hash().
+ HValue* hash = AddUncasted<HBitwise>(Token::BIT_AND, object, mask);
+
+ // Load the key.
+ HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
+ HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
+ static_cast<HValue*>(NULL),
+ FAST_ELEMENTS, ALLOW_RETURN_HOLE);
+
+ // Check if object == key.
+ IfBuilder if_objectiskey(this);
+ if_objectiskey.If<HCompareObjectEqAndBranch>(object, key);
+ if_objectiskey.Then();
+ {
+ // Make the key_index available.
+ Push(key_index);
+ }
+ if_objectiskey.JoinContinuation(&found);
+ }
+ if_objectissmi.Else();
+ {
+ if (type->Is(Type::Smi())) {
+ if_objectissmi.Deopt("Expected smi");
+ } else {
+ // Check if the object is a heap number.
+ IfBuilder if_objectisnumber(this);
+ if_objectisnumber.If<HCompareMap>(
+ object, isolate()->factory()->heap_number_map());
+ if_objectisnumber.Then();
+ {
+ // Compute hash for heap number similar to double_get_hash().
+ HValue* low = Add<HLoadNamedField>(
+ object, HObjectAccess::ForHeapNumberValueLowestBits());
+ HValue* high = Add<HLoadNamedField>(
+ object, HObjectAccess::ForHeapNumberValueHighestBits());
+ HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, low, high);
+ hash = AddUncasted<HBitwise>(Token::BIT_AND, hash, mask);
+
+ // Load the key.
+ HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1());
+ HValue* key = Add<HLoadKeyed>(number_string_cache, key_index,
+ static_cast<HValue*>(NULL),
+ FAST_ELEMENTS, ALLOW_RETURN_HOLE);
+
+ // Check if key is a heap number (the number string cache contains only
+ // SMIs and heap number, so it is sufficient to do a SMI check here).
+ IfBuilder if_keyisnotsmi(this);
+ if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key);
+ if_keyisnotsmi.Then();
+ {
+ // Check if values of key and object match.
+ IfBuilder if_keyeqobject(this);
+ if_keyeqobject.If<HCompareNumericAndBranch>(
+ Add<HLoadNamedField>(key, HObjectAccess::ForHeapNumberValue()),
+ Add<HLoadNamedField>(object, HObjectAccess::ForHeapNumberValue()),
+ Token::EQ);
+ if_keyeqobject.Then();
+ {
+ // Make the key_index available.
+ Push(key_index);
+ }
+ if_keyeqobject.JoinContinuation(&found);
+ }
+ if_keyisnotsmi.JoinContinuation(&found);
+ }
+ if_objectisnumber.Else();
+ {
+ if (type->Is(Type::Number())) {
+ if_objectisnumber.Deopt("Expected heap number");
+ }
+ }
+ if_objectisnumber.JoinContinuation(&found);
+ }
+ }
+ if_objectissmi.JoinContinuation(&found);
+
+ // Check for cache hit.
+ IfBuilder if_found(this, &found);
+ if_found.Then();
+ {
+ // Count number to string operation in native code.
+ AddIncrementCounter(isolate()->counters()->number_to_string_native());
+
+ // Load the value in case of cache hit.
+ HValue* key_index = Pop();
+ HValue* value_index = AddUncasted<HAdd>(key_index, graph()->GetConstant1());
+ Push(Add<HLoadKeyed>(number_string_cache, value_index,
+ static_cast<HValue*>(NULL),
+ FAST_ELEMENTS, ALLOW_RETURN_HOLE));
+ }
+ if_found.Else();
+ {
+ // Cache miss, fallback to runtime.
+ Add<HPushArgument>(object);
+ Push(Add<HCallRuntime>(
+ isolate()->factory()->empty_string(),
+ Runtime::FunctionForId(Runtime::kNumberToStringSkipCache),
+ 1));
+ }
+ if_found.End();
+
+ return Pop();
+}
+
+
+HValue* HGraphBuilder::BuildSeqStringSizeFor(HValue* length,
+ String::Encoding encoding) {
+ STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0);
+ HValue* size = length;
+ if (encoding == String::TWO_BYTE_ENCODING) {
+ size = AddUncasted<HShl>(length, graph()->GetConstant1());
+ size->ClearFlag(HValue::kCanOverflow);
+ size->SetFlag(HValue::kUint32);
+ }
+ size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>(
+ SeqString::kHeaderSize + kObjectAlignmentMask)));
+ size->ClearFlag(HValue::kCanOverflow);
+ size = AddUncasted<HBitwise>(
+ Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>(
+ ~kObjectAlignmentMask)));
+ return size;
+}
+
+
+void HGraphBuilder::BuildCopySeqStringChars(HValue* src,
+ HValue* src_offset,
+ String::Encoding src_encoding,
+ HValue* dst,
+ HValue* dst_offset,
+ String::Encoding dst_encoding,
+ HValue* length) {
+ ASSERT(dst_encoding != String::ONE_BYTE_ENCODING ||
+ src_encoding == String::ONE_BYTE_ENCODING);
+ LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement);
+ HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT);
+ {
+ HValue* src_index = AddUncasted<HAdd>(src_offset, index);
+ HValue* value =
+ AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index);
+ HValue* dst_index = AddUncasted<HAdd>(dst_offset, index);
+ Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value);
+ }
+ loop.EndBody();
+}
+
+
+HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left,
+ HValue* right,
+ PretenureFlag pretenure_flag) {
+ // Determine the string lengths.
+ HValue* left_length = Add<HLoadNamedField>(
+ left, HObjectAccess::ForStringLength());
+ HValue* right_length = Add<HLoadNamedField>(
+ right, HObjectAccess::ForStringLength());
+
+ // Compute the combined string length. If the result is larger than the max
+ // supported string length, we bailout to the runtime. This is done implicitly
+ // when converting the result back to a smi in case the max string length
+ // equals the max smi valie. Otherwise, for platforms with 32-bit smis, we do
+ HValue* length = AddUncasted<HAdd>(left_length, right_length);
+ STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
+ if (String::kMaxLength != Smi::kMaxValue) {
+ IfBuilder if_nooverflow(this);
+ if_nooverflow.If<HCompareNumericAndBranch>(
+ length, Add<HConstant>(String::kMaxLength), Token::LTE);
+ if_nooverflow.Then();
+ if_nooverflow.ElseDeopt("String length exceeds limit");
+ }
+
+ // Determine the string instance types.
+ HLoadNamedField* left_instance_type = Add<HLoadNamedField>(
+ Add<HLoadNamedField>(left, HObjectAccess::ForMap()),
+ HObjectAccess::ForMapInstanceType());
+ HLoadNamedField* right_instance_type = Add<HLoadNamedField>(
+ Add<HLoadNamedField>(right, HObjectAccess::ForMap()),
+ HObjectAccess::ForMapInstanceType());
+
+ // Compute difference of instance types.
+ HValue* xored_instance_types = AddUncasted<HBitwise>(
+ Token::BIT_XOR, left_instance_type, right_instance_type);
+
+ // Check if we should create a cons string.
+ IfBuilder if_createcons(this);
+ if_createcons.If<HCompareNumericAndBranch>(
+ length, Add<HConstant>(ConsString::kMinLength), Token::GTE);
+ if_createcons.Then();
+ {
+ // Allocate the cons string object. HAllocate does not care whether we
+ // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use
+ // CONS_STRING_TYPE here. Below we decide whether the cons string is
+ // one-byte or two-byte and set the appropriate map.
+ HAllocate* string = Add<HAllocate>(Add<HConstant>(ConsString::kSize),
+ HType::String(), pretenure_flag,
+ CONS_STRING_TYPE);
+
+ // Compute the intersection of instance types.
+ HValue* anded_instance_types = AddUncasted<HBitwise>(
+ Token::BIT_AND, left_instance_type, right_instance_type);
+
+ // We create a one-byte cons string if
+ // 1. both strings are one-byte, or
+ // 2. at least one of the strings is two-byte, but happens to contain only
+ // one-byte characters.
+ // To do this, we check
+ // 1. if both strings are one-byte, or if the one-byte data hint is set in
+ // both strings, or
+ // 2. if one of the strings has the one-byte data hint set and the other
+ // string is one-byte.
+ IfBuilder if_onebyte(this);
+ STATIC_ASSERT(kOneByteStringTag != 0);
+ STATIC_ASSERT(kOneByteDataHintMask != 0);
+ if_onebyte.If<HCompareNumericAndBranch>(
+ AddUncasted<HBitwise>(
+ Token::BIT_AND, anded_instance_types,
+ Add<HConstant>(static_cast<int32_t>(
+ kStringEncodingMask | kOneByteDataHintMask))),
+ graph()->GetConstant0(), Token::NE);
+ if_onebyte.Or();
+ STATIC_ASSERT(kOneByteStringTag != 0 &&
+ kOneByteDataHintTag != 0 &&
+ kOneByteDataHintTag != kOneByteStringTag);
+ if_onebyte.If<HCompareNumericAndBranch>(
+ AddUncasted<HBitwise>(
+ Token::BIT_AND, xored_instance_types,
+ Add<HConstant>(static_cast<int32_t>(
+ kOneByteStringTag | kOneByteDataHintTag))),
+ Add<HConstant>(static_cast<int32_t>(
+ kOneByteStringTag | kOneByteDataHintTag)), Token::EQ);
+ if_onebyte.Then();
+ {
+ // We can safely skip the write barrier for storing the map here.
+ Handle<Map> map = isolate()->factory()->cons_ascii_string_map();
+ AddStoreMapConstantNoWriteBarrier(string, map);
+ }
+ if_onebyte.Else();
+ {
+ // We can safely skip the write barrier for storing the map here.
+ Handle<Map> map = isolate()->factory()->cons_string_map();
+ AddStoreMapConstantNoWriteBarrier(string, map);
+ }
+ if_onebyte.End();
+
+ // Initialize the cons string fields.
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
+ Add<HConstant>(String::kEmptyHashField));
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), length);
+ Add<HStoreNamedField>(string, HObjectAccess::ForConsStringFirst(), left);
+ Add<HStoreNamedField>(string, HObjectAccess::ForConsStringSecond(),
+ right);
+
+ // Count the native string addition.
+ AddIncrementCounter(isolate()->counters()->string_add_native());
+
+ // Cons string is result.
+ Push(string);
+ }
+ if_createcons.Else();
+ {
+ // Compute union of instance types.
+ HValue* ored_instance_types = AddUncasted<HBitwise>(
+ Token::BIT_OR, left_instance_type, right_instance_type);
+
+ // Check if both strings have the same encoding and both are
+ // sequential.
+ IfBuilder if_sameencodingandsequential(this);
+ if_sameencodingandsequential.If<HCompareNumericAndBranch>(
+ AddUncasted<HBitwise>(
+ Token::BIT_AND, xored_instance_types,
+ Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
+ graph()->GetConstant0(), Token::EQ);
+ if_sameencodingandsequential.And();
+ STATIC_ASSERT(kSeqStringTag == 0);
+ if_sameencodingandsequential.If<HCompareNumericAndBranch>(
+ AddUncasted<HBitwise>(
+ Token::BIT_AND, ored_instance_types,
+ Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))),
+ graph()->GetConstant0(), Token::EQ);
+ if_sameencodingandsequential.Then();
+ {
+ // Check if the result is a one-byte string.
+ IfBuilder if_onebyte(this);
+ STATIC_ASSERT(kOneByteStringTag != 0);
+ if_onebyte.If<HCompareNumericAndBranch>(
+ AddUncasted<HBitwise>(
+ Token::BIT_AND, ored_instance_types,
+ Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))),
+ graph()->GetConstant0(), Token::NE);
+ if_onebyte.Then();
+ {
+ // Calculate the number of bytes needed for the characters in the
+ // string while observing object alignment.
+ HValue* size = BuildSeqStringSizeFor(
+ length, String::ONE_BYTE_ENCODING);
+
+ // Allocate the ASCII string object.
+ Handle<Map> map = isolate()->factory()->ascii_string_map();
+ HAllocate* string = Add<HAllocate>(size, HType::String(),
+ pretenure_flag, ASCII_STRING_TYPE);
+ string->set_known_initial_map(map);
+
+ // We can safely skip the write barrier for storing map here.
+ AddStoreMapConstantNoWriteBarrier(string, map);
+
+ // Length must be stored into the string before we copy characters to
+ // make debug verification code happy.
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
+ length);
+
+ // Copy bytes from the left string.
+ BuildCopySeqStringChars(
+ left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+ string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+ left_length);
+
+ // Copy bytes from the right string.
+ BuildCopySeqStringChars(
+ right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING,
+ string, left_length, String::ONE_BYTE_ENCODING,
+ right_length);
+
+ // Count the native string addition.
+ AddIncrementCounter(isolate()->counters()->string_add_native());
+
+ // Return the string.
+ Push(string);
+ }
+ if_onebyte.Else();
+ {
+ // Calculate the number of bytes needed for the characters in the
+ // string while observing object alignment.
+ HValue* size = BuildSeqStringSizeFor(
+ length, String::TWO_BYTE_ENCODING);
+
+ // Allocate the two-byte string object.
+ Handle<Map> map = isolate()->factory()->string_map();
+ HAllocate* string = Add<HAllocate>(size, HType::String(),
+ pretenure_flag, STRING_TYPE);
+ string->set_known_initial_map(map);
+
+ // We can safely skip the write barrier for storing map here.
+ AddStoreMapConstantNoWriteBarrier(string, map);
+
+ // Length must be stored into the string before we copy characters to
+ // make debug verification code happy.
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(),
+ length);
+
+ // Copy bytes from the left string.
+ BuildCopySeqStringChars(
+ left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
+ string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
+ left_length);
+
+ // Copy bytes from the right string.
+ BuildCopySeqStringChars(
+ right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING,
+ string, left_length, String::TWO_BYTE_ENCODING,
+ right_length);
+
+ // Return the string.
+ Push(string);
+ }
+ if_onebyte.End();
+
+ // Initialize the (common) string fields.
+ HValue* string = Pop();
+ Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(),
+ Add<HConstant>(String::kEmptyHashField));
+
+ // Count the native string addition.
+ AddIncrementCounter(isolate()->counters()->string_add_native());
+
+ Push(string);
+ }
+ if_sameencodingandsequential.Else();
+ {
+ // Fallback to the runtime to add the two strings.
+ Add<HPushArgument>(left);
+ Add<HPushArgument>(right);
+ Push(Add<HCallRuntime>(isolate()->factory()->empty_string(),
+ Runtime::FunctionForId(Runtime::kStringAdd),
+ 2));
+ }
+ if_sameencodingandsequential.End();
+ }
+ if_createcons.End();
+
+ return Pop();
+}
+
+
+HValue* HGraphBuilder::BuildStringAdd(HValue* left,
+ HValue* right,
+ PretenureFlag pretenure_flag) {
+ // Determine the string lengths.
+ HValue* left_length = Add<HLoadNamedField>(
+ left, HObjectAccess::ForStringLength());
+ HValue* right_length = Add<HLoadNamedField>(
+ right, HObjectAccess::ForStringLength());
+
+ // Check if left string is empty.
+ IfBuilder if_leftisempty(this);
+ if_leftisempty.If<HCompareNumericAndBranch>(
+ left_length, graph()->GetConstant0(), Token::EQ);
+ if_leftisempty.Then();
+ {
+ // Count the native string addition.
+ AddIncrementCounter(isolate()->counters()->string_add_native());
+
+ // Just return the right string.
+ Push(right);
+ }
+ if_leftisempty.Else();
+ {
+ // Check if right string is empty.
+ IfBuilder if_rightisempty(this);
+ if_rightisempty.If<HCompareNumericAndBranch>(
+ right_length, graph()->GetConstant0(), Token::EQ);
+ if_rightisempty.Then();
+ {
+ // Count the native string addition.
+ AddIncrementCounter(isolate()->counters()->string_add_native());
+
+ // Just return the left string.
+ Push(left);
+ }
+ if_rightisempty.Else();
+ {
+ // Concatenate the two non-empty strings.
+ Push(BuildUncheckedStringAdd(left, right, pretenure_flag));
+ }
+ if_rightisempty.End();
+ }
+ if_leftisempty.End();
+
+ return Pop();
+}
+
+
HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
HValue* checked_object,
HValue* key,
@@ -1318,9 +2070,10 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>(
key, graph()->GetConstant0(), Token::GTE);
negative_checker.Then();
- HInstruction* result = AddExternalArrayElementAccess(
+ HInstruction* result = AddElementAccess(
external_elements, key, val, bounds_check, elements_kind, is_store);
negative_checker.ElseDeopt("Negative key encountered");
+ negative_checker.End();
length_checker.End();
return result;
} else {
@@ -1328,7 +2081,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
checked_key = Add<HBoundsCheck>(key, length);
HLoadExternalArrayPointer* external_elements =
Add<HLoadExternalArrayPointer>(elements);
- return AddExternalArrayElementAccess(
+ return AddElementAccess(
external_elements, checked_key, val,
checked_object, elements_kind, is_store);
}
@@ -1342,7 +2095,7 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
// deopt, leaving the backing store in an invalid state.
if (is_store && IsFastSmiElementsKind(elements_kind) &&
!val->type().IsSmi()) {
- val = Add<HForceRepresentation>(val, Representation::Smi());
+ val = AddUncasted<HForceRepresentation>(val, Representation::Smi());
}
if (IsGrowStoreMode(store_mode)) {
@@ -1361,16 +2114,58 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
elements_kind, length);
} else {
HCheckMaps* check_cow_map = Add<HCheckMaps>(
- elements, isolate()->factory()->fixed_array_map(),
- top_info());
+ elements, isolate()->factory()->fixed_array_map(), top_info());
check_cow_map->ClearGVNFlag(kDependsOnElementsKind);
}
}
}
- return AddFastElementAccess(elements, checked_key, val, checked_object,
- elements_kind, is_store, load_mode, store_mode);
-}
+ return AddElementAccess(elements, checked_key, val, checked_object,
+ elements_kind, is_store, load_mode);
+}
+
+
+
+HValue* HGraphBuilder::BuildAllocateArrayFromLength(
+ JSArrayBuilder* array_builder,
+ HValue* length_argument) {
+ if (length_argument->IsConstant() &&
+ HConstant::cast(length_argument)->HasSmiValue()) {
+ int array_length = HConstant::cast(length_argument)->Integer32Value();
+ HValue* new_object = array_length == 0
+ ? array_builder->AllocateEmptyArray()
+ : array_builder->AllocateArray(length_argument, length_argument);
+ return new_object;
+ }
+
+ HValue* constant_zero = graph()->GetConstant0();
+ HConstant* max_alloc_length =
+ Add<HConstant>(JSObject::kInitialMaxFastElementArray);
+ HInstruction* checked_length = Add<HBoundsCheck>(length_argument,
+ max_alloc_length);
+ IfBuilder if_builder(this);
+ if_builder.If<HCompareNumericAndBranch>(checked_length, constant_zero,
+ Token::EQ);
+ if_builder.Then();
+ const int initial_capacity = JSArray::kPreallocatedArrayElements;
+ HConstant* initial_capacity_node = Add<HConstant>(initial_capacity);
+ Push(initial_capacity_node); // capacity
+ Push(constant_zero); // length
+ if_builder.Else();
+ if (!(top_info()->IsStub()) &&
+ IsFastPackedElementsKind(array_builder->kind())) {
+ // We'll come back later with better (holey) feedback.
+ if_builder.Deopt("Holey array despite packed elements_kind feedback");
+ } else {
+ Push(checked_length); // capacity
+ Push(checked_length); // length
+ }
+ if_builder.End();
+ // Figure out total size
+ HValue* length = Pop();
+ HValue* capacity = Pop();
+ return array_builder->AllocateArray(capacity, length);
+}
HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind,
HValue* capacity) {
@@ -1386,11 +2181,11 @@ HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind,
}
HConstant* elements_size_value = Add<HConstant>(elements_size);
- HValue* mul = Add<HMul>(capacity, elements_size_value);
+ HValue* mul = AddUncasted<HMul>(capacity, elements_size_value);
mul->ClearFlag(HValue::kCanOverflow);
HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize);
- HValue* total_size = Add<HAdd>(mul, header_size);
+ HValue* total_size = AddUncasted<HAdd>(mul, header_size);
total_size->ClearFlag(HValue::kCanOverflow);
return Add<HAllocate>(total_size, HType::JSArray(),
@@ -1417,7 +2212,7 @@ HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader(
HValue* capacity) {
// The HForceRepresentation is to prevent possible deopt on int-smi
// conversion after allocation but before the new object fields are set.
- capacity = Add<HForceRepresentation>(capacity, Representation::Smi());
+ capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi());
HValue* new_elements = BuildAllocateElements(kind, capacity);
BuildInitializeElementsHeader(new_elements, kind, capacity);
return new_elements;
@@ -1442,9 +2237,8 @@ HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array,
length_field);
if (mode == TRACK_ALLOCATION_SITE) {
- BuildCreateAllocationMemento(array,
- JSArray::kSize,
- allocation_site_payload);
+ BuildCreateAllocationMemento(
+ array, Add<HConstant>(JSArray::kSize), allocation_site_payload);
}
int elements_location = JSArray::kSize;
@@ -1452,91 +2246,38 @@ HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array,
elements_location += AllocationMemento::kSize;
}
- HValue* elements = Add<HInnerAllocatedObject>(array, elements_location);
+ HInnerAllocatedObject* elements = Add<HInnerAllocatedObject>(
+ array, Add<HConstant>(elements_location));
Add<HStoreNamedField>(array, HObjectAccess::ForElementsPointer(), elements);
- return static_cast<HInnerAllocatedObject*>(elements);
+ return elements;
}
-HInstruction* HGraphBuilder::AddExternalArrayElementAccess(
- HValue* external_elements,
+HInstruction* HGraphBuilder::AddElementAccess(
+ HValue* elements,
HValue* checked_key,
HValue* val,
HValue* dependency,
ElementsKind elements_kind,
- bool is_store) {
+ bool is_store,
+ LoadKeyedHoleMode load_mode) {
if (is_store) {
ASSERT(val != NULL);
- switch (elements_kind) {
- case EXTERNAL_PIXEL_ELEMENTS: {
- val = Add<HClampToUint8>(val);
- break;
- }
- case EXTERNAL_BYTE_ELEMENTS:
- case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
- case EXTERNAL_SHORT_ELEMENTS:
- case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
- case EXTERNAL_INT_ELEMENTS:
- case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
- break;
- }
- case EXTERNAL_FLOAT_ELEMENTS:
- case EXTERNAL_DOUBLE_ELEMENTS:
- break;
- case FAST_SMI_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- case DICTIONARY_ELEMENTS:
- case NON_STRICT_ARGUMENTS_ELEMENTS:
- UNREACHABLE();
- break;
+ if (elements_kind == EXTERNAL_PIXEL_ELEMENTS) {
+ val = Add<HClampToUint8>(val);
}
- return Add<HStoreKeyed>(external_elements, checked_key, val, elements_kind);
- } else {
- ASSERT(val == NULL);
- HLoadKeyed* load = Add<HLoadKeyed>(external_elements,
- checked_key,
- dependency,
- elements_kind);
- if (FLAG_opt_safe_uint32_operations &&
- elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
- graph()->RecordUint32Instruction(load);
- }
- return load;
+ return Add<HStoreKeyed>(elements, checked_key, val, elements_kind);
}
-}
-
-HInstruction* HGraphBuilder::AddFastElementAccess(
- HValue* elements,
- HValue* checked_key,
- HValue* val,
- HValue* load_dependency,
- ElementsKind elements_kind,
- bool is_store,
- LoadKeyedHoleMode load_mode,
- KeyedAccessStoreMode store_mode) {
- if (is_store) {
- ASSERT(val != NULL);
- switch (elements_kind) {
- case FAST_SMI_ELEMENTS:
- case FAST_HOLEY_SMI_ELEMENTS:
- case FAST_ELEMENTS:
- case FAST_HOLEY_ELEMENTS:
- case FAST_DOUBLE_ELEMENTS:
- case FAST_HOLEY_DOUBLE_ELEMENTS:
- return Add<HStoreKeyed>(elements, checked_key, val, elements_kind);
- default:
- UNREACHABLE();
- return NULL;
- }
+ ASSERT(!is_store);
+ ASSERT(val == NULL);
+ HLoadKeyed* load = Add<HLoadKeyed>(
+ elements, checked_key, dependency, elements_kind, load_mode);
+ if (FLAG_opt_safe_uint32_operations &&
+ elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
+ graph()->RecordUint32Instruction(load);
}
- // It's an element load (!is_store).
- return Add<HLoadKeyed>(
- elements, checked_key, load_dependency, elements_kind, load_mode);
+ return load;
}
@@ -1614,19 +2355,15 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
: Add<HConstant>(nan_double);
// Special loop unfolding case
- static const int kLoopUnfoldLimit = 4;
- bool unfold_loop = false;
- int initial_capacity = JSArray::kPreallocatedArrayElements;
- if (from->IsConstant() && to->IsConstant() &&
- initial_capacity <= kLoopUnfoldLimit) {
- HConstant* constant_from = HConstant::cast(from);
- HConstant* constant_to = HConstant::cast(to);
+ static const int kLoopUnfoldLimit = 8;
+ STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= kLoopUnfoldLimit);
+ int initial_capacity = -1;
+ if (from->IsInteger32Constant() && to->IsInteger32Constant()) {
+ int constant_from = from->GetInteger32Constant();
+ int constant_to = to->GetInteger32Constant();
- if (constant_from->HasInteger32Value() &&
- constant_from->Integer32Value() == 0 &&
- constant_to->HasInteger32Value() &&
- constant_to->Integer32Value() == initial_capacity) {
- unfold_loop = true;
+ if (constant_from == 0 && constant_to <= kLoopUnfoldLimit) {
+ initial_capacity = constant_to;
}
}
@@ -1636,7 +2373,7 @@ void HGraphBuilder::BuildFillElementsWithHole(HValue* elements,
elements_kind = FAST_HOLEY_ELEMENTS;
}
- if (unfold_loop) {
+ if (initial_capacity >= 0) {
for (int i = 0; i < initial_capacity; i++) {
HInstruction* key = Add<HConstant>(i);
Add<HStoreKeyed>(elements, key, hole, elements_kind);
@@ -1742,7 +2479,8 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HValue* boilerplate,
// Create an allocation site info if requested.
if (mode == TRACK_ALLOCATION_SITE) {
- BuildCreateAllocationMemento(object, JSArray::kSize, allocation_site);
+ BuildCreateAllocationMemento(
+ object, Add<HConstant>(JSArray::kSize), allocation_site);
}
if (length > 0) {
@@ -1786,9 +2524,8 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HValue* boilerplate,
void HGraphBuilder::BuildCompareNil(
HValue* value,
Handle<Type> type,
- int position,
HIfContinuation* continuation) {
- IfBuilder if_nil(this, position);
+ IfBuilder if_nil(this);
bool some_case_handled = false;
bool some_case_missing = false;
@@ -1836,19 +2573,31 @@ void HGraphBuilder::BuildCompareNil(
}
-HValue* HGraphBuilder::BuildCreateAllocationMemento(HValue* previous_object,
- int previous_object_size,
- HValue* alloc_site) {
- // TODO(mvstanton): ASSERT altered to CHECK to diagnose chromium bug 284577
- CHECK(alloc_site != NULL);
- HInnerAllocatedObject* alloc_memento = Add<HInnerAllocatedObject>(
+void HGraphBuilder::BuildCreateAllocationMemento(
+ HValue* previous_object,
+ HValue* previous_object_size,
+ HValue* allocation_site) {
+ ASSERT(allocation_site != NULL);
+ HInnerAllocatedObject* allocation_memento = Add<HInnerAllocatedObject>(
previous_object, previous_object_size);
- Handle<Map> alloc_memento_map(
- isolate()->heap()->allocation_memento_map());
- AddStoreMapConstant(alloc_memento, alloc_memento_map);
- HObjectAccess access = HObjectAccess::ForAllocationMementoSite();
- Add<HStoreNamedField>(alloc_memento, access, alloc_site);
- return alloc_memento;
+ AddStoreMapConstant(
+ allocation_memento, isolate()->factory()->allocation_memento_map());
+ Add<HStoreNamedField>(
+ allocation_memento,
+ HObjectAccess::ForAllocationMementoSite(),
+ allocation_site);
+ if (FLAG_allocation_site_pretenuring) {
+ HValue* memento_create_count = Add<HLoadNamedField>(
+ allocation_site, HObjectAccess::ForAllocationSiteOffset(
+ AllocationSite::kMementoCreateCountOffset));
+ memento_create_count = AddUncasted<HAdd>(
+ memento_create_count, graph()->GetConstant1());
+ HStoreNamedField* store = Add<HStoreNamedField>(
+ allocation_site, HObjectAccess::ForAllocationSiteOffset(
+ AllocationSite::kMementoCreateCountOffset), memento_create_count);
+ // No write barrier needed to store a smi.
+ store->SkipWriteBarrier();
+ }
}
@@ -1897,12 +2646,18 @@ HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder,
HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() {
- if (kind_ == GetInitialFastElementsKind()) {
+ if (!builder()->top_info()->IsStub()) {
+ // A constant map is fine.
+ Handle<Map> map(builder()->isolate()->get_initial_js_array_map(kind_),
+ builder()->isolate());
+ return builder()->Add<HConstant>(map);
+ }
+
+ if (constructor_function_ != NULL && kind_ == GetInitialFastElementsKind()) {
// No need for a context lookup if the kind_ matches the initial
// map, because we can just load the map in that case.
HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap();
- return builder()->AddInstruction(
- builder()->BuildLoadNamedField(constructor_function_, access));
+ return builder()->AddLoadNamedField(constructor_function_, access);
}
HInstruction* native_context = builder()->BuildGetNativeContext();
@@ -1922,8 +2677,7 @@ HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() {
HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() {
// Find the map near the constructor function
HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap();
- return builder()->AddInstruction(
- builder()->BuildLoadNamedField(constructor_function_, access));
+ return builder()->AddLoadNamedField(constructor_function_, access);
}
@@ -1941,12 +2695,14 @@ HValue* HGraphBuilder::JSArrayBuilder::EstablishAllocationSize(
HInstruction* elements_size_value =
builder()->Add<HConstant>(elements_size());
- HInstruction* mul = builder()->Add<HMul>(length_node, elements_size_value);
- mul->ClearFlag(HValue::kCanOverflow);
-
+ HInstruction* mul = HMul::NewImul(builder()->zone(), builder()->context(),
+ length_node, elements_size_value);
+ builder()->AddInstruction(mul);
HInstruction* base = builder()->Add<HConstant>(base_size);
- HInstruction* total_size = builder()->Add<HAdd>(base, mul);
+ HInstruction* total_size = HAdd::New(builder()->zone(), builder()->context(),
+ base, mul);
total_size->ClearFlag(HValue::kCanOverflow);
+ builder()->AddInstruction(total_size);
return total_size;
}
@@ -1970,34 +2726,40 @@ HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() {
HConstant* capacity = builder()->Add<HConstant>(initial_capacity());
return AllocateArray(size_in_bytes,
capacity,
- builder()->graph()->GetConstant0(),
- true);
+ builder()->graph()->GetConstant0());
}
HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity,
HValue* length_field,
- bool fill_with_hole) {
+ FillMode fill_mode) {
HValue* size_in_bytes = EstablishAllocationSize(capacity);
- return AllocateArray(size_in_bytes, capacity, length_field, fill_with_hole);
+ return AllocateArray(size_in_bytes, capacity, length_field, fill_mode);
}
HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes,
HValue* capacity,
HValue* length_field,
- bool fill_with_hole) {
+ FillMode fill_mode) {
// These HForceRepresentations are because we store these as fields in the
// objects we construct, and an int32-to-smi HChange could deopt. Accept
// the deopt possibility now, before allocation occurs.
- capacity = builder()->Add<HForceRepresentation>(capacity,
- Representation::Smi());
- length_field = builder()->Add<HForceRepresentation>(length_field,
- Representation::Smi());
+ capacity =
+ builder()->AddUncasted<HForceRepresentation>(capacity,
+ Representation::Smi());
+ length_field =
+ builder()->AddUncasted<HForceRepresentation>(length_field,
+ Representation::Smi());
// Allocate (dealing with failure appropriately)
HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes,
HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE);
+ // Folded array allocation should be aligned if it has fast double elements.
+ if (IsFastDoubleElementsKind(kind_)) {
+ new_object->MakeDoubleAligned();
+ }
+
// Fill in the fields: map, properties, length
HValue* map;
if (allocation_site_payload_ == NULL) {
@@ -2015,7 +2777,7 @@ HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes,
// Initialize the elements
builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity);
- if (fill_with_hole) {
+ if (fill_mode == FILL_WITH_HOLE) {
builder()->BuildFillElementsWithHole(elements_location_, kind_,
graph()->GetConstant0(), capacity);
}
@@ -2057,6 +2819,9 @@ HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info)
// to know it's the initial state.
function_state_= &initial_function_state_;
InitializeAstVisitor(info->isolate());
+ if (FLAG_emit_opt_code_positions) {
+ SetSourcePosition(info->shared_info()->start_position());
+ }
}
@@ -2069,8 +2834,8 @@ HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first,
return first;
} else {
HBasicBlock* join_block = graph()->CreateBasicBlock();
- first->Goto(join_block);
- second->Goto(join_block);
+ Goto(first, join_block);
+ Goto(second, join_block);
join_block->SetJoinId(join_id);
return join_block;
}
@@ -2081,7 +2846,7 @@ HBasicBlock* HOptimizedGraphBuilder::JoinContinue(IterationStatement* statement,
HBasicBlock* exit_block,
HBasicBlock* continue_block) {
if (continue_block != NULL) {
- if (exit_block != NULL) exit_block->Goto(continue_block);
+ if (exit_block != NULL) Goto(exit_block, continue_block);
continue_block->SetJoinId(statement->ContinueId());
return continue_block;
}
@@ -2094,10 +2859,10 @@ HBasicBlock* HOptimizedGraphBuilder::CreateLoop(IterationStatement* statement,
HBasicBlock* body_exit,
HBasicBlock* loop_successor,
HBasicBlock* break_block) {
- if (body_exit != NULL) body_exit->Goto(loop_entry);
+ if (body_exit != NULL) Goto(body_exit, loop_entry);
loop_entry->PostProcessLoopHeader(statement);
if (break_block != NULL) {
- if (loop_successor != NULL) loop_successor->Goto(break_block);
+ if (loop_successor != NULL) Goto(loop_successor, break_block);
break_block->SetJoinId(statement->ExitId());
return break_block;
}
@@ -2105,8 +2870,26 @@ HBasicBlock* HOptimizedGraphBuilder::CreateLoop(IterationStatement* statement,
}
-void HBasicBlock::FinishExit(HControlInstruction* instruction) {
- Finish(instruction);
+// Build a new loop header block and set it as the current block.
+HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry() {
+ HBasicBlock* loop_entry = CreateLoopHeaderBlock();
+ Goto(loop_entry);
+ set_current_block(loop_entry);
+ return loop_entry;
+}
+
+
+HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry(
+ IterationStatement* statement) {
+ HBasicBlock* loop_entry = osr()->HasOsrEntryAt(statement)
+ ? osr()->BuildOsrLoopEntry(statement)
+ : BuildLoopEntry();
+ return loop_entry;
+}
+
+
+void HBasicBlock::FinishExit(HControlInstruction* instruction, int position) {
+ Finish(instruction, position);
ClearEnvironment();
}
@@ -2124,7 +2907,6 @@ HGraph::HGraph(CompilationInfo* info)
zone_(info->zone()),
is_recursive_(false),
use_optimistic_licm_(false),
- has_soft_deoptimize_(false),
depends_on_empty_array_proto_elements_(false),
type_change_checksum_(0),
maximum_environment_size_(0),
@@ -2153,12 +2935,12 @@ HBasicBlock* HGraph::CreateBasicBlock() {
}
-void HGraph::FinalizeUniqueValueIds() {
+void HGraph::FinalizeUniqueness() {
DisallowHeapAllocation no_gc;
- ASSERT(!isolate()->optimizing_compiler_thread()->IsOptimizerThread());
+ ASSERT(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
for (int i = 0; i < blocks()->length(); ++i) {
for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) {
- it.Current()->FinalizeUniqueValueId();
+ it.Current()->FinalizeUniqueness();
}
}
}
@@ -2656,7 +3438,7 @@ void EffectContext::ReturnControl(HControlInstruction* instr,
HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
instr->SetSuccessorAt(0, empty_true);
instr->SetSuccessorAt(1, empty_false);
- owner()->current_block()->Finish(instr);
+ owner()->FinishCurrentBlock(instr);
HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id);
owner()->set_current_block(join);
}
@@ -2666,7 +3448,7 @@ void EffectContext::ReturnContinuation(HIfContinuation* continuation,
BailoutId ast_id) {
HBasicBlock* true_branch = NULL;
HBasicBlock* false_branch = NULL;
- continuation->Continue(&true_branch, &false_branch, NULL);
+ continuation->Continue(&true_branch, &false_branch);
if (!continuation->IsTrueReachable()) {
owner()->set_current_block(false_branch);
} else if (!continuation->IsFalseReachable()) {
@@ -2700,7 +3482,7 @@ void ValueContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock();
instr->SetSuccessorAt(0, materialize_true);
instr->SetSuccessorAt(1, materialize_false);
- owner()->current_block()->Finish(instr);
+ owner()->FinishCurrentBlock(instr);
owner()->set_current_block(materialize_true);
owner()->Push(owner()->graph()->GetConstantTrue());
owner()->set_current_block(materialize_false);
@@ -2715,7 +3497,7 @@ void ValueContext::ReturnContinuation(HIfContinuation* continuation,
BailoutId ast_id) {
HBasicBlock* materialize_true = NULL;
HBasicBlock* materialize_false = NULL;
- continuation->Continue(&materialize_true, &materialize_false, NULL);
+ continuation->Continue(&materialize_true, &materialize_false);
if (continuation->IsTrueReachable()) {
owner()->set_current_block(materialize_true);
owner()->Push(owner()->graph()->GetConstantTrue());
@@ -2755,9 +3537,9 @@ void TestContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
instr->SetSuccessorAt(0, empty_true);
instr->SetSuccessorAt(1, empty_false);
- owner()->current_block()->Finish(instr);
- empty_true->Goto(if_true(), owner()->function_state());
- empty_false->Goto(if_false(), owner()->function_state());
+ owner()->FinishCurrentBlock(instr);
+ owner()->Goto(empty_true, if_true(), owner()->function_state());
+ owner()->Goto(empty_false, if_false(), owner()->function_state());
owner()->set_current_block(NULL);
}
@@ -2766,12 +3548,12 @@ void TestContext::ReturnContinuation(HIfContinuation* continuation,
BailoutId ast_id) {
HBasicBlock* true_branch = NULL;
HBasicBlock* false_branch = NULL;
- continuation->Continue(&true_branch, &false_branch, NULL);
+ continuation->Continue(&true_branch, &false_branch);
if (continuation->IsTrueReachable()) {
- true_branch->Goto(if_true(), owner()->function_state());
+ owner()->Goto(true_branch, if_true(), owner()->function_state());
}
if (continuation->IsFalseReachable()) {
- false_branch->Goto(if_false(), owner()->function_state());
+ owner()->Goto(false_branch, if_false(), owner()->function_state());
}
owner()->set_current_block(NULL);
}
@@ -2786,15 +3568,8 @@ void TestContext::BuildBranch(HValue* value) {
if (value != NULL && value->CheckFlag(HValue::kIsArguments)) {
builder->Bailout(kArgumentsObjectValueInATestContext);
}
- HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
- HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
ToBooleanStub::Types expected(condition()->to_boolean_types());
- HBranch* test = new(zone()) HBranch(value, expected, empty_true, empty_false);
- builder->current_block()->Finish(test);
-
- empty_true->Goto(if_true(), builder->function_state());
- empty_false->Goto(if_false(), builder->function_state());
- builder->set_current_block(NULL);
+ ReturnControl(owner()->New<HBranch>(value, expected), BailoutId::None());
}
@@ -2910,7 +3685,7 @@ bool HOptimizedGraphBuilder::BuildGraph() {
// not replayed by the Lithium translation.
HEnvironment* initial_env = environment()->CopyWithoutHistory();
HBasicBlock* body_entry = CreateBasicBlock(initial_env);
- current_block()->Goto(body_entry);
+ Goto(body_entry);
body_entry->SetJoinId(BailoutId::FunctionEntry());
set_current_block(body_entry);
@@ -2922,8 +3697,7 @@ bool HOptimizedGraphBuilder::BuildGraph() {
VisitDeclarations(scope->declarations());
Add<HSimulate>(BailoutId::Declarations());
- HValue* context = environment()->context();
- Add<HStackCheck>(context, HStackCheck::kFunctionEntry);
+ Add<HStackCheck>(HStackCheck::kFunctionEntry);
VisitStatements(current_info()->function()->body());
if (HasStackOverflow()) return false;
@@ -2948,7 +3722,7 @@ bool HOptimizedGraphBuilder::BuildGraph() {
type_info->set_inlined_type_change_checksum(composite_checksum);
// Perform any necessary OSR-specific cleanups or changes to the graph.
- osr_->FinishGraph();
+ osr()->FinishGraph();
return true;
}
@@ -2973,7 +3747,6 @@ bool HGraph::Optimize(BailoutReason* bailout_reason) {
Run<HEnvironmentLivenessAnalysisPhase>();
}
- Run<HPropagateDeoptimizingMarkPhase>();
if (!CheckConstPhiUses()) {
*bailout_reason = kUnsupportedPhiUseOfConstVariable;
return false;
@@ -2984,11 +3757,15 @@ bool HGraph::Optimize(BailoutReason* bailout_reason) {
return false;
}
- // Remove dead code and phis
- if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
+ // Find and mark unreachable code to simplify optimizations, especially gvn,
+ // where unreachable code could unnecessarily defeat LICM.
+ Run<HMarkUnreachableBlocksPhase>();
+ if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>();
+ if (FLAG_load_elimination) Run<HLoadEliminationPhase>();
+
CollectPhis();
if (has_osr()) osr()->FinishOsrValues();
@@ -3014,6 +3791,8 @@ bool HGraph::Optimize(BailoutReason* bailout_reason) {
if (FLAG_use_gvn) Run<HGlobalValueNumberingPhase>();
+ if (FLAG_check_elimination) Run<HCheckEliminationPhase>();
+
if (FLAG_use_range) Run<HRangeAnalysisPhase>();
Run<HComputeChangeUndefinedToNaN>();
@@ -3022,17 +3801,17 @@ bool HGraph::Optimize(BailoutReason* bailout_reason) {
// Eliminate redundant stack checks on backwards branches.
Run<HStackCheckEliminationPhase>();
- if (FLAG_array_bounds_checks_elimination) {
- Run<HBoundsCheckEliminationPhase>();
- }
- if (FLAG_array_bounds_checks_hoisting) {
- Run<HBoundsCheckHoistingPhase>();
- }
+ if (FLAG_array_bounds_checks_elimination) Run<HBoundsCheckEliminationPhase>();
+ if (FLAG_array_bounds_checks_hoisting) Run<HBoundsCheckHoistingPhase>();
if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>();
if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>();
RestoreActualValues();
+ // Find unreachable code a second time, GVN and other optimizations may have
+ // made blocks unreachable that were previously reachable.
+ Run<HMarkUnreachableBlocksPhase>();
+
return true;
}
@@ -3065,12 +3844,6 @@ void HGraph::RestoreActualValues() {
}
-void HGraphBuilder::PushAndAdd(HInstruction* instr) {
- Push(instr);
- AddInstruction(instr);
-}
-
-
template <class Instruction>
HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) {
int count = call->argument_count();
@@ -3091,10 +3864,6 @@ void HOptimizedGraphBuilder::SetUpScope(Scope* scope) {
HInstruction* context = Add<HContext>();
environment()->BindContext(context);
- HConstant* undefined_constant = HConstant::cast(Add<HConstant>(
- isolate()->factory()->undefined_value()));
- graph()->set_undefined_constant(undefined_constant);
-
// Create an arguments object containing the initial parameters. Set the
// initial values of parameters including "this" having parameter index 0.
ASSERT_EQ(scope->num_parameters() + 1, environment()->parameter_count());
@@ -3108,6 +3877,7 @@ void HOptimizedGraphBuilder::SetUpScope(Scope* scope) {
AddInstruction(arguments_object);
graph()->SetArgumentsObject(arguments_object);
+ HConstant* undefined_constant = graph()->GetConstantUndefined();
// Initialize specials and locals to undefined.
for (int i = environment()->parameter_count() + 1;
i < environment()->length();
@@ -3150,7 +3920,7 @@ void HOptimizedGraphBuilder::VisitBlock(Block* stmt) {
}
HBasicBlock* break_block = break_info.break_block();
if (break_block != NULL) {
- if (current_block() != NULL) current_block()->Goto(break_block);
+ if (current_block() != NULL) Goto(break_block);
break_block->SetJoinId(stmt->ExitId());
set_current_block(break_block);
}
@@ -3260,7 +4030,7 @@ void HOptimizedGraphBuilder::VisitContinueStatement(
HBasicBlock* continue_block = break_scope()->Get(
stmt->target(), BreakAndContinueScope::CONTINUE, &drop_extra);
Drop(drop_extra);
- current_block()->Goto(continue_block);
+ Goto(continue_block);
set_current_block(NULL);
}
@@ -3273,7 +4043,7 @@ void HOptimizedGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
HBasicBlock* break_block = break_scope()->Get(
stmt->target(), BreakAndContinueScope::BREAK, &drop_extra);
Drop(drop_extra);
- current_block()->Goto(break_block);
+ Goto(break_block);
set_current_block(NULL);
}
@@ -3296,26 +4066,26 @@ void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
if (context->IsTest()) {
TestContext* test = TestContext::cast(context);
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- current_block()->Goto(test->if_true(), state);
+ Goto(test->if_true(), state);
} else if (context->IsEffect()) {
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- current_block()->Goto(function_return(), state);
+ Goto(function_return(), state);
} else {
ASSERT(context->IsValue());
CHECK_ALIVE(VisitForValue(stmt->expression()));
HValue* return_value = Pop();
HValue* receiver = environment()->arguments_environment()->Lookup(0);
HHasInstanceTypeAndBranch* typecheck =
- new(zone()) HHasInstanceTypeAndBranch(return_value,
- FIRST_SPEC_OBJECT_TYPE,
- LAST_SPEC_OBJECT_TYPE);
+ New<HHasInstanceTypeAndBranch>(return_value,
+ FIRST_SPEC_OBJECT_TYPE,
+ LAST_SPEC_OBJECT_TYPE);
HBasicBlock* if_spec_object = graph()->CreateBasicBlock();
HBasicBlock* not_spec_object = graph()->CreateBasicBlock();
typecheck->SetSuccessorAt(0, if_spec_object);
typecheck->SetSuccessorAt(1, not_spec_object);
- current_block()->Finish(typecheck);
- if_spec_object->AddLeaveInlined(return_value, state);
- not_spec_object->AddLeaveInlined(receiver, state);
+ FinishCurrentBlock(typecheck);
+ AddLeaveInlined(if_spec_object, return_value, state);
+ AddLeaveInlined(not_spec_object, receiver, state);
}
} else if (state->inlining_kind() == SETTER_CALL_RETURN) {
// Return from an inlined setter call. The returned value is never used, the
@@ -3325,11 +4095,11 @@ void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
HValue* rhs = environment()->arguments_environment()->Lookup(1);
context->ReturnValue(rhs);
} else if (context->IsEffect()) {
- current_block()->Goto(function_return(), state);
+ Goto(function_return(), state);
} else {
ASSERT(context->IsValue());
HValue* rhs = environment()->arguments_environment()->Lookup(1);
- current_block()->AddLeaveInlined(rhs, state);
+ AddLeaveInlined(rhs, state);
}
} else {
// Return from a normal inlined function. Visit the subexpression in the
@@ -3339,11 +4109,11 @@ void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
VisitForControl(stmt->expression(), test->if_true(), test->if_false());
} else if (context->IsEffect()) {
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- current_block()->Goto(function_return(), state);
+ Goto(function_return(), state);
} else {
ASSERT(context->IsValue());
CHECK_ALIVE(VisitForValue(stmt->expression()));
- current_block()->AddLeaveInlined(Pop(), state);
+ AddLeaveInlined(Pop(), state);
}
}
set_current_block(NULL);
@@ -3377,8 +4147,6 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
return Bailout(kSwitchStatementMixedOrNonLiteralSwitchLabels);
}
- HValue* context = environment()->context();
-
CHECK_ALIVE(VisitForValue(stmt->tag()));
Add<HSimulate>(stmt->EntryId());
HValue* tag_value = Pop();
@@ -3389,13 +4157,11 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
// Test switch's tag value if all clauses are string literals
if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) {
- string_check = new(zone()) HIsStringAndBranch(tag_value);
first_test_block = graph()->CreateBasicBlock();
not_string_block = graph()->CreateBasicBlock();
-
- string_check->SetSuccessorAt(0, first_test_block);
- string_check->SetSuccessorAt(1, not_string_block);
- current_block()->Finish(string_check);
+ string_check = New<HIsStringAndBranch>(
+ tag_value, first_test_block, not_string_block);
+ FinishCurrentBlock(string_check);
set_current_block(first_test_block);
}
@@ -3424,21 +4190,21 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
}
HCompareNumericAndBranch* compare_ =
- new(zone()) HCompareNumericAndBranch(tag_value,
- label_value,
- Token::EQ_STRICT);
+ New<HCompareNumericAndBranch>(tag_value,
+ label_value,
+ Token::EQ_STRICT);
compare_->set_observed_input_representation(
Representation::Smi(), Representation::Smi());
compare = compare_;
} else {
- compare = new(zone()) HStringCompareAndBranch(context, tag_value,
- label_value,
- Token::EQ_STRICT);
+ compare = New<HStringCompareAndBranch>(tag_value,
+ label_value,
+ Token::EQ_STRICT);
}
compare->SetSuccessorAt(0, body_block);
compare->SetSuccessorAt(1, next_test_block);
- current_block()->Finish(compare);
+ FinishCurrentBlock(compare);
set_current_block(next_test_block);
}
@@ -3471,6 +4237,13 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
last_block = NULL; // Cleared to indicate we've handled it.
}
} else {
+ // If the current test block is deoptimizing due to an unhandled clause
+ // of the switch, the test instruction is in the next block since the
+ // deopt must end the current block.
+ if (curr_test_block->IsDeoptimizing()) {
+ ASSERT(curr_test_block->end()->SecondSuccessor() == NULL);
+ curr_test_block = curr_test_block->end()->FirstSuccessor();
+ }
normal_block = curr_test_block->end()->FirstSuccessor();
curr_test_block = curr_test_block->end()->SecondSuccessor();
}
@@ -3512,8 +4285,8 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
last_block,
stmt->ExitId()));
} else {
- if (fall_through_block != NULL) fall_through_block->Goto(break_block);
- if (last_block != NULL) last_block->Goto(break_block);
+ if (fall_through_block != NULL) Goto(fall_through_block, break_block);
+ if (last_block != NULL) Goto(last_block, break_block);
break_block->SetJoinId(stmt->ExitId());
set_current_block(break_block);
}
@@ -3525,9 +4298,8 @@ void HOptimizedGraphBuilder::VisitLoopBody(IterationStatement* stmt,
BreakAndContinueInfo* break_info) {
BreakAndContinueScope push(break_info, this);
Add<HSimulate>(stmt->StackCheckId());
- HValue* context = environment()->context();
- HStackCheck* stack_check = HStackCheck::cast(Add<HStackCheck>(
- context, HStackCheck::kBackwardsBranch));
+ HStackCheck* stack_check =
+ HStackCheck::cast(Add<HStackCheck>(HStackCheck::kBackwardsBranch));
ASSERT(loop_entry->IsLoopHeader());
loop_entry->loop_information()->set_stack_check(stack_check);
CHECK_BAILOUT(Visit(stmt->body()));
@@ -3539,7 +4311,7 @@ void HOptimizedGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
ASSERT(current_block() != NULL);
- HBasicBlock* loop_entry = osr_->BuildPossibleOsrLoopEntry(stmt);
+ HBasicBlock* loop_entry = BuildLoopEntry(stmt);
BreakAndContinueInfo break_info(stmt);
CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
@@ -3578,7 +4350,7 @@ void HOptimizedGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
ASSERT(current_block() != NULL);
- HBasicBlock* loop_entry = osr_->BuildPossibleOsrLoopEntry(stmt);
+ HBasicBlock* loop_entry = BuildLoopEntry(stmt);
// If the condition is constant true, do not generate a branch.
HBasicBlock* loop_successor = NULL;
@@ -3620,7 +4392,7 @@ void HOptimizedGraphBuilder::VisitForStatement(ForStatement* stmt) {
CHECK_ALIVE(Visit(stmt->init()));
}
ASSERT(current_block() != NULL);
- HBasicBlock* loop_entry = osr_->BuildPossibleOsrLoopEntry(stmt);
+ HBasicBlock* loop_entry = BuildLoopEntry(stmt);
HBasicBlock* loop_successor = NULL;
if (stmt->cond() != NULL) {
@@ -3703,14 +4475,14 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
HForInCacheArray::cast(array)->set_index_cache(
HForInCacheArray::cast(index_cache));
- HBasicBlock* loop_entry = osr_->BuildPossibleOsrLoopEntry(stmt);
+ HBasicBlock* loop_entry = BuildLoopEntry(stmt);
HValue* index = environment()->ExpressionStackAt(0);
HValue* limit = environment()->ExpressionStackAt(1);
// Check that we still have more keys.
HCompareNumericAndBranch* compare_index =
- new(zone()) HCompareNumericAndBranch(index, limit, Token::LT);
+ New<HCompareNumericAndBranch>(index, limit, Token::LT);
compare_index->set_observed_input_representation(
Representation::Smi(), Representation::Smi());
@@ -3719,7 +4491,7 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
compare_index->SetSuccessorAt(0, loop_body);
compare_index->SetSuccessorAt(1, loop_successor);
- current_block()->Finish(compare_index);
+ FinishCurrentBlock(compare_index);
set_current_block(loop_successor);
Drop(5);
@@ -3749,9 +4521,7 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
set_current_block(body_exit);
HValue* current_index = Pop();
- HInstruction* new_index = New<HAdd>(current_index,
- graph()->GetConstant1());
- PushAndAdd(new_index);
+ Push(AddUncasted<HAdd>(current_index, graph()->GetConstant1()));
body_exit = current_block();
}
@@ -3798,6 +4568,11 @@ void HOptimizedGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
}
+void HOptimizedGraphBuilder::VisitCaseClause(CaseClause* clause) {
+ UNREACHABLE();
+}
+
+
static Handle<SharedFunctionInfo> SearchSharedFunctionInfo(
Code* unoptimized_code, FunctionLiteral* expr) {
int start_position = expr->start_position();
@@ -3828,19 +4603,18 @@ void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
}
// We also have a stack overflow if the recursive compilation did.
if (HasStackOverflow()) return;
- HValue* context = environment()->context();
HFunctionLiteral* instr =
- new(zone()) HFunctionLiteral(context, shared_info, expr->pretenure());
+ New<HFunctionLiteral>(shared_info, expr->pretenure());
return ast_context()->ReturnInstruction(instr, expr->id());
}
-void HOptimizedGraphBuilder::VisitSharedFunctionInfoLiteral(
- SharedFunctionInfoLiteral* expr) {
+void HOptimizedGraphBuilder::VisitNativeFunctionLiteral(
+ NativeFunctionLiteral* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- return Bailout(kSharedFunctionInfoLiteral);
+ return Bailout(kNativeFunctionLiteral);
}
@@ -3954,19 +4728,15 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
return ast_context()->ReturnInstruction(constant, expr->id());
} else {
HLoadGlobalCell* instr =
- new(zone()) HLoadGlobalCell(cell, lookup.GetPropertyDetails());
+ New<HLoadGlobalCell>(cell, lookup.GetPropertyDetails());
return ast_context()->ReturnInstruction(instr, expr->id());
}
} else {
- HValue* context = environment()->context();
- HGlobalObject* global_object = new(zone()) HGlobalObject(context);
- AddInstruction(global_object);
+ HGlobalObject* global_object = Add<HGlobalObject>();
HLoadGlobalGeneric* instr =
- new(zone()) HLoadGlobalGeneric(context,
- global_object,
- variable->name(),
- ast_context()->is_for_typeof());
- instr->set_position(expr->position());
+ New<HLoadGlobalGeneric>(global_object,
+ variable->name(),
+ ast_context()->is_for_typeof());
return ast_context()->ReturnInstruction(instr, expr->id());
}
}
@@ -4009,13 +4779,10 @@ void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
ASSERT(current_block()->HasPredecessor());
Handle<JSFunction> closure = function_state()->compilation_info()->closure();
Handle<FixedArray> literals(closure->literals());
- HValue* context = environment()->context();
-
- HRegExpLiteral* instr = new(zone()) HRegExpLiteral(context,
- literals,
- expr->pattern(),
- expr->flags(),
- expr->literal_index());
+ HRegExpLiteral* instr = New<HRegExpLiteral>(literals,
+ expr->pattern(),
+ expr->flags(),
+ expr->literal_index());
return ast_context()->ReturnInstruction(instr, expr->id());
}
@@ -4080,20 +4847,6 @@ static bool LookupAccessorPair(Handle<Map> map,
}
-static bool LookupGetter(Handle<Map> map,
- Handle<String> name,
- Handle<JSFunction>* getter,
- Handle<JSObject>* holder) {
- Handle<AccessorPair> accessors;
- if (LookupAccessorPair(map, name, &accessors, holder) &&
- accessors->getter()->IsJSFunction()) {
- *getter = Handle<JSFunction>(JSFunction::cast(accessors->getter()));
- return true;
- }
- return false;
-}
-
-
static bool LookupSetter(Handle<Map> map,
Handle<String> name,
Handle<JSFunction>* setter,
@@ -4101,7 +4854,11 @@ static bool LookupSetter(Handle<Map> map,
Handle<AccessorPair> accessors;
if (LookupAccessorPair(map, name, &accessors, holder) &&
accessors->setter()->IsJSFunction()) {
- *setter = Handle<JSFunction>(JSFunction::cast(accessors->setter()));
+ Handle<JSFunction> func(JSFunction::cast(accessors->setter()));
+ CallOptimization call_optimization(func);
+ // TODO(dcarney): temporary hack unless crankshaft can handle api calls.
+ if (call_optimization.is_simple_api_call()) return false;
+ *setter = func;
return true;
}
return false;
@@ -4116,7 +4873,7 @@ static bool IsFastLiteral(Handle<JSObject> boilerplate,
int* max_properties) {
if (boilerplate->map()->is_deprecated()) {
Handle<Object> result = JSObject::TryMigrateInstance(boilerplate);
- if (result->IsSmi()) return false;
+ if (result.is_null()) return false;
}
ASSERT(max_depth >= 0 && *max_properties >= 0);
@@ -4177,23 +4934,29 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
+ expr->BuildConstantProperties(isolate());
Handle<JSFunction> closure = function_state()->compilation_info()->closure();
HInstruction* literal;
// Check whether to use fast or slow deep-copying for boilerplate.
int max_properties = kMaxFastLiteralProperties;
- Handle<Object> boilerplate(closure->literals()->get(
- expr->literal_index()), isolate());
- if (boilerplate->IsJSObject() &&
- IsFastLiteral(Handle<JSObject>::cast(boilerplate),
- kMaxFastLiteralDepth,
- &max_properties)) {
- Handle<JSObject> boilerplate_object =
- Handle<JSObject>::cast(boilerplate);
+ Handle<Object> literals_cell(closure->literals()->get(expr->literal_index()),
+ isolate());
+ Handle<AllocationSite> site;
+ Handle<JSObject> boilerplate;
+ if (!literals_cell->IsUndefined()) {
+ // Retrieve the boilerplate
+ site = Handle<AllocationSite>::cast(literals_cell);
+ boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()),
+ isolate());
+ }
- literal = BuildFastLiteral(boilerplate_object,
- Handle<Object>::null(),
- DONT_TRACK_ALLOCATION_SITE);
+ if (!boilerplate.is_null() &&
+ IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) {
+ AllocationSiteUsageContext usage_context(isolate(), site, false);
+ usage_context.EnterNewScope();
+ literal = BuildFastLiteral(boilerplate, &usage_context);
+ usage_context.ExitScope(site, boilerplate);
} else {
NoObservableSideEffectsScope no_effects(this);
Handle<FixedArray> closure_literals(closure->literals(), isolate());
@@ -4209,9 +4972,10 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
Add<HPushArgument>(Add<HConstant>(constant_properties));
Add<HPushArgument>(Add<HConstant>(flags));
- Runtime::FunctionId function_id =
- (expr->depth() > 1 || expr->may_store_doubles())
- ? Runtime::kCreateObjectLiteral : Runtime::kCreateObjectLiteralShallow;
+ // TODO(mvstanton): Add a flag to turn off creation of any
+ // AllocationMementos for this call: we are in crankshaft and should have
+ // learned enough about transition behavior to stop emitting mementos.
+ Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral;
literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
Runtime::FunctionForId(function_id),
4);
@@ -4292,6 +5056,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
+ expr->BuildConstantElements(isolate());
ZoneList<Expression*>* subexprs = expr->values();
int length = subexprs->length();
HInstruction* literal;
@@ -4301,67 +5066,73 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
bool uninitialized = false;
Handle<Object> literals_cell(literals->get(expr->literal_index()),
isolate());
- Handle<Object> raw_boilerplate;
+ Handle<JSObject> boilerplate_object;
if (literals_cell->IsUndefined()) {
uninitialized = true;
- raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
+ Handle<Object> raw_boilerplate = Runtime::CreateArrayLiteralBoilerplate(
isolate(), literals, expr->constant_elements());
if (raw_boilerplate.is_null()) {
return Bailout(kArrayBoilerplateCreationFailed);
}
- site = isolate()->factory()->NewAllocationSite();
- site->set_transition_info(*raw_boilerplate);
+ boilerplate_object = Handle<JSObject>::cast(raw_boilerplate);
+ AllocationSiteCreationContext creation_context(isolate());
+ site = creation_context.EnterNewScope();
+ if (JSObject::DeepWalk(boilerplate_object, &creation_context).is_null()) {
+ return Bailout(kArrayBoilerplateCreationFailed);
+ }
+ creation_context.ExitScope(site, boilerplate_object);
literals->set(expr->literal_index(), *site);
- if (JSObject::cast(*raw_boilerplate)->elements()->map() ==
+ if (boilerplate_object->elements()->map() ==
isolate()->heap()->fixed_cow_array_map()) {
isolate()->counters()->cow_arrays_created_runtime()->Increment();
}
} else {
ASSERT(literals_cell->IsAllocationSite());
site = Handle<AllocationSite>::cast(literals_cell);
- raw_boilerplate = Handle<Object>(site->transition_info(), isolate());
+ boilerplate_object = Handle<JSObject>(
+ JSObject::cast(site->transition_info()), isolate());
}
- ASSERT(!raw_boilerplate.is_null());
- ASSERT(site->IsLiteralSite());
+ ASSERT(!boilerplate_object.is_null());
+ ASSERT(site->SitePointsToLiteral());
- Handle<JSObject> boilerplate_object =
- Handle<JSObject>::cast(raw_boilerplate);
ElementsKind boilerplate_elements_kind =
- Handle<JSObject>::cast(boilerplate_object)->GetElementsKind();
-
- // TODO(mvstanton): This heuristic is only a temporary solution. In the
- // end, we want to quit creating allocation site info after a certain number
- // of GCs for a call site.
- AllocationSiteMode mode = AllocationSite::GetMode(
- boilerplate_elements_kind);
+ boilerplate_object->GetElementsKind();
// Check whether to use fast or slow deep-copying for boilerplate.
int max_properties = kMaxFastLiteralProperties;
if (IsFastLiteral(boilerplate_object,
kMaxFastLiteralDepth,
&max_properties)) {
- literal = BuildFastLiteral(boilerplate_object,
- site,
- mode);
+ AllocationSiteUsageContext usage_context(isolate(), site, false);
+ usage_context.EnterNewScope();
+ literal = BuildFastLiteral(boilerplate_object, &usage_context);
+ usage_context.ExitScope(site, boilerplate_object);
} else {
NoObservableSideEffectsScope no_effects(this);
// Boilerplate already exists and constant elements are never accessed,
// pass an empty fixed array to the runtime function instead.
Handle<FixedArray> constants = isolate()->factory()->empty_fixed_array();
int literal_index = expr->literal_index();
+ int flags = expr->depth() == 1
+ ? ArrayLiteral::kShallowElements
+ : ArrayLiteral::kNoFlags;
+ flags |= ArrayLiteral::kDisableMementos;
Add<HPushArgument>(Add<HConstant>(literals));
Add<HPushArgument>(Add<HConstant>(literal_index));
Add<HPushArgument>(Add<HConstant>(constants));
+ Add<HPushArgument>(Add<HConstant>(flags));
- Runtime::FunctionId function_id = (expr->depth() > 1)
- ? Runtime::kCreateArrayLiteral : Runtime::kCreateArrayLiteralShallow;
+ // TODO(mvstanton): Consider a flag to turn off creation of any
+ // AllocationMementos for this call: we are in crankshaft and should have
+ // learned enough about transition behavior to stop emitting mementos.
+ Runtime::FunctionId function_id = Runtime::kCreateArrayLiteral;
literal = Add<HCallRuntime>(isolate()->factory()->empty_string(),
Runtime::FunctionForId(function_id),
- 3);
+ 4);
// De-opt if elements kind changed from boilerplate_elements_kind.
Handle<Map> map = Handle<Map>(boilerplate_object->map(), isolate());
@@ -4415,31 +5186,6 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
}
-// Sets the lookup result and returns true if the load/store can be inlined.
-static bool ComputeLoadStoreField(Handle<Map> type,
- Handle<String> name,
- LookupResult* lookup,
- bool is_store) {
- ASSERT(!is_store || !type->is_observed());
- if (!CanInlinePropertyAccess(*type)) {
- lookup->NotFound();
- return false;
- }
- // If we directly find a field, the access can be inlined.
- type->LookupDescriptor(NULL, *name, lookup);
- if (lookup->IsField()) return true;
-
- // For a load, we are out of luck if there is no such field.
- if (!is_store) return false;
-
- // 2nd chance: A store into a non-existent field can still be inlined if we
- // have a matching transition and some room left in the object.
- type->LookupTransition(NULL, *name, lookup);
- return lookup->IsTransitionToField(*type) &&
- (type->unused_property_fields() > 0);
-}
-
-
HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object,
Handle<Map> map) {
BuildCheckHeapObject(object);
@@ -4484,7 +5230,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
}
HObjectAccess field_access = HObjectAccess::ForField(map, lookup, name);
- bool transition_to_field = lookup->IsTransitionToField(*map);
+ bool transition_to_field = lookup->IsTransitionToField();
HStoreNamedField *instr;
if (FLAG_track_double_fields && field_access.representation().IsDouble()) {
@@ -4520,7 +5266,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
}
if (transition_to_field) {
- Handle<Map> transition(lookup->GetTransitionMapFromMap(*map));
+ Handle<Map> transition(lookup->GetTransitionTarget());
HConstant* transition_constant = Add<HConstant>(transition);
instr->SetTransition(transition_constant, top_info());
// TODO(fschneider): Record the new map type of the object in the IR to
@@ -4535,9 +5281,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedGeneric(
HValue* object,
Handle<String> name,
HValue* value) {
- HValue* context = environment()->context();
- return new(zone()) HStoreNamedGeneric(
- context,
+ return New<HStoreNamedGeneric>(
object,
name,
value,
@@ -4545,6 +5289,28 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedGeneric(
}
+// Sets the lookup result and returns true if the load/store can be inlined.
+static bool ComputeStoreField(Handle<Map> type,
+ Handle<String> name,
+ LookupResult* lookup,
+ bool lookup_transition = true) {
+ ASSERT(!type->is_observed());
+ if (!CanInlinePropertyAccess(*type)) {
+ lookup->NotFound();
+ return false;
+ }
+ // If we directly find a field, the access can be inlined.
+ type->LookupDescriptor(NULL, *name, lookup);
+ if (lookup->IsField()) return true;
+
+ if (!lookup_transition) return false;
+
+ type->LookupTransition(NULL, *name, lookup);
+ return lookup->IsTransitionToField() &&
+ (type->unused_property_fields() > 0);
+}
+
+
HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic(
HValue* object,
Handle<String> name,
@@ -4552,7 +5318,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic(
Handle<Map> map) {
// Handle a store to a known field.
LookupResult lookup(isolate());
- if (ComputeLoadStoreField(map, name, &lookup, true)) {
+ if (ComputeStoreField(map, name, &lookup)) {
HCheckMaps* checked_object = AddCheckMap(object, map);
return BuildStoreNamedField(checked_object, name, value, map, &lookup);
}
@@ -4562,140 +5328,192 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic(
}
-static bool CanLoadPropertyFromPrototype(Handle<Map> map,
- Handle<Name> name,
- LookupResult* lookup) {
- if (!CanInlinePropertyAccess(*map)) return false;
- map->LookupDescriptor(NULL, *name, lookup);
- if (lookup->IsFound()) return false;
+bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad(
+ PropertyAccessInfo* info) {
+ if (!CanInlinePropertyAccess(*map_)) return false;
+
+ if (!LookupDescriptor()) return false;
+
+ if (!lookup_.IsFound()) {
+ return (!info->lookup_.IsFound() || info->has_holder()) &&
+ map_->prototype() == info->map_->prototype();
+ }
+
+ // Mismatch if the other access info found the property in the prototype
+ // chain.
+ if (info->has_holder()) return false;
+
+ if (lookup_.IsPropertyCallbacks()) {
+ return accessor_.is_identical_to(info->accessor_);
+ }
+
+ if (lookup_.IsConstant()) {
+ return constant_.is_identical_to(info->constant_);
+ }
+
+ ASSERT(lookup_.IsField());
+ if (!info->lookup_.IsField()) return false;
+
+ Representation r = access_.representation();
+ if (!info->access_.representation().IsCompatibleForLoad(r)) return false;
+ if (info->access_.offset() != access_.offset()) return false;
+ if (info->access_.IsInobject() != access_.IsInobject()) return false;
+ info->GeneralizeRepresentation(r);
return true;
}
-HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic(
- HValue* object,
- SmallMapList* types,
- Handle<String> name) {
- // Use monomorphic load if property lookup results in the same field index
- // for all maps. Requires special map check on the set of all handled maps.
- if (types->length() > kMaxLoadPolymorphism) return NULL;
+bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() {
+ map_->LookupDescriptor(NULL, *name_, &lookup_);
+ return LoadResult(map_);
+}
- LookupResult lookup(isolate());
- int count;
- HObjectAccess access = HObjectAccess::ForMap(); // initial value unused.
- for (count = 0; count < types->length(); ++count) {
- Handle<Map> map = types->at(count);
- if (!ComputeLoadStoreField(map, name, &lookup, false)) break;
- HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name);
+bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) {
+ if (lookup_.IsField()) {
+ access_ = HObjectAccess::ForField(map, &lookup_, name_);
+ } else if (lookup_.IsPropertyCallbacks()) {
+ Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate());
+ if (!callback->IsAccessorPair()) return false;
+ Object* getter = Handle<AccessorPair>::cast(callback)->getter();
+ if (!getter->IsJSFunction()) return false;
+ Handle<JSFunction> accessor = handle(JSFunction::cast(getter));
+ CallOptimization call_optimization(accessor);
+ // TODO(dcarney): temporary hack unless crankshaft can handle api calls.
+ if (call_optimization.is_simple_api_call()) return false;
+ accessor_ = accessor;
+ } else if (lookup_.IsConstant()) {
+ constant_ = handle(lookup_.GetConstantFromMap(*map), isolate());
+ }
- if (count == 0) {
- // First time through the loop; set access and representation.
- access = new_access;
- } else if (!access.representation().IsCompatibleForLoad(
- new_access.representation())) {
- // Representations did not match.
- break;
- } else if (access.offset() != new_access.offset()) {
- // Offsets did not match.
- break;
- } else if (access.IsInobject() != new_access.IsInobject()) {
- // In-objectness did not match.
- break;
+ return true;
+}
+
+
+bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() {
+ Handle<Map> map = map_;
+ while (map->prototype()->IsJSObject()) {
+ holder_ = handle(JSObject::cast(map->prototype()));
+ if (holder_->map()->is_deprecated()) {
+ JSObject::TryMigrateInstance(holder_);
+ }
+ map = Handle<Map>(holder_->map());
+ if (!CanInlinePropertyAccess(*map)) {
+ lookup_.NotFound();
+ return false;
}
- access = access.WithRepresentation(
- access.representation().generalize(new_access.representation()));
+ map->LookupDescriptor(*holder_, *name_, &lookup_);
+ if (lookup_.IsFound()) return LoadResult(map);
}
+ lookup_.NotFound();
+ return true;
+}
- if (count == types->length()) {
- // Everything matched; can use monomorphic load.
- BuildCheckHeapObject(object);
- HCheckMaps* checked_object = Add<HCheckMaps>(object, types);
- return BuildLoadNamedField(checked_object, access);
- }
- if (count != 0) return NULL;
+bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() {
+ if (!CanInlinePropertyAccess(*map_)) return IsStringLength();
+ if (IsJSObjectFieldAccessor()) return true;
+ if (!LookupDescriptor()) return false;
+ if (lookup_.IsFound()) return true;
+ return LookupInPrototypes();
+}
+
- // Second chance: the property is on the prototype and all maps have the
- // same prototype.
- Handle<Map> map(types->at(0));
- if (!CanLoadPropertyFromPrototype(map, name, &lookup)) return NULL;
+bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic(
+ SmallMapList* types) {
+ ASSERT(map_.is_identical_to(types->first()));
+ if (!CanLoadMonomorphic()) return false;
+ if (types->length() > kMaxLoadPolymorphism) return false;
- Handle<Object> prototype(map->prototype(), isolate());
- for (count = 1; count < types->length(); ++count) {
- Handle<Map> test_map(types->at(count));
- if (!CanLoadPropertyFromPrototype(test_map, name, &lookup)) return NULL;
- if (test_map->prototype() != *prototype) return NULL;
+ if (IsStringLength()) {
+ for (int i = 1; i < types->length(); ++i) {
+ if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
+ }
+ return true;
}
- LookupInPrototypes(map, name, &lookup);
- if (!lookup.IsField()) return NULL;
+ if (IsArrayLength()) {
+ bool is_fast = IsFastElementsKind(map_->elements_kind());
+ for (int i = 1; i < types->length(); ++i) {
+ Handle<Map> test_map = types->at(i);
+ if (test_map->instance_type() != JS_ARRAY_TYPE) return false;
+ if (IsFastElementsKind(test_map->elements_kind()) != is_fast) {
+ return false;
+ }
+ }
+ return true;
+ }
- BuildCheckHeapObject(object);
- Add<HCheckMaps>(object, types);
+ if (IsJSObjectFieldAccessor()) {
+ InstanceType instance_type = map_->instance_type();
+ for (int i = 1; i < types->length(); ++i) {
+ if (types->at(i)->instance_type() != instance_type) return false;
+ }
+ return true;
+ }
+
+ for (int i = 1; i < types->length(); ++i) {
+ PropertyAccessInfo test_info(isolate(), types->at(i), name_);
+ if (!test_info.IsCompatibleForLoad(this)) return false;
+ }
- Handle<JSObject> holder(lookup.holder());
- Handle<Map> holder_map(holder->map());
- HValue* checked_holder = BuildCheckPrototypeMaps(
- Handle<JSObject>::cast(prototype), holder);
- return BuildLoadNamedField(checked_holder,
- HObjectAccess::ForField(holder_map, &lookup, name));
+ return true;
}
-// Returns true if an instance of this map can never find a property with this
-// name in its prototype chain. This means all prototypes up to the top are
-// fast and don't have the name in them. It would be good if we could optimize
-// polymorphic loads where the property is sometimes found in the prototype
-// chain.
-static bool PrototypeChainCanNeverResolve(
- Handle<Map> map, Handle<String> name) {
- Isolate* isolate = map->GetIsolate();
- Object* current = map->prototype();
- while (current != isolate->heap()->null_value()) {
- if (current->IsJSGlobalProxy() ||
- current->IsGlobalObject() ||
- !current->IsJSObject() ||
- !CanInlinePropertyAccess(JSObject::cast(current)->map()) ||
- JSObject::cast(current)->IsAccessCheckNeeded()) {
- return false;
- }
+HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
+ PropertyAccessInfo* info,
+ HValue* object,
+ HInstruction* checked_object,
+ BailoutId ast_id,
+ BailoutId return_id,
+ bool can_inline_accessor) {
- LookupResult lookup(isolate);
- Map* map = JSObject::cast(current)->map();
- map->LookupDescriptor(NULL, *name, &lookup);
- if (lookup.IsFound()) return false;
- if (!lookup.IsCacheable()) return false;
- current = JSObject::cast(current)->GetPrototype();
+ HObjectAccess access = HObjectAccess::ForMap(); // bogus default
+ if (info->GetJSObjectFieldAccess(&access)) {
+ return New<HLoadNamedField>(checked_object, access);
}
- return true;
+
+ HValue* checked_holder = checked_object;
+ if (info->has_holder()) {
+ Handle<JSObject> prototype(JSObject::cast(info->map()->prototype()));
+ checked_holder = BuildCheckPrototypeMaps(prototype, info->holder());
+ }
+
+ if (!info->lookup()->IsFound()) return graph()->GetConstantUndefined();
+
+ if (info->lookup()->IsField()) {
+ return BuildLoadNamedField(checked_holder, info->access());
+ }
+
+ if (info->lookup()->IsPropertyCallbacks()) {
+ Push(checked_object);
+ if (FLAG_inline_accessors &&
+ can_inline_accessor &&
+ TryInlineGetter(info->accessor(), ast_id, return_id)) {
+ return NULL;
+ }
+ Add<HPushArgument>(Pop());
+ return New<HCallConstantFunction>(info->accessor(), 1);
+ }
+
+ ASSERT(info->lookup()->IsConstant());
+ return New<HConstant>(info->constant());
}
void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
- int position,
BailoutId ast_id,
+ BailoutId return_id,
HValue* object,
SmallMapList* types,
Handle<String> name) {
- HInstruction* instr = TryLoadPolymorphicAsMonomorphic(object, types, name);
- if (instr != NULL) {
- instr->set_position(position);
- return ast_context()->ReturnInstruction(instr, ast_id);
- }
-
// Something did not match; must use a polymorphic load.
int count = 0;
HBasicBlock* join = NULL;
for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
- Handle<Map> map = types->at(i);
- LookupResult lookup(isolate());
- if (ComputeLoadStoreField(map, name, &lookup, false) ||
- (lookup.IsCacheable() &&
- CanInlinePropertyAccess(*map) &&
- (lookup.IsConstant() ||
- (!lookup.IsFound() &&
- PrototypeChainCanNeverResolve(map, name))))) {
+ PropertyAccessInfo info(isolate(), types->at(i), name);
+ if (info.CanLoadMonomorphic()) {
if (count == 0) {
BuildCheckHeapObject(object);
join = graph()->CreateBasicBlock();
@@ -4703,37 +5521,24 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
++count;
HBasicBlock* if_true = graph()->CreateBasicBlock();
HBasicBlock* if_false = graph()->CreateBasicBlock();
- HCompareMap* compare =
- new(zone()) HCompareMap(object, map, if_true, if_false);
- current_block()->Finish(compare);
+ HCompareMap* compare = New<HCompareMap>(
+ object, info.map(), if_true, if_false);
+ FinishCurrentBlock(compare);
set_current_block(if_true);
- // TODO(verwaest): Merge logic with BuildLoadNamedMonomorphic.
- if (lookup.IsField()) {
- HObjectAccess access = HObjectAccess::ForField(map, &lookup, name);
- HLoadNamedField* load = BuildLoadNamedField(compare, access);
- load->set_position(position);
- AddInstruction(load);
- if (!ast_context()->IsEffect()) Push(load);
- } else if (lookup.IsConstant()) {
- Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate());
- HConstant* hconstant = Add<HConstant>(constant);
- if (!ast_context()->IsEffect()) Push(hconstant);
+ HInstruction* load = BuildLoadMonomorphic(
+ &info, object, compare, ast_id, return_id, FLAG_polymorphic_inlining);
+ if (load == NULL) {
+ if (HasStackOverflow()) return;
} else {
- ASSERT(!lookup.IsFound());
- if (map->prototype()->IsJSObject()) {
- Handle<JSObject> prototype(JSObject::cast(map->prototype()));
- Handle<JSObject> holder = prototype;
- while (holder->map()->prototype()->IsJSObject()) {
- holder = handle(JSObject::cast(holder->map()->prototype()));
- }
- BuildCheckPrototypeMaps(prototype, holder);
+ if (!load->IsLinked()) {
+ AddInstruction(load);
}
- if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined());
+ if (!ast_context()->IsEffect()) Push(load);
}
- current_block()->Goto(join);
+ if (current_block() != NULL) Goto(join);
set_current_block(if_false);
}
}
@@ -4742,16 +5547,17 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
// know about and do not want to handle ones we've never seen. Otherwise
// use a generic IC.
if (count == types->length() && FLAG_deoptimize_uncommon_cases) {
+ // Because the deopt may be the only path in the polymorphic load, make sure
+ // that the environment stack matches the depth on deopt that it otherwise
+ // would have had after a successful load.
+ if (!ast_context()->IsEffect()) Push(graph()->GetConstant0());
FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join);
} else {
- HValue* context = environment()->context();
- HInstruction* load = new(zone()) HLoadNamedGeneric(context, object, name);
- load->set_position(position);
- AddInstruction(load);
+ HInstruction* load = Add<HLoadNamedGeneric>(object, name);
if (!ast_context()->IsEffect()) Push(load);
if (join != NULL) {
- current_block()->Goto(join);
+ Goto(join);
} else {
Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
@@ -4767,7 +5573,6 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
- int position,
BailoutId assignment_id,
HValue* object,
HValue* value,
@@ -4777,8 +5582,6 @@ bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
// for all maps. Requires special map check on the set of all handled maps.
if (types->length() > kMaxStorePolymorphism) return false;
- // TODO(verwaest): Merge the checking logic with the code in
- // TryLoadPolymorphicAsMonomorphic.
LookupResult lookup(isolate());
int count;
Representation representation = Representation::None();
@@ -4786,7 +5589,7 @@ bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
for (count = 0; count < types->length(); ++count) {
Handle<Map> map = types->at(count);
// Pass false to ignore transitions.
- if (!ComputeLoadStoreField(map, name, &lookup, false)) break;
+ if (!ComputeStoreField(map, name, &lookup, false)) break;
ASSERT(!map->is_observed());
HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name);
@@ -4819,7 +5622,6 @@ bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
checked_object, name, value, types->at(count - 1), &lookup),
true);
if (!ast_context()->IsEffect()) Push(value);
- store->set_position(position);
AddInstruction(store);
Add<HSimulate>(assignment_id);
if (!ast_context()->IsEffect()) Drop(1);
@@ -4829,14 +5631,13 @@ bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
- int position,
BailoutId assignment_id,
HValue* object,
HValue* value,
SmallMapList* types,
Handle<String> name) {
if (TryStorePolymorphicAsMonomorphic(
- position, assignment_id, object, value, types, name)) {
+ assignment_id, object, value, types, name)) {
return;
}
@@ -4848,7 +5649,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) {
Handle<Map> map = types->at(i);
LookupResult lookup(isolate());
- if (ComputeLoadStoreField(map, name, &lookup, true)) {
+ if (ComputeStoreField(map, name, &lookup)) {
if (count == 0) {
BuildCheckHeapObject(object);
join = graph()->CreateBasicBlock();
@@ -4856,19 +5657,17 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
++count;
HBasicBlock* if_true = graph()->CreateBasicBlock();
HBasicBlock* if_false = graph()->CreateBasicBlock();
- HCompareMap* compare =
- new(zone()) HCompareMap(object, map, if_true, if_false);
- current_block()->Finish(compare);
+ HCompareMap* compare = New<HCompareMap>(object, map, if_true, if_false);
+ FinishCurrentBlock(compare);
set_current_block(if_true);
HInstruction* instr;
CHECK_ALIVE(instr = BuildStoreNamedField(
compare, name, value, map, &lookup));
- instr->set_position(position);
// Goto will add the HSimulate for the store.
AddInstruction(instr);
if (!ast_context()->IsEffect()) Push(value);
- current_block()->Goto(join);
+ Goto(join);
set_current_block(if_false);
}
@@ -4881,14 +5680,13 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
FinishExitWithHardDeoptimization("Unknown map in polymorphic store", join);
} else {
HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
- instr->set_position(position);
AddInstruction(instr);
if (join != NULL) {
if (!ast_context()->IsEffect()) {
Push(value);
}
- current_block()->Goto(join);
+ Goto(join);
} else {
// The HSimulate for the store should not see the stored value in
// effect contexts (it is not materialized at expr->id() in the
@@ -4942,8 +5740,7 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
HValue* key = environment()->ExpressionStackAt(1);
HValue* object = environment()->ExpressionStackAt(2);
bool has_side_effects = false;
- HandleKeyedElementAccess(object, key, value, expr, return_id,
- expr->position(),
+ HandleKeyedElementAccess(object, key, value, expr,
true, // is_store
&has_side_effects);
Drop(3);
@@ -4982,7 +5779,7 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
Drop(2);
Add<HPushArgument>(object);
Add<HPushArgument>(value);
- instr = new(zone()) HCallConstantFunction(setter, 2);
+ instr = New<HCallConstantFunction>(setter, 2);
} else {
Drop(2);
CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object,
@@ -4992,15 +5789,13 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
}
} else if (types != NULL && types->length() > 1) {
Drop(2);
- return HandlePolymorphicStoreNamedField(
- expr->position(), ast_id, object, value, types, name);
+ return HandlePolymorphicStoreNamedField(ast_id, object, value, types, name);
} else {
Drop(2);
instr = BuildStoreNamedGeneric(object, name, value);
}
if (!ast_context()->IsEffect()) Push(value);
- instr->set_position(expr->position());
AddInstruction(instr);
if (instr->HasObservableSideEffects()) {
Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
@@ -5029,7 +5824,6 @@ void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
Variable* var,
HValue* value,
- int position,
BailoutId ast_id) {
LookupResult lookup(isolate());
GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
@@ -5052,7 +5846,6 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
}
HInstruction* instr =
Add<HStoreGlobalCell>(value, cell, lookup.GetPropertyDetails());
- instr->set_position(position);
if (instr->HasObservableSideEffects()) {
Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
}
@@ -5061,7 +5854,7 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
HStoreGlobalGeneric* instr =
Add<HStoreGlobalGeneric>(global_object, var->name(),
value, function_strict_mode_flag());
- instr->set_position(position);
+ USE(instr);
ASSERT(instr->HasObservableSideEffects());
Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
}
@@ -5090,7 +5883,6 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
case Variable::UNALLOCATED:
HandleGlobalVariableAssignment(var,
Top(),
- expr->position(),
expr->AssignmentId());
break;
@@ -5152,25 +5944,19 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
CHECK_ALIVE(VisitForValue(prop->obj()));
HValue* object = Top();
HValue* key = NULL;
- if ((!prop->IsStringLength() &&
- !prop->IsFunctionPrototype() &&
- !prop->key()->IsPropertyName()) ||
+ if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) ||
prop->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(prop->key()));
key = Top();
}
- CHECK_ALIVE(PushLoad(prop, object, key, expr->position()));
+ CHECK_ALIVE(PushLoad(prop, object, key));
CHECK_ALIVE(VisitForValue(expr->value()));
HValue* right = Pop();
HValue* left = Pop();
- HInstruction* instr = BuildBinaryOperation(operation, left, right);
- PushAndAdd(instr);
- if (instr->HasObservableSideEffects()) {
- Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE);
- }
+ Push(BuildBinaryOperation(operation, left, right));
BuildStore(expr, prop, expr->id(),
expr->AssignmentId(), expr->IsUninitialized());
} else {
@@ -5223,7 +6009,6 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
CHECK_ALIVE(VisitForValue(expr->value()));
HandleGlobalVariableAssignment(var,
Top(),
- expr->position(),
expr->AssignmentId());
return ast_context()->ReturnValue(Pop());
@@ -5322,9 +6107,16 @@ void HOptimizedGraphBuilder::VisitThrow(Throw* expr) {
CHECK_ALIVE(VisitForValue(expr->exception()));
HValue* value = environment()->Pop();
- HThrow* instr = Add<HThrow>(value);
- instr->set_position(expr->position());
+ if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
+ Add<HThrow>(value);
Add<HSimulate>(expr->id());
+
+ // If the throw definitely exits the function, we can finish with a dummy
+ // control flow at this point. This is not the case if the throw is inside
+ // an inlined function which may be replaced.
+ if (call_context() == NULL) {
+ FinishExitCurrentBlock(New<HAbnormalExit>());
+ }
}
@@ -5343,6 +6135,12 @@ HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object,
}
+HInstruction* HGraphBuilder::AddLoadNamedField(HValue* object,
+ HObjectAccess access) {
+ return AddInstruction(BuildLoadNamedField(object, access));
+}
+
+
HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* object,
HValue* checked_string) {
if (FLAG_fold_constants && object->IsConstant()) {
@@ -5363,93 +6161,14 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric(
Add<HDeoptimize>("Insufficient type feedback for generic named load",
Deoptimizer::SOFT);
}
- HValue* context = environment()->context();
- return new(zone()) HLoadNamedGeneric(context, object, name);
-}
-
-
-HInstruction* HOptimizedGraphBuilder::BuildCallGetter(
- HValue* object,
- Handle<Map> map,
- Handle<JSFunction> getter,
- Handle<JSObject> holder) {
- AddCheckConstantFunction(holder, object, map);
- Add<HPushArgument>(object);
- return new(zone()) HCallConstantFunction(getter, 1);
+ return New<HLoadNamedGeneric>(object, name);
}
-HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
- HValue* object,
- Handle<String> name,
- Handle<Map> map) {
- // Handle a load from a known field.
- ASSERT(!map->is_dictionary_map());
-
- // Handle access to various length properties
- if (name->Equals(isolate()->heap()->length_string())) {
- if (map->instance_type() == JS_ARRAY_TYPE) {
- HCheckMaps* checked_object = AddCheckMap(object, map);
- return New<HLoadNamedField>(
- checked_object, HObjectAccess::ForArrayLength(map->elements_kind()));
- }
- }
-
- LookupResult lookup(isolate());
- map->LookupDescriptor(NULL, *name, &lookup);
- if (lookup.IsField()) {
- HCheckMaps* checked_object = AddCheckMap(object, map);
- ASSERT(map->IsJSObjectMap());
- return BuildLoadNamedField(
- checked_object, HObjectAccess::ForField(map, &lookup, name));
- }
-
- // Handle a load of a constant known function.
- if (lookup.IsConstant()) {
- AddCheckMap(object, map);
- Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate());
- return New<HConstant>(constant);
- }
-
- if (lookup.IsFound()) {
- // Cannot handle the property, do a generic load instead.
- HValue* context = environment()->context();
- return new(zone()) HLoadNamedGeneric(context, object, name);
- }
-
- // Handle a load from a known field somewhere in the prototype chain.
- LookupInPrototypes(map, name, &lookup);
- if (lookup.IsField()) {
- Handle<JSObject> prototype(JSObject::cast(map->prototype()));
- Handle<JSObject> holder(lookup.holder());
- AddCheckMap(object, map);
- HValue* checked_holder = BuildCheckPrototypeMaps(prototype, holder);
- Handle<Map> holder_map(holder->map());
- return BuildLoadNamedField(
- checked_holder, HObjectAccess::ForField(holder_map, &lookup, name));
- }
-
- // Handle a load of a constant function somewhere in the prototype chain.
- if (lookup.IsConstant()) {
- Handle<JSObject> prototype(JSObject::cast(map->prototype()));
- Handle<JSObject> holder(lookup.holder());
- Handle<Map> holder_map(holder->map());
- AddCheckMap(object, map);
- BuildCheckPrototypeMaps(prototype, holder);
- Handle<Object> constant(lookup.GetConstantFromMap(*holder_map), isolate());
- return New<HConstant>(constant);
- }
-
- // No luck, do a generic load.
- HValue* context = environment()->context();
- return new(zone()) HLoadNamedGeneric(context, object, name);
-}
-
HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object,
HValue* key) {
- HValue* context = environment()->context();
- return new(zone()) HLoadKeyedGeneric(context, object, key);
+ return New<HLoadKeyedGeneric>(object, key);
}
@@ -5483,6 +6202,21 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
checked_object->ClearGVNFlag(kDependsOnElementsKind);
}
+ if (is_store && map->prototype()->IsJSObject()) {
+ // monomorphic stores need a prototype chain check because shape
+ // changes could allow callbacks on elements in the chain that
+ // aren't compatible with monomorphic keyed stores.
+ Handle<JSObject> prototype(JSObject::cast(map->prototype()));
+ Object* holder = map->prototype();
+ while (holder->GetPrototype(isolate())->IsJSObject()) {
+ holder = holder->GetPrototype(isolate());
+ }
+ ASSERT(holder->GetPrototype(isolate())->IsNull());
+
+ BuildCheckPrototypeMaps(prototype,
+ Handle<JSObject>(JSObject::cast(holder)));
+ }
+
LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map);
return BuildUncheckedMonomorphicElementAccess(
checked_object, key, val,
@@ -5563,8 +6297,6 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
HValue* key,
HValue* val,
SmallMapList* maps,
- BailoutId ast_id,
- int position,
bool is_store,
KeyedAccessStoreMode store_mode,
bool* has_side_effects) {
@@ -5576,9 +6308,6 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
TryBuildConsolidatedElementLoad(object, key, val, maps);
if (consolidated_load != NULL) {
*has_side_effects |= consolidated_load->HasObservableSideEffects();
- if (position != RelocInfo::kNoPosition) {
- consolidated_load->set_position(position);
- }
return consolidated_load;
}
}
@@ -5635,7 +6364,6 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
store_mode);
}
*has_side_effects |= instr->HasObservableSideEffects();
- if (position != RelocInfo::kNoPosition) instr->set_position(position);
return is_store ? NULL : instr;
}
@@ -5648,8 +6376,8 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
HBasicBlock* this_map = graph()->CreateBasicBlock();
HBasicBlock* other_map = graph()->CreateBasicBlock();
HCompareMap* mapcompare =
- new(zone()) HCompareMap(object, map, this_map, other_map);
- current_block()->Finish(mapcompare);
+ New<HCompareMap>(object, map, this_map, other_map);
+ FinishCurrentBlock(mapcompare);
set_current_block(this_map);
HInstruction* access = NULL;
@@ -5672,12 +6400,11 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
*has_side_effects |= access->HasObservableSideEffects();
// The caller will use has_side_effects and add a correct Simulate.
access->SetFlag(HValue::kHasNoObservableSideEffects);
- if (position != RelocInfo::kNoPosition) access->set_position(position);
if (!is_store) {
Push(access);
}
NoObservableSideEffectsScope scope(this);
- current_block()->GotoNoSimulate(join);
+ GotoNoSimulate(join);
set_current_block(other_map);
}
@@ -5695,8 +6422,6 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
HValue* key,
HValue* val,
Expression* expr,
- BailoutId ast_id,
- int position,
bool is_store,
bool* has_side_effects) {
ASSERT(!expr->IsPropertyName());
@@ -5705,6 +6430,22 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
SmallMapList* types;
bool monomorphic = ComputeReceiverTypes(expr, obj, &types);
+ bool force_generic = false;
+ if (is_store && (monomorphic || (types != NULL && !types->is_empty()))) {
+ // Stores can't be mono/polymorphic if their prototype chain has dictionary
+ // elements. However a receiver map that has dictionary elements itself
+ // should be left to normal mono/poly behavior (the other maps may benefit
+ // from highly optimized stores).
+ for (int i = 0; i < types->length(); i++) {
+ Handle<Map> current_map = types->at(i);
+ if (current_map->DictionaryElementsInPrototypeChainOnly()) {
+ force_generic = true;
+ monomorphic = false;
+ break;
+ }
+ }
+ }
+
if (monomorphic) {
Handle<Map> map = types->first();
if (map->has_slow_elements_kind()) {
@@ -5716,19 +6457,20 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
instr = BuildMonomorphicElementAccess(
obj, key, val, NULL, map, is_store, expr->GetStoreMode());
}
- } else if (types != NULL && !types->is_empty()) {
+ } else if (!force_generic && (types != NULL && !types->is_empty())) {
return HandlePolymorphicElementAccess(
- obj, key, val, types, ast_id, position, is_store,
+ obj, key, val, types, is_store,
expr->GetStoreMode(), has_side_effects);
} else {
if (is_store) {
- if (expr->IsAssignment() && expr->AsAssignment()->IsUninitialized()) {
+ if (expr->IsAssignment() &&
+ expr->AsAssignment()->HasNoTypeInformation()) {
Add<HDeoptimize>("Insufficient type feedback for keyed store",
Deoptimizer::SOFT);
}
instr = BuildStoreKeyedGeneric(obj, key, val);
} else {
- if (expr->AsProperty()->IsUninitialized()) {
+ if (expr->AsProperty()->HasNoTypeInformation()) {
Add<HDeoptimize>("Insufficient type feedback for keyed load",
Deoptimizer::SOFT);
}
@@ -5736,7 +6478,6 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
}
AddInstruction(instr);
}
- if (position != RelocInfo::kNoPosition) instr->set_position(position);
*has_side_effects = instr->HasObservableSideEffects();
return instr;
}
@@ -5746,9 +6487,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreKeyedGeneric(
HValue* object,
HValue* key,
HValue* value) {
- HValue* context = environment()->context();
- return new(zone()) HStoreKeyedGeneric(
- context,
+ return New<HStoreKeyedGeneric>(
object,
key,
value,
@@ -5815,7 +6554,7 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
HInstruction* elements = Add<HArgumentsElements>(false);
HInstruction* length = Add<HArgumentsLength>(elements);
HInstruction* checked_key = Add<HBoundsCheck>(key, length);
- result = new(zone()) HAccessArgumentsAt(elements, length, checked_key);
+ result = New<HAccessArgumentsAt>(elements, length, checked_key);
} else {
EnsureArgumentsArePushedForAccess();
@@ -5825,7 +6564,7 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
arguments_environment()->parameter_count() - 1;
HInstruction* length = Add<HConstant>(argument_count);
HInstruction* checked_key = Add<HBoundsCheck>(key, length);
- result = new(zone()) HAccessArgumentsAt(elements, length, checked_key);
+ result = New<HAccessArgumentsAt>(elements, length, checked_key);
}
}
ast_context()->ReturnInstruction(result, expr->id());
@@ -5835,66 +6574,66 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
void HOptimizedGraphBuilder::PushLoad(Property* expr,
HValue* object,
- HValue* key,
- int position) {
+ HValue* key) {
ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
Push(object);
if (key != NULL) Push(key);
- BuildLoad(expr, position, expr->LoadId());
+ BuildLoad(expr, expr->LoadId());
+}
+
+
+static bool AreStringTypes(SmallMapList* types) {
+ for (int i = 0; i < types->length(); i++) {
+ if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false;
+ }
+ return true;
}
void HOptimizedGraphBuilder::BuildLoad(Property* expr,
- int position,
BailoutId ast_id) {
HInstruction* instr = NULL;
- if (expr->IsStringLength()) {
- HValue* string = Pop();
- BuildCheckHeapObject(string);
- HInstruction* checkstring =
- AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
- instr = BuildLoadStringLength(string, checkstring);
- } else if (expr->IsStringAccess()) {
+ if (expr->IsStringAccess()) {
HValue* index = Pop();
HValue* string = Pop();
- HValue* context = environment()->context();
- HInstruction* char_code =
- BuildStringCharCodeAt(string, index);
+ HInstruction* char_code = BuildStringCharCodeAt(string, index);
AddInstruction(char_code);
- instr = HStringCharFromCode::New(zone(), context, char_code);
+ instr = NewUncasted<HStringCharFromCode>(char_code);
} else if (expr->IsFunctionPrototype()) {
HValue* function = Pop();
BuildCheckHeapObject(function);
- instr = new(zone()) HLoadFunctionPrototype(function);
+ instr = New<HLoadFunctionPrototype>(function);
} else if (expr->key()->IsPropertyName()) {
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
- HValue* object = Top();
+ HValue* object = Pop();
SmallMapList* types;
- bool monomorphic = ComputeReceiverTypes(expr, object, &types);
+ ComputeReceiverTypes(expr, object, &types);
+ ASSERT(types != NULL);
+
+ if (types->length() > 0) {
+ PropertyAccessInfo info(isolate(), types->first(), name);
+ if (!info.CanLoadAsMonomorphic(types)) {
+ return HandlePolymorphicLoadNamedField(
+ ast_id, expr->LoadId(), object, types, name);
+ }
- if (monomorphic) {
- Handle<Map> map = types->first();
- Handle<JSFunction> getter;
- Handle<JSObject> holder;
- if (LookupGetter(map, name, &getter, &holder)) {
- AddCheckConstantFunction(holder, Top(), map);
- if (FLAG_inline_accessors &&
- TryInlineGetter(getter, ast_id, expr->LoadId())) {
- return;
- }
- Add<HPushArgument>(Pop());
- instr = new(zone()) HCallConstantFunction(getter, 1);
+ BuildCheckHeapObject(object);
+ HInstruction* checked_object;
+ if (AreStringTypes(types)) {
+ checked_object =
+ Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING);
} else {
- instr = BuildLoadNamedMonomorphic(Pop(), name, map);
+ checked_object = Add<HCheckMaps>(object, types);
}
- } else if (types != NULL && types->length() > 1) {
- return HandlePolymorphicLoadNamedField(
- position, ast_id, Pop(), types, name);
+ instr = BuildLoadMonomorphic(
+ &info, object, checked_object, ast_id, expr->LoadId());
+ if (instr == NULL) return;
+ if (instr->IsLinked()) return ast_context()->ReturnValue(instr);
} else {
- instr = BuildLoadNamedGeneric(Pop(), name, expr);
+ instr = BuildLoadNamedGeneric(object, name, expr);
}
} else {
@@ -5903,7 +6642,7 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
bool has_side_effects = false;
HValue* load = HandleKeyedElementAccess(
- obj, key, NULL, expr, ast_id, position,
+ obj, key, NULL, expr,
false, // is_store
&has_side_effects);
if (has_side_effects) {
@@ -5917,7 +6656,6 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
}
return ast_context()->ReturnValue(load);
}
- instr->set_position(position);
return ast_context()->ReturnInstruction(instr, ast_id);
}
@@ -5930,14 +6668,12 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
if (TryArgumentsAccess(expr)) return;
CHECK_ALIVE(VisitForValue(expr->obj()));
- if ((!expr->IsStringLength() &&
- !expr->IsFunctionPrototype() &&
- !expr->key()->IsPropertyName()) ||
+ if ((!expr->IsFunctionPrototype() && !expr->key()->IsPropertyName()) ||
expr->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(expr->key()));
}
- BuildLoad(expr, expr->position(), expr->id());
+ BuildLoad(expr, expr->id());
}
@@ -6031,22 +6767,13 @@ bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic(
Handle<String> name) {
if (types->length() > kMaxCallPolymorphism) return false;
- Handle<Map> map(types->at(0));
- LookupResult lookup(isolate());
- if (!CanLoadPropertyFromPrototype(map, name, &lookup)) return false;
-
- Handle<Object> prototype(map->prototype(), isolate());
- for (int count = 1; count < types->length(); ++count) {
- Handle<Map> test_map(types->at(count));
- if (!CanLoadPropertyFromPrototype(test_map, name, &lookup)) return false;
- if (test_map->prototype() != *prototype) return false;
- }
-
- if (!expr->ComputeTarget(map, name)) return false;
+ PropertyAccessInfo info(isolate(), types->at(0), name);
+ if (!info.CanLoadAsMonomorphic(types)) return false;
+ if (!expr->ComputeTarget(info.map(), name)) return false;
BuildCheckHeapObject(receiver);
Add<HCheckMaps>(receiver, types);
- AddCheckPrototypeMaps(expr->holder(), map);
+ AddCheckPrototypeMaps(expr->holder(), info.map());
if (FLAG_trace_inlining) {
Handle<JSFunction> caller = current_info()->closure();
SmartArrayPointer<char> caller_name =
@@ -6058,8 +6785,7 @@ bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic(
if (!TryInlineCall(expr)) {
int argument_count = expr->arguments()->length() + 1; // Includes receiver.
HCallConstantFunction* call =
- new(zone()) HCallConstantFunction(expr->target(), argument_count);
- call->set_position(expr->position());
+ New<HCallConstantFunction>(expr->target(), argument_count);
PreProcessCall(call);
AddInstruction(call);
if (!ast_context()->IsEffect()) Push(call);
@@ -6123,11 +6849,9 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
number_block = graph()->CreateBasicBlock();
- HIsSmiAndBranch* smicheck = new(zone()) HIsSmiAndBranch(receiver);
- smicheck->SetSuccessorAt(0, empty_smi_block);
- smicheck->SetSuccessorAt(1, not_smi_block);
- current_block()->Finish(smicheck);
- empty_smi_block->Goto(number_block);
+ FinishCurrentBlock(New<HIsSmiAndBranch>(
+ receiver, empty_smi_block, not_smi_block));
+ Goto(empty_smi_block, number_block);
set_current_block(not_smi_block);
} else {
BuildCheckHeapObject(receiver);
@@ -6138,27 +6862,24 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
HUnaryControlInstruction* compare;
if (handle_smi && map.is_identical_to(number_marker_map)) {
- compare = new(zone()) HCompareMap(
- receiver, heap_number_map, if_true, if_false);
+ compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false);
map = initial_number_map;
expr->set_number_check(
Handle<JSObject>(JSObject::cast(map->prototype())));
} else if (map.is_identical_to(string_marker_map)) {
- compare = new(zone()) HIsStringAndBranch(receiver);
- compare->SetSuccessorAt(0, if_true);
- compare->SetSuccessorAt(1, if_false);
+ compare = New<HIsStringAndBranch>(receiver, if_true, if_false);
map = initial_string_map;
expr->set_string_check(
Handle<JSObject>(JSObject::cast(map->prototype())));
} else {
- compare = new(zone()) HCompareMap(receiver, map, if_true, if_false);
+ compare = New<HCompareMap>(receiver, map, if_true, if_false);
expr->set_map_check();
}
- current_block()->Finish(compare);
+ FinishCurrentBlock(compare);
if (expr->check_type() == NUMBER_CHECK) {
- if_true->Goto(number_block);
+ Goto(if_true, number_block);
if_true = number_block;
number_block->SetJoinId(expr->id());
}
@@ -6180,14 +6901,13 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
if (HasStackOverflow()) return;
} else {
HCallConstantFunction* call =
- new(zone()) HCallConstantFunction(expr->target(), argument_count);
- call->set_position(expr->position());
+ New<HCallConstantFunction>(expr->target(), argument_count);
PreProcessCall(call);
AddInstruction(call);
if (!ast_context()->IsEffect()) Push(call);
}
- if (current_block() != NULL) current_block()->Goto(join);
+ if (current_block() != NULL) Goto(join);
set_current_block(if_false);
}
@@ -6198,18 +6918,17 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
// Because the deopt may be the only path in the polymorphic call, make sure
// that the environment stack matches the depth on deopt that it otherwise
// would have had after a successful call.
- Drop(argument_count - (ast_context()->IsEffect() ? 0 : 1));
+ Drop(argument_count);
+ if (!ast_context()->IsEffect()) Push(graph()->GetConstant0());
FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join);
} else {
- HValue* context = environment()->context();
- HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count);
- call->set_position(expr->position());
+ HCallNamed* call = New<HCallNamed>(name, argument_count);
PreProcessCall(call);
if (join != NULL) {
AddInstruction(call);
if (!ast_context()->IsEffect()) Push(call);
- current_block()->Goto(join);
+ Goto(join);
} else {
return ast_context()->ReturnInstruction(call, expr->id());
}
@@ -6258,6 +6977,11 @@ int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
Handle<JSFunction> caller = current_info()->closure();
Handle<SharedFunctionInfo> target_shared(target->shared());
+ // Always inline builtins marked for inlining.
+ if (target->IsBuiltin()) {
+ return target_shared->inline_builtin() ? 0 : kNotInlinable;
+ }
+
// Do a quick check on source code length to avoid parsing large
// inlining candidates.
if (target_shared->SourceSize() >
@@ -6267,7 +6991,7 @@ int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
}
// Target must be inlineable.
- if (!target->IsInlineable()) {
+ if (!target_shared->IsInlineable()) {
TraceInline(target, caller, "target not inlineable");
return kNotInlinable;
}
@@ -6298,18 +7022,6 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
return false;
}
-#if !V8_TARGET_ARCH_IA32
- // Target must be able to use caller's context.
- CompilationInfo* outer_info = current_info();
- if (target->context() != outer_info->closure()->context() ||
- outer_info->scope()->contains_with() ||
- outer_info->scope()->num_heap_slots() > 0) {
- TraceInline(target, caller, "target requires context change");
- return false;
- }
-#endif
-
-
// Don't inline deeper than the maximum number of inlining levels.
HEnvironment* env = environment();
int current_level = 1;
@@ -6447,15 +7159,9 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
undefined,
function_state()->inlining_kind(),
undefined_receiver);
-#if V8_TARGET_ARCH_IA32
- // IA32 only, overwrite the caller's context in the deoptimization
- // environment with the correct one.
- //
- // TODO(kmillikin): implement the same inlining on other platforms so we
- // can remove the unsightly ifdefs in this function.
+
HConstant* context = Add<HConstant>(Handle<Context>(target->context()));
inner_env->BindContext(context);
-#endif
Add<HSimulate>(return_id);
current_block()->UpdateEnvironment(inner_env);
@@ -6511,12 +7217,12 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
// return value will always evaluate to true, in a value context the
// return value is the newly allocated receiver.
if (call_context()->IsTest()) {
- current_block()->Goto(inlined_test_context()->if_true(), state);
+ Goto(inlined_test_context()->if_true(), state);
} else if (call_context()->IsEffect()) {
- current_block()->Goto(function_return(), state);
+ Goto(function_return(), state);
} else {
ASSERT(call_context()->IsValue());
- current_block()->AddLeaveInlined(implicit_return_value, state);
+ AddLeaveInlined(implicit_return_value, state);
}
} else if (state->inlining_kind() == SETTER_CALL_RETURN) {
// Falling off the end of an inlined setter call. The returned value is
@@ -6525,21 +7231,21 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
if (call_context()->IsTest()) {
inlined_test_context()->ReturnValue(implicit_return_value);
} else if (call_context()->IsEffect()) {
- current_block()->Goto(function_return(), state);
+ Goto(function_return(), state);
} else {
ASSERT(call_context()->IsValue());
- current_block()->AddLeaveInlined(implicit_return_value, state);
+ AddLeaveInlined(implicit_return_value, state);
}
} else {
// Falling off the end of a normal inlined function. This basically means
// returning undefined.
if (call_context()->IsTest()) {
- current_block()->Goto(inlined_test_context()->if_false(), state);
+ Goto(inlined_test_context()->if_false(), state);
} else if (call_context()->IsEffect()) {
- current_block()->Goto(function_return(), state);
+ Goto(function_return(), state);
} else {
ASSERT(call_context()->IsValue());
- current_block()->AddLeaveInlined(undefined, state);
+ AddLeaveInlined(undefined, state);
}
}
}
@@ -6561,13 +7267,13 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
entry->RegisterReturnTarget(if_true, zone());
if_true->SetJoinId(ast_id);
HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
- if_true->Goto(true_target, function_state());
+ Goto(if_true, true_target, function_state());
}
if (if_false->HasPredecessor()) {
entry->RegisterReturnTarget(if_false, zone());
if_false->SetJoinId(ast_id);
HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
- if_false->Goto(false_target, function_state());
+ Goto(if_false, false_target, function_state());
}
set_current_block(NULL);
return true;
@@ -6665,16 +7371,10 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr,
case kMathAbs:
case kMathSqrt:
case kMathLog:
- case kMathSin:
- case kMathCos:
- case kMathTan:
if (expr->arguments()->length() == 1) {
HValue* argument = Pop();
- HValue* context = environment()->context();
Drop(1); // Receiver.
- HInstruction* op =
- HUnaryMathOperation::New(zone(), context, argument, id);
- op->set_position(expr->position());
+ HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
if (drop_extra) Drop(1); // Optionally drop the function.
ast_context()->ReturnInstruction(op, expr->id());
return true;
@@ -6685,8 +7385,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr,
HValue* right = Pop();
HValue* left = Pop();
Drop(1); // Receiver.
- HValue* context = environment()->context();
- HInstruction* op = HMul::NewImul(zone(), context, left, right);
+ HInstruction* op = HMul::NewImul(zone(), context(), left, right);
if (drop_extra) Drop(1); // Optionally drop the function.
ast_context()->ReturnInstruction(op, expr->id());
return true;
@@ -6716,7 +7415,6 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
if (argument_count == 2 && check_type == STRING_CHECK) {
HValue* index = Pop();
HValue* string = Pop();
- HValue* context = environment()->context();
ASSERT(!expr->holder().is_null());
BuildCheckPrototypeMaps(Call::GetPrototypeForPrimitiveCheck(
STRING_CHECK, expr->holder()->GetIsolate()),
@@ -6728,8 +7426,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
return true;
}
AddInstruction(char_code);
- HInstruction* result =
- HStringCharFromCode::New(zone(), context, char_code);
+ HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
ast_context()->ReturnInstruction(result, expr->id());
return true;
}
@@ -6738,10 +7435,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
HValue* argument = Pop();
- HValue* context = environment()->context();
Drop(1); // Receiver.
- HInstruction* result =
- HStringCharFromCode::New(zone(), context, argument);
+ HInstruction* result = NewUncasted<HStringCharFromCode>(argument);
ast_context()->ReturnInstruction(result, expr->id());
return true;
}
@@ -6754,17 +7449,11 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
case kMathAbs:
case kMathSqrt:
case kMathLog:
- case kMathSin:
- case kMathCos:
- case kMathTan:
if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) {
AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
HValue* argument = Pop();
- HValue* context = environment()->context();
Drop(1); // Receiver.
- HInstruction* op =
- HUnaryMathOperation::New(zone(), context, argument, id);
- op->set_position(expr->position());
+ HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id);
ast_context()->ReturnInstruction(op, expr->id());
return true;
}
@@ -6775,45 +7464,32 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
HValue* right = Pop();
HValue* left = Pop();
Pop(); // Pop receiver.
- HValue* context = environment()->context();
HInstruction* result = NULL;
// Use sqrt() if exponent is 0.5 or -0.5.
if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) {
double exponent = HConstant::cast(right)->DoubleValue();
if (exponent == 0.5) {
- result =
- HUnaryMathOperation::New(zone(), context, left, kMathPowHalf);
+ result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf);
} else if (exponent == -0.5) {
HValue* one = graph()->GetConstant1();
- HInstruction* sqrt =
- HUnaryMathOperation::New(zone(), context, left, kMathPowHalf);
- AddInstruction(sqrt);
+ HInstruction* sqrt = AddUncasted<HUnaryMathOperation>(
+ left, kMathPowHalf);
// MathPowHalf doesn't have side effects so there's no need for
// an environment simulation here.
ASSERT(!sqrt->HasObservableSideEffects());
- result = HDiv::New(zone(), context, one, sqrt);
+ result = NewUncasted<HDiv>(one, sqrt);
} else if (exponent == 2.0) {
- result = HMul::New(zone(), context, left, left);
+ result = NewUncasted<HMul>(left, left);
}
}
if (result == NULL) {
- result = HPower::New(zone(), context, left, right);
+ result = NewUncasted<HPower>(left, right);
}
ast_context()->ReturnInstruction(result, expr->id());
return true;
}
break;
- case kMathRandom:
- if (argument_count == 1 && check_type == RECEIVER_MAP_CHECK) {
- AddCheckConstantFunction(expr->holder(), receiver, receiver_map);
- Drop(1); // Receiver.
- HGlobalObject* global_object = Add<HGlobalObject>();
- HRandom* result = new(zone()) HRandom(global_object);
- ast_context()->ReturnInstruction(result, expr->id());
- return true;
- }
- break;
case kMathMax:
case kMathMin:
if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) {
@@ -6821,11 +7497,9 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
HValue* right = Pop();
HValue* left = Pop();
Drop(1); // Receiver.
- HValue* context = environment()->context();
HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin
: HMathMinMax::kMathMax;
- HInstruction* result =
- HMathMinMax::New(zone(), context, left, right, op);
+ HInstruction* result = NewUncasted<HMathMinMax>(left, right, op);
ast_context()->ReturnInstruction(result, expr->id());
return true;
}
@@ -6836,8 +7510,7 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
HValue* right = Pop();
HValue* left = Pop();
Drop(1); // Receiver.
- HValue* context = environment()->context();
- HInstruction* result = HMul::NewImul(zone(), context, left, right);
+ HInstruction* result = HMul::NewImul(zone(), context(), left, right);
ast_context()->ReturnInstruction(result, expr->id());
return true;
}
@@ -6878,6 +7551,7 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
// Found pattern f.apply(receiver, arguments).
CHECK_ALIVE_OR_RETURN(VisitForValue(prop->obj()), true);
HValue* function = Top();
+
AddCheckConstantFunction(expr->holder(), function, function_map);
Drop(1);
@@ -6888,12 +7562,10 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
HInstruction* elements = Add<HArgumentsElements>(false);
HInstruction* length = Add<HArgumentsLength>(elements);
HValue* wrapped_receiver = BuildWrapReceiver(receiver, function);
- HInstruction* result =
- new(zone()) HApplyArguments(function,
- wrapped_receiver,
- length,
- elements);
- result->set_position(expr->position());
+ HInstruction* result = New<HApplyArguments>(function,
+ wrapped_receiver,
+ length,
+ elements);
ast_context()->ReturnInstruction(result, expr->id());
return true;
} else {
@@ -6910,28 +7582,24 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
}
Handle<JSFunction> known_function;
- if (function->IsConstant()) {
- HConstant* constant_function = HConstant::cast(function);
+ if (function->IsConstant() &&
+ HConstant::cast(function)->handle(isolate())->IsJSFunction()) {
known_function = Handle<JSFunction>::cast(
- constant_function->handle(isolate()));
+ HConstant::cast(function)->handle(isolate()));
int args_count = arguments_count - 1; // Excluding receiver.
if (TryInlineApply(known_function, expr, args_count)) return true;
}
Drop(arguments_count - 1);
- PushAndAdd(New<HPushArgument>(Pop()));
+ Push(Add<HPushArgument>(Pop()));
for (int i = 1; i < arguments_count; i++) {
- PushAndAdd(New<HPushArgument>(arguments_values->at(i)));
+ Push(Add<HPushArgument>(arguments_values->at(i)));
}
- HValue* context = environment()->context();
- HInvokeFunction* call = new(zone()) HInvokeFunction(
- context,
- function,
- known_function,
- arguments_count);
+ HInvokeFunction* call = New<HInvokeFunction>(function,
+ known_function,
+ arguments_count);
Drop(arguments_count);
- call->set_position(expr->position());
ast_context()->ReturnInstruction(call, expr->id());
return true;
}
@@ -6950,20 +7618,30 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
if (prop != NULL) {
if (!prop->key()->IsPropertyName()) {
// Keyed function call.
- CHECK_ALIVE(VisitArgument(prop->obj()));
-
+ CHECK_ALIVE(VisitForValue(prop->obj()));
CHECK_ALIVE(VisitForValue(prop->key()));
+
// Push receiver and key like the non-optimized code generator expects it.
HValue* key = Pop();
HValue* receiver = Pop();
Push(key);
- Push(receiver);
-
+ Push(Add<HPushArgument>(receiver));
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
- HValue* context = environment()->context();
- call = new(zone()) HCallKeyed(context, key, argument_count);
- call->set_position(expr->position());
+ if (expr->IsMonomorphic()) {
+ BuildCheckHeapObject(receiver);
+ ElementsKind kind = expr->KeyedArrayCallIsHoley()
+ ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS;
+
+ Handle<Map> map(isolate()->get_initial_js_array_map(kind));
+
+ HValue* function = BuildMonomorphicElementAccess(
+ receiver, key, NULL, NULL, map, false, STANDARD_STORE);
+
+ call = New<HCallFunction>(function, argument_count);
+ } else {
+ call = New<HCallKeyed>(key, argument_count);
+ }
Drop(argument_count + 1); // 1 is the key.
return ast_context()->ReturnInstruction(call, expr->id());
}
@@ -7001,16 +7679,13 @@ void HOptimizedGraphBuilder::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.
- HValue* context = environment()->context();
- call = PreProcessCall(
- new(zone()) HCallNamed(context, name, argument_count));
+ call = PreProcessCall(New<HCallNamed>(name, argument_count));
} else {
AddCheckConstantFunction(expr->holder(), receiver, map);
if (TryInlineCall(expr)) return;
call = PreProcessCall(
- new(zone()) HCallConstantFunction(expr->target(),
- argument_count));
+ New<HCallConstantFunction>(expr->target(), argument_count));
}
} else if (types != NULL && types->length() > 1) {
ASSERT(expr->check_type() == RECEIVER_MAP_CHECK);
@@ -7018,11 +7693,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
return;
} else {
- HValue* context = environment()->context();
- call = PreProcessCall(
- new(zone()) HCallNamed(context, name, argument_count));
+ call = PreProcessCall(New<HCallNamed>(name, argument_count));
}
-
} else {
VariableProxy* proxy = expr->expression()->AsVariableProxy();
if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
@@ -7046,9 +7718,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
if (known_global_function) {
// Push the global object instead of the global receiver because
// code generated by the full code generator expects it.
- HValue* context = environment()->context();
- HGlobalObject* global_object = new(zone()) HGlobalObject(context);
- PushAndAdd(global_object);
+ HGlobalObject* global_object = Add<HGlobalObject>();
+ Push(global_object);
CHECK_ALIVE(VisitExpressions(expr->arguments()));
CHECK_ALIVE(VisitForValue(expr->expression()));
@@ -7080,16 +7751,14 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
if (CallStubCompiler::HasCustomCallGenerator(expr->target())) {
// When the target has a custom call IC generator, use the IC,
// because it is likely to generate better code.
- HValue* context = environment()->context();
- call = PreProcessCall(
- new(zone()) HCallNamed(context, var->name(), argument_count));
+ call = PreProcessCall(New<HCallNamed>(var->name(), argument_count));
} else {
- call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(),
- argument_count));
+ call = PreProcessCall(New<HCallKnownGlobal>(
+ expr->target(), argument_count));
}
} else {
HGlobalObject* receiver = Add<HGlobalObject>();
- PushAndAdd(New<HPushArgument>(receiver));
+ Push(Add<HPushArgument>(receiver));
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
call = New<HCallGlobal>(var->name(), argument_count);
@@ -7102,8 +7771,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
CHECK_ALIVE(VisitForValue(expr->expression()));
HValue* function = Top();
HGlobalObject* global = Add<HGlobalObject>();
- HGlobalReceiver* receiver = New<HGlobalReceiver>(global);
- PushAndAdd(receiver);
+ HGlobalReceiver* receiver = Add<HGlobalReceiver>(global);
+ Push(receiver);
CHECK_ALIVE(VisitExpressions(expr->arguments()));
Add<HCheckValue>(function, expr->target());
@@ -7129,7 +7798,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
HValue* function = Top();
HGlobalObject* global_object = Add<HGlobalObject>();
HGlobalReceiver* receiver = Add<HGlobalReceiver>(global_object);
- PushAndAdd(New<HPushArgument>(receiver));
+ Push(Add<HPushArgument>(receiver));
CHECK_ALIVE(VisitArgumentList(expr->arguments()));
call = New<HCallFunction>(function, argument_count);
@@ -7137,11 +7806,75 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
}
}
- call->set_position(expr->position());
return ast_context()->ReturnInstruction(call, expr->id());
}
+void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) {
+ NoObservableSideEffectsScope no_effects(this);
+
+ int argument_count = expr->arguments()->length();
+ // We should at least have the constructor on the expression stack.
+ HValue* constructor = environment()->ExpressionStackAt(argument_count);
+
+ ElementsKind kind = expr->elements_kind();
+ Handle<Cell> cell = expr->allocation_info_cell();
+ AllocationSite* site = AllocationSite::cast(cell->value());
+
+ // Register on the site for deoptimization if the cell value changes.
+ site->AddDependentCompilationInfo(AllocationSite::TRANSITIONS, top_info());
+ HInstruction* cell_instruction = Add<HConstant>(cell);
+
+ // In the single constant argument case, we may have to adjust elements kind
+ // to avoid creating a packed non-empty array.
+ if (argument_count == 1 && !IsHoleyElementsKind(kind)) {
+ HValue* argument = environment()->Top();
+ if (argument->IsConstant()) {
+ HConstant* constant_argument = HConstant::cast(argument);
+ ASSERT(constant_argument->HasSmiValue());
+ int constant_array_size = constant_argument->Integer32Value();
+ if (constant_array_size != 0) {
+ kind = GetHoleyElementsKind(kind);
+ }
+ }
+ }
+
+ // Build the array.
+ JSArrayBuilder array_builder(this,
+ kind,
+ cell_instruction,
+ constructor,
+ DISABLE_ALLOCATION_SITES);
+ HValue* new_object;
+ if (argument_count == 0) {
+ new_object = array_builder.AllocateEmptyArray();
+ } else if (argument_count == 1) {
+ HValue* argument = environment()->Top();
+ new_object = BuildAllocateArrayFromLength(&array_builder, argument);
+ } else {
+ HValue* length = Add<HConstant>(argument_count);
+ // Smi arrays need to initialize array elements with the hole because
+ // bailout could occur if the arguments don't fit in a smi.
+ //
+ // TODO(mvstanton): If all the arguments are constants in smi range, then
+ // we could set fill_with_hole to false and save a few instructions.
+ JSArrayBuilder::FillMode fill_mode = IsFastSmiElementsKind(kind)
+ ? JSArrayBuilder::FILL_WITH_HOLE
+ : JSArrayBuilder::DONT_FILL_WITH_HOLE;
+ new_object = array_builder.AllocateArray(length, length, fill_mode);
+ HValue* elements = array_builder.GetElementsLocation();
+ for (int i = 0; i < argument_count; i++) {
+ HValue* value = environment()->ExpressionStackAt(argument_count - i - 1);
+ HValue* constant_i = Add<HConstant>(i);
+ Add<HStoreKeyed>(elements, constant_i, value, kind);
+ }
+ }
+
+ Drop(argument_count + 1); // drop constructor and args.
+ ast_context()->ReturnValue(new_object);
+}
+
+
// Checks whether allocation using the given constructor can be inlined.
static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
return constructor->has_initial_map() &&
@@ -7151,22 +7884,67 @@ static bool IsAllocationInlineable(Handle<JSFunction> constructor) {
}
+bool HOptimizedGraphBuilder::IsCallNewArrayInlineable(CallNew* expr) {
+ bool inline_ok = false;
+ Handle<JSFunction> caller = current_info()->closure();
+ Handle<JSFunction> target(isolate()->global_context()->array_function(),
+ isolate());
+ int argument_count = expr->arguments()->length();
+ // We should have the function plus array arguments on the environment stack.
+ ASSERT(environment()->length() >= (argument_count + 1));
+ Handle<Cell> cell = expr->allocation_info_cell();
+ AllocationSite* site = AllocationSite::cast(cell->value());
+ if (site->CanInlineCall()) {
+ // We also want to avoid inlining in certain 1 argument scenarios.
+ if (argument_count == 1) {
+ HValue* argument = Top();
+ if (argument->IsConstant()) {
+ // Do not inline if the constant length argument is not a smi or
+ // outside the valid range for a fast array.
+ HConstant* constant_argument = HConstant::cast(argument);
+ if (constant_argument->HasSmiValue()) {
+ int value = constant_argument->Integer32Value();
+ inline_ok = value >= 0 &&
+ value < JSObject::kInitialMaxFastElementArray;
+ if (!inline_ok) {
+ TraceInline(target, caller,
+ "Length outside of valid array range");
+ }
+ }
+ } else {
+ inline_ok = true;
+ }
+ } else {
+ inline_ok = true;
+ }
+ } else {
+ TraceInline(target, caller, "AllocationSite requested no inlining.");
+ }
+
+ if (inline_ok) {
+ TraceInline(target, caller, NULL);
+ }
+ return inline_ok;
+}
+
+
void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
+ if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
int argument_count = expr->arguments()->length() + 1; // Plus constructor.
- HValue* context = environment()->context();
Factory* factory = isolate()->factory();
+ // The constructor function is on the stack in the unoptimized code
+ // during evaluation of the arguments.
+ CHECK_ALIVE(VisitForValue(expr->expression()));
+ HValue* function = Top();
+ CHECK_ALIVE(VisitExpressions(expr->arguments()));
+
if (FLAG_inline_construct &&
expr->IsMonomorphic() &&
IsAllocationInlineable(expr->target())) {
- // The constructor function is on the stack in the unoptimized code
- // during evaluation of the arguments.
- CHECK_ALIVE(VisitForValue(expr->expression()));
- HValue* function = Top();
- CHECK_ALIVE(VisitExpressions(expr->arguments()));
Handle<JSFunction> constructor = expr->target();
HValue* check = Add<HCheckValue>(function, constructor);
@@ -7245,29 +8023,32 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
receiver->DeleteAndReplaceWith(NULL);
check->DeleteAndReplaceWith(NULL);
environment()->SetExpressionStackAt(receiver_index, function);
- HInstruction* call = PreProcessCall(
- new(zone()) HCallNew(context, function, argument_count));
- call->set_position(expr->position());
+ HInstruction* call =
+ PreProcessCall(New<HCallNew>(function, argument_count));
return ast_context()->ReturnInstruction(call, expr->id());
} else {
// The constructor function is both an operand to the instruction and an
// argument to the construct call.
Handle<JSFunction> array_function(
isolate()->global_context()->array_function(), isolate());
- CHECK_ALIVE(VisitArgument(expr->expression()));
- HValue* constructor = HPushArgument::cast(Top())->argument();
- CHECK_ALIVE(VisitArgumentList(expr->arguments()));
+ bool use_call_new_array = expr->target().is_identical_to(array_function);
+ Handle<Cell> cell = expr->allocation_info_cell();
+ if (use_call_new_array && IsCallNewArrayInlineable(expr)) {
+ // Verify we are still calling the array function for our native context.
+ Add<HCheckValue>(function, array_function);
+ BuildInlinedCallNewArray(expr);
+ return;
+ }
+
HBinaryCall* call;
- if (expr->target().is_identical_to(array_function)) {
- Handle<Cell> cell = expr->allocation_info_cell();
- Add<HCheckValue>(constructor, array_function);
- call = new(zone()) HCallNewArray(context, constructor, argument_count,
- cell, expr->elements_kind());
+ if (use_call_new_array) {
+ Add<HCheckValue>(function, array_function);
+ call = New<HCallNewArray>(function, argument_count, cell,
+ expr->elements_kind());
} else {
- call = new(zone()) HCallNew(context, constructor, argument_count);
+ call = New<HCallNew>(function, argument_count);
}
- Drop(argument_count);
- call->set_position(expr->position());
+ PreProcessCall(call);
return ast_context()->ReturnInstruction(call, expr->id());
}
}
@@ -7289,6 +8070,184 @@ const HOptimizedGraphBuilder::InlineFunctionGenerator
#undef INLINE_FUNCTION_GENERATOR_ADDRESS
+template <class ViewClass>
+void HGraphBuilder::BuildArrayBufferViewInitialization(
+ HValue* obj,
+ HValue* buffer,
+ HValue* byte_offset,
+ HValue* byte_length) {
+
+ for (int offset = ViewClass::kSize;
+ offset < ViewClass::kSizeWithInternalFields;
+ offset += kPointerSize) {
+ Add<HStoreNamedField>(obj,
+ HObjectAccess::ForJSObjectOffset(offset),
+ Add<HConstant>(static_cast<int32_t>(0)));
+ }
+
+ Add<HStoreNamedField>(
+ obj,
+ HObjectAccess::ForJSArrayBufferViewBuffer(), buffer);
+ Add<HStoreNamedField>(
+ obj,
+ HObjectAccess::ForJSArrayBufferViewByteOffset(),
+ byte_offset);
+ Add<HStoreNamedField>(
+ obj,
+ HObjectAccess::ForJSArrayBufferViewByteLength(),
+ byte_length);
+
+ HObjectAccess weak_first_view_access =
+ HObjectAccess::ForJSArrayBufferWeakFirstView();
+ Add<HStoreNamedField>(obj,
+ HObjectAccess::ForJSArrayBufferViewWeakNext(),
+ Add<HLoadNamedField>(buffer, weak_first_view_access));
+ Add<HStoreNamedField>(buffer, weak_first_view_access, obj);
+}
+
+
+void HOptimizedGraphBuilder::VisitDataViewInitialize(
+ CallRuntime* expr) {
+ ZoneList<Expression*>* arguments = expr->arguments();
+
+ NoObservableSideEffectsScope scope(this);
+ ASSERT(arguments->length()== 4);
+ CHECK_ALIVE(VisitForValue(arguments->at(0)));
+ HValue* obj = Pop();
+
+ CHECK_ALIVE(VisitForValue(arguments->at(1)));
+ HValue* buffer = Pop();
+
+ CHECK_ALIVE(VisitForValue(arguments->at(2)));
+ HValue* byte_offset = Pop();
+
+ CHECK_ALIVE(VisitForValue(arguments->at(3)));
+ HValue* byte_length = Pop();
+
+ BuildArrayBufferViewInitialization<JSDataView>(
+ obj, buffer, byte_offset, byte_length);
+}
+
+
+void HOptimizedGraphBuilder::VisitTypedArrayInitialize(
+ CallRuntime* expr) {
+ ZoneList<Expression*>* arguments = expr->arguments();
+
+ NoObservableSideEffectsScope scope(this);
+ static const int kObjectArg = 0;
+ static const int kArrayIdArg = 1;
+ static const int kBufferArg = 2;
+ static const int kByteOffsetArg = 3;
+ static const int kByteLengthArg = 4;
+ static const int kArgsLength = 5;
+ ASSERT(arguments->length() == kArgsLength);
+
+
+ CHECK_ALIVE(VisitForValue(arguments->at(kObjectArg)));
+ HValue* obj = Pop();
+
+ ASSERT(arguments->at(kArrayIdArg)->node_type() == AstNode::kLiteral);
+ Handle<Object> value =
+ static_cast<Literal*>(arguments->at(kArrayIdArg))->value();
+ ASSERT(value->IsSmi());
+ int array_id = Smi::cast(*value)->value();
+
+ CHECK_ALIVE(VisitForValue(arguments->at(kBufferArg)));
+ HValue* buffer = Pop();
+
+ HValue* byte_offset;
+ bool is_zero_byte_offset;
+
+ if (arguments->at(kByteOffsetArg)->node_type() == AstNode::kLiteral
+ && Smi::FromInt(0) ==
+ *static_cast<Literal*>(arguments->at(kByteOffsetArg))->value()) {
+ byte_offset = Add<HConstant>(static_cast<int32_t>(0));
+ is_zero_byte_offset = true;
+ } else {
+ CHECK_ALIVE(VisitForValue(arguments->at(kByteOffsetArg)));
+ byte_offset = Pop();
+ is_zero_byte_offset = false;
+ }
+
+ CHECK_ALIVE(VisitForValue(arguments->at(kByteLengthArg)));
+ HValue* byte_length = Pop();
+
+ IfBuilder byte_offset_smi(this);
+
+ if (!is_zero_byte_offset) {
+ byte_offset_smi.If<HIsSmiAndBranch>(byte_offset);
+ byte_offset_smi.Then();
+ }
+
+ { // byte_offset is Smi.
+ BuildArrayBufferViewInitialization<JSTypedArray>(
+ obj, buffer, byte_offset, byte_length);
+
+ ExternalArrayType array_type = kExternalByteArray; // Bogus initialization.
+ size_t element_size = 1; // Bogus initialization.
+ Runtime::ArrayIdToTypeAndSize(array_id, &array_type, &element_size);
+
+ HInstruction* length = AddUncasted<HDiv>(byte_length,
+ Add<HConstant>(static_cast<int32_t>(element_size)));
+
+ Add<HStoreNamedField>(obj,
+ HObjectAccess::ForJSTypedArrayLength(),
+ length);
+
+ HValue* elements =
+ Add<HAllocate>(
+ Add<HConstant>(ExternalArray::kAlignedSize),
+ HType::JSArray(),
+ NOT_TENURED,
+ static_cast<InstanceType>(FIRST_EXTERNAL_ARRAY_TYPE + array_type));
+
+ Handle<Map> external_array_map(
+ isolate()->heap()->MapForExternalArrayType(array_type));
+ Add<HStoreNamedField>(elements,
+ HObjectAccess::ForMap(),
+ Add<HConstant>(external_array_map));
+
+ HValue* backing_store = Add<HLoadNamedField>(
+ buffer, HObjectAccess::ForJSArrayBufferBackingStore());
+
+ HValue* typed_array_start;
+ if (is_zero_byte_offset) {
+ typed_array_start = backing_store;
+ } else {
+ HInstruction* external_pointer =
+ AddUncasted<HAdd>(backing_store, byte_offset);
+ // Arguments are checked prior to call to TypedArrayInitialize,
+ // including byte_offset.
+ external_pointer->ClearFlag(HValue::kCanOverflow);
+ typed_array_start = external_pointer;
+ }
+
+ Add<HStoreNamedField>(elements,
+ HObjectAccess::ForExternalArrayExternalPointer(),
+ typed_array_start);
+ Add<HStoreNamedField>(elements,
+ HObjectAccess::ForFixedArrayLength(),
+ length);
+ Add<HStoreNamedField>(
+ obj, HObjectAccess::ForElementsPointer(), elements);
+ }
+
+ if (!is_zero_byte_offset) {
+ byte_offset_smi.Else();
+ { // byte_offset is not Smi.
+ Push(Add<HPushArgument>(obj));
+ VisitArgument(arguments->at(kArrayIdArg));
+ Push(Add<HPushArgument>(buffer));
+ Push(Add<HPushArgument>(byte_offset));
+ Push(Add<HPushArgument>(byte_length));
+ Add<HCallRuntime>(expr->name(), expr->function(), kArgsLength);
+ Drop(kArgsLength);
+ }
+ }
+ byte_offset_smi.End();
+}
+
+
void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
@@ -7299,6 +8258,21 @@ void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
const Runtime::Function* function = expr->function();
ASSERT(function != NULL);
+
+ if (function->function_id == Runtime::kDataViewInitialize) {
+ return VisitDataViewInitialize(expr);
+ }
+
+ if (function->function_id == Runtime::kTypedArrayInitialize) {
+ return VisitTypedArrayInitialize(expr);
+ }
+
+ if (function->function_id == Runtime::kMaxSmi) {
+ ASSERT(expr->arguments()->length() == 0);
+ HConstant* max_smi = New<HConstant>(static_cast<int32_t>(Smi::kMaxValue));
+ return ast_context()->ReturnInstruction(max_smi, expr->id());
+ }
+
if (function->intrinsic_type == Runtime::INLINE) {
ASSERT(expr->name()->length() > 0);
ASSERT(expr->name()->Get(0) == '_');
@@ -7389,8 +8363,7 @@ void HOptimizedGraphBuilder::VisitVoid(UnaryOperation* expr) {
void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) {
CHECK_ALIVE(VisitForTypeOf(expr->expression()));
HValue* value = Pop();
- HValue* context = environment()->context();
- HInstruction* instr = new(zone()) HTypeof(context, value);
+ HInstruction* instr = New<HTypeof>(value);
return ast_context()->ReturnInstruction(instr, expr->id());
}
@@ -7443,7 +8416,7 @@ HInstruction* HOptimizedGraphBuilder::BuildIncrement(
bool returns_original_input,
CountOperation* expr) {
// The input to the count operation is on top of the expression stack.
- TypeInfo info = expr->type();
+ Handle<Type> info = expr->type();
Representation rep = Representation::FromType(info);
if (rep.IsNone() || rep.IsTagged()) {
rep = Representation::Smi();
@@ -7454,7 +8427,7 @@ HInstruction* HOptimizedGraphBuilder::BuildIncrement(
// actual HChange instruction we need is (sometimes) added in a later
// phase, so it is not available now to be used as an input to HAdd and
// as the return value.
- HInstruction* number_input = Add<HForceRepresentation>(Pop(), rep);
+ HInstruction* number_input = AddUncasted<HForceRepresentation>(Pop(), rep);
if (!rep.IsDouble()) {
number_input->SetFlag(HInstruction::kFlexibleRepresentation);
number_input->SetFlag(HInstruction::kCannotBeTagged);
@@ -7499,6 +8472,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
+ if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
Expression* target = expr->expression();
VariableProxy* proxy = target->AsVariableProxy();
Property* prop = target->AsProperty();
@@ -7531,7 +8505,6 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
case Variable::UNALLOCATED:
HandleGlobalVariableAssignment(var,
after,
- expr->position(),
expr->AssignmentId());
break;
@@ -7583,15 +8556,13 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
HValue* object = Top();
HValue* key = NULL;
- if ((!prop->IsStringLength() &&
- !prop->IsFunctionPrototype() &&
- !prop->key()->IsPropertyName()) ||
+ if ((!prop->IsFunctionPrototype() && !prop->key()->IsPropertyName()) ||
prop->IsStringAccess()) {
CHECK_ALIVE(VisitForValue(prop->key()));
key = Top();
}
- CHECK_ALIVE(PushLoad(prop, object, key, expr->position()));
+ CHECK_ALIVE(PushLoad(prop, object, key));
after = BuildIncrement(returns_original_input, expr);
@@ -7627,7 +8598,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
}
BuildCheckHeapObject(string);
HValue* checkstring =
- AddInstruction(HCheckInstanceType::NewIsString(string, zone()));
+ Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING);
HInstruction* length = BuildLoadStringLength(string, checkstring);
AddInstruction(length);
HInstruction* checked_index = Add<HBoundsCheck>(index, length);
@@ -7635,9 +8606,16 @@ HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt(
}
-// Checks if the given shift amounts have form: (sa) and (32 - sa).
+// Checks if the given shift amounts have following forms:
+// (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa).
static bool ShiftAmountsAllowReplaceByRotate(HValue* sa,
HValue* const32_minus_sa) {
+ if (sa->IsConstant() && const32_minus_sa->IsConstant()) {
+ const HConstant* c1 = HConstant::cast(sa);
+ const HConstant* c2 = HConstant::cast(const32_minus_sa);
+ return c1->HasInteger32Value() && c2->HasInteger32Value() &&
+ (c1->Integer32Value() + c2->Integer32Value() == 32);
+ }
if (!const32_minus_sa->IsSub()) return false;
HSub* sub = HSub::cast(const32_minus_sa);
if (sa != sub->right()) return false;
@@ -7654,10 +8632,10 @@ static bool ShiftAmountsAllowReplaceByRotate(HValue* sa,
// directions that can be replaced by one rotate right instruction or not.
// Returns the operand and the shift amount for the rotate instruction in the
// former case.
-bool HOptimizedGraphBuilder::MatchRotateRight(HValue* left,
- HValue* right,
- HValue** operand,
- HValue** shift_amount) {
+bool HGraphBuilder::MatchRotateRight(HValue* left,
+ HValue* right,
+ HValue** operand,
+ HValue** shift_amount) {
HShl* shl;
HShr* shr;
if (left->IsShl() && right->IsShr()) {
@@ -7693,6 +8671,19 @@ bool CanBeZero(HValue* right) {
}
+HValue* HGraphBuilder::EnforceNumberType(HValue* number,
+ Handle<Type> expected) {
+ if (expected->Is(Type::Smi())) {
+ return AddUncasted<HForceRepresentation>(number, Representation::Smi());
+ }
+ if (expected->Is(Type::Signed32())) {
+ return AddUncasted<HForceRepresentation>(number,
+ Representation::Integer32());
+ }
+ return number;
+}
+
+
HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) {
if (value->IsConstant()) {
HConstant* constant = HConstant::cast(value);
@@ -7703,97 +8694,221 @@ HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) {
}
}
+ // We put temporary values on the stack, which don't correspond to anything
+ // in baseline code. Since nothing is observable we avoid recording those
+ // pushes with a NoObservableSideEffectsScope.
+ NoObservableSideEffectsScope no_effects(this);
+
+ Handle<Type> expected_type = *expected;
+
+ // Separate the number type from the rest.
+ Handle<Type> expected_obj = handle(Type::Intersect(
+ expected_type, handle(Type::NonNumber(), isolate())), isolate());
+ Handle<Type> expected_number = handle(Type::Intersect(
+ expected_type, handle(Type::Number(), isolate())), isolate());
+
+ // We expect to get a number.
+ // (We need to check first, since Type::None->Is(Type::Any()) == true.
+ if (expected_obj->Is(Type::None())) {
+ ASSERT(!expected_number->Is(Type::None()));
+ return value;
+ }
+
+ if (expected_obj->Is(Type::Undefined())) {
+ // This is already done by HChange.
+ *expected = handle(Type::Union(
+ expected_number, handle(Type::Double(), isolate())), isolate());
+ return value;
+ }
+
return value;
}
-HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation(
+HValue* HOptimizedGraphBuilder::BuildBinaryOperation(
BinaryOperation* expr,
HValue* left,
HValue* right) {
- HValue* context = environment()->context();
Handle<Type> left_type = expr->left()->bounds().lower;
Handle<Type> right_type = expr->right()->bounds().lower;
Handle<Type> result_type = expr->bounds().lower;
Maybe<int> fixed_right_arg = expr->fixed_right_arg();
+
+ HValue* result = HGraphBuilder::BuildBinaryOperation(
+ expr->op(), left, right, left_type, right_type,
+ result_type, fixed_right_arg);
+ // Add a simulate after instructions with observable side effects, and
+ // after phis, which are the result of BuildBinaryOperation when we
+ // inlined some complex subgraph.
+ if (result->HasObservableSideEffects() || result->IsPhi()) {
+ Push(result);
+ Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE);
+ Drop(1);
+ }
+ return result;
+}
+
+
+HValue* HGraphBuilder::BuildBinaryOperation(
+ Token::Value op,
+ HValue* left,
+ HValue* right,
+ Handle<Type> left_type,
+ Handle<Type> right_type,
+ Handle<Type> result_type,
+ Maybe<int> fixed_right_arg) {
+
Representation left_rep = Representation::FromType(left_type);
Representation right_rep = Representation::FromType(right_type);
- Representation result_rep = Representation::FromType(result_type);
- if (expr->op() != Token::ADD ||
- (left->type().IsNonString() && right->type().IsNonString())) {
- // For addition we can only truncate the arguments to number if we can
- // prove that we will not end up in string concatenation mode.
- left = TruncateToNumber(left, &left_type);
- right = TruncateToNumber(right, &right_type);
- }
+ bool maybe_string_add = op == Token::ADD &&
+ (left_type->Maybe(Type::String()) ||
+ right_type->Maybe(Type::String()));
if (left_type->Is(Type::None())) {
Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation",
Deoptimizer::SOFT);
- // TODO(rossberg): we should be able to get rid of non-continuous defaults.
+ // TODO(rossberg): we should be able to get rid of non-continuous
+ // defaults.
left_type = handle(Type::Any(), isolate());
+ } else {
+ if (!maybe_string_add) left = TruncateToNumber(left, &left_type);
+ left_rep = Representation::FromType(left_type);
}
+
if (right_type->Is(Type::None())) {
Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation",
Deoptimizer::SOFT);
right_type = handle(Type::Any(), isolate());
+ } else {
+ if (!maybe_string_add) right = TruncateToNumber(right, &right_type);
+ right_rep = Representation::FromType(right_type);
+ }
+
+ // Special case for string addition here.
+ if (op == Token::ADD &&
+ (left_type->Is(Type::String()) || right_type->Is(Type::String()))) {
+ // Validate type feedback for left argument.
+ if (left_type->Is(Type::String())) {
+ left = BuildCheckString(left);
+ }
+
+ // Validate type feedback for right argument.
+ if (right_type->Is(Type::String())) {
+ right = BuildCheckString(right);
+ }
+
+ // Convert left argument as necessary.
+ if (left_type->Is(Type::Number())) {
+ ASSERT(right_type->Is(Type::String()));
+ left = BuildNumberToString(left, left_type);
+ } else if (!left_type->Is(Type::String())) {
+ ASSERT(right_type->Is(Type::String()));
+ HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT);
+ Add<HPushArgument>(left);
+ Add<HPushArgument>(right);
+ return AddUncasted<HInvokeFunction>(function, 2);
+ }
+
+ // Convert right argument as necessary.
+ if (right_type->Is(Type::Number())) {
+ ASSERT(left_type->Is(Type::String()));
+ right = BuildNumberToString(right, right_type);
+ } else if (!right_type->Is(Type::String())) {
+ ASSERT(left_type->Is(Type::String()));
+ HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT);
+ Add<HPushArgument>(left);
+ Add<HPushArgument>(right);
+ return AddUncasted<HInvokeFunction>(function, 2);
+ }
+
+ return AddUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_NONE);
}
+
+ if (graph()->info()->IsStub()) {
+ left = EnforceNumberType(left, left_type);
+ right = EnforceNumberType(right, right_type);
+ }
+
+ Representation result_rep = Representation::FromType(result_type);
+
+ bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) ||
+ (right_rep.IsTagged() && !right_rep.IsSmi());
+
HInstruction* instr = NULL;
- switch (expr->op()) {
- case Token::ADD:
- if (left_type->Is(Type::String()) && right_type->Is(Type::String())) {
- BuildCheckHeapObject(left);
- AddInstruction(HCheckInstanceType::NewIsString(left, zone()));
- BuildCheckHeapObject(right);
- AddInstruction(HCheckInstanceType::NewIsString(right, zone()));
- instr = HStringAdd::New(zone(), context, left, right);
- } else {
- instr = HAdd::New(zone(), context, left, right);
+ // Only the stub is allowed to call into the runtime, since otherwise we would
+ // inline several instructions (including the two pushes) for every tagged
+ // operation in optimized code, which is more expensive, than a stub call.
+ if (graph()->info()->IsStub() && is_non_primitive) {
+ HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op));
+ Add<HPushArgument>(left);
+ Add<HPushArgument>(right);
+ instr = AddUncasted<HInvokeFunction>(function, 2);
+ } else {
+ switch (op) {
+ case Token::ADD:
+ instr = AddUncasted<HAdd>(left, right);
+ break;
+ case Token::SUB:
+ instr = AddUncasted<HSub>(left, right);
+ break;
+ case Token::MUL:
+ instr = AddUncasted<HMul>(left, right);
+ break;
+ case Token::MOD: {
+ if (fixed_right_arg.has_value) {
+ if (right->IsConstant()) {
+ HConstant* c_right = HConstant::cast(right);
+ if (c_right->HasInteger32Value()) {
+ ASSERT_EQ(fixed_right_arg.value, c_right->Integer32Value());
+ }
+ } else {
+ HConstant* fixed_right = Add<HConstant>(
+ static_cast<int>(fixed_right_arg.value));
+ IfBuilder if_same(this);
+ if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ);
+ if_same.Then();
+ if_same.ElseDeopt("Unexpected RHS of binary operation");
+ right = fixed_right;
+ }
+ }
+ instr = AddUncasted<HMod>(left, right);
+ break;
}
- break;
- case Token::SUB:
- instr = HSub::New(zone(), context, left, right);
- break;
- case Token::MUL:
- instr = HMul::New(zone(), context, left, right);
- break;
- case Token::MOD:
- instr = HMod::New(zone(), context, left, right, fixed_right_arg);
- break;
- case Token::DIV:
- instr = HDiv::New(zone(), context, left, right);
- break;
- case Token::BIT_XOR:
- case Token::BIT_AND:
- instr = NewUncasted<HBitwise>(expr->op(), left, right);
- break;
- case Token::BIT_OR: {
- HValue* operand, *shift_amount;
- if (left_type->Is(Type::Signed32()) &&
- right_type->Is(Type::Signed32()) &&
- MatchRotateRight(left, right, &operand, &shift_amount)) {
- instr = new(zone()) HRor(context, operand, shift_amount);
- } else {
- instr = NewUncasted<HBitwise>(expr->op(), left, right);
+ case Token::DIV:
+ instr = AddUncasted<HDiv>(left, right);
+ break;
+ case Token::BIT_XOR:
+ case Token::BIT_AND:
+ instr = AddUncasted<HBitwise>(op, left, right);
+ break;
+ case Token::BIT_OR: {
+ HValue* operand, *shift_amount;
+ if (left_type->Is(Type::Signed32()) &&
+ right_type->Is(Type::Signed32()) &&
+ MatchRotateRight(left, right, &operand, &shift_amount)) {
+ instr = AddUncasted<HRor>(operand, shift_amount);
+ } else {
+ instr = AddUncasted<HBitwise>(op, left, right);
+ }
+ break;
}
- break;
+ case Token::SAR:
+ instr = AddUncasted<HSar>(left, right);
+ break;
+ case Token::SHR:
+ instr = AddUncasted<HShr>(left, right);
+ if (FLAG_opt_safe_uint32_operations && instr->IsShr() &&
+ CanBeZero(right)) {
+ graph()->RecordUint32Instruction(instr);
+ }
+ break;
+ case Token::SHL:
+ instr = AddUncasted<HShl>(left, right);
+ break;
+ default:
+ UNREACHABLE();
}
- case Token::SAR:
- instr = HSar::New(zone(), context, left, right);
- break;
- case Token::SHR:
- instr = HShr::New(zone(), context, left, right);
- if (FLAG_opt_safe_uint32_operations && instr->IsShr() &&
- CanBeZero(right)) {
- graph()->RecordUint32Instruction(instr);
- }
- break;
- case Token::SHL:
- instr = HShl::New(zone(), context, left, right);
- break;
- default:
- UNREACHABLE();
}
if (instr->IsBinaryOperation()) {
@@ -7801,6 +8916,19 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation(
binop->set_observed_input_representation(1, left_rep);
binop->set_observed_input_representation(2, right_rep);
binop->initialize_output_representation(result_rep);
+ if (graph()->info()->IsStub()) {
+ // Stub should not call into stub.
+ instr->SetFlag(HValue::kCannotBeTagged);
+ // And should truncate on HForceRepresentation already.
+ if (left->IsForceRepresentation()) {
+ left->CopyFlag(HValue::kTruncatingToSmi, instr);
+ left->CopyFlag(HValue::kTruncatingToInt32, instr);
+ }
+ if (right->IsForceRepresentation()) {
+ right->CopyFlag(HValue::kTruncatingToSmi, instr);
+ right->CopyFlag(HValue::kTruncatingToInt32, instr);
+ }
+ }
}
return instr;
}
@@ -7875,11 +9003,14 @@ void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
ASSERT(current_block() != NULL);
HValue* left_value = Top();
- if (left_value->IsConstant()) {
- HConstant* left_constant = HConstant::cast(left_value);
- if ((is_logical_and && left_constant->BooleanValue()) ||
- (!is_logical_and && !left_constant->BooleanValue())) {
- Drop(1); // left_value.
+ // Short-circuit left values that always evaluate to the same boolean value.
+ if (expr->left()->ToBooleanIsTrue() || expr->left()->ToBooleanIsFalse()) {
+ // l (evals true) && r -> r
+ // l (evals true) || r -> l
+ // l (evals false) && r -> l
+ // l (evals false) || r -> r
+ if (is_logical_and == expr->left()->ToBooleanIsTrue()) {
+ Drop(1);
CHECK_ALIVE(VisitForValue(expr->right()));
}
return ast_context()->ReturnValue(Pop());
@@ -7890,9 +9021,9 @@ void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
HBasicBlock* eval_right = graph()->CreateBasicBlock();
ToBooleanStub::Types expected(expr->left()->to_boolean_types());
HBranch* test = is_logical_and
- ? new(zone()) HBranch(left_value, expected, eval_right, empty_block)
- : new(zone()) HBranch(left_value, expected, empty_block, eval_right);
- current_block()->Finish(test);
+ ? New<HBranch>(left_value, expected, eval_right, empty_block)
+ : New<HBranch>(left_value, expected, empty_block, eval_right);
+ FinishCurrentBlock(test);
set_current_block(eval_right);
Drop(1); // Value of the left subexpression.
@@ -7949,11 +9080,15 @@ void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
CHECK_ALIVE(VisitForValue(expr->left()));
CHECK_ALIVE(VisitForValue(expr->right()));
+ SetSourcePosition(expr->position());
HValue* right = Pop();
HValue* left = Pop();
- HInstruction* instr = BuildBinaryOperation(expr, left, right);
- instr->set_position(expr->position());
- return ast_context()->ReturnInstruction(instr, expr->id());
+ HValue* result = BuildBinaryOperation(expr, left, right);
+ if (FLAG_emit_opt_code_positions && result->IsBinaryOperation()) {
+ HBinaryOperation::cast(result)->SetOperandPositions(
+ zone(), expr->left()->position(), expr->right()->position());
+ }
+ return ast_context()->ReturnValue(result);
}
@@ -7961,9 +9096,9 @@ void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
Expression* sub_expr,
Handle<String> check) {
CHECK_ALIVE(VisitForTypeOf(sub_expr));
+ SetSourcePosition(expr->position());
HValue* value = Pop();
- HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check);
- instr->set_position(expr->position());
+ HTypeofIsAndBranch* instr = New<HTypeofIsAndBranch>(value, check);
return ast_context()->ReturnControl(instr, expr->id());
}
@@ -7985,6 +9120,8 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
+ if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
+
// Check for a few fast cases. The AST visiting behavior must be in sync
// with the full codegen: We don't push both left and right values onto
// the expression stack when one side is a special-case literal.
@@ -8007,9 +9144,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
HValue* value = Pop();
Literal* literal = expr->right()->AsLiteral();
Handle<String> rhs = Handle<String>::cast(literal->value());
- HClassOfTestAndBranch* instr =
- new(zone()) HClassOfTestAndBranch(value, rhs);
- instr->set_position(expr->position());
+ HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs);
return ast_context()->ReturnControl(instr, expr->id());
}
@@ -8023,7 +9158,8 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
CHECK_ALIVE(VisitForValue(expr->left()));
CHECK_ALIVE(VisitForValue(expr->right()));
- HValue* context = environment()->context();
+ if (FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
+
HValue* right = Pop();
HValue* left = Pop();
Token::Value op = expr->op();
@@ -8031,7 +9167,6 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
if (IsLiteralCompareBool(isolate(), left, op, right)) {
HCompareObjectEqAndBranch* result =
New<HCompareObjectEqAndBranch>(left, right);
- result->set_position(expr->position());
return ast_context()->ReturnControl(result, expr->id());
}
@@ -8062,14 +9197,12 @@ void HOptimizedGraphBuilder::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()) {
- HInstanceOf* result = new(zone()) HInstanceOf(context, left, right);
- result->set_position(expr->position());
+ HInstanceOf* result = New<HInstanceOf>(left, right);
return ast_context()->ReturnInstruction(result, expr->id());
} else {
Add<HCheckValue>(right, target);
HInstanceOfKnownGlobal* result =
- new(zone()) HInstanceOfKnownGlobal(context, left, target);
- result->set_position(expr->position());
+ New<HInstanceOfKnownGlobal>(left, target);
return ast_context()->ReturnInstruction(result, expr->id());
}
@@ -8081,8 +9214,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
Add<HPushArgument>(right);
// TODO(olivf) InvokeFunction produces a check for the parameter count,
// even though we are certain to pass the correct number of arguments here.
- HInstruction* result = new(zone()) HInvokeFunction(context, function, 2);
- result->set_position(expr->position());
+ HInstruction* result = New<HInvokeFunction>(function, 2);
return ast_context()->ReturnInstruction(result, expr->id());
}
@@ -8106,16 +9238,18 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
AddCheckMap(right, map);
HCompareObjectEqAndBranch* result =
New<HCompareObjectEqAndBranch>(left, right);
- result->set_position(expr->position());
+ if (FLAG_emit_opt_code_positions) {
+ result->set_operand_position(zone(), 0, expr->left()->position());
+ result->set_operand_position(zone(), 1, expr->right()->position());
+ }
return ast_context()->ReturnControl(result, expr->id());
} else {
BuildCheckHeapObject(left);
- AddInstruction(HCheckInstanceType::NewIsSpecObject(left, zone()));
+ Add<HCheckInstanceType>(left, HCheckInstanceType::IS_SPEC_OBJECT);
BuildCheckHeapObject(right);
- AddInstruction(HCheckInstanceType::NewIsSpecObject(right, zone()));
+ Add<HCheckInstanceType>(right, HCheckInstanceType::IS_SPEC_OBJECT);
HCompareObjectEqAndBranch* result =
- new(zone()) HCompareObjectEqAndBranch(left, right);
- result->set_position(expr->position());
+ New<HCompareObjectEqAndBranch>(left, right);
return ast_context()->ReturnControl(result, expr->id());
}
}
@@ -8125,26 +9259,35 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
} else if (combined_type->Is(Type::InternalizedString()) &&
Token::IsEqualityOp(op)) {
BuildCheckHeapObject(left);
- AddInstruction(HCheckInstanceType::NewIsInternalizedString(left, zone()));
+ Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING);
BuildCheckHeapObject(right);
- AddInstruction(HCheckInstanceType::NewIsInternalizedString(right, zone()));
+ Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING);
HCompareObjectEqAndBranch* result =
- new(zone()) HCompareObjectEqAndBranch(left, right);
- result->set_position(expr->position());
+ New<HCompareObjectEqAndBranch>(left, right);
+ return ast_context()->ReturnControl(result, expr->id());
+ } else if (combined_type->Is(Type::String())) {
+ BuildCheckHeapObject(left);
+ Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING);
+ BuildCheckHeapObject(right);
+ Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING);
+ HStringCompareAndBranch* result =
+ New<HStringCompareAndBranch>(left, right, op);
return ast_context()->ReturnControl(result, expr->id());
} else {
if (combined_rep.IsTagged() || combined_rep.IsNone()) {
- HCompareGeneric* result =
- new(zone()) HCompareGeneric(context, left, right, op);
+ HCompareGeneric* result = New<HCompareGeneric>(left, right, op);
result->set_observed_input_representation(1, left_rep);
result->set_observed_input_representation(2, right_rep);
- result->set_position(expr->position());
return ast_context()->ReturnInstruction(result, expr->id());
} else {
HCompareNumericAndBranch* result =
- new(zone()) HCompareNumericAndBranch(left, right, op);
+ New<HCompareNumericAndBranch>(left, right, op);
result->set_observed_input_representation(left_rep, right_rep);
- result->set_position(expr->position());
+ if (FLAG_emit_opt_code_positions) {
+ result->SetOperandPositions(zone(),
+ expr->left()->position(),
+ expr->right()->position());
+ }
return ast_context()->ReturnControl(result, expr->id());
}
}
@@ -8158,6 +9301,7 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
ASSERT(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT);
+ if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
CHECK_ALIVE(VisitForValue(sub_expr));
HValue* value = Pop();
if (expr->op() == Token::EQ_STRICT) {
@@ -8166,7 +9310,6 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
: graph()->GetConstantUndefined();
HCompareObjectEqAndBranch* instr =
New<HCompareObjectEqAndBranch>(value, nil_constant);
- instr->set_position(expr->position());
return ast_context()->ReturnControl(instr, expr->id());
} else {
ASSERT_EQ(Token::EQ, expr->op());
@@ -8174,7 +9317,7 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
? handle(Type::Any(), isolate_)
: expr->combined_type();
HIfContinuation continuation;
- BuildCompareNil(value, type, expr->position(), &continuation);
+ BuildCompareNil(value, type, &continuation);
return ast_context()->ReturnContinuation(&continuation, expr->id());
}
}
@@ -8187,49 +9330,40 @@ HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
return New<HConstant>(
function_state()->compilation_info()->closure());
} else {
- return new(zone()) HThisFunction;
+ return New<HThisFunction>();
}
}
HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
Handle<JSObject> boilerplate_object,
- Handle<Object> allocation_site_object,
- AllocationSiteMode mode) {
+ AllocationSiteUsageContext* site_context) {
NoObservableSideEffectsScope no_effects(this);
-
- Handle<FixedArrayBase> elements(boilerplate_object->elements());
- int object_size = boilerplate_object->map()->instance_size();
- int object_offset = object_size;
-
InstanceType instance_type = boilerplate_object->map()->instance_type();
- bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE &&
- AllocationSite::CanTrack(instance_type);
+ ASSERT(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE);
- // If using allocation sites, then the payload on the site should already
- // be filled in as a valid (boilerplate) array.
- ASSERT(!create_allocation_site_info ||
- AllocationSite::cast(*allocation_site_object)->IsLiteralSite());
+ HType type = instance_type == JS_ARRAY_TYPE
+ ? HType::JSArray() : HType::JSObject();
+ HValue* object_size_constant = Add<HConstant>(
+ boilerplate_object->map()->instance_size());
- if (create_allocation_site_info) {
- object_size += AllocationMemento::kSize;
+ // We should pull pre-tenure mode from the allocation site.
+ // For now, just see what it says, and remark on it if it sez
+ // we should pretenure. That means the rudimentary counting in the garbage
+ // collector is having an effect.
+ PretenureFlag pretenure_flag = isolate()->heap()->GetPretenureMode();
+ if (FLAG_allocation_site_pretenuring) {
+ pretenure_flag = site_context->current()->GetPretenureMode()
+ ? TENURED
+ : NOT_TENURED;
}
- ASSERT(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE);
- HType type = instance_type == JS_ARRAY_TYPE
- ? HType::JSArray() : HType::JSObject();
- HValue* object_size_constant = Add<HConstant>(object_size);
HInstruction* object = Add<HAllocate>(object_size_constant, type,
- isolate()->heap()->GetPretenureMode(), instance_type);
-
+ pretenure_flag, instance_type, site_context->current());
BuildEmitObjectHeader(boilerplate_object, object);
- if (create_allocation_site_info) {
- HInstruction* allocation_site = Add<HConstant>(allocation_site_object);
- BuildCreateAllocationMemento(object, object_offset, allocation_site);
- }
-
+ Handle<FixedArrayBase> elements(boilerplate_object->elements());
int elements_size = (elements->length() > 0 &&
elements->map() != isolate()->heap()->fixed_cow_array_map()) ?
elements->Size() : 0;
@@ -8239,23 +9373,24 @@ HInstruction* HOptimizedGraphBuilder::BuildFastLiteral(
HValue* object_elements_size = Add<HConstant>(elements_size);
if (boilerplate_object->HasFastDoubleElements()) {
object_elements = Add<HAllocate>(object_elements_size, HType::JSObject(),
- isolate()->heap()->GetPretenureMode(), FIXED_DOUBLE_ARRAY_TYPE);
+ pretenure_flag, FIXED_DOUBLE_ARRAY_TYPE, site_context->current());
} else {
object_elements = Add<HAllocate>(object_elements_size, HType::JSObject(),
- isolate()->heap()->GetPretenureMode(), FIXED_ARRAY_TYPE);
+ pretenure_flag, FIXED_ARRAY_TYPE, site_context->current());
}
}
BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements);
-
// Copy object elements if non-COW.
if (object_elements != NULL) {
- BuildEmitElements(boilerplate_object, elements, object_elements);
+ BuildEmitElements(boilerplate_object, elements, object_elements,
+ site_context);
}
// Copy in-object properties.
if (boilerplate_object->map()->NumberOfFields() != 0) {
- BuildEmitInObjectProperties(boilerplate_object, object);
+ BuildEmitInObjectProperties(boilerplate_object, object, site_context,
+ pretenure_flag);
}
return object;
}
@@ -8307,7 +9442,9 @@ void HOptimizedGraphBuilder::BuildInitElementsInObjectHeader(
void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
Handle<JSObject> boilerplate_object,
- HInstruction* object) {
+ HInstruction* object,
+ AllocationSiteUsageContext* site_context,
+ PretenureFlag pretenure_flag) {
Handle<DescriptorArray> descriptors(
boilerplate_object->map()->instance_descriptors());
int limit = boilerplate_object->map()->NumberOfOwnDescriptors();
@@ -8331,25 +9468,38 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
if (value->IsJSObject()) {
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
+ Handle<AllocationSite> current_site = site_context->EnterNewScope();
HInstruction* result =
- BuildFastLiteral(value_object,
- Handle<Object>::null(), DONT_TRACK_ALLOCATION_SITE);
+ BuildFastLiteral(value_object, site_context);
+ site_context->ExitScope(current_site, value_object);
Add<HStoreNamedField>(object, access, result);
} else {
Representation representation = details.representation();
- HInstruction* value_instruction = Add<HConstant>(value);
+ HInstruction* value_instruction;
if (representation.IsDouble()) {
// Allocate a HeapNumber box and store the value into it.
HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize);
+ // This heap number alloc does not have a corresponding
+ // AllocationSite. That is okay because
+ // 1) it's a child object of another object with a valid allocation site
+ // 2) we can just use the mode of the parent object for pretenuring
HInstruction* double_box =
Add<HAllocate>(heap_number_constant, HType::HeapNumber(),
- isolate()->heap()->GetPretenureMode(), HEAP_NUMBER_TYPE);
+ pretenure_flag, HEAP_NUMBER_TYPE);
AddStoreMapConstant(double_box,
isolate()->factory()->heap_number_map());
Add<HStoreNamedField>(double_box, HObjectAccess::ForHeapNumberValue(),
- value_instruction);
+ Add<HConstant>(value));
value_instruction = double_box;
+ } else if (representation.IsSmi()) {
+ value_instruction = value->IsUninitialized()
+ ? graph()->GetConstant0()
+ : Add<HConstant>(value);
+ // Ensure that value is stored as smi.
+ access = access.WithRepresentation(representation);
+ } else {
+ value_instruction = Add<HConstant>(value);
}
Add<HStoreNamedField>(object, access, value_instruction);
@@ -8371,7 +9521,8 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties(
void HOptimizedGraphBuilder::BuildEmitElements(
Handle<JSObject> boilerplate_object,
Handle<FixedArrayBase> elements,
- HValue* object_elements) {
+ HValue* object_elements,
+ AllocationSiteUsageContext* site_context) {
ElementsKind kind = boilerplate_object->map()->elements_kind();
int elements_length = elements->length();
HValue* object_elements_length = Add<HConstant>(elements_length);
@@ -8381,7 +9532,8 @@ void HOptimizedGraphBuilder::BuildEmitElements(
if (elements->IsFixedDoubleArray()) {
BuildEmitFixedDoubleArray(elements, kind, object_elements);
} else if (elements->IsFixedArray()) {
- BuildEmitFixedArray(elements, kind, object_elements);
+ BuildEmitFixedArray(elements, kind, object_elements,
+ site_context);
} else {
UNREACHABLE();
}
@@ -8410,7 +9562,8 @@ void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray(
void HOptimizedGraphBuilder::BuildEmitFixedArray(
Handle<FixedArrayBase> elements,
ElementsKind kind,
- HValue* object_elements) {
+ HValue* object_elements,
+ AllocationSiteUsageContext* site_context) {
HInstruction* boilerplate_elements = Add<HConstant>(elements);
int elements_length = elements->length();
Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements);
@@ -8419,9 +9572,10 @@ void HOptimizedGraphBuilder::BuildEmitFixedArray(
HValue* key_constant = Add<HConstant>(i);
if (value->IsJSObject()) {
Handle<JSObject> value_object = Handle<JSObject>::cast(value);
+ Handle<AllocationSite> current_site = site_context->EnterNewScope();
HInstruction* result =
- BuildFastLiteral(value_object,
- Handle<Object>::null(), DONT_TRACK_ALLOCATION_SITE);
+ BuildFastLiteral(value_object, site_context);
+ site_context->ExitScope(current_site, value_object);
Add<HStoreKeyed>(object_elements, key_constant, result, kind);
} else {
HInstruction* value_instruction =
@@ -8584,7 +9738,7 @@ void HOptimizedGraphBuilder::GenerateIsSmi(CallRuntime* call) {
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
- HIsSmiAndBranch* result = new(zone()) HIsSmiAndBranch(value);
+ HIsSmiAndBranch* result = New<HIsSmiAndBranch>(value);
return ast_context()->ReturnControl(result, call->id());
}
@@ -8594,9 +9748,9 @@ void HOptimizedGraphBuilder::GenerateIsSpecObject(CallRuntime* call) {
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
HHasInstanceTypeAndBranch* result =
- new(zone()) HHasInstanceTypeAndBranch(value,
- FIRST_SPEC_OBJECT_TYPE,
- LAST_SPEC_OBJECT_TYPE);
+ New<HHasInstanceTypeAndBranch>(value,
+ FIRST_SPEC_OBJECT_TYPE,
+ LAST_SPEC_OBJECT_TYPE);
return ast_context()->ReturnControl(result, call->id());
}
@@ -8606,7 +9760,16 @@ void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) {
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
HHasInstanceTypeAndBranch* result =
- new(zone()) HHasInstanceTypeAndBranch(value, JS_FUNCTION_TYPE);
+ New<HHasInstanceTypeAndBranch>(value, JS_FUNCTION_TYPE);
+ return ast_context()->ReturnControl(result, call->id());
+}
+
+
+void HOptimizedGraphBuilder::GenerateIsMinusZero(CallRuntime* call) {
+ ASSERT(call->arguments()->length() == 1);
+ CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+ HValue* value = Pop();
+ HCompareMinusZeroAndBranch* result = New<HCompareMinusZeroAndBranch>(value);
return ast_context()->ReturnControl(result, call->id());
}
@@ -8616,7 +9779,7 @@ void HOptimizedGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) {
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
HHasCachedArrayIndexAndBranch* result =
- new(zone()) HHasCachedArrayIndexAndBranch(value);
+ New<HHasCachedArrayIndexAndBranch>(value);
return ast_context()->ReturnControl(result, call->id());
}
@@ -8626,7 +9789,7 @@ void HOptimizedGraphBuilder::GenerateIsArray(CallRuntime* call) {
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
HHasInstanceTypeAndBranch* result =
- new(zone()) HHasInstanceTypeAndBranch(value, JS_ARRAY_TYPE);
+ New<HHasInstanceTypeAndBranch>(value, JS_ARRAY_TYPE);
return ast_context()->ReturnControl(result, call->id());
}
@@ -8636,7 +9799,7 @@ void HOptimizedGraphBuilder::GenerateIsRegExp(CallRuntime* call) {
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
HHasInstanceTypeAndBranch* result =
- new(zone()) HHasInstanceTypeAndBranch(value, JS_REGEXP_TYPE);
+ New<HHasInstanceTypeAndBranch>(value, JS_REGEXP_TYPE);
return ast_context()->ReturnControl(result, call->id());
}
@@ -8645,7 +9808,7 @@ void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) {
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
- HIsObjectAndBranch* result = new(zone()) HIsObjectAndBranch(value);
+ HIsObjectAndBranch* result = New<HIsObjectAndBranch>(value);
return ast_context()->ReturnControl(result, call->id());
}
@@ -8659,8 +9822,7 @@ void HOptimizedGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) {
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
- HIsUndetectableAndBranch* result =
- new(zone()) HIsUndetectableAndBranch(value);
+ HIsUndetectableAndBranch* result = New<HIsUndetectableAndBranch>(value);
return ast_context()->ReturnControl(result, call->id());
}
@@ -8681,7 +9843,7 @@ void HOptimizedGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
: graph()->GetConstantFalse();
return ast_context()->ReturnValue(value);
} else {
- return ast_context()->ReturnControl(new(zone()) HIsConstructCallAndBranch,
+ return ast_context()->ReturnControl(New<HIsConstructCallAndBranch>(),
call->id());
}
}
@@ -8711,8 +9873,8 @@ void HOptimizedGraphBuilder::GenerateArguments(CallRuntime* call) {
HInstruction* elements = Add<HArgumentsElements>(false);
HInstruction* length = Add<HArgumentsLength>(elements);
HInstruction* checked_index = Add<HBoundsCheck>(index, length);
- HAccessArgumentsAt* result =
- new(zone()) HAccessArgumentsAt(elements, length, checked_index);
+ HAccessArgumentsAt* result = New<HAccessArgumentsAt>(
+ elements, length, checked_index);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -8729,7 +9891,7 @@ void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) {
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
- HValueOf* result = new(zone()) HValueOf(value);
+ HValueOf* result = New<HValueOf>(value);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -8740,7 +9902,7 @@ void HOptimizedGraphBuilder::GenerateDateField(CallRuntime* call) {
Smi* index = Smi::cast(*(call->arguments()->at(1)->AsLiteral()->value()));
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* date = Pop();
- HDateField* result = new(zone()) HDateField(date, index);
+ HDateField* result = New<HDateField>(date, index);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -8754,9 +9916,10 @@ void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar(
HValue* value = Pop();
HValue* index = Pop();
HValue* string = Pop();
- HSeqStringSetChar* result = new(zone()) HSeqStringSetChar(
- String::ONE_BYTE_ENCODING, string, index, value);
- return ast_context()->ReturnInstruction(result, call->id());
+ Add<HSeqStringSetChar>(String::ONE_BYTE_ENCODING, string,
+ index, value);
+ Add<HSimulate>(call->id(), FIXED_SIMULATE);
+ return ast_context()->ReturnValue(graph()->GetConstantUndefined());
}
@@ -8769,9 +9932,10 @@ void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar(
HValue* value = Pop();
HValue* index = Pop();
HValue* string = Pop();
- HSeqStringSetChar* result = new(zone()) HSeqStringSetChar(
- String::TWO_BYTE_ENCODING, string, index, value);
- return ast_context()->ReturnInstruction(result, call->id());
+ Add<HSeqStringSetChar>(String::TWO_BYTE_ENCODING, string,
+ index, value);
+ Add<HSimulate>(call->id(), FIXED_SIMULATE);
+ return ast_context()->ReturnValue(graph()->GetConstantUndefined());
}
@@ -8782,31 +9946,28 @@ void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
HValue* value = Pop();
HValue* object = Pop();
// Check if object is a not a smi.
- HIsSmiAndBranch* smicheck = new(zone()) HIsSmiAndBranch(object);
HBasicBlock* if_smi = graph()->CreateBasicBlock();
HBasicBlock* if_heap_object = graph()->CreateBasicBlock();
HBasicBlock* join = graph()->CreateBasicBlock();
- smicheck->SetSuccessorAt(0, if_smi);
- smicheck->SetSuccessorAt(1, if_heap_object);
- current_block()->Finish(smicheck);
- if_smi->Goto(join);
+ FinishCurrentBlock(New<HIsSmiAndBranch>(object, if_smi, if_heap_object));
+ Goto(if_smi, join);
// Check if object is a JSValue.
set_current_block(if_heap_object);
HHasInstanceTypeAndBranch* typecheck =
- new(zone()) HHasInstanceTypeAndBranch(object, JS_VALUE_TYPE);
+ New<HHasInstanceTypeAndBranch>(object, JS_VALUE_TYPE);
HBasicBlock* if_js_value = graph()->CreateBasicBlock();
HBasicBlock* not_js_value = graph()->CreateBasicBlock();
typecheck->SetSuccessorAt(0, if_js_value);
typecheck->SetSuccessorAt(1, not_js_value);
- current_block()->Finish(typecheck);
- not_js_value->Goto(join);
+ FinishCurrentBlock(typecheck);
+ Goto(not_js_value, join);
// Create in-object property store to kValueOffset.
set_current_block(if_js_value);
Add<HStoreNamedField>(object,
HObjectAccess::ForJSObjectOffset(JSValue::kValueOffset), value);
- if_js_value->Goto(join);
+ Goto(if_js_value, join);
join->SetJoinId(call->id());
set_current_block(join);
return ast_context()->ReturnValue(value);
@@ -8830,7 +9991,7 @@ void HOptimizedGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) {
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* char_code = Pop();
- HInstruction* result = New<HStringCharFromCode>(char_code);
+ HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -8844,7 +10005,7 @@ void HOptimizedGraphBuilder::GenerateStringCharAt(CallRuntime* call) {
HValue* string = Pop();
HInstruction* char_code = BuildStringCharCodeAt(string, index);
AddInstruction(char_code);
- HInstruction* result = New<HStringCharFromCode>(char_code);
+ HInstruction* result = NewUncasted<HStringCharFromCode>(char_code);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -8868,14 +10029,6 @@ void HOptimizedGraphBuilder::GenerateLog(CallRuntime* call) {
}
-// Fast support for Math.random().
-void HOptimizedGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) {
- HGlobalObject* global_object = Add<HGlobalObject>();
- HRandom* result = new(zone()) HRandom(global_object);
- return ast_context()->ReturnInstruction(result, call->id());
-}
-
-
// Fast support for StringAdd.
void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) {
ASSERT_EQ(2, call->arguments()->length());
@@ -8883,9 +10036,8 @@ void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) {
CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
HValue* right = Pop();
HValue* left = Pop();
- HValue* context = environment()->context();
- HInstruction* result = HStringAdd::New(
- zone(), context, left, right, STRING_ADD_CHECK_BOTH);
+ HInstruction* result =
+ NewUncasted<HStringAdd>(left, right, STRING_ADD_CHECK_BOTH);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -8894,8 +10046,7 @@ void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) {
void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) {
ASSERT_EQ(3, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->context();
- HCallStub* result = new(zone()) HCallStub(context, CodeStub::SubString, 3);
+ HCallStub* result = New<HCallStub>(CodeStub::SubString, 3);
Drop(3);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -8905,9 +10056,7 @@ void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) {
void HOptimizedGraphBuilder::GenerateStringCompare(CallRuntime* call) {
ASSERT_EQ(2, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->context();
- HCallStub* result =
- new(zone()) HCallStub(context, CodeStub::StringCompare, 2);
+ HCallStub* result = New<HCallStub>(CodeStub::StringCompare, 2);
Drop(2);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -8917,8 +10066,7 @@ void HOptimizedGraphBuilder::GenerateStringCompare(CallRuntime* call) {
void HOptimizedGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
ASSERT_EQ(4, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->context();
- HCallStub* result = new(zone()) HCallStub(context, CodeStub::RegExpExec, 4);
+ HCallStub* result = New<HCallStub>(CodeStub::RegExpExec, 4);
Drop(4);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -8928,9 +10076,7 @@ void HOptimizedGraphBuilder::GenerateRegExpExec(CallRuntime* call) {
void HOptimizedGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) {
ASSERT_EQ(3, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->context();
- HCallStub* result =
- new(zone()) HCallStub(context, CodeStub::RegExpConstructResult, 3);
+ HCallStub* result = New<HCallStub>(CodeStub::RegExpConstructResult, 3);
Drop(3);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -8945,12 +10091,11 @@ void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) {
// Fast support for number to string.
void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) {
ASSERT_EQ(1, call->arguments()->length());
- CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->context();
- HCallStub* result =
- new(zone()) HCallStub(context, CodeStub::NumberToString, 1);
- Drop(1);
- return ast_context()->ReturnInstruction(result, call->id());
+ CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
+ HValue* number = Pop();
+ HValue* result = BuildNumberToString(
+ number, handle(Type::Number(), isolate()));
+ return ast_context()->ReturnValue(result);
}
@@ -8969,25 +10114,25 @@ void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) {
// Branch for function proxies, or other non-functions.
HHasInstanceTypeAndBranch* typecheck =
- new(zone()) HHasInstanceTypeAndBranch(function, JS_FUNCTION_TYPE);
+ New<HHasInstanceTypeAndBranch>(function, JS_FUNCTION_TYPE);
HBasicBlock* if_jsfunction = graph()->CreateBasicBlock();
HBasicBlock* if_nonfunction = graph()->CreateBasicBlock();
HBasicBlock* join = graph()->CreateBasicBlock();
typecheck->SetSuccessorAt(0, if_jsfunction);
typecheck->SetSuccessorAt(1, if_nonfunction);
- current_block()->Finish(typecheck);
+ FinishCurrentBlock(typecheck);
set_current_block(if_jsfunction);
HInstruction* invoke_result = Add<HInvokeFunction>(function, arg_count);
Drop(arg_count);
Push(invoke_result);
- if_jsfunction->Goto(join);
+ Goto(if_jsfunction, join);
set_current_block(if_nonfunction);
HInstruction* call_result = Add<HCallFunction>(function, arg_count);
Drop(arg_count);
Push(call_result);
- if_nonfunction->Goto(join);
+ Goto(if_nonfunction, join);
set_current_block(join);
join->SetJoinId(call->id());
@@ -9002,43 +10147,7 @@ void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) {
CHECK_ALIVE(VisitForValue(call->arguments()->at(1)));
HValue* right = Pop();
HValue* left = Pop();
- HInstruction* result = HPower::New(zone(), context(), left, right);
- return ast_context()->ReturnInstruction(result, call->id());
-}
-
-
-void HOptimizedGraphBuilder::GenerateMathSin(CallRuntime* call) {
- ASSERT_EQ(1, call->arguments()->length());
- CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->context();
- HCallStub* result =
- new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
- result->set_transcendental_type(TranscendentalCache::SIN);
- Drop(1);
- return ast_context()->ReturnInstruction(result, call->id());
-}
-
-
-void HOptimizedGraphBuilder::GenerateMathCos(CallRuntime* call) {
- ASSERT_EQ(1, call->arguments()->length());
- CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->context();
- HCallStub* result =
- new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
- result->set_transcendental_type(TranscendentalCache::COS);
- Drop(1);
- return ast_context()->ReturnInstruction(result, call->id());
-}
-
-
-void HOptimizedGraphBuilder::GenerateMathTan(CallRuntime* call) {
- ASSERT_EQ(1, call->arguments()->length());
- CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->context();
- HCallStub* result =
- new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
- result->set_transcendental_type(TranscendentalCache::TAN);
- Drop(1);
+ HInstruction* result = NewUncasted<HPower>(left, right);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -9046,9 +10155,7 @@ void HOptimizedGraphBuilder::GenerateMathTan(CallRuntime* call) {
void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) {
ASSERT_EQ(1, call->arguments()->length());
CHECK_ALIVE(VisitArgumentList(call->arguments()));
- HValue* context = environment()->context();
- HCallStub* result =
- new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1);
+ HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1);
result->set_transcendental_type(TranscendentalCache::LOG);
Drop(1);
return ast_context()->ReturnInstruction(result, call->id());
@@ -9059,9 +10166,7 @@ void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) {
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
- HValue* context = environment()->context();
- HInstruction* result =
- HUnaryMathOperation::New(zone(), context, value, kMathSqrt);
+ HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -9076,7 +10181,7 @@ void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) {
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
- HGetCachedArrayIndex* result = new(zone()) HGetCachedArrayIndex(value);
+ HGetCachedArrayIndex* result = New<HGetCachedArrayIndex>(value);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -9099,7 +10204,7 @@ void HOptimizedGraphBuilder::GenerateGeneratorThrow(CallRuntime* call) {
void HOptimizedGraphBuilder::GenerateDebugBreakInOptimizedCode(
CallRuntime* call) {
- AddInstruction(new(zone()) HDebugBreak());
+ Add<HDebugBreak>();
return ast_context()->ReturnValue(graph()->GetConstant0());
}
@@ -9422,7 +10527,7 @@ void HTracer::TraceCompilation(CompilationInfo* info) {
void HTracer::TraceLithium(const char* name, LChunk* chunk) {
- ASSERT(!FLAG_concurrent_recompilation);
+ ASSERT(!chunk->isolate()->concurrent_recompilation_enabled());
AllowHandleDereference allow_deref;
AllowDeferredHandleDereference allow_deferred_deref;
Trace(name, chunk->graph(), chunk);
@@ -9430,7 +10535,7 @@ void HTracer::TraceLithium(const char* name, LChunk* chunk) {
void HTracer::TraceHydrogen(const char* name, HGraph* graph) {
- ASSERT(!FLAG_concurrent_recompilation);
+ ASSERT(!graph->isolate()->concurrent_recompilation_enabled());
AllowHandleDereference allow_deref;
AllowDeferredHandleDereference allow_deferred_deref;
Trace(name, graph, NULL);
@@ -9514,7 +10619,8 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
Tag HIR_tag(this, "HIR");
for (HInstructionIterator it(current); !it.Done(); it.Advance()) {
HInstruction* instruction = it.Current();
- int bci = 0;
+ int bci = FLAG_emit_opt_code_positions && instruction->has_position() ?
+ instruction->position() : 0;
int uses = instruction->UseCount();
PrintIndent();
trace_.Add("%d %d ", bci, uses);
@@ -9539,6 +10645,9 @@ void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) {
trace_.Add("%d ",
LifetimePosition::FromInstructionIndex(i).Value());
linstr->PrintTo(&trace_);
+ trace_.Add(" [hir:");
+ linstr->hydrogen_value()->PrintNameTo(&trace_);
+ trace_.Add("]");
trace_.Add(" <|@\n");
}
}