25#if V8_ENABLE_WEBASSEMBLY
38static const int kMaxDepthForInlining = 50;
43 if (v8_flags.trace_turbo_inlining) { \
44 StdoutStream() << x << "\n"; \
53 DCHECK(call->opcode() == IrOpcode::kJSCall ||
54 call->opcode() == IrOpcode::kJSConstruct);
58 return call_->
InputAt(JSCallOrConstructNode::TargetIndex());
85#if V8_ENABLE_WEBASSEMBLY
89 Node* exception_target,
91 JSWasmCallNode
n(call);
95 static_cast<int>(n.Parameters().signature()->parameter_count()));
101 Node* exception_target,
103 int argument_count) {
113 int const inlinee_new_target_index =
start.NewTargetOutputIndex();
114 int const inlinee_arity_index =
start.ArgCountOutputIndex();
115 int const inlinee_context_index =
start.ContextOutputIndex();
119 const int inliner_inputs = argument_count +
124 Node* use = edge.from();
125 switch (use->opcode()) {
126 case IrOpcode::kParameter: {
129 if (index < inliner_inputs && index < inlinee_new_target_index) {
132 Replace(use, call->InputAt(index));
133 }
else if (index == inlinee_new_target_index) {
136 }
else if (index == inlinee_arity_index) {
139 }
else if (index == inlinee_context_index) {
143#ifdef V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE
154 edge.UpdateTo(effect);
156 edge.UpdateTo(control);
158 edge.UpdateTo(frame_state);
166 if (exception_target !=
nullptr) {
168 int subcall_count =
static_cast<int>(uncaught_subcalls.
size());
169 if (subcall_count > 0) {
170 TRACE(
"Inlinee contains " << subcall_count
171 <<
" calls without local exception handler; "
172 <<
"linking to surrounding exception handler.");
175 for (
Node* subcall : uncaught_subcalls) {
181 on_exception_nodes.
push_back(on_exception);
184 DCHECK_EQ(subcall_count,
static_cast<int>(on_exception_nodes.
size()));
185 if (subcall_count > 0) {
186 Node* control_output =
188 &on_exception_nodes.
front());
190 values_effects = on_exception_nodes;
191 values_effects.
push_back(control_output);
194 subcall_count + 1, &values_effects.
front());
195 Node* effect_output =
197 subcall_count + 1, &values_effects.
front());
210 switch (input->opcode()) {
211 case IrOpcode::kReturn:
216 case IrOpcode::kDeoptimize:
217 case IrOpcode::kTerminate:
218 case IrOpcode::kThrow:
230 if (!values.empty()) {
231 int const input_count =
static_cast<int>(controls.
size());
233 input_count, &controls.
front());
234 values.push_back(control_output);
238 static_cast<int>(values.size()), &values.front());
239 Node* effect_output =
241 static_cast<int>(effects.
size()), &effects.
front());
254 OptionalBytecodeArrayRef maybe_bytecode_array,
Node* context,
256 const int argument_count_with_receiver =
260 if (maybe_bytecode_array.has_value()) {
261 bytecode_array_handle = maybe_bytecode_array->object();
265 frame_state_type, argument_count_with_receiver, 0, 0, shared.object(),
266 bytecode_array_handle);
273 Node* params_node =
nullptr;
274#if V8_ENABLE_WEBASSEMBLY
275 const bool skip_params =
276 frame_state_type == FrameStateType::kWasmInlinedIntoJS;
278 const bool skip_params =
false;
294 node->InputAt(JSCallOrConstructNode::ReceiverOrNewTargetIndex()));
295 for (
int i = 0;
i < argument_count;
i++) {
300 params_node =
graph()->
NewNode(op_param,
static_cast<int>(params.size()),
303 if (context ==
nullptr) context =
jsgraph()->UndefinedConstant();
304 if (callee ==
nullptr) {
305 callee = node->
InputAt(JSCallOrConstructNode::TargetIndex());
315 return !shared_info.construct_as_builtin() &&
326 Node* target = node->
InputAt(JSCallOrConstructNode::TargetIndex());
337 if (!function.feedback_vector(
broker()).has_value()) {
350 broker()->target_native_context())) {
354 return function.shared(
broker());
362 if (match.IsJSCreateClosure()) {
366 }
else if (match.IsCheckClosure()) {
368 return cell.shared_function_info(
broker());
380 Node** context_out) {
382 Node* target = node->
InputAt(JSCallOrConstructNode::TargetIndex());
388 CHECK(function.feedback_vector(
broker()).has_value());
393 return function.raw_feedback_cell(
broker());
396 if (match.IsJSCreateClosure()) {
405 }
else if (match.IsCheckClosure()) {
412 match.
node(), effect, control);
422#if V8_ENABLE_WEBASSEMBLY
423JSInliner::WasmInlineResult JSInliner::TryWasmInlining(
424 const JSWasmCallNode& call_node) {
425 const JSWasmCallParameters& wasm_call_params = call_node.Parameters();
427 const int fct_index = wasm_call_params.function_index();
428 TRACE(
"Considering wasm function ["
430 << WasmFunctionNameForTrace(native_module, fct_index) <<
" of module "
431 << wasm_call_params.module() <<
" for inlining");
436 TRACE(
"- not inlining: another wasm module is already used for inlining");
444 TRACE(
"- not inlining: wasm inlining into try catch is not supported");
449 TFGraph::SubgraphScope graph_scope(
graph());
457 bool can_inline_body =
458 builder.TryWasmInlining(fct_index, native_module, inlining_id);
459 if (can_inline_body) {
468Reduction JSInliner::ReduceJSWasmCall(Node* node) {
469 JSWasmCallNode call_node(node);
470 const JSWasmCallParameters& wasm_call_params = call_node.Parameters();
471 int fct_index = wasm_call_params.function_index();
472 wasm::NativeModule* native_module = wasm_call_params.native_module();
473 const wasm::CanonicalSig*
sig = wasm_call_params.signature();
477 WasmInlineResult inline_result;
482 inline_result = TryWasmInlining(call_node);
486 Node* wrapper_start_node;
487 Node* wrapper_end_node;
488 size_t subgraph_min_node_id;
490 TFGraph::SubgraphScope scope(
graph());
496 Node* continuation_frame_state =
497 CreateJSWasmCallBuiltinContinuationFrameState(
498 jsgraph(), call_node.context(), call_node.frame_state(),
sig);
510 bool set_in_wasm_flag = !(inline_result.can_inline_body ||
511 v8_flags.turboshaft_wasm_in_js_inlining);
520 StartNode
start{wrapper_start_node};
522 Node* exception_target =
nullptr;
529 if (exception_target !=
nullptr) {
532 for (Node* subnode : inlined_nodes.reachable) {
534 if (subnode->id() < subgraph_min_node_id)
continue;
540 DCHECK_EQ(2, subnode->op()->ControlOutputCount());
541 uncaught_subcalls.push_back(subnode);
550 Node* wasm_fct_call =
nullptr;
551 if (inline_result.can_inline_body ||
552 v8_flags.turboshaft_wasm_in_js_inlining) {
554 for (Node* subnode : inlined_nodes.reachable) {
556 if (subnode->id() < subgraph_min_node_id)
continue;
558 if (subnode->opcode() == IrOpcode::kCall &&
560 wasm_fct_call = subnode;
564 DCHECK_IMPLIES(inline_result.can_inline_body, wasm_fct_call !=
nullptr);
568 if (
v8_flags.turboshaft_wasm_in_js_inlining && wasm_fct_call) {
570 {wasm_fct_call->id(), &wasm_call_params});
583 wrapper_end_node, exception_target, uncaught_subcalls);
585 if (inline_result.can_inline_body) {
586 InlineWasmFunction(wasm_fct_call, inline_result.body_start,
587 inline_result.body_end, call_node.frame_state(),
588 wasm_call_params.shared_fct_info(),
589 call_node.ArgumentCount(), context);
594void JSInliner::InlineWasmFunction(Node* call, Node* inlinee_start,
595 Node* inlinee_end, Node* frame_state,
596 SharedFunctionInfoRef shared_fct_info,
597 int argument_count, Node* context) {
609 Node* callee =
jsgraph()->UndefinedConstant();
611 call, FrameState{frame_state}, argument_count,
612 FrameStateType::kWasmInlinedIntoJS, shared_fct_info, {},
context, callee);
614 frame_state_inside, effect, control);
615 effect = check_point;
617 for (Edge edge : inlinee_start->use_edges()) {
618 Node* use = edge.from();
619 if (use ==
nullptr)
continue;
620 switch (use->opcode()) {
621 case IrOpcode::kParameter: {
630 edge.UpdateTo(effect);
634 edge.UpdateTo(use->opcode() == IrOpcode::kProjection
647 DCHECK_EQ(inlinee_end->inputs().count(), 1);
648 Node* terminator = *inlinee_end->inputs().begin();
649 DCHECK_EQ(terminator->opcode(), IrOpcode::kReturn);
658 int return_values = terminator->InputCount();
662 int return_count = return_values - 3;
663 Node* effect_output = terminator->InputAt(return_count + 1);
664 Node* control_output = terminator->InputAt(return_count + 2);
665 for (Edge use_edge : call->use_edges()) {
667 Node* use = use_edge.from();
682#if V8_ENABLE_WEBASSEMBLY
683 DCHECK_NE(node->opcode(), IrOpcode::kJSWasmCall);
689 if (!shared_info.has_value())
return NoChange();
695 shared_info->GetInlineability(
broker());
701 TRACE(
"Not inlining " << *shared_info <<
" into " << outer_shared_info
702 <<
" because it had its optimization disabled.");
709 if (node->opcode() == IrOpcode::kJSConstruct &&
711 TRACE(
"Not inlining " << *shared_info <<
" into " << outer_shared_info
712 <<
" because constructor is not constructable.");
718 if (node->opcode() == IrOpcode::kJSCall &&
720 TRACE(
"Not inlining " << *shared_info <<
" into " << outer_shared_info
721 <<
" because callee is a class constructor.");
727 int nesting_level = 0;
728 for (
Node* frame_state = call.frame_state();
729 frame_state->
opcode() == IrOpcode::kFrameState;
732 if (nesting_level > kMaxDepthForInlining) {
733 TRACE(
"Not inlining "
734 << *shared_info <<
" into " << outer_shared_info
735 <<
" because call has exceeded the maximum depth for function "
741 Node* exception_target =
nullptr;
749 CHECK(shared_info->is_compiled());
751 if (
info_->source_positions() &&
752 !shared_info->object()->AreSourcePositionsAvailable(
753 broker()->local_isolate_or_isolate())) {
760 TRACE(
"Not inlining " << *shared_info <<
" into " << outer_shared_info
761 <<
" because source positions are missing.");
769 TRACE(
"Inlining " << *shared_info <<
" into " << outer_shared_info
770 << ((exception_target !=
nullptr) ?
" (inside try-block)"
782 if (
v8_flags.profile_guided_optimization &&
788 v8_flags.invocation_count_for_early_optimization) {
789 info_->set_could_not_inline_all_candidates();
800 if (
info_->analyze_environment_liveness()) {
803 if (
info_->bailout_on_uninitialized()) {
825 if (exception_target !=
nullptr) {
843 if (node->opcode() == IrOpcode::kJSConstruct) {
859 if (NeedsImplicitReceiver(*shared_info)) {
860 Effect effect = n.effect();
862 Node* frame_state_inside;
864 if (
m.HasResolvedValue() &&
m.Ref(
broker()).IsJSFunction()) {
867 frame_state_inside = frame_state;
870 node, frame_state, n.ArgumentCount(),
876 caller_context, frame_state_inside, effect, control);
891 check, node, create);
899 Node* branch_is_receiver =
901 Node* branch_is_receiver_true =
903 Node* branch_is_receiver_false =
907 Runtime::kThrowConstructorReturnedNonObject),
909 branch_is_receiver_false);
910 uncaught_subcalls.
push_back(branch_is_receiver_false);
911 branch_is_receiver_false =
913 branch_is_receiver_false);
917 branch_is_receiver_true);
921 node->ReplaceInput(JSCallNode::ReceiverIndex(),
receiver);
926 *shared_info, bytecode_array, caller_context);
931 if (node->opcode() == IrOpcode::kJSCall &&
932 is_sloppy(shared_info->language_mode()) && !shared_info->native()) {
937 broker()->target_native_context().global_proxy_object(
broker()),
943 global_proxy, effect,
start);
945 JSCallNode::ReceiverIndex());
954 shared_info->internal_formal_parameter_count_without_receiver());
958 node, frame_state, call.argument_count(),
963 exception_target, uncaught_subcalls, call.argument_count());
static constexpr BytecodeOffset None()
int AddInlinedFunction(IndirectHandle< SharedFunctionInfo > inlined_function, IndirectHandle< BytecodeArray > inlined_bytecode, SourcePosition pos)
IndirectHandle< SharedFunctionInfo > shared_info() const
CodeKind code_kind() const
InlinedFunctionList & inlined_functions()
TickCounter & tick_counter()
@ kHasOptimizationDisabled
void push_back(const T &value)
static FieldAccess ForJSFunctionContext()
void ReplaceWithValue(Node *node, Node *value, Node *effect=nullptr, Node *control=nullptr)
void MergeControlToEnd(TFGraph *graph, CommonOperatorBuilder *common, Node *node)
static Reduction Replace(Node *node)
IndirectHandle< BytecodeArray > object() const
uint16_t parameter_count_without_receiver() const
ConvertReceiverMode convert_mode() const
const Operator * StateValues(int arguments, SparseInputMask bitmask)
const Operator * FrameState(BytecodeOffset bailout_id, OutputFrameStateCombine state_combine, const FrameStateFunctionInfo *function_info)
const FrameStateFunctionInfo * CreateFrameStateFunctionInfo(FrameStateType type, uint16_t parameter_count, uint16_t max_arguments, int local_count, IndirectHandle< SharedFunctionInfo > shared_info, IndirectHandle< BytecodeArray > bytecode_array)
OptionalSharedFunctionInfoRef shared_function_info(JSHeapBroker *broker) const
OptionalFeedbackVectorRef feedback_vector(JSHeapBroker *broker) const
Node * outer_frame_state() const
static bool IsInlineeOpcode(Value value)
CallFrequency const & frequency() const
FrameState frame_state() const
JSCallAccessor(Node *call)
int argument_count() const
Node * new_target() const
const CallParameters & Parameters() const
int ArgumentCount() const override
static constexpr int kFeedbackVectorInputCount
static constexpr int kReceiverOrNewTargetInputCount
static constexpr bool kHaveIdenticalLayouts
static constexpr int ArgumentIndex(int i)
static constexpr int kExtraInputCount
int ArgumentCount() const
const ConstructParameters & Parameters() const
JSOperatorBuilder * javascript() const
SimplifiedOperatorBuilder * simplified() const
Node * ConstantNoHole(ObjectRef ref, JSHeapBroker *broker)
Reduction ReduceJSCall(Node *node)
JSHeapBroker * broker() const
FrameState CreateArtificialFrameState(Node *node, FrameState outer_frame_state, int parameter_count, FrameStateType frame_state_type, SharedFunctionInfoRef shared, OptionalBytecodeArrayRef maybe_bytecode_array, Node *context=nullptr, Node *callee=nullptr)
Reduction InlineCall(Node *call, Node *new_target, Node *context, Node *frame_state, StartNode start, Node *end, Node *exception_target, const NodeVector &uncaught_subcalls, int argument_count)
CommonOperatorBuilder * common() const
NodeOriginTable *const node_origins_
Isolate * isolate() const
SimplifiedOperatorBuilder * simplified() const
JSGraph * jsgraph() const
JSOperatorBuilder * javascript() const
JsWasmCallsSidetable * js_wasm_calls_sidetable_
const wasm::WasmModule * wasm_module_
bool inline_wasm_fct_if_supported_
OptionalSharedFunctionInfoRef DetermineCallTarget(Node *node)
FeedbackCellRef DetermineCallContext(Node *node, Node **context_out)
OptimizedCompilationInfo * info_
SourcePositionTable *const source_positions_
CommonOperatorBuilder * common() const
static void ReplaceEffectInput(Node *node, Node *effect, int index=0)
static bool IsControlEdge(Edge edge)
static void ReplaceControlInput(Node *node, Node *control, int index=0)
static void ReplaceUses(Node *node, Node *value, Node *effect=nullptr, Node *success=nullptr, Node *exception=nullptr)
static Node * GetEffectInput(Node *node, int index=0)
static Node * GetContextInput(Node *node)
static bool IsValueEdge(Edge edge)
static bool IsFrameStateEdge(Edge edge)
static Node * GetFrameStateInput(Node *node)
static bool CanBePrimitive(JSHeapBroker *broker, Node *receiver, Effect effect)
static Node * GetValueInput(Node *node, int index)
static bool IsEffectEdge(Edge edge)
static void ReplaceValueInput(Node *node, Node *value, int index)
static bool IsExceptionalCall(Node *node, Node **out_exception=nullptr)
static Node * GetControlInput(Node *node, int index=0)
static Node * FindSuccessfulControlProjection(Node *node)
constexpr IrOpcode::Value opcode() const
const Operator * op() const
Node * InputAt(int index) const
static OutputFrameStateCombine Ignore()
static Reduction Changed(Node *node)
static Reduction NoChange()
SourcePosition GetSourcePosition(Node *node) const
Node * NewNode(const Operator *op, int input_count, Node *const *inputs, bool incomplete=false)
const WasmModule * module() const
WasmEnabledFeatures enabled_features() const
DirectHandle< Object > new_target
FrameState outer_frame_state
ZoneVector< RpoNumber > & result
TNode< Oddball > UndefinedConstant(JSGraph *jsgraph)
CallDescriptor const * CallDescriptorOf(const Operator *const op)
ZoneVector< Node * > NodeVector
int ParameterIndexOf(const Operator *const op)
const CallParameters & CallParametersOf(const Operator *op)
Handle< FeedbackCell > FeedbackCellOf(const Operator *op)
void BuildInlinedJSToWasmWrapper(Zone *zone, MachineGraph *mcgraph, const wasm::CanonicalSig *signature, Isolate *isolate, compiler::SourcePositionTable *spt, Node *frame_state, bool set_in_wasm_flag)
void BuildGraphFromBytecode(JSHeapBroker *broker, Zone *local_zone, SharedFunctionInfoRef shared_info, BytecodeArrayRef bytecode, FeedbackCellRef feedback_cell, BytecodeOffset osr_offset, JSGraph *jsgraph, CallFrequency const &invocation_frequency, SourcePositionTable *source_positions, NodeOriginTable *node_origins, int inlining_id, CodeKind code_kind, BytecodeGraphBuilderFlags flags, TickCounter *tick_counter, ObserveNodeInfo const &observe_node_info)
ref_traits< T >::ref_type MakeRef(JSHeapBroker *broker, Tagged< T > object)
@ kSkipFirstStackAndTierupCheck
@ kAnalyzeEnvironmentLiveness
@ kBailoutOnUninitialized
bool is_asmjs_module(const WasmModule *module)
Signature< ValueType > FunctionSig
bool is_sloppy(LanguageMode language_mode)
bool IsClassConstructor(FunctionKind kind)
bool IsDerivedConstructor(FunctionKind kind)
kWasmInternalFunctionIndirectPointerTag kProtectedInstanceDataOffset sig
bool IsConstructable(FunctionKind kind)
V8_EXPORT_PRIVATE FlagValues v8_flags
static constexpr RelaxedLoadTag kRelaxedLoad
#define DCHECK_LE(v1, v2)
#define CHECK_LE(lhs, rhs)
#define DCHECK_IMPLIES(v1, v2)
#define DCHECK_NE(v1, v2)
#define DCHECK_GE(v1, v2)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
#define DCHECK_EQ(v1, v2)
HeapObjectRef Ref(JSHeapBroker *broker) const
const Operator * op() const
bool HasResolvedValue() const