| 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;
|
| }
|
|
|