11cb0ef41Sopenharmony_ci// Copyright 2014 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/compiler/js-inlining.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/ast/ast.h"
81cb0ef41Sopenharmony_ci#include "src/codegen/compiler.h"
91cb0ef41Sopenharmony_ci#include "src/codegen/optimized-compilation-info.h"
101cb0ef41Sopenharmony_ci#include "src/codegen/tick-counter.h"
111cb0ef41Sopenharmony_ci#include "src/compiler/access-builder.h"
121cb0ef41Sopenharmony_ci#include "src/compiler/all-nodes.h"
131cb0ef41Sopenharmony_ci#include "src/compiler/bytecode-graph-builder.h"
141cb0ef41Sopenharmony_ci#include "src/compiler/common-operator.h"
151cb0ef41Sopenharmony_ci#include "src/compiler/compiler-source-position-table.h"
161cb0ef41Sopenharmony_ci#include "src/compiler/graph-reducer.h"
171cb0ef41Sopenharmony_ci#include "src/compiler/js-heap-broker.h"
181cb0ef41Sopenharmony_ci#include "src/compiler/js-operator.h"
191cb0ef41Sopenharmony_ci#include "src/compiler/node-matchers.h"
201cb0ef41Sopenharmony_ci#include "src/compiler/node-properties.h"
211cb0ef41Sopenharmony_ci#include "src/compiler/operator-properties.h"
221cb0ef41Sopenharmony_ci#include "src/compiler/simplified-operator.h"
231cb0ef41Sopenharmony_ci#include "src/execution/isolate-inl.h"
241cb0ef41Sopenharmony_ci#include "src/objects/feedback-cell-inl.h"
251cb0ef41Sopenharmony_ci#include "src/parsing/parse-info.h"
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY
281cb0ef41Sopenharmony_ci#include "src/compiler/wasm-compiler.h"
291cb0ef41Sopenharmony_ci#endif  // V8_ENABLE_WEBASSEMBLY
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_cinamespace v8 {
321cb0ef41Sopenharmony_cinamespace internal {
331cb0ef41Sopenharmony_cinamespace compiler {
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_cinamespace {
361cb0ef41Sopenharmony_ci// This is just to avoid some corner cases, especially since we allow recursive
371cb0ef41Sopenharmony_ci// inlining.
381cb0ef41Sopenharmony_cistatic const int kMaxDepthForInlining = 50;
391cb0ef41Sopenharmony_ci}  // namespace
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci#define TRACE(x)                     \
421cb0ef41Sopenharmony_ci  do {                               \
431cb0ef41Sopenharmony_ci    if (FLAG_trace_turbo_inlining) { \
441cb0ef41Sopenharmony_ci      StdoutStream() << x << "\n";   \
451cb0ef41Sopenharmony_ci    }                                \
461cb0ef41Sopenharmony_ci  } while (false)
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci// Provides convenience accessors for the common layout of nodes having either
491cb0ef41Sopenharmony_ci// the {JSCall} or the {JSConstruct} operator.
501cb0ef41Sopenharmony_ciclass JSCallAccessor {
511cb0ef41Sopenharmony_ci public:
521cb0ef41Sopenharmony_ci  explicit JSCallAccessor(Node* call) : call_(call) {
531cb0ef41Sopenharmony_ci    DCHECK(call->opcode() == IrOpcode::kJSCall ||
541cb0ef41Sopenharmony_ci           call->opcode() == IrOpcode::kJSConstruct);
551cb0ef41Sopenharmony_ci  }
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci  Node* target() const {
581cb0ef41Sopenharmony_ci    return call_->InputAt(JSCallOrConstructNode::TargetIndex());
591cb0ef41Sopenharmony_ci  }
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  Node* receiver() const {
621cb0ef41Sopenharmony_ci    return JSCallNode{call_}.receiver();
631cb0ef41Sopenharmony_ci  }
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci  Node* new_target() const { return JSConstructNode{call_}.new_target(); }
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  FrameState frame_state() const {
681cb0ef41Sopenharmony_ci    return FrameState{NodeProperties::GetFrameStateInput(call_)};
691cb0ef41Sopenharmony_ci  }
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci  int argument_count() const {
721cb0ef41Sopenharmony_ci    return (call_->opcode() == IrOpcode::kJSCall)
731cb0ef41Sopenharmony_ci               ? JSCallNode{call_}.ArgumentCount()
741cb0ef41Sopenharmony_ci               : JSConstructNode{call_}.ArgumentCount();
751cb0ef41Sopenharmony_ci  }
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  CallFrequency const& frequency() const {
781cb0ef41Sopenharmony_ci    return (call_->opcode() == IrOpcode::kJSCall)
791cb0ef41Sopenharmony_ci               ? JSCallNode{call_}.Parameters().frequency()
801cb0ef41Sopenharmony_ci               : JSConstructNode{call_}.Parameters().frequency();
811cb0ef41Sopenharmony_ci  }
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci private:
841cb0ef41Sopenharmony_ci  Node* call_;
851cb0ef41Sopenharmony_ci};
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY
881cb0ef41Sopenharmony_ciReduction JSInliner::InlineJSWasmCall(Node* call, Node* new_target,
891cb0ef41Sopenharmony_ci                                      Node* context, Node* frame_state,
901cb0ef41Sopenharmony_ci                                      StartNode start, Node* end,
911cb0ef41Sopenharmony_ci                                      Node* exception_target,
921cb0ef41Sopenharmony_ci                                      const NodeVector& uncaught_subcalls) {
931cb0ef41Sopenharmony_ci  JSWasmCallNode n(call);
941cb0ef41Sopenharmony_ci  return InlineCall(
951cb0ef41Sopenharmony_ci      call, new_target, context, frame_state, start, end, exception_target,
961cb0ef41Sopenharmony_ci      uncaught_subcalls,
971cb0ef41Sopenharmony_ci      static_cast<int>(n.Parameters().signature()->parameter_count()));
981cb0ef41Sopenharmony_ci}
991cb0ef41Sopenharmony_ci#endif  // V8_ENABLE_WEBASSEMBLY
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ciReduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
1021cb0ef41Sopenharmony_ci                                Node* frame_state, StartNode start, Node* end,
1031cb0ef41Sopenharmony_ci                                Node* exception_target,
1041cb0ef41Sopenharmony_ci                                const NodeVector& uncaught_subcalls,
1051cb0ef41Sopenharmony_ci                                int argument_count) {
1061cb0ef41Sopenharmony_ci  DCHECK_IMPLIES(IrOpcode::IsInlineeOpcode(call->opcode()),
1071cb0ef41Sopenharmony_ci                 argument_count == JSCallAccessor(call).argument_count());
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci  // The scheduler is smart enough to place our code; we just ensure {control}
1101cb0ef41Sopenharmony_ci  // becomes the control input of the start of the inlinee, and {effect} becomes
1111cb0ef41Sopenharmony_ci  // the effect input of the start of the inlinee.
1121cb0ef41Sopenharmony_ci  Node* control = NodeProperties::GetControlInput(call);
1131cb0ef41Sopenharmony_ci  Node* effect = NodeProperties::GetEffectInput(call);
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci  int const inlinee_new_target_index = start.NewTargetOutputIndex();
1161cb0ef41Sopenharmony_ci  int const inlinee_arity_index = start.ArgCountOutputIndex();
1171cb0ef41Sopenharmony_ci  int const inlinee_context_index = start.ContextOutputIndex();
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  // {inliner_inputs} counts the target, receiver/new_target, and arguments; but
1201cb0ef41Sopenharmony_ci  // not feedback vector, context, effect or control.
1211cb0ef41Sopenharmony_ci  const int inliner_inputs = argument_count +
1221cb0ef41Sopenharmony_ci                             JSCallOrConstructNode::kExtraInputCount -
1231cb0ef41Sopenharmony_ci                             JSCallOrConstructNode::kFeedbackVectorInputCount;
1241cb0ef41Sopenharmony_ci  // Iterate over all uses of the start node.
1251cb0ef41Sopenharmony_ci  for (Edge edge : start->use_edges()) {
1261cb0ef41Sopenharmony_ci    Node* use = edge.from();
1271cb0ef41Sopenharmony_ci    switch (use->opcode()) {
1281cb0ef41Sopenharmony_ci      case IrOpcode::kParameter: {
1291cb0ef41Sopenharmony_ci        int index = 1 + ParameterIndexOf(use->op());
1301cb0ef41Sopenharmony_ci        DCHECK_LE(index, inlinee_context_index);
1311cb0ef41Sopenharmony_ci        if (index < inliner_inputs && index < inlinee_new_target_index) {
1321cb0ef41Sopenharmony_ci          // There is an input from the call, and the index is a value
1331cb0ef41Sopenharmony_ci          // projection but not the context, so rewire the input.
1341cb0ef41Sopenharmony_ci          Replace(use, call->InputAt(index));
1351cb0ef41Sopenharmony_ci        } else if (index == inlinee_new_target_index) {
1361cb0ef41Sopenharmony_ci          // The projection is requesting the new target value.
1371cb0ef41Sopenharmony_ci          Replace(use, new_target);
1381cb0ef41Sopenharmony_ci        } else if (index == inlinee_arity_index) {
1391cb0ef41Sopenharmony_ci          // The projection is requesting the number of arguments.
1401cb0ef41Sopenharmony_ci          Replace(use, jsgraph()->Constant(argument_count));
1411cb0ef41Sopenharmony_ci        } else if (index == inlinee_context_index) {
1421cb0ef41Sopenharmony_ci          // The projection is requesting the inlinee function context.
1431cb0ef41Sopenharmony_ci          Replace(use, context);
1441cb0ef41Sopenharmony_ci        } else {
1451cb0ef41Sopenharmony_ci          // Call has fewer arguments than required, fill with undefined.
1461cb0ef41Sopenharmony_ci          Replace(use, jsgraph()->UndefinedConstant());
1471cb0ef41Sopenharmony_ci        }
1481cb0ef41Sopenharmony_ci        break;
1491cb0ef41Sopenharmony_ci      }
1501cb0ef41Sopenharmony_ci      default:
1511cb0ef41Sopenharmony_ci        if (NodeProperties::IsEffectEdge(edge)) {
1521cb0ef41Sopenharmony_ci          edge.UpdateTo(effect);
1531cb0ef41Sopenharmony_ci        } else if (NodeProperties::IsControlEdge(edge)) {
1541cb0ef41Sopenharmony_ci          edge.UpdateTo(control);
1551cb0ef41Sopenharmony_ci        } else if (NodeProperties::IsFrameStateEdge(edge)) {
1561cb0ef41Sopenharmony_ci          edge.UpdateTo(frame_state);
1571cb0ef41Sopenharmony_ci        } else {
1581cb0ef41Sopenharmony_ci          UNREACHABLE();
1591cb0ef41Sopenharmony_ci        }
1601cb0ef41Sopenharmony_ci        break;
1611cb0ef41Sopenharmony_ci    }
1621cb0ef41Sopenharmony_ci  }
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  if (exception_target != nullptr) {
1651cb0ef41Sopenharmony_ci    // Link uncaught calls in the inlinee to {exception_target}
1661cb0ef41Sopenharmony_ci    int subcall_count = static_cast<int>(uncaught_subcalls.size());
1671cb0ef41Sopenharmony_ci    if (subcall_count > 0) {
1681cb0ef41Sopenharmony_ci      TRACE("Inlinee contains " << subcall_count
1691cb0ef41Sopenharmony_ci                                << " calls without local exception handler; "
1701cb0ef41Sopenharmony_ci                                << "linking to surrounding exception handler.");
1711cb0ef41Sopenharmony_ci    }
1721cb0ef41Sopenharmony_ci    NodeVector on_exception_nodes(local_zone_);
1731cb0ef41Sopenharmony_ci    for (Node* subcall : uncaught_subcalls) {
1741cb0ef41Sopenharmony_ci      Node* on_success = graph()->NewNode(common()->IfSuccess(), subcall);
1751cb0ef41Sopenharmony_ci      NodeProperties::ReplaceUses(subcall, subcall, subcall, on_success);
1761cb0ef41Sopenharmony_ci      NodeProperties::ReplaceControlInput(on_success, subcall);
1771cb0ef41Sopenharmony_ci      Node* on_exception =
1781cb0ef41Sopenharmony_ci          graph()->NewNode(common()->IfException(), subcall, subcall);
1791cb0ef41Sopenharmony_ci      on_exception_nodes.push_back(on_exception);
1801cb0ef41Sopenharmony_ci    }
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci    DCHECK_EQ(subcall_count, static_cast<int>(on_exception_nodes.size()));
1831cb0ef41Sopenharmony_ci    if (subcall_count > 0) {
1841cb0ef41Sopenharmony_ci      Node* control_output =
1851cb0ef41Sopenharmony_ci          graph()->NewNode(common()->Merge(subcall_count), subcall_count,
1861cb0ef41Sopenharmony_ci                           &on_exception_nodes.front());
1871cb0ef41Sopenharmony_ci      NodeVector values_effects(local_zone_);
1881cb0ef41Sopenharmony_ci      values_effects = on_exception_nodes;
1891cb0ef41Sopenharmony_ci      values_effects.push_back(control_output);
1901cb0ef41Sopenharmony_ci      Node* value_output = graph()->NewNode(
1911cb0ef41Sopenharmony_ci          common()->Phi(MachineRepresentation::kTagged, subcall_count),
1921cb0ef41Sopenharmony_ci          subcall_count + 1, &values_effects.front());
1931cb0ef41Sopenharmony_ci      Node* effect_output =
1941cb0ef41Sopenharmony_ci          graph()->NewNode(common()->EffectPhi(subcall_count),
1951cb0ef41Sopenharmony_ci                           subcall_count + 1, &values_effects.front());
1961cb0ef41Sopenharmony_ci      ReplaceWithValue(exception_target, value_output, effect_output,
1971cb0ef41Sopenharmony_ci                       control_output);
1981cb0ef41Sopenharmony_ci    } else {
1991cb0ef41Sopenharmony_ci      ReplaceWithValue(exception_target, exception_target, exception_target,
2001cb0ef41Sopenharmony_ci                       jsgraph()->Dead());
2011cb0ef41Sopenharmony_ci    }
2021cb0ef41Sopenharmony_ci  }
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_ci  NodeVector values(local_zone_);
2051cb0ef41Sopenharmony_ci  NodeVector effects(local_zone_);
2061cb0ef41Sopenharmony_ci  NodeVector controls(local_zone_);
2071cb0ef41Sopenharmony_ci  for (Node* const input : end->inputs()) {
2081cb0ef41Sopenharmony_ci    switch (input->opcode()) {
2091cb0ef41Sopenharmony_ci      case IrOpcode::kReturn:
2101cb0ef41Sopenharmony_ci        values.push_back(NodeProperties::GetValueInput(input, 1));
2111cb0ef41Sopenharmony_ci        effects.push_back(NodeProperties::GetEffectInput(input));
2121cb0ef41Sopenharmony_ci        controls.push_back(NodeProperties::GetControlInput(input));
2131cb0ef41Sopenharmony_ci        break;
2141cb0ef41Sopenharmony_ci      case IrOpcode::kDeoptimize:
2151cb0ef41Sopenharmony_ci      case IrOpcode::kTerminate:
2161cb0ef41Sopenharmony_ci      case IrOpcode::kThrow:
2171cb0ef41Sopenharmony_ci        NodeProperties::MergeControlToEnd(graph(), common(), input);
2181cb0ef41Sopenharmony_ci        Revisit(graph()->end());
2191cb0ef41Sopenharmony_ci        break;
2201cb0ef41Sopenharmony_ci      default:
2211cb0ef41Sopenharmony_ci        UNREACHABLE();
2221cb0ef41Sopenharmony_ci    }
2231cb0ef41Sopenharmony_ci  }
2241cb0ef41Sopenharmony_ci  DCHECK_EQ(values.size(), effects.size());
2251cb0ef41Sopenharmony_ci  DCHECK_EQ(values.size(), controls.size());
2261cb0ef41Sopenharmony_ci
2271cb0ef41Sopenharmony_ci  // Depending on whether the inlinee produces a value, we either replace value
2281cb0ef41Sopenharmony_ci  // uses with said value or kill value uses if no value can be returned.
2291cb0ef41Sopenharmony_ci  if (values.size() > 0) {
2301cb0ef41Sopenharmony_ci    int const input_count = static_cast<int>(controls.size());
2311cb0ef41Sopenharmony_ci    Node* control_output = graph()->NewNode(common()->Merge(input_count),
2321cb0ef41Sopenharmony_ci                                            input_count, &controls.front());
2331cb0ef41Sopenharmony_ci    values.push_back(control_output);
2341cb0ef41Sopenharmony_ci    effects.push_back(control_output);
2351cb0ef41Sopenharmony_ci    Node* value_output = graph()->NewNode(
2361cb0ef41Sopenharmony_ci        common()->Phi(MachineRepresentation::kTagged, input_count),
2371cb0ef41Sopenharmony_ci        static_cast<int>(values.size()), &values.front());
2381cb0ef41Sopenharmony_ci    Node* effect_output =
2391cb0ef41Sopenharmony_ci        graph()->NewNode(common()->EffectPhi(input_count),
2401cb0ef41Sopenharmony_ci                         static_cast<int>(effects.size()), &effects.front());
2411cb0ef41Sopenharmony_ci    ReplaceWithValue(call, value_output, effect_output, control_output);
2421cb0ef41Sopenharmony_ci    return Changed(value_output);
2431cb0ef41Sopenharmony_ci  } else {
2441cb0ef41Sopenharmony_ci    ReplaceWithValue(call, jsgraph()->Dead(), jsgraph()->Dead(),
2451cb0ef41Sopenharmony_ci                     jsgraph()->Dead());
2461cb0ef41Sopenharmony_ci    return Changed(call);
2471cb0ef41Sopenharmony_ci  }
2481cb0ef41Sopenharmony_ci}
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ciFrameState JSInliner::CreateArtificialFrameState(
2511cb0ef41Sopenharmony_ci    Node* node, FrameState outer_frame_state, int parameter_count,
2521cb0ef41Sopenharmony_ci    BytecodeOffset bailout_id, FrameStateType frame_state_type,
2531cb0ef41Sopenharmony_ci    SharedFunctionInfoRef shared, Node* context) {
2541cb0ef41Sopenharmony_ci  const int parameter_count_with_receiver =
2551cb0ef41Sopenharmony_ci      parameter_count + JSCallOrConstructNode::kReceiverOrNewTargetInputCount;
2561cb0ef41Sopenharmony_ci  const FrameStateFunctionInfo* state_info =
2571cb0ef41Sopenharmony_ci      common()->CreateFrameStateFunctionInfo(
2581cb0ef41Sopenharmony_ci          frame_state_type, parameter_count_with_receiver, 0, shared.object());
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ci  const Operator* op = common()->FrameState(
2611cb0ef41Sopenharmony_ci      bailout_id, OutputFrameStateCombine::Ignore(), state_info);
2621cb0ef41Sopenharmony_ci  const Operator* op0 = common()->StateValues(0, SparseInputMask::Dense());
2631cb0ef41Sopenharmony_ci  Node* node0 = graph()->NewNode(op0);
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ci  NodeVector params(local_zone_);
2661cb0ef41Sopenharmony_ci  params.push_back(
2671cb0ef41Sopenharmony_ci      node->InputAt(JSCallOrConstructNode::ReceiverOrNewTargetIndex()));
2681cb0ef41Sopenharmony_ci  for (int i = 0; i < parameter_count; i++) {
2691cb0ef41Sopenharmony_ci    params.push_back(node->InputAt(JSCallOrConstructNode::ArgumentIndex(i)));
2701cb0ef41Sopenharmony_ci  }
2711cb0ef41Sopenharmony_ci  const Operator* op_param = common()->StateValues(
2721cb0ef41Sopenharmony_ci      static_cast<int>(params.size()), SparseInputMask::Dense());
2731cb0ef41Sopenharmony_ci  Node* params_node = graph()->NewNode(
2741cb0ef41Sopenharmony_ci      op_param, static_cast<int>(params.size()), &params.front());
2751cb0ef41Sopenharmony_ci  if (context == nullptr) context = jsgraph()->UndefinedConstant();
2761cb0ef41Sopenharmony_ci  return FrameState{graph()->NewNode(
2771cb0ef41Sopenharmony_ci      op, params_node, node0, node0, context,
2781cb0ef41Sopenharmony_ci      node->InputAt(JSCallOrConstructNode::TargetIndex()), outer_frame_state)};
2791cb0ef41Sopenharmony_ci}
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_cinamespace {
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_cibool NeedsImplicitReceiver(SharedFunctionInfoRef shared_info) {
2841cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
2851cb0ef41Sopenharmony_ci  return !shared_info.construct_as_builtin() &&
2861cb0ef41Sopenharmony_ci         !IsDerivedConstructor(shared_info.kind());
2871cb0ef41Sopenharmony_ci}
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ci}  // namespace
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci// Determines whether the call target of the given call {node} is statically
2921cb0ef41Sopenharmony_ci// known and can be used as an inlining candidate. The {SharedFunctionInfo} of
2931cb0ef41Sopenharmony_ci// the call target is provided (the exact closure might be unknown).
2941cb0ef41Sopenharmony_cibase::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget(
2951cb0ef41Sopenharmony_ci    Node* node) {
2961cb0ef41Sopenharmony_ci  DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
2971cb0ef41Sopenharmony_ci  Node* target = node->InputAt(JSCallOrConstructNode::TargetIndex());
2981cb0ef41Sopenharmony_ci  HeapObjectMatcher match(target);
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci  // This reducer can handle both normal function calls as well a constructor
3011cb0ef41Sopenharmony_ci  // calls whenever the target is a constant function object, as follows:
3021cb0ef41Sopenharmony_ci  //  - JSCall(target:constant, receiver, args..., vector)
3031cb0ef41Sopenharmony_ci  //  - JSConstruct(target:constant, new.target, args..., vector)
3041cb0ef41Sopenharmony_ci  if (match.HasResolvedValue() && match.Ref(broker()).IsJSFunction()) {
3051cb0ef41Sopenharmony_ci    JSFunctionRef function = match.Ref(broker()).AsJSFunction();
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_ci    // The function might have not been called yet.
3081cb0ef41Sopenharmony_ci    if (!function.feedback_vector(broker()->dependencies()).has_value()) {
3091cb0ef41Sopenharmony_ci      return base::nullopt;
3101cb0ef41Sopenharmony_ci    }
3111cb0ef41Sopenharmony_ci
3121cb0ef41Sopenharmony_ci    // Disallow cross native-context inlining for now. This means that all parts
3131cb0ef41Sopenharmony_ci    // of the resulting code will operate on the same global object. This also
3141cb0ef41Sopenharmony_ci    // prevents cross context leaks, where we could inline functions from a
3151cb0ef41Sopenharmony_ci    // different context and hold on to that context (and closure) from the code
3161cb0ef41Sopenharmony_ci    // object.
3171cb0ef41Sopenharmony_ci    // TODO(turbofan): We might want to revisit this restriction later when we
3181cb0ef41Sopenharmony_ci    // have a need for this, and we know how to model different native contexts
3191cb0ef41Sopenharmony_ci    // in the same graph in a compositional way.
3201cb0ef41Sopenharmony_ci    if (!function.native_context().equals(broker()->target_native_context())) {
3211cb0ef41Sopenharmony_ci      return base::nullopt;
3221cb0ef41Sopenharmony_ci    }
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_ci    return function.shared();
3251cb0ef41Sopenharmony_ci  }
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ci  // This reducer can also handle calls where the target is statically known to
3281cb0ef41Sopenharmony_ci  // be the result of a closure instantiation operation, as follows:
3291cb0ef41Sopenharmony_ci  //  - JSCall(JSCreateClosure[shared](context), receiver, args..., vector)
3301cb0ef41Sopenharmony_ci  //  - JSConstruct(JSCreateClosure[shared](context),
3311cb0ef41Sopenharmony_ci  //                new.target, args..., vector)
3321cb0ef41Sopenharmony_ci  if (match.IsJSCreateClosure()) {
3331cb0ef41Sopenharmony_ci    JSCreateClosureNode n(target);
3341cb0ef41Sopenharmony_ci    FeedbackCellRef cell = n.GetFeedbackCellRefChecked(broker());
3351cb0ef41Sopenharmony_ci    return cell.shared_function_info();
3361cb0ef41Sopenharmony_ci  } else if (match.IsCheckClosure()) {
3371cb0ef41Sopenharmony_ci    FeedbackCellRef cell = MakeRef(broker(), FeedbackCellOf(match.op()));
3381cb0ef41Sopenharmony_ci    return cell.shared_function_info();
3391cb0ef41Sopenharmony_ci  }
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ci  return base::nullopt;
3421cb0ef41Sopenharmony_ci}
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ci// Determines statically known information about the call target (assuming that
3451cb0ef41Sopenharmony_ci// the call target is known according to {DetermineCallTarget} above). The
3461cb0ef41Sopenharmony_ci// following static information is provided:
3471cb0ef41Sopenharmony_ci//  - context         : The context (as SSA value) bound by the call target.
3481cb0ef41Sopenharmony_ci//  - feedback_vector : The target is guaranteed to use this feedback vector.
3491cb0ef41Sopenharmony_ciFeedbackCellRef JSInliner::DetermineCallContext(Node* node,
3501cb0ef41Sopenharmony_ci                                                Node** context_out) {
3511cb0ef41Sopenharmony_ci  DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
3521cb0ef41Sopenharmony_ci  Node* target = node->InputAt(JSCallOrConstructNode::TargetIndex());
3531cb0ef41Sopenharmony_ci  HeapObjectMatcher match(target);
3541cb0ef41Sopenharmony_ci
3551cb0ef41Sopenharmony_ci  if (match.HasResolvedValue() && match.Ref(broker()).IsJSFunction()) {
3561cb0ef41Sopenharmony_ci    JSFunctionRef function = match.Ref(broker()).AsJSFunction();
3571cb0ef41Sopenharmony_ci    // This was already ensured by DetermineCallTarget
3581cb0ef41Sopenharmony_ci    CHECK(function.feedback_vector(broker()->dependencies()).has_value());
3591cb0ef41Sopenharmony_ci
3601cb0ef41Sopenharmony_ci    // The inlinee specializes to the context from the JSFunction object.
3611cb0ef41Sopenharmony_ci    *context_out = jsgraph()->Constant(function.context());
3621cb0ef41Sopenharmony_ci    return function.raw_feedback_cell(broker()->dependencies());
3631cb0ef41Sopenharmony_ci  }
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_ci  if (match.IsJSCreateClosure()) {
3661cb0ef41Sopenharmony_ci    // Load the feedback vector of the target by looking up its vector cell at
3671cb0ef41Sopenharmony_ci    // the instantiation site (we only decide to inline if it's populated).
3681cb0ef41Sopenharmony_ci    JSCreateClosureNode n(target);
3691cb0ef41Sopenharmony_ci    FeedbackCellRef cell = n.GetFeedbackCellRefChecked(broker());
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_ci    // The inlinee uses the locally provided context at instantiation.
3721cb0ef41Sopenharmony_ci    *context_out = NodeProperties::GetContextInput(match.node());
3731cb0ef41Sopenharmony_ci    return cell;
3741cb0ef41Sopenharmony_ci  } else if (match.IsCheckClosure()) {
3751cb0ef41Sopenharmony_ci    FeedbackCellRef cell = MakeRef(broker(), FeedbackCellOf(match.op()));
3761cb0ef41Sopenharmony_ci
3771cb0ef41Sopenharmony_ci    Node* effect = NodeProperties::GetEffectInput(node);
3781cb0ef41Sopenharmony_ci    Node* control = NodeProperties::GetControlInput(node);
3791cb0ef41Sopenharmony_ci    *context_out = effect = graph()->NewNode(
3801cb0ef41Sopenharmony_ci        simplified()->LoadField(AccessBuilder::ForJSFunctionContext()),
3811cb0ef41Sopenharmony_ci        match.node(), effect, control);
3821cb0ef41Sopenharmony_ci    NodeProperties::ReplaceEffectInput(node, effect);
3831cb0ef41Sopenharmony_ci
3841cb0ef41Sopenharmony_ci    return cell;
3851cb0ef41Sopenharmony_ci  }
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_ci  // Must succeed.
3881cb0ef41Sopenharmony_ci  UNREACHABLE();
3891cb0ef41Sopenharmony_ci}
3901cb0ef41Sopenharmony_ci
3911cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY
3921cb0ef41Sopenharmony_ciReduction JSInliner::ReduceJSWasmCall(Node* node) {
3931cb0ef41Sopenharmony_ci  // Create the subgraph for the inlinee.
3941cb0ef41Sopenharmony_ci  Node* start_node;
3951cb0ef41Sopenharmony_ci  Node* end;
3961cb0ef41Sopenharmony_ci  size_t subgraph_min_node_id;
3971cb0ef41Sopenharmony_ci  {
3981cb0ef41Sopenharmony_ci    Graph::SubgraphScope scope(graph());
3991cb0ef41Sopenharmony_ci
4001cb0ef41Sopenharmony_ci    graph()->SetEnd(nullptr);
4011cb0ef41Sopenharmony_ci
4021cb0ef41Sopenharmony_ci    JSWasmCallNode n(node);
4031cb0ef41Sopenharmony_ci    const JSWasmCallParameters& wasm_call_params = n.Parameters();
4041cb0ef41Sopenharmony_ci
4051cb0ef41Sopenharmony_ci    // Create a nested frame state inside the frame state attached to the
4061cb0ef41Sopenharmony_ci    // call; this will ensure that lazy deoptimizations at this point will
4071cb0ef41Sopenharmony_ci    // still return the result of the Wasm function call.
4081cb0ef41Sopenharmony_ci    Node* continuation_frame_state =
4091cb0ef41Sopenharmony_ci        CreateJSWasmCallBuiltinContinuationFrameState(
4101cb0ef41Sopenharmony_ci            jsgraph(), n.context(), n.frame_state(),
4111cb0ef41Sopenharmony_ci            wasm_call_params.signature());
4121cb0ef41Sopenharmony_ci    JSWasmCallData js_wasm_call_data(wasm_call_params.signature());
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ci    // All the nodes inserted by the inlined subgraph will have
4151cb0ef41Sopenharmony_ci    // id >= subgraph_min_node_id. We use this later to avoid wire nodes that
4161cb0ef41Sopenharmony_ci    // are not inserted by the inlinee but were already part of the graph to the
4171cb0ef41Sopenharmony_ci    // surrounding exception handler, if present.
4181cb0ef41Sopenharmony_ci    subgraph_min_node_id = graph()->NodeCount();
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ci    BuildInlinedJSToWasmWrapper(
4211cb0ef41Sopenharmony_ci        graph()->zone(), jsgraph(), wasm_call_params.signature(),
4221cb0ef41Sopenharmony_ci        wasm_call_params.module(), isolate(), source_positions_,
4231cb0ef41Sopenharmony_ci        StubCallMode::kCallBuiltinPointer, wasm::WasmFeatures::FromFlags(),
4241cb0ef41Sopenharmony_ci        &js_wasm_call_data, continuation_frame_state);
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ci    // Extract the inlinee start/end nodes.
4271cb0ef41Sopenharmony_ci    start_node = graph()->start();
4281cb0ef41Sopenharmony_ci    end = graph()->end();
4291cb0ef41Sopenharmony_ci  }
4301cb0ef41Sopenharmony_ci  StartNode start{start_node};
4311cb0ef41Sopenharmony_ci
4321cb0ef41Sopenharmony_ci  Node* exception_target = nullptr;
4331cb0ef41Sopenharmony_ci  NodeProperties::IsExceptionalCall(node, &exception_target);
4341cb0ef41Sopenharmony_ci
4351cb0ef41Sopenharmony_ci  // If we are inlining into a surrounding exception handler, we collect all
4361cb0ef41Sopenharmony_ci  // potentially throwing nodes within the inlinee that are not handled locally
4371cb0ef41Sopenharmony_ci  // by the inlinee itself. They are later wired into the surrounding handler.
4381cb0ef41Sopenharmony_ci  NodeVector uncaught_subcalls(local_zone_);
4391cb0ef41Sopenharmony_ci  if (exception_target != nullptr) {
4401cb0ef41Sopenharmony_ci    // Find all uncaught 'calls' in the inlinee.
4411cb0ef41Sopenharmony_ci    AllNodes inlined_nodes(local_zone_, end, graph());
4421cb0ef41Sopenharmony_ci    for (Node* subnode : inlined_nodes.reachable) {
4431cb0ef41Sopenharmony_ci      // Ignore nodes that are not part of the inlinee.
4441cb0ef41Sopenharmony_ci      if (subnode->id() < subgraph_min_node_id) continue;
4451cb0ef41Sopenharmony_ci
4461cb0ef41Sopenharmony_ci      // Every possibly throwing node should get {IfSuccess} and {IfException}
4471cb0ef41Sopenharmony_ci      // projections, unless there already is local exception handling.
4481cb0ef41Sopenharmony_ci      if (subnode->op()->HasProperty(Operator::kNoThrow)) continue;
4491cb0ef41Sopenharmony_ci      if (!NodeProperties::IsExceptionalCall(subnode)) {
4501cb0ef41Sopenharmony_ci        DCHECK_EQ(2, subnode->op()->ControlOutputCount());
4511cb0ef41Sopenharmony_ci        uncaught_subcalls.push_back(subnode);
4521cb0ef41Sopenharmony_ci      }
4531cb0ef41Sopenharmony_ci    }
4541cb0ef41Sopenharmony_ci  }
4551cb0ef41Sopenharmony_ci
4561cb0ef41Sopenharmony_ci  Node* context = NodeProperties::GetContextInput(node);
4571cb0ef41Sopenharmony_ci  Node* frame_state = NodeProperties::GetFrameStateInput(node);
4581cb0ef41Sopenharmony_ci  Node* new_target = jsgraph()->UndefinedConstant();
4591cb0ef41Sopenharmony_ci
4601cb0ef41Sopenharmony_ci  return InlineJSWasmCall(node, new_target, context, frame_state, start, end,
4611cb0ef41Sopenharmony_ci                          exception_target, uncaught_subcalls);
4621cb0ef41Sopenharmony_ci}
4631cb0ef41Sopenharmony_ci#endif  // V8_ENABLE_WEBASSEMBLY
4641cb0ef41Sopenharmony_ci
4651cb0ef41Sopenharmony_ciReduction JSInliner::ReduceJSCall(Node* node) {
4661cb0ef41Sopenharmony_ci  DCHECK(IrOpcode::IsInlineeOpcode(node->opcode()));
4671cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY
4681cb0ef41Sopenharmony_ci  DCHECK_NE(node->opcode(), IrOpcode::kJSWasmCall);
4691cb0ef41Sopenharmony_ci#endif  // V8_ENABLE_WEBASSEMBLY
4701cb0ef41Sopenharmony_ci  JSCallAccessor call(node);
4711cb0ef41Sopenharmony_ci
4721cb0ef41Sopenharmony_ci  // Determine the call target.
4731cb0ef41Sopenharmony_ci  base::Optional<SharedFunctionInfoRef> shared_info(DetermineCallTarget(node));
4741cb0ef41Sopenharmony_ci  if (!shared_info.has_value()) return NoChange();
4751cb0ef41Sopenharmony_ci
4761cb0ef41Sopenharmony_ci  SharedFunctionInfoRef outer_shared_info =
4771cb0ef41Sopenharmony_ci      MakeRef(broker(), info_->shared_info());
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ci  SharedFunctionInfo::Inlineability inlineability =
4801cb0ef41Sopenharmony_ci      shared_info->GetInlineability();
4811cb0ef41Sopenharmony_ci  if (inlineability != SharedFunctionInfo::kIsInlineable) {
4821cb0ef41Sopenharmony_ci    // The function is no longer inlineable. The only way this can happen is if
4831cb0ef41Sopenharmony_ci    // the function had its optimization disabled in the meantime, e.g. because
4841cb0ef41Sopenharmony_ci    // another optimization job failed too often.
4851cb0ef41Sopenharmony_ci    CHECK_EQ(inlineability, SharedFunctionInfo::kHasOptimizationDisabled);
4861cb0ef41Sopenharmony_ci    TRACE("Not inlining " << *shared_info << " into " << outer_shared_info
4871cb0ef41Sopenharmony_ci                          << " because it had its optimization disabled.");
4881cb0ef41Sopenharmony_ci    return NoChange();
4891cb0ef41Sopenharmony_ci  }
4901cb0ef41Sopenharmony_ci  // NOTE: Even though we bailout in the kHasOptimizationDisabled case above, we
4911cb0ef41Sopenharmony_ci  // won't notice if the function's optimization is disabled after this point.
4921cb0ef41Sopenharmony_ci
4931cb0ef41Sopenharmony_ci  // Constructor must be constructable.
4941cb0ef41Sopenharmony_ci  if (node->opcode() == IrOpcode::kJSConstruct &&
4951cb0ef41Sopenharmony_ci      !IsConstructable(shared_info->kind())) {
4961cb0ef41Sopenharmony_ci    TRACE("Not inlining " << *shared_info << " into " << outer_shared_info
4971cb0ef41Sopenharmony_ci                          << " because constructor is not constructable.");
4981cb0ef41Sopenharmony_ci    return NoChange();
4991cb0ef41Sopenharmony_ci  }
5001cb0ef41Sopenharmony_ci
5011cb0ef41Sopenharmony_ci  // Class constructors are callable, but [[Call]] will raise an exception.
5021cb0ef41Sopenharmony_ci  // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ).
5031cb0ef41Sopenharmony_ci  if (node->opcode() == IrOpcode::kJSCall &&
5041cb0ef41Sopenharmony_ci      IsClassConstructor(shared_info->kind())) {
5051cb0ef41Sopenharmony_ci    TRACE("Not inlining " << *shared_info << " into " << outer_shared_info
5061cb0ef41Sopenharmony_ci                          << " because callee is a class constructor.");
5071cb0ef41Sopenharmony_ci    return NoChange();
5081cb0ef41Sopenharmony_ci  }
5091cb0ef41Sopenharmony_ci
5101cb0ef41Sopenharmony_ci  // To ensure inlining always terminates, we have an upper limit on inlining
5111cb0ef41Sopenharmony_ci  // the nested calls.
5121cb0ef41Sopenharmony_ci  int nesting_level = 0;
5131cb0ef41Sopenharmony_ci  for (Node* frame_state = call.frame_state();
5141cb0ef41Sopenharmony_ci       frame_state->opcode() == IrOpcode::kFrameState;
5151cb0ef41Sopenharmony_ci       frame_state = FrameState{frame_state}.outer_frame_state()) {
5161cb0ef41Sopenharmony_ci    nesting_level++;
5171cb0ef41Sopenharmony_ci    if (nesting_level > kMaxDepthForInlining) {
5181cb0ef41Sopenharmony_ci      TRACE("Not inlining "
5191cb0ef41Sopenharmony_ci            << *shared_info << " into " << outer_shared_info
5201cb0ef41Sopenharmony_ci            << " because call has exceeded the maximum depth for function "
5211cb0ef41Sopenharmony_ci               "inlining.");
5221cb0ef41Sopenharmony_ci      return NoChange();
5231cb0ef41Sopenharmony_ci    }
5241cb0ef41Sopenharmony_ci  }
5251cb0ef41Sopenharmony_ci
5261cb0ef41Sopenharmony_ci  Node* exception_target = nullptr;
5271cb0ef41Sopenharmony_ci  NodeProperties::IsExceptionalCall(node, &exception_target);
5281cb0ef41Sopenharmony_ci
5291cb0ef41Sopenharmony_ci  // JSInliningHeuristic has already filtered candidates without a BytecodeArray
5301cb0ef41Sopenharmony_ci  // based on SharedFunctionInfoRef::GetInlineability. For the inlineable ones
5311cb0ef41Sopenharmony_ci  // (kIsInlineable), the broker holds a reference to the bytecode array, which
5321cb0ef41Sopenharmony_ci  // prevents it from getting flushed.  Therefore, the following check should
5331cb0ef41Sopenharmony_ci  // always hold true.
5341cb0ef41Sopenharmony_ci  CHECK(shared_info->is_compiled());
5351cb0ef41Sopenharmony_ci
5361cb0ef41Sopenharmony_ci  if (info_->source_positions() &&
5371cb0ef41Sopenharmony_ci      !shared_info->object()->AreSourcePositionsAvailable(
5381cb0ef41Sopenharmony_ci          broker()->local_isolate_or_isolate())) {
5391cb0ef41Sopenharmony_ci    // This case is expected to be very rare, since we generate source
5401cb0ef41Sopenharmony_ci    // positions for all functions when debugging or profiling are turned
5411cb0ef41Sopenharmony_ci    // on (see Isolate::NeedsDetailedOptimizedCodeLineInfo). Source
5421cb0ef41Sopenharmony_ci    // positions should only be missing here if there is a race between 1)
5431cb0ef41Sopenharmony_ci    // enabling/disabling the debugger/profiler, and 2) this compile job.
5441cb0ef41Sopenharmony_ci    // In that case, we simply don't inline.
5451cb0ef41Sopenharmony_ci    TRACE("Not inlining " << *shared_info << " into " << outer_shared_info
5461cb0ef41Sopenharmony_ci                          << " because source positions are missing.");
5471cb0ef41Sopenharmony_ci    return NoChange();
5481cb0ef41Sopenharmony_ci  }
5491cb0ef41Sopenharmony_ci
5501cb0ef41Sopenharmony_ci  // Determine the target's feedback vector and its context.
5511cb0ef41Sopenharmony_ci  Node* context;
5521cb0ef41Sopenharmony_ci  FeedbackCellRef feedback_cell = DetermineCallContext(node, &context);
5531cb0ef41Sopenharmony_ci
5541cb0ef41Sopenharmony_ci  TRACE("Inlining " << *shared_info << " into " << outer_shared_info
5551cb0ef41Sopenharmony_ci                    << ((exception_target != nullptr) ? " (inside try-block)"
5561cb0ef41Sopenharmony_ci                                                      : ""));
5571cb0ef41Sopenharmony_ci  // ----------------------------------------------------------------
5581cb0ef41Sopenharmony_ci  // After this point, we've made a decision to inline this function.
5591cb0ef41Sopenharmony_ci  // We shall not bailout from inlining if we got here.
5601cb0ef41Sopenharmony_ci
5611cb0ef41Sopenharmony_ci  BytecodeArrayRef bytecode_array = shared_info->GetBytecodeArray();
5621cb0ef41Sopenharmony_ci
5631cb0ef41Sopenharmony_ci  // Remember that we inlined this function.
5641cb0ef41Sopenharmony_ci  int inlining_id =
5651cb0ef41Sopenharmony_ci      info_->AddInlinedFunction(shared_info->object(), bytecode_array.object(),
5661cb0ef41Sopenharmony_ci                                source_positions_->GetSourcePosition(node));
5671cb0ef41Sopenharmony_ci
5681cb0ef41Sopenharmony_ci  // Create the subgraph for the inlinee.
5691cb0ef41Sopenharmony_ci  Node* start_node;
5701cb0ef41Sopenharmony_ci  Node* end;
5711cb0ef41Sopenharmony_ci  {
5721cb0ef41Sopenharmony_ci    // Run the BytecodeGraphBuilder to create the subgraph.
5731cb0ef41Sopenharmony_ci    Graph::SubgraphScope scope(graph());
5741cb0ef41Sopenharmony_ci    BytecodeGraphBuilderFlags flags(
5751cb0ef41Sopenharmony_ci        BytecodeGraphBuilderFlag::kSkipFirstStackAndTierupCheck);
5761cb0ef41Sopenharmony_ci    if (info_->analyze_environment_liveness()) {
5771cb0ef41Sopenharmony_ci      flags |= BytecodeGraphBuilderFlag::kAnalyzeEnvironmentLiveness;
5781cb0ef41Sopenharmony_ci    }
5791cb0ef41Sopenharmony_ci    if (info_->bailout_on_uninitialized()) {
5801cb0ef41Sopenharmony_ci      flags |= BytecodeGraphBuilderFlag::kBailoutOnUninitialized;
5811cb0ef41Sopenharmony_ci    }
5821cb0ef41Sopenharmony_ci    {
5831cb0ef41Sopenharmony_ci      CallFrequency frequency = call.frequency();
5841cb0ef41Sopenharmony_ci      BuildGraphFromBytecode(broker(), zone(), *shared_info, feedback_cell,
5851cb0ef41Sopenharmony_ci                             BytecodeOffset::None(), jsgraph(), frequency,
5861cb0ef41Sopenharmony_ci                             source_positions_, inlining_id, info_->code_kind(),
5871cb0ef41Sopenharmony_ci                             flags, &info_->tick_counter());
5881cb0ef41Sopenharmony_ci    }
5891cb0ef41Sopenharmony_ci
5901cb0ef41Sopenharmony_ci    // Extract the inlinee start/end nodes.
5911cb0ef41Sopenharmony_ci    start_node = graph()->start();
5921cb0ef41Sopenharmony_ci    end = graph()->end();
5931cb0ef41Sopenharmony_ci  }
5941cb0ef41Sopenharmony_ci  StartNode start{start_node};
5951cb0ef41Sopenharmony_ci
5961cb0ef41Sopenharmony_ci  // If we are inlining into a surrounding exception handler, we collect all
5971cb0ef41Sopenharmony_ci  // potentially throwing nodes within the inlinee that are not handled locally
5981cb0ef41Sopenharmony_ci  // by the inlinee itself. They are later wired into the surrounding handler.
5991cb0ef41Sopenharmony_ci  NodeVector uncaught_subcalls(local_zone_);
6001cb0ef41Sopenharmony_ci  if (exception_target != nullptr) {
6011cb0ef41Sopenharmony_ci    // Find all uncaught 'calls' in the inlinee.
6021cb0ef41Sopenharmony_ci    AllNodes inlined_nodes(local_zone_, end, graph());
6031cb0ef41Sopenharmony_ci    for (Node* subnode : inlined_nodes.reachable) {
6041cb0ef41Sopenharmony_ci      // Every possibly throwing node should get {IfSuccess} and {IfException}
6051cb0ef41Sopenharmony_ci      // projections, unless there already is local exception handling.
6061cb0ef41Sopenharmony_ci      if (subnode->op()->HasProperty(Operator::kNoThrow)) continue;
6071cb0ef41Sopenharmony_ci      if (!NodeProperties::IsExceptionalCall(subnode)) {
6081cb0ef41Sopenharmony_ci        DCHECK_EQ(2, subnode->op()->ControlOutputCount());
6091cb0ef41Sopenharmony_ci        uncaught_subcalls.push_back(subnode);
6101cb0ef41Sopenharmony_ci      }
6111cb0ef41Sopenharmony_ci    }
6121cb0ef41Sopenharmony_ci  }
6131cb0ef41Sopenharmony_ci
6141cb0ef41Sopenharmony_ci  FrameState frame_state = call.frame_state();
6151cb0ef41Sopenharmony_ci  Node* new_target = jsgraph()->UndefinedConstant();
6161cb0ef41Sopenharmony_ci
6171cb0ef41Sopenharmony_ci  // Inline {JSConstruct} requires some additional magic.
6181cb0ef41Sopenharmony_ci  if (node->opcode() == IrOpcode::kJSConstruct) {
6191cb0ef41Sopenharmony_ci    STATIC_ASSERT(JSCallOrConstructNode::kHaveIdenticalLayouts);
6201cb0ef41Sopenharmony_ci    JSConstructNode n(node);
6211cb0ef41Sopenharmony_ci
6221cb0ef41Sopenharmony_ci    new_target = n.new_target();
6231cb0ef41Sopenharmony_ci
6241cb0ef41Sopenharmony_ci    // Insert nodes around the call that model the behavior required for a
6251cb0ef41Sopenharmony_ci    // constructor dispatch (allocate implicit receiver and check return value).
6261cb0ef41Sopenharmony_ci    // This models the behavior usually accomplished by our {JSConstructStub}.
6271cb0ef41Sopenharmony_ci    // Note that the context has to be the callers context (input to call node).
6281cb0ef41Sopenharmony_ci    // Also note that by splitting off the {JSCreate} piece of the constructor
6291cb0ef41Sopenharmony_ci    // call, we create an observable deoptimization point after the receiver
6301cb0ef41Sopenharmony_ci    // instantiation but before the invocation (i.e. inside {JSConstructStub}
6311cb0ef41Sopenharmony_ci    // where execution continues at {construct_stub_create_deopt_pc_offset}).
6321cb0ef41Sopenharmony_ci    Node* receiver = jsgraph()->TheHoleConstant();  // Implicit receiver.
6331cb0ef41Sopenharmony_ci    Node* caller_context = NodeProperties::GetContextInput(node);
6341cb0ef41Sopenharmony_ci    if (NeedsImplicitReceiver(*shared_info)) {
6351cb0ef41Sopenharmony_ci      Effect effect = n.effect();
6361cb0ef41Sopenharmony_ci      Control control = n.control();
6371cb0ef41Sopenharmony_ci      Node* frame_state_inside = CreateArtificialFrameState(
6381cb0ef41Sopenharmony_ci          node, frame_state, n.ArgumentCount(),
6391cb0ef41Sopenharmony_ci          BytecodeOffset::ConstructStubCreate(), FrameStateType::kConstructStub,
6401cb0ef41Sopenharmony_ci          *shared_info, caller_context);
6411cb0ef41Sopenharmony_ci      Node* create =
6421cb0ef41Sopenharmony_ci          graph()->NewNode(javascript()->Create(), call.target(), new_target,
6431cb0ef41Sopenharmony_ci                           caller_context, frame_state_inside, effect, control);
6441cb0ef41Sopenharmony_ci      uncaught_subcalls.push_back(create);  // Adds {IfSuccess} & {IfException}.
6451cb0ef41Sopenharmony_ci      NodeProperties::ReplaceControlInput(node, create);
6461cb0ef41Sopenharmony_ci      NodeProperties::ReplaceEffectInput(node, create);
6471cb0ef41Sopenharmony_ci      // Placeholder to hold {node}'s value dependencies while {node} is
6481cb0ef41Sopenharmony_ci      // replaced.
6491cb0ef41Sopenharmony_ci      Node* dummy = graph()->NewNode(common()->Dead());
6501cb0ef41Sopenharmony_ci      NodeProperties::ReplaceUses(node, dummy, node, node, node);
6511cb0ef41Sopenharmony_ci      Node* result;
6521cb0ef41Sopenharmony_ci      // Insert a check of the return value to determine whether the return
6531cb0ef41Sopenharmony_ci      // value or the implicit receiver should be selected as a result of the
6541cb0ef41Sopenharmony_ci      // call.
6551cb0ef41Sopenharmony_ci      Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), node);
6561cb0ef41Sopenharmony_ci      result =
6571cb0ef41Sopenharmony_ci          graph()->NewNode(common()->Select(MachineRepresentation::kTagged),
6581cb0ef41Sopenharmony_ci                           check, node, create);
6591cb0ef41Sopenharmony_ci      receiver = create;  // The implicit receiver.
6601cb0ef41Sopenharmony_ci      ReplaceWithValue(dummy, result);
6611cb0ef41Sopenharmony_ci    } else if (IsDerivedConstructor(shared_info->kind())) {
6621cb0ef41Sopenharmony_ci      Node* node_success =
6631cb0ef41Sopenharmony_ci          NodeProperties::FindSuccessfulControlProjection(node);
6641cb0ef41Sopenharmony_ci      Node* is_receiver =
6651cb0ef41Sopenharmony_ci          graph()->NewNode(simplified()->ObjectIsReceiver(), node);
6661cb0ef41Sopenharmony_ci      Node* branch_is_receiver =
6671cb0ef41Sopenharmony_ci          graph()->NewNode(common()->Branch(), is_receiver, node_success);
6681cb0ef41Sopenharmony_ci      Node* branch_is_receiver_true =
6691cb0ef41Sopenharmony_ci          graph()->NewNode(common()->IfTrue(), branch_is_receiver);
6701cb0ef41Sopenharmony_ci      Node* branch_is_receiver_false =
6711cb0ef41Sopenharmony_ci          graph()->NewNode(common()->IfFalse(), branch_is_receiver);
6721cb0ef41Sopenharmony_ci      branch_is_receiver_false = graph()->NewNode(
6731cb0ef41Sopenharmony_ci          javascript()->CallRuntime(
6741cb0ef41Sopenharmony_ci              Runtime::kThrowConstructorReturnedNonObject),
6751cb0ef41Sopenharmony_ci          caller_context, NodeProperties::GetFrameStateInput(node), node,
6761cb0ef41Sopenharmony_ci          branch_is_receiver_false);
6771cb0ef41Sopenharmony_ci      uncaught_subcalls.push_back(branch_is_receiver_false);
6781cb0ef41Sopenharmony_ci      branch_is_receiver_false =
6791cb0ef41Sopenharmony_ci          graph()->NewNode(common()->Throw(), branch_is_receiver_false,
6801cb0ef41Sopenharmony_ci                           branch_is_receiver_false);
6811cb0ef41Sopenharmony_ci      NodeProperties::MergeControlToEnd(graph(), common(),
6821cb0ef41Sopenharmony_ci                                        branch_is_receiver_false);
6831cb0ef41Sopenharmony_ci
6841cb0ef41Sopenharmony_ci      ReplaceWithValue(node_success, node_success, node_success,
6851cb0ef41Sopenharmony_ci                       branch_is_receiver_true);
6861cb0ef41Sopenharmony_ci      // Fix input destroyed by the above {ReplaceWithValue} call.
6871cb0ef41Sopenharmony_ci      NodeProperties::ReplaceControlInput(branch_is_receiver, node_success, 0);
6881cb0ef41Sopenharmony_ci    }
6891cb0ef41Sopenharmony_ci    node->ReplaceInput(JSCallNode::ReceiverIndex(), receiver);
6901cb0ef41Sopenharmony_ci    // Insert a construct stub frame into the chain of frame states. This will
6911cb0ef41Sopenharmony_ci    // reconstruct the proper frame when deoptimizing within the constructor.
6921cb0ef41Sopenharmony_ci    frame_state = CreateArtificialFrameState(
6931cb0ef41Sopenharmony_ci        node, frame_state, n.ArgumentCount(),
6941cb0ef41Sopenharmony_ci        BytecodeOffset::ConstructStubInvoke(), FrameStateType::kConstructStub,
6951cb0ef41Sopenharmony_ci        *shared_info, caller_context);
6961cb0ef41Sopenharmony_ci  }
6971cb0ef41Sopenharmony_ci
6981cb0ef41Sopenharmony_ci  // Insert a JSConvertReceiver node for sloppy callees. Note that the context
6991cb0ef41Sopenharmony_ci  // passed into this node has to be the callees context (loaded above).
7001cb0ef41Sopenharmony_ci  if (node->opcode() == IrOpcode::kJSCall &&
7011cb0ef41Sopenharmony_ci      is_sloppy(shared_info->language_mode()) && !shared_info->native()) {
7021cb0ef41Sopenharmony_ci    Effect effect{NodeProperties::GetEffectInput(node)};
7031cb0ef41Sopenharmony_ci    if (NodeProperties::CanBePrimitive(broker(), call.receiver(), effect)) {
7041cb0ef41Sopenharmony_ci      CallParameters const& p = CallParametersOf(node->op());
7051cb0ef41Sopenharmony_ci      Node* global_proxy = jsgraph()->Constant(
7061cb0ef41Sopenharmony_ci          broker()->target_native_context().global_proxy_object());
7071cb0ef41Sopenharmony_ci      Node* receiver = effect =
7081cb0ef41Sopenharmony_ci          graph()->NewNode(simplified()->ConvertReceiver(p.convert_mode()),
7091cb0ef41Sopenharmony_ci                           call.receiver(), global_proxy, effect, start);
7101cb0ef41Sopenharmony_ci      NodeProperties::ReplaceValueInput(node, receiver,
7111cb0ef41Sopenharmony_ci                                        JSCallNode::ReceiverIndex());
7121cb0ef41Sopenharmony_ci      NodeProperties::ReplaceEffectInput(node, effect);
7131cb0ef41Sopenharmony_ci    }
7141cb0ef41Sopenharmony_ci  }
7151cb0ef41Sopenharmony_ci
7161cb0ef41Sopenharmony_ci  // Insert argument adaptor frame if required. The callees formal parameter
7171cb0ef41Sopenharmony_ci  // count have to match the number of arguments passed
7181cb0ef41Sopenharmony_ci  // to the call.
7191cb0ef41Sopenharmony_ci  int parameter_count =
7201cb0ef41Sopenharmony_ci      shared_info->internal_formal_parameter_count_without_receiver();
7211cb0ef41Sopenharmony_ci  DCHECK_EQ(parameter_count, start.FormalParameterCountWithoutReceiver());
7221cb0ef41Sopenharmony_ci  if (call.argument_count() != parameter_count) {
7231cb0ef41Sopenharmony_ci    frame_state = CreateArtificialFrameState(
7241cb0ef41Sopenharmony_ci        node, frame_state, call.argument_count(), BytecodeOffset::None(),
7251cb0ef41Sopenharmony_ci        FrameStateType::kArgumentsAdaptor, *shared_info);
7261cb0ef41Sopenharmony_ci  }
7271cb0ef41Sopenharmony_ci
7281cb0ef41Sopenharmony_ci  return InlineCall(node, new_target, context, frame_state, start, end,
7291cb0ef41Sopenharmony_ci                    exception_target, uncaught_subcalls, call.argument_count());
7301cb0ef41Sopenharmony_ci}
7311cb0ef41Sopenharmony_ci
7321cb0ef41Sopenharmony_ciGraph* JSInliner::graph() const { return jsgraph()->graph(); }
7331cb0ef41Sopenharmony_ci
7341cb0ef41Sopenharmony_ciJSOperatorBuilder* JSInliner::javascript() const {
7351cb0ef41Sopenharmony_ci  return jsgraph()->javascript();
7361cb0ef41Sopenharmony_ci}
7371cb0ef41Sopenharmony_ci
7381cb0ef41Sopenharmony_ciCommonOperatorBuilder* JSInliner::common() const { return jsgraph()->common(); }
7391cb0ef41Sopenharmony_ci
7401cb0ef41Sopenharmony_ciSimplifiedOperatorBuilder* JSInliner::simplified() const {
7411cb0ef41Sopenharmony_ci  return jsgraph()->simplified();
7421cb0ef41Sopenharmony_ci}
7431cb0ef41Sopenharmony_ci
7441cb0ef41Sopenharmony_ci#undef TRACE
7451cb0ef41Sopenharmony_ci
7461cb0ef41Sopenharmony_ci}  // namespace compiler
7471cb0ef41Sopenharmony_ci}  // namespace internal
7481cb0ef41Sopenharmony_ci}  // namespace v8
749