diff options
Diffstat (limited to 'deps/v8/src/compiler/bytecode-graph-builder.cc')
-rw-r--r-- | deps/v8/src/compiler/bytecode-graph-builder.cc | 518 |
1 files changed, 403 insertions, 115 deletions
diff --git a/deps/v8/src/compiler/bytecode-graph-builder.cc b/deps/v8/src/compiler/bytecode-graph-builder.cc index 2249cbcb3f..a17947a246 100644 --- a/deps/v8/src/compiler/bytecode-graph-builder.cc +++ b/deps/v8/src/compiler/bytecode-graph-builder.cc @@ -60,6 +60,9 @@ class BytecodeGraphBuilder::Environment : public ZoneObject { Environment* CopyForConditional() const; Environment* CopyForLoop(); void Merge(Environment* other); + void PrepareForOsr(); + + void PrepareForLoopExit(Node* loop); private: explicit Environment(const Environment* copy); @@ -109,6 +112,11 @@ class BytecodeGraphBuilder::FrameStateBeforeAndAfter { id_before, OutputFrameStateCombine::Ignore()); id_after_ = BailoutId(id_before.ToInt() + builder->bytecode_iterator().current_bytecode_size()); + // Create an explicit checkpoint node for before the operation. + Node* node = builder_->NewNode(builder_->common()->Checkpoint()); + DCHECK_EQ(IrOpcode::kDead, + NodeProperties::GetFrameStateInput(node)->opcode()); + NodeProperties::ReplaceFrameStateInput(node, frame_state_before_); } ~FrameStateBeforeAndAfter() { @@ -123,29 +131,21 @@ class BytecodeGraphBuilder::FrameStateBeforeAndAfter { void AddToNode(Node* node, OutputFrameStateCombine combine) { DCHECK(!added_to_node_); - int count = OperatorProperties::GetFrameStateInputCount(node->op()); - DCHECK_LE(count, 2); - if (count >= 1) { + bool has_frame_state = OperatorProperties::HasFrameStateInput(node->op()); + if (has_frame_state) { // Add the frame state for after the operation. DCHECK_EQ(IrOpcode::kDead, - NodeProperties::GetFrameStateInput(node, 0)->opcode()); + NodeProperties::GetFrameStateInput(node)->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_); + NodeProperties::ReplaceFrameStateInput(node, frame_state_after); } if (!combine.IsOutputIgnored()) { output_poke_offset_ = static_cast<int>(combine.GetOffsetToPokeAt()); output_poke_count_ = node->op()->ValueOutputCount(); } - frame_states_unused_ = count == 0; + frame_states_unused_ = !has_frame_state; added_to_node_ = true; } @@ -352,12 +352,39 @@ void BytecodeGraphBuilder::Environment::PrepareForLoop() { builder()->exit_controls_.push_back(terminate); } +void BytecodeGraphBuilder::Environment::PrepareForOsr() { + DCHECK_EQ(IrOpcode::kLoop, GetControlDependency()->opcode()); + DCHECK_EQ(1, GetControlDependency()->InputCount()); + Node* start = graph()->start(); + + // Create a control node for the OSR entry point and merge it into the loop + // header. Update the current environment's control dependency accordingly. + Node* entry = graph()->NewNode(common()->OsrLoopEntry(), start, start); + Node* control = builder()->MergeControl(GetControlDependency(), entry); + UpdateControlDependency(control); + + // Create a merge of the effect from the OSR entry and the existing effect + // dependency. Update the current environment's effect dependency accordingly. + Node* effect = builder()->MergeEffect(GetEffectDependency(), entry, control); + UpdateEffectDependency(effect); + + // Rename all values in the environment which will extend or introduce Phi + // nodes to contain the OSR values available at the entry point. + Node* osr_context = graph()->NewNode( + common()->OsrValue(Linkage::kOsrContextSpillSlotIndex), entry); + context_ = builder()->MergeValue(context_, osr_context, control); + int size = static_cast<int>(values()->size()); + for (int i = 0; i < size; i++) { + int idx = i; // Indexing scheme follows {StandardFrame}, adapt accordingly. + if (i >= register_base()) idx += InterpreterFrameConstants::kExtraSlotCount; + if (i >= accumulator_base()) idx = Linkage::kOsrAccumulatorRegisterIndex; + Node* osr_value = graph()->NewNode(common()->OsrValue(idx), entry); + values_[i] = builder()->MergeValue(values_[i], osr_value, control); + } +} bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate( Node** state_values, int offset, int count) { - if (!builder()->deoptimization_enabled_) { - return false; - } if (*state_values == nullptr) { return true; } @@ -372,6 +399,31 @@ bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate( return false; } +void BytecodeGraphBuilder::Environment::PrepareForLoopExit(Node* loop) { + DCHECK_EQ(loop->opcode(), IrOpcode::kLoop); + + Node* control = GetControlDependency(); + + // Create the loop exit node. + Node* loop_exit = graph()->NewNode(common()->LoopExit(), control, loop); + UpdateControlDependency(loop_exit); + + // Rename the effect. + Node* effect_rename = graph()->NewNode(common()->LoopExitEffect(), + GetEffectDependency(), loop_exit); + UpdateEffectDependency(effect_rename); + + // TODO(jarin) We should also rename context here. However, uncoditional + // 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; + } +} void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values, int offset, @@ -385,10 +437,6 @@ void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values, Node* BytecodeGraphBuilder::Environment::Checkpoint( BailoutId bailout_id, OutputFrameStateCombine combine) { - if (!builder()->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(), @@ -423,7 +471,6 @@ bool BytecodeGraphBuilder::Environment::StateValuesAreUpToDate( bool BytecodeGraphBuilder::Environment::StateValuesAreUpToDate( int output_poke_offset, int output_poke_count) { - if (!builder()->deoptimization_enabled_) return true; // 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; @@ -444,12 +491,12 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone, bytecode_array_(handle(info->shared_info()->bytecode_array())), exception_handler_table_( handle(HandlerTable::cast(bytecode_array()->handler_table()))), - feedback_vector_(handle(info->shared_info()->feedback_vector())), + feedback_vector_(handle(info->closure()->feedback_vector())), frame_state_function_info_(common()->CreateFrameStateFunctionInfo( FrameStateType::kInterpretedFunction, bytecode_array()->parameter_count(), bytecode_array()->register_count(), info->shared_info())), - deoptimization_enabled_(info->is_deoptimization_enabled()), + osr_ast_id_(info->osr_ast_id()), merge_environments_(local_zone), exception_handlers_(local_zone), current_exception_handler_(0), @@ -524,6 +571,10 @@ bool BytecodeGraphBuilder::CreateGraph() { GetFunctionContext()); set_environment(&env); + // For OSR add an {OsrNormalEntry} as the start of the top-level environment. + // It will be replaced with {Dead} after typing and optimizations. + if (!osr_ast_id_.IsNone()) NewNode(common()->OsrNormalEntry()); + VisitBytecodes(); // Finish the basic structure of the graph. @@ -538,8 +589,11 @@ bool BytecodeGraphBuilder::CreateGraph() { void BytecodeGraphBuilder::VisitBytecodes() { 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); interpreter::BytecodeArrayIterator iterator(bytecode_array()); set_bytecode_iterator(&iterator); while (!iterator.done()) { @@ -586,6 +640,11 @@ void BytecodeGraphBuilder::VisitLdaUndefined() { environment()->BindAccumulator(node); } +void BytecodeGraphBuilder::VisitLdrUndefined() { + Node* node = jsgraph()->UndefinedConstant(); + environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0), node); +} + void BytecodeGraphBuilder::VisitLdaNull() { Node* node = jsgraph()->NullConstant(); environment()->BindAccumulator(node); @@ -623,25 +682,33 @@ void BytecodeGraphBuilder::VisitMov() { environment()->BindRegister(bytecode_iterator().GetRegisterOperand(1), value); } -void BytecodeGraphBuilder::BuildLoadGlobal( - TypeofMode typeof_mode) { - FrameStateBeforeAndAfter states(this); - Handle<Name> name = - Handle<Name>::cast(bytecode_iterator().GetConstantForIndexOperand(0)); +Node* BytecodeGraphBuilder::BuildLoadGlobal(TypeofMode typeof_mode) { VectorSlotPair feedback = - CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(1)); - + CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(0)); + DCHECK_EQ(FeedbackVectorSlotKind::LOAD_GLOBAL_IC, + feedback_vector()->GetKind(feedback.slot())); + Handle<Name> name(feedback_vector()->GetName(feedback.slot())); const Operator* op = javascript()->LoadGlobal(name, feedback, typeof_mode); - Node* node = NewNode(op, GetFunctionClosure()); - environment()->BindAccumulator(node, &states); + return NewNode(op, GetFunctionClosure()); } void BytecodeGraphBuilder::VisitLdaGlobal() { - BuildLoadGlobal(TypeofMode::NOT_INSIDE_TYPEOF); + FrameStateBeforeAndAfter states(this); + Node* node = BuildLoadGlobal(TypeofMode::NOT_INSIDE_TYPEOF); + environment()->BindAccumulator(node, &states); +} + +void BytecodeGraphBuilder::VisitLdrGlobal() { + FrameStateBeforeAndAfter states(this); + Node* node = BuildLoadGlobal(TypeofMode::NOT_INSIDE_TYPEOF); + environment()->BindRegister(bytecode_iterator().GetRegisterOperand(1), node, + &states); } void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeof() { - BuildLoadGlobal(TypeofMode::INSIDE_TYPEOF); + FrameStateBeforeAndAfter states(this); + Node* node = BuildLoadGlobal(TypeofMode::INSIDE_TYPEOF); + environment()->BindAccumulator(node, &states); } void BytecodeGraphBuilder::BuildStoreGlobal(LanguageMode language_mode) { @@ -665,7 +732,7 @@ void BytecodeGraphBuilder::VisitStaGlobalStrict() { BuildStoreGlobal(LanguageMode::STRICT); } -void BytecodeGraphBuilder::VisitLdaContextSlot() { +Node* BytecodeGraphBuilder::BuildLoadContextSlot() { // 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. @@ -676,10 +743,19 @@ void BytecodeGraphBuilder::VisitLdaContextSlot() { 0, bytecode_iterator().GetIndexOperand(1), false); Node* context = environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); - Node* node = NewNode(op, context); + return NewNode(op, context); +} + +void BytecodeGraphBuilder::VisitLdaContextSlot() { + Node* node = BuildLoadContextSlot(); environment()->BindAccumulator(node); } +void BytecodeGraphBuilder::VisitLdrContextSlot() { + Node* node = BuildLoadContextSlot(); + environment()->BindRegister(bytecode_iterator().GetRegisterOperand(2), node); +} + void BytecodeGraphBuilder::VisitStaContextSlot() { // TODO(mythria): LoadContextSlots are unrolled by the required depth when // generating bytecode. Hence the value of depth is always 0. Update this @@ -732,8 +808,7 @@ void BytecodeGraphBuilder::VisitStaLookupSlotStrict() { BuildStaLookupSlot(LanguageMode::STRICT); } -void BytecodeGraphBuilder::BuildNamedLoad() { - FrameStateBeforeAndAfter states(this); +Node* BytecodeGraphBuilder::BuildNamedLoad() { Node* object = environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); Handle<Name> name = @@ -742,14 +817,23 @@ void BytecodeGraphBuilder::BuildNamedLoad() { CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2)); const Operator* op = javascript()->LoadNamed(name, feedback); - Node* node = NewNode(op, object, GetFunctionClosure()); - environment()->BindAccumulator(node, &states); + return NewNode(op, object, GetFunctionClosure()); } -void BytecodeGraphBuilder::VisitLoadIC() { BuildNamedLoad(); } +void BytecodeGraphBuilder::VisitLdaNamedProperty() { + FrameStateBeforeAndAfter states(this); + Node* node = BuildNamedLoad(); + environment()->BindAccumulator(node, &states); +} -void BytecodeGraphBuilder::BuildKeyedLoad() { +void BytecodeGraphBuilder::VisitLdrNamedProperty() { FrameStateBeforeAndAfter states(this); + Node* node = BuildNamedLoad(); + environment()->BindRegister(bytecode_iterator().GetRegisterOperand(3), node, + &states); +} + +Node* BytecodeGraphBuilder::BuildKeyedLoad() { Node* key = environment()->LookupAccumulator(); Node* object = environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); @@ -757,11 +841,21 @@ void BytecodeGraphBuilder::BuildKeyedLoad() { CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(1)); const Operator* op = javascript()->LoadProperty(feedback); - Node* node = NewNode(op, object, key, GetFunctionClosure()); + return NewNode(op, object, key, GetFunctionClosure()); +} + +void BytecodeGraphBuilder::VisitLdaKeyedProperty() { + FrameStateBeforeAndAfter states(this); + Node* node = BuildKeyedLoad(); environment()->BindAccumulator(node, &states); } -void BytecodeGraphBuilder::VisitKeyedLoadIC() { BuildKeyedLoad(); } +void BytecodeGraphBuilder::VisitLdrKeyedProperty() { + FrameStateBeforeAndAfter states(this); + Node* node = BuildKeyedLoad(); + environment()->BindRegister(bytecode_iterator().GetRegisterOperand(2), node, + &states); +} void BytecodeGraphBuilder::BuildNamedStore(LanguageMode language_mode) { FrameStateBeforeAndAfter states(this); @@ -778,11 +872,11 @@ void BytecodeGraphBuilder::BuildNamedStore(LanguageMode language_mode) { environment()->RecordAfterState(node, &states); } -void BytecodeGraphBuilder::VisitStoreICSloppy() { +void BytecodeGraphBuilder::VisitStaNamedPropertySloppy() { BuildNamedStore(LanguageMode::SLOPPY); } -void BytecodeGraphBuilder::VisitStoreICStrict() { +void BytecodeGraphBuilder::VisitStaNamedPropertyStrict() { BuildNamedStore(LanguageMode::STRICT); } @@ -801,11 +895,11 @@ void BytecodeGraphBuilder::BuildKeyedStore(LanguageMode language_mode) { environment()->RecordAfterState(node, &states); } -void BytecodeGraphBuilder::VisitKeyedStoreICSloppy() { +void BytecodeGraphBuilder::VisitStaKeyedPropertySloppy() { BuildKeyedStore(LanguageMode::SLOPPY); } -void BytecodeGraphBuilder::VisitKeyedStoreICStrict() { +void BytecodeGraphBuilder::VisitStaKeyedPropertyStrict() { BuildKeyedStore(LanguageMode::STRICT); } @@ -832,6 +926,43 @@ void BytecodeGraphBuilder::VisitCreateClosure() { environment()->BindAccumulator(closure); } +void BytecodeGraphBuilder::VisitCreateBlockContext() { + Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::cast( + bytecode_iterator().GetConstantForIndexOperand(0)); + + const Operator* op = javascript()->CreateBlockContext(scope_info); + Node* context = NewNode(op, environment()->LookupAccumulator()); + environment()->BindAccumulator(context); +} + +void BytecodeGraphBuilder::VisitCreateFunctionContext() { + uint32_t slots = bytecode_iterator().GetIndexOperand(0); + const Operator* op = javascript()->CreateFunctionContext(slots); + Node* context = NewNode(op, GetFunctionClosure()); + environment()->BindAccumulator(context); +} + +void BytecodeGraphBuilder::VisitCreateCatchContext() { + interpreter::Register reg = bytecode_iterator().GetRegisterOperand(0); + Node* exception = environment()->LookupRegister(reg); + Handle<String> name = + Handle<String>::cast(bytecode_iterator().GetConstantForIndexOperand(1)); + Node* closure = environment()->LookupAccumulator(); + + const Operator* op = javascript()->CreateCatchContext(name); + Node* context = NewNode(op, exception, closure); + environment()->BindAccumulator(context); +} + +void BytecodeGraphBuilder::VisitCreateWithContext() { + Node* object = + environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); + + const Operator* op = javascript()->CreateWithContext(); + Node* context = NewNode(op, object, environment()->LookupAccumulator()); + environment()->BindAccumulator(context); +} + void BytecodeGraphBuilder::BuildCreateArguments(CreateArgumentsType type) { FrameStateBeforeAndAfter states(this); const Operator* op = javascript()->CreateArguments(type); @@ -879,15 +1010,21 @@ void BytecodeGraphBuilder::VisitCreateArrayLiteral() { } void BytecodeGraphBuilder::VisitCreateObjectLiteral() { + FrameStateBeforeAndAfter states(this); Handle<FixedArray> constant_properties = Handle<FixedArray>::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::CreateObjectLiteralFlags::FlagsBits::decode(bytecode_flags); // TODO(mstarzinger): Thread through number of properties. int number_of_properties = constant_properties->length() / 2; - const Operator* op = javascript()->CreateLiteralObject( - constant_properties, literal_flags, literal_index, number_of_properties); - BuildCreateLiteral(op); + Node* literal = NewNode( + javascript()->CreateLiteralObject(constant_properties, literal_flags, + literal_index, number_of_properties), + GetFunctionClosure()); + environment()->BindRegister(bytecode_iterator().GetRegisterOperand(3), + literal, &states); } Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op, @@ -908,14 +1045,15 @@ Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op, void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode) { FrameStateBeforeAndAfter states(this); - // 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(bytecode_iterator().GetRegisterOperand(0)); interpreter::Register receiver = 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); VectorSlotPair feedback = CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(3)); @@ -963,8 +1101,7 @@ Node* BytecodeGraphBuilder::ProcessCallRuntimeArguments( void BytecodeGraphBuilder::VisitCallRuntime() { FrameStateBeforeAndAfter states(this); - Runtime::FunctionId functionId = static_cast<Runtime::FunctionId>( - bytecode_iterator().GetRuntimeIdOperand(0)); + Runtime::FunctionId functionId = bytecode_iterator().GetRuntimeIdOperand(0); interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1); size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2); @@ -976,8 +1113,7 @@ void BytecodeGraphBuilder::VisitCallRuntime() { void BytecodeGraphBuilder::VisitCallRuntimeForPair() { FrameStateBeforeAndAfter states(this); - Runtime::FunctionId functionId = static_cast<Runtime::FunctionId>( - bytecode_iterator().GetRuntimeIdOperand(0)); + Runtime::FunctionId functionId = bytecode_iterator().GetRuntimeIdOperand(0); interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1); size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2); interpreter::Register first_return = @@ -991,8 +1127,7 @@ void BytecodeGraphBuilder::VisitCallRuntimeForPair() { void BytecodeGraphBuilder::VisitInvokeIntrinsic() { FrameStateBeforeAndAfter states(this); - Runtime::FunctionId functionId = static_cast<Runtime::FunctionId>( - bytecode_iterator().GetRuntimeIdOperand(0)); + Runtime::FunctionId functionId = bytecode_iterator().GetIntrinsicIdOperand(0); interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1); size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2); @@ -1042,6 +1177,7 @@ void BytecodeGraphBuilder::BuildThrow() { } void BytecodeGraphBuilder::VisitThrow() { + BuildLoopExitsForFunctionExit(); BuildThrow(); Node* call = environment()->LookupAccumulator(); Node* control = NewNode(common()->Throw(), call); @@ -1049,6 +1185,7 @@ void BytecodeGraphBuilder::VisitThrow() { } void BytecodeGraphBuilder::VisitReThrow() { + BuildLoopExitsForFunctionExit(); Node* value = environment()->LookupAccumulator(); Node* call = NewNode(javascript()->CallRuntime(Runtime::kReThrow), value); Node* control = NewNode(common()->Throw(), call); @@ -1064,78 +1201,143 @@ void BytecodeGraphBuilder::BuildBinaryOp(const Operator* js_op) { environment()->BindAccumulator(node, &states); } +// Helper function to create binary operation hint from the recorded type +// feedback. +BinaryOperationHint BytecodeGraphBuilder::GetBinaryOperationHint( + int operand_index) { + FeedbackVectorSlot slot = feedback_vector()->ToSlot( + bytecode_iterator().GetIndexOperand(operand_index)); + DCHECK_EQ(FeedbackVectorSlotKind::GENERAL, feedback_vector()->GetKind(slot)); + Object* feedback = feedback_vector()->Get(slot); + BinaryOperationHint hint = BinaryOperationHint::kAny; + if (feedback->IsSmi()) { + hint = BinaryOperationHintFromFeedback((Smi::cast(feedback))->value()); + } + return hint; +} + void BytecodeGraphBuilder::VisitAdd() { - BinaryOperationHints hints = BinaryOperationHints::Any(); - BuildBinaryOp(javascript()->Add(hints)); + BuildBinaryOp( + javascript()->Add(GetBinaryOperationHint(kBinaryOperationHintIndex))); } void BytecodeGraphBuilder::VisitSub() { - BinaryOperationHints hints = BinaryOperationHints::Any(); - BuildBinaryOp(javascript()->Subtract(hints)); + BuildBinaryOp(javascript()->Subtract( + GetBinaryOperationHint(kBinaryOperationHintIndex))); } void BytecodeGraphBuilder::VisitMul() { - BinaryOperationHints hints = BinaryOperationHints::Any(); - BuildBinaryOp(javascript()->Multiply(hints)); + BuildBinaryOp(javascript()->Multiply( + GetBinaryOperationHint(kBinaryOperationHintIndex))); } void BytecodeGraphBuilder::VisitDiv() { - BinaryOperationHints hints = BinaryOperationHints::Any(); - BuildBinaryOp(javascript()->Divide(hints)); + BuildBinaryOp( + javascript()->Divide(GetBinaryOperationHint(kBinaryOperationHintIndex))); } void BytecodeGraphBuilder::VisitMod() { - BinaryOperationHints hints = BinaryOperationHints::Any(); - BuildBinaryOp(javascript()->Modulus(hints)); + BuildBinaryOp( + javascript()->Modulus(GetBinaryOperationHint(kBinaryOperationHintIndex))); } void BytecodeGraphBuilder::VisitBitwiseOr() { - BinaryOperationHints hints = BinaryOperationHints::Any(); - BuildBinaryOp(javascript()->BitwiseOr(hints)); + BuildBinaryOp(javascript()->BitwiseOr( + GetBinaryOperationHint(kBinaryOperationHintIndex))); } void BytecodeGraphBuilder::VisitBitwiseXor() { - BinaryOperationHints hints = BinaryOperationHints::Any(); - BuildBinaryOp(javascript()->BitwiseXor(hints)); + BuildBinaryOp(javascript()->BitwiseXor( + GetBinaryOperationHint(kBinaryOperationHintIndex))); } void BytecodeGraphBuilder::VisitBitwiseAnd() { - BinaryOperationHints hints = BinaryOperationHints::Any(); - BuildBinaryOp(javascript()->BitwiseAnd(hints)); + BuildBinaryOp(javascript()->BitwiseAnd( + GetBinaryOperationHint(kBinaryOperationHintIndex))); } void BytecodeGraphBuilder::VisitShiftLeft() { - BinaryOperationHints hints = BinaryOperationHints::Any(); - BuildBinaryOp(javascript()->ShiftLeft(hints)); + BuildBinaryOp(javascript()->ShiftLeft( + GetBinaryOperationHint(kBinaryOperationHintIndex))); } void BytecodeGraphBuilder::VisitShiftRight() { - BinaryOperationHints hints = BinaryOperationHints::Any(); - BuildBinaryOp(javascript()->ShiftRight(hints)); + BuildBinaryOp(javascript()->ShiftRight( + GetBinaryOperationHint(kBinaryOperationHintIndex))); } void BytecodeGraphBuilder::VisitShiftRightLogical() { - BinaryOperationHints hints = BinaryOperationHints::Any(); - BuildBinaryOp(javascript()->ShiftRightLogical(hints)); + BuildBinaryOp(javascript()->ShiftRightLogical( + GetBinaryOperationHint(kBinaryOperationHintIndex))); +} + +void BytecodeGraphBuilder::BuildBinaryOpWithImmediate(const Operator* js_op) { + FrameStateBeforeAndAfter states(this); + Node* left = + environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1)); + Node* right = jsgraph()->Constant(bytecode_iterator().GetImmediateOperand(0)); + Node* node = NewNode(js_op, left, right); + environment()->BindAccumulator(node, &states); +} + +void BytecodeGraphBuilder::VisitAddSmi() { + BuildBinaryOpWithImmediate( + javascript()->Add(GetBinaryOperationHint(kBinaryOperationSmiHintIndex))); +} + +void BytecodeGraphBuilder::VisitSubSmi() { + BuildBinaryOpWithImmediate(javascript()->Subtract( + GetBinaryOperationHint(kBinaryOperationSmiHintIndex))); +} + +void BytecodeGraphBuilder::VisitBitwiseOrSmi() { + BuildBinaryOpWithImmediate(javascript()->BitwiseOr( + GetBinaryOperationHint(kBinaryOperationSmiHintIndex))); +} + +void BytecodeGraphBuilder::VisitBitwiseAndSmi() { + BuildBinaryOpWithImmediate(javascript()->BitwiseAnd( + GetBinaryOperationHint(kBinaryOperationSmiHintIndex))); +} + +void BytecodeGraphBuilder::VisitShiftLeftSmi() { + BuildBinaryOpWithImmediate(javascript()->ShiftLeft( + GetBinaryOperationHint(kBinaryOperationSmiHintIndex))); +} + +void BytecodeGraphBuilder::VisitShiftRightSmi() { + BuildBinaryOpWithImmediate(javascript()->ShiftRight( + GetBinaryOperationHint(kBinaryOperationSmiHintIndex))); } void BytecodeGraphBuilder::VisitInc() { FrameStateBeforeAndAfter states(this); - const Operator* js_op = javascript()->Add(BinaryOperationHints::Any()); + // 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()->OneConstant()); + jsgraph()->Constant(-1)); environment()->BindAccumulator(node, &states); } void BytecodeGraphBuilder::VisitDec() { FrameStateBeforeAndAfter states(this); - const Operator* js_op = javascript()->Subtract(BinaryOperationHints::Any()); + const Operator* js_op = + javascript()->Subtract(GetBinaryOperationHint(kCountOperationHintIndex)); Node* node = NewNode(js_op, environment()->LookupAccumulator(), jsgraph()->OneConstant()); environment()->BindAccumulator(node, &states); } void BytecodeGraphBuilder::VisitLogicalNot() { + Node* value = environment()->LookupAccumulator(); + Node* node = NewNode(common()->Select(MachineRepresentation::kTagged), value, + jsgraph()->FalseConstant(), jsgraph()->TrueConstant()); + environment()->BindAccumulator(node); +} + +void BytecodeGraphBuilder::VisitToBooleanLogicalNot() { Node* value = NewNode(javascript()->ToBoolean(ToBooleanHint::kAny), environment()->LookupAccumulator()); Node* node = NewNode(common()->Select(MachineRepresentation::kTagged), value, @@ -1177,31 +1379,38 @@ void BytecodeGraphBuilder::BuildCompareOp(const Operator* js_op) { } void BytecodeGraphBuilder::VisitTestEqual() { - BuildCompareOp(javascript()->Equal()); + CompareOperationHint hint = CompareOperationHint::kAny; + BuildCompareOp(javascript()->Equal(hint)); } void BytecodeGraphBuilder::VisitTestNotEqual() { - BuildCompareOp(javascript()->NotEqual()); + CompareOperationHint hint = CompareOperationHint::kAny; + BuildCompareOp(javascript()->NotEqual(hint)); } void BytecodeGraphBuilder::VisitTestEqualStrict() { - BuildCompareOp(javascript()->StrictEqual()); + CompareOperationHint hint = CompareOperationHint::kAny; + BuildCompareOp(javascript()->StrictEqual(hint)); } void BytecodeGraphBuilder::VisitTestLessThan() { - BuildCompareOp(javascript()->LessThan()); + CompareOperationHint hint = CompareOperationHint::kAny; + BuildCompareOp(javascript()->LessThan(hint)); } void BytecodeGraphBuilder::VisitTestGreaterThan() { - BuildCompareOp(javascript()->GreaterThan()); + CompareOperationHint hint = CompareOperationHint::kAny; + BuildCompareOp(javascript()->GreaterThan(hint)); } void BytecodeGraphBuilder::VisitTestLessThanOrEqual() { - BuildCompareOp(javascript()->LessThanOrEqual()); + CompareOperationHint hint = CompareOperationHint::kAny; + BuildCompareOp(javascript()->LessThanOrEqual(hint)); } void BytecodeGraphBuilder::VisitTestGreaterThanOrEqual() { - BuildCompareOp(javascript()->GreaterThanOrEqual()); + CompareOperationHint hint = CompareOperationHint::kAny; + BuildCompareOp(javascript()->GreaterThanOrEqual(hint)); } void BytecodeGraphBuilder::VisitTestIn() { @@ -1209,14 +1418,14 @@ void BytecodeGraphBuilder::VisitTestIn() { } void BytecodeGraphBuilder::VisitTestInstanceOf() { - DCHECK(!FLAG_harmony_instanceof); BuildCompareOp(javascript()->InstanceOf()); } void BytecodeGraphBuilder::BuildCastOperator(const Operator* js_op) { FrameStateBeforeAndAfter states(this); - Node* node = NewNode(js_op, environment()->LookupAccumulator()); - environment()->BindAccumulator(node, &states); + Node* value = NewNode(js_op, environment()->LookupAccumulator()); + environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0), value, + &states); } void BytecodeGraphBuilder::VisitToName() { @@ -1296,7 +1505,17 @@ void BytecodeGraphBuilder::VisitStackCheck() { environment()->RecordAfterState(node, &states); } +void BytecodeGraphBuilder::VisitOsrPoll() { + // TODO(4764): This should be moved into the {VisitBytecodes} once we merge + // the polling with existing bytecode. This will also guarantee that we are + // not missing the OSR entry point, which we wouldn't catch right now. + if (osr_ast_id_.ToInt() == bytecode_iterator().current_offset()) { + environment()->PrepareForOsr(); + } +} + void BytecodeGraphBuilder::VisitReturn() { + BuildLoopExitsForFunctionExit(); Node* control = NewNode(common()->Return(), environment()->LookupAccumulator()); MergeControlToLeaveFunction(control); @@ -1317,10 +1536,11 @@ DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK); void BytecodeGraphBuilder::BuildForInPrepare() { FrameStateBeforeAndAfter states(this); - Node* receiver = environment()->LookupAccumulator(); + Node* receiver = + environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0)); Node* prepare = NewNode(javascript()->ForInPrepare(), receiver); environment()->BindRegistersToProjections( - bytecode_iterator().GetRegisterOperand(0), prepare, &states); + bytecode_iterator().GetRegisterOperand(1), prepare, &states); } void BytecodeGraphBuilder::VisitForInPrepare() { BuildForInPrepare(); } @@ -1362,6 +1582,51 @@ void BytecodeGraphBuilder::VisitForInStep() { environment()->BindAccumulator(index, &states); } +void BytecodeGraphBuilder::VisitSuspendGenerator() { + Node* state = environment()->LookupAccumulator(); + Node* generator = environment()->LookupRegister( + bytecode_iterator().GetRegisterOperand(0)); + // The offsets used by the bytecode iterator are relative to a different base + // than what is used in the interpreter, hence the addition. + Node* offset = + jsgraph()->Constant(bytecode_iterator().current_offset() + + (BytecodeArray::kHeaderSize - kHeapObjectTag)); + + int register_count = environment()->register_count(); + int value_input_count = 3 + register_count; + + Node** value_inputs = local_zone()->NewArray<Node*>(value_input_count); + value_inputs[0] = generator; + value_inputs[1] = state; + value_inputs[2] = offset; + for (int i = 0; i < register_count; ++i) { + value_inputs[3 + i] = + environment()->LookupRegister(interpreter::Register(i)); + } + + MakeNode(javascript()->GeneratorStore(register_count), value_input_count, + value_inputs, false); +} + +void BytecodeGraphBuilder::VisitResumeGenerator() { + FrameStateBeforeAndAfter states(this); + + Node* generator = environment()->LookupRegister( + bytecode_iterator().GetRegisterOperand(0)); + + // Bijection between registers and array indices must match that used in + // InterpreterAssembler::ExportRegisterFile. + for (int i = 0; i < environment()->register_count(); ++i) { + Node* value = NewNode(javascript()->GeneratorRestoreRegister(i), generator); + environment()->BindRegister(interpreter::Register(i), value); + } + + Node* state = + NewNode(javascript()->GeneratorRestoreContinuation(), generator); + + environment()->BindAccumulator(state, &states); +} + void BytecodeGraphBuilder::VisitWide() { // Consumed by the BytecodeArrayIterator. UNREACHABLE(); @@ -1373,10 +1638,12 @@ void BytecodeGraphBuilder::VisitExtraWide() { } void BytecodeGraphBuilder::VisitIllegal() { - // Never present in valid bytecode. + // Not emitted in valid bytecode. UNREACHABLE(); } +void BytecodeGraphBuilder::VisitNop() {} + void BytecodeGraphBuilder::SwitchToMergeEnvironment(int current_offset) { if (merge_environments_[current_offset] != nullptr) { if (environment() != nullptr) { @@ -1395,6 +1662,7 @@ void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) { } void BytecodeGraphBuilder::MergeIntoSuccessorEnvironment(int target_offset) { + BuildLoopExitsForBranch(target_offset); if (merge_environments_[target_offset] == 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 @@ -1413,6 +1681,28 @@ void BytecodeGraphBuilder::MergeControlToLeaveFunction(Node* exit) { set_environment(nullptr); } +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)); + } +} + +void BytecodeGraphBuilder::BuildLoopExitsUntilLoop(int loop_offset) { + int origin_offset = bytecode_iterator().current_offset(); + int current_loop = loop_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); + } +} + +void BytecodeGraphBuilder::BuildLoopExitsForFunctionExit() { + BuildLoopExitsUntilLoop(-1); +} + void BytecodeGraphBuilder::BuildJump() { MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); } @@ -1431,7 +1721,8 @@ void BytecodeGraphBuilder::BuildConditionalJump(Node* condition) { void BytecodeGraphBuilder::BuildJumpIfEqual(Node* comperand) { Node* accumulator = environment()->LookupAccumulator(); Node* condition = - NewNode(javascript()->StrictEqual(), accumulator, comperand); + NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), + accumulator, comperand); BuildConditionalJump(condition); } @@ -1440,14 +1731,17 @@ 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); + Node* condition = + NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), to_boolean, + comperand); BuildConditionalJump(condition); } void BytecodeGraphBuilder::BuildJumpIfNotHole() { Node* accumulator = environment()->LookupAccumulator(); - Node* condition = NewNode(javascript()->StrictEqual(), accumulator, - jsgraph()->TheHoleConstant()); + Node* condition = + NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), + accumulator, jsgraph()->TheHoleConstant()); Node* node = NewNode(common()->Select(MachineRepresentation::kTagged), condition, jsgraph()->FalseConstant(), jsgraph()->TrueConstant()); @@ -1481,10 +1775,8 @@ void BytecodeGraphBuilder::EnterAndExitExceptionHandlers(int current_offset) { int next_end = table->GetRangeEnd(current_exception_handler_); int next_handler = table->GetRangeHandler(current_exception_handler_); int context_register = table->GetRangeData(current_exception_handler_); - CatchPrediction pred = - table->GetRangePrediction(current_exception_handler_); exception_handlers_.push( - {next_start, next_end, next_handler, context_register, pred}); + {next_start, next_end, next_handler, context_register}); current_exception_handler_++; } } @@ -1494,7 +1786,7 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, DCHECK_EQ(op->ValueInputCount(), value_input_count); bool has_context = OperatorProperties::HasContextInput(op); - int frame_state_count = OperatorProperties::GetFrameStateInputCount(op); + bool has_frame_state = OperatorProperties::HasFrameStateInput(op); bool has_control = op->ControlInputCount() == 1; bool has_effect = op->EffectInputCount() == 1; @@ -1502,13 +1794,13 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, DCHECK_LT(op->EffectInputCount(), 2); Node* result = nullptr; - if (!has_context && frame_state_count == 0 && !has_control && !has_effect) { + if (!has_context && !has_frame_state && !has_control && !has_effect) { result = graph()->NewNode(op, value_input_count, value_inputs, incomplete); } else { bool inside_handler = !exception_handlers_.empty(); int input_count_with_deps = value_input_count; if (has_context) ++input_count_with_deps; - input_count_with_deps += frame_state_count; + if (has_frame_state) ++input_count_with_deps; if (has_control) ++input_count_with_deps; if (has_effect) ++input_count_with_deps; Node** buffer = EnsureInputBufferSize(input_count_with_deps); @@ -1517,7 +1809,7 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, if (has_context) { *current_input++ = environment()->Context(); } - for (int i = 0; i < frame_state_count; i++) { + if (has_frame_state) { // The frame state will be inserted later. Here we misuse // the {Dead} node as a sentinel to be later overwritten // with the real frame state. @@ -1542,13 +1834,9 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, if (!result->op()->HasProperty(Operator::kNoThrow) && inside_handler) { int handler_offset = exception_handlers_.top().handler_offset_; int context_index = exception_handlers_.top().context_register_; - CatchPrediction prediction = exception_handlers_.top().pred_; interpreter::Register context_register(context_index); - IfExceptionHint hint = prediction == CatchPrediction::CAUGHT - ? IfExceptionHint::kLocallyCaught - : IfExceptionHint::kLocallyUncaught; Environment* success_env = environment()->CopyForConditional(); - const Operator* op = common()->IfException(hint); + const Operator* op = common()->IfException(); Node* effect = environment()->GetEffectDependency(); Node* on_exception = graph()->NewNode(op, effect, result); Node* context = environment()->LookupRegister(context_register); |