Index: src/hydrogen.cc |
diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
index 40aa1c2dc93462b87950dfefe226e95a70514b5d..913ff665198b25051e63472cb6e6c5a9ec49afc1 100644 |
--- a/src/hydrogen.cc |
+++ b/src/hydrogen.cc |
@@ -34,6 +34,7 @@ |
#include "full-codegen.h" |
#include "hashmap.h" |
#include "hydrogen-bce.h" |
+#include "hydrogen-bch.h" |
#include "hydrogen-canonicalize.h" |
#include "hydrogen-dce.h" |
#include "hydrogen-dehoist.h" |
@@ -148,26 +149,6 @@ void HBasicBlock::AddInstruction(HInstruction* instr) { |
} |
-HDeoptimize* HBasicBlock::CreateDeoptimize( |
- HDeoptimize::UseEnvironment has_uses) { |
- ASSERT(HasEnvironment()); |
- if (has_uses == HDeoptimize::kNoUses) |
- return new(zone()) HDeoptimize(0, 0, 0, zone()); |
- |
- HEnvironment* environment = last_environment(); |
- int first_local_index = environment->first_local_index(); |
- int first_expression_index = environment->first_expression_index(); |
- HDeoptimize* instr = new(zone()) HDeoptimize( |
- environment->length(), first_local_index, first_expression_index, zone()); |
- for (int i = 0; i < environment->length(); i++) { |
- HValue* val = environment->values()->at(i); |
- instr->AddEnvironmentValue(val, zone()); |
- } |
- |
- return instr; |
-} |
- |
- |
HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id, |
RemovableSimulate removable) { |
ASSERT(HasEnvironment()); |
@@ -702,13 +683,16 @@ HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, int position) |
: builder_(builder), |
position_(position), |
finished_(false), |
+ deopt_then_(false), |
+ deopt_else_(false), |
did_then_(false), |
did_else_(false), |
did_and_(false), |
did_or_(false), |
captured_(false), |
needs_compare_(true), |
- split_edge_merge_block_(NULL) { |
+ split_edge_merge_block_(NULL), |
+ merge_block_(NULL) { |
HEnvironment* env = builder->environment(); |
first_true_block_ = builder->CreateBasicBlock(env->Copy()); |
last_true_block_ = NULL; |
@@ -722,6 +706,8 @@ HGraphBuilder::IfBuilder::IfBuilder( |
: builder_(builder), |
position_(RelocInfo::kNoPosition), |
finished_(false), |
+ deopt_then_(false), |
+ deopt_else_(false), |
did_then_(false), |
did_else_(false), |
did_and_(false), |
@@ -838,14 +824,13 @@ void HGraphBuilder::IfBuilder::Else() { |
void HGraphBuilder::IfBuilder::Deopt() { |
- HBasicBlock* block = builder_->current_block(); |
- block->FinishExitWithDeoptimization(HDeoptimize::kUseAll); |
- builder_->set_current_block(NULL); |
+ ASSERT(did_then_); |
if (did_else_) { |
- first_false_block_ = NULL; |
+ deopt_else_ = true; |
} else { |
- first_true_block_ = NULL; |
+ deopt_then_ = true; |
} |
+ builder_->Add<HDeoptimize>(Deoptimizer::EAGER); |
} |
@@ -870,20 +855,30 @@ void HGraphBuilder::IfBuilder::End() { |
last_true_block_ = builder_->current_block(); |
} |
if (first_true_block_ == NULL) { |
- // Deopt on true. Nothing to do, just continue the false block. |
+ // Return on true. Nothing to do, just continue the false block. |
} else if (first_false_block_ == NULL) { |
// Deopt on false. Nothing to do except switching to the true block. |
builder_->set_current_block(last_true_block_); |
} else { |
- HEnvironment* merge_env = last_true_block_->last_environment()->Copy(); |
- merge_block_ = builder_->CreateBasicBlock(merge_env); |
+ 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()); |
- last_true_block_->GotoNoSimulate(merge_block_); |
- last_false_block->GotoNoSimulate(merge_block_); |
+ 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_); |
+ } |
builder_->set_current_block(merge_block_); |
} |
} |
@@ -993,36 +988,6 @@ HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { |
} |
-void HGraphBuilder::AddSimulate(BailoutId id, |
- RemovableSimulate removable) { |
- ASSERT(current_block() != NULL); |
- ASSERT(no_side_effects_scope_count_ == 0); |
- current_block()->AddSimulate(id, removable); |
-} |
- |
- |
-HReturn* HGraphBuilder::AddReturn(HValue* value) { |
- HValue* context = environment()->LookupContext(); |
- int num_parameters = graph()->info()->num_parameters(); |
- HValue* params = Add<HConstant>(num_parameters); |
- HReturn* return_instruction = new(graph()->zone()) |
- HReturn(value, context, params); |
- current_block()->FinishExit(return_instruction); |
- return return_instruction; |
-} |
- |
- |
-void HGraphBuilder::AddSoftDeoptimize(SoftDeoptimizeMode mode) { |
- isolate()->counters()->soft_deopts_requested()->Increment(); |
- if (FLAG_always_opt && mode == CAN_OMIT_SOFT_DEOPT) return; |
- if (current_block()->IsDeoptimizing()) return; |
- Add<HSoftDeoptimize>(); |
- isolate()->counters()->soft_deopts_inserted()->Increment(); |
- current_block()->MarkAsDeoptimizing(); |
- graph()->set_has_soft_deoptimize(true); |
-} |
- |
- |
HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { |
HBasicBlock* b = graph()->CreateBasicBlock(); |
b->SetInitialEnvironment(env); |
@@ -1045,14 +1010,52 @@ HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { |
} |
-HValue* HGraphBuilder::BuildCheckMap(HValue* obj, |
- Handle<Map> map) { |
- HCheckMaps* check = HCheckMaps::New(obj, map, zone()); |
+void HGraphBuilder::FinishExitWithHardDeoptimization( |
+ HBasicBlock* continuation) { |
+ PadEnvironmentForContinuation(current_block(), continuation); |
+ Add<HDeoptimize>(Deoptimizer::EAGER); |
+ if (no_side_effects_scope_count_ > 0) { |
+ current_block()->GotoNoSimulate(continuation); |
+ } else { |
+ current_block()->Goto(continuation); |
+ } |
+} |
+ |
+ |
+void HGraphBuilder::PadEnvironmentForContinuation( |
+ HBasicBlock* from, |
+ HBasicBlock* continuation) { |
+ if (continuation->last_environment() != NULL) { |
+ // When merging from a deopt block to a continuation, resolve differences in |
+ // environment by pushing undefined and popping extra values so that the |
+ // environments match during the join. |
+ int continuation_env_length = continuation->last_environment()->length(); |
+ while (continuation_env_length != from->last_environment()->length()) { |
+ if (continuation_env_length > from->last_environment()->length()) { |
+ from->last_environment()->Push(graph()->GetConstantUndefined()); |
+ } else { |
+ from->last_environment()->Pop(); |
+ } |
+ } |
+ } else { |
+ ASSERT(continuation->predecessors()->length() == 0); |
+ } |
+} |
+ |
+ |
+HValue* HGraphBuilder::BuildCheckMap(HValue* obj, Handle<Map> map) { |
+ HCheckMaps* check = HCheckMaps::New(obj, map, zone(), top_info()); |
AddInstruction(check); |
return check; |
} |
+HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) { |
+ if (object->type().IsJSObject()) return object; |
+ return Add<HWrapReceiver>(object, function); |
+} |
+ |
+ |
HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, |
HValue* elements, |
ElementsKind kind, |
@@ -1094,10 +1097,7 @@ HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, |
HAdd::New(zone, context, key, graph_->GetConstant1())); |
new_length->ClearFlag(HValue::kCanOverflow); |
- Representation representation = IsFastElementsKind(kind) |
- ? Representation::Smi() : Representation::Tagged(); |
- AddStore(object, HObjectAccess::ForArrayLength(), new_length, |
- representation); |
+ AddStore(object, HObjectAccess::ForArrayLength(kind), new_length); |
} |
length_checker.Else(); |
@@ -1165,10 +1165,8 @@ void HGraphBuilder::BuildTransitionElementsKind(HValue* object, |
HInstruction* elements_length = AddLoadFixedArrayLength(elements); |
HInstruction* array_length = is_jsarray |
- ? AddLoad(object, HObjectAccess::ForArrayLength(), |
- NULL, Representation::Smi()) |
+ ? AddLoad(object, HObjectAccess::ForArrayLength(from_kind), NULL) |
: elements_length; |
- array_length->set_type(HType::Smi()); |
BuildGrowElementsCapacity(object, elements, from_kind, to_kind, |
array_length, elements_length); |
@@ -1210,14 +1208,14 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
if (is_store && (fast_elements || fast_smi_only_elements) && |
store_mode != STORE_NO_TRANSITION_HANDLE_COW) { |
HCheckMaps* check_cow_map = HCheckMaps::New( |
- elements, isolate()->factory()->fixed_array_map(), zone); |
+ elements, isolate()->factory()->fixed_array_map(), zone, top_info()); |
check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
AddInstruction(check_cow_map); |
} |
HInstruction* length = NULL; |
if (is_js_array) { |
- length = AddLoad(object, HObjectAccess::ForArrayLength(), mapcheck, |
- Representation::Smi()); |
+ length = AddLoad(object, HObjectAccess::ForArrayLength(elements_kind), |
+ mapcheck); |
} else { |
length = AddLoadFixedArrayLength(elements); |
} |
@@ -1278,7 +1276,8 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
length); |
} else { |
HCheckMaps* check_cow_map = HCheckMaps::New( |
- elements, isolate()->factory()->fixed_array_map(), zone); |
+ elements, isolate()->factory()->fixed_array_map(), |
+ zone, top_info()); |
check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
AddInstruction(check_cow_map); |
} |
@@ -1332,10 +1331,7 @@ void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements, |
: factory->fixed_array_map(); |
AddStoreMapConstant(elements, map); |
- Representation representation = IsFastElementsKind(kind) |
- ? Representation::Smi() : Representation::Tagged(); |
- AddStore(elements, HObjectAccess::ForFixedArrayLength(), capacity, |
- representation); |
+ AddStore(elements, HObjectAccess::ForFixedArrayLength(), capacity); |
} |
@@ -1352,6 +1348,7 @@ HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader( |
HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array, |
HValue* array_map, |
AllocationSiteMode mode, |
+ ElementsKind elements_kind, |
HValue* allocation_site_payload, |
HValue* length_field) { |
@@ -1362,7 +1359,7 @@ HInnerAllocatedObject* HGraphBuilder::BuildJSArrayHeader(HValue* array, |
HObjectAccess access = HObjectAccess::ForPropertiesPointer(); |
AddStore(array, access, empty_fixed_array); |
- AddStore(array, HObjectAccess::ForArrayLength(), length_field); |
+ AddStore(array, HObjectAccess::ForArrayLength(elements_kind), length_field); |
if (mode == TRACK_ALLOCATION_SITE) { |
BuildCreateAllocationMemento(array, |
@@ -1469,10 +1466,7 @@ HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object, |
HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength(HValue* object) { |
- HLoadNamedField* instr = AddLoad(object, HObjectAccess::ForFixedArrayLength(), |
- NULL, Representation::Smi()); |
- instr->set_type(HType::Smi()); |
- return instr; |
+ return AddLoad(object, HObjectAccess::ForFixedArrayLength()); |
} |
@@ -1721,7 +1715,7 @@ HInstruction* HGraphBuilder::BuildUnaryMathOp( |
input, graph()->GetConstantMinus1()); |
Representation rep = Representation::FromType(type); |
if (type->Is(Type::None())) { |
- AddSoftDeoptimize(); |
+ Add<HDeoptimize>(Deoptimizer::SOFT); |
} |
if (instr->IsBinaryOperation()) { |
HBinaryOperation* binop = HBinaryOperation::cast(instr); |
@@ -1732,7 +1726,7 @@ HInstruction* HGraphBuilder::BuildUnaryMathOp( |
} |
case Token::BIT_NOT: |
if (type->Is(Type::None())) { |
- AddSoftDeoptimize(); |
+ Add<HDeoptimize>(Deoptimizer::SOFT); |
} |
return new(zone()) HBitNot(input); |
} |
@@ -1843,11 +1837,8 @@ HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode(HValue* context) { |
// 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(); |
- HInstruction* load = |
- builder()->BuildLoadNamedField(constructor_function_, |
- access, |
- Representation::Tagged()); |
- return builder()->AddInstruction(load); |
+ return builder()->AddInstruction( |
+ builder()->BuildLoadNamedField(constructor_function_, access)); |
} |
HInstruction* native_context = builder()->BuildGetNativeContext(context); |
@@ -1868,9 +1859,7 @@ HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() { |
// Find the map near the constructor function |
HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); |
return builder()->AddInstruction( |
- builder()->BuildLoadNamedField(constructor_function_, |
- access, |
- Representation::Tagged())); |
+ builder()->BuildLoadNamedField(constructor_function_, access)); |
} |
@@ -1884,11 +1873,8 @@ HValue* HGraphBuilder::JSArrayBuilder::EstablishAllocationSize( |
base_size += AllocationMemento::kSize; |
} |
- if (IsFastDoubleElementsKind(kind_)) { |
- base_size += FixedDoubleArray::kHeaderSize; |
- } else { |
- base_size += FixedArray::kHeaderSize; |
- } |
+ STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize); |
+ base_size += FixedArray::kHeaderSize; |
HInstruction* elements_size_value = |
builder()->Add<HConstant>(elements_size()); |
@@ -1958,6 +1944,7 @@ HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes, |
elements_location_ = builder()->BuildJSArrayHeader(new_object, |
map, |
mode_, |
+ kind_, |
allocation_site_payload_, |
length_field); |
@@ -1975,17 +1962,15 @@ HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes, |
HStoreNamedField* HGraphBuilder::AddStore(HValue *object, |
HObjectAccess access, |
- HValue *val, |
- Representation representation) { |
- return Add<HStoreNamedField>(object, access, val, representation); |
+ HValue *val) { |
+ return Add<HStoreNamedField>(object, access, val); |
} |
HLoadNamedField* HGraphBuilder::AddLoad(HValue *object, |
HObjectAccess access, |
- HValue *typecheck, |
- Representation representation) { |
- return Add<HLoadNamedField>(object, access, typecheck, representation); |
+ HValue *typecheck) { |
+ return Add<HLoadNamedField>(object, access, typecheck); |
} |
@@ -2640,7 +2625,7 @@ void EffectContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { |
ASSERT(!instr->IsControlInstruction()); |
owner()->AddInstruction(instr); |
if (instr->HasObservableSideEffects()) { |
- owner()->AddSimulate(ast_id, REMOVABLE_SIMULATE); |
+ owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
} |
} |
@@ -2682,7 +2667,7 @@ void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { |
owner()->AddInstruction(instr); |
owner()->Push(instr); |
if (instr->HasObservableSideEffects()) { |
- owner()->AddSimulate(ast_id, REMOVABLE_SIMULATE); |
+ owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
} |
} |
@@ -2738,7 +2723,7 @@ void TestContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { |
// this one isn't actually needed (and wouldn't work if it were targeted). |
if (instr->HasObservableSideEffects()) { |
builder->Push(instr); |
- builder->AddSimulate(ast_id, REMOVABLE_SIMULATE); |
+ builder->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
builder->Pop(); |
} |
BuildBranch(instr); |
@@ -2926,7 +2911,7 @@ bool HOptimizedGraphBuilder::BuildGraph() { |
VisitVariableDeclaration(scope->function()); |
} |
VisitDeclarations(scope->declarations()); |
- AddSimulate(BailoutId::Declarations()); |
+ Add<HSimulate>(BailoutId::Declarations()); |
HValue* context = environment()->LookupContext(); |
Add<HStackCheck>(context, HStackCheck::kFunctionEntry); |
@@ -2935,7 +2920,7 @@ bool HOptimizedGraphBuilder::BuildGraph() { |
if (HasStackOverflow()) return false; |
if (current_block() != NULL) { |
- AddReturn(graph()->GetConstantUndefined()); |
+ Add<HReturn>(graph()->GetConstantUndefined()); |
set_current_block(NULL); |
} |
@@ -3033,6 +3018,9 @@ bool HGraph::Optimize(SmartArrayPointer<char>* bailout_reason) { |
if (FLAG_array_bounds_checks_elimination && !FLAG_idefs) { |
Run<HBoundsCheckEliminationPhase>(); |
} |
+ if (FLAG_array_bounds_checks_hoisting && !FLAG_idefs) { |
+ Run<HBoundsCheckHoistingPhase>(); |
+ } |
if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>(); |
if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); |
@@ -3114,7 +3102,7 @@ void HGraph::RestoreActualValues() { |
} |
-void HOptimizedGraphBuilder::PushAndAdd(HInstruction* instr) { |
+void HGraphBuilder::PushAndAdd(HInstruction* instr) { |
Push(instr); |
AddInstruction(instr); |
} |
@@ -3225,10 +3213,10 @@ void HOptimizedGraphBuilder::VisitIfStatement(IfStatement* stmt) { |
ASSERT(current_block() != NULL); |
ASSERT(current_block()->HasPredecessor()); |
if (stmt->condition()->ToBooleanIsTrue()) { |
- AddSimulate(stmt->ThenId()); |
+ Add<HSimulate>(stmt->ThenId()); |
Visit(stmt->then_statement()); |
} else if (stmt->condition()->ToBooleanIsFalse()) { |
- AddSimulate(stmt->ElseId()); |
+ Add<HSimulate>(stmt->ElseId()); |
Visit(stmt->else_statement()); |
} else { |
HBasicBlock* cond_true = graph()->CreateBasicBlock(); |
@@ -3335,7 +3323,7 @@ void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { |
// Not an inlined return, so an actual one. |
CHECK_ALIVE(VisitForValue(stmt->expression())); |
HValue* result = environment()->Pop(); |
- AddReturn(result); |
+ Add<HReturn>(result); |
} else if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) { |
// Return from an inlined construct call. In a test context the return value |
// will always evaluate to true, in a value context the return value needs |
@@ -3427,7 +3415,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
HValue* context = environment()->LookupContext(); |
CHECK_ALIVE(VisitForValue(stmt->tag())); |
- AddSimulate(stmt->EntryId()); |
+ Add<HSimulate>(stmt->EntryId()); |
HValue* tag_value = Pop(); |
HBasicBlock* first_test_block = current_block(); |
@@ -3467,7 +3455,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) { |
if (!clause->compare_type()->Is(Type::Smi())) { |
- AddSoftDeoptimize(); |
+ Add<HDeoptimize>(Deoptimizer::SOFT); |
} |
HCompareNumericAndBranch* compare_ = |
@@ -3517,7 +3505,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { |
normal_block = last_block; |
last_block = NULL; // Cleared to indicate we've handled it. |
} |
- } else if (!curr_test_block->end()->IsDeoptimize()) { |
+ } else { |
normal_block = curr_test_block->end()->FirstSuccessor(); |
curr_test_block = curr_test_block->end()->SecondSuccessor(); |
} |
@@ -3571,7 +3559,7 @@ void HOptimizedGraphBuilder::VisitLoopBody(IterationStatement* stmt, |
HBasicBlock* loop_entry, |
BreakAndContinueInfo* break_info) { |
BreakAndContinueScope push(break_info, this); |
- AddSimulate(stmt->StackCheckId()); |
+ Add<HSimulate>(stmt->StackCheckId()); |
HValue* context = environment()->LookupContext(); |
HStackCheck* stack_check = Add<HStackCheck>( |
context, HStackCheck::kBackwardsBranch); |
@@ -3732,7 +3720,7 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { |
HInstruction* map = Add<HForInPrepareMap>( |
environment()->LookupContext(), enumerable); |
- AddSimulate(stmt->PrepareId()); |
+ Add<HSimulate>(stmt->PrepareId()); |
HInstruction* array = Add<HForInCacheArray>( |
enumerable, map, DescriptorArray::kEnumCacheBridgeCacheIndex); |
@@ -3801,7 +3789,6 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { |
environment()->LookupContext(), |
current_index, |
graph()->GetConstant1()); |
- new_index->AssumeRepresentation(Representation::Integer32()); |
PushAndAdd(new_index); |
body_exit = current_block(); |
} |
@@ -4329,7 +4316,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
} |
AddInstruction(store); |
if (store->HasObservableSideEffects()) { |
- AddSimulate(key->id(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(key->id(), REMOVABLE_SIMULATE); |
} |
} else { |
CHECK_ALIVE(VisitForEffect(value)); |
@@ -4452,7 +4439,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
// De-opt if elements kind changed from boilerplate_elements_kind. |
Handle<Map> map = Handle<Map>(original_boilerplate_object->map(), |
isolate()); |
- AddInstruction(HCheckMaps::New(literal, map, zone())); |
+ AddInstruction(HCheckMaps::New(literal, map, zone(), top_info())); |
} |
// The array is expected in the bailout environment during computation |
@@ -4494,7 +4481,7 @@ void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
break; |
} |
- AddSimulate(expr->GetIdForElement(i)); |
+ Add<HSimulate>(expr->GetIdForElement(i)); |
} |
Drop(1); // array literal index |
@@ -4527,30 +4514,17 @@ static bool ComputeLoadStoreField(Handle<Map> type, |
} |
-static Representation ComputeLoadStoreRepresentation(Handle<Map> type, |
- LookupResult* lookup) { |
- if (lookup->IsField()) { |
- return lookup->representation(); |
- } else { |
- Map* transition = lookup->GetTransitionMapFromMap(*type); |
- int descriptor = transition->LastAdded(); |
- PropertyDetails details = |
- transition->instance_descriptors()->GetDetails(descriptor); |
- return details.representation(); |
- } |
-} |
- |
- |
void HOptimizedGraphBuilder::AddCheckMap(HValue* object, Handle<Map> map) { |
BuildCheckHeapObject(object); |
- AddInstruction(HCheckMaps::New(object, map, zone())); |
+ AddInstruction(HCheckMaps::New(object, map, zone(), top_info())); |
} |
void HOptimizedGraphBuilder::AddCheckMapsWithTransitions(HValue* object, |
Handle<Map> map) { |
BuildCheckHeapObject(object); |
- AddInstruction(HCheckMaps::NewWithTransitions(object, map, zone())); |
+ AddInstruction(HCheckMaps::NewWithTransitions( |
+ object, map, zone(), top_info())); |
} |
@@ -4591,33 +4565,33 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( |
} |
HObjectAccess field_access = HObjectAccess::ForField(map, lookup, name); |
- Representation representation = ComputeLoadStoreRepresentation(map, lookup); |
bool transition_to_field = lookup->IsTransitionToField(*map); |
HStoreNamedField *instr; |
- if (FLAG_track_double_fields && representation.IsDouble()) { |
+ if (FLAG_track_double_fields && field_access.representation().IsDouble()) { |
+ HObjectAccess heap_number_access = |
+ field_access.WithRepresentation(Representation::Tagged()); |
if (transition_to_field) { |
// The store requires a mutable HeapNumber to be allocated. |
NoObservableSideEffectsScope no_side_effects(this); |
HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize); |
- HInstruction* double_box = Add<HAllocate>( |
+ HInstruction* heap_number = Add<HAllocate>( |
environment()->LookupContext(), heap_number_size, |
HType::HeapNumber(), HAllocate::CAN_ALLOCATE_IN_NEW_SPACE); |
- AddStoreMapConstant(double_box, isolate()->factory()->heap_number_map()); |
- AddStore(double_box, HObjectAccess::ForHeapNumberValue(), |
- value, Representation::Double()); |
- instr = new(zone()) HStoreNamedField(object, field_access, double_box); |
+ AddStoreMapConstant(heap_number, isolate()->factory()->heap_number_map()); |
+ AddStore(heap_number, HObjectAccess::ForHeapNumberValue(), value); |
+ instr = new(zone()) HStoreNamedField( |
+ object, heap_number_access, heap_number); |
} else { |
// Already holds a HeapNumber; load the box and write its value field. |
- HInstruction* double_box = AddLoad(object, field_access); |
- double_box->set_type(HType::HeapNumber()); |
- instr = new(zone()) HStoreNamedField(double_box, |
- HObjectAccess::ForHeapNumberValue(), value, Representation::Double()); |
+ HInstruction* heap_number = AddLoad(object, heap_number_access); |
+ heap_number->set_type(HType::HeapNumber()); |
+ instr = new(zone()) HStoreNamedField(heap_number, |
+ HObjectAccess::ForHeapNumberValue(), value); |
} |
} else { |
- // This is a non-double store. |
- instr = new(zone()) HStoreNamedField( |
- object, field_access, value, representation); |
+ // This is a normal store. |
+ instr = new(zone()) HStoreNamedField(object, field_access, value); |
} |
if (transition_to_field) { |
@@ -4684,20 +4658,18 @@ HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic( |
LookupResult lookup(isolate()); |
int count; |
- Representation representation = Representation::None(); |
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); |
- Representation new_representation = |
- ComputeLoadStoreRepresentation(map, &lookup); |
if (count == 0) { |
// First time through the loop; set access and representation. |
access = new_access; |
- } else if (!representation.IsCompatibleForLoad(new_representation)) { |
+ } else if (!access.representation().IsCompatibleForLoad( |
+ new_access.representation())) { |
// Representations did not match. |
break; |
} else if (access.offset() != new_access.offset()) { |
@@ -4707,14 +4679,15 @@ HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic( |
// In-objectness did not match. |
break; |
} |
- representation = representation.generalize(new_representation); |
+ access = access.WithRepresentation( |
+ access.representation().generalize(new_access.representation())); |
} |
if (count == types->length()) { |
// Everything matched; can use monomorphic load. |
BuildCheckHeapObject(object); |
AddInstruction(HCheckMaps::New(object, types, zone())); |
- return BuildLoadNamedField(object, access, representation); |
+ return BuildLoadNamedField(object, access); |
} |
if (count != 0) return NULL; |
@@ -4736,14 +4709,14 @@ HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic( |
BuildCheckHeapObject(object); |
AddInstruction(HCheckMaps::New(object, types, zone())); |
+ |
Handle<JSObject> holder(lookup.holder()); |
Handle<Map> holder_map(holder->map()); |
AddInstruction(new(zone()) HCheckPrototypeMaps( |
Handle<JSObject>::cast(prototype), holder, zone(), top_info())); |
HValue* holder_value = AddInstruction(new(zone()) HConstant(holder)); |
return BuildLoadNamedField(holder_value, |
- HObjectAccess::ForField(holder_map, &lookup, name), |
- ComputeLoadStoreRepresentation(map, &lookup)); |
+ HObjectAccess::ForField(holder_map, &lookup, name)); |
} |
@@ -4792,8 +4765,7 @@ bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( |
ASSERT(!map->is_observed()); |
HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name); |
- Representation new_representation = |
- ComputeLoadStoreRepresentation(map, &lookup); |
+ Representation new_representation = new_access.representation(); |
if (count == 0) { |
// First time through the loop; set access and representation. |
@@ -4824,7 +4796,7 @@ bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( |
if (!ast_context()->IsEffect()) Push(result_value); |
store->set_position(position); |
AddInstruction(store); |
- AddSimulate(assignment_id); |
+ Add<HSimulate>(assignment_id); |
if (!ast_context()->IsEffect()) Drop(1); |
ast_context()->ReturnValue(result_value); |
return true; |
@@ -4883,7 +4855,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( |
// 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) { |
- current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); |
+ FinishExitWithHardDeoptimization(join); |
} else { |
HInstruction* instr = BuildStoreNamedGeneric(object, name, store_value); |
instr->set_position(position); |
@@ -4900,10 +4872,10 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( |
// unoptimized code). |
if (instr->HasObservableSideEffects()) { |
if (ast_context()->IsEffect()) { |
- AddSimulate(assignment_id, REMOVABLE_SIMULATE); |
+ Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE); |
} else { |
Push(result_value); |
- AddSimulate(assignment_id, REMOVABLE_SIMULATE); |
+ Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE); |
Drop(1); |
} |
} |
@@ -4931,7 +4903,7 @@ void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
HValue* value = environment()->ExpressionStackAt(0); |
HValue* object = environment()->ExpressionStackAt(1); |
- if (expr->IsUninitialized()) AddSoftDeoptimize(); |
+ if (expr->IsUninitialized()) Add<HDeoptimize>(Deoptimizer::SOFT); |
return BuildStoreNamed(expr, expr->id(), expr->position(), |
expr->AssignmentId(), prop, object, value, value); |
} else { |
@@ -4948,7 +4920,7 @@ void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
&has_side_effects); |
Drop(3); |
Push(value); |
- AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); |
return ast_context()->ReturnValue(Pop()); |
} |
} |
@@ -4977,14 +4949,14 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( |
} |
builder.Then(); |
builder.Else(); |
- AddSoftDeoptimize(MUST_EMIT_SOFT_DEOPT); |
+ Add<HDeoptimize>(Deoptimizer::EAGER); |
builder.End(); |
} |
HInstruction* instr = |
Add<HStoreGlobalCell>(value, cell, lookup.GetPropertyDetails()); |
instr->set_position(position); |
if (instr->HasObservableSideEffects()) { |
- AddSimulate(ast_id, REMOVABLE_SIMULATE); |
+ Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
} |
} else { |
HValue* context = environment()->LookupContext(); |
@@ -4994,7 +4966,7 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( |
value, function_strict_mode_flag()); |
instr->set_position(position); |
ASSERT(instr->HasObservableSideEffects()); |
- AddSimulate(ast_id, REMOVABLE_SIMULATE); |
+ Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
} |
} |
@@ -5056,7 +5028,7 @@ void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr, |
instr->set_position(position); |
AddInstruction(instr); |
if (instr->HasObservableSideEffects()) { |
- AddSimulate(id, REMOVABLE_SIMULATE); |
+ Add<HSimulate>(id, REMOVABLE_SIMULATE); |
} |
if (!ast_context()->IsEffect()) Drop(1); |
return ast_context()->ReturnValue(result_value); |
@@ -5134,7 +5106,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(), |
mode, Top()); |
if (instr->HasObservableSideEffects()) { |
- AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); |
} |
break; |
} |
@@ -5175,7 +5147,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop); |
PushAndAdd(load); |
if (load->HasObservableSideEffects()) { |
- AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE); |
} |
CHECK_ALIVE(VisitForValue(expr->value())); |
@@ -5185,7 +5157,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
HInstruction* instr = BuildBinaryOperation(operation, left, right); |
PushAndAdd(instr); |
if (instr->HasObservableSideEffects()) { |
- AddSimulate(operation->id(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE); |
} |
return BuildStoreNamed(prop, expr->id(), expr->position(), |
@@ -5203,7 +5175,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
false, // is_store |
&has_side_effects); |
Push(load); |
- if (has_side_effects) AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
+ if (has_side_effects) Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE); |
CHECK_ALIVE(VisitForValue(expr->value())); |
HValue* right = Pop(); |
@@ -5212,7 +5184,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
HInstruction* instr = BuildBinaryOperation(operation, left, right); |
PushAndAdd(instr); |
if (instr->HasObservableSideEffects()) { |
- AddSimulate(operation->id(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(operation->id(), REMOVABLE_SIMULATE); |
} |
HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(), |
@@ -5224,7 +5196,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
Drop(3); |
Push(instr); |
ASSERT(has_side_effects); // Stores always have side effects. |
- AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); |
return ast_context()->ReturnValue(Pop()); |
} |
@@ -5346,7 +5318,7 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { |
HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(), |
mode, Top()); |
if (instr->HasObservableSideEffects()) { |
- AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); |
} |
return ast_context()->ReturnValue(Pop()); |
} |
@@ -5380,30 +5352,24 @@ void HOptimizedGraphBuilder::VisitThrow(Throw* expr) { |
HValue* value = environment()->Pop(); |
HThrow* instr = Add<HThrow>(context, value); |
instr->set_position(expr->position()); |
- AddSimulate(expr->id()); |
+ Add<HSimulate>(expr->id()); |
current_block()->FinishExit(new(zone()) HAbnormalExit); |
set_current_block(NULL); |
} |
-HLoadNamedField* HGraphBuilder::BuildLoadNamedField( |
- HValue* object, |
- HObjectAccess access, |
- Representation representation) { |
- bool load_double = false; |
- if (representation.IsDouble()) { |
- representation = Representation::Tagged(); |
- load_double = FLAG_track_double_fields; |
- } |
- HLoadNamedField* field = |
- new(zone()) HLoadNamedField(object, access, NULL, representation); |
- if (load_double) { |
- AddInstruction(field); |
- field->set_type(HType::HeapNumber()); |
- return new(zone()) HLoadNamedField(field, |
- HObjectAccess::ForHeapNumberValue(), NULL, Representation::Double()); |
+HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, |
+ HObjectAccess access) { |
+ if (FLAG_track_double_fields && access.representation().IsDouble()) { |
+ // load the heap number |
+ HLoadNamedField* heap_number = |
+ AddLoad(object, access.WithRepresentation(Representation::Tagged())); |
+ heap_number->set_type(HType::HeapNumber()); |
+ // load the double value from it |
+ return new(zone()) HLoadNamedField(heap_number, |
+ HObjectAccess::ForHeapNumberValue(), NULL); |
} |
- return field; |
+ return new(zone()) HLoadNamedField(object, access, NULL); |
} |
@@ -5412,7 +5378,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( |
Handle<String> name, |
Property* expr) { |
if (expr->IsUninitialized()) { |
- AddSoftDeoptimize(); |
+ Add<HDeoptimize>(Deoptimizer::SOFT); |
} |
HValue* context = environment()->LookupContext(); |
return new(zone()) HLoadNamedGeneric(context, object, name); |
@@ -5443,7 +5409,7 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( |
if (map->instance_type() == JS_ARRAY_TYPE) { |
AddCheckMapsWithTransitions(object, map); |
return new(zone()) HLoadNamedField(object, |
- HObjectAccess::ForArrayLength()); |
+ HObjectAccess::ForArrayLength(map->elements_kind())); |
} |
} |
@@ -5452,15 +5418,14 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( |
if (lookup.IsField()) { |
AddCheckMap(object, map); |
return BuildLoadNamedField(object, |
- HObjectAccess::ForField(map, &lookup, name), |
- ComputeLoadStoreRepresentation(map, &lookup)); |
+ HObjectAccess::ForField(map, &lookup, name)); |
} |
// Handle a load of a constant known function. |
- if (lookup.IsConstantFunction()) { |
+ if (lookup.IsConstant()) { |
AddCheckMap(object, map); |
- Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map)); |
- return new(zone()) HConstant(function); |
+ Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); |
+ return new(zone()) HConstant(constant); |
} |
// Handle a load from a known field somewhere in the prototype chain. |
@@ -5473,19 +5438,18 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( |
Add<HCheckPrototypeMaps>(prototype, holder, zone(), top_info()); |
HValue* holder_value = Add<HConstant>(holder); |
return BuildLoadNamedField(holder_value, |
- HObjectAccess::ForField(holder_map, &lookup, name), |
- ComputeLoadStoreRepresentation(map, &lookup)); |
+ HObjectAccess::ForField(holder_map, &lookup, name)); |
} |
// Handle a load of a constant function somewhere in the prototype chain. |
- if (lookup.IsConstantFunction()) { |
+ if (lookup.IsConstant()) { |
Handle<JSObject> prototype(JSObject::cast(map->prototype())); |
Handle<JSObject> holder(lookup.holder()); |
Handle<Map> holder_map(holder->map()); |
AddCheckMap(object, map); |
Add<HCheckPrototypeMaps>(prototype, holder, zone(), top_info()); |
- Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*holder_map)); |
- return new(zone()) HConstant(function); |
+ Handle<Object> constant(lookup.GetConstantFromMap(*holder_map), isolate()); |
+ return new(zone()) HConstant(constant); |
} |
// No luck, do a generic load. |
@@ -5508,7 +5472,8 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( |
Handle<Map> map, |
bool is_store, |
KeyedAccessStoreMode store_mode) { |
- HCheckMaps* mapcheck = HCheckMaps::New(object, map, zone(), dependency); |
+ HCheckMaps* mapcheck = HCheckMaps::New( |
+ object, map, zone(), top_info(), dependency); |
AddInstruction(mapcheck); |
if (dependency) { |
mapcheck->ClearGVNFlag(kDependsOnElementsKind); |
@@ -5692,12 +5657,11 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( |
if (is_store && !IsFastDoubleElementsKind(elements_kind)) { |
AddInstruction(HCheckMaps::New( |
elements, isolate()->factory()->fixed_array_map(), |
- zone(), mapcompare)); |
+ zone(), top_info(), mapcompare)); |
} |
- if (map->IsJSArray()) { |
- HInstruction* length = AddLoad(object, HObjectAccess::ForArrayLength(), |
- mapcompare, Representation::Smi()); |
- length->set_type(HType::Smi()); |
+ if (map->instance_type() == JS_ARRAY_TYPE) { |
+ HInstruction* length = AddLoad( |
+ object, HObjectAccess::ForArrayLength(elements_kind), mapcompare); |
checked_key = Add<HBoundsCheck>(key, length); |
} else { |
HInstruction* length = AddLoadFixedArrayLength(elements); |
@@ -5734,7 +5698,8 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( |
} |
// Deopt if none of the cases matched. |
- current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); |
+ NoObservableSideEffectsScope scope(this); |
+ FinishExitWithHardDeoptimization(join); |
set_current_block(join); |
return is_store ? NULL : Pop(); |
} |
@@ -5770,12 +5735,12 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( |
} else { |
if (is_store) { |
if (expr->IsAssignment() && expr->AsAssignment()->IsUninitialized()) { |
- AddSoftDeoptimize(); |
+ Add<HDeoptimize>(Deoptimizer::SOFT); |
} |
instr = BuildStoreKeyedGeneric(obj, key, val); |
} else { |
if (expr->AsProperty()->IsUninitialized()) { |
- AddSoftDeoptimize(); |
+ Add<HDeoptimize>(Deoptimizer::SOFT); |
} |
instr = BuildLoadKeyedGeneric(obj, key); |
} |
@@ -5954,10 +5919,10 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) { |
&has_side_effects); |
if (has_side_effects) { |
if (ast_context()->IsEffect()) { |
- AddSimulate(expr->id(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
} else { |
Push(load); |
- AddSimulate(expr->id(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
Drop(1); |
} |
} |
@@ -6059,7 +6024,7 @@ bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic( |
PreProcessCall(call); |
AddInstruction(call); |
if (!ast_context()->IsEffect()) Push(call); |
- AddSimulate(expr->id(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
} |
@@ -6191,7 +6156,11 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
// know about and do not want to handle ones we've never seen. Otherwise |
// use a generic IC. |
if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { |
- current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); |
+ // 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)); |
+ FinishExitWithHardDeoptimization(join); |
} else { |
HValue* context = environment()->LookupContext(); |
HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count); |
@@ -6449,7 +6418,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind, |
inner_env->BindContext(context); |
#endif |
- AddSimulate(return_id); |
+ Add<HSimulate>(return_id); |
current_block()->UpdateEnvironment(inner_env); |
HArgumentsObject* arguments_object = NULL; |
@@ -6883,7 +6852,7 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
if (function_state()->outer() == NULL) { |
HInstruction* elements = Add<HArgumentsElements>(false); |
HInstruction* length = Add<HArgumentsLength>(elements); |
- HValue* wrapped_receiver = Add<HWrapReceiver>(receiver, function); |
+ HValue* wrapped_receiver = BuildWrapReceiver(receiver, function); |
HInstruction* result = |
new(zone()) HApplyArguments(function, |
wrapped_receiver, |
@@ -6900,7 +6869,7 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
HArgumentsObject* args = function_state()->entry()->arguments_object(); |
const ZoneList<HValue*>* arguments_values = args->arguments_values(); |
int arguments_count = arguments_values->length(); |
- PushAndAdd(new(zone()) HWrapReceiver(receiver, function)); |
+ Push(BuildWrapReceiver(receiver, function)); |
for (int i = 1; i < arguments_count; i++) { |
Push(arguments_values->at(i)); |
} |
@@ -7462,8 +7431,8 @@ void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) { |
void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) { |
CHECK_ALIVE(VisitForValue(expr->expression())); |
- HValue* value = Pop(); |
Handle<Type> operand_type = expr->expression()->bounds().lower; |
+ HValue* value = TruncateToNumber(Pop(), &operand_type); |
HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::SUB); |
return ast_context()->ReturnInstruction(instr, expr->id()); |
} |
@@ -7471,8 +7440,8 @@ void HOptimizedGraphBuilder::VisitSub(UnaryOperation* expr) { |
void HOptimizedGraphBuilder::VisitBitNot(UnaryOperation* expr) { |
CHECK_ALIVE(VisitForValue(expr->expression())); |
- HValue* value = Pop(); |
Handle<Type> operand_type = expr->expression()->bounds().lower; |
+ HValue* value = TruncateToNumber(Pop(), &operand_type); |
HInstruction* instr = BuildUnaryMathOp(value, operand_type, Token::BIT_NOT); |
return ast_context()->ReturnInstruction(instr, expr->id()); |
} |
@@ -7627,7 +7596,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { |
HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(), |
mode, after); |
if (instr->HasObservableSideEffects()) { |
- AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); |
} |
break; |
} |
@@ -7670,7 +7639,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { |
if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop); |
PushAndAdd(load); |
if (load->HasObservableSideEffects()) { |
- AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE); |
} |
after = BuildIncrement(returns_original_input, expr); |
@@ -7693,7 +7662,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { |
false, // is_store |
&has_side_effects); |
Push(load); |
- if (has_side_effects) AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
+ if (has_side_effects) Add<HSimulate>(prop->LoadId(), REMOVABLE_SIMULATE); |
after = BuildIncrement(returns_original_input, expr); |
input = environment()->ExpressionStackAt(0); |
@@ -7710,7 +7679,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { |
environment()->SetExpressionStackAt(0, after); |
if (returns_original_input) environment()->SetExpressionStackAt(1, input); |
ASSERT(has_side_effects); // Stores always have side effects. |
- AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); |
} |
} |
@@ -7802,6 +7771,40 @@ bool CanBeZero(HValue* right) { |
} |
+HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) { |
+ if (value->IsConstant()) { |
+ HConstant* constant = HConstant::cast(value); |
+ Maybe<HConstant*> number = constant->CopyToTruncatedNumber(zone()); |
+ if (number.has_value) { |
+ *expected = handle(Type::Number(), isolate()); |
+ return AddInstruction(number.value); |
+ } |
+ return value; |
+ } |
+ |
+ Handle<Type> expected_type = *expected; |
+ Representation rep = Representation::FromType(expected_type); |
+ if (!rep.IsTagged()) return value; |
+ |
+ // If our type feedback suggests that we can non-observably truncate to number |
+ // we introduce the appropriate check here. This avoids 'value' having a |
+ // tagged representation later on. |
+ if (expected_type->Is(Type::Oddball())) { |
+ // TODO(olivf) The BinaryOpStub only records undefined. It might pay off to |
+ // also record booleans and convert them to 0/1 here. |
+ IfBuilder if_nan(this); |
+ if_nan.If<HCompareObjectEqAndBranch>(value, |
+ graph()->GetConstantUndefined()); |
+ if_nan.Then(); |
+ if_nan.ElseDeopt(); |
+ if_nan.End(); |
+ return Add<HConstant>(OS::nan_value(), Representation::Double()); |
+ } |
+ |
+ return value; |
+} |
+ |
+ |
HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( |
BinaryOperation* expr, |
HValue* left, |
@@ -7815,13 +7818,21 @@ HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( |
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); |
+ } |
+ |
if (left_type->Is(Type::None())) { |
- AddSoftDeoptimize(); |
+ Add<HDeoptimize>(Deoptimizer::SOFT); |
// TODO(rossberg): we should be able to get rid of non-continuous defaults. |
left_type = handle(Type::Any(), isolate()); |
} |
if (right_type->Is(Type::None())) { |
- AddSoftDeoptimize(); |
+ Add<HDeoptimize>(Deoptimizer::SOFT); |
right_type = handle(Type::Any(), isolate()); |
} |
HInstruction* instr = NULL; |
@@ -8171,7 +8182,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
// Cases handled below depend on collected type feedback. They should |
// soft deoptimize when there is no type feedback. |
if (combined_type->Is(Type::None())) { |
- AddSoftDeoptimize(); |
+ Add<HDeoptimize>(Deoptimizer::SOFT); |
combined_type = left_type = right_type = handle(Type::Any(), isolate()); |
} |
@@ -8447,11 +8458,8 @@ HValue* HOptimizedGraphBuilder::BuildEmitObjectHeader( |
HInstruction* length = Add<HConstant>(length_field); |
ASSERT(boilerplate_array->length()->IsSmi()); |
- Representation representation = |
- IsFastElementsKind(boilerplate_array->GetElementsKind()) |
- ? Representation::Smi() : Representation::Tagged(); |
- AddStore(object_header, HObjectAccess::ForArrayLength(), |
- length, representation); |
+ AddStore(object_header, HObjectAccess::ForArrayLength( |
+ boilerplate_array->GetElementsKind()), length); |
} |
return result; |
@@ -8517,7 +8525,7 @@ void HOptimizedGraphBuilder::BuildEmitInObjectProperties( |
AddStoreMapConstant(double_box, |
isolate()->factory()->heap_number_map()); |
AddStore(double_box, HObjectAccess::ForHeapNumberValue(), |
- value_instruction, Representation::Double()); |
+ value_instruction); |
value_instruction = double_box; |
} |
@@ -8674,7 +8682,7 @@ void HOptimizedGraphBuilder::VisitVariableDeclaration( |
HStoreContextSlot* store = Add<HStoreContextSlot>( |
context, variable->index(), HStoreContextSlot::kNoCheck, value); |
if (store->HasObservableSideEffects()) { |
- AddSimulate(proxy->id(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE); |
} |
} |
break; |
@@ -8712,7 +8720,7 @@ void HOptimizedGraphBuilder::VisitFunctionDeclaration( |
HStoreContextSlot* store = Add<HStoreContextSlot>( |
context, variable->index(), HStoreContextSlot::kNoCheck, value); |
if (store->HasObservableSideEffects()) { |
- AddSimulate(proxy->id(), REMOVABLE_SIMULATE); |
+ Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE); |
} |
break; |
} |