diff options
Diffstat (limited to 'deps/v8/src/compiler/bytecode-graph-builder.cc')
-rw-r--r-- | deps/v8/src/compiler/bytecode-graph-builder.cc | 1401 |
1 files changed, 1255 insertions, 146 deletions
diff --git a/deps/v8/src/compiler/bytecode-graph-builder.cc b/deps/v8/src/compiler/bytecode-graph-builder.cc index e113833dc1..cf0b6ab438 100644 --- a/deps/v8/src/compiler/bytecode-graph-builder.cc +++ b/deps/v8/src/compiler/bytecode-graph-builder.cc @@ -4,16 +4,78 @@ #include "src/compiler/bytecode-graph-builder.h" +#include "src/compiler/bytecode-branch-analysis.h" #include "src/compiler/linkage.h" #include "src/compiler/operator-properties.h" -#include "src/interpreter/bytecode-array-iterator.h" +#include "src/interpreter/bytecodes.h" namespace v8 { namespace internal { namespace compiler { +// Helper for generating frame states for before and after a bytecode. +class BytecodeGraphBuilder::FrameStateBeforeAndAfter { + public: + FrameStateBeforeAndAfter(BytecodeGraphBuilder* builder, + const interpreter::BytecodeArrayIterator& iterator) + : builder_(builder), + id_after_(BailoutId::None()), + added_to_node_(false), + output_poke_offset_(0), + output_poke_count_(0) { + BailoutId id_before(iterator.current_offset()); + frame_state_before_ = builder_->environment()->Checkpoint( + id_before, OutputFrameStateCombine::Ignore()); + id_after_ = BailoutId(id_before.ToInt() + iterator.current_bytecode_size()); + } + + ~FrameStateBeforeAndAfter() { + DCHECK(added_to_node_); + DCHECK(builder_->environment()->StateValuesAreUpToDate(output_poke_offset_, + output_poke_count_)); + } + + private: + friend class Environment; + + void AddToNode(Node* node, OutputFrameStateCombine combine) { + DCHECK(!added_to_node_); + int count = OperatorProperties::GetFrameStateInputCount(node->op()); + DCHECK_LE(count, 2); + if (count >= 1) { + // Add the frame state for after the operation. + DCHECK_EQ(IrOpcode::kDead, + NodeProperties::GetFrameStateInput(node, 0)->opcode()); + Node* frame_state_after = + builder_->environment()->Checkpoint(id_after_, combine); + NodeProperties::ReplaceFrameStateInput(node, 0, frame_state_after); + } + + if (count >= 2) { + // Add the frame state for before the operation. + DCHECK_EQ(IrOpcode::kDead, + NodeProperties::GetFrameStateInput(node, 1)->opcode()); + NodeProperties::ReplaceFrameStateInput(node, 1, frame_state_before_); + } + + if (!combine.IsOutputIgnored()) { + output_poke_offset_ = static_cast<int>(combine.GetOffsetToPokeAt()); + output_poke_count_ = node->op()->ValueOutputCount(); + } + added_to_node_ = true; + } + + BytecodeGraphBuilder* builder_; + Node* frame_state_before_; + BailoutId id_after_; + + bool added_to_node_; + int output_poke_offset_; + int output_poke_count_; +}; + + // Issues: -// - Need to deal with FrameState / FrameStateBeforeAndAfter / StateValue. // - Scopes - intimately tied to AST. Need to eval what is needed. // - Need to resolve closure parameter treatment. BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder, @@ -27,10 +89,13 @@ BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder, context_(context), control_dependency_(control_dependency), effect_dependency_(control_dependency), - values_(builder->local_zone()) { + values_(builder->local_zone()), + parameters_state_values_(nullptr), + registers_state_values_(nullptr), + accumulator_state_values_(nullptr) { // The layout of values_ is: // - // [receiver] [parameters] [registers] + // [receiver] [parameters] [registers] [accumulator] // // parameter[0] is the receiver (this), parameters 1..N are the // parameters supplied to the method (arg0..argN-1). The accumulator @@ -50,7 +115,26 @@ BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder, values()->insert(values()->end(), register_count, undefined_constant); // Accumulator - accumulator_ = undefined_constant; + accumulator_base_ = static_cast<int>(values()->size()); + values()->push_back(undefined_constant); +} + + +BytecodeGraphBuilder::Environment::Environment( + const BytecodeGraphBuilder::Environment* other) + : builder_(other->builder_), + register_count_(other->register_count_), + parameter_count_(other->parameter_count_), + context_(other->context_), + control_dependency_(other->control_dependency_), + effect_dependency_(other->effect_dependency_), + values_(other->zone()), + parameters_state_values_(nullptr), + registers_state_values_(nullptr), + accumulator_state_values_(nullptr), + register_base_(other->register_base_), + accumulator_base_(other->accumulator_base_) { + values_ = other->values_; } @@ -64,27 +148,75 @@ int BytecodeGraphBuilder::Environment::RegisterToValuesIndex( } -void BytecodeGraphBuilder::Environment::BindRegister( - interpreter::Register the_register, Node* node) { - int values_index = RegisterToValuesIndex(the_register); - values()->at(values_index) = node; +Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const { + return values()->at(accumulator_base_); } Node* BytecodeGraphBuilder::Environment::LookupRegister( interpreter::Register the_register) const { + if (the_register.is_function_context()) { + return builder()->GetFunctionContext(); + } else if (the_register.is_function_closure()) { + return builder()->GetFunctionClosure(); + } else if (the_register.is_new_target()) { + return builder()->GetNewTarget(); + } else { + int values_index = RegisterToValuesIndex(the_register); + return values()->at(values_index); + } +} + + +void BytecodeGraphBuilder::Environment::ExchangeRegisters( + interpreter::Register reg0, interpreter::Register reg1) { + int reg0_index = RegisterToValuesIndex(reg0); + int reg1_index = RegisterToValuesIndex(reg1); + Node* saved_reg0_value = values()->at(reg0_index); + values()->at(reg0_index) = values()->at(reg1_index); + values()->at(reg1_index) = saved_reg0_value; +} + + +void BytecodeGraphBuilder::Environment::BindAccumulator( + Node* node, FrameStateBeforeAndAfter* states) { + if (states) { + states->AddToNode(node, OutputFrameStateCombine::PokeAt(0)); + } + values()->at(accumulator_base_) = node; +} + + +void BytecodeGraphBuilder::Environment::BindRegister( + interpreter::Register the_register, Node* node, + FrameStateBeforeAndAfter* states) { int values_index = RegisterToValuesIndex(the_register); - return values()->at(values_index); + if (states) { + states->AddToNode(node, OutputFrameStateCombine::PokeAt(accumulator_base_ - + values_index)); + } + values()->at(values_index) = node; } -void BytecodeGraphBuilder::Environment::BindAccumulator(Node* node) { - accumulator_ = node; +void BytecodeGraphBuilder::Environment::BindRegistersToProjections( + interpreter::Register first_reg, Node* node, + FrameStateBeforeAndAfter* states) { + int values_index = RegisterToValuesIndex(first_reg); + if (states) { + states->AddToNode(node, OutputFrameStateCombine::PokeAt(accumulator_base_ - + values_index)); + } + for (int i = 0; i < node->op()->ValueOutputCount(); i++) { + values()->at(values_index + i) = + builder()->NewNode(common()->Projection(i), node); + } } -Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const { - return accumulator_; +void BytecodeGraphBuilder::Environment::RecordAfterState( + Node* node, FrameStateBeforeAndAfter* states) { + states->AddToNode(node, OutputFrameStateCombine::Ignore()); } @@ -98,24 +230,188 @@ void BytecodeGraphBuilder::Environment::MarkAsUnreachable() { } +BytecodeGraphBuilder::Environment* +BytecodeGraphBuilder::Environment::CopyForLoop() { + PrepareForLoop(); + return new (zone()) Environment(this); +} + + +BytecodeGraphBuilder::Environment* +BytecodeGraphBuilder::Environment::CopyForConditional() const { + return new (zone()) Environment(this); +} + + +void BytecodeGraphBuilder::Environment::Merge( + BytecodeGraphBuilder::Environment* other) { + // Nothing to do if the other environment is dead. + if (other->IsMarkedAsUnreachable()) { + return; + } + + // Create a merge of the control dependencies of both environments and update + // the current environment's control dependency accordingly. + Node* control = builder()->MergeControl(GetControlDependency(), + other->GetControlDependency()); + UpdateControlDependency(control); + + // Create a merge of the effect dependencies of both environments and update + // the current environment's effect dependency accordingly. + Node* effect = builder()->MergeEffect(GetEffectDependency(), + other->GetEffectDependency(), control); + UpdateEffectDependency(effect); + + // Introduce Phi nodes for values that have differing input at merge points, + // potentially extending an existing Phi node if possible. + context_ = builder()->MergeValue(context_, other->context_, control); + for (size_t i = 0; i < values_.size(); i++) { + values_[i] = builder()->MergeValue(values_[i], other->values_[i], control); + } +} + + +void BytecodeGraphBuilder::Environment::PrepareForLoop() { + // Create a control node for the loop header. + Node* control = builder()->NewLoop(); + + // Create a Phi for external effects. + Node* effect = builder()->NewEffectPhi(1, GetEffectDependency(), control); + UpdateEffectDependency(effect); + + // Assume everything in the loop is updated. + 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); + } + + // Connect to the loop end. + Node* terminate = builder()->graph()->NewNode( + builder()->common()->Terminate(), effect, control); + builder()->exit_controls_.push_back(terminate); +} + + +bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate( + Node** state_values, int offset, int count) { + if (!builder()->info()->is_deoptimization_enabled()) { + return false; + } + 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); + for (int i = 0; i < count; i++) { + if ((*state_values)->InputAt(i) != env_values[i]) { + return true; + } + } + return false; +} + + +void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values, + int offset, + int count) { + if (StateValuesRequireUpdate(state_values, offset, count)) { + const Operator* op = common()->StateValues(count); + (*state_values) = graph()->NewNode(op, count, &values()->at(offset)); + } +} + + +Node* BytecodeGraphBuilder::Environment::Checkpoint( + BailoutId bailout_id, OutputFrameStateCombine combine) { + if (!builder()->info()->is_deoptimization_enabled()) { + return builder()->jsgraph()->EmptyFrameState(); + } + + // TODO(rmcilroy): Consider using StateValuesCache for some state values. + UpdateStateValues(¶meters_state_values_, 0, parameter_count()); + UpdateStateValues(®isters_state_values_, register_base(), + register_count()); + UpdateStateValues(&accumulator_state_values_, accumulator_base(), 1); + + const Operator* op = common()->FrameState( + bailout_id, combine, builder()->frame_state_function_info()); + Node* result = graph()->NewNode( + op, parameters_state_values_, registers_state_values_, + accumulator_state_values_, Context(), builder()->GetFunctionClosure(), + builder()->graph()->start()); + + return result; +} + + +bool BytecodeGraphBuilder::Environment::StateValuesAreUpToDate( + Node** state_values, int offset, int count, int output_poke_start, + int output_poke_end) { + DCHECK_LE(static_cast<size_t>(offset + count), values()->size()); + for (int i = 0; i < count; i++, offset++) { + if (offset < output_poke_start || offset >= output_poke_end) { + if ((*state_values)->InputAt(i) != values()->at(offset)) { + return false; + } + } + } + return true; +} + + +bool BytecodeGraphBuilder::Environment::StateValuesAreUpToDate( + int output_poke_offset, int output_poke_count) { + // Poke offset is relative to the top of the stack (i.e., the accumulator). + int output_poke_start = accumulator_base() - output_poke_offset; + int output_poke_end = output_poke_start + output_poke_count; + return StateValuesAreUpToDate(¶meters_state_values_, 0, parameter_count(), + output_poke_start, output_poke_end) && + StateValuesAreUpToDate(®isters_state_values_, register_base(), + register_count(), output_poke_start, + output_poke_end) && + StateValuesAreUpToDate(&accumulator_state_values_, accumulator_base(), + 1, output_poke_start, output_poke_end); +} + + BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone, CompilationInfo* compilation_info, JSGraph* jsgraph) : local_zone_(local_zone), info_(compilation_info), jsgraph_(jsgraph), + bytecode_array_(handle(info()->shared_info()->bytecode_array())), + frame_state_function_info_(common()->CreateFrameStateFunctionInfo( + FrameStateType::kInterpretedFunction, + bytecode_array()->parameter_count(), + bytecode_array()->register_count(), info()->shared_info(), + CALL_MAINTAINS_NATIVE_CONTEXT)), + merge_environments_(local_zone), + loop_header_environments_(local_zone), input_buffer_size_(0), input_buffer_(nullptr), - exit_controls_(local_zone) { - bytecode_array_ = handle(info()->shared_info()->bytecode_array()); + exit_controls_(local_zone) {} + + +Node* BytecodeGraphBuilder::GetNewTarget() { + if (!new_target_.is_set()) { + int params = bytecode_array()->parameter_count(); + int index = Linkage::GetJSCallNewTargetParamIndex(params); + const Operator* op = common()->Parameter(index, "%new.target"); + Node* node = NewNode(op, graph()->start()); + new_target_.set(node); + } + return new_target_.get(); } Node* BytecodeGraphBuilder::GetFunctionContext() { if (!function_context_.is_set()) { - // Parameter (arity + 1) is special for the outer context of the function - const Operator* op = - common()->Parameter(bytecode_array()->parameter_count(), "%context"); + int params = bytecode_array()->parameter_count(); + int index = Linkage::GetJSCallContextParamIndex(params); + const Operator* op = common()->Parameter(index, "%context"); Node* node = NewNode(op, graph()->start()); function_context_.set(node); } @@ -123,13 +419,72 @@ Node* BytecodeGraphBuilder::GetFunctionContext() { } +Node* BytecodeGraphBuilder::GetFunctionClosure() { + if (!function_closure_.is_set()) { + int index = Linkage::kJSCallClosureParamIndex; + const Operator* op = common()->Parameter(index, "%closure"); + Node* node = NewNode(op, graph()->start()); + function_closure_.set(node); + } + return function_closure_.get(); +} + + +Node* BytecodeGraphBuilder::BuildLoadObjectField(Node* object, int offset) { + return NewNode(jsgraph()->machine()->Load(MachineType::AnyTagged()), object, + jsgraph()->IntPtrConstant(offset - kHeapObjectTag)); +} + + +Node* BytecodeGraphBuilder::BuildLoadImmutableObjectField(Node* object, + int offset) { + return graph()->NewNode(jsgraph()->machine()->Load(MachineType::AnyTagged()), + object, + jsgraph()->IntPtrConstant(offset - kHeapObjectTag), + graph()->start(), graph()->start()); +} + + +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* BytecodeGraphBuilder::BuildLoadFeedbackVector() { + if (!feedback_vector_.is_set()) { + Node* closure = GetFunctionClosure(); + Node* shared = BuildLoadImmutableObjectField( + closure, JSFunction::kSharedFunctionInfoOffset); + Node* vector = BuildLoadImmutableObjectField( + shared, SharedFunctionInfo::kFeedbackVectorOffset); + feedback_vector_.set(vector); + } + return feedback_vector_.get(); +} + + +VectorSlotPair BytecodeGraphBuilder::CreateVectorSlotPair(int slot_id) { + Handle<TypeFeedbackVector> feedback_vector = info()->feedback_vector(); + FeedbackVectorSlot slot; + if (slot_id >= TypeFeedbackVector::kReservedIndexCount) { + slot = feedback_vector->ToSlot(slot_id); + } + return VectorSlotPair(feedback_vector, slot); +} + + bool BytecodeGraphBuilder::CreateGraph(bool stack_check) { // Set up the basic structure of the graph. Outputs for {Start} are // the formal parameters (including the receiver) plus context and // closure. - // The additional count items are for the context and closure. - int actual_parameter_count = bytecode_array()->parameter_count() + 2; + // Set up the basic structure of the graph. Outputs for {Start} are the formal + // parameters (including the receiver) plus new target, number of arguments, + // context and closure. + int actual_parameter_count = bytecode_array()->parameter_count() + 4; graph()->SetStart(graph()->NewNode(common()->Start(actual_parameter_count))); Environment env(this, bytecode_array()->register_count(), @@ -137,13 +492,7 @@ bool BytecodeGraphBuilder::CreateGraph(bool stack_check) { GetFunctionContext()); set_environment(&env); - // Build function context only if there are context allocated variables. - if (info()->num_heap_slots() > 0) { - UNIMPLEMENTED(); // TODO(oth): Write ast-graph-builder equivalent. - } else { - // Simply use the outer function context in building the graph. - CreateGraphBody(stack_check); - } + CreateGraphBody(stack_check); // Finish the basic structure of the graph. DCHECK_NE(0u, exit_controls_.size()); @@ -159,23 +508,41 @@ bool BytecodeGraphBuilder::CreateGraph(bool stack_check) { void BytecodeGraphBuilder::CreateGraphBody(bool stack_check) { // TODO(oth): Review ast-graph-builder equivalent, i.e. arguments // object setup, this function variable if used, tracing hooks. + + if (stack_check) { + Node* node = NewNode(javascript()->StackCheck()); + PrepareEntryFrameState(node); + } + VisitBytecodes(); } void BytecodeGraphBuilder::VisitBytecodes() { + BytecodeBranchAnalysis analysis(bytecode_array(), local_zone()); + analysis.Analyze(); + set_branch_analysis(&analysis); interpreter::BytecodeArrayIterator iterator(bytecode_array()); + set_bytecode_iterator(&iterator); while (!iterator.done()) { - switch (iterator.current_bytecode()) { + int current_offset = iterator.current_offset(); + if (analysis.is_reachable(current_offset)) { + MergeEnvironmentsOfForwardBranches(current_offset); + BuildLoopHeaderForBackwardBranches(current_offset); + + switch (iterator.current_bytecode()) { #define BYTECODE_CASE(name, ...) \ case interpreter::Bytecode::k##name: \ Visit##name(iterator); \ break; - BYTECODE_LIST(BYTECODE_CASE) + BYTECODE_LIST(BYTECODE_CASE) #undef BYTECODE_CODE + } } iterator.Advance(); } + set_branch_analysis(nullptr); + set_bytecode_iterator(nullptr); } @@ -256,547 +623,1093 @@ void BytecodeGraphBuilder::VisitStar( } +void BytecodeGraphBuilder::VisitMov( + const interpreter::BytecodeArrayIterator& iterator) { + Node* value = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + environment()->BindRegister(iterator.GetRegisterOperand(1), value); +} + + +void BytecodeGraphBuilder::VisitExchange( + const interpreter::BytecodeArrayIterator& iterator) { + environment()->ExchangeRegisters(iterator.GetRegisterOperand(0), + iterator.GetRegisterOperand(1)); +} + + +void BytecodeGraphBuilder::VisitExchangeWide( + const interpreter::BytecodeArrayIterator& iterator) { + environment()->ExchangeRegisters(iterator.GetRegisterOperand(0), + iterator.GetRegisterOperand(1)); +} + + +void BytecodeGraphBuilder::BuildLoadGlobal( + const interpreter::BytecodeArrayIterator& iterator, + TypeofMode typeof_mode) { + FrameStateBeforeAndAfter states(this, iterator); + Handle<Name> name = + Handle<Name>::cast(iterator.GetConstantForIndexOperand(0)); + VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(1)); + + const Operator* op = javascript()->LoadGlobal(name, feedback, typeof_mode); + Node* node = NewNode(op, BuildLoadFeedbackVector()); + environment()->BindAccumulator(node, &states); +} + + void BytecodeGraphBuilder::VisitLdaGlobalSloppy( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_sloppy(language_mode())); + BuildLoadGlobal(iterator, TypeofMode::NOT_INSIDE_TYPEOF); } void BytecodeGraphBuilder::VisitLdaGlobalStrict( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_strict(language_mode())); + BuildLoadGlobal(iterator, TypeofMode::NOT_INSIDE_TYPEOF); } void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeofSloppy( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_sloppy(language_mode())); + BuildLoadGlobal(iterator, TypeofMode::INSIDE_TYPEOF); } void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeofStrict( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_strict(language_mode())); + BuildLoadGlobal(iterator, TypeofMode::INSIDE_TYPEOF); } void BytecodeGraphBuilder::VisitLdaGlobalSloppyWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_sloppy(language_mode())); + BuildLoadGlobal(iterator, TypeofMode::NOT_INSIDE_TYPEOF); } void BytecodeGraphBuilder::VisitLdaGlobalStrictWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_strict(language_mode())); + BuildLoadGlobal(iterator, TypeofMode::NOT_INSIDE_TYPEOF); } void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeofSloppyWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_sloppy(language_mode())); + BuildLoadGlobal(iterator, TypeofMode::INSIDE_TYPEOF); } void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeofStrictWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_strict(language_mode())); + BuildLoadGlobal(iterator, TypeofMode::INSIDE_TYPEOF); +} + + +void BytecodeGraphBuilder::BuildStoreGlobal( + const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + Handle<Name> name = + Handle<Name>::cast(iterator.GetConstantForIndexOperand(0)); + VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(1)); + Node* value = environment()->LookupAccumulator(); + + const Operator* op = + javascript()->StoreGlobal(language_mode(), name, feedback); + Node* node = NewNode(op, value, BuildLoadFeedbackVector()); + environment()->RecordAfterState(node, &states); } void BytecodeGraphBuilder::VisitStaGlobalSloppy( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_sloppy(language_mode())); + BuildStoreGlobal(iterator); } void BytecodeGraphBuilder::VisitStaGlobalStrict( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_strict(language_mode())); + BuildStoreGlobal(iterator); } void BytecodeGraphBuilder::VisitStaGlobalSloppyWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_sloppy(language_mode())); + BuildStoreGlobal(iterator); } void BytecodeGraphBuilder::VisitStaGlobalStrictWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_strict(language_mode())); + BuildStoreGlobal(iterator); } void BytecodeGraphBuilder::VisitLdaContextSlot( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + // TODO(mythria): LoadContextSlots are unrolled by the required depth when + // generating bytecode. Hence the value of depth is always 0. Update this + // code, when the implementation changes. + // 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, iterator.GetIndexOperand(1), false); + Node* context = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + Node* node = NewNode(op, context); + environment()->BindAccumulator(node); +} + + +void BytecodeGraphBuilder::VisitLdaContextSlotWide( + const interpreter::BytecodeArrayIterator& iterator) { + VisitLdaContextSlot(iterator); } void BytecodeGraphBuilder::VisitStaContextSlot( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + // TODO(mythria): LoadContextSlots are unrolled by the required depth when + // generating bytecode. Hence the value of depth is always 0. Update this + // code, when the implementation changes. + const Operator* op = + javascript()->StoreContext(0, iterator.GetIndexOperand(1)); + Node* context = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + Node* value = environment()->LookupAccumulator(); + NewNode(op, context, value); } -void BytecodeGraphBuilder::VisitLoadICSloppy( +void BytecodeGraphBuilder::VisitStaContextSlotWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + VisitStaContextSlot(iterator); } -void BytecodeGraphBuilder::VisitLoadICStrict( +void BytecodeGraphBuilder::BuildLdaLookupSlot( + TypeofMode typeof_mode, const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + FrameStateBeforeAndAfter states(this, iterator); + Handle<String> name = + Handle<String>::cast(iterator.GetConstantForIndexOperand(0)); + const Operator* op = javascript()->LoadDynamic(name, typeof_mode); + Node* value = + NewNode(op, BuildLoadFeedbackVector(), environment()->Context()); + environment()->BindAccumulator(value, &states); } -void BytecodeGraphBuilder::VisitKeyedLoadICSloppy( +void BytecodeGraphBuilder::VisitLdaLookupSlot( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildLdaLookupSlot(TypeofMode::NOT_INSIDE_TYPEOF, iterator); } -void BytecodeGraphBuilder::VisitKeyedLoadICStrict( +void BytecodeGraphBuilder::VisitLdaLookupSlotInsideTypeof( + const interpreter::BytecodeArrayIterator& iterator) { + BuildLdaLookupSlot(TypeofMode::INSIDE_TYPEOF, iterator); +} + + +void BytecodeGraphBuilder::BuildStaLookupSlot( + LanguageMode language_mode, + const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + Node* value = environment()->LookupAccumulator(); + Node* name = jsgraph()->Constant(iterator.GetConstantForIndexOperand(0)); + Node* language = jsgraph()->Constant(language_mode); + const Operator* op = javascript()->CallRuntime(Runtime::kStoreLookupSlot, 4); + Node* store = NewNode(op, value, environment()->Context(), name, language); + environment()->BindAccumulator(store, &states); +} + + +void BytecodeGraphBuilder::VisitLdaLookupSlotWide( + const interpreter::BytecodeArrayIterator& iterator) { + VisitLdaLookupSlot(iterator); +} + + +void BytecodeGraphBuilder::VisitLdaLookupSlotInsideTypeofWide( + const interpreter::BytecodeArrayIterator& iterator) { + VisitLdaLookupSlotInsideTypeof(iterator); +} + + +void BytecodeGraphBuilder::VisitStaLookupSlotSloppy( + const interpreter::BytecodeArrayIterator& iterator) { + BuildStaLookupSlot(LanguageMode::SLOPPY, iterator); +} + + +void BytecodeGraphBuilder::VisitStaLookupSlotStrict( + const interpreter::BytecodeArrayIterator& iterator) { + BuildStaLookupSlot(LanguageMode::STRICT, iterator); +} + + +void BytecodeGraphBuilder::VisitStaLookupSlotSloppyWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + VisitStaLookupSlotSloppy(iterator); +} + + +void BytecodeGraphBuilder::VisitStaLookupSlotStrictWide( + const interpreter::BytecodeArrayIterator& iterator) { + VisitStaLookupSlotStrict(iterator); +} + + +void BytecodeGraphBuilder::BuildNamedLoad( + const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + Handle<Name> name = + Handle<Name>::cast(iterator.GetConstantForIndexOperand(1)); + VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(2)); + + const Operator* op = javascript()->LoadNamed(language_mode(), name, feedback); + Node* node = NewNode(op, object, BuildLoadFeedbackVector()); + environment()->BindAccumulator(node, &states); +} + + +void BytecodeGraphBuilder::VisitLoadICSloppy( + const interpreter::BytecodeArrayIterator& iterator) { + DCHECK(is_sloppy(language_mode())); + BuildNamedLoad(iterator); +} + + +void BytecodeGraphBuilder::VisitLoadICStrict( + const interpreter::BytecodeArrayIterator& iterator) { + DCHECK(is_strict(language_mode())); + BuildNamedLoad(iterator); } void BytecodeGraphBuilder::VisitLoadICSloppyWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_sloppy(language_mode())); + BuildNamedLoad(iterator); } void BytecodeGraphBuilder::VisitLoadICStrictWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_strict(language_mode())); + BuildNamedLoad(iterator); +} + + +void BytecodeGraphBuilder::BuildKeyedLoad( + const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + Node* key = environment()->LookupAccumulator(); + Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(1)); + + const Operator* op = javascript()->LoadProperty(language_mode(), feedback); + Node* node = NewNode(op, object, key, BuildLoadFeedbackVector()); + environment()->BindAccumulator(node, &states); +} + + +void BytecodeGraphBuilder::VisitKeyedLoadICSloppy( + const interpreter::BytecodeArrayIterator& iterator) { + DCHECK(is_sloppy(language_mode())); + BuildKeyedLoad(iterator); +} + + +void BytecodeGraphBuilder::VisitKeyedLoadICStrict( + const interpreter::BytecodeArrayIterator& iterator) { + DCHECK(is_strict(language_mode())); + BuildKeyedLoad(iterator); } void BytecodeGraphBuilder::VisitKeyedLoadICSloppyWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_sloppy(language_mode())); + BuildKeyedLoad(iterator); } void BytecodeGraphBuilder::VisitKeyedLoadICStrictWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_strict(language_mode())); + BuildKeyedLoad(iterator); +} + + +void BytecodeGraphBuilder::BuildNamedStore( + const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + Node* value = environment()->LookupAccumulator(); + Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + Handle<Name> name = + Handle<Name>::cast(iterator.GetConstantForIndexOperand(1)); + VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(2)); + + const Operator* op = + javascript()->StoreNamed(language_mode(), name, feedback); + Node* node = NewNode(op, object, value, BuildLoadFeedbackVector()); + environment()->RecordAfterState(node, &states); } void BytecodeGraphBuilder::VisitStoreICSloppy( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_sloppy(language_mode())); + BuildNamedStore(iterator); } void BytecodeGraphBuilder::VisitStoreICStrict( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_strict(language_mode())); + BuildNamedStore(iterator); } -void BytecodeGraphBuilder::VisitKeyedStoreICSloppy( +void BytecodeGraphBuilder::VisitStoreICSloppyWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_sloppy(language_mode())); + BuildNamedStore(iterator); } -void BytecodeGraphBuilder::VisitKeyedStoreICStrict( +void BytecodeGraphBuilder::VisitStoreICStrictWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_strict(language_mode())); + BuildNamedStore(iterator); } -void BytecodeGraphBuilder::VisitStoreICSloppyWide( +void BytecodeGraphBuilder::BuildKeyedStore( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + FrameStateBeforeAndAfter states(this, iterator); + Node* value = environment()->LookupAccumulator(); + Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + Node* key = environment()->LookupRegister(iterator.GetRegisterOperand(1)); + VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(2)); + + const Operator* op = javascript()->StoreProperty(language_mode(), feedback); + Node* node = NewNode(op, object, key, value, BuildLoadFeedbackVector()); + environment()->RecordAfterState(node, &states); } -void BytecodeGraphBuilder::VisitStoreICStrictWide( +void BytecodeGraphBuilder::VisitKeyedStoreICSloppy( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_sloppy(language_mode())); + BuildKeyedStore(iterator); +} + + +void BytecodeGraphBuilder::VisitKeyedStoreICStrict( + const interpreter::BytecodeArrayIterator& iterator) { + DCHECK(is_strict(language_mode())); + BuildKeyedStore(iterator); } void BytecodeGraphBuilder::VisitKeyedStoreICSloppyWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_sloppy(language_mode())); + BuildKeyedStore(iterator); } void BytecodeGraphBuilder::VisitKeyedStoreICStrictWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_strict(language_mode())); + BuildKeyedStore(iterator); } void BytecodeGraphBuilder::VisitPushContext( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + Node* context = environment()->LookupAccumulator(); + environment()->BindRegister(iterator.GetRegisterOperand(0), context); + environment()->SetContext(context); } void BytecodeGraphBuilder::VisitPopContext( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + Node* context = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + environment()->SetContext(context); } void BytecodeGraphBuilder::VisitCreateClosure( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + Handle<SharedFunctionInfo> shared_info = + Handle<SharedFunctionInfo>::cast(iterator.GetConstantForIndexOperand(0)); + PretenureFlag tenured = + iterator.GetImmediateOperand(1) ? TENURED : NOT_TENURED; + const Operator* op = javascript()->CreateClosure(shared_info, tenured); + Node* closure = NewNode(op); + environment()->BindAccumulator(closure); +} + + +void BytecodeGraphBuilder::VisitCreateClosureWide( + const interpreter::BytecodeArrayIterator& iterator) { + VisitCreateClosure(iterator); +} + + +void BytecodeGraphBuilder::BuildCreateArguments( + CreateArgumentsParameters::Type type, + const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + const Operator* op = javascript()->CreateArguments(type, 0); + Node* object = NewNode(op, GetFunctionClosure()); + environment()->BindAccumulator(object, &states); } void BytecodeGraphBuilder::VisitCreateMappedArguments( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCreateArguments(CreateArgumentsParameters::kMappedArguments, iterator); } void BytecodeGraphBuilder::VisitCreateUnmappedArguments( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCreateArguments(CreateArgumentsParameters::kUnmappedArguments, iterator); +} + + +void BytecodeGraphBuilder::BuildCreateLiteral( + const Operator* op, const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + Node* literal = NewNode(op, GetFunctionClosure()); + environment()->BindAccumulator(literal, &states); +} + + +void BytecodeGraphBuilder::BuildCreateRegExpLiteral( + const interpreter::BytecodeArrayIterator& iterator) { + Handle<String> constant_pattern = + Handle<String>::cast(iterator.GetConstantForIndexOperand(0)); + int literal_index = iterator.GetIndexOperand(1); + int literal_flags = iterator.GetImmediateOperand(2); + const Operator* op = javascript()->CreateLiteralRegExp( + constant_pattern, literal_flags, literal_index); + BuildCreateLiteral(op, iterator); } void BytecodeGraphBuilder::VisitCreateRegExpLiteral( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCreateRegExpLiteral(iterator); +} + + +void BytecodeGraphBuilder::VisitCreateRegExpLiteralWide( + const interpreter::BytecodeArrayIterator& iterator) { + BuildCreateRegExpLiteral(iterator); +} + + +void BytecodeGraphBuilder::BuildCreateArrayLiteral( + const interpreter::BytecodeArrayIterator& iterator) { + Handle<FixedArray> constant_elements = + Handle<FixedArray>::cast(iterator.GetConstantForIndexOperand(0)); + int literal_index = iterator.GetIndexOperand(1); + int literal_flags = iterator.GetImmediateOperand(2); + const Operator* op = javascript()->CreateLiteralArray( + constant_elements, literal_flags, literal_index); + BuildCreateLiteral(op, iterator); } void BytecodeGraphBuilder::VisitCreateArrayLiteral( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCreateArrayLiteral(iterator); +} + + +void BytecodeGraphBuilder::VisitCreateArrayLiteralWide( + const interpreter::BytecodeArrayIterator& iterator) { + BuildCreateArrayLiteral(iterator); +} + + +void BytecodeGraphBuilder::BuildCreateObjectLiteral( + const interpreter::BytecodeArrayIterator& iterator) { + Handle<FixedArray> constant_properties = + Handle<FixedArray>::cast(iterator.GetConstantForIndexOperand(0)); + int literal_index = iterator.GetIndexOperand(1); + int literal_flags = iterator.GetImmediateOperand(2); + const Operator* op = javascript()->CreateLiteralObject( + constant_properties, literal_flags, literal_index); + BuildCreateLiteral(op, iterator); } void BytecodeGraphBuilder::VisitCreateObjectLiteral( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCreateObjectLiteral(iterator); +} + + +void BytecodeGraphBuilder::VisitCreateObjectLiteralWide( + const interpreter::BytecodeArrayIterator& iterator) { + BuildCreateObjectLiteral(iterator); +} + + +Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op, + Node* callee, + interpreter::Register receiver, + size_t arity) { + Node** all = info()->zone()->NewArray<Node*>(static_cast<int>(arity)); + all[0] = callee; + all[1] = environment()->LookupRegister(receiver); + int receiver_index = receiver.index(); + for (int i = 2; i < static_cast<int>(arity); ++i) { + all[i] = environment()->LookupRegister( + interpreter::Register(receiver_index + i - 1)); + } + Node* value = MakeNode(call_op, static_cast<int>(arity), all, false); + return value; +} + + +void BytecodeGraphBuilder::BuildCall( + const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + // TODO(rmcilroy): Set receiver_hint correctly based on whether the receiver + // register has been loaded with null / undefined explicitly or we are sure it + // is not null / undefined. + ConvertReceiverMode receiver_hint = ConvertReceiverMode::kAny; + Node* callee = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + interpreter::Register receiver = iterator.GetRegisterOperand(1); + size_t arg_count = iterator.GetCountOperand(2); + VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(3)); + + const Operator* call = javascript()->CallFunction( + arg_count + 2, language_mode(), feedback, receiver_hint); + Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 2); + environment()->BindAccumulator(value, &states); } void BytecodeGraphBuilder::VisitCall( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCall(iterator); } -void BytecodeGraphBuilder::VisitCallRuntime( +void BytecodeGraphBuilder::VisitCallWide( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCall(iterator); } void BytecodeGraphBuilder::VisitCallJSRuntime( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + FrameStateBeforeAndAfter states(this, iterator); + Node* callee = BuildLoadNativeContextField(iterator.GetIndexOperand(0)); + interpreter::Register receiver = iterator.GetRegisterOperand(1); + size_t arg_count = iterator.GetCountOperand(2); + + // Create node to perform the JS runtime call. + const Operator* call = + javascript()->CallFunction(arg_count + 2, language_mode()); + Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 2); + environment()->BindAccumulator(value, &states); +} + + +Node* BytecodeGraphBuilder::ProcessCallRuntimeArguments( + const Operator* call_runtime_op, interpreter::Register first_arg, + size_t arity) { + Node** all = info()->zone()->NewArray<Node*>(arity); + int first_arg_index = first_arg.index(); + for (int i = 0; i < static_cast<int>(arity); ++i) { + all[i] = environment()->LookupRegister( + interpreter::Register(first_arg_index + i)); + } + Node* value = MakeNode(call_runtime_op, static_cast<int>(arity), all, false); + return value; +} + + +void BytecodeGraphBuilder::VisitCallRuntime( + const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + Runtime::FunctionId functionId = + static_cast<Runtime::FunctionId>(iterator.GetIndexOperand(0)); + interpreter::Register first_arg = iterator.GetRegisterOperand(1); + size_t arg_count = iterator.GetCountOperand(2); + + // Create node to perform the runtime call. + const Operator* call = javascript()->CallRuntime(functionId, arg_count); + Node* value = ProcessCallRuntimeArguments(call, first_arg, arg_count); + environment()->BindAccumulator(value, &states); +} + + +void BytecodeGraphBuilder::VisitCallRuntimeForPair( + const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + Runtime::FunctionId functionId = + static_cast<Runtime::FunctionId>(iterator.GetIndexOperand(0)); + interpreter::Register first_arg = iterator.GetRegisterOperand(1); + size_t arg_count = iterator.GetCountOperand(2); + interpreter::Register first_return = iterator.GetRegisterOperand(3); + + // Create node to perform the runtime call. + const Operator* call = javascript()->CallRuntime(functionId, arg_count); + Node* return_pair = ProcessCallRuntimeArguments(call, first_arg, arg_count); + environment()->BindRegistersToProjections(first_return, return_pair, &states); +} + + +Node* BytecodeGraphBuilder::ProcessCallNewArguments( + const Operator* call_new_op, interpreter::Register callee, + interpreter::Register first_arg, size_t arity) { + Node** all = info()->zone()->NewArray<Node*>(arity); + all[0] = environment()->LookupRegister(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)); + } + // Original constructor is the same as the callee. + all[arity - 1] = environment()->LookupRegister(callee); + Node* value = MakeNode(call_new_op, static_cast<int>(arity), all, false); + return value; } void BytecodeGraphBuilder::VisitNew( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + FrameStateBeforeAndAfter states(this, iterator); + interpreter::Register callee = iterator.GetRegisterOperand(0); + interpreter::Register first_arg = iterator.GetRegisterOperand(1); + size_t arg_count = iterator.GetCountOperand(2); + + // TODO(turbofan): Pass the feedback here. + const Operator* call = javascript()->CallConstruct( + static_cast<int>(arg_count) + 2, VectorSlotPair()); + Node* value = ProcessCallNewArguments(call, callee, first_arg, arg_count + 2); + environment()->BindAccumulator(value, &states); } void BytecodeGraphBuilder::VisitThrow( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + FrameStateBeforeAndAfter states(this, iterator); + Node* value = environment()->LookupAccumulator(); + // TODO(mythria): Change to Runtime::kThrow when we have deoptimization + // information support in the interpreter. + NewNode(javascript()->CallRuntime(Runtime::kReThrow, 1), value); + Node* control = NewNode(common()->Throw(), value); + environment()->RecordAfterState(control, &states); + UpdateControlDependencyToLeaveFunction(control); } void BytecodeGraphBuilder::BuildBinaryOp( const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); Node* left = environment()->LookupRegister(iterator.GetRegisterOperand(0)); Node* right = environment()->LookupAccumulator(); Node* node = NewNode(js_op, left, right); - - // TODO(oth): Real frame state and environment check pointing. - int frame_state_count = - OperatorProperties::GetFrameStateInputCount(node->op()); - for (int i = 0; i < frame_state_count; i++) { - NodeProperties::ReplaceFrameStateInput(node, i, - jsgraph()->EmptyFrameState()); - } - environment()->BindAccumulator(node); + environment()->BindAccumulator(node, &states); } void BytecodeGraphBuilder::VisitAdd( const interpreter::BytecodeArrayIterator& iterator) { - BuildBinaryOp(javascript()->Add(language_mode()), iterator); + BinaryOperationHints hints = BinaryOperationHints::Any(); + BuildBinaryOp(javascript()->Add(language_mode(), hints), iterator); } void BytecodeGraphBuilder::VisitSub( const interpreter::BytecodeArrayIterator& iterator) { - BuildBinaryOp(javascript()->Subtract(language_mode()), iterator); + BinaryOperationHints hints = BinaryOperationHints::Any(); + BuildBinaryOp(javascript()->Subtract(language_mode(), hints), iterator); } void BytecodeGraphBuilder::VisitMul( const interpreter::BytecodeArrayIterator& iterator) { - BuildBinaryOp(javascript()->Multiply(language_mode()), iterator); + BinaryOperationHints hints = BinaryOperationHints::Any(); + BuildBinaryOp(javascript()->Multiply(language_mode(), hints), iterator); } void BytecodeGraphBuilder::VisitDiv( const interpreter::BytecodeArrayIterator& iterator) { - BuildBinaryOp(javascript()->Divide(language_mode()), iterator); + BinaryOperationHints hints = BinaryOperationHints::Any(); + BuildBinaryOp(javascript()->Divide(language_mode(), hints), iterator); } void BytecodeGraphBuilder::VisitMod( const interpreter::BytecodeArrayIterator& iterator) { - BuildBinaryOp(javascript()->Modulus(language_mode()), iterator); + BinaryOperationHints hints = BinaryOperationHints::Any(); + BuildBinaryOp(javascript()->Modulus(language_mode(), hints), iterator); } void BytecodeGraphBuilder::VisitBitwiseOr( const interpreter::BytecodeArrayIterator& iterator) { - BuildBinaryOp(javascript()->BitwiseOr(language_mode()), iterator); + BinaryOperationHints hints = BinaryOperationHints::Any(); + BuildBinaryOp(javascript()->BitwiseOr(language_mode(), hints), iterator); } void BytecodeGraphBuilder::VisitBitwiseXor( const interpreter::BytecodeArrayIterator& iterator) { - BuildBinaryOp(javascript()->BitwiseXor(language_mode()), iterator); + BinaryOperationHints hints = BinaryOperationHints::Any(); + BuildBinaryOp(javascript()->BitwiseXor(language_mode(), hints), iterator); } void BytecodeGraphBuilder::VisitBitwiseAnd( const interpreter::BytecodeArrayIterator& iterator) { - BuildBinaryOp(javascript()->BitwiseAnd(language_mode()), iterator); + BinaryOperationHints hints = BinaryOperationHints::Any(); + BuildBinaryOp(javascript()->BitwiseAnd(language_mode(), hints), iterator); } void BytecodeGraphBuilder::VisitShiftLeft( const interpreter::BytecodeArrayIterator& iterator) { - BuildBinaryOp(javascript()->ShiftLeft(language_mode()), iterator); + BinaryOperationHints hints = BinaryOperationHints::Any(); + BuildBinaryOp(javascript()->ShiftLeft(language_mode(), hints), iterator); } void BytecodeGraphBuilder::VisitShiftRight( const interpreter::BytecodeArrayIterator& iterator) { - BuildBinaryOp(javascript()->ShiftRight(language_mode()), iterator); + BinaryOperationHints hints = BinaryOperationHints::Any(); + BuildBinaryOp(javascript()->ShiftRight(language_mode(), hints), iterator); } void BytecodeGraphBuilder::VisitShiftRightLogical( const interpreter::BytecodeArrayIterator& iterator) { - BuildBinaryOp(javascript()->ShiftRightLogical(language_mode()), iterator); + BinaryOperationHints hints = BinaryOperationHints::Any(); + BuildBinaryOp(javascript()->ShiftRightLogical(language_mode(), hints), + iterator); } void BytecodeGraphBuilder::VisitInc( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + FrameStateBeforeAndAfter states(this, iterator); + const Operator* js_op = + javascript()->Add(language_mode(), BinaryOperationHints::Any()); + Node* node = NewNode(js_op, environment()->LookupAccumulator(), + jsgraph()->OneConstant()); + environment()->BindAccumulator(node, &states); } void BytecodeGraphBuilder::VisitDec( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + FrameStateBeforeAndAfter states(this, iterator); + const Operator* js_op = + javascript()->Subtract(language_mode(), BinaryOperationHints::Any()); + Node* node = NewNode(js_op, environment()->LookupAccumulator(), + jsgraph()->OneConstant()); + environment()->BindAccumulator(node, &states); } void BytecodeGraphBuilder::VisitLogicalNot( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + Node* value = NewNode(javascript()->ToBoolean(ToBooleanHint::kAny), + environment()->LookupAccumulator()); + Node* node = NewNode(common()->Select(MachineRepresentation::kTagged), value, + jsgraph()->FalseConstant(), jsgraph()->TrueConstant()); + environment()->BindAccumulator(node); } void BytecodeGraphBuilder::VisitTypeOf( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + Node* node = + NewNode(javascript()->TypeOf(), environment()->LookupAccumulator()); + environment()->BindAccumulator(node); +} + + +void BytecodeGraphBuilder::BuildDelete( + const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + Node* key = environment()->LookupAccumulator(); + Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + Node* node = + NewNode(javascript()->DeleteProperty(language_mode()), object, key); + environment()->BindAccumulator(node, &states); } void BytecodeGraphBuilder::VisitDeletePropertyStrict( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_strict(language_mode())); + BuildDelete(iterator); } void BytecodeGraphBuilder::VisitDeletePropertySloppy( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + DCHECK(is_sloppy(language_mode())); + BuildDelete(iterator); +} + + +void BytecodeGraphBuilder::VisitDeleteLookupSlot( + const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + Node* name = environment()->LookupAccumulator(); + const Operator* op = javascript()->CallRuntime(Runtime::kDeleteLookupSlot, 2); + Node* result = NewNode(op, environment()->Context(), name); + environment()->BindAccumulator(result, &states); +} + + +void BytecodeGraphBuilder::BuildCompareOp( + const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + Node* left = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + Node* right = environment()->LookupAccumulator(); + Node* node = NewNode(js_op, left, right); + environment()->BindAccumulator(node, &states); } void BytecodeGraphBuilder::VisitTestEqual( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCompareOp(javascript()->Equal(), iterator); } void BytecodeGraphBuilder::VisitTestNotEqual( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCompareOp(javascript()->NotEqual(), iterator); } void BytecodeGraphBuilder::VisitTestEqualStrict( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCompareOp(javascript()->StrictEqual(), iterator); } void BytecodeGraphBuilder::VisitTestNotEqualStrict( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCompareOp(javascript()->StrictNotEqual(), iterator); } void BytecodeGraphBuilder::VisitTestLessThan( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCompareOp(javascript()->LessThan(language_mode()), iterator); } void BytecodeGraphBuilder::VisitTestGreaterThan( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCompareOp(javascript()->GreaterThan(language_mode()), iterator); } void BytecodeGraphBuilder::VisitTestLessThanOrEqual( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCompareOp(javascript()->LessThanOrEqual(language_mode()), iterator); } void BytecodeGraphBuilder::VisitTestGreaterThanOrEqual( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCompareOp(javascript()->GreaterThanOrEqual(language_mode()), iterator); } void BytecodeGraphBuilder::VisitTestIn( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCompareOp(javascript()->HasProperty(), iterator); } void BytecodeGraphBuilder::VisitTestInstanceOf( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCompareOp(javascript()->InstanceOf(), iterator); } -void BytecodeGraphBuilder::VisitToBoolean( - const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); +void BytecodeGraphBuilder::BuildCastOperator( + const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + Node* node = NewNode(js_op, environment()->LookupAccumulator()); + environment()->BindAccumulator(node, &states); } void BytecodeGraphBuilder::VisitToName( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCastOperator(javascript()->ToName(), iterator); } -void BytecodeGraphBuilder::VisitToNumber( +void BytecodeGraphBuilder::VisitToObject( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCastOperator(javascript()->ToObject(), iterator); } -void BytecodeGraphBuilder::VisitToObject( +void BytecodeGraphBuilder::VisitToNumber( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildCastOperator(javascript()->ToNumber(), iterator); } void BytecodeGraphBuilder::VisitJump( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJump(); } void BytecodeGraphBuilder::VisitJumpConstant( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJump(); +} + + +void BytecodeGraphBuilder::VisitJumpConstantWide( + const interpreter::BytecodeArrayIterator& iterator) { + BuildJump(); } void BytecodeGraphBuilder::VisitJumpIfTrue( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJumpIfEqual(jsgraph()->TrueConstant()); } void BytecodeGraphBuilder::VisitJumpIfTrueConstant( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJumpIfEqual(jsgraph()->TrueConstant()); +} + + +void BytecodeGraphBuilder::VisitJumpIfTrueConstantWide( + const interpreter::BytecodeArrayIterator& iterator) { + BuildJumpIfEqual(jsgraph()->TrueConstant()); } void BytecodeGraphBuilder::VisitJumpIfFalse( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJumpIfEqual(jsgraph()->FalseConstant()); } void BytecodeGraphBuilder::VisitJumpIfFalseConstant( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJumpIfEqual(jsgraph()->FalseConstant()); +} + + +void BytecodeGraphBuilder::VisitJumpIfFalseConstantWide( + const interpreter::BytecodeArrayIterator& iterator) { + BuildJumpIfEqual(jsgraph()->FalseConstant()); } void BytecodeGraphBuilder::VisitJumpIfToBooleanTrue( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJumpIfToBooleanEqual(jsgraph()->TrueConstant()); } void BytecodeGraphBuilder::VisitJumpIfToBooleanTrueConstant( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJumpIfToBooleanEqual(jsgraph()->TrueConstant()); +} + + +void BytecodeGraphBuilder::VisitJumpIfToBooleanTrueConstantWide( + const interpreter::BytecodeArrayIterator& iterator) { + BuildJumpIfToBooleanEqual(jsgraph()->TrueConstant()); } void BytecodeGraphBuilder::VisitJumpIfToBooleanFalse( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJumpIfToBooleanEqual(jsgraph()->FalseConstant()); } void BytecodeGraphBuilder::VisitJumpIfToBooleanFalseConstant( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJumpIfToBooleanEqual(jsgraph()->FalseConstant()); +} + + +void BytecodeGraphBuilder::VisitJumpIfToBooleanFalseConstantWide( + const interpreter::BytecodeArrayIterator& iterator) { + BuildJumpIfToBooleanEqual(jsgraph()->FalseConstant()); } void BytecodeGraphBuilder::VisitJumpIfNull( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJumpIfEqual(jsgraph()->NullConstant()); } void BytecodeGraphBuilder::VisitJumpIfNullConstant( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJumpIfEqual(jsgraph()->NullConstant()); +} + + +void BytecodeGraphBuilder::VisitJumpIfNullConstantWide( + const interpreter::BytecodeArrayIterator& iterator) { + BuildJumpIfEqual(jsgraph()->NullConstant()); } void BytecodeGraphBuilder::VisitJumpIfUndefined( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJumpIfEqual(jsgraph()->UndefinedConstant()); } void BytecodeGraphBuilder::VisitJumpIfUndefinedConstant( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + BuildJumpIfEqual(jsgraph()->UndefinedConstant()); +} + + +void BytecodeGraphBuilder::VisitJumpIfUndefinedConstantWide( + const interpreter::BytecodeArrayIterator& iterator) { + BuildJumpIfEqual(jsgraph()->UndefinedConstant()); } @@ -805,24 +1718,156 @@ void BytecodeGraphBuilder::VisitReturn( Node* control = NewNode(common()->Return(), environment()->LookupAccumulator()); UpdateControlDependencyToLeaveFunction(control); + set_environment(nullptr); } void BytecodeGraphBuilder::VisitForInPrepare( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + Node* prepare = nullptr; + { + FrameStateBeforeAndAfter states(this, iterator); + Node* receiver = environment()->LookupAccumulator(); + prepare = NewNode(javascript()->ForInPrepare(), receiver); + environment()->RecordAfterState(prepare, &states); + } + // Project cache_type, cache_array, cache_length into register + // operands 1, 2, 3. + for (int i = 0; i < 3; i++) { + environment()->BindRegister(iterator.GetRegisterOperand(i), + NewNode(common()->Projection(i), prepare)); + } } -void BytecodeGraphBuilder::VisitForInNext( +void BytecodeGraphBuilder::VisitForInDone( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + FrameStateBeforeAndAfter states(this, iterator); + Node* index = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + Node* cache_length = + environment()->LookupRegister(iterator.GetRegisterOperand(1)); + Node* exit_cond = NewNode(javascript()->ForInDone(), index, cache_length); + environment()->BindAccumulator(exit_cond, &states); } -void BytecodeGraphBuilder::VisitForInDone( +void BytecodeGraphBuilder::VisitForInNext( const interpreter::BytecodeArrayIterator& iterator) { - UNIMPLEMENTED(); + FrameStateBeforeAndAfter states(this, iterator); + Node* receiver = + environment()->LookupRegister(iterator.GetRegisterOperand(0)); + Node* cache_type = + environment()->LookupRegister(iterator.GetRegisterOperand(1)); + Node* cache_array = + environment()->LookupRegister(iterator.GetRegisterOperand(2)); + Node* index = environment()->LookupRegister(iterator.GetRegisterOperand(3)); + Node* value = NewNode(javascript()->ForInNext(), receiver, cache_array, + cache_type, index); + environment()->BindAccumulator(value, &states); +} + + +void BytecodeGraphBuilder::VisitForInStep( + const interpreter::BytecodeArrayIterator& iterator) { + FrameStateBeforeAndAfter states(this, iterator); + Node* index = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + index = NewNode(javascript()->ForInStep(), index); + environment()->BindAccumulator(index, &states); +} + + +void BytecodeGraphBuilder::MergeEnvironmentsOfBackwardBranches( + int source_offset, int target_offset) { + DCHECK_GE(source_offset, target_offset); + const ZoneVector<int>* branch_sites = + branch_analysis()->BackwardBranchesTargetting(target_offset); + if (branch_sites->back() == source_offset) { + // The set of back branches is complete, merge them. + DCHECK_GE(branch_sites->at(0), target_offset); + Environment* merged = merge_environments_[branch_sites->at(0)]; + for (size_t i = 1; i < branch_sites->size(); i++) { + DCHECK_GE(branch_sites->at(i), target_offset); + merged->Merge(merge_environments_[branch_sites->at(i)]); + } + // And now merge with loop header environment created when loop + // header was visited. + loop_header_environments_[target_offset]->Merge(merged); + } +} + + +void BytecodeGraphBuilder::MergeEnvironmentsOfForwardBranches( + int source_offset) { + if (branch_analysis()->forward_branches_target(source_offset)) { + // Merge environments of branches that reach this bytecode. + auto branch_sites = + branch_analysis()->ForwardBranchesTargetting(source_offset); + DCHECK_LT(branch_sites->at(0), source_offset); + Environment* merged = merge_environments_[branch_sites->at(0)]; + for (size_t i = 1; i < branch_sites->size(); i++) { + DCHECK_LT(branch_sites->at(i), source_offset); + merged->Merge(merge_environments_[branch_sites->at(i)]); + } + if (environment()) { + merged->Merge(environment()); + } + set_environment(merged); + } +} + + +void BytecodeGraphBuilder::BuildLoopHeaderForBackwardBranches( + int source_offset) { + if (branch_analysis()->backward_branches_target(source_offset)) { + // Add loop header and store a copy so we can connect merged back + // edge inputs to the loop header. + loop_header_environments_[source_offset] = environment()->CopyForLoop(); + } +} + + +void BytecodeGraphBuilder::BuildJump(int source_offset, int target_offset) { + DCHECK_NULL(merge_environments_[source_offset]); + merge_environments_[source_offset] = environment(); + if (source_offset >= target_offset) { + MergeEnvironmentsOfBackwardBranches(source_offset, target_offset); + } + set_environment(nullptr); +} + + +void BytecodeGraphBuilder::BuildJump() { + int source_offset = bytecode_iterator()->current_offset(); + int target_offset = bytecode_iterator()->GetJumpTargetOffset(); + BuildJump(source_offset, target_offset); +} + + +void BytecodeGraphBuilder::BuildConditionalJump(Node* condition) { + int source_offset = bytecode_iterator()->current_offset(); + NewBranch(condition); + Environment* if_false_environment = environment()->CopyForConditional(); + NewIfTrue(); + BuildJump(source_offset, bytecode_iterator()->GetJumpTargetOffset()); + set_environment(if_false_environment); + NewIfFalse(); +} + + +void BytecodeGraphBuilder::BuildJumpIfEqual(Node* comperand) { + Node* accumulator = environment()->LookupAccumulator(); + Node* condition = + NewNode(javascript()->StrictEqual(), accumulator, comperand); + BuildConditionalJump(condition); +} + + +void BytecodeGraphBuilder::BuildJumpIfToBooleanEqual(Node* comperand) { + Node* accumulator = environment()->LookupAccumulator(); + Node* to_boolean = + NewNode(javascript()->ToBoolean(ToBooleanHint::kAny), accumulator); + Node* condition = NewNode(javascript()->StrictEqual(), to_boolean, comperand); + BuildConditionalJump(condition); } @@ -836,6 +1881,16 @@ Node** BytecodeGraphBuilder::EnsureInputBufferSize(int size) { } +void BytecodeGraphBuilder::PrepareEntryFrameState(Node* node) { + DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); + DCHECK_EQ(IrOpcode::kDead, + NodeProperties::GetFrameStateInput(node, 0)->opcode()); + NodeProperties::ReplaceFrameStateInput( + node, 0, environment()->Checkpoint(BailoutId(0), + OutputFrameStateCombine::Ignore())); +} + + Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, Node** value_inputs, bool incomplete) { DCHECK_EQ(op->ValueInputCount(), value_input_count); @@ -848,7 +1903,7 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, DCHECK_LT(op->ControlInputCount(), 2); DCHECK_LT(op->EffectInputCount(), 2); - Node* result = NULL; + Node* result = nullptr; if (!has_context && frame_state_count == 0 && !has_control && !has_effect) { result = graph()->NewNode(op, value_input_count, value_inputs, incomplete); } else { @@ -898,6 +1953,25 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, } +Node* BytecodeGraphBuilder::NewPhi(int count, Node* input, Node* control) { + const Operator* phi_op = common()->Phi(MachineRepresentation::kTagged, count); + Node** buffer = EnsureInputBufferSize(count + 1); + MemsetPointer(buffer, input, count); + buffer[count] = control; + return graph()->NewNode(phi_op, count + 1, buffer, true); +} + + +Node* BytecodeGraphBuilder::NewEffectPhi(int count, Node* input, + Node* control) { + const Operator* phi_op = common()->EffectPhi(count); + Node** buffer = EnsureInputBufferSize(count + 1); + MemsetPointer(buffer, input, count); + buffer[count] = control; + return graph()->NewNode(phi_op, count + 1, buffer, true); +} + + Node* BytecodeGraphBuilder::MergeControl(Node* control, Node* other) { int inputs = control->op()->ControlInputCount() + 1; if (control->opcode() == IrOpcode::kLoop) { @@ -920,6 +1994,41 @@ Node* BytecodeGraphBuilder::MergeControl(Node* control, Node* other) { } +Node* BytecodeGraphBuilder::MergeEffect(Node* value, Node* other, + Node* control) { + int inputs = control->op()->ControlInputCount(); + if (value->opcode() == IrOpcode::kEffectPhi && + NodeProperties::GetControlInput(value) == control) { + // Phi already exists, add input. + value->InsertInput(graph_zone(), inputs - 1, other); + NodeProperties::ChangeOp(value, common()->EffectPhi(inputs)); + } else if (value != other) { + // Phi does not exist yet, introduce one. + value = NewEffectPhi(inputs, value, control); + value->ReplaceInput(inputs - 1, other); + } + return value; +} + + +Node* BytecodeGraphBuilder::MergeValue(Node* value, Node* other, + Node* control) { + int inputs = control->op()->ControlInputCount(); + if (value->opcode() == IrOpcode::kPhi && + NodeProperties::GetControlInput(value) == control) { + // Phi already exists, add input. + value->InsertInput(graph_zone(), inputs - 1, other); + NodeProperties::ChangeOp( + value, common()->Phi(MachineRepresentation::kTagged, inputs)); + } else if (value != other) { + // Phi does not exist yet, introduce one. + value = NewPhi(inputs, value, control); + value->ReplaceInput(inputs - 1, other); + } + return value; +} + + void BytecodeGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) { if (environment()->IsMarkedAsUnreachable()) return; environment()->MarkAsUnreachable(); |