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()), ¶ms.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