diff options
Diffstat (limited to 'src/compiler/bytecode-graph-builder.cc')
-rw-r--r-- | src/compiler/bytecode-graph-builder.cc | 887 |
1 files changed, 549 insertions, 338 deletions
diff --git a/src/compiler/bytecode-graph-builder.cc b/src/compiler/bytecode-graph-builder.cc index 34b50df3..aaeee666 100644 --- a/src/compiler/bytecode-graph-builder.cc +++ b/src/compiler/bytecode-graph-builder.cc @@ -7,12 +7,14 @@ #include "src/ast/ast.h" #include "src/ast/scopes.h" #include "src/compilation-info.h" -#include "src/compiler/bytecode-branch-analysis.h" #include "src/compiler/compiler-source-position-table.h" +#include "src/compiler/js-type-hint-lowering.h" #include "src/compiler/linkage.h" #include "src/compiler/operator-properties.h" +#include "src/compiler/simplified-operator.h" #include "src/interpreter/bytecodes.h" #include "src/objects-inl.h" +#include "src/objects/literal-objects.h" namespace v8 { namespace internal { @@ -36,7 +38,6 @@ class BytecodeGraphBuilder::Environment : public ZoneObject { Node* LookupAccumulator() const; Node* LookupRegister(interpreter::Register the_register) const; - void MarkAllRegistersLive(); void BindAccumulator(Node* node, FrameStateAttachmentMode mode = kDontAttachFrameState); @@ -57,7 +58,8 @@ class BytecodeGraphBuilder::Environment : public ZoneObject { // Preserve a checkpoint of the environment for the IR graph. Any // further mutation of the environment will not affect checkpoints. Node* Checkpoint(BailoutId bytecode_offset, OutputFrameStateCombine combine, - bool owner_has_exception); + bool owner_has_exception, + const BytecodeLivenessState* liveness); // Control dependency tracked by this environment. Node* GetControlDependency() const { return control_dependency_; } @@ -68,30 +70,29 @@ class BytecodeGraphBuilder::Environment : public ZoneObject { Node* Context() const { return context_; } void SetContext(Node* new_context) { context_ = new_context; } - Environment* CopyForConditional(); - Environment* CopyForLoop(); - Environment* CopyForOsrEntry(); + Environment* Copy(); void Merge(Environment* other); - void PrepareForOsrEntry(); - void PrepareForLoopExit(Node* loop); + void PrepareForOsrEntry(); + void PrepareForLoop(const BytecodeLoopAssignments& assignments); + void PrepareForLoopExit(Node* loop, + const BytecodeLoopAssignments& assignments); private: - Environment(const Environment* copy, LivenessAnalyzerBlock* liveness_block); - void PrepareForLoop(); + explicit Environment(const Environment* copy); - bool StateValuesRequireUpdate(Node** state_values, int offset, int count); - void UpdateStateValues(Node** state_values, int offset, int count); + bool StateValuesRequireUpdate(Node** state_values, Node** values, int count); + void UpdateStateValues(Node** state_values, Node** values, int count); + void UpdateStateValuesWithCache(Node** state_values, Node** values, int count, + const BitVector* liveness, + int liveness_offset); int RegisterToValuesIndex(interpreter::Register the_register) const; - bool IsLivenessBlockConsistent() const; - Zone* zone() const { return builder_->local_zone(); } Graph* graph() const { return builder_->graph(); } CommonOperatorBuilder* common() const { return builder_->common(); } BytecodeGraphBuilder* builder() const { return builder_; } - LivenessAnalyzerBlock* liveness_block() const { return liveness_block_; } const NodeVector* values() const { return &values_; } NodeVector* values() { return &values_; } int register_base() const { return register_base_; } @@ -100,7 +101,6 @@ class BytecodeGraphBuilder::Environment : public ZoneObject { BytecodeGraphBuilder* builder_; int register_count_; int parameter_count_; - LivenessAnalyzerBlock* liveness_block_; Node* context_; Node* control_dependency_; Node* effect_dependency_; @@ -124,9 +124,6 @@ BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder, : builder_(builder), register_count_(register_count), parameter_count_(parameter_count), - liveness_block_(builder->is_liveness_analysis_enabled_ - ? builder_->liveness_analyzer()->NewBlock() - : nullptr), context_(context), control_dependency_(control_dependency), effect_dependency_(control_dependency), @@ -161,12 +158,10 @@ BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder, } BytecodeGraphBuilder::Environment::Environment( - const BytecodeGraphBuilder::Environment* other, - LivenessAnalyzerBlock* liveness_block) + const BytecodeGraphBuilder::Environment* other) : builder_(other->builder_), register_count_(other->register_count_), parameter_count_(other->parameter_count_), - liveness_block_(liveness_block), context_(other->context_), control_dependency_(other->control_dependency_), effect_dependency_(other->effect_dependency_), @@ -189,16 +184,7 @@ int BytecodeGraphBuilder::Environment::RegisterToValuesIndex( } } -bool BytecodeGraphBuilder::Environment::IsLivenessBlockConsistent() const { - return !builder_->IsLivenessAnalysisEnabled() == - (liveness_block() == nullptr); -} - Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const { - DCHECK(IsLivenessBlockConsistent()); - if (liveness_block() != nullptr) { - liveness_block()->LookupAccumulator(); - } return values()->at(accumulator_base_); } @@ -213,32 +199,15 @@ Node* BytecodeGraphBuilder::Environment::LookupRegister( return builder()->GetNewTarget(); } else { int values_index = RegisterToValuesIndex(the_register); - if (liveness_block() != nullptr && !the_register.is_parameter()) { - DCHECK(IsLivenessBlockConsistent()); - liveness_block()->Lookup(the_register.index()); - } return values()->at(values_index); } } -void BytecodeGraphBuilder::Environment::MarkAllRegistersLive() { - DCHECK(IsLivenessBlockConsistent()); - if (liveness_block() != nullptr) { - for (int i = 0; i < register_count(); ++i) { - liveness_block()->Lookup(i); - } - } -} - void BytecodeGraphBuilder::Environment::BindAccumulator( Node* node, FrameStateAttachmentMode mode) { if (mode == FrameStateAttachmentMode::kAttachFrameState) { builder()->PrepareFrameState(node, OutputFrameStateCombine::PokeAt(0)); } - DCHECK(IsLivenessBlockConsistent()); - if (liveness_block() != nullptr) { - liveness_block()->BindAccumulator(); - } values()->at(accumulator_base_) = node; } @@ -251,10 +220,6 @@ void BytecodeGraphBuilder::Environment::BindRegister( accumulator_base_ - values_index)); } values()->at(values_index) = node; - if (liveness_block() != nullptr && !the_register.is_parameter()) { - DCHECK(IsLivenessBlockConsistent()); - liveness_block()->Bind(the_register.index()); - } } void BytecodeGraphBuilder::Environment::BindRegistersToProjections( @@ -278,45 +243,13 @@ void BytecodeGraphBuilder::Environment::RecordAfterState( } } - -BytecodeGraphBuilder::Environment* -BytecodeGraphBuilder::Environment::CopyForLoop() { - PrepareForLoop(); - if (liveness_block() != nullptr) { - // Finish the current block before copying. - liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block()); - } - return new (zone()) Environment(this, liveness_block()); -} - -BytecodeGraphBuilder::Environment* -BytecodeGraphBuilder::Environment::CopyForOsrEntry() { - return new (zone()) - Environment(this, builder_->liveness_analyzer()->NewBlock()); -} - -BytecodeGraphBuilder::Environment* -BytecodeGraphBuilder::Environment::CopyForConditional() { - LivenessAnalyzerBlock* copy_liveness_block = nullptr; - if (liveness_block() != nullptr) { - copy_liveness_block = - builder_->liveness_analyzer()->NewBlock(liveness_block()); - liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block()); - } - return new (zone()) Environment(this, copy_liveness_block); +BytecodeGraphBuilder::Environment* BytecodeGraphBuilder::Environment::Copy() { + return new (zone()) Environment(this); } void BytecodeGraphBuilder::Environment::Merge( BytecodeGraphBuilder::Environment* other) { - if (builder_->is_liveness_analysis_enabled_) { - if (GetControlDependency()->opcode() != IrOpcode::kLoop) { - liveness_block_ = - builder()->liveness_analyzer()->NewBlock(liveness_block()); - } - liveness_block()->AddPredecessor(other->liveness_block()); - } - // Create a merge of the control dependencies of both environments and update // the current environment's control dependency accordingly. Node* control = builder()->MergeControl(GetControlDependency(), @@ -337,8 +270,8 @@ void BytecodeGraphBuilder::Environment::Merge( } } - -void BytecodeGraphBuilder::Environment::PrepareForLoop() { +void BytecodeGraphBuilder::Environment::PrepareForLoop( + const BytecodeLoopAssignments& assignments) { // Create a control node for the loop header. Node* control = builder()->NewLoop(); @@ -346,11 +279,23 @@ void BytecodeGraphBuilder::Environment::PrepareForLoop() { Node* effect = builder()->NewEffectPhi(1, GetEffectDependency(), control); UpdateEffectDependency(effect); - // Assume everything in the loop is updated. + // Create Phis for any values that may be updated by the end of the loop. context_ = builder()->NewPhi(1, context_, control); - int size = static_cast<int>(values()->size()); - for (int i = 0; i < size; i++) { - values()->at(i) = builder()->NewPhi(1, values()->at(i), control); + for (int i = 0; i < parameter_count(); i++) { + if (assignments.ContainsParameter(i)) { + values_[i] = builder()->NewPhi(1, values_[i], control); + } + } + for (int i = 0; i < register_count(); i++) { + if (assignments.ContainsLocal(i)) { + int index = register_base() + i; + values_[index] = builder()->NewPhi(1, values_[index], control); + } + } + + if (assignments.ContainsAccumulator()) { + values_[accumulator_base()] = + builder()->NewPhi(1, values_[accumulator_base()], control); } // Connect to the loop end. @@ -384,7 +329,7 @@ void BytecodeGraphBuilder::Environment::PrepareForOsrEntry() { BailoutId loop_id(builder_->bytecode_iterator().current_offset()); Node* frame_state = - Checkpoint(loop_id, OutputFrameStateCombine::Ignore(), false); + Checkpoint(loop_id, OutputFrameStateCombine::Ignore(), false, nullptr); Node* checkpoint = graph()->NewNode(common()->Checkpoint(), frame_state, entry, entry); UpdateEffectDependency(checkpoint); @@ -402,22 +347,22 @@ void BytecodeGraphBuilder::Environment::PrepareForOsrEntry() { } bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate( - Node** state_values, int offset, int count) { + Node** state_values, Node** values, int count) { if (*state_values == nullptr) { return true; } - DCHECK_EQ((*state_values)->InputCount(), count); - DCHECK_LE(static_cast<size_t>(offset + count), values()->size()); - Node** env_values = (count == 0) ? nullptr : &values()->at(offset); + Node::Inputs inputs = (*state_values)->inputs(); + if (inputs.count() != count) return true; for (int i = 0; i < count; i++) { - if ((*state_values)->InputAt(i) != env_values[i]) { + if (inputs[i] != values[i]) { return true; } } return false; } -void BytecodeGraphBuilder::Environment::PrepareForLoopExit(Node* loop) { +void BytecodeGraphBuilder::Environment::PrepareForLoopExit( + Node* loop, const BytecodeLoopAssignments& assignments) { DCHECK_EQ(loop->opcode(), IrOpcode::kLoop); Node* control = GetControlDependency(); @@ -431,34 +376,80 @@ void BytecodeGraphBuilder::Environment::PrepareForLoopExit(Node* loop) { GetEffectDependency(), loop_exit); UpdateEffectDependency(effect_rename); - // TODO(jarin) We should also rename context here. However, uncoditional + // TODO(jarin) We should also rename context here. However, unconditional // renaming confuses global object and native context specialization. // We should only rename if the context is assigned in the loop. - // Rename the environmnent values. - for (size_t i = 0; i < values_.size(); i++) { - Node* rename = - graph()->NewNode(common()->LoopExitValue(), values_[i], loop_exit); - values_[i] = rename; + // Rename the environment values if they were assigned in the loop. + for (int i = 0; i < parameter_count(); i++) { + if (assignments.ContainsParameter(i)) { + Node* rename = + graph()->NewNode(common()->LoopExitValue(), values_[i], loop_exit); + values_[i] = rename; + } + } + for (int i = 0; i < register_count(); i++) { + if (assignments.ContainsLocal(i)) { + Node* rename = graph()->NewNode(common()->LoopExitValue(), + values_[register_base() + i], loop_exit); + values_[register_base() + i] = rename; + } + } + + if (assignments.ContainsAccumulator()) { + Node* rename = graph()->NewNode(common()->LoopExitValue(), + values_[accumulator_base()], loop_exit); + values_[accumulator_base()] = rename; } } void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values, - int offset, + Node** values, int count) { - if (StateValuesRequireUpdate(state_values, offset, count)) { - const Operator* op = common()->StateValues(count); - (*state_values) = graph()->NewNode(op, count, &values()->at(offset)); + if (StateValuesRequireUpdate(state_values, values, count)) { + const Operator* op = common()->StateValues(count, SparseInputMask::Dense()); + (*state_values) = graph()->NewNode(op, count, values); } } +void BytecodeGraphBuilder::Environment::UpdateStateValuesWithCache( + Node** state_values, Node** values, int count, const BitVector* liveness, + int liveness_offset) { + *state_values = builder_->state_values_cache_.GetNodeForValues( + values, static_cast<size_t>(count), liveness, liveness_offset); +} + Node* BytecodeGraphBuilder::Environment::Checkpoint( BailoutId bailout_id, OutputFrameStateCombine combine, - bool owner_has_exception) { - UpdateStateValues(¶meters_state_values_, 0, parameter_count()); - UpdateStateValues(®isters_state_values_, register_base(), - register_count()); - UpdateStateValues(&accumulator_state_values_, accumulator_base(), 1); + bool owner_has_exception, const BytecodeLivenessState* liveness) { + if (parameter_count() == register_count()) { + // Re-use the state-value cache if the number of local registers happens + // to match the parameter count. + UpdateStateValuesWithCache(¶meters_state_values_, &values()->at(0), + parameter_count(), nullptr, 0); + } else { + UpdateStateValues(¶meters_state_values_, &values()->at(0), + parameter_count()); + } + + UpdateStateValuesWithCache(®isters_state_values_, + &values()->at(register_base()), register_count(), + liveness ? &liveness->bit_vector() : nullptr, 0); + + bool accumulator_is_live = !liveness || liveness->AccumulatorIsLive(); + if (parameter_count() == 1 && accumulator_is_live && + values()->at(accumulator_base()) == values()->at(0)) { + // Re-use the parameter state values if there happens to only be one + // parameter and the accumulator is live and holds that parameter's value. + accumulator_state_values_ = parameters_state_values_; + } else { + // Otherwise, use the state values cache to hopefully re-use local register + // state values (if there is only one local register), or at the very least + // re-use previous accumulator state values. + UpdateStateValuesWithCache( + &accumulator_state_values_, &values()->at(accumulator_base()), 1, + liveness ? &liveness->bit_vector() : nullptr, register_count()); + } const Operator* op = common()->FrameState( bailout_id, combine, builder()->frame_state_function_info()); @@ -467,51 +458,40 @@ Node* BytecodeGraphBuilder::Environment::Checkpoint( accumulator_state_values_, Context(), builder()->GetFunctionClosure(), builder()->graph()->start()); - if (liveness_block() != nullptr) { - // If the owning node has an exception, register the checkpoint to the - // predecessor so that the checkpoint is used for both the normal and the - // exceptional paths. Yes, this is a terrible hack and we might want - // to use an explicit frame state for the exceptional path. - if (owner_has_exception) { - liveness_block()->GetPredecessor()->Checkpoint(result); - } else { - liveness_block()->Checkpoint(result); - } - } - return result; } BytecodeGraphBuilder::BytecodeGraphBuilder( - Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph, - float invocation_frequency, SourcePositionTable* source_positions, - int inlining_id) + Zone* local_zone, Handle<SharedFunctionInfo> shared_info, + Handle<FeedbackVector> feedback_vector, BailoutId osr_ast_id, + JSGraph* jsgraph, float invocation_frequency, + SourcePositionTable* source_positions, int inlining_id) : local_zone_(local_zone), jsgraph_(jsgraph), invocation_frequency_(invocation_frequency), - bytecode_array_(handle(info->shared_info()->bytecode_array())), + bytecode_array_(handle(shared_info->bytecode_array())), exception_handler_table_( handle(HandlerTable::cast(bytecode_array()->handler_table()))), - feedback_vector_(handle(info->closure()->feedback_vector())), + feedback_vector_(feedback_vector), frame_state_function_info_(common()->CreateFrameStateFunctionInfo( FrameStateType::kInterpretedFunction, bytecode_array()->parameter_count(), - bytecode_array()->register_count(), info->shared_info())), - osr_ast_id_(info->osr_ast_id()), + bytecode_array()->register_count(), shared_info)), + bytecode_iterator_(nullptr), + bytecode_analysis_(nullptr), + environment_(nullptr), + osr_ast_id_(osr_ast_id), + osr_loop_offset_(-1), merge_environments_(local_zone), exception_handlers_(local_zone), current_exception_handler_(0), input_buffer_size_(0), input_buffer_(nullptr), + needs_eager_checkpoint_(true), exit_controls_(local_zone), - is_liveness_analysis_enabled_(FLAG_analyze_environment_liveness && - info->is_deoptimization_enabled()), state_values_cache_(jsgraph), - liveness_analyzer_( - static_cast<size_t>(bytecode_array()->register_count()), true, - local_zone), source_positions_(source_positions), - start_position_(info->shared_info()->start_position(), inlining_id) {} + start_position_(shared_info->start_position(), inlining_id) {} Node* BytecodeGraphBuilder::GetNewTarget() { if (!new_target_.is_set()) { @@ -551,14 +531,16 @@ Node* BytecodeGraphBuilder::GetFunctionClosure() { Node* BytecodeGraphBuilder::BuildLoadNativeContextField(int index) { const Operator* op = javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true); - Node* native_context = NewNode(op, environment()->Context()); - return NewNode(javascript()->LoadContext(0, index, true), native_context); + Node* native_context = NewNode(op); + Node* result = NewNode(javascript()->LoadContext(0, index, true)); + NodeProperties::ReplaceContextInput(result, native_context); + return result; } VectorSlotPair BytecodeGraphBuilder::CreateVectorSlotPair(int slot_id) { - FeedbackVectorSlot slot; - if (slot_id >= TypeFeedbackVector::kReservedIndexCount) { + FeedbackSlot slot; + if (slot_id >= FeedbackVector::kReservedIndexCount) { slot = feedback_vector()->ToSlot(slot_id); } return VectorSlotPair(feedback_vector(), slot); @@ -587,24 +569,42 @@ bool BytecodeGraphBuilder::CreateGraph(bool stack_check) { Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs); graph()->SetEnd(end); - ClearNonLiveSlotsInFrameStates(); - return true; } void BytecodeGraphBuilder::PrepareEagerCheckpoint() { - if (environment()->GetEffectDependency()->opcode() != IrOpcode::kCheckpoint) { + if (needs_eager_checkpoint()) { // Create an explicit checkpoint node for before the operation. This only // needs to happen if we aren't effect-dominated by a {Checkpoint} already. + mark_as_needing_eager_checkpoint(false); Node* node = NewNode(common()->Checkpoint()); DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); DCHECK_EQ(IrOpcode::kDead, NodeProperties::GetFrameStateInput(node)->opcode()); BailoutId bailout_id(bytecode_iterator().current_offset()); + + const BytecodeLivenessState* liveness_before = + bytecode_analysis()->GetInLivenessFor( + bytecode_iterator().current_offset()); + Node* frame_state_before = environment()->Checkpoint( - bailout_id, OutputFrameStateCombine::Ignore(), false); + bailout_id, OutputFrameStateCombine::Ignore(), false, liveness_before); NodeProperties::ReplaceFrameStateInput(node, frame_state_before); +#ifdef DEBUG + } else { + // In case we skipped checkpoint creation above, we must be able to find an + // existing checkpoint that effect-dominates the nodes about to be created. + // Starting a search from the current effect-dependency has to succeed. + Node* effect = environment()->GetEffectDependency(); + while (effect->opcode() != IrOpcode::kCheckpoint) { + DCHECK(effect->op()->HasProperty(Operator::kNoWrite)); + DCHECK_EQ(1, effect->op()->EffectInputCount()); + effect = NodeProperties::GetEffectInput(effect); + } + } +#else } +#endif // DEBUG } void BytecodeGraphBuilder::PrepareFrameState(Node* node, @@ -617,40 +617,36 @@ void BytecodeGraphBuilder::PrepareFrameState(Node* node, NodeProperties::GetFrameStateInput(node)->opcode()); BailoutId bailout_id(bytecode_iterator().current_offset()); bool has_exception = NodeProperties::IsExceptionalCall(node); - Node* frame_state_after = - environment()->Checkpoint(bailout_id, combine, has_exception); - NodeProperties::ReplaceFrameStateInput(node, frame_state_after); - } -} -void BytecodeGraphBuilder::ClearNonLiveSlotsInFrameStates() { - if (!IsLivenessAnalysisEnabled()) { - return; - } - NonLiveFrameStateSlotReplacer replacer( - &state_values_cache_, jsgraph()->OptimizedOutConstant(), - liveness_analyzer()->local_count(), true, local_zone()); - liveness_analyzer()->Run(&replacer); - if (FLAG_trace_environment_liveness) { - OFStream os(stdout); - liveness_analyzer()->Print(os); + const BytecodeLivenessState* liveness_after = + bytecode_analysis()->GetOutLivenessFor( + bytecode_iterator().current_offset()); + + Node* frame_state_after = environment()->Checkpoint( + bailout_id, combine, has_exception, liveness_after); + NodeProperties::ReplaceFrameStateInput(node, frame_state_after); } } void BytecodeGraphBuilder::VisitBytecodes(bool stack_check) { - BytecodeBranchAnalysis analysis(bytecode_array(), local_zone()); - BytecodeLoopAnalysis loop_analysis(bytecode_array(), &analysis, local_zone()); - analysis.Analyze(); - loop_analysis.Analyze(); - set_branch_analysis(&analysis); - set_loop_analysis(&loop_analysis); + BytecodeAnalysis bytecode_analysis(bytecode_array(), local_zone(), + FLAG_analyze_environment_liveness); + bytecode_analysis.Analyze(osr_ast_id_); + set_bytecode_analysis(&bytecode_analysis); interpreter::BytecodeArrayIterator iterator(bytecode_array()); set_bytecode_iterator(&iterator); SourcePositionTableIterator source_position_iterator( bytecode_array()->source_position_table()); + if (FLAG_trace_environment_liveness) { + OFStream of(stdout); + + bytecode_analysis.PrintLivenessTo(of); + } + BuildOSRNormalEntryPoint(); + for (; !iterator.done(); iterator.Advance()) { int current_offset = iterator.current_offset(); UpdateCurrentSourcePosition(&source_position_iterator, current_offset); @@ -658,7 +654,6 @@ void BytecodeGraphBuilder::VisitBytecodes(bool stack_check) { SwitchToMergeEnvironment(current_offset); if (environment() != nullptr) { BuildLoopHeaderEnvironment(current_offset); - BuildOSRLoopEntryPoint(current_offset); // Skip the first stack check if stack_check is false if (!stack_check && @@ -677,8 +672,7 @@ void BytecodeGraphBuilder::VisitBytecodes(bool stack_check) { } } } - - set_branch_analysis(nullptr); + set_bytecode_analysis(nullptr); set_bytecode_iterator(nullptr); DCHECK(exception_handlers_.empty()); } @@ -741,27 +735,32 @@ void BytecodeGraphBuilder::VisitMov() { environment()->BindRegister(bytecode_iterator().GetRegisterOperand(1), value); } -Node* BytecodeGraphBuilder::BuildLoadGlobal(uint32_t feedback_slot_index, +Node* BytecodeGraphBuilder::BuildLoadGlobal(Handle<Name> name, + uint32_t feedback_slot_index, TypeofMode typeof_mode) { VectorSlotPair feedback = CreateVectorSlotPair(feedback_slot_index); - DCHECK_EQ(FeedbackVectorSlotKind::LOAD_GLOBAL_IC, - feedback_vector()->GetKind(feedback.slot())); - Handle<Name> name(feedback_vector()->GetName(feedback.slot())); + DCHECK(IsLoadGlobalICKind(feedback_vector()->GetKind(feedback.slot()))); const Operator* op = javascript()->LoadGlobal(name, feedback, typeof_mode); - return NewNode(op, GetFunctionClosure()); + return NewNode(op); } void BytecodeGraphBuilder::VisitLdaGlobal() { PrepareEagerCheckpoint(); - Node* node = BuildLoadGlobal(bytecode_iterator().GetIndexOperand(0), - TypeofMode::NOT_INSIDE_TYPEOF); + Handle<Name> name = + Handle<Name>::cast(bytecode_iterator().GetConstantForIndexOperand(0)); + uint32_t feedback_slot_index = bytecode_iterator().GetIndexOperand(1); + Node* node = + BuildLoadGlobal(name, feedback_slot_index, TypeofMode::NOT_INSIDE_TYPEOF); environment()->BindAccumulator(node, Environment::kAttachFrameState); } void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeof() { PrepareEagerCheckpoint(); - Node* node = BuildLoadGlobal(bytecode_iterator().GetIndexOperand(0), - TypeofMode::INSIDE_TYPEOF); + Handle<Name> name = + Handle<Name>::cast(bytecode_iterator().GetConstantForIndexOperand(0)); + uint32_t feedback_slot_index = bytecode_iterator().GetIndexOperand(1); + Node* node = + BuildLoadGlobal(name, feedback_slot_index, TypeofMode::INSIDE_TYPEOF); environment()->BindAccumulator(node, Environment::kAttachFrameState); } @@ -774,7 +773,7 @@ void BytecodeGraphBuilder::BuildStoreGlobal(LanguageMode language_mode) { Node* value = environment()->LookupAccumulator(); const Operator* op = javascript()->StoreGlobal(language_mode, name, feedback); - Node* node = NewNode(op, value, GetFunctionClosure()); + Node* node = NewNode(op, value); environment()->RecordAfterState(node, Environment::kAttachFrameState); } @@ -786,27 +785,56 @@ void BytecodeGraphBuilder::VisitStaGlobalStrict() { BuildStoreGlobal(LanguageMode::STRICT); } +void BytecodeGraphBuilder::VisitStaDataPropertyInLiteral() { + PrepareEagerCheckpoint(); + + Node* object = + environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); + Node* name = + environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1)); + Node* value = environment()->LookupAccumulator(); + int flags = bytecode_iterator().GetFlagOperand(2); + VectorSlotPair feedback = + CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(3)); + + const Operator* op = javascript()->StoreDataPropertyInLiteral(feedback); + Node* node = NewNode(op, object, name, value, jsgraph()->Constant(flags)); + environment()->RecordAfterState(node, Environment::kAttachFrameState); +} + void BytecodeGraphBuilder::VisitLdaContextSlot() { - // TODO(mythria): immutable flag is also set to false. This information is not - // available in bytecode array. update this code when the implementation - // changes. const Operator* op = javascript()->LoadContext( bytecode_iterator().GetUnsignedImmediateOperand(2), bytecode_iterator().GetIndexOperand(1), false); + Node* node = NewNode(op); + Node* context = + environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); + NodeProperties::ReplaceContextInput(node, context); + environment()->BindAccumulator(node); +} + +void BytecodeGraphBuilder::VisitLdaImmutableContextSlot() { + const Operator* op = javascript()->LoadContext( + bytecode_iterator().GetUnsignedImmediateOperand(2), + bytecode_iterator().GetIndexOperand(1), true); + Node* node = NewNode(op); Node* context = environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); - Node* node = NewNode(op, context); + NodeProperties::ReplaceContextInput(node, context); environment()->BindAccumulator(node); } void BytecodeGraphBuilder::VisitLdaCurrentContextSlot() { - // TODO(mythria): immutable flag is also set to false. This information is not - // available in bytecode array. update this code when the implementation - // changes. const Operator* op = javascript()->LoadContext( 0, bytecode_iterator().GetIndexOperand(0), false); - Node* context = environment()->Context(); - Node* node = NewNode(op, context); + Node* node = NewNode(op); + environment()->BindAccumulator(node); +} + +void BytecodeGraphBuilder::VisitLdaImmutableCurrentContextSlot() { + const Operator* op = javascript()->LoadContext( + 0, bytecode_iterator().GetIndexOperand(0), true); + Node* node = NewNode(op); environment()->BindAccumulator(node); } @@ -814,18 +842,18 @@ void BytecodeGraphBuilder::VisitStaContextSlot() { const Operator* op = javascript()->StoreContext( bytecode_iterator().GetUnsignedImmediateOperand(2), bytecode_iterator().GetIndexOperand(1)); + Node* value = environment()->LookupAccumulator(); + Node* node = NewNode(op, value); Node* context = environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); - Node* value = environment()->LookupAccumulator(); - NewNode(op, context, value); + NodeProperties::ReplaceContextInput(node, context); } void BytecodeGraphBuilder::VisitStaCurrentContextSlot() { const Operator* op = javascript()->StoreContext(0, bytecode_iterator().GetIndexOperand(0)); - Node* context = environment()->Context(); Node* value = environment()->LookupAccumulator(); - NewNode(op, context, value); + NewNode(op, value); } void BytecodeGraphBuilder::BuildLdaLookupSlot(TypeofMode typeof_mode) { @@ -857,15 +885,14 @@ BytecodeGraphBuilder::Environment* BytecodeGraphBuilder::CheckContextExtensions( // the same scope as the variable itself has no way of shadowing it. for (uint32_t d = 0; d < depth; d++) { Node* extension_slot = - NewNode(javascript()->LoadContext(d, Context::EXTENSION_INDEX, false), - environment()->Context()); + NewNode(javascript()->LoadContext(d, Context::EXTENSION_INDEX, false)); Node* check_no_extension = - NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), - extension_slot, jsgraph()->TheHoleConstant()); + NewNode(simplified()->ReferenceEqual(), extension_slot, + jsgraph()->TheHoleConstant()); NewBranch(check_no_extension); - Environment* true_environment = environment()->CopyForConditional(); + Environment* true_environment = environment()->Copy(); { NewIfFalse(); @@ -904,8 +931,7 @@ void BytecodeGraphBuilder::BuildLdaLookupContextSlot(TypeofMode typeof_mode) { uint32_t slot_index = bytecode_iterator().GetIndexOperand(1); const Operator* op = javascript()->LoadContext(depth, slot_index, false); - Node* context = environment()->Context(); - environment()->BindAccumulator(NewNode(op, context)); + environment()->BindAccumulator(NewNode(op)); } // Only build the slow path if there were any slow-path checks. @@ -930,6 +956,7 @@ void BytecodeGraphBuilder::BuildLdaLookupContextSlot(TypeofMode typeof_mode) { fast_environment->Merge(environment()); set_environment(fast_environment); + mark_as_needing_eager_checkpoint(true); } } @@ -950,8 +977,10 @@ void BytecodeGraphBuilder::BuildLdaLookupGlobalSlot(TypeofMode typeof_mode) { // Fast path, do a global load. { PrepareEagerCheckpoint(); - Node* node = - BuildLoadGlobal(bytecode_iterator().GetIndexOperand(1), typeof_mode); + Handle<Name> name = + Handle<Name>::cast(bytecode_iterator().GetConstantForIndexOperand(0)); + uint32_t feedback_slot_index = bytecode_iterator().GetIndexOperand(1); + Node* node = BuildLoadGlobal(name, feedback_slot_index, typeof_mode); environment()->BindAccumulator(node, Environment::kAttachFrameState); } @@ -977,6 +1006,7 @@ void BytecodeGraphBuilder::BuildLdaLookupGlobalSlot(TypeofMode typeof_mode) { fast_environment->Merge(environment()); set_environment(fast_environment); + mark_as_needing_eager_checkpoint(true); } } @@ -1018,7 +1048,7 @@ void BytecodeGraphBuilder::VisitLdaNamedProperty() { CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2)); const Operator* op = javascript()->LoadNamed(name, feedback); - Node* node = NewNode(op, object, GetFunctionClosure()); + Node* node = NewNode(op, object); environment()->BindAccumulator(node, Environment::kAttachFrameState); } @@ -1031,11 +1061,12 @@ void BytecodeGraphBuilder::VisitLdaKeyedProperty() { CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(1)); const Operator* op = javascript()->LoadProperty(feedback); - Node* node = NewNode(op, object, key, GetFunctionClosure()); + Node* node = NewNode(op, object, key); environment()->BindAccumulator(node, Environment::kAttachFrameState); } -void BytecodeGraphBuilder::BuildNamedStore(LanguageMode language_mode) { +void BytecodeGraphBuilder::BuildNamedStore(LanguageMode language_mode, + StoreMode store_mode) { PrepareEagerCheckpoint(); Node* value = environment()->LookupAccumulator(); Node* object = @@ -1045,17 +1076,31 @@ void BytecodeGraphBuilder::BuildNamedStore(LanguageMode language_mode) { VectorSlotPair feedback = CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2)); - const Operator* op = javascript()->StoreNamed(language_mode, name, feedback); - Node* node = NewNode(op, object, value, GetFunctionClosure()); + const Operator* op; + if (store_mode == StoreMode::kOwn) { + DCHECK_EQ(FeedbackSlotKind::kStoreOwnNamed, + feedback.vector()->GetKind(feedback.slot())); + op = javascript()->StoreNamedOwn(name, feedback); + } else { + DCHECK(store_mode == StoreMode::kNormal); + DCHECK_EQ(feedback.vector()->GetLanguageMode(feedback.slot()), + language_mode); + op = javascript()->StoreNamed(language_mode, name, feedback); + } + Node* node = NewNode(op, object, value); environment()->RecordAfterState(node, Environment::kAttachFrameState); } void BytecodeGraphBuilder::VisitStaNamedPropertySloppy() { - BuildNamedStore(LanguageMode::SLOPPY); + BuildNamedStore(LanguageMode::SLOPPY, StoreMode::kNormal); } void BytecodeGraphBuilder::VisitStaNamedPropertyStrict() { - BuildNamedStore(LanguageMode::STRICT); + BuildNamedStore(LanguageMode::STRICT, StoreMode::kNormal); +} + +void BytecodeGraphBuilder::VisitStaNamedOwnProperty() { + BuildNamedStore(LanguageMode::STRICT, StoreMode::kOwn); } void BytecodeGraphBuilder::BuildKeyedStore(LanguageMode language_mode) { @@ -1068,8 +1113,9 @@ void BytecodeGraphBuilder::BuildKeyedStore(LanguageMode language_mode) { VectorSlotPair feedback = CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2)); + DCHECK_EQ(feedback.vector()->GetLanguageMode(feedback.slot()), language_mode); const Operator* op = javascript()->StoreProperty(language_mode, feedback); - Node* node = NewNode(op, object, key, value, GetFunctionClosure()); + Node* node = NewNode(op, object, key, value); environment()->RecordAfterState(node, Environment::kAttachFrameState); } @@ -1085,8 +1131,7 @@ void BytecodeGraphBuilder::VisitLdaModuleVariable() { int32_t cell_index = bytecode_iterator().GetImmediateOperand(0); uint32_t depth = bytecode_iterator().GetUnsignedImmediateOperand(1); Node* module = - NewNode(javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false), - environment()->Context()); + NewNode(javascript()->LoadContext(depth, Context::EXTENSION_INDEX, true)); Node* value = NewNode(javascript()->LoadModule(cell_index), module); environment()->BindAccumulator(value); } @@ -1095,8 +1140,7 @@ void BytecodeGraphBuilder::VisitStaModuleVariable() { int32_t cell_index = bytecode_iterator().GetImmediateOperand(0); uint32_t depth = bytecode_iterator().GetUnsignedImmediateOperand(1); Node* module = - NewNode(javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false), - environment()->Context()); + NewNode(javascript()->LoadContext(depth, Context::EXTENSION_INDEX, true)); Node* value = environment()->LookupAccumulator(); NewNode(javascript()->StoreModule(cell_index), module, value); } @@ -1117,12 +1161,14 @@ void BytecodeGraphBuilder::VisitPopContext() { void BytecodeGraphBuilder::VisitCreateClosure() { Handle<SharedFunctionInfo> shared_info = Handle<SharedFunctionInfo>::cast( bytecode_iterator().GetConstantForIndexOperand(0)); + int const slot_id = bytecode_iterator().GetIndexOperand(1); + VectorSlotPair pair = CreateVectorSlotPair(slot_id); PretenureFlag tenured = interpreter::CreateClosureFlags::PretenuredBit::decode( - bytecode_iterator().GetFlagOperand(1)) + bytecode_iterator().GetFlagOperand(2)) ? TENURED : NOT_TENURED; - const Operator* op = javascript()->CreateClosure(shared_info, tenured); + const Operator* op = javascript()->CreateClosure(shared_info, pair, tenured); Node* closure = NewNode(op); environment()->BindAccumulator(closure); } @@ -1138,7 +1184,15 @@ void BytecodeGraphBuilder::VisitCreateBlockContext() { void BytecodeGraphBuilder::VisitCreateFunctionContext() { uint32_t slots = bytecode_iterator().GetUnsignedImmediateOperand(0); - const Operator* op = javascript()->CreateFunctionContext(slots); + const Operator* op = + javascript()->CreateFunctionContext(slots, FUNCTION_SCOPE); + Node* context = NewNode(op, GetFunctionClosure()); + environment()->BindAccumulator(context); +} + +void BytecodeGraphBuilder::VisitCreateEvalContext() { + uint32_t slots = bytecode_iterator().GetUnsignedImmediateOperand(0); + const Operator* op = javascript()->CreateFunctionContext(slots, EVAL_SCOPE); Node* context = NewNode(op, GetFunctionClosure()); environment()->BindAccumulator(context); } @@ -1198,16 +1252,21 @@ void BytecodeGraphBuilder::VisitCreateRegExpLiteral() { } void BytecodeGraphBuilder::VisitCreateArrayLiteral() { - Handle<FixedArray> constant_elements = Handle<FixedArray>::cast( - bytecode_iterator().GetConstantForIndexOperand(0)); + Handle<ConstantElementsPair> constant_elements = + Handle<ConstantElementsPair>::cast( + bytecode_iterator().GetConstantForIndexOperand(0)); int literal_index = bytecode_iterator().GetIndexOperand(1); - int literal_flags = bytecode_iterator().GetFlagOperand(2); + int bytecode_flags = bytecode_iterator().GetFlagOperand(2); + int literal_flags = + interpreter::CreateArrayLiteralFlags::FlagsBits::decode(bytecode_flags); // Disable allocation site mementos. Only unoptimized code will collect // feedback about allocation site. Once the code is optimized we expect the // data to converge. So, we disable allocation site mementos in optimized // code. We can revisit this when we have data to the contrary. literal_flags |= ArrayLiteral::kDisableMementos; - int number_of_elements = constant_elements->length(); + // TODO(mstarzinger): Thread through number of elements. The below number is + // only an estimate and does not match {ArrayLiteral::values::length}. + int number_of_elements = constant_elements->constant_values()->length(); Node* literal = NewNode( javascript()->CreateLiteralArray(constant_elements, literal_flags, literal_index, number_of_elements), @@ -1216,15 +1275,16 @@ void BytecodeGraphBuilder::VisitCreateArrayLiteral() { } void BytecodeGraphBuilder::VisitCreateObjectLiteral() { - PrepareEagerCheckpoint(); - Handle<FixedArray> constant_properties = Handle<FixedArray>::cast( - bytecode_iterator().GetConstantForIndexOperand(0)); + Handle<BoilerplateDescription> constant_properties = + Handle<BoilerplateDescription>::cast( + bytecode_iterator().GetConstantForIndexOperand(0)); int literal_index = bytecode_iterator().GetIndexOperand(1); int bytecode_flags = bytecode_iterator().GetFlagOperand(2); int literal_flags = interpreter::CreateObjectLiteralFlags::FlagsBits::decode(bytecode_flags); - // TODO(mstarzinger): Thread through number of properties. - int number_of_properties = constant_properties->length() / 2; + // TODO(mstarzinger): Thread through number of properties. The below number is + // only an estimate and does not match {ObjectLiteral::properties_count}. + int number_of_properties = constant_properties->size(); Node* literal = NewNode( javascript()->CreateLiteralObject(constant_properties, literal_flags, literal_index, number_of_properties), @@ -1260,13 +1320,13 @@ void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode, // Slot index of 0 is used indicate no feedback slot is available. Assert // the assumption that slot index 0 is never a valid feedback slot. - STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0); + STATIC_ASSERT(FeedbackVector::kReservedIndexCount > 0); int const slot_id = bytecode_iterator().GetIndexOperand(3); VectorSlotPair feedback = CreateVectorSlotPair(slot_id); float const frequency = ComputeCallFrequency(slot_id); - const Operator* call = javascript()->CallFunction( - arg_count + 1, frequency, feedback, receiver_hint, tail_call_mode); + const Operator* call = javascript()->Call(arg_count + 1, frequency, feedback, + receiver_hint, tail_call_mode); Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 1); environment()->BindAccumulator(value, Environment::kAttachFrameState); } @@ -1275,6 +1335,19 @@ void BytecodeGraphBuilder::VisitCall() { BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kAny); } +void BytecodeGraphBuilder::VisitCallWithSpread() { + PrepareEagerCheckpoint(); + Node* callee = + environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); + interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1); + size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2); + const Operator* call = + javascript()->CallWithSpread(static_cast<int>(arg_count + 1)); + + Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 1); + environment()->BindAccumulator(value, Environment::kAttachFrameState); +} + void BytecodeGraphBuilder::VisitCallProperty() { BuildCall(TailCallMode::kDisallow, ConvertReceiverMode::kNotNullOrUndefined); } @@ -1295,7 +1368,7 @@ void BytecodeGraphBuilder::VisitCallJSRuntime() { size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2); // Create node to perform the JS runtime call. - const Operator* call = javascript()->CallFunction(arg_count + 1); + const Operator* call = javascript()->Call(arg_count + 1); Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 1); environment()->BindAccumulator(value, Environment::kAttachFrameState); } @@ -1340,6 +1413,37 @@ void BytecodeGraphBuilder::VisitCallRuntimeForPair() { Environment::kAttachFrameState); } +Node* BytecodeGraphBuilder::ProcessConstructWithSpreadArguments( + const Operator* op, Node* callee, Node* new_target, + interpreter::Register first_arg, size_t arity) { + Node** all = local_zone()->NewArray<Node*>(arity); + all[0] = callee; + int first_arg_index = first_arg.index(); + for (int i = 1; i < static_cast<int>(arity) - 1; ++i) { + all[i] = environment()->LookupRegister( + interpreter::Register(first_arg_index + i - 1)); + } + all[arity - 1] = new_target; + Node* value = MakeNode(op, static_cast<int>(arity), all, false); + return value; +} + +void BytecodeGraphBuilder::VisitConstructWithSpread() { + PrepareEagerCheckpoint(); + interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0); + interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1); + size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2); + + Node* new_target = environment()->LookupAccumulator(); + Node* callee = environment()->LookupRegister(callee_reg); + + const Operator* op = + javascript()->ConstructWithSpread(static_cast<int>(arg_count) + 2); + Node* value = ProcessConstructWithSpreadArguments(op, callee, new_target, + first_arg, arg_count + 2); + environment()->BindAccumulator(value, Environment::kAttachFrameState); +} + void BytecodeGraphBuilder::VisitInvokeIntrinsic() { PrepareEagerCheckpoint(); Runtime::FunctionId functionId = bytecode_iterator().GetIntrinsicIdOperand(0); @@ -1353,7 +1457,7 @@ void BytecodeGraphBuilder::VisitInvokeIntrinsic() { environment()->BindAccumulator(value, Environment::kAttachFrameState); } -Node* BytecodeGraphBuilder::ProcessCallNewArguments( +Node* BytecodeGraphBuilder::ProcessConstructArguments( const Operator* call_new_op, Node* callee, Node* new_target, interpreter::Register first_arg, size_t arity) { Node** all = local_zone()->NewArray<Node*>(arity); @@ -1368,14 +1472,14 @@ Node* BytecodeGraphBuilder::ProcessCallNewArguments( return value; } -void BytecodeGraphBuilder::VisitNew() { +void BytecodeGraphBuilder::VisitConstruct() { PrepareEagerCheckpoint(); interpreter::Register callee_reg = bytecode_iterator().GetRegisterOperand(0); interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1); size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2); // Slot index of 0 is used indicate no feedback slot is available. Assert // the assumption that slot index 0 is never a valid feedback slot. - STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0); + STATIC_ASSERT(FeedbackVector::kReservedIndexCount > 0); int const slot_id = bytecode_iterator().GetIndexOperand(3); VectorSlotPair feedback = CreateVectorSlotPair(slot_id); @@ -1383,24 +1487,18 @@ void BytecodeGraphBuilder::VisitNew() { Node* callee = environment()->LookupRegister(callee_reg); float const frequency = ComputeCallFrequency(slot_id); - const Operator* call = javascript()->CallConstruct( + const Operator* call = javascript()->Construct( static_cast<int>(arg_count) + 2, frequency, feedback); - Node* value = ProcessCallNewArguments(call, callee, new_target, first_arg, - arg_count + 2); + Node* value = ProcessConstructArguments(call, callee, new_target, first_arg, + arg_count + 2); environment()->BindAccumulator(value, Environment::kAttachFrameState); } -void BytecodeGraphBuilder::BuildThrow() { - PrepareEagerCheckpoint(); +void BytecodeGraphBuilder::VisitThrow() { + BuildLoopExitsForFunctionExit(); Node* value = environment()->LookupAccumulator(); Node* call = NewNode(javascript()->CallRuntime(Runtime::kThrow), value); environment()->BindAccumulator(call, Environment::kAttachFrameState); -} - -void BytecodeGraphBuilder::VisitThrow() { - BuildLoopExitsForFunctionExit(); - BuildThrow(); - Node* call = environment()->LookupAccumulator(); Node* control = NewNode(common()->Throw(), call); MergeControlToLeaveFunction(control); } @@ -1413,12 +1511,39 @@ void BytecodeGraphBuilder::VisitReThrow() { MergeControlToLeaveFunction(control); } -void BytecodeGraphBuilder::BuildBinaryOp(const Operator* js_op) { +Node* BytecodeGraphBuilder::TryBuildSimplifiedBinaryOp(const Operator* op, + Node* left, Node* right, + FeedbackSlot slot) { + Node* effect = environment()->GetEffectDependency(); + Node* control = environment()->GetControlDependency(); + JSTypeHintLowering type_hint_lowering(jsgraph(), feedback_vector()); + Reduction early_reduction = type_hint_lowering.ReduceBinaryOperation( + op, left, right, effect, control, slot); + if (early_reduction.Changed()) { + Node* node = early_reduction.replacement(); + if (node->op()->EffectOutputCount() > 0) { + environment()->UpdateEffectDependency(node); + } + return node; + } + return nullptr; +} + +void BytecodeGraphBuilder::BuildBinaryOp(const Operator* op) { PrepareEagerCheckpoint(); Node* left = environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); Node* right = environment()->LookupAccumulator(); - Node* node = NewNode(js_op, left, right); + + Node* node = nullptr; + FeedbackSlot slot = feedback_vector()->ToSlot( + bytecode_iterator().GetIndexOperand(kBinaryOperationHintIndex)); + if (Node* simplified = TryBuildSimplifiedBinaryOp(op, left, right, slot)) { + node = simplified; + } else { + node = NewNode(op, left, right); + } + environment()->BindAccumulator(node, Environment::kAttachFrameState); } @@ -1426,10 +1551,9 @@ void BytecodeGraphBuilder::BuildBinaryOp(const Operator* js_op) { // feedback. BinaryOperationHint BytecodeGraphBuilder::GetBinaryOperationHint( int operand_index) { - FeedbackVectorSlot slot = feedback_vector()->ToSlot( + FeedbackSlot slot = feedback_vector()->ToSlot( bytecode_iterator().GetIndexOperand(operand_index)); - DCHECK_EQ(FeedbackVectorSlotKind::INTERPRETER_BINARYOP_IC, - feedback_vector()->GetKind(slot)); + DCHECK_EQ(FeedbackSlotKind::kBinaryOp, feedback_vector()->GetKind(slot)); BinaryOpICNexus nexus(feedback_vector(), slot); return nexus.GetBinaryOperationFeedback(); } @@ -1441,10 +1565,9 @@ CompareOperationHint BytecodeGraphBuilder::GetCompareOperationHint() { if (slot_index == 0) { return CompareOperationHint::kAny; } - FeedbackVectorSlot slot = + FeedbackSlot slot = feedback_vector()->ToSlot(bytecode_iterator().GetIndexOperand(1)); - DCHECK_EQ(FeedbackVectorSlotKind::INTERPRETER_COMPARE_IC, - feedback_vector()->GetKind(slot)); + DCHECK_EQ(FeedbackSlotKind::kCompareOp, feedback_vector()->GetKind(slot)); CompareICNexus nexus(feedback_vector(), slot); return nexus.GetCompareOperationFeedback(); } @@ -1460,61 +1583,58 @@ void BytecodeGraphBuilder::VisitAdd() { } void BytecodeGraphBuilder::VisitSub() { - BuildBinaryOp(javascript()->Subtract( - GetBinaryOperationHint(kBinaryOperationHintIndex))); + BuildBinaryOp(javascript()->Subtract()); } void BytecodeGraphBuilder::VisitMul() { - BuildBinaryOp(javascript()->Multiply( - GetBinaryOperationHint(kBinaryOperationHintIndex))); + BuildBinaryOp(javascript()->Multiply()); } -void BytecodeGraphBuilder::VisitDiv() { - BuildBinaryOp( - javascript()->Divide(GetBinaryOperationHint(kBinaryOperationHintIndex))); -} +void BytecodeGraphBuilder::VisitDiv() { BuildBinaryOp(javascript()->Divide()); } void BytecodeGraphBuilder::VisitMod() { - BuildBinaryOp( - javascript()->Modulus(GetBinaryOperationHint(kBinaryOperationHintIndex))); + BuildBinaryOp(javascript()->Modulus()); } void BytecodeGraphBuilder::VisitBitwiseOr() { - BuildBinaryOp(javascript()->BitwiseOr( - GetBinaryOperationHint(kBinaryOperationHintIndex))); + BuildBinaryOp(javascript()->BitwiseOr()); } void BytecodeGraphBuilder::VisitBitwiseXor() { - BuildBinaryOp(javascript()->BitwiseXor( - GetBinaryOperationHint(kBinaryOperationHintIndex))); + BuildBinaryOp(javascript()->BitwiseXor()); } void BytecodeGraphBuilder::VisitBitwiseAnd() { - BuildBinaryOp(javascript()->BitwiseAnd( - GetBinaryOperationHint(kBinaryOperationHintIndex))); + BuildBinaryOp(javascript()->BitwiseAnd()); } void BytecodeGraphBuilder::VisitShiftLeft() { - BuildBinaryOp(javascript()->ShiftLeft( - GetBinaryOperationHint(kBinaryOperationHintIndex))); + BuildBinaryOp(javascript()->ShiftLeft()); } void BytecodeGraphBuilder::VisitShiftRight() { - BuildBinaryOp(javascript()->ShiftRight( - GetBinaryOperationHint(kBinaryOperationHintIndex))); + BuildBinaryOp(javascript()->ShiftRight()); } void BytecodeGraphBuilder::VisitShiftRightLogical() { - BuildBinaryOp(javascript()->ShiftRightLogical( - GetBinaryOperationHint(kBinaryOperationHintIndex))); + BuildBinaryOp(javascript()->ShiftRightLogical()); } -void BytecodeGraphBuilder::BuildBinaryOpWithImmediate(const Operator* js_op) { +void BytecodeGraphBuilder::BuildBinaryOpWithImmediate(const Operator* op) { PrepareEagerCheckpoint(); Node* left = environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1)); Node* right = jsgraph()->Constant(bytecode_iterator().GetImmediateOperand(0)); - Node* node = NewNode(js_op, left, right); + + Node* node = nullptr; + FeedbackSlot slot = feedback_vector()->ToSlot( + bytecode_iterator().GetIndexOperand(kBinaryOperationSmiHintIndex)); + if (Node* simplified = TryBuildSimplifiedBinaryOp(op, left, right, slot)) { + node = simplified; + } else { + node = NewNode(op, left, right); + } + environment()->BindAccumulator(node, Environment::kAttachFrameState); } @@ -1524,62 +1644,73 @@ void BytecodeGraphBuilder::VisitAddSmi() { } void BytecodeGraphBuilder::VisitSubSmi() { - BuildBinaryOpWithImmediate(javascript()->Subtract( - GetBinaryOperationHint(kBinaryOperationSmiHintIndex))); + BuildBinaryOpWithImmediate(javascript()->Subtract()); } void BytecodeGraphBuilder::VisitBitwiseOrSmi() { - BuildBinaryOpWithImmediate(javascript()->BitwiseOr( - GetBinaryOperationHint(kBinaryOperationSmiHintIndex))); + BuildBinaryOpWithImmediate(javascript()->BitwiseOr()); } void BytecodeGraphBuilder::VisitBitwiseAndSmi() { - BuildBinaryOpWithImmediate(javascript()->BitwiseAnd( - GetBinaryOperationHint(kBinaryOperationSmiHintIndex))); + BuildBinaryOpWithImmediate(javascript()->BitwiseAnd()); } void BytecodeGraphBuilder::VisitShiftLeftSmi() { - BuildBinaryOpWithImmediate(javascript()->ShiftLeft( - GetBinaryOperationHint(kBinaryOperationSmiHintIndex))); + BuildBinaryOpWithImmediate(javascript()->ShiftLeft()); } void BytecodeGraphBuilder::VisitShiftRightSmi() { - BuildBinaryOpWithImmediate(javascript()->ShiftRight( - GetBinaryOperationHint(kBinaryOperationSmiHintIndex))); + BuildBinaryOpWithImmediate(javascript()->ShiftRight()); } void BytecodeGraphBuilder::VisitInc() { PrepareEagerCheckpoint(); // Note: Use subtract -1 here instead of add 1 to ensure we always convert to // a number, not a string. - const Operator* js_op = - javascript()->Subtract(GetBinaryOperationHint(kCountOperationHintIndex)); - Node* node = NewNode(js_op, environment()->LookupAccumulator(), - jsgraph()->Constant(-1)); + Node* left = environment()->LookupAccumulator(); + Node* right = jsgraph()->Constant(-1); + const Operator* op = javascript()->Subtract(); + + Node* node = nullptr; + FeedbackSlot slot = feedback_vector()->ToSlot( + bytecode_iterator().GetIndexOperand(kCountOperationHintIndex)); + if (Node* simplified = TryBuildSimplifiedBinaryOp(op, left, right, slot)) { + node = simplified; + } else { + node = NewNode(op, left, right); + } + environment()->BindAccumulator(node, Environment::kAttachFrameState); } void BytecodeGraphBuilder::VisitDec() { PrepareEagerCheckpoint(); - const Operator* js_op = - javascript()->Subtract(GetBinaryOperationHint(kCountOperationHintIndex)); - Node* node = NewNode(js_op, environment()->LookupAccumulator(), - jsgraph()->OneConstant()); + Node* left = environment()->LookupAccumulator(); + Node* right = jsgraph()->OneConstant(); + const Operator* op = javascript()->Subtract(); + + Node* node = nullptr; + FeedbackSlot slot = feedback_vector()->ToSlot( + bytecode_iterator().GetIndexOperand(kCountOperationHintIndex)); + if (Node* simplified = TryBuildSimplifiedBinaryOp(op, left, right, slot)) { + node = simplified; + } else { + node = NewNode(op, left, right); + } + environment()->BindAccumulator(node, Environment::kAttachFrameState); } void BytecodeGraphBuilder::VisitLogicalNot() { Node* value = environment()->LookupAccumulator(); - Node* node = NewNode(common()->Select(MachineRepresentation::kTagged), value, - jsgraph()->FalseConstant(), jsgraph()->TrueConstant()); + Node* node = NewNode(simplified()->BooleanNot(), value); environment()->BindAccumulator(node); } void BytecodeGraphBuilder::VisitToBooleanLogicalNot() { Node* value = NewNode(javascript()->ToBoolean(ToBooleanHint::kAny), environment()->LookupAccumulator()); - Node* node = NewNode(common()->Select(MachineRepresentation::kTagged), value, - jsgraph()->FalseConstant(), jsgraph()->TrueConstant()); + Node* node = NewNode(simplified()->BooleanNot(), value); environment()->BindAccumulator(node); } @@ -1607,6 +1738,13 @@ void BytecodeGraphBuilder::VisitDeletePropertySloppy() { BuildDelete(LanguageMode::SLOPPY); } +void BytecodeGraphBuilder::VisitGetSuperConstructor() { + Node* node = NewNode(javascript()->GetSuperConstructor(), + environment()->LookupAccumulator()); + environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0), node, + Environment::kAttachFrameState); +} + void BytecodeGraphBuilder::BuildCompareOp(const Operator* js_op) { PrepareEagerCheckpoint(); Node* left = @@ -1652,8 +1790,30 @@ void BytecodeGraphBuilder::VisitTestInstanceOf() { BuildCompareOp(javascript()->InstanceOf()); } +void BytecodeGraphBuilder::VisitTestUndetectable() { + Node* object = + environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); + Node* node = NewNode(jsgraph()->simplified()->ObjectIsUndetectable(), object); + environment()->BindAccumulator(node); +} + +void BytecodeGraphBuilder::VisitTestNull() { + Node* object = + environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); + Node* result = NewNode(simplified()->ReferenceEqual(), object, + jsgraph()->NullConstant()); + environment()->BindAccumulator(result); +} + +void BytecodeGraphBuilder::VisitTestUndefined() { + Node* object = + environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); + Node* result = NewNode(simplified()->ReferenceEqual(), object, + jsgraph()->UndefinedConstant()); + environment()->BindAccumulator(result); +} + void BytecodeGraphBuilder::BuildCastOperator(const Operator* js_op) { - PrepareEagerCheckpoint(); Node* value = NewNode(js_op, environment()->LookupAccumulator()); environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0), value, Environment::kAttachFrameState); @@ -1705,6 +1865,12 @@ void BytecodeGraphBuilder::VisitJumpIfNotHoleConstant() { BuildJumpIfNotHole(); } +void BytecodeGraphBuilder::VisitJumpIfJSReceiver() { BuildJumpIfJSReceiver(); } + +void BytecodeGraphBuilder::VisitJumpIfJSReceiverConstant() { + BuildJumpIfJSReceiver(); +} + void BytecodeGraphBuilder::VisitJumpIfNull() { BuildJumpIfEqual(jsgraph()->NullConstant()); } @@ -1729,6 +1895,12 @@ void BytecodeGraphBuilder::VisitStackCheck() { environment()->RecordAfterState(node, Environment::kAttachFrameState); } +void BytecodeGraphBuilder::VisitSetPendingMessage() { + Node* previous_message = NewNode(javascript()->LoadMessage()); + NewNode(javascript()->StoreMessage(), environment()->LookupAccumulator()); + environment()->BindAccumulator(previous_message); +} + void BytecodeGraphBuilder::VisitReturn() { BuildLoopExitsForFunctionExit(); Node* pop_node = jsgraph()->ZeroConstant(); @@ -1739,10 +1911,8 @@ void BytecodeGraphBuilder::VisitReturn() { void BytecodeGraphBuilder::VisitDebugger() { PrepareEagerCheckpoint(); - Node* call = - NewNode(javascript()->CallRuntime(Runtime::kHandleDebuggerStatement)); - environment()->BindAccumulator(call, Environment::kAttachFrameState); - environment()->MarkAllRegistersLive(); + Node* call = NewNode(javascript()->Debugger()); + environment()->RecordAfterState(call, Environment::kAttachFrameState); } // We cannot create a graph from the debugger copy of the bytecode array. @@ -1798,8 +1968,9 @@ void BytecodeGraphBuilder::VisitForInStep() { PrepareEagerCheckpoint(); Node* index = environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); - index = NewNode(javascript()->Add(BinaryOperationHint::kSignedSmall), index, - jsgraph()->OneConstant()); + index = NewNode( + simplified()->SpeculativeNumberAdd(NumberOperationHint::kSignedSmall), + index, jsgraph()->OneConstant()); environment()->BindAccumulator(index, Environment::kAttachFrameState); } @@ -1866,33 +2037,45 @@ void BytecodeGraphBuilder::VisitIllegal() { void BytecodeGraphBuilder::VisitNop() {} void BytecodeGraphBuilder::SwitchToMergeEnvironment(int current_offset) { - if (merge_environments_[current_offset] != nullptr) { + auto it = merge_environments_.find(current_offset); + if (it != merge_environments_.end()) { + mark_as_needing_eager_checkpoint(true); if (environment() != nullptr) { - merge_environments_[current_offset]->Merge(environment()); + it->second->Merge(environment()); } - set_environment(merge_environments_[current_offset]); + set_environment(it->second); } } void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) { - if (branch_analysis()->backward_branches_target(current_offset)) { - // Add loop header and store a copy so we can connect merged back - // edge inputs to the loop header. - merge_environments_[current_offset] = environment()->CopyForLoop(); + if (bytecode_analysis()->IsLoopHeader(current_offset)) { + mark_as_needing_eager_checkpoint(true); + const LoopInfo& loop_info = + bytecode_analysis()->GetLoopInfoFor(current_offset); + + // Add loop header. + environment()->PrepareForLoop(loop_info.assignments()); + + BuildOSRLoopEntryPoint(current_offset); + + // Store a copy of the environment so we can connect merged back edge inputs + // to the loop header. + merge_environments_[current_offset] = environment()->Copy(); } } void BytecodeGraphBuilder::MergeIntoSuccessorEnvironment(int target_offset) { BuildLoopExitsForBranch(target_offset); - if (merge_environments_[target_offset] == nullptr) { + Environment*& merge_environment = merge_environments_[target_offset]; + if (merge_environment == nullptr) { // Append merge nodes to the environment. We may merge here with another // environment. So add a place holder for merge nodes. We may add redundant // but will be eliminated in a later pass. // TODO(mstarzinger): Be smarter about this! NewMerge(); - merge_environments_[target_offset] = environment(); + merge_environment = environment(); } else { - merge_environments_[target_offset]->Merge(environment()); + merge_environment->Merge(environment()); } set_environment(nullptr); } @@ -1903,13 +2086,14 @@ void BytecodeGraphBuilder::MergeControlToLeaveFunction(Node* exit) { } void BytecodeGraphBuilder::BuildOSRLoopEntryPoint(int current_offset) { - if (!osr_ast_id_.IsNone() && osr_ast_id_.ToInt() == current_offset) { + DCHECK(bytecode_analysis()->IsLoopHeader(current_offset)); + + if (!osr_ast_id_.IsNone() && osr_loop_offset_ == current_offset) { // For OSR add a special {OsrLoopEntry} node into the current loop header. // It will be turned into a usable entry by the OSR deconstruction. - Environment* loop_env = merge_environments_[current_offset]; - Environment* osr_env = loop_env->CopyForOsrEntry(); + Environment* osr_env = environment()->Copy(); osr_env->PrepareForOsrEntry(); - loop_env->Merge(osr_env); + environment()->Merge(osr_env); } } @@ -1918,9 +2102,11 @@ void BytecodeGraphBuilder::BuildOSRNormalEntryPoint() { // For OSR add an {OsrNormalEntry} as the the top-level environment start. // It will be replaced with {Dead} by the OSR deconstruction. NewNode(common()->OsrNormalEntry()); - // Note that the requested OSR entry point must be the target of a backward - // branch, otherwise there will not be a proper loop header available. - DCHECK(branch_analysis()->backward_branches_target(osr_ast_id_.ToInt())); + // Translate the offset of the jump instruction to the jump target offset of + // that instruction so that the derived BailoutId points to the loop header. + osr_loop_offset_ = + bytecode_analysis()->GetLoopOffsetFor(osr_ast_id_.ToInt()); + DCHECK(bytecode_analysis()->IsLoopHeader(osr_loop_offset_)); } } @@ -1928,17 +2114,20 @@ void BytecodeGraphBuilder::BuildLoopExitsForBranch(int target_offset) { int origin_offset = bytecode_iterator().current_offset(); // Only build loop exits for forward edges. if (target_offset > origin_offset) { - BuildLoopExitsUntilLoop(loop_analysis()->GetLoopOffsetFor(target_offset)); + BuildLoopExitsUntilLoop( + bytecode_analysis()->GetLoopOffsetFor(target_offset)); } } void BytecodeGraphBuilder::BuildLoopExitsUntilLoop(int loop_offset) { int origin_offset = bytecode_iterator().current_offset(); - int current_loop = loop_analysis()->GetLoopOffsetFor(origin_offset); + int current_loop = bytecode_analysis()->GetLoopOffsetFor(origin_offset); while (loop_offset < current_loop) { Node* loop_node = merge_environments_[current_loop]->GetControlDependency(); - environment()->PrepareForLoopExit(loop_node); - current_loop = loop_analysis()->GetParentLoopFor(current_loop); + const LoopInfo& loop_info = + bytecode_analysis()->GetLoopInfoFor(current_loop); + environment()->PrepareForLoopExit(loop_node, loop_info.assignments()); + current_loop = loop_info.parent_offset(); } } @@ -1952,7 +2141,7 @@ void BytecodeGraphBuilder::BuildJump() { void BytecodeGraphBuilder::BuildJumpIf(Node* condition) { NewBranch(condition); - Environment* if_false_environment = environment()->CopyForConditional(); + Environment* if_false_environment = environment()->Copy(); NewIfTrue(); MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); set_environment(if_false_environment); @@ -1961,7 +2150,7 @@ void BytecodeGraphBuilder::BuildJumpIf(Node* condition) { void BytecodeGraphBuilder::BuildJumpIfNot(Node* condition) { NewBranch(condition); - Environment* if_true_environment = environment()->CopyForConditional(); + Environment* if_true_environment = environment()->Copy(); NewIfFalse(); MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); set_environment(if_true_environment); @@ -1971,17 +2160,30 @@ void BytecodeGraphBuilder::BuildJumpIfNot(Node* condition) { void BytecodeGraphBuilder::BuildJumpIfEqual(Node* comperand) { Node* accumulator = environment()->LookupAccumulator(); Node* condition = - NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), - accumulator, comperand); + NewNode(simplified()->ReferenceEqual(), accumulator, comperand); BuildJumpIf(condition); } void BytecodeGraphBuilder::BuildJumpIfFalse() { - BuildJumpIfNot(environment()->LookupAccumulator()); + NewBranch(environment()->LookupAccumulator()); + Environment* if_true_environment = environment()->Copy(); + environment()->BindAccumulator(jsgraph()->FalseConstant()); + NewIfFalse(); + MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); + if_true_environment->BindAccumulator(jsgraph()->TrueConstant()); + set_environment(if_true_environment); + NewIfTrue(); } void BytecodeGraphBuilder::BuildJumpIfTrue() { - BuildJumpIf(environment()->LookupAccumulator()); + NewBranch(environment()->LookupAccumulator()); + Environment* if_false_environment = environment()->Copy(); + environment()->BindAccumulator(jsgraph()->TrueConstant()); + NewIfTrue(); + MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); + if_false_environment->BindAccumulator(jsgraph()->FalseConstant()); + set_environment(if_false_environment); + NewIfFalse(); } void BytecodeGraphBuilder::BuildJumpIfToBooleanTrue() { @@ -2000,12 +2202,17 @@ void BytecodeGraphBuilder::BuildJumpIfToBooleanFalse() { void BytecodeGraphBuilder::BuildJumpIfNotHole() { Node* accumulator = environment()->LookupAccumulator(); - Node* condition = - NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), - accumulator, jsgraph()->TheHoleConstant()); + Node* condition = NewNode(simplified()->ReferenceEqual(), accumulator, + jsgraph()->TheHoleConstant()); BuildJumpIfNot(condition); } +void BytecodeGraphBuilder::BuildJumpIfJSReceiver() { + Node* accumulator = environment()->LookupAccumulator(); + Node* condition = NewNode(simplified()->ObjectIsReceiver(), accumulator); + BuildJumpIf(condition); +} + Node** BytecodeGraphBuilder::EnsureInputBufferSize(int size) { if (size > input_buffer_size_) { size = size + kInputBufferSizeIncrement + input_buffer_size_; @@ -2093,7 +2300,7 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, int handler_offset = exception_handlers_.top().handler_offset_; int context_index = exception_handlers_.top().context_register_; interpreter::Register context_register(context_index); - Environment* success_env = environment()->CopyForConditional(); + Environment* success_env = environment()->Copy(); const Operator* op = common()->IfException(); Node* effect = environment()->GetEffectDependency(); Node* on_exception = graph()->NewNode(op, effect, result); @@ -2111,6 +2318,10 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, Node* on_success = graph()->NewNode(if_success, result); environment()->UpdateControlDependency(on_success); } + // Ensure checkpoints are created after operations with side-effects. + if (has_effect && !result->op()->HasProperty(Operator::kNoWrite)) { + mark_as_needing_eager_checkpoint(true); + } } return result; |