11cb0ef41Sopenharmony_ci// Copyright 2015 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-call-reducer.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <functional> 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#include "src/api/api-inl.h" 101cb0ef41Sopenharmony_ci#include "src/base/small-vector.h" 111cb0ef41Sopenharmony_ci#include "src/builtins/builtins-promise.h" 121cb0ef41Sopenharmony_ci#include "src/builtins/builtins-utils.h" 131cb0ef41Sopenharmony_ci#include "src/codegen/code-factory.h" 141cb0ef41Sopenharmony_ci#include "src/codegen/tnode.h" 151cb0ef41Sopenharmony_ci#include "src/compiler/access-builder.h" 161cb0ef41Sopenharmony_ci#include "src/compiler/access-info.h" 171cb0ef41Sopenharmony_ci#include "src/compiler/allocation-builder-inl.h" 181cb0ef41Sopenharmony_ci#include "src/compiler/allocation-builder.h" 191cb0ef41Sopenharmony_ci#include "src/compiler/common-operator.h" 201cb0ef41Sopenharmony_ci#include "src/compiler/compilation-dependencies.h" 211cb0ef41Sopenharmony_ci#include "src/compiler/fast-api-calls.h" 221cb0ef41Sopenharmony_ci#include "src/compiler/feedback-source.h" 231cb0ef41Sopenharmony_ci#include "src/compiler/graph-assembler.h" 241cb0ef41Sopenharmony_ci#include "src/compiler/js-graph.h" 251cb0ef41Sopenharmony_ci#include "src/compiler/linkage.h" 261cb0ef41Sopenharmony_ci#include "src/compiler/map-inference.h" 271cb0ef41Sopenharmony_ci#include "src/compiler/node-matchers.h" 281cb0ef41Sopenharmony_ci#include "src/compiler/opcodes.h" 291cb0ef41Sopenharmony_ci#include "src/compiler/property-access-builder.h" 301cb0ef41Sopenharmony_ci#include "src/compiler/simplified-operator.h" 311cb0ef41Sopenharmony_ci#include "src/compiler/state-values-utils.h" 321cb0ef41Sopenharmony_ci#include "src/compiler/type-cache.h" 331cb0ef41Sopenharmony_ci#include "src/ic/call-optimization.h" 341cb0ef41Sopenharmony_ci#include "src/logging/counters.h" 351cb0ef41Sopenharmony_ci#include "src/objects/arguments-inl.h" 361cb0ef41Sopenharmony_ci#include "src/objects/feedback-vector-inl.h" 371cb0ef41Sopenharmony_ci#include "src/objects/js-array-buffer-inl.h" 381cb0ef41Sopenharmony_ci#include "src/objects/js-array-inl.h" 391cb0ef41Sopenharmony_ci#include "src/objects/js-function.h" 401cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 411cb0ef41Sopenharmony_ci#include "src/objects/ordered-hash-table.h" 421cb0ef41Sopenharmony_ci#include "src/objects/string-inl.h" 431cb0ef41Sopenharmony_ci 441cb0ef41Sopenharmony_ci#ifdef V8_INTL_SUPPORT 451cb0ef41Sopenharmony_ci#include "src/objects/intl-objects.h" 461cb0ef41Sopenharmony_ci#endif 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_cinamespace v8 { 491cb0ef41Sopenharmony_cinamespace internal { 501cb0ef41Sopenharmony_cinamespace compiler { 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci// Shorter lambda declarations with less visual clutter. 531cb0ef41Sopenharmony_ci#define _ [&]() 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ciclass JSCallReducerAssembler : public JSGraphAssembler { 561cb0ef41Sopenharmony_ci protected: 571cb0ef41Sopenharmony_ci class CatchScope; 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci private: 601cb0ef41Sopenharmony_ci static constexpr bool kMarkLoopExits = true; 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ci public: 631cb0ef41Sopenharmony_ci JSCallReducerAssembler(JSCallReducer* reducer, Node* node) 641cb0ef41Sopenharmony_ci : JSGraphAssembler( 651cb0ef41Sopenharmony_ci reducer->JSGraphForGraphAssembler(), 661cb0ef41Sopenharmony_ci reducer->ZoneForGraphAssembler(), 671cb0ef41Sopenharmony_ci [reducer](Node* n) { reducer->RevisitForGraphAssembler(n); }, 681cb0ef41Sopenharmony_ci kMarkLoopExits), 691cb0ef41Sopenharmony_ci dependencies_(reducer->dependencies()), 701cb0ef41Sopenharmony_ci node_(node), 711cb0ef41Sopenharmony_ci outermost_catch_scope_( 721cb0ef41Sopenharmony_ci CatchScope::Outermost(reducer->ZoneForGraphAssembler())), 731cb0ef41Sopenharmony_ci catch_scope_(&outermost_catch_scope_) { 741cb0ef41Sopenharmony_ci InitializeEffectControl(NodeProperties::GetEffectInput(node), 751cb0ef41Sopenharmony_ci NodeProperties::GetControlInput(node)); 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci // Finish initializing the outermost catch scope. 781cb0ef41Sopenharmony_ci bool has_handler = 791cb0ef41Sopenharmony_ci NodeProperties::IsExceptionalCall(node, &outermost_handler_); 801cb0ef41Sopenharmony_ci outermost_catch_scope_.set_has_handler(has_handler); 811cb0ef41Sopenharmony_ci outermost_catch_scope_.set_gasm(this); 821cb0ef41Sopenharmony_ci } 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci TNode<Object> ReduceJSCallWithArrayLikeOrSpreadOfEmpty( 851cb0ef41Sopenharmony_ci std::unordered_set<Node*>* generated_calls_with_array_like_or_spread); 861cb0ef41Sopenharmony_ci TNode<Object> ReduceMathUnary(const Operator* op); 871cb0ef41Sopenharmony_ci TNode<Object> ReduceMathBinary(const Operator* op); 881cb0ef41Sopenharmony_ci TNode<String> ReduceStringPrototypeSubstring(); 891cb0ef41Sopenharmony_ci TNode<Boolean> ReduceStringPrototypeStartsWith(); 901cb0ef41Sopenharmony_ci TNode<Boolean> ReduceStringPrototypeStartsWith( 911cb0ef41Sopenharmony_ci const StringRef& search_element_string); 921cb0ef41Sopenharmony_ci TNode<String> ReduceStringPrototypeSlice(); 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ci TNode<Object> TargetInput() const { return JSCallNode{node_ptr()}.target(); } 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci template <typename T> 971cb0ef41Sopenharmony_ci TNode<T> ReceiverInputAs() const { 981cb0ef41Sopenharmony_ci return TNode<T>::UncheckedCast(JSCallNode{node_ptr()}.receiver()); 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci TNode<Object> ReceiverInput() const { return ReceiverInputAs<Object>(); } 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci CatchScope* catch_scope() const { return catch_scope_; } 1041cb0ef41Sopenharmony_ci Node* outermost_handler() const { return outermost_handler_; } 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci Node* node_ptr() const { return node_; } 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci protected: 1091cb0ef41Sopenharmony_ci using NodeGenerator0 = std::function<TNode<Object>()>; 1101cb0ef41Sopenharmony_ci using VoidGenerator0 = std::function<void()>; 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci // TODO(jgruber): Currently IfBuilder0 and IfBuilder1 are implemented as 1131cb0ef41Sopenharmony_ci // separate classes. If, in the future, we encounter additional use cases that 1141cb0ef41Sopenharmony_ci // return more than 1 value, we should merge these back into a single variadic 1151cb0ef41Sopenharmony_ci // implementation. 1161cb0ef41Sopenharmony_ci class IfBuilder0 final { 1171cb0ef41Sopenharmony_ci public: 1181cb0ef41Sopenharmony_ci IfBuilder0(JSGraphAssembler* gasm, TNode<Boolean> cond, bool negate_cond) 1191cb0ef41Sopenharmony_ci : gasm_(gasm), 1201cb0ef41Sopenharmony_ci cond_(cond), 1211cb0ef41Sopenharmony_ci negate_cond_(negate_cond), 1221cb0ef41Sopenharmony_ci initial_effect_(gasm->effect()), 1231cb0ef41Sopenharmony_ci initial_control_(gasm->control()) {} 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_ci IfBuilder0& ExpectTrue() { 1261cb0ef41Sopenharmony_ci DCHECK_EQ(hint_, BranchHint::kNone); 1271cb0ef41Sopenharmony_ci hint_ = BranchHint::kTrue; 1281cb0ef41Sopenharmony_ci return *this; 1291cb0ef41Sopenharmony_ci } 1301cb0ef41Sopenharmony_ci IfBuilder0& ExpectFalse() { 1311cb0ef41Sopenharmony_ci DCHECK_EQ(hint_, BranchHint::kNone); 1321cb0ef41Sopenharmony_ci hint_ = BranchHint::kFalse; 1331cb0ef41Sopenharmony_ci return *this; 1341cb0ef41Sopenharmony_ci } 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ci IfBuilder0& Then(const VoidGenerator0& body) { 1371cb0ef41Sopenharmony_ci then_body_ = body; 1381cb0ef41Sopenharmony_ci return *this; 1391cb0ef41Sopenharmony_ci } 1401cb0ef41Sopenharmony_ci IfBuilder0& Else(const VoidGenerator0& body) { 1411cb0ef41Sopenharmony_ci else_body_ = body; 1421cb0ef41Sopenharmony_ci return *this; 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci ~IfBuilder0() { 1461cb0ef41Sopenharmony_ci // Ensure correct usage: effect/control must not have been modified while 1471cb0ef41Sopenharmony_ci // the IfBuilder0 instance is alive. 1481cb0ef41Sopenharmony_ci DCHECK_EQ(gasm_->effect(), initial_effect_); 1491cb0ef41Sopenharmony_ci DCHECK_EQ(gasm_->control(), initial_control_); 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci // Unlike IfBuilder1, this supports an empty then or else body. This is 1521cb0ef41Sopenharmony_ci // possible since the merge does not take any value inputs. 1531cb0ef41Sopenharmony_ci DCHECK(then_body_ || else_body_); 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ci if (negate_cond_) std::swap(then_body_, else_body_); 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci auto if_true = (hint_ == BranchHint::kFalse) ? gasm_->MakeDeferredLabel() 1581cb0ef41Sopenharmony_ci : gasm_->MakeLabel(); 1591cb0ef41Sopenharmony_ci auto if_false = (hint_ == BranchHint::kTrue) ? gasm_->MakeDeferredLabel() 1601cb0ef41Sopenharmony_ci : gasm_->MakeLabel(); 1611cb0ef41Sopenharmony_ci auto merge = gasm_->MakeLabel(); 1621cb0ef41Sopenharmony_ci gasm_->Branch(cond_, &if_true, &if_false); 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ci gasm_->Bind(&if_true); 1651cb0ef41Sopenharmony_ci if (then_body_) then_body_(); 1661cb0ef41Sopenharmony_ci if (gasm_->HasActiveBlock()) gasm_->Goto(&merge); 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci gasm_->Bind(&if_false); 1691cb0ef41Sopenharmony_ci if (else_body_) else_body_(); 1701cb0ef41Sopenharmony_ci if (gasm_->HasActiveBlock()) gasm_->Goto(&merge); 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci gasm_->Bind(&merge); 1731cb0ef41Sopenharmony_ci } 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci IfBuilder0(const IfBuilder0&) = delete; 1761cb0ef41Sopenharmony_ci IfBuilder0& operator=(const IfBuilder0&) = delete; 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_ci private: 1791cb0ef41Sopenharmony_ci JSGraphAssembler* const gasm_; 1801cb0ef41Sopenharmony_ci const TNode<Boolean> cond_; 1811cb0ef41Sopenharmony_ci const bool negate_cond_; 1821cb0ef41Sopenharmony_ci const Effect initial_effect_; 1831cb0ef41Sopenharmony_ci const Control initial_control_; 1841cb0ef41Sopenharmony_ci BranchHint hint_ = BranchHint::kNone; 1851cb0ef41Sopenharmony_ci VoidGenerator0 then_body_; 1861cb0ef41Sopenharmony_ci VoidGenerator0 else_body_; 1871cb0ef41Sopenharmony_ci }; 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ci IfBuilder0 If(TNode<Boolean> cond) { return {this, cond, false}; } 1901cb0ef41Sopenharmony_ci IfBuilder0 IfNot(TNode<Boolean> cond) { return {this, cond, true}; } 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci template <typename T> 1931cb0ef41Sopenharmony_ci class IfBuilder1 { 1941cb0ef41Sopenharmony_ci using If1BodyFunction = std::function<TNode<T>()>; 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci public: 1971cb0ef41Sopenharmony_ci IfBuilder1(JSGraphAssembler* gasm, TNode<Boolean> cond) 1981cb0ef41Sopenharmony_ci : gasm_(gasm), cond_(cond) {} 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci V8_WARN_UNUSED_RESULT IfBuilder1& ExpectTrue() { 2011cb0ef41Sopenharmony_ci DCHECK_EQ(hint_, BranchHint::kNone); 2021cb0ef41Sopenharmony_ci hint_ = BranchHint::kTrue; 2031cb0ef41Sopenharmony_ci return *this; 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci 2061cb0ef41Sopenharmony_ci V8_WARN_UNUSED_RESULT IfBuilder1& ExpectFalse() { 2071cb0ef41Sopenharmony_ci DCHECK_EQ(hint_, BranchHint::kNone); 2081cb0ef41Sopenharmony_ci hint_ = BranchHint::kFalse; 2091cb0ef41Sopenharmony_ci return *this; 2101cb0ef41Sopenharmony_ci } 2111cb0ef41Sopenharmony_ci 2121cb0ef41Sopenharmony_ci V8_WARN_UNUSED_RESULT IfBuilder1& Then(const If1BodyFunction& body) { 2131cb0ef41Sopenharmony_ci then_body_ = body; 2141cb0ef41Sopenharmony_ci return *this; 2151cb0ef41Sopenharmony_ci } 2161cb0ef41Sopenharmony_ci V8_WARN_UNUSED_RESULT IfBuilder1& Else(const If1BodyFunction& body) { 2171cb0ef41Sopenharmony_ci else_body_ = body; 2181cb0ef41Sopenharmony_ci return *this; 2191cb0ef41Sopenharmony_ci } 2201cb0ef41Sopenharmony_ci 2211cb0ef41Sopenharmony_ci V8_WARN_UNUSED_RESULT TNode<T> Value() { 2221cb0ef41Sopenharmony_ci DCHECK(then_body_); 2231cb0ef41Sopenharmony_ci DCHECK(else_body_); 2241cb0ef41Sopenharmony_ci auto if_true = (hint_ == BranchHint::kFalse) ? gasm_->MakeDeferredLabel() 2251cb0ef41Sopenharmony_ci : gasm_->MakeLabel(); 2261cb0ef41Sopenharmony_ci auto if_false = (hint_ == BranchHint::kTrue) ? gasm_->MakeDeferredLabel() 2271cb0ef41Sopenharmony_ci : gasm_->MakeLabel(); 2281cb0ef41Sopenharmony_ci auto merge = gasm_->MakeLabel(kPhiRepresentation); 2291cb0ef41Sopenharmony_ci gasm_->Branch(cond_, &if_true, &if_false); 2301cb0ef41Sopenharmony_ci 2311cb0ef41Sopenharmony_ci gasm_->Bind(&if_true); 2321cb0ef41Sopenharmony_ci TNode<T> then_result = then_body_(); 2331cb0ef41Sopenharmony_ci if (gasm_->HasActiveBlock()) gasm_->Goto(&merge, then_result); 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ci gasm_->Bind(&if_false); 2361cb0ef41Sopenharmony_ci TNode<T> else_result = else_body_(); 2371cb0ef41Sopenharmony_ci if (gasm_->HasActiveBlock()) { 2381cb0ef41Sopenharmony_ci gasm_->Goto(&merge, else_result); 2391cb0ef41Sopenharmony_ci } 2401cb0ef41Sopenharmony_ci 2411cb0ef41Sopenharmony_ci gasm_->Bind(&merge); 2421cb0ef41Sopenharmony_ci return merge.PhiAt<T>(0); 2431cb0ef41Sopenharmony_ci } 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci private: 2461cb0ef41Sopenharmony_ci static constexpr MachineRepresentation kPhiRepresentation = 2471cb0ef41Sopenharmony_ci MachineRepresentation::kTagged; 2481cb0ef41Sopenharmony_ci 2491cb0ef41Sopenharmony_ci JSGraphAssembler* const gasm_; 2501cb0ef41Sopenharmony_ci const TNode<Boolean> cond_; 2511cb0ef41Sopenharmony_ci BranchHint hint_ = BranchHint::kNone; 2521cb0ef41Sopenharmony_ci If1BodyFunction then_body_; 2531cb0ef41Sopenharmony_ci If1BodyFunction else_body_; 2541cb0ef41Sopenharmony_ci }; 2551cb0ef41Sopenharmony_ci 2561cb0ef41Sopenharmony_ci template <typename T> 2571cb0ef41Sopenharmony_ci IfBuilder1<T> SelectIf(TNode<Boolean> cond) { 2581cb0ef41Sopenharmony_ci return {this, cond}; 2591cb0ef41Sopenharmony_ci } 2601cb0ef41Sopenharmony_ci 2611cb0ef41Sopenharmony_ci // Simplified operators. 2621cb0ef41Sopenharmony_ci TNode<Number> SpeculativeToNumber( 2631cb0ef41Sopenharmony_ci TNode<Object> value, 2641cb0ef41Sopenharmony_ci NumberOperationHint hint = NumberOperationHint::kNumberOrOddball); 2651cb0ef41Sopenharmony_ci TNode<Smi> CheckSmi(TNode<Object> value); 2661cb0ef41Sopenharmony_ci TNode<String> CheckString(TNode<Object> value); 2671cb0ef41Sopenharmony_ci TNode<Number> CheckBounds(TNode<Number> value, TNode<Number> limit); 2681cb0ef41Sopenharmony_ci 2691cb0ef41Sopenharmony_ci // Common operators. 2701cb0ef41Sopenharmony_ci TNode<Smi> TypeGuardUnsignedSmall(TNode<Object> value); 2711cb0ef41Sopenharmony_ci TNode<Object> TypeGuardNonInternal(TNode<Object> value); 2721cb0ef41Sopenharmony_ci TNode<Number> TypeGuardFixedArrayLength(TNode<Object> value); 2731cb0ef41Sopenharmony_ci TNode<Object> Call4(const Callable& callable, TNode<Context> context, 2741cb0ef41Sopenharmony_ci TNode<Object> arg0, TNode<Object> arg1, 2751cb0ef41Sopenharmony_ci TNode<Object> arg2, TNode<Object> arg3); 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ci // Javascript operators. 2781cb0ef41Sopenharmony_ci TNode<Object> JSCall3(TNode<Object> function, TNode<Object> this_arg, 2791cb0ef41Sopenharmony_ci TNode<Object> arg0, TNode<Object> arg1, 2801cb0ef41Sopenharmony_ci TNode<Object> arg2, FrameState frame_state); 2811cb0ef41Sopenharmony_ci TNode<Object> JSCall4(TNode<Object> function, TNode<Object> this_arg, 2821cb0ef41Sopenharmony_ci TNode<Object> arg0, TNode<Object> arg1, 2831cb0ef41Sopenharmony_ci TNode<Object> arg2, TNode<Object> arg3, 2841cb0ef41Sopenharmony_ci FrameState frame_state); 2851cb0ef41Sopenharmony_ci TNode<Object> JSCallRuntime2(Runtime::FunctionId function_id, 2861cb0ef41Sopenharmony_ci TNode<Object> arg0, TNode<Object> arg1, 2871cb0ef41Sopenharmony_ci FrameState frame_state); 2881cb0ef41Sopenharmony_ci 2891cb0ef41Sopenharmony_ci // Emplace a copy of the call node into the graph at current effect/control. 2901cb0ef41Sopenharmony_ci TNode<Object> CopyNode(); 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_ci // Used in special cases in which we are certain CreateArray does not throw. 2931cb0ef41Sopenharmony_ci TNode<JSArray> CreateArrayNoThrow(TNode<Object> ctor, TNode<Number> size, 2941cb0ef41Sopenharmony_ci FrameState frame_state); 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_ci TNode<JSArray> AllocateEmptyJSArray(ElementsKind kind, 2971cb0ef41Sopenharmony_ci const NativeContextRef& native_context); 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ci TNode<Number> NumberInc(TNode<Number> value) { 3001cb0ef41Sopenharmony_ci return NumberAdd(value, OneConstant()); 3011cb0ef41Sopenharmony_ci } 3021cb0ef41Sopenharmony_ci 3031cb0ef41Sopenharmony_ci void MaybeInsertMapChecks(MapInference* inference, 3041cb0ef41Sopenharmony_ci bool has_stability_dependency) { 3051cb0ef41Sopenharmony_ci // TODO(jgruber): Implement MapInference::InsertMapChecks in graph 3061cb0ef41Sopenharmony_ci // assembler. 3071cb0ef41Sopenharmony_ci if (!has_stability_dependency) { 3081cb0ef41Sopenharmony_ci Effect e = effect(); 3091cb0ef41Sopenharmony_ci inference->InsertMapChecks(jsgraph(), &e, Control{control()}, feedback()); 3101cb0ef41Sopenharmony_ci InitializeEffectControl(e, control()); 3111cb0ef41Sopenharmony_ci } 3121cb0ef41Sopenharmony_ci } 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_ci // TODO(jgruber): Currently, it's the responsibility of the developer to note 3151cb0ef41Sopenharmony_ci // which operations may throw and appropriately wrap these in a call to 3161cb0ef41Sopenharmony_ci // MayThrow (see e.g. JSCall3 and CallRuntime2). A more methodical approach 3171cb0ef41Sopenharmony_ci // would be good. 3181cb0ef41Sopenharmony_ci TNode<Object> MayThrow(const NodeGenerator0& body) { 3191cb0ef41Sopenharmony_ci TNode<Object> result = body(); 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_ci if (catch_scope()->has_handler()) { 3221cb0ef41Sopenharmony_ci // The IfException node is later merged into the outer graph. 3231cb0ef41Sopenharmony_ci // Note: AddNode is intentionally not called since effect and control 3241cb0ef41Sopenharmony_ci // should not be updated. 3251cb0ef41Sopenharmony_ci Node* if_exception = 3261cb0ef41Sopenharmony_ci graph()->NewNode(common()->IfException(), effect(), control()); 3271cb0ef41Sopenharmony_ci catch_scope()->RegisterIfExceptionNode(if_exception); 3281cb0ef41Sopenharmony_ci 3291cb0ef41Sopenharmony_ci // Control resumes here. 3301cb0ef41Sopenharmony_ci AddNode(graph()->NewNode(common()->IfSuccess(), control())); 3311cb0ef41Sopenharmony_ci } 3321cb0ef41Sopenharmony_ci 3331cb0ef41Sopenharmony_ci return result; 3341cb0ef41Sopenharmony_ci } 3351cb0ef41Sopenharmony_ci 3361cb0ef41Sopenharmony_ci // A catch scope represents a single catch handler. The handler can be 3371cb0ef41Sopenharmony_ci // custom catch logic within the reduction itself; or a catch handler in the 3381cb0ef41Sopenharmony_ci // outside graph into which the reduction will be integrated (in this case 3391cb0ef41Sopenharmony_ci // the scope is called 'outermost'). 3401cb0ef41Sopenharmony_ci class V8_NODISCARD CatchScope { 3411cb0ef41Sopenharmony_ci private: 3421cb0ef41Sopenharmony_ci // Only used to partially construct the outermost scope. 3431cb0ef41Sopenharmony_ci explicit CatchScope(Zone* zone) : if_exception_nodes_(zone) {} 3441cb0ef41Sopenharmony_ci 3451cb0ef41Sopenharmony_ci // For all inner scopes. 3461cb0ef41Sopenharmony_ci CatchScope(Zone* zone, JSCallReducerAssembler* gasm) 3471cb0ef41Sopenharmony_ci : gasm_(gasm), 3481cb0ef41Sopenharmony_ci parent_(gasm->catch_scope_), 3491cb0ef41Sopenharmony_ci has_handler_(true), 3501cb0ef41Sopenharmony_ci if_exception_nodes_(zone) { 3511cb0ef41Sopenharmony_ci gasm_->catch_scope_ = this; 3521cb0ef41Sopenharmony_ci } 3531cb0ef41Sopenharmony_ci 3541cb0ef41Sopenharmony_ci public: 3551cb0ef41Sopenharmony_ci ~CatchScope() { gasm_->catch_scope_ = parent_; } 3561cb0ef41Sopenharmony_ci 3571cb0ef41Sopenharmony_ci static CatchScope Outermost(Zone* zone) { return CatchScope{zone}; } 3581cb0ef41Sopenharmony_ci static CatchScope Inner(Zone* zone, JSCallReducerAssembler* gasm) { 3591cb0ef41Sopenharmony_ci return {zone, gasm}; 3601cb0ef41Sopenharmony_ci } 3611cb0ef41Sopenharmony_ci 3621cb0ef41Sopenharmony_ci bool has_handler() const { return has_handler_; } 3631cb0ef41Sopenharmony_ci bool is_outermost() const { return parent_ == nullptr; } 3641cb0ef41Sopenharmony_ci CatchScope* parent() const { return parent_; } 3651cb0ef41Sopenharmony_ci 3661cb0ef41Sopenharmony_ci // Should only be used to initialize the outermost scope (inner scopes 3671cb0ef41Sopenharmony_ci // always have a handler and are passed the gasm pointer at construction). 3681cb0ef41Sopenharmony_ci void set_has_handler(bool v) { 3691cb0ef41Sopenharmony_ci DCHECK(is_outermost()); 3701cb0ef41Sopenharmony_ci has_handler_ = v; 3711cb0ef41Sopenharmony_ci } 3721cb0ef41Sopenharmony_ci void set_gasm(JSCallReducerAssembler* v) { 3731cb0ef41Sopenharmony_ci DCHECK(is_outermost()); 3741cb0ef41Sopenharmony_ci gasm_ = v; 3751cb0ef41Sopenharmony_ci } 3761cb0ef41Sopenharmony_ci 3771cb0ef41Sopenharmony_ci bool has_exceptional_control_flow() const { 3781cb0ef41Sopenharmony_ci return !if_exception_nodes_.empty(); 3791cb0ef41Sopenharmony_ci } 3801cb0ef41Sopenharmony_ci 3811cb0ef41Sopenharmony_ci void RegisterIfExceptionNode(Node* if_exception) { 3821cb0ef41Sopenharmony_ci DCHECK(has_handler()); 3831cb0ef41Sopenharmony_ci if_exception_nodes_.push_back(if_exception); 3841cb0ef41Sopenharmony_ci } 3851cb0ef41Sopenharmony_ci 3861cb0ef41Sopenharmony_ci void MergeExceptionalPaths(TNode<Object>* exception_out, Effect* effect_out, 3871cb0ef41Sopenharmony_ci Control* control_out) { 3881cb0ef41Sopenharmony_ci DCHECK(has_handler()); 3891cb0ef41Sopenharmony_ci DCHECK(has_exceptional_control_flow()); 3901cb0ef41Sopenharmony_ci 3911cb0ef41Sopenharmony_ci const int size = static_cast<int>(if_exception_nodes_.size()); 3921cb0ef41Sopenharmony_ci 3931cb0ef41Sopenharmony_ci if (size == 1) { 3941cb0ef41Sopenharmony_ci // No merge needed. 3951cb0ef41Sopenharmony_ci Node* e = if_exception_nodes_.at(0); 3961cb0ef41Sopenharmony_ci *exception_out = TNode<Object>::UncheckedCast(e); 3971cb0ef41Sopenharmony_ci *effect_out = Effect(e); 3981cb0ef41Sopenharmony_ci *control_out = Control(e); 3991cb0ef41Sopenharmony_ci } else { 4001cb0ef41Sopenharmony_ci DCHECK_GT(size, 1); 4011cb0ef41Sopenharmony_ci 4021cb0ef41Sopenharmony_ci Node* merge = gasm_->graph()->NewNode(gasm_->common()->Merge(size), 4031cb0ef41Sopenharmony_ci size, if_exception_nodes_.data()); 4041cb0ef41Sopenharmony_ci 4051cb0ef41Sopenharmony_ci // These phis additionally take {merge} as an input. Temporarily add 4061cb0ef41Sopenharmony_ci // it to the list. 4071cb0ef41Sopenharmony_ci if_exception_nodes_.push_back(merge); 4081cb0ef41Sopenharmony_ci const int size_with_merge = 4091cb0ef41Sopenharmony_ci static_cast<int>(if_exception_nodes_.size()); 4101cb0ef41Sopenharmony_ci 4111cb0ef41Sopenharmony_ci Node* ephi = gasm_->graph()->NewNode(gasm_->common()->EffectPhi(size), 4121cb0ef41Sopenharmony_ci size_with_merge, 4131cb0ef41Sopenharmony_ci if_exception_nodes_.data()); 4141cb0ef41Sopenharmony_ci Node* phi = gasm_->graph()->NewNode( 4151cb0ef41Sopenharmony_ci gasm_->common()->Phi(MachineRepresentation::kTagged, size), 4161cb0ef41Sopenharmony_ci size_with_merge, if_exception_nodes_.data()); 4171cb0ef41Sopenharmony_ci if_exception_nodes_.pop_back(); 4181cb0ef41Sopenharmony_ci 4191cb0ef41Sopenharmony_ci *exception_out = TNode<Object>::UncheckedCast(phi); 4201cb0ef41Sopenharmony_ci *effect_out = Effect(ephi); 4211cb0ef41Sopenharmony_ci *control_out = Control(merge); 4221cb0ef41Sopenharmony_ci } 4231cb0ef41Sopenharmony_ci } 4241cb0ef41Sopenharmony_ci 4251cb0ef41Sopenharmony_ci private: 4261cb0ef41Sopenharmony_ci JSCallReducerAssembler* gasm_ = nullptr; 4271cb0ef41Sopenharmony_ci CatchScope* const parent_ = nullptr; 4281cb0ef41Sopenharmony_ci bool has_handler_ = false; 4291cb0ef41Sopenharmony_ci NodeVector if_exception_nodes_; 4301cb0ef41Sopenharmony_ci }; 4311cb0ef41Sopenharmony_ci 4321cb0ef41Sopenharmony_ci class TryCatchBuilder0 { 4331cb0ef41Sopenharmony_ci public: 4341cb0ef41Sopenharmony_ci using TryFunction = VoidGenerator0; 4351cb0ef41Sopenharmony_ci using CatchFunction = std::function<void(TNode<Object>)>; 4361cb0ef41Sopenharmony_ci 4371cb0ef41Sopenharmony_ci TryCatchBuilder0(JSCallReducerAssembler* gasm, const TryFunction& try_body) 4381cb0ef41Sopenharmony_ci : gasm_(gasm), try_body_(try_body) {} 4391cb0ef41Sopenharmony_ci 4401cb0ef41Sopenharmony_ci void Catch(const CatchFunction& catch_body) { 4411cb0ef41Sopenharmony_ci TNode<Object> handler_exception; 4421cb0ef41Sopenharmony_ci Effect handler_effect{nullptr}; 4431cb0ef41Sopenharmony_ci Control handler_control{nullptr}; 4441cb0ef41Sopenharmony_ci 4451cb0ef41Sopenharmony_ci auto continuation = gasm_->MakeLabel(); 4461cb0ef41Sopenharmony_ci 4471cb0ef41Sopenharmony_ci // Try. 4481cb0ef41Sopenharmony_ci { 4491cb0ef41Sopenharmony_ci CatchScope catch_scope = CatchScope::Inner(gasm_->temp_zone(), gasm_); 4501cb0ef41Sopenharmony_ci try_body_(); 4511cb0ef41Sopenharmony_ci gasm_->Goto(&continuation); 4521cb0ef41Sopenharmony_ci 4531cb0ef41Sopenharmony_ci catch_scope.MergeExceptionalPaths(&handler_exception, &handler_effect, 4541cb0ef41Sopenharmony_ci &handler_control); 4551cb0ef41Sopenharmony_ci } 4561cb0ef41Sopenharmony_ci 4571cb0ef41Sopenharmony_ci // Catch. 4581cb0ef41Sopenharmony_ci { 4591cb0ef41Sopenharmony_ci gasm_->InitializeEffectControl(handler_effect, handler_control); 4601cb0ef41Sopenharmony_ci catch_body(handler_exception); 4611cb0ef41Sopenharmony_ci gasm_->Goto(&continuation); 4621cb0ef41Sopenharmony_ci } 4631cb0ef41Sopenharmony_ci 4641cb0ef41Sopenharmony_ci gasm_->Bind(&continuation); 4651cb0ef41Sopenharmony_ci } 4661cb0ef41Sopenharmony_ci 4671cb0ef41Sopenharmony_ci private: 4681cb0ef41Sopenharmony_ci JSCallReducerAssembler* const gasm_; 4691cb0ef41Sopenharmony_ci const VoidGenerator0 try_body_; 4701cb0ef41Sopenharmony_ci }; 4711cb0ef41Sopenharmony_ci 4721cb0ef41Sopenharmony_ci TryCatchBuilder0 Try(const VoidGenerator0& try_body) { 4731cb0ef41Sopenharmony_ci return {this, try_body}; 4741cb0ef41Sopenharmony_ci } 4751cb0ef41Sopenharmony_ci 4761cb0ef41Sopenharmony_ci using ConditionFunction1 = std::function<TNode<Boolean>(TNode<Number>)>; 4771cb0ef41Sopenharmony_ci using StepFunction1 = std::function<TNode<Number>(TNode<Number>)>; 4781cb0ef41Sopenharmony_ci class ForBuilder0 { 4791cb0ef41Sopenharmony_ci using For0BodyFunction = std::function<void(TNode<Number>)>; 4801cb0ef41Sopenharmony_ci 4811cb0ef41Sopenharmony_ci public: 4821cb0ef41Sopenharmony_ci ForBuilder0(JSGraphAssembler* gasm, TNode<Number> initial_value, 4831cb0ef41Sopenharmony_ci const ConditionFunction1& cond, const StepFunction1& step) 4841cb0ef41Sopenharmony_ci : gasm_(gasm), 4851cb0ef41Sopenharmony_ci initial_value_(initial_value), 4861cb0ef41Sopenharmony_ci cond_(cond), 4871cb0ef41Sopenharmony_ci step_(step) {} 4881cb0ef41Sopenharmony_ci 4891cb0ef41Sopenharmony_ci void Do(const For0BodyFunction& body) { 4901cb0ef41Sopenharmony_ci auto loop_exit = gasm_->MakeLabel(); 4911cb0ef41Sopenharmony_ci 4921cb0ef41Sopenharmony_ci { 4931cb0ef41Sopenharmony_ci GraphAssembler::LoopScope<kPhiRepresentation> loop_scope(gasm_); 4941cb0ef41Sopenharmony_ci 4951cb0ef41Sopenharmony_ci auto loop_header = loop_scope.loop_header_label(); 4961cb0ef41Sopenharmony_ci auto loop_body = gasm_->MakeLabel(); 4971cb0ef41Sopenharmony_ci 4981cb0ef41Sopenharmony_ci gasm_->Goto(loop_header, initial_value_); 4991cb0ef41Sopenharmony_ci 5001cb0ef41Sopenharmony_ci gasm_->Bind(loop_header); 5011cb0ef41Sopenharmony_ci TNode<Number> i = loop_header->PhiAt<Number>(0); 5021cb0ef41Sopenharmony_ci 5031cb0ef41Sopenharmony_ci gasm_->BranchWithHint(cond_(i), &loop_body, &loop_exit, 5041cb0ef41Sopenharmony_ci BranchHint::kTrue); 5051cb0ef41Sopenharmony_ci 5061cb0ef41Sopenharmony_ci gasm_->Bind(&loop_body); 5071cb0ef41Sopenharmony_ci body(i); 5081cb0ef41Sopenharmony_ci gasm_->Goto(loop_header, step_(i)); 5091cb0ef41Sopenharmony_ci } 5101cb0ef41Sopenharmony_ci 5111cb0ef41Sopenharmony_ci gasm_->Bind(&loop_exit); 5121cb0ef41Sopenharmony_ci } 5131cb0ef41Sopenharmony_ci 5141cb0ef41Sopenharmony_ci private: 5151cb0ef41Sopenharmony_ci static constexpr MachineRepresentation kPhiRepresentation = 5161cb0ef41Sopenharmony_ci MachineRepresentation::kTagged; 5171cb0ef41Sopenharmony_ci 5181cb0ef41Sopenharmony_ci JSGraphAssembler* const gasm_; 5191cb0ef41Sopenharmony_ci const TNode<Number> initial_value_; 5201cb0ef41Sopenharmony_ci const ConditionFunction1 cond_; 5211cb0ef41Sopenharmony_ci const StepFunction1 step_; 5221cb0ef41Sopenharmony_ci }; 5231cb0ef41Sopenharmony_ci 5241cb0ef41Sopenharmony_ci ForBuilder0 ForZeroUntil(TNode<Number> excluded_limit) { 5251cb0ef41Sopenharmony_ci TNode<Number> initial_value = ZeroConstant(); 5261cb0ef41Sopenharmony_ci auto cond = [=](TNode<Number> i) { 5271cb0ef41Sopenharmony_ci return NumberLessThan(i, excluded_limit); 5281cb0ef41Sopenharmony_ci }; 5291cb0ef41Sopenharmony_ci auto step = [=](TNode<Number> i) { return NumberAdd(i, OneConstant()); }; 5301cb0ef41Sopenharmony_ci return {this, initial_value, cond, step}; 5311cb0ef41Sopenharmony_ci } 5321cb0ef41Sopenharmony_ci 5331cb0ef41Sopenharmony_ci ForBuilder0 Forever(TNode<Number> initial_value, const StepFunction1& step) { 5341cb0ef41Sopenharmony_ci return {this, initial_value, [=](TNode<Number>) { return TrueConstant(); }, 5351cb0ef41Sopenharmony_ci step}; 5361cb0ef41Sopenharmony_ci } 5371cb0ef41Sopenharmony_ci 5381cb0ef41Sopenharmony_ci using For1BodyFunction = std::function<void(TNode<Number>, TNode<Object>*)>; 5391cb0ef41Sopenharmony_ci class ForBuilder1 { 5401cb0ef41Sopenharmony_ci public: 5411cb0ef41Sopenharmony_ci ForBuilder1(JSGraphAssembler* gasm, TNode<Number> initial_value, 5421cb0ef41Sopenharmony_ci const ConditionFunction1& cond, const StepFunction1& step, 5431cb0ef41Sopenharmony_ci TNode<Object> initial_arg0) 5441cb0ef41Sopenharmony_ci : gasm_(gasm), 5451cb0ef41Sopenharmony_ci initial_value_(initial_value), 5461cb0ef41Sopenharmony_ci cond_(cond), 5471cb0ef41Sopenharmony_ci step_(step), 5481cb0ef41Sopenharmony_ci initial_arg0_(initial_arg0) {} 5491cb0ef41Sopenharmony_ci 5501cb0ef41Sopenharmony_ci V8_WARN_UNUSED_RESULT ForBuilder1& Do(const For1BodyFunction& body) { 5511cb0ef41Sopenharmony_ci body_ = body; 5521cb0ef41Sopenharmony_ci return *this; 5531cb0ef41Sopenharmony_ci } 5541cb0ef41Sopenharmony_ci 5551cb0ef41Sopenharmony_ci V8_WARN_UNUSED_RESULT TNode<Object> Value() { 5561cb0ef41Sopenharmony_ci DCHECK(body_); 5571cb0ef41Sopenharmony_ci TNode<Object> arg0 = initial_arg0_; 5581cb0ef41Sopenharmony_ci 5591cb0ef41Sopenharmony_ci auto loop_exit = gasm_->MakeDeferredLabel(kPhiRepresentation); 5601cb0ef41Sopenharmony_ci 5611cb0ef41Sopenharmony_ci { 5621cb0ef41Sopenharmony_ci GraphAssembler::LoopScope<kPhiRepresentation, kPhiRepresentation> 5631cb0ef41Sopenharmony_ci loop_scope(gasm_); 5641cb0ef41Sopenharmony_ci 5651cb0ef41Sopenharmony_ci auto loop_header = loop_scope.loop_header_label(); 5661cb0ef41Sopenharmony_ci auto loop_body = gasm_->MakeDeferredLabel(kPhiRepresentation); 5671cb0ef41Sopenharmony_ci 5681cb0ef41Sopenharmony_ci gasm_->Goto(loop_header, initial_value_, initial_arg0_); 5691cb0ef41Sopenharmony_ci 5701cb0ef41Sopenharmony_ci gasm_->Bind(loop_header); 5711cb0ef41Sopenharmony_ci TNode<Number> i = loop_header->PhiAt<Number>(0); 5721cb0ef41Sopenharmony_ci arg0 = loop_header->PhiAt<Object>(1); 5731cb0ef41Sopenharmony_ci 5741cb0ef41Sopenharmony_ci gasm_->BranchWithHint(cond_(i), &loop_body, &loop_exit, 5751cb0ef41Sopenharmony_ci BranchHint::kTrue, arg0); 5761cb0ef41Sopenharmony_ci 5771cb0ef41Sopenharmony_ci gasm_->Bind(&loop_body); 5781cb0ef41Sopenharmony_ci body_(i, &arg0); 5791cb0ef41Sopenharmony_ci gasm_->Goto(loop_header, step_(i), arg0); 5801cb0ef41Sopenharmony_ci } 5811cb0ef41Sopenharmony_ci 5821cb0ef41Sopenharmony_ci gasm_->Bind(&loop_exit); 5831cb0ef41Sopenharmony_ci return TNode<Object>::UncheckedCast(loop_exit.PhiAt<Object>(0)); 5841cb0ef41Sopenharmony_ci } 5851cb0ef41Sopenharmony_ci 5861cb0ef41Sopenharmony_ci void ValueIsUnused() { USE(Value()); } 5871cb0ef41Sopenharmony_ci 5881cb0ef41Sopenharmony_ci private: 5891cb0ef41Sopenharmony_ci static constexpr MachineRepresentation kPhiRepresentation = 5901cb0ef41Sopenharmony_ci MachineRepresentation::kTagged; 5911cb0ef41Sopenharmony_ci 5921cb0ef41Sopenharmony_ci JSGraphAssembler* const gasm_; 5931cb0ef41Sopenharmony_ci const TNode<Number> initial_value_; 5941cb0ef41Sopenharmony_ci const ConditionFunction1 cond_; 5951cb0ef41Sopenharmony_ci const StepFunction1 step_; 5961cb0ef41Sopenharmony_ci For1BodyFunction body_; 5971cb0ef41Sopenharmony_ci const TNode<Object> initial_arg0_; 5981cb0ef41Sopenharmony_ci }; 5991cb0ef41Sopenharmony_ci 6001cb0ef41Sopenharmony_ci ForBuilder1 For1(TNode<Number> initial_value, const ConditionFunction1& cond, 6011cb0ef41Sopenharmony_ci const StepFunction1& step, TNode<Object> initial_arg0) { 6021cb0ef41Sopenharmony_ci return {this, initial_value, cond, step, initial_arg0}; 6031cb0ef41Sopenharmony_ci } 6041cb0ef41Sopenharmony_ci 6051cb0ef41Sopenharmony_ci ForBuilder1 For1ZeroUntil(TNode<Number> excluded_limit, 6061cb0ef41Sopenharmony_ci TNode<Object> initial_arg0) { 6071cb0ef41Sopenharmony_ci TNode<Number> initial_value = ZeroConstant(); 6081cb0ef41Sopenharmony_ci auto cond = [=](TNode<Number> i) { 6091cb0ef41Sopenharmony_ci return NumberLessThan(i, excluded_limit); 6101cb0ef41Sopenharmony_ci }; 6111cb0ef41Sopenharmony_ci auto step = [=](TNode<Number> i) { return NumberAdd(i, OneConstant()); }; 6121cb0ef41Sopenharmony_ci return {this, initial_value, cond, step, initial_arg0}; 6131cb0ef41Sopenharmony_ci } 6141cb0ef41Sopenharmony_ci 6151cb0ef41Sopenharmony_ci void ThrowIfNotCallable(TNode<Object> maybe_callable, 6161cb0ef41Sopenharmony_ci FrameState frame_state) { 6171cb0ef41Sopenharmony_ci IfNot(ObjectIsCallable(maybe_callable)) 6181cb0ef41Sopenharmony_ci .Then(_ { 6191cb0ef41Sopenharmony_ci JSCallRuntime2(Runtime::kThrowTypeError, 6201cb0ef41Sopenharmony_ci NumberConstant(static_cast<double>( 6211cb0ef41Sopenharmony_ci MessageTemplate::kCalledNonCallable)), 6221cb0ef41Sopenharmony_ci maybe_callable, frame_state); 6231cb0ef41Sopenharmony_ci Unreachable(); // The runtime call throws unconditionally. 6241cb0ef41Sopenharmony_ci }) 6251cb0ef41Sopenharmony_ci .ExpectTrue(); 6261cb0ef41Sopenharmony_ci } 6271cb0ef41Sopenharmony_ci 6281cb0ef41Sopenharmony_ci const FeedbackSource& feedback() const { 6291cb0ef41Sopenharmony_ci CallParameters const& p = CallParametersOf(node_ptr()->op()); 6301cb0ef41Sopenharmony_ci return p.feedback(); 6311cb0ef41Sopenharmony_ci } 6321cb0ef41Sopenharmony_ci 6331cb0ef41Sopenharmony_ci int ArgumentCount() const { return JSCallNode{node_ptr()}.ArgumentCount(); } 6341cb0ef41Sopenharmony_ci 6351cb0ef41Sopenharmony_ci TNode<Object> Argument(int index) const { 6361cb0ef41Sopenharmony_ci return TNode<Object>::UncheckedCast(JSCallNode{node_ptr()}.Argument(index)); 6371cb0ef41Sopenharmony_ci } 6381cb0ef41Sopenharmony_ci 6391cb0ef41Sopenharmony_ci template <typename T> 6401cb0ef41Sopenharmony_ci TNode<T> ArgumentAs(int index) const { 6411cb0ef41Sopenharmony_ci return TNode<T>::UncheckedCast(Argument(index)); 6421cb0ef41Sopenharmony_ci } 6431cb0ef41Sopenharmony_ci 6441cb0ef41Sopenharmony_ci TNode<Object> ArgumentOrNaN(int index) { 6451cb0ef41Sopenharmony_ci return TNode<Object>::UncheckedCast( 6461cb0ef41Sopenharmony_ci ArgumentCount() > index ? Argument(index) : NaNConstant()); 6471cb0ef41Sopenharmony_ci } 6481cb0ef41Sopenharmony_ci 6491cb0ef41Sopenharmony_ci TNode<Object> ArgumentOrUndefined(int index) { 6501cb0ef41Sopenharmony_ci return TNode<Object>::UncheckedCast( 6511cb0ef41Sopenharmony_ci ArgumentCount() > index ? Argument(index) : UndefinedConstant()); 6521cb0ef41Sopenharmony_ci } 6531cb0ef41Sopenharmony_ci 6541cb0ef41Sopenharmony_ci TNode<Number> ArgumentOrZero(int index) { 6551cb0ef41Sopenharmony_ci return TNode<Number>::UncheckedCast( 6561cb0ef41Sopenharmony_ci ArgumentCount() > index ? Argument(index) : ZeroConstant()); 6571cb0ef41Sopenharmony_ci } 6581cb0ef41Sopenharmony_ci 6591cb0ef41Sopenharmony_ci TNode<Context> ContextInput() const { 6601cb0ef41Sopenharmony_ci return TNode<Context>::UncheckedCast( 6611cb0ef41Sopenharmony_ci NodeProperties::GetContextInput(node_)); 6621cb0ef41Sopenharmony_ci } 6631cb0ef41Sopenharmony_ci 6641cb0ef41Sopenharmony_ci FrameState FrameStateInput() const { 6651cb0ef41Sopenharmony_ci return FrameState(NodeProperties::GetFrameStateInput(node_)); 6661cb0ef41Sopenharmony_ci } 6671cb0ef41Sopenharmony_ci 6681cb0ef41Sopenharmony_ci JSOperatorBuilder* javascript() const { return jsgraph()->javascript(); } 6691cb0ef41Sopenharmony_ci 6701cb0ef41Sopenharmony_ci CompilationDependencies* dependencies() const { return dependencies_; } 6711cb0ef41Sopenharmony_ci 6721cb0ef41Sopenharmony_ci private: 6731cb0ef41Sopenharmony_ci CompilationDependencies* const dependencies_; 6741cb0ef41Sopenharmony_ci Node* const node_; 6751cb0ef41Sopenharmony_ci CatchScope outermost_catch_scope_; 6761cb0ef41Sopenharmony_ci Node* outermost_handler_; 6771cb0ef41Sopenharmony_ci CatchScope* catch_scope_; 6781cb0ef41Sopenharmony_ci friend class CatchScope; 6791cb0ef41Sopenharmony_ci}; 6801cb0ef41Sopenharmony_ci 6811cb0ef41Sopenharmony_cienum class ArrayReduceDirection { kLeft, kRight }; 6821cb0ef41Sopenharmony_cienum class ArrayFindVariant { kFind, kFindIndex }; 6831cb0ef41Sopenharmony_cienum class ArrayEverySomeVariant { kEvery, kSome }; 6841cb0ef41Sopenharmony_cienum class ArrayIndexOfIncludesVariant { kIncludes, kIndexOf }; 6851cb0ef41Sopenharmony_ci 6861cb0ef41Sopenharmony_ci// This subclass bundles functionality specific to reducing iterating array 6871cb0ef41Sopenharmony_ci// builtins. 6881cb0ef41Sopenharmony_ciclass IteratingArrayBuiltinReducerAssembler : public JSCallReducerAssembler { 6891cb0ef41Sopenharmony_ci public: 6901cb0ef41Sopenharmony_ci IteratingArrayBuiltinReducerAssembler(JSCallReducer* reducer, Node* node) 6911cb0ef41Sopenharmony_ci : JSCallReducerAssembler(reducer, node) { 6921cb0ef41Sopenharmony_ci DCHECK(FLAG_turbo_inline_array_builtins); 6931cb0ef41Sopenharmony_ci } 6941cb0ef41Sopenharmony_ci 6951cb0ef41Sopenharmony_ci TNode<Object> ReduceArrayPrototypeForEach( 6961cb0ef41Sopenharmony_ci MapInference* inference, const bool has_stability_dependency, 6971cb0ef41Sopenharmony_ci ElementsKind kind, const SharedFunctionInfoRef& shared); 6981cb0ef41Sopenharmony_ci TNode<Object> ReduceArrayPrototypeReduce(MapInference* inference, 6991cb0ef41Sopenharmony_ci const bool has_stability_dependency, 7001cb0ef41Sopenharmony_ci ElementsKind kind, 7011cb0ef41Sopenharmony_ci ArrayReduceDirection direction, 7021cb0ef41Sopenharmony_ci const SharedFunctionInfoRef& shared); 7031cb0ef41Sopenharmony_ci TNode<JSArray> ReduceArrayPrototypeMap( 7041cb0ef41Sopenharmony_ci MapInference* inference, const bool has_stability_dependency, 7051cb0ef41Sopenharmony_ci ElementsKind kind, const SharedFunctionInfoRef& shared, 7061cb0ef41Sopenharmony_ci const NativeContextRef& native_context); 7071cb0ef41Sopenharmony_ci TNode<JSArray> ReduceArrayPrototypeFilter( 7081cb0ef41Sopenharmony_ci MapInference* inference, const bool has_stability_dependency, 7091cb0ef41Sopenharmony_ci ElementsKind kind, const SharedFunctionInfoRef& shared, 7101cb0ef41Sopenharmony_ci const NativeContextRef& native_context); 7111cb0ef41Sopenharmony_ci TNode<Object> ReduceArrayPrototypeFind(MapInference* inference, 7121cb0ef41Sopenharmony_ci const bool has_stability_dependency, 7131cb0ef41Sopenharmony_ci ElementsKind kind, 7141cb0ef41Sopenharmony_ci const SharedFunctionInfoRef& shared, 7151cb0ef41Sopenharmony_ci const NativeContextRef& native_context, 7161cb0ef41Sopenharmony_ci ArrayFindVariant variant); 7171cb0ef41Sopenharmony_ci TNode<Boolean> ReduceArrayPrototypeEverySome( 7181cb0ef41Sopenharmony_ci MapInference* inference, const bool has_stability_dependency, 7191cb0ef41Sopenharmony_ci ElementsKind kind, const SharedFunctionInfoRef& shared, 7201cb0ef41Sopenharmony_ci const NativeContextRef& native_context, ArrayEverySomeVariant variant); 7211cb0ef41Sopenharmony_ci TNode<Object> ReduceArrayPrototypeIndexOfIncludes( 7221cb0ef41Sopenharmony_ci ElementsKind kind, ArrayIndexOfIncludesVariant variant); 7231cb0ef41Sopenharmony_ci 7241cb0ef41Sopenharmony_ci private: 7251cb0ef41Sopenharmony_ci // Returns {index,value}. Assumes that the map has not changed, but possibly 7261cb0ef41Sopenharmony_ci // the length and backing store. 7271cb0ef41Sopenharmony_ci std::pair<TNode<Number>, TNode<Object>> SafeLoadElement(ElementsKind kind, 7281cb0ef41Sopenharmony_ci TNode<JSArray> o, 7291cb0ef41Sopenharmony_ci TNode<Number> index) { 7301cb0ef41Sopenharmony_ci // Make sure that the access is still in bounds, since the callback could 7311cb0ef41Sopenharmony_ci // have changed the array's size. 7321cb0ef41Sopenharmony_ci TNode<Number> length = LoadJSArrayLength(o, kind); 7331cb0ef41Sopenharmony_ci index = CheckBounds(index, length); 7341cb0ef41Sopenharmony_ci 7351cb0ef41Sopenharmony_ci // Reload the elements pointer before calling the callback, since the 7361cb0ef41Sopenharmony_ci // previous callback might have resized the array causing the elements 7371cb0ef41Sopenharmony_ci // buffer to be re-allocated. 7381cb0ef41Sopenharmony_ci TNode<HeapObject> elements = 7391cb0ef41Sopenharmony_ci LoadField<HeapObject>(AccessBuilder::ForJSObjectElements(), o); 7401cb0ef41Sopenharmony_ci TNode<Object> value = LoadElement<Object>( 7411cb0ef41Sopenharmony_ci AccessBuilder::ForFixedArrayElement(kind), elements, index); 7421cb0ef41Sopenharmony_ci return std::make_pair(index, value); 7431cb0ef41Sopenharmony_ci } 7441cb0ef41Sopenharmony_ci 7451cb0ef41Sopenharmony_ci template <typename... Vars> 7461cb0ef41Sopenharmony_ci TNode<Object> MaybeSkipHole( 7471cb0ef41Sopenharmony_ci TNode<Object> o, ElementsKind kind, 7481cb0ef41Sopenharmony_ci GraphAssemblerLabel<sizeof...(Vars)>* continue_label, 7491cb0ef41Sopenharmony_ci TNode<Vars>... vars) { 7501cb0ef41Sopenharmony_ci if (!IsHoleyElementsKind(kind)) return o; 7511cb0ef41Sopenharmony_ci 7521cb0ef41Sopenharmony_ci std::array<MachineRepresentation, sizeof...(Vars)> reps = { 7531cb0ef41Sopenharmony_ci MachineRepresentationOf<Vars>::value...}; 7541cb0ef41Sopenharmony_ci auto if_not_hole = 7551cb0ef41Sopenharmony_ci MakeLabel<sizeof...(Vars)>(reps, GraphAssemblerLabelType::kNonDeferred); 7561cb0ef41Sopenharmony_ci BranchWithHint(HoleCheck(kind, o), continue_label, &if_not_hole, 7571cb0ef41Sopenharmony_ci BranchHint::kFalse, vars...); 7581cb0ef41Sopenharmony_ci 7591cb0ef41Sopenharmony_ci // The contract is that we don't leak "the hole" into "user JavaScript", 7601cb0ef41Sopenharmony_ci // so we must rename the {element} here to explicitly exclude "the hole" 7611cb0ef41Sopenharmony_ci // from the type of {element}. 7621cb0ef41Sopenharmony_ci Bind(&if_not_hole); 7631cb0ef41Sopenharmony_ci return TypeGuardNonInternal(o); 7641cb0ef41Sopenharmony_ci } 7651cb0ef41Sopenharmony_ci 7661cb0ef41Sopenharmony_ci TNode<Smi> LoadJSArrayLength(TNode<JSArray> array, ElementsKind kind) { 7671cb0ef41Sopenharmony_ci return LoadField<Smi>(AccessBuilder::ForJSArrayLength(kind), array); 7681cb0ef41Sopenharmony_ci } 7691cb0ef41Sopenharmony_ci void StoreJSArrayLength(TNode<JSArray> array, TNode<Number> value, 7701cb0ef41Sopenharmony_ci ElementsKind kind) { 7711cb0ef41Sopenharmony_ci StoreField(AccessBuilder::ForJSArrayLength(kind), array, value); 7721cb0ef41Sopenharmony_ci } 7731cb0ef41Sopenharmony_ci void StoreFixedArrayBaseElement(TNode<FixedArrayBase> o, TNode<Number> index, 7741cb0ef41Sopenharmony_ci TNode<Object> v, ElementsKind kind) { 7751cb0ef41Sopenharmony_ci StoreElement(AccessBuilder::ForFixedArrayElement(kind), o, index, v); 7761cb0ef41Sopenharmony_ci } 7771cb0ef41Sopenharmony_ci 7781cb0ef41Sopenharmony_ci TNode<FixedArrayBase> LoadElements(TNode<JSObject> o) { 7791cb0ef41Sopenharmony_ci return LoadField<FixedArrayBase>(AccessBuilder::ForJSObjectElements(), o); 7801cb0ef41Sopenharmony_ci } 7811cb0ef41Sopenharmony_ci TNode<Smi> LoadFixedArrayBaseLength(TNode<FixedArrayBase> o) { 7821cb0ef41Sopenharmony_ci return LoadField<Smi>(AccessBuilder::ForFixedArrayLength(), o); 7831cb0ef41Sopenharmony_ci } 7841cb0ef41Sopenharmony_ci 7851cb0ef41Sopenharmony_ci TNode<Boolean> HoleCheck(ElementsKind kind, TNode<Object> v) { 7861cb0ef41Sopenharmony_ci return IsDoubleElementsKind(kind) 7871cb0ef41Sopenharmony_ci ? NumberIsFloat64Hole(TNode<Number>::UncheckedCast(v)) 7881cb0ef41Sopenharmony_ci : IsTheHole(v); 7891cb0ef41Sopenharmony_ci } 7901cb0ef41Sopenharmony_ci 7911cb0ef41Sopenharmony_ci TNode<Number> CheckFloat64Hole(TNode<Number> value, 7921cb0ef41Sopenharmony_ci CheckFloat64HoleMode mode) { 7931cb0ef41Sopenharmony_ci return AddNode<Number>( 7941cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->CheckFloat64Hole(mode, feedback()), 7951cb0ef41Sopenharmony_ci value, effect(), control())); 7961cb0ef41Sopenharmony_ci } 7971cb0ef41Sopenharmony_ci 7981cb0ef41Sopenharmony_ci // May deopt for holey double elements. 7991cb0ef41Sopenharmony_ci TNode<Object> TryConvertHoleToUndefined(TNode<Object> value, 8001cb0ef41Sopenharmony_ci ElementsKind kind) { 8011cb0ef41Sopenharmony_ci DCHECK(IsHoleyElementsKind(kind)); 8021cb0ef41Sopenharmony_ci if (kind == HOLEY_DOUBLE_ELEMENTS) { 8031cb0ef41Sopenharmony_ci // TODO(7409): avoid deopt if not all uses of value are truncated. 8041cb0ef41Sopenharmony_ci TNode<Number> number = TNode<Number>::UncheckedCast(value); 8051cb0ef41Sopenharmony_ci return CheckFloat64Hole(number, CheckFloat64HoleMode::kAllowReturnHole); 8061cb0ef41Sopenharmony_ci } 8071cb0ef41Sopenharmony_ci 8081cb0ef41Sopenharmony_ci return ConvertTaggedHoleToUndefined(value); 8091cb0ef41Sopenharmony_ci } 8101cb0ef41Sopenharmony_ci}; 8111cb0ef41Sopenharmony_ci 8121cb0ef41Sopenharmony_ciclass PromiseBuiltinReducerAssembler : public JSCallReducerAssembler { 8131cb0ef41Sopenharmony_ci public: 8141cb0ef41Sopenharmony_ci PromiseBuiltinReducerAssembler(JSCallReducer* reducer, Node* node, 8151cb0ef41Sopenharmony_ci JSHeapBroker* broker) 8161cb0ef41Sopenharmony_ci : JSCallReducerAssembler(reducer, node), broker_(broker) { 8171cb0ef41Sopenharmony_ci DCHECK_EQ(IrOpcode::kJSConstruct, node->opcode()); 8181cb0ef41Sopenharmony_ci } 8191cb0ef41Sopenharmony_ci 8201cb0ef41Sopenharmony_ci TNode<Object> ReducePromiseConstructor( 8211cb0ef41Sopenharmony_ci const NativeContextRef& native_context); 8221cb0ef41Sopenharmony_ci 8231cb0ef41Sopenharmony_ci int ConstructArity() const { 8241cb0ef41Sopenharmony_ci return JSConstructNode{node_ptr()}.ArgumentCount(); 8251cb0ef41Sopenharmony_ci } 8261cb0ef41Sopenharmony_ci 8271cb0ef41Sopenharmony_ci TNode<Object> TargetInput() const { 8281cb0ef41Sopenharmony_ci return JSConstructNode{node_ptr()}.target(); 8291cb0ef41Sopenharmony_ci } 8301cb0ef41Sopenharmony_ci 8311cb0ef41Sopenharmony_ci TNode<Object> NewTargetInput() const { 8321cb0ef41Sopenharmony_ci return JSConstructNode{node_ptr()}.new_target(); 8331cb0ef41Sopenharmony_ci } 8341cb0ef41Sopenharmony_ci 8351cb0ef41Sopenharmony_ci private: 8361cb0ef41Sopenharmony_ci TNode<JSPromise> CreatePromise(TNode<Context> context) { 8371cb0ef41Sopenharmony_ci return AddNode<JSPromise>( 8381cb0ef41Sopenharmony_ci graph()->NewNode(javascript()->CreatePromise(), context, effect())); 8391cb0ef41Sopenharmony_ci } 8401cb0ef41Sopenharmony_ci 8411cb0ef41Sopenharmony_ci TNode<Context> CreateFunctionContext(const NativeContextRef& native_context, 8421cb0ef41Sopenharmony_ci TNode<Context> outer_context, 8431cb0ef41Sopenharmony_ci int slot_count) { 8441cb0ef41Sopenharmony_ci return AddNode<Context>(graph()->NewNode( 8451cb0ef41Sopenharmony_ci javascript()->CreateFunctionContext( 8461cb0ef41Sopenharmony_ci native_context.scope_info(), 8471cb0ef41Sopenharmony_ci slot_count - Context::MIN_CONTEXT_SLOTS, FUNCTION_SCOPE), 8481cb0ef41Sopenharmony_ci outer_context, effect(), control())); 8491cb0ef41Sopenharmony_ci } 8501cb0ef41Sopenharmony_ci 8511cb0ef41Sopenharmony_ci void StoreContextSlot(TNode<Context> context, size_t slot_index, 8521cb0ef41Sopenharmony_ci TNode<Object> value) { 8531cb0ef41Sopenharmony_ci StoreField(AccessBuilder::ForContextSlot(slot_index), context, value); 8541cb0ef41Sopenharmony_ci } 8551cb0ef41Sopenharmony_ci 8561cb0ef41Sopenharmony_ci TNode<JSFunction> CreateClosureFromBuiltinSharedFunctionInfo( 8571cb0ef41Sopenharmony_ci SharedFunctionInfoRef shared, TNode<Context> context) { 8581cb0ef41Sopenharmony_ci DCHECK(shared.HasBuiltinId()); 8591cb0ef41Sopenharmony_ci Handle<FeedbackCell> feedback_cell = 8601cb0ef41Sopenharmony_ci isolate()->factory()->many_closures_cell(); 8611cb0ef41Sopenharmony_ci Callable const callable = 8621cb0ef41Sopenharmony_ci Builtins::CallableFor(isolate(), shared.builtin_id()); 8631cb0ef41Sopenharmony_ci CodeTRef code = MakeRef(broker_, *callable.code()); 8641cb0ef41Sopenharmony_ci return AddNode<JSFunction>(graph()->NewNode( 8651cb0ef41Sopenharmony_ci javascript()->CreateClosure(shared, code), HeapConstant(feedback_cell), 8661cb0ef41Sopenharmony_ci context, effect(), control())); 8671cb0ef41Sopenharmony_ci } 8681cb0ef41Sopenharmony_ci 8691cb0ef41Sopenharmony_ci void CallPromiseExecutor(TNode<Object> executor, TNode<JSFunction> resolve, 8701cb0ef41Sopenharmony_ci TNode<JSFunction> reject, FrameState frame_state) { 8711cb0ef41Sopenharmony_ci JSConstructNode n(node_ptr()); 8721cb0ef41Sopenharmony_ci const ConstructParameters& p = n.Parameters(); 8731cb0ef41Sopenharmony_ci FeedbackSource no_feedback_source{}; 8741cb0ef41Sopenharmony_ci Node* no_feedback = UndefinedConstant(); 8751cb0ef41Sopenharmony_ci MayThrow(_ { 8761cb0ef41Sopenharmony_ci return AddNode<Object>(graph()->NewNode( 8771cb0ef41Sopenharmony_ci javascript()->Call(JSCallNode::ArityForArgc(2), p.frequency(), 8781cb0ef41Sopenharmony_ci no_feedback_source, 8791cb0ef41Sopenharmony_ci ConvertReceiverMode::kNullOrUndefined), 8801cb0ef41Sopenharmony_ci executor, UndefinedConstant(), resolve, reject, no_feedback, 8811cb0ef41Sopenharmony_ci n.context(), frame_state, effect(), control())); 8821cb0ef41Sopenharmony_ci }); 8831cb0ef41Sopenharmony_ci } 8841cb0ef41Sopenharmony_ci 8851cb0ef41Sopenharmony_ci void CallPromiseReject(TNode<JSFunction> reject, TNode<Object> exception, 8861cb0ef41Sopenharmony_ci FrameState frame_state) { 8871cb0ef41Sopenharmony_ci JSConstructNode n(node_ptr()); 8881cb0ef41Sopenharmony_ci const ConstructParameters& p = n.Parameters(); 8891cb0ef41Sopenharmony_ci FeedbackSource no_feedback_source{}; 8901cb0ef41Sopenharmony_ci Node* no_feedback = UndefinedConstant(); 8911cb0ef41Sopenharmony_ci MayThrow(_ { 8921cb0ef41Sopenharmony_ci return AddNode<Object>(graph()->NewNode( 8931cb0ef41Sopenharmony_ci javascript()->Call(JSCallNode::ArityForArgc(1), p.frequency(), 8941cb0ef41Sopenharmony_ci no_feedback_source, 8951cb0ef41Sopenharmony_ci ConvertReceiverMode::kNullOrUndefined), 8961cb0ef41Sopenharmony_ci reject, UndefinedConstant(), exception, no_feedback, n.context(), 8971cb0ef41Sopenharmony_ci frame_state, effect(), control())); 8981cb0ef41Sopenharmony_ci }); 8991cb0ef41Sopenharmony_ci } 9001cb0ef41Sopenharmony_ci 9011cb0ef41Sopenharmony_ci JSHeapBroker* const broker_; 9021cb0ef41Sopenharmony_ci}; 9031cb0ef41Sopenharmony_ci 9041cb0ef41Sopenharmony_ciclass FastApiCallReducerAssembler : public JSCallReducerAssembler { 9051cb0ef41Sopenharmony_ci public: 9061cb0ef41Sopenharmony_ci FastApiCallReducerAssembler( 9071cb0ef41Sopenharmony_ci JSCallReducer* reducer, Node* node, 9081cb0ef41Sopenharmony_ci const FunctionTemplateInfoRef function_template_info, 9091cb0ef41Sopenharmony_ci const FastApiCallFunctionVector& c_candidate_functions, Node* receiver, 9101cb0ef41Sopenharmony_ci Node* holder, const SharedFunctionInfoRef shared, Node* target, 9111cb0ef41Sopenharmony_ci const int arity, Node* effect) 9121cb0ef41Sopenharmony_ci : JSCallReducerAssembler(reducer, node), 9131cb0ef41Sopenharmony_ci c_candidate_functions_(c_candidate_functions), 9141cb0ef41Sopenharmony_ci function_template_info_(function_template_info), 9151cb0ef41Sopenharmony_ci receiver_(receiver), 9161cb0ef41Sopenharmony_ci holder_(holder), 9171cb0ef41Sopenharmony_ci shared_(shared), 9181cb0ef41Sopenharmony_ci target_(target), 9191cb0ef41Sopenharmony_ci arity_(arity) { 9201cb0ef41Sopenharmony_ci DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); 9211cb0ef41Sopenharmony_ci CHECK_GT(c_candidate_functions.size(), 0); 9221cb0ef41Sopenharmony_ci InitializeEffectControl(effect, NodeProperties::GetControlInput(node)); 9231cb0ef41Sopenharmony_ci } 9241cb0ef41Sopenharmony_ci 9251cb0ef41Sopenharmony_ci TNode<Object> ReduceFastApiCall() { 9261cb0ef41Sopenharmony_ci JSCallNode n(node_ptr()); 9271cb0ef41Sopenharmony_ci 9281cb0ef41Sopenharmony_ci // C arguments include the receiver at index 0. Thus C index 1 corresponds 9291cb0ef41Sopenharmony_ci // to the JS argument 0, etc. 9301cb0ef41Sopenharmony_ci // All functions in c_candidate_functions_ have the same number of 9311cb0ef41Sopenharmony_ci // arguments, so extract c_argument_count from the first function. 9321cb0ef41Sopenharmony_ci const int c_argument_count = 9331cb0ef41Sopenharmony_ci static_cast<int>(c_candidate_functions_[0].signature->ArgumentCount()); 9341cb0ef41Sopenharmony_ci CHECK_GE(c_argument_count, kReceiver); 9351cb0ef41Sopenharmony_ci 9361cb0ef41Sopenharmony_ci int cursor = 0; 9371cb0ef41Sopenharmony_ci base::SmallVector<Node*, kInlineSize> inputs(c_argument_count + arity_ + 9381cb0ef41Sopenharmony_ci kExtraInputsCount); 9391cb0ef41Sopenharmony_ci inputs[cursor++] = n.receiver(); 9401cb0ef41Sopenharmony_ci 9411cb0ef41Sopenharmony_ci // TODO(turbofan): Consider refactoring CFunctionInfo to distinguish 9421cb0ef41Sopenharmony_ci // between receiver and arguments, simplifying this (and related) spots. 9431cb0ef41Sopenharmony_ci int js_args_count = c_argument_count - kReceiver; 9441cb0ef41Sopenharmony_ci for (int i = 0; i < js_args_count; ++i) { 9451cb0ef41Sopenharmony_ci if (i < n.ArgumentCount()) { 9461cb0ef41Sopenharmony_ci inputs[cursor++] = n.Argument(i); 9471cb0ef41Sopenharmony_ci } else { 9481cb0ef41Sopenharmony_ci inputs[cursor++] = UndefinedConstant(); 9491cb0ef41Sopenharmony_ci } 9501cb0ef41Sopenharmony_ci } 9511cb0ef41Sopenharmony_ci 9521cb0ef41Sopenharmony_ci // Here we add the arguments for the slow call, which will be 9531cb0ef41Sopenharmony_ci // reconstructed at a later phase. Those are effectively the same 9541cb0ef41Sopenharmony_ci // arguments as for the fast call, but we want to have them as 9551cb0ef41Sopenharmony_ci // separate inputs, so that SimplifiedLowering can provide the best 9561cb0ef41Sopenharmony_ci // possible UseInfos for each of them. The inputs to FastApiCall 9571cb0ef41Sopenharmony_ci // look like: 9581cb0ef41Sopenharmony_ci // [fast callee, receiver, ... C arguments, 9591cb0ef41Sopenharmony_ci // call code, external constant for function, argc, call handler info data, 9601cb0ef41Sopenharmony_ci // holder, receiver, ... JS arguments, context, new frame state] 9611cb0ef41Sopenharmony_ci CallHandlerInfoRef call_handler_info = *function_template_info_.call_code(); 9621cb0ef41Sopenharmony_ci Callable call_api_callback = CodeFactory::CallApiCallback(isolate()); 9631cb0ef41Sopenharmony_ci CallInterfaceDescriptor cid = call_api_callback.descriptor(); 9641cb0ef41Sopenharmony_ci CallDescriptor* call_descriptor = 9651cb0ef41Sopenharmony_ci Linkage::GetStubCallDescriptor(graph()->zone(), cid, arity_ + kReceiver, 9661cb0ef41Sopenharmony_ci CallDescriptor::kNeedsFrameState); 9671cb0ef41Sopenharmony_ci ApiFunction api_function(call_handler_info.callback()); 9681cb0ef41Sopenharmony_ci ExternalReference function_reference = ExternalReference::Create( 9691cb0ef41Sopenharmony_ci isolate(), &api_function, ExternalReference::DIRECT_API_CALL, 9701cb0ef41Sopenharmony_ci function_template_info_.c_functions().data(), 9711cb0ef41Sopenharmony_ci function_template_info_.c_signatures().data(), 9721cb0ef41Sopenharmony_ci static_cast<unsigned>(function_template_info_.c_functions().size())); 9731cb0ef41Sopenharmony_ci 9741cb0ef41Sopenharmony_ci Node* continuation_frame_state = 9751cb0ef41Sopenharmony_ci CreateGenericLazyDeoptContinuationFrameState( 9761cb0ef41Sopenharmony_ci jsgraph(), shared_, target_, ContextInput(), receiver_, 9771cb0ef41Sopenharmony_ci FrameStateInput()); 9781cb0ef41Sopenharmony_ci 9791cb0ef41Sopenharmony_ci inputs[cursor++] = HeapConstant(call_api_callback.code()); 9801cb0ef41Sopenharmony_ci inputs[cursor++] = ExternalConstant(function_reference); 9811cb0ef41Sopenharmony_ci inputs[cursor++] = NumberConstant(arity_); 9821cb0ef41Sopenharmony_ci inputs[cursor++] = Constant(call_handler_info.data()); 9831cb0ef41Sopenharmony_ci inputs[cursor++] = holder_; 9841cb0ef41Sopenharmony_ci inputs[cursor++] = receiver_; 9851cb0ef41Sopenharmony_ci for (int i = 0; i < arity_; ++i) { 9861cb0ef41Sopenharmony_ci inputs[cursor++] = Argument(i); 9871cb0ef41Sopenharmony_ci } 9881cb0ef41Sopenharmony_ci inputs[cursor++] = ContextInput(); 9891cb0ef41Sopenharmony_ci inputs[cursor++] = continuation_frame_state; 9901cb0ef41Sopenharmony_ci inputs[cursor++] = effect(); 9911cb0ef41Sopenharmony_ci inputs[cursor++] = control(); 9921cb0ef41Sopenharmony_ci 9931cb0ef41Sopenharmony_ci DCHECK_EQ(cursor, c_argument_count + arity_ + kExtraInputsCount); 9941cb0ef41Sopenharmony_ci 9951cb0ef41Sopenharmony_ci return FastApiCall(call_descriptor, inputs.begin(), inputs.size()); 9961cb0ef41Sopenharmony_ci } 9971cb0ef41Sopenharmony_ci 9981cb0ef41Sopenharmony_ci private: 9991cb0ef41Sopenharmony_ci static constexpr int kSlowTarget = 1; 10001cb0ef41Sopenharmony_ci static constexpr int kEffectAndControl = 2; 10011cb0ef41Sopenharmony_ci static constexpr int kContextAndFrameState = 2; 10021cb0ef41Sopenharmony_ci static constexpr int kCallCodeDataAndArgc = 3; 10031cb0ef41Sopenharmony_ci static constexpr int kHolder = 1, kReceiver = 1; 10041cb0ef41Sopenharmony_ci static constexpr int kExtraInputsCount = 10051cb0ef41Sopenharmony_ci kSlowTarget + kEffectAndControl + kContextAndFrameState + 10061cb0ef41Sopenharmony_ci kCallCodeDataAndArgc + kHolder + kReceiver; 10071cb0ef41Sopenharmony_ci static constexpr int kInlineSize = 12; 10081cb0ef41Sopenharmony_ci 10091cb0ef41Sopenharmony_ci TNode<Object> FastApiCall(CallDescriptor* descriptor, Node** inputs, 10101cb0ef41Sopenharmony_ci size_t inputs_size) { 10111cb0ef41Sopenharmony_ci return AddNode<Object>( 10121cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->FastApiCall(c_candidate_functions_, 10131cb0ef41Sopenharmony_ci feedback(), descriptor), 10141cb0ef41Sopenharmony_ci static_cast<int>(inputs_size), inputs)); 10151cb0ef41Sopenharmony_ci } 10161cb0ef41Sopenharmony_ci 10171cb0ef41Sopenharmony_ci const FastApiCallFunctionVector c_candidate_functions_; 10181cb0ef41Sopenharmony_ci const FunctionTemplateInfoRef function_template_info_; 10191cb0ef41Sopenharmony_ci Node* const receiver_; 10201cb0ef41Sopenharmony_ci Node* const holder_; 10211cb0ef41Sopenharmony_ci const SharedFunctionInfoRef shared_; 10221cb0ef41Sopenharmony_ci Node* const target_; 10231cb0ef41Sopenharmony_ci const int arity_; 10241cb0ef41Sopenharmony_ci}; 10251cb0ef41Sopenharmony_ci 10261cb0ef41Sopenharmony_ciTNode<Number> JSCallReducerAssembler::SpeculativeToNumber( 10271cb0ef41Sopenharmony_ci TNode<Object> value, NumberOperationHint hint) { 10281cb0ef41Sopenharmony_ci return AddNode<Number>( 10291cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->SpeculativeToNumber(hint, feedback()), 10301cb0ef41Sopenharmony_ci value, effect(), control())); 10311cb0ef41Sopenharmony_ci} 10321cb0ef41Sopenharmony_ci 10331cb0ef41Sopenharmony_ciTNode<Smi> JSCallReducerAssembler::CheckSmi(TNode<Object> value) { 10341cb0ef41Sopenharmony_ci return AddNode<Smi>(graph()->NewNode(simplified()->CheckSmi(feedback()), 10351cb0ef41Sopenharmony_ci value, effect(), control())); 10361cb0ef41Sopenharmony_ci} 10371cb0ef41Sopenharmony_ci 10381cb0ef41Sopenharmony_ciTNode<String> JSCallReducerAssembler::CheckString(TNode<Object> value) { 10391cb0ef41Sopenharmony_ci return AddNode<String>(graph()->NewNode(simplified()->CheckString(feedback()), 10401cb0ef41Sopenharmony_ci value, effect(), control())); 10411cb0ef41Sopenharmony_ci} 10421cb0ef41Sopenharmony_ci 10431cb0ef41Sopenharmony_ciTNode<Number> JSCallReducerAssembler::CheckBounds(TNode<Number> value, 10441cb0ef41Sopenharmony_ci TNode<Number> limit) { 10451cb0ef41Sopenharmony_ci return AddNode<Number>(graph()->NewNode(simplified()->CheckBounds(feedback()), 10461cb0ef41Sopenharmony_ci value, limit, effect(), control())); 10471cb0ef41Sopenharmony_ci} 10481cb0ef41Sopenharmony_ci 10491cb0ef41Sopenharmony_ciTNode<Smi> JSCallReducerAssembler::TypeGuardUnsignedSmall(TNode<Object> value) { 10501cb0ef41Sopenharmony_ci return TNode<Smi>::UncheckedCast(TypeGuard(Type::UnsignedSmall(), value)); 10511cb0ef41Sopenharmony_ci} 10521cb0ef41Sopenharmony_ci 10531cb0ef41Sopenharmony_ciTNode<Object> JSCallReducerAssembler::TypeGuardNonInternal( 10541cb0ef41Sopenharmony_ci TNode<Object> value) { 10551cb0ef41Sopenharmony_ci return TNode<Object>::UncheckedCast(TypeGuard(Type::NonInternal(), value)); 10561cb0ef41Sopenharmony_ci} 10571cb0ef41Sopenharmony_ci 10581cb0ef41Sopenharmony_ciTNode<Number> JSCallReducerAssembler::TypeGuardFixedArrayLength( 10591cb0ef41Sopenharmony_ci TNode<Object> value) { 10601cb0ef41Sopenharmony_ci DCHECK(TypeCache::Get()->kFixedDoubleArrayLengthType.Is( 10611cb0ef41Sopenharmony_ci TypeCache::Get()->kFixedArrayLengthType)); 10621cb0ef41Sopenharmony_ci return TNode<Number>::UncheckedCast( 10631cb0ef41Sopenharmony_ci TypeGuard(TypeCache::Get()->kFixedArrayLengthType, value)); 10641cb0ef41Sopenharmony_ci} 10651cb0ef41Sopenharmony_ci 10661cb0ef41Sopenharmony_ciTNode<Object> JSCallReducerAssembler::Call4( 10671cb0ef41Sopenharmony_ci const Callable& callable, TNode<Context> context, TNode<Object> arg0, 10681cb0ef41Sopenharmony_ci TNode<Object> arg1, TNode<Object> arg2, TNode<Object> arg3) { 10691cb0ef41Sopenharmony_ci // TODO(jgruber): Make this more generic. Currently it's fitted to its single 10701cb0ef41Sopenharmony_ci // callsite. 10711cb0ef41Sopenharmony_ci CallDescriptor* desc = Linkage::GetStubCallDescriptor( 10721cb0ef41Sopenharmony_ci graph()->zone(), callable.descriptor(), 10731cb0ef41Sopenharmony_ci callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags, 10741cb0ef41Sopenharmony_ci Operator::kEliminatable); 10751cb0ef41Sopenharmony_ci 10761cb0ef41Sopenharmony_ci return TNode<Object>::UncheckedCast(Call(desc, HeapConstant(callable.code()), 10771cb0ef41Sopenharmony_ci arg0, arg1, arg2, arg3, context)); 10781cb0ef41Sopenharmony_ci} 10791cb0ef41Sopenharmony_ci 10801cb0ef41Sopenharmony_ciTNode<Object> JSCallReducerAssembler::JSCall3( 10811cb0ef41Sopenharmony_ci TNode<Object> function, TNode<Object> this_arg, TNode<Object> arg0, 10821cb0ef41Sopenharmony_ci TNode<Object> arg1, TNode<Object> arg2, FrameState frame_state) { 10831cb0ef41Sopenharmony_ci JSCallNode n(node_ptr()); 10841cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 10851cb0ef41Sopenharmony_ci return MayThrow(_ { 10861cb0ef41Sopenharmony_ci return AddNode<Object>(graph()->NewNode( 10871cb0ef41Sopenharmony_ci javascript()->Call(JSCallNode::ArityForArgc(3), p.frequency(), 10881cb0ef41Sopenharmony_ci p.feedback(), ConvertReceiverMode::kAny, 10891cb0ef41Sopenharmony_ci p.speculation_mode(), 10901cb0ef41Sopenharmony_ci CallFeedbackRelation::kUnrelated), 10911cb0ef41Sopenharmony_ci function, this_arg, arg0, arg1, arg2, n.feedback_vector(), 10921cb0ef41Sopenharmony_ci ContextInput(), frame_state, effect(), control())); 10931cb0ef41Sopenharmony_ci }); 10941cb0ef41Sopenharmony_ci} 10951cb0ef41Sopenharmony_ci 10961cb0ef41Sopenharmony_ciTNode<Object> JSCallReducerAssembler::JSCall4( 10971cb0ef41Sopenharmony_ci TNode<Object> function, TNode<Object> this_arg, TNode<Object> arg0, 10981cb0ef41Sopenharmony_ci TNode<Object> arg1, TNode<Object> arg2, TNode<Object> arg3, 10991cb0ef41Sopenharmony_ci FrameState frame_state) { 11001cb0ef41Sopenharmony_ci JSCallNode n(node_ptr()); 11011cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 11021cb0ef41Sopenharmony_ci return MayThrow(_ { 11031cb0ef41Sopenharmony_ci return AddNode<Object>(graph()->NewNode( 11041cb0ef41Sopenharmony_ci javascript()->Call(JSCallNode::ArityForArgc(4), p.frequency(), 11051cb0ef41Sopenharmony_ci p.feedback(), ConvertReceiverMode::kAny, 11061cb0ef41Sopenharmony_ci p.speculation_mode(), 11071cb0ef41Sopenharmony_ci CallFeedbackRelation::kUnrelated), 11081cb0ef41Sopenharmony_ci function, this_arg, arg0, arg1, arg2, arg3, n.feedback_vector(), 11091cb0ef41Sopenharmony_ci ContextInput(), frame_state, effect(), control())); 11101cb0ef41Sopenharmony_ci }); 11111cb0ef41Sopenharmony_ci} 11121cb0ef41Sopenharmony_ci 11131cb0ef41Sopenharmony_ciTNode<Object> JSCallReducerAssembler::JSCallRuntime2( 11141cb0ef41Sopenharmony_ci Runtime::FunctionId function_id, TNode<Object> arg0, TNode<Object> arg1, 11151cb0ef41Sopenharmony_ci FrameState frame_state) { 11161cb0ef41Sopenharmony_ci return MayThrow(_ { 11171cb0ef41Sopenharmony_ci return AddNode<Object>( 11181cb0ef41Sopenharmony_ci graph()->NewNode(javascript()->CallRuntime(function_id, 2), arg0, arg1, 11191cb0ef41Sopenharmony_ci ContextInput(), frame_state, effect(), control())); 11201cb0ef41Sopenharmony_ci }); 11211cb0ef41Sopenharmony_ci} 11221cb0ef41Sopenharmony_ci 11231cb0ef41Sopenharmony_ciTNode<Object> JSCallReducerAssembler::CopyNode() { 11241cb0ef41Sopenharmony_ci return MayThrow(_ { 11251cb0ef41Sopenharmony_ci Node* copy = graph()->CloneNode(node_ptr()); 11261cb0ef41Sopenharmony_ci NodeProperties::ReplaceEffectInput(copy, effect()); 11271cb0ef41Sopenharmony_ci NodeProperties::ReplaceControlInput(copy, control()); 11281cb0ef41Sopenharmony_ci return AddNode<Object>(copy); 11291cb0ef41Sopenharmony_ci }); 11301cb0ef41Sopenharmony_ci} 11311cb0ef41Sopenharmony_ci 11321cb0ef41Sopenharmony_ciTNode<JSArray> JSCallReducerAssembler::CreateArrayNoThrow( 11331cb0ef41Sopenharmony_ci TNode<Object> ctor, TNode<Number> size, FrameState frame_state) { 11341cb0ef41Sopenharmony_ci return AddNode<JSArray>( 11351cb0ef41Sopenharmony_ci graph()->NewNode(javascript()->CreateArray(1, base::nullopt), ctor, ctor, 11361cb0ef41Sopenharmony_ci size, ContextInput(), frame_state, effect(), control())); 11371cb0ef41Sopenharmony_ci} 11381cb0ef41Sopenharmony_ciTNode<JSArray> JSCallReducerAssembler::AllocateEmptyJSArray( 11391cb0ef41Sopenharmony_ci ElementsKind kind, const NativeContextRef& native_context) { 11401cb0ef41Sopenharmony_ci // TODO(jgruber): Port AllocationBuilder to JSGraphAssembler. 11411cb0ef41Sopenharmony_ci MapRef map = native_context.GetInitialJSArrayMap(kind); 11421cb0ef41Sopenharmony_ci 11431cb0ef41Sopenharmony_ci AllocationBuilder ab(jsgraph(), effect(), control()); 11441cb0ef41Sopenharmony_ci ab.Allocate(map.instance_size(), AllocationType::kYoung, Type::Array()); 11451cb0ef41Sopenharmony_ci ab.Store(AccessBuilder::ForMap(), map); 11461cb0ef41Sopenharmony_ci Node* empty_fixed_array = jsgraph()->EmptyFixedArrayConstant(); 11471cb0ef41Sopenharmony_ci ab.Store(AccessBuilder::ForJSObjectPropertiesOrHashKnownPointer(), 11481cb0ef41Sopenharmony_ci empty_fixed_array); 11491cb0ef41Sopenharmony_ci ab.Store(AccessBuilder::ForJSObjectElements(), empty_fixed_array); 11501cb0ef41Sopenharmony_ci ab.Store(AccessBuilder::ForJSArrayLength(kind), jsgraph()->ZeroConstant()); 11511cb0ef41Sopenharmony_ci for (int i = 0; i < map.GetInObjectProperties(); ++i) { 11521cb0ef41Sopenharmony_ci ab.Store(AccessBuilder::ForJSObjectInObjectProperty(map, i), 11531cb0ef41Sopenharmony_ci jsgraph()->UndefinedConstant()); 11541cb0ef41Sopenharmony_ci } 11551cb0ef41Sopenharmony_ci Node* result = ab.Finish(); 11561cb0ef41Sopenharmony_ci InitializeEffectControl(result, control()); 11571cb0ef41Sopenharmony_ci return TNode<JSArray>::UncheckedCast(result); 11581cb0ef41Sopenharmony_ci} 11591cb0ef41Sopenharmony_ci 11601cb0ef41Sopenharmony_ciTNode<Object> JSCallReducerAssembler::ReduceMathUnary(const Operator* op) { 11611cb0ef41Sopenharmony_ci TNode<Object> input = Argument(0); 11621cb0ef41Sopenharmony_ci TNode<Number> input_as_number = SpeculativeToNumber(input); 11631cb0ef41Sopenharmony_ci return TNode<Object>::UncheckedCast(graph()->NewNode(op, input_as_number)); 11641cb0ef41Sopenharmony_ci} 11651cb0ef41Sopenharmony_ci 11661cb0ef41Sopenharmony_ciTNode<Object> JSCallReducerAssembler::ReduceMathBinary(const Operator* op) { 11671cb0ef41Sopenharmony_ci TNode<Object> left = Argument(0); 11681cb0ef41Sopenharmony_ci TNode<Object> right = ArgumentOrNaN(1); 11691cb0ef41Sopenharmony_ci TNode<Number> left_number = SpeculativeToNumber(left); 11701cb0ef41Sopenharmony_ci TNode<Number> right_number = SpeculativeToNumber(right); 11711cb0ef41Sopenharmony_ci return TNode<Object>::UncheckedCast( 11721cb0ef41Sopenharmony_ci graph()->NewNode(op, left_number, right_number)); 11731cb0ef41Sopenharmony_ci} 11741cb0ef41Sopenharmony_ci 11751cb0ef41Sopenharmony_ciTNode<String> JSCallReducerAssembler::ReduceStringPrototypeSubstring() { 11761cb0ef41Sopenharmony_ci TNode<Object> receiver = ReceiverInput(); 11771cb0ef41Sopenharmony_ci TNode<Object> start = Argument(0); 11781cb0ef41Sopenharmony_ci TNode<Object> end = ArgumentOrUndefined(1); 11791cb0ef41Sopenharmony_ci 11801cb0ef41Sopenharmony_ci TNode<String> receiver_string = CheckString(receiver); 11811cb0ef41Sopenharmony_ci TNode<Number> start_smi = CheckSmi(start); 11821cb0ef41Sopenharmony_ci 11831cb0ef41Sopenharmony_ci TNode<Number> length = StringLength(receiver_string); 11841cb0ef41Sopenharmony_ci 11851cb0ef41Sopenharmony_ci TNode<Number> end_smi = SelectIf<Number>(IsUndefined(end)) 11861cb0ef41Sopenharmony_ci .Then(_ { return length; }) 11871cb0ef41Sopenharmony_ci .Else(_ { return CheckSmi(end); }) 11881cb0ef41Sopenharmony_ci .ExpectFalse() 11891cb0ef41Sopenharmony_ci .Value(); 11901cb0ef41Sopenharmony_ci 11911cb0ef41Sopenharmony_ci TNode<Number> zero = TNode<Number>::UncheckedCast(ZeroConstant()); 11921cb0ef41Sopenharmony_ci TNode<Number> finalStart = NumberMin(NumberMax(start_smi, zero), length); 11931cb0ef41Sopenharmony_ci TNode<Number> finalEnd = NumberMin(NumberMax(end_smi, zero), length); 11941cb0ef41Sopenharmony_ci TNode<Number> from = NumberMin(finalStart, finalEnd); 11951cb0ef41Sopenharmony_ci TNode<Number> to = NumberMax(finalStart, finalEnd); 11961cb0ef41Sopenharmony_ci 11971cb0ef41Sopenharmony_ci return StringSubstring(receiver_string, from, to); 11981cb0ef41Sopenharmony_ci} 11991cb0ef41Sopenharmony_ci 12001cb0ef41Sopenharmony_ciTNode<Boolean> JSCallReducerAssembler::ReduceStringPrototypeStartsWith( 12011cb0ef41Sopenharmony_ci const StringRef& search_element_string) { 12021cb0ef41Sopenharmony_ci TNode<Object> receiver = ReceiverInput(); 12031cb0ef41Sopenharmony_ci TNode<Object> start = ArgumentOrZero(1); 12041cb0ef41Sopenharmony_ci 12051cb0ef41Sopenharmony_ci TNode<String> receiver_string = CheckString(receiver); 12061cb0ef41Sopenharmony_ci TNode<Smi> start_smi = CheckSmi(start); 12071cb0ef41Sopenharmony_ci TNode<Number> length = StringLength(receiver_string); 12081cb0ef41Sopenharmony_ci 12091cb0ef41Sopenharmony_ci TNode<Number> zero = ZeroConstant(); 12101cb0ef41Sopenharmony_ci TNode<Number> clamped_start = NumberMin(NumberMax(start_smi, zero), length); 12111cb0ef41Sopenharmony_ci 12121cb0ef41Sopenharmony_ci int search_string_length = search_element_string.length().value(); 12131cb0ef41Sopenharmony_ci DCHECK(search_string_length <= JSCallReducer::kMaxInlineMatchSequence); 12141cb0ef41Sopenharmony_ci 12151cb0ef41Sopenharmony_ci auto out = MakeLabel(MachineRepresentation::kTagged); 12161cb0ef41Sopenharmony_ci 12171cb0ef41Sopenharmony_ci auto search_string_too_long = 12181cb0ef41Sopenharmony_ci NumberLessThan(NumberSubtract(length, clamped_start), 12191cb0ef41Sopenharmony_ci NumberConstant(search_string_length)); 12201cb0ef41Sopenharmony_ci 12211cb0ef41Sopenharmony_ci GotoIf(search_string_too_long, &out, BranchHint::kFalse, FalseConstant()); 12221cb0ef41Sopenharmony_ci 12231cb0ef41Sopenharmony_ci STATIC_ASSERT(String::kMaxLength <= kSmiMaxValue); 12241cb0ef41Sopenharmony_ci 12251cb0ef41Sopenharmony_ci for (int i = 0; i < search_string_length; i++) { 12261cb0ef41Sopenharmony_ci TNode<Number> k = NumberConstant(i); 12271cb0ef41Sopenharmony_ci TNode<Number> receiver_string_position = TNode<Number>::UncheckedCast( 12281cb0ef41Sopenharmony_ci TypeGuard(Type::UnsignedSmall(), NumberAdd(k, clamped_start))); 12291cb0ef41Sopenharmony_ci Node* receiver_string_char = 12301cb0ef41Sopenharmony_ci StringCharCodeAt(receiver_string, receiver_string_position); 12311cb0ef41Sopenharmony_ci Node* search_string_char = 12321cb0ef41Sopenharmony_ci jsgraph()->Constant(search_element_string.GetChar(i).value()); 12331cb0ef41Sopenharmony_ci auto is_equal = graph()->NewNode(simplified()->NumberEqual(), 12341cb0ef41Sopenharmony_ci search_string_char, receiver_string_char); 12351cb0ef41Sopenharmony_ci GotoIfNot(is_equal, &out, FalseConstant()); 12361cb0ef41Sopenharmony_ci } 12371cb0ef41Sopenharmony_ci 12381cb0ef41Sopenharmony_ci Goto(&out, TrueConstant()); 12391cb0ef41Sopenharmony_ci 12401cb0ef41Sopenharmony_ci Bind(&out); 12411cb0ef41Sopenharmony_ci return out.PhiAt<Boolean>(0); 12421cb0ef41Sopenharmony_ci} 12431cb0ef41Sopenharmony_ci 12441cb0ef41Sopenharmony_ciTNode<Boolean> JSCallReducerAssembler::ReduceStringPrototypeStartsWith() { 12451cb0ef41Sopenharmony_ci TNode<Object> receiver = ReceiverInput(); 12461cb0ef41Sopenharmony_ci TNode<Object> search_element = ArgumentOrUndefined(0); 12471cb0ef41Sopenharmony_ci TNode<Object> start = ArgumentOrZero(1); 12481cb0ef41Sopenharmony_ci 12491cb0ef41Sopenharmony_ci TNode<String> receiver_string = CheckString(receiver); 12501cb0ef41Sopenharmony_ci TNode<String> search_string = CheckString(search_element); 12511cb0ef41Sopenharmony_ci TNode<Smi> start_smi = CheckSmi(start); 12521cb0ef41Sopenharmony_ci TNode<Number> length = StringLength(receiver_string); 12531cb0ef41Sopenharmony_ci 12541cb0ef41Sopenharmony_ci TNode<Number> zero = ZeroConstant(); 12551cb0ef41Sopenharmony_ci TNode<Number> clamped_start = NumberMin(NumberMax(start_smi, zero), length); 12561cb0ef41Sopenharmony_ci 12571cb0ef41Sopenharmony_ci TNode<Number> search_string_length = StringLength(search_string); 12581cb0ef41Sopenharmony_ci 12591cb0ef41Sopenharmony_ci auto out = MakeLabel(MachineRepresentation::kTagged); 12601cb0ef41Sopenharmony_ci 12611cb0ef41Sopenharmony_ci auto search_string_too_long = NumberLessThan( 12621cb0ef41Sopenharmony_ci NumberSubtract(length, clamped_start), search_string_length); 12631cb0ef41Sopenharmony_ci 12641cb0ef41Sopenharmony_ci GotoIf(search_string_too_long, &out, BranchHint::kFalse, FalseConstant()); 12651cb0ef41Sopenharmony_ci 12661cb0ef41Sopenharmony_ci STATIC_ASSERT(String::kMaxLength <= kSmiMaxValue); 12671cb0ef41Sopenharmony_ci 12681cb0ef41Sopenharmony_ci ForZeroUntil(search_string_length).Do([&](TNode<Number> k) { 12691cb0ef41Sopenharmony_ci TNode<Number> receiver_string_position = TNode<Number>::UncheckedCast( 12701cb0ef41Sopenharmony_ci TypeGuard(Type::UnsignedSmall(), NumberAdd(k, clamped_start))); 12711cb0ef41Sopenharmony_ci Node* receiver_string_char = 12721cb0ef41Sopenharmony_ci StringCharCodeAt(receiver_string, receiver_string_position); 12731cb0ef41Sopenharmony_ci Node* search_string_char = StringCharCodeAt(search_string, k); 12741cb0ef41Sopenharmony_ci auto is_equal = graph()->NewNode(simplified()->NumberEqual(), 12751cb0ef41Sopenharmony_ci receiver_string_char, search_string_char); 12761cb0ef41Sopenharmony_ci GotoIfNot(is_equal, &out, FalseConstant()); 12771cb0ef41Sopenharmony_ci }); 12781cb0ef41Sopenharmony_ci 12791cb0ef41Sopenharmony_ci Goto(&out, TrueConstant()); 12801cb0ef41Sopenharmony_ci 12811cb0ef41Sopenharmony_ci Bind(&out); 12821cb0ef41Sopenharmony_ci return out.PhiAt<Boolean>(0); 12831cb0ef41Sopenharmony_ci} 12841cb0ef41Sopenharmony_ci 12851cb0ef41Sopenharmony_ciTNode<String> JSCallReducerAssembler::ReduceStringPrototypeSlice() { 12861cb0ef41Sopenharmony_ci TNode<Object> receiver = ReceiverInput(); 12871cb0ef41Sopenharmony_ci TNode<Object> start = Argument(0); 12881cb0ef41Sopenharmony_ci TNode<Object> end = ArgumentOrUndefined(1); 12891cb0ef41Sopenharmony_ci 12901cb0ef41Sopenharmony_ci TNode<String> receiver_string = CheckString(receiver); 12911cb0ef41Sopenharmony_ci TNode<Number> start_smi = CheckSmi(start); 12921cb0ef41Sopenharmony_ci 12931cb0ef41Sopenharmony_ci TNode<Number> length = StringLength(receiver_string); 12941cb0ef41Sopenharmony_ci 12951cb0ef41Sopenharmony_ci TNode<Number> end_smi = SelectIf<Number>(IsUndefined(end)) 12961cb0ef41Sopenharmony_ci .Then(_ { return length; }) 12971cb0ef41Sopenharmony_ci .Else(_ { return CheckSmi(end); }) 12981cb0ef41Sopenharmony_ci .ExpectFalse() 12991cb0ef41Sopenharmony_ci .Value(); 13001cb0ef41Sopenharmony_ci 13011cb0ef41Sopenharmony_ci TNode<Number> zero = TNode<Number>::UncheckedCast(ZeroConstant()); 13021cb0ef41Sopenharmony_ci TNode<Number> from_untyped = 13031cb0ef41Sopenharmony_ci SelectIf<Number>(NumberLessThan(start_smi, zero)) 13041cb0ef41Sopenharmony_ci .Then(_ { return NumberMax(NumberAdd(length, start_smi), zero); }) 13051cb0ef41Sopenharmony_ci .Else(_ { return NumberMin(start_smi, length); }) 13061cb0ef41Sopenharmony_ci .ExpectFalse() 13071cb0ef41Sopenharmony_ci .Value(); 13081cb0ef41Sopenharmony_ci // {from} is always in non-negative Smi range, but our typer cannot figure 13091cb0ef41Sopenharmony_ci // that out yet. 13101cb0ef41Sopenharmony_ci TNode<Smi> from = TypeGuardUnsignedSmall(from_untyped); 13111cb0ef41Sopenharmony_ci 13121cb0ef41Sopenharmony_ci TNode<Number> to_untyped = 13131cb0ef41Sopenharmony_ci SelectIf<Number>(NumberLessThan(end_smi, zero)) 13141cb0ef41Sopenharmony_ci .Then(_ { return NumberMax(NumberAdd(length, end_smi), zero); }) 13151cb0ef41Sopenharmony_ci .Else(_ { return NumberMin(end_smi, length); }) 13161cb0ef41Sopenharmony_ci .ExpectFalse() 13171cb0ef41Sopenharmony_ci .Value(); 13181cb0ef41Sopenharmony_ci // {to} is always in non-negative Smi range, but our typer cannot figure that 13191cb0ef41Sopenharmony_ci // out yet. 13201cb0ef41Sopenharmony_ci TNode<Smi> to = TypeGuardUnsignedSmall(to_untyped); 13211cb0ef41Sopenharmony_ci 13221cb0ef41Sopenharmony_ci return SelectIf<String>(NumberLessThan(from, to)) 13231cb0ef41Sopenharmony_ci .Then(_ { return StringSubstring(receiver_string, from, to); }) 13241cb0ef41Sopenharmony_ci .Else(_ { return EmptyStringConstant(); }) 13251cb0ef41Sopenharmony_ci .ExpectTrue() 13261cb0ef41Sopenharmony_ci .Value(); 13271cb0ef41Sopenharmony_ci} 13281cb0ef41Sopenharmony_ci 13291cb0ef41Sopenharmony_cinamespace { 13301cb0ef41Sopenharmony_ci 13311cb0ef41Sopenharmony_cistruct ForEachFrameStateParams { 13321cb0ef41Sopenharmony_ci JSGraph* jsgraph; 13331cb0ef41Sopenharmony_ci SharedFunctionInfoRef shared; 13341cb0ef41Sopenharmony_ci TNode<Context> context; 13351cb0ef41Sopenharmony_ci TNode<Object> target; 13361cb0ef41Sopenharmony_ci FrameState outer_frame_state; 13371cb0ef41Sopenharmony_ci TNode<Object> receiver; 13381cb0ef41Sopenharmony_ci TNode<Object> callback; 13391cb0ef41Sopenharmony_ci TNode<Object> this_arg; 13401cb0ef41Sopenharmony_ci TNode<Object> original_length; 13411cb0ef41Sopenharmony_ci}; 13421cb0ef41Sopenharmony_ci 13431cb0ef41Sopenharmony_ciFrameState ForEachLoopLazyFrameState(const ForEachFrameStateParams& params, 13441cb0ef41Sopenharmony_ci TNode<Object> k) { 13451cb0ef41Sopenharmony_ci Builtin builtin = Builtin::kArrayForEachLoopLazyDeoptContinuation; 13461cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {params.receiver, params.callback, 13471cb0ef41Sopenharmony_ci params.this_arg, k, params.original_length}; 13481cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 13491cb0ef41Sopenharmony_ci params.jsgraph, params.shared, builtin, params.target, params.context, 13501cb0ef41Sopenharmony_ci checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, 13511cb0ef41Sopenharmony_ci ContinuationFrameStateMode::LAZY); 13521cb0ef41Sopenharmony_ci} 13531cb0ef41Sopenharmony_ci 13541cb0ef41Sopenharmony_ciFrameState ForEachLoopEagerFrameState(const ForEachFrameStateParams& params, 13551cb0ef41Sopenharmony_ci TNode<Object> k) { 13561cb0ef41Sopenharmony_ci Builtin builtin = Builtin::kArrayForEachLoopEagerDeoptContinuation; 13571cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {params.receiver, params.callback, 13581cb0ef41Sopenharmony_ci params.this_arg, k, params.original_length}; 13591cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 13601cb0ef41Sopenharmony_ci params.jsgraph, params.shared, builtin, params.target, params.context, 13611cb0ef41Sopenharmony_ci checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, 13621cb0ef41Sopenharmony_ci ContinuationFrameStateMode::EAGER); 13631cb0ef41Sopenharmony_ci} 13641cb0ef41Sopenharmony_ci 13651cb0ef41Sopenharmony_ci} // namespace 13661cb0ef41Sopenharmony_ci 13671cb0ef41Sopenharmony_ciTNode<Object> 13681cb0ef41Sopenharmony_ciIteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeForEach( 13691cb0ef41Sopenharmony_ci MapInference* inference, const bool has_stability_dependency, 13701cb0ef41Sopenharmony_ci ElementsKind kind, const SharedFunctionInfoRef& shared) { 13711cb0ef41Sopenharmony_ci FrameState outer_frame_state = FrameStateInput(); 13721cb0ef41Sopenharmony_ci TNode<Context> context = ContextInput(); 13731cb0ef41Sopenharmony_ci TNode<Object> target = TargetInput(); 13741cb0ef41Sopenharmony_ci TNode<JSArray> receiver = ReceiverInputAs<JSArray>(); 13751cb0ef41Sopenharmony_ci TNode<Object> fncallback = ArgumentOrUndefined(0); 13761cb0ef41Sopenharmony_ci TNode<Object> this_arg = ArgumentOrUndefined(1); 13771cb0ef41Sopenharmony_ci 13781cb0ef41Sopenharmony_ci TNode<Number> original_length = LoadJSArrayLength(receiver, kind); 13791cb0ef41Sopenharmony_ci 13801cb0ef41Sopenharmony_ci ForEachFrameStateParams frame_state_params{ 13811cb0ef41Sopenharmony_ci jsgraph(), shared, context, target, outer_frame_state, 13821cb0ef41Sopenharmony_ci receiver, fncallback, this_arg, original_length}; 13831cb0ef41Sopenharmony_ci 13841cb0ef41Sopenharmony_ci ThrowIfNotCallable(fncallback, ForEachLoopLazyFrameState(frame_state_params, 13851cb0ef41Sopenharmony_ci ZeroConstant())); 13861cb0ef41Sopenharmony_ci 13871cb0ef41Sopenharmony_ci ForZeroUntil(original_length).Do([&](TNode<Number> k) { 13881cb0ef41Sopenharmony_ci Checkpoint(ForEachLoopEagerFrameState(frame_state_params, k)); 13891cb0ef41Sopenharmony_ci 13901cb0ef41Sopenharmony_ci // Deopt if the map has changed during the iteration. 13911cb0ef41Sopenharmony_ci MaybeInsertMapChecks(inference, has_stability_dependency); 13921cb0ef41Sopenharmony_ci 13931cb0ef41Sopenharmony_ci TNode<Object> element; 13941cb0ef41Sopenharmony_ci std::tie(k, element) = SafeLoadElement(kind, receiver, k); 13951cb0ef41Sopenharmony_ci 13961cb0ef41Sopenharmony_ci auto continue_label = MakeLabel(); 13971cb0ef41Sopenharmony_ci element = MaybeSkipHole(element, kind, &continue_label); 13981cb0ef41Sopenharmony_ci 13991cb0ef41Sopenharmony_ci TNode<Number> next_k = NumberAdd(k, OneConstant()); 14001cb0ef41Sopenharmony_ci JSCall3(fncallback, this_arg, element, k, receiver, 14011cb0ef41Sopenharmony_ci ForEachLoopLazyFrameState(frame_state_params, next_k)); 14021cb0ef41Sopenharmony_ci 14031cb0ef41Sopenharmony_ci Goto(&continue_label); 14041cb0ef41Sopenharmony_ci Bind(&continue_label); 14051cb0ef41Sopenharmony_ci }); 14061cb0ef41Sopenharmony_ci 14071cb0ef41Sopenharmony_ci return UndefinedConstant(); 14081cb0ef41Sopenharmony_ci} 14091cb0ef41Sopenharmony_ci 14101cb0ef41Sopenharmony_cinamespace { 14111cb0ef41Sopenharmony_ci 14121cb0ef41Sopenharmony_cistruct ReduceFrameStateParams { 14131cb0ef41Sopenharmony_ci JSGraph* jsgraph; 14141cb0ef41Sopenharmony_ci SharedFunctionInfoRef shared; 14151cb0ef41Sopenharmony_ci ArrayReduceDirection direction; 14161cb0ef41Sopenharmony_ci TNode<Context> context; 14171cb0ef41Sopenharmony_ci TNode<Object> target; 14181cb0ef41Sopenharmony_ci FrameState outer_frame_state; 14191cb0ef41Sopenharmony_ci}; 14201cb0ef41Sopenharmony_ci 14211cb0ef41Sopenharmony_ciFrameState ReducePreLoopLazyFrameState(const ReduceFrameStateParams& params, 14221cb0ef41Sopenharmony_ci TNode<Object> receiver, 14231cb0ef41Sopenharmony_ci TNode<Object> callback, TNode<Object> k, 14241cb0ef41Sopenharmony_ci TNode<Number> original_length) { 14251cb0ef41Sopenharmony_ci Builtin builtin = (params.direction == ArrayReduceDirection::kLeft) 14261cb0ef41Sopenharmony_ci ? Builtin::kArrayReduceLoopLazyDeoptContinuation 14271cb0ef41Sopenharmony_ci : Builtin::kArrayReduceRightLoopLazyDeoptContinuation; 14281cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {receiver, callback, k, original_length}; 14291cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 14301cb0ef41Sopenharmony_ci params.jsgraph, params.shared, builtin, params.target, params.context, 14311cb0ef41Sopenharmony_ci checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, 14321cb0ef41Sopenharmony_ci ContinuationFrameStateMode::LAZY); 14331cb0ef41Sopenharmony_ci} 14341cb0ef41Sopenharmony_ci 14351cb0ef41Sopenharmony_ciFrameState ReducePreLoopEagerFrameState(const ReduceFrameStateParams& params, 14361cb0ef41Sopenharmony_ci TNode<Object> receiver, 14371cb0ef41Sopenharmony_ci TNode<Object> callback, 14381cb0ef41Sopenharmony_ci TNode<Number> original_length) { 14391cb0ef41Sopenharmony_ci Builtin builtin = 14401cb0ef41Sopenharmony_ci (params.direction == ArrayReduceDirection::kLeft) 14411cb0ef41Sopenharmony_ci ? Builtin::kArrayReducePreLoopEagerDeoptContinuation 14421cb0ef41Sopenharmony_ci : Builtin::kArrayReduceRightPreLoopEagerDeoptContinuation; 14431cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {receiver, callback, original_length}; 14441cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 14451cb0ef41Sopenharmony_ci params.jsgraph, params.shared, builtin, params.target, params.context, 14461cb0ef41Sopenharmony_ci checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, 14471cb0ef41Sopenharmony_ci ContinuationFrameStateMode::EAGER); 14481cb0ef41Sopenharmony_ci} 14491cb0ef41Sopenharmony_ci 14501cb0ef41Sopenharmony_ciFrameState ReduceLoopLazyFrameState(const ReduceFrameStateParams& params, 14511cb0ef41Sopenharmony_ci TNode<Object> receiver, 14521cb0ef41Sopenharmony_ci TNode<Object> callback, TNode<Object> k, 14531cb0ef41Sopenharmony_ci TNode<Number> original_length) { 14541cb0ef41Sopenharmony_ci Builtin builtin = (params.direction == ArrayReduceDirection::kLeft) 14551cb0ef41Sopenharmony_ci ? Builtin::kArrayReduceLoopLazyDeoptContinuation 14561cb0ef41Sopenharmony_ci : Builtin::kArrayReduceRightLoopLazyDeoptContinuation; 14571cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {receiver, callback, k, original_length}; 14581cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 14591cb0ef41Sopenharmony_ci params.jsgraph, params.shared, builtin, params.target, params.context, 14601cb0ef41Sopenharmony_ci checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, 14611cb0ef41Sopenharmony_ci ContinuationFrameStateMode::LAZY); 14621cb0ef41Sopenharmony_ci} 14631cb0ef41Sopenharmony_ci 14641cb0ef41Sopenharmony_ciFrameState ReduceLoopEagerFrameState(const ReduceFrameStateParams& params, 14651cb0ef41Sopenharmony_ci TNode<Object> receiver, 14661cb0ef41Sopenharmony_ci TNode<Object> callback, TNode<Object> k, 14671cb0ef41Sopenharmony_ci TNode<Number> original_length, 14681cb0ef41Sopenharmony_ci TNode<Object> accumulator) { 14691cb0ef41Sopenharmony_ci Builtin builtin = (params.direction == ArrayReduceDirection::kLeft) 14701cb0ef41Sopenharmony_ci ? Builtin::kArrayReduceLoopEagerDeoptContinuation 14711cb0ef41Sopenharmony_ci : Builtin::kArrayReduceRightLoopEagerDeoptContinuation; 14721cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {receiver, callback, k, original_length, 14731cb0ef41Sopenharmony_ci accumulator}; 14741cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 14751cb0ef41Sopenharmony_ci params.jsgraph, params.shared, builtin, params.target, params.context, 14761cb0ef41Sopenharmony_ci checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, 14771cb0ef41Sopenharmony_ci ContinuationFrameStateMode::EAGER); 14781cb0ef41Sopenharmony_ci} 14791cb0ef41Sopenharmony_ci 14801cb0ef41Sopenharmony_ci} // namespace 14811cb0ef41Sopenharmony_ci 14821cb0ef41Sopenharmony_ciTNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeReduce( 14831cb0ef41Sopenharmony_ci MapInference* inference, const bool has_stability_dependency, 14841cb0ef41Sopenharmony_ci ElementsKind kind, ArrayReduceDirection direction, 14851cb0ef41Sopenharmony_ci const SharedFunctionInfoRef& shared) { 14861cb0ef41Sopenharmony_ci FrameState outer_frame_state = FrameStateInput(); 14871cb0ef41Sopenharmony_ci TNode<Context> context = ContextInput(); 14881cb0ef41Sopenharmony_ci TNode<Object> target = TargetInput(); 14891cb0ef41Sopenharmony_ci TNode<JSArray> receiver = ReceiverInputAs<JSArray>(); 14901cb0ef41Sopenharmony_ci TNode<Object> fncallback = ArgumentOrUndefined(0); 14911cb0ef41Sopenharmony_ci 14921cb0ef41Sopenharmony_ci ReduceFrameStateParams frame_state_params{ 14931cb0ef41Sopenharmony_ci jsgraph(), shared, direction, context, target, outer_frame_state}; 14941cb0ef41Sopenharmony_ci 14951cb0ef41Sopenharmony_ci TNode<Number> original_length = LoadJSArrayLength(receiver, kind); 14961cb0ef41Sopenharmony_ci 14971cb0ef41Sopenharmony_ci // Set up variable behavior depending on the reduction kind (left/right). 14981cb0ef41Sopenharmony_ci TNode<Number> k; 14991cb0ef41Sopenharmony_ci StepFunction1 step; 15001cb0ef41Sopenharmony_ci ConditionFunction1 cond; 15011cb0ef41Sopenharmony_ci TNode<Number> zero = ZeroConstant(); 15021cb0ef41Sopenharmony_ci TNode<Number> one = OneConstant(); 15031cb0ef41Sopenharmony_ci if (direction == ArrayReduceDirection::kLeft) { 15041cb0ef41Sopenharmony_ci k = zero; 15051cb0ef41Sopenharmony_ci step = [&](TNode<Number> i) { return NumberAdd(i, one); }; 15061cb0ef41Sopenharmony_ci cond = [&](TNode<Number> i) { return NumberLessThan(i, original_length); }; 15071cb0ef41Sopenharmony_ci } else { 15081cb0ef41Sopenharmony_ci k = NumberSubtract(original_length, one); 15091cb0ef41Sopenharmony_ci step = [&](TNode<Number> i) { return NumberSubtract(i, one); }; 15101cb0ef41Sopenharmony_ci cond = [&](TNode<Number> i) { return NumberLessThanOrEqual(zero, i); }; 15111cb0ef41Sopenharmony_ci } 15121cb0ef41Sopenharmony_ci 15131cb0ef41Sopenharmony_ci ThrowIfNotCallable( 15141cb0ef41Sopenharmony_ci fncallback, ReducePreLoopLazyFrameState(frame_state_params, receiver, 15151cb0ef41Sopenharmony_ci fncallback, k, original_length)); 15161cb0ef41Sopenharmony_ci 15171cb0ef41Sopenharmony_ci // Set initial accumulator value. 15181cb0ef41Sopenharmony_ci TNode<Object> accumulator; 15191cb0ef41Sopenharmony_ci if (ArgumentCount() > 1) { 15201cb0ef41Sopenharmony_ci accumulator = Argument(1); // Initial value specified by the user. 15211cb0ef41Sopenharmony_ci } else { 15221cb0ef41Sopenharmony_ci // The initial value was not specified by the user. In this case, the first 15231cb0ef41Sopenharmony_ci // (or last in the case of reduceRight) non-holey value of the array is 15241cb0ef41Sopenharmony_ci // used. Loop until we find it. If not found, trigger a deopt. 15251cb0ef41Sopenharmony_ci // TODO(jgruber): The deopt does not seem necessary. Instead we could simply 15261cb0ef41Sopenharmony_ci // throw the TypeError here from optimized code. 15271cb0ef41Sopenharmony_ci auto found_initial_element = MakeLabel(MachineRepresentation::kTagged, 15281cb0ef41Sopenharmony_ci MachineRepresentation::kTagged); 15291cb0ef41Sopenharmony_ci Forever(k, step).Do([&](TNode<Number> k) { 15301cb0ef41Sopenharmony_ci Checkpoint(ReducePreLoopEagerFrameState(frame_state_params, receiver, 15311cb0ef41Sopenharmony_ci fncallback, original_length)); 15321cb0ef41Sopenharmony_ci CheckIf(cond(k), DeoptimizeReason::kNoInitialElement); 15331cb0ef41Sopenharmony_ci 15341cb0ef41Sopenharmony_ci TNode<Object> element; 15351cb0ef41Sopenharmony_ci std::tie(k, element) = SafeLoadElement(kind, receiver, k); 15361cb0ef41Sopenharmony_ci 15371cb0ef41Sopenharmony_ci auto continue_label = MakeLabel(); 15381cb0ef41Sopenharmony_ci GotoIf(HoleCheck(kind, element), &continue_label); 15391cb0ef41Sopenharmony_ci Goto(&found_initial_element, k, TypeGuardNonInternal(element)); 15401cb0ef41Sopenharmony_ci 15411cb0ef41Sopenharmony_ci Bind(&continue_label); 15421cb0ef41Sopenharmony_ci }); 15431cb0ef41Sopenharmony_ci Unreachable(); // The loop is exited either by deopt or a jump to below. 15441cb0ef41Sopenharmony_ci 15451cb0ef41Sopenharmony_ci // TODO(jgruber): This manual fiddling with blocks could be avoided by 15461cb0ef41Sopenharmony_ci // implementing a `break` mechanic for loop builders. 15471cb0ef41Sopenharmony_ci Bind(&found_initial_element); 15481cb0ef41Sopenharmony_ci k = step(found_initial_element.PhiAt<Number>(0)); 15491cb0ef41Sopenharmony_ci accumulator = found_initial_element.PhiAt<Object>(1); 15501cb0ef41Sopenharmony_ci } 15511cb0ef41Sopenharmony_ci 15521cb0ef41Sopenharmony_ci TNode<Object> result = 15531cb0ef41Sopenharmony_ci For1(k, cond, step, accumulator) 15541cb0ef41Sopenharmony_ci .Do([&](TNode<Number> k, TNode<Object>* accumulator) { 15551cb0ef41Sopenharmony_ci Checkpoint(ReduceLoopEagerFrameState(frame_state_params, receiver, 15561cb0ef41Sopenharmony_ci fncallback, k, original_length, 15571cb0ef41Sopenharmony_ci *accumulator)); 15581cb0ef41Sopenharmony_ci 15591cb0ef41Sopenharmony_ci // Deopt if the map has changed during the iteration. 15601cb0ef41Sopenharmony_ci MaybeInsertMapChecks(inference, has_stability_dependency); 15611cb0ef41Sopenharmony_ci 15621cb0ef41Sopenharmony_ci TNode<Object> element; 15631cb0ef41Sopenharmony_ci std::tie(k, element) = SafeLoadElement(kind, receiver, k); 15641cb0ef41Sopenharmony_ci 15651cb0ef41Sopenharmony_ci auto continue_label = MakeLabel(MachineRepresentation::kTagged); 15661cb0ef41Sopenharmony_ci element = 15671cb0ef41Sopenharmony_ci MaybeSkipHole(element, kind, &continue_label, *accumulator); 15681cb0ef41Sopenharmony_ci 15691cb0ef41Sopenharmony_ci TNode<Number> next_k = step(k); 15701cb0ef41Sopenharmony_ci TNode<Object> next_accumulator = JSCall4( 15711cb0ef41Sopenharmony_ci fncallback, UndefinedConstant(), *accumulator, element, k, 15721cb0ef41Sopenharmony_ci receiver, 15731cb0ef41Sopenharmony_ci ReduceLoopLazyFrameState(frame_state_params, receiver, 15741cb0ef41Sopenharmony_ci fncallback, next_k, original_length)); 15751cb0ef41Sopenharmony_ci Goto(&continue_label, next_accumulator); 15761cb0ef41Sopenharmony_ci 15771cb0ef41Sopenharmony_ci Bind(&continue_label); 15781cb0ef41Sopenharmony_ci *accumulator = continue_label.PhiAt<Object>(0); 15791cb0ef41Sopenharmony_ci }) 15801cb0ef41Sopenharmony_ci .Value(); 15811cb0ef41Sopenharmony_ci 15821cb0ef41Sopenharmony_ci return result; 15831cb0ef41Sopenharmony_ci} 15841cb0ef41Sopenharmony_ci 15851cb0ef41Sopenharmony_cinamespace { 15861cb0ef41Sopenharmony_ci 15871cb0ef41Sopenharmony_cistruct MapFrameStateParams { 15881cb0ef41Sopenharmony_ci JSGraph* jsgraph; 15891cb0ef41Sopenharmony_ci SharedFunctionInfoRef shared; 15901cb0ef41Sopenharmony_ci TNode<Context> context; 15911cb0ef41Sopenharmony_ci TNode<Object> target; 15921cb0ef41Sopenharmony_ci FrameState outer_frame_state; 15931cb0ef41Sopenharmony_ci TNode<Object> receiver; 15941cb0ef41Sopenharmony_ci TNode<Object> callback; 15951cb0ef41Sopenharmony_ci TNode<Object> this_arg; 15961cb0ef41Sopenharmony_ci base::Optional<TNode<JSArray>> a; 15971cb0ef41Sopenharmony_ci TNode<Object> original_length; 15981cb0ef41Sopenharmony_ci}; 15991cb0ef41Sopenharmony_ci 16001cb0ef41Sopenharmony_ciFrameState MapPreLoopLazyFrameState(const MapFrameStateParams& params) { 16011cb0ef41Sopenharmony_ci DCHECK(!params.a); 16021cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {params.receiver, params.callback, 16031cb0ef41Sopenharmony_ci params.this_arg, params.original_length}; 16041cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 16051cb0ef41Sopenharmony_ci params.jsgraph, params.shared, 16061cb0ef41Sopenharmony_ci Builtin::kArrayMapPreLoopLazyDeoptContinuation, params.target, 16071cb0ef41Sopenharmony_ci params.context, checkpoint_params, arraysize(checkpoint_params), 16081cb0ef41Sopenharmony_ci params.outer_frame_state, ContinuationFrameStateMode::LAZY); 16091cb0ef41Sopenharmony_ci} 16101cb0ef41Sopenharmony_ci 16111cb0ef41Sopenharmony_ciFrameState MapLoopLazyFrameState(const MapFrameStateParams& params, 16121cb0ef41Sopenharmony_ci TNode<Number> k) { 16131cb0ef41Sopenharmony_ci Node* checkpoint_params[] = { 16141cb0ef41Sopenharmony_ci params.receiver, params.callback, params.this_arg, *params.a, k, 16151cb0ef41Sopenharmony_ci params.original_length}; 16161cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 16171cb0ef41Sopenharmony_ci params.jsgraph, params.shared, 16181cb0ef41Sopenharmony_ci Builtin::kArrayMapLoopLazyDeoptContinuation, params.target, 16191cb0ef41Sopenharmony_ci params.context, checkpoint_params, arraysize(checkpoint_params), 16201cb0ef41Sopenharmony_ci params.outer_frame_state, ContinuationFrameStateMode::LAZY); 16211cb0ef41Sopenharmony_ci} 16221cb0ef41Sopenharmony_ci 16231cb0ef41Sopenharmony_ciFrameState MapLoopEagerFrameState(const MapFrameStateParams& params, 16241cb0ef41Sopenharmony_ci TNode<Number> k) { 16251cb0ef41Sopenharmony_ci Node* checkpoint_params[] = { 16261cb0ef41Sopenharmony_ci params.receiver, params.callback, params.this_arg, *params.a, k, 16271cb0ef41Sopenharmony_ci params.original_length}; 16281cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 16291cb0ef41Sopenharmony_ci params.jsgraph, params.shared, 16301cb0ef41Sopenharmony_ci Builtin::kArrayMapLoopEagerDeoptContinuation, params.target, 16311cb0ef41Sopenharmony_ci params.context, checkpoint_params, arraysize(checkpoint_params), 16321cb0ef41Sopenharmony_ci params.outer_frame_state, ContinuationFrameStateMode::EAGER); 16331cb0ef41Sopenharmony_ci} 16341cb0ef41Sopenharmony_ci 16351cb0ef41Sopenharmony_ci} // namespace 16361cb0ef41Sopenharmony_ci 16371cb0ef41Sopenharmony_ciTNode<JSArray> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeMap( 16381cb0ef41Sopenharmony_ci MapInference* inference, const bool has_stability_dependency, 16391cb0ef41Sopenharmony_ci ElementsKind kind, const SharedFunctionInfoRef& shared, 16401cb0ef41Sopenharmony_ci const NativeContextRef& native_context) { 16411cb0ef41Sopenharmony_ci FrameState outer_frame_state = FrameStateInput(); 16421cb0ef41Sopenharmony_ci TNode<Context> context = ContextInput(); 16431cb0ef41Sopenharmony_ci TNode<Object> target = TargetInput(); 16441cb0ef41Sopenharmony_ci TNode<JSArray> receiver = ReceiverInputAs<JSArray>(); 16451cb0ef41Sopenharmony_ci TNode<Object> fncallback = ArgumentOrUndefined(0); 16461cb0ef41Sopenharmony_ci TNode<Object> this_arg = ArgumentOrUndefined(1); 16471cb0ef41Sopenharmony_ci 16481cb0ef41Sopenharmony_ci TNode<Number> original_length = LoadJSArrayLength(receiver, kind); 16491cb0ef41Sopenharmony_ci 16501cb0ef41Sopenharmony_ci // If the array length >= kMaxFastArrayLength, then CreateArray 16511cb0ef41Sopenharmony_ci // will create a dictionary. We should deopt in this case, and make sure 16521cb0ef41Sopenharmony_ci // not to attempt inlining again. 16531cb0ef41Sopenharmony_ci original_length = CheckBounds(original_length, 16541cb0ef41Sopenharmony_ci NumberConstant(JSArray::kMaxFastArrayLength)); 16551cb0ef41Sopenharmony_ci 16561cb0ef41Sopenharmony_ci // Even though {JSCreateArray} is not marked as {kNoThrow}, we can elide the 16571cb0ef41Sopenharmony_ci // exceptional projections because it cannot throw with the given 16581cb0ef41Sopenharmony_ci // parameters. 16591cb0ef41Sopenharmony_ci TNode<Object> array_ctor = 16601cb0ef41Sopenharmony_ci Constant(native_context.GetInitialJSArrayMap(kind).GetConstructor()); 16611cb0ef41Sopenharmony_ci 16621cb0ef41Sopenharmony_ci MapFrameStateParams frame_state_params{ 16631cb0ef41Sopenharmony_ci jsgraph(), shared, context, target, outer_frame_state, 16641cb0ef41Sopenharmony_ci receiver, fncallback, this_arg, {} /* TBD */, original_length}; 16651cb0ef41Sopenharmony_ci 16661cb0ef41Sopenharmony_ci TNode<JSArray> a = 16671cb0ef41Sopenharmony_ci CreateArrayNoThrow(array_ctor, original_length, 16681cb0ef41Sopenharmony_ci MapPreLoopLazyFrameState(frame_state_params)); 16691cb0ef41Sopenharmony_ci frame_state_params.a = a; 16701cb0ef41Sopenharmony_ci 16711cb0ef41Sopenharmony_ci ThrowIfNotCallable(fncallback, 16721cb0ef41Sopenharmony_ci MapLoopLazyFrameState(frame_state_params, ZeroConstant())); 16731cb0ef41Sopenharmony_ci 16741cb0ef41Sopenharmony_ci ForZeroUntil(original_length).Do([&](TNode<Number> k) { 16751cb0ef41Sopenharmony_ci Checkpoint(MapLoopEagerFrameState(frame_state_params, k)); 16761cb0ef41Sopenharmony_ci MaybeInsertMapChecks(inference, has_stability_dependency); 16771cb0ef41Sopenharmony_ci 16781cb0ef41Sopenharmony_ci TNode<Object> element; 16791cb0ef41Sopenharmony_ci std::tie(k, element) = SafeLoadElement(kind, receiver, k); 16801cb0ef41Sopenharmony_ci 16811cb0ef41Sopenharmony_ci auto continue_label = MakeLabel(); 16821cb0ef41Sopenharmony_ci element = MaybeSkipHole(element, kind, &continue_label); 16831cb0ef41Sopenharmony_ci 16841cb0ef41Sopenharmony_ci TNode<Object> v = JSCall3(fncallback, this_arg, element, k, receiver, 16851cb0ef41Sopenharmony_ci MapLoopLazyFrameState(frame_state_params, k)); 16861cb0ef41Sopenharmony_ci 16871cb0ef41Sopenharmony_ci // The array {a} should be HOLEY_SMI_ELEMENTS because we'd only come into 16881cb0ef41Sopenharmony_ci // this loop if the input array length is non-zero, and "new Array({x > 0})" 16891cb0ef41Sopenharmony_ci // always produces a HOLEY array. 16901cb0ef41Sopenharmony_ci MapRef holey_double_map = 16911cb0ef41Sopenharmony_ci native_context.GetInitialJSArrayMap(HOLEY_DOUBLE_ELEMENTS); 16921cb0ef41Sopenharmony_ci MapRef holey_map = native_context.GetInitialJSArrayMap(HOLEY_ELEMENTS); 16931cb0ef41Sopenharmony_ci TransitionAndStoreElement(holey_double_map, holey_map, a, k, v); 16941cb0ef41Sopenharmony_ci 16951cb0ef41Sopenharmony_ci Goto(&continue_label); 16961cb0ef41Sopenharmony_ci Bind(&continue_label); 16971cb0ef41Sopenharmony_ci }); 16981cb0ef41Sopenharmony_ci 16991cb0ef41Sopenharmony_ci return a; 17001cb0ef41Sopenharmony_ci} 17011cb0ef41Sopenharmony_ci 17021cb0ef41Sopenharmony_cinamespace { 17031cb0ef41Sopenharmony_ci 17041cb0ef41Sopenharmony_cistruct FilterFrameStateParams { 17051cb0ef41Sopenharmony_ci JSGraph* jsgraph; 17061cb0ef41Sopenharmony_ci SharedFunctionInfoRef shared; 17071cb0ef41Sopenharmony_ci TNode<Context> context; 17081cb0ef41Sopenharmony_ci TNode<Object> target; 17091cb0ef41Sopenharmony_ci FrameState outer_frame_state; 17101cb0ef41Sopenharmony_ci TNode<Object> receiver; 17111cb0ef41Sopenharmony_ci TNode<Object> callback; 17121cb0ef41Sopenharmony_ci TNode<Object> this_arg; 17131cb0ef41Sopenharmony_ci TNode<JSArray> a; 17141cb0ef41Sopenharmony_ci TNode<Object> original_length; 17151cb0ef41Sopenharmony_ci}; 17161cb0ef41Sopenharmony_ci 17171cb0ef41Sopenharmony_ciFrameState FilterLoopLazyFrameState(const FilterFrameStateParams& params, 17181cb0ef41Sopenharmony_ci TNode<Number> k, TNode<Number> to, 17191cb0ef41Sopenharmony_ci TNode<Object> element) { 17201cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {params.receiver, 17211cb0ef41Sopenharmony_ci params.callback, 17221cb0ef41Sopenharmony_ci params.this_arg, 17231cb0ef41Sopenharmony_ci params.a, 17241cb0ef41Sopenharmony_ci k, 17251cb0ef41Sopenharmony_ci params.original_length, 17261cb0ef41Sopenharmony_ci element, 17271cb0ef41Sopenharmony_ci to}; 17281cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 17291cb0ef41Sopenharmony_ci params.jsgraph, params.shared, 17301cb0ef41Sopenharmony_ci Builtin::kArrayFilterLoopLazyDeoptContinuation, params.target, 17311cb0ef41Sopenharmony_ci params.context, checkpoint_params, arraysize(checkpoint_params), 17321cb0ef41Sopenharmony_ci params.outer_frame_state, ContinuationFrameStateMode::LAZY); 17331cb0ef41Sopenharmony_ci} 17341cb0ef41Sopenharmony_ci 17351cb0ef41Sopenharmony_ciFrameState FilterLoopEagerPostCallbackFrameState( 17361cb0ef41Sopenharmony_ci const FilterFrameStateParams& params, TNode<Number> k, TNode<Number> to, 17371cb0ef41Sopenharmony_ci TNode<Object> element, TNode<Object> callback_value) { 17381cb0ef41Sopenharmony_ci // Note that we are intentionally reusing the 17391cb0ef41Sopenharmony_ci // Builtin::kArrayFilterLoopLazyDeoptContinuation as an *eager* entry 17401cb0ef41Sopenharmony_ci // point in this case. This is safe, because re-evaluating a [ToBoolean] 17411cb0ef41Sopenharmony_ci // coercion is safe. 17421cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {params.receiver, 17431cb0ef41Sopenharmony_ci params.callback, 17441cb0ef41Sopenharmony_ci params.this_arg, 17451cb0ef41Sopenharmony_ci params.a, 17461cb0ef41Sopenharmony_ci k, 17471cb0ef41Sopenharmony_ci params.original_length, 17481cb0ef41Sopenharmony_ci element, 17491cb0ef41Sopenharmony_ci to, 17501cb0ef41Sopenharmony_ci callback_value}; 17511cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 17521cb0ef41Sopenharmony_ci params.jsgraph, params.shared, 17531cb0ef41Sopenharmony_ci Builtin::kArrayFilterLoopLazyDeoptContinuation, params.target, 17541cb0ef41Sopenharmony_ci params.context, checkpoint_params, arraysize(checkpoint_params), 17551cb0ef41Sopenharmony_ci params.outer_frame_state, ContinuationFrameStateMode::EAGER); 17561cb0ef41Sopenharmony_ci} 17571cb0ef41Sopenharmony_ci 17581cb0ef41Sopenharmony_ciFrameState FilterLoopEagerFrameState(const FilterFrameStateParams& params, 17591cb0ef41Sopenharmony_ci TNode<Number> k, TNode<Number> to) { 17601cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {params.receiver, 17611cb0ef41Sopenharmony_ci params.callback, 17621cb0ef41Sopenharmony_ci params.this_arg, 17631cb0ef41Sopenharmony_ci params.a, 17641cb0ef41Sopenharmony_ci k, 17651cb0ef41Sopenharmony_ci params.original_length, 17661cb0ef41Sopenharmony_ci to}; 17671cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 17681cb0ef41Sopenharmony_ci params.jsgraph, params.shared, 17691cb0ef41Sopenharmony_ci Builtin::kArrayFilterLoopEagerDeoptContinuation, params.target, 17701cb0ef41Sopenharmony_ci params.context, checkpoint_params, arraysize(checkpoint_params), 17711cb0ef41Sopenharmony_ci params.outer_frame_state, ContinuationFrameStateMode::EAGER); 17721cb0ef41Sopenharmony_ci} 17731cb0ef41Sopenharmony_ci 17741cb0ef41Sopenharmony_ci} // namespace 17751cb0ef41Sopenharmony_ci 17761cb0ef41Sopenharmony_ciTNode<JSArray> 17771cb0ef41Sopenharmony_ciIteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeFilter( 17781cb0ef41Sopenharmony_ci MapInference* inference, const bool has_stability_dependency, 17791cb0ef41Sopenharmony_ci ElementsKind kind, const SharedFunctionInfoRef& shared, 17801cb0ef41Sopenharmony_ci const NativeContextRef& native_context) { 17811cb0ef41Sopenharmony_ci FrameState outer_frame_state = FrameStateInput(); 17821cb0ef41Sopenharmony_ci TNode<Context> context = ContextInput(); 17831cb0ef41Sopenharmony_ci TNode<Object> target = TargetInput(); 17841cb0ef41Sopenharmony_ci TNode<JSArray> receiver = ReceiverInputAs<JSArray>(); 17851cb0ef41Sopenharmony_ci TNode<Object> fncallback = ArgumentOrUndefined(0); 17861cb0ef41Sopenharmony_ci TNode<Object> this_arg = ArgumentOrUndefined(1); 17871cb0ef41Sopenharmony_ci 17881cb0ef41Sopenharmony_ci // The output array is packed (filter doesn't visit holes). 17891cb0ef41Sopenharmony_ci const ElementsKind packed_kind = GetPackedElementsKind(kind); 17901cb0ef41Sopenharmony_ci TNode<JSArray> a = AllocateEmptyJSArray(packed_kind, native_context); 17911cb0ef41Sopenharmony_ci 17921cb0ef41Sopenharmony_ci TNode<Number> original_length = LoadJSArrayLength(receiver, kind); 17931cb0ef41Sopenharmony_ci 17941cb0ef41Sopenharmony_ci FilterFrameStateParams frame_state_params{ 17951cb0ef41Sopenharmony_ci jsgraph(), shared, context, target, outer_frame_state, 17961cb0ef41Sopenharmony_ci receiver, fncallback, this_arg, a, original_length}; 17971cb0ef41Sopenharmony_ci 17981cb0ef41Sopenharmony_ci // This frame state doesn't ever call the deopt continuation, it's only 17991cb0ef41Sopenharmony_ci // necessary to specify a continuation in order to handle the exceptional 18001cb0ef41Sopenharmony_ci // case. We don't have all the values available to completely fill out 18011cb0ef41Sopenharmony_ci // the checkpoint parameters yet, but that's okay because it'll never be 18021cb0ef41Sopenharmony_ci // called. 18031cb0ef41Sopenharmony_ci TNode<Number> zero = ZeroConstant(); 18041cb0ef41Sopenharmony_ci ThrowIfNotCallable(fncallback, FilterLoopLazyFrameState(frame_state_params, 18051cb0ef41Sopenharmony_ci zero, zero, zero)); 18061cb0ef41Sopenharmony_ci 18071cb0ef41Sopenharmony_ci TNode<Number> initial_a_length = zero; 18081cb0ef41Sopenharmony_ci For1ZeroUntil(original_length, initial_a_length) 18091cb0ef41Sopenharmony_ci .Do([&](TNode<Number> k, TNode<Object>* a_length_object) { 18101cb0ef41Sopenharmony_ci TNode<Number> a_length = TNode<Number>::UncheckedCast(*a_length_object); 18111cb0ef41Sopenharmony_ci Checkpoint(FilterLoopEagerFrameState(frame_state_params, k, a_length)); 18121cb0ef41Sopenharmony_ci MaybeInsertMapChecks(inference, has_stability_dependency); 18131cb0ef41Sopenharmony_ci 18141cb0ef41Sopenharmony_ci TNode<Object> element; 18151cb0ef41Sopenharmony_ci std::tie(k, element) = SafeLoadElement(kind, receiver, k); 18161cb0ef41Sopenharmony_ci 18171cb0ef41Sopenharmony_ci auto continue_label = MakeLabel(MachineRepresentation::kTaggedSigned); 18181cb0ef41Sopenharmony_ci element = MaybeSkipHole(element, kind, &continue_label, a_length); 18191cb0ef41Sopenharmony_ci 18201cb0ef41Sopenharmony_ci TNode<Object> v = JSCall3( 18211cb0ef41Sopenharmony_ci fncallback, this_arg, element, k, receiver, 18221cb0ef41Sopenharmony_ci FilterLoopLazyFrameState(frame_state_params, k, a_length, element)); 18231cb0ef41Sopenharmony_ci 18241cb0ef41Sopenharmony_ci // We need an eager frame state for right after the callback function 18251cb0ef41Sopenharmony_ci // returned, just in case an attempt to grow the output array fails. 18261cb0ef41Sopenharmony_ci Checkpoint(FilterLoopEagerPostCallbackFrameState(frame_state_params, k, 18271cb0ef41Sopenharmony_ci a_length, element, v)); 18281cb0ef41Sopenharmony_ci 18291cb0ef41Sopenharmony_ci GotoIfNot(ToBoolean(v), &continue_label, a_length); 18301cb0ef41Sopenharmony_ci 18311cb0ef41Sopenharmony_ci // Since the callback returned a trueish value, store the element in a. 18321cb0ef41Sopenharmony_ci { 18331cb0ef41Sopenharmony_ci TNode<Number> a_length1 = TypeGuardFixedArrayLength(a_length); 18341cb0ef41Sopenharmony_ci TNode<FixedArrayBase> elements = LoadElements(a); 18351cb0ef41Sopenharmony_ci elements = MaybeGrowFastElements(kind, FeedbackSource{}, a, elements, 18361cb0ef41Sopenharmony_ci a_length1, 18371cb0ef41Sopenharmony_ci LoadFixedArrayBaseLength(elements)); 18381cb0ef41Sopenharmony_ci 18391cb0ef41Sopenharmony_ci TNode<Number> new_a_length = NumberInc(a_length1); 18401cb0ef41Sopenharmony_ci StoreJSArrayLength(a, new_a_length, kind); 18411cb0ef41Sopenharmony_ci StoreFixedArrayBaseElement(elements, a_length1, element, kind); 18421cb0ef41Sopenharmony_ci 18431cb0ef41Sopenharmony_ci Goto(&continue_label, new_a_length); 18441cb0ef41Sopenharmony_ci } 18451cb0ef41Sopenharmony_ci 18461cb0ef41Sopenharmony_ci Bind(&continue_label); 18471cb0ef41Sopenharmony_ci *a_length_object = 18481cb0ef41Sopenharmony_ci TNode<Object>::UncheckedCast(continue_label.PhiAt(0)); 18491cb0ef41Sopenharmony_ci }) 18501cb0ef41Sopenharmony_ci .ValueIsUnused(); 18511cb0ef41Sopenharmony_ci 18521cb0ef41Sopenharmony_ci return a; 18531cb0ef41Sopenharmony_ci} 18541cb0ef41Sopenharmony_ci 18551cb0ef41Sopenharmony_cinamespace { 18561cb0ef41Sopenharmony_ci 18571cb0ef41Sopenharmony_cistruct FindFrameStateParams { 18581cb0ef41Sopenharmony_ci JSGraph* jsgraph; 18591cb0ef41Sopenharmony_ci SharedFunctionInfoRef shared; 18601cb0ef41Sopenharmony_ci TNode<Context> context; 18611cb0ef41Sopenharmony_ci TNode<Object> target; 18621cb0ef41Sopenharmony_ci FrameState outer_frame_state; 18631cb0ef41Sopenharmony_ci TNode<Object> receiver; 18641cb0ef41Sopenharmony_ci TNode<Object> callback; 18651cb0ef41Sopenharmony_ci TNode<Object> this_arg; 18661cb0ef41Sopenharmony_ci TNode<Object> original_length; 18671cb0ef41Sopenharmony_ci}; 18681cb0ef41Sopenharmony_ci 18691cb0ef41Sopenharmony_ciFrameState FindLoopLazyFrameState(const FindFrameStateParams& params, 18701cb0ef41Sopenharmony_ci TNode<Number> k, ArrayFindVariant variant) { 18711cb0ef41Sopenharmony_ci Builtin builtin = (variant == ArrayFindVariant::kFind) 18721cb0ef41Sopenharmony_ci ? Builtin::kArrayFindLoopLazyDeoptContinuation 18731cb0ef41Sopenharmony_ci : Builtin::kArrayFindIndexLoopLazyDeoptContinuation; 18741cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {params.receiver, params.callback, 18751cb0ef41Sopenharmony_ci params.this_arg, k, params.original_length}; 18761cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 18771cb0ef41Sopenharmony_ci params.jsgraph, params.shared, builtin, params.target, params.context, 18781cb0ef41Sopenharmony_ci checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, 18791cb0ef41Sopenharmony_ci ContinuationFrameStateMode::LAZY); 18801cb0ef41Sopenharmony_ci} 18811cb0ef41Sopenharmony_ci 18821cb0ef41Sopenharmony_ciFrameState FindLoopEagerFrameState(const FindFrameStateParams& params, 18831cb0ef41Sopenharmony_ci TNode<Number> k, ArrayFindVariant variant) { 18841cb0ef41Sopenharmony_ci Builtin builtin = (variant == ArrayFindVariant::kFind) 18851cb0ef41Sopenharmony_ci ? Builtin::kArrayFindLoopEagerDeoptContinuation 18861cb0ef41Sopenharmony_ci : Builtin::kArrayFindIndexLoopEagerDeoptContinuation; 18871cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {params.receiver, params.callback, 18881cb0ef41Sopenharmony_ci params.this_arg, k, params.original_length}; 18891cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 18901cb0ef41Sopenharmony_ci params.jsgraph, params.shared, builtin, params.target, params.context, 18911cb0ef41Sopenharmony_ci checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, 18921cb0ef41Sopenharmony_ci ContinuationFrameStateMode::EAGER); 18931cb0ef41Sopenharmony_ci} 18941cb0ef41Sopenharmony_ci 18951cb0ef41Sopenharmony_ciFrameState FindLoopAfterCallbackLazyFrameState( 18961cb0ef41Sopenharmony_ci const FindFrameStateParams& params, TNode<Number> next_k, 18971cb0ef41Sopenharmony_ci TNode<Object> if_found_value, ArrayFindVariant variant) { 18981cb0ef41Sopenharmony_ci Builtin builtin = 18991cb0ef41Sopenharmony_ci (variant == ArrayFindVariant::kFind) 19001cb0ef41Sopenharmony_ci ? Builtin::kArrayFindLoopAfterCallbackLazyDeoptContinuation 19011cb0ef41Sopenharmony_ci : Builtin::kArrayFindIndexLoopAfterCallbackLazyDeoptContinuation; 19021cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {params.receiver, params.callback, 19031cb0ef41Sopenharmony_ci params.this_arg, next_k, 19041cb0ef41Sopenharmony_ci params.original_length, if_found_value}; 19051cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 19061cb0ef41Sopenharmony_ci params.jsgraph, params.shared, builtin, params.target, params.context, 19071cb0ef41Sopenharmony_ci checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, 19081cb0ef41Sopenharmony_ci ContinuationFrameStateMode::LAZY); 19091cb0ef41Sopenharmony_ci} 19101cb0ef41Sopenharmony_ci 19111cb0ef41Sopenharmony_ci} // namespace 19121cb0ef41Sopenharmony_ci 19131cb0ef41Sopenharmony_ciTNode<Object> IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeFind( 19141cb0ef41Sopenharmony_ci MapInference* inference, const bool has_stability_dependency, 19151cb0ef41Sopenharmony_ci ElementsKind kind, const SharedFunctionInfoRef& shared, 19161cb0ef41Sopenharmony_ci const NativeContextRef& native_context, ArrayFindVariant variant) { 19171cb0ef41Sopenharmony_ci FrameState outer_frame_state = FrameStateInput(); 19181cb0ef41Sopenharmony_ci TNode<Context> context = ContextInput(); 19191cb0ef41Sopenharmony_ci TNode<Object> target = TargetInput(); 19201cb0ef41Sopenharmony_ci TNode<JSArray> receiver = ReceiverInputAs<JSArray>(); 19211cb0ef41Sopenharmony_ci TNode<Object> fncallback = ArgumentOrUndefined(0); 19221cb0ef41Sopenharmony_ci TNode<Object> this_arg = ArgumentOrUndefined(1); 19231cb0ef41Sopenharmony_ci 19241cb0ef41Sopenharmony_ci TNode<Number> original_length = LoadJSArrayLength(receiver, kind); 19251cb0ef41Sopenharmony_ci 19261cb0ef41Sopenharmony_ci FindFrameStateParams frame_state_params{ 19271cb0ef41Sopenharmony_ci jsgraph(), shared, context, target, outer_frame_state, 19281cb0ef41Sopenharmony_ci receiver, fncallback, this_arg, original_length}; 19291cb0ef41Sopenharmony_ci 19301cb0ef41Sopenharmony_ci ThrowIfNotCallable( 19311cb0ef41Sopenharmony_ci fncallback, 19321cb0ef41Sopenharmony_ci FindLoopLazyFrameState(frame_state_params, ZeroConstant(), variant)); 19331cb0ef41Sopenharmony_ci 19341cb0ef41Sopenharmony_ci const bool is_find_variant = (variant == ArrayFindVariant::kFind); 19351cb0ef41Sopenharmony_ci auto out = MakeLabel(MachineRepresentation::kTagged); 19361cb0ef41Sopenharmony_ci 19371cb0ef41Sopenharmony_ci ForZeroUntil(original_length).Do([&](TNode<Number> k) { 19381cb0ef41Sopenharmony_ci Checkpoint(FindLoopEagerFrameState(frame_state_params, k, variant)); 19391cb0ef41Sopenharmony_ci MaybeInsertMapChecks(inference, has_stability_dependency); 19401cb0ef41Sopenharmony_ci 19411cb0ef41Sopenharmony_ci TNode<Object> element; 19421cb0ef41Sopenharmony_ci std::tie(k, element) = SafeLoadElement(kind, receiver, k); 19431cb0ef41Sopenharmony_ci 19441cb0ef41Sopenharmony_ci if (IsHoleyElementsKind(kind)) { 19451cb0ef41Sopenharmony_ci element = TryConvertHoleToUndefined(element, kind); 19461cb0ef41Sopenharmony_ci } 19471cb0ef41Sopenharmony_ci 19481cb0ef41Sopenharmony_ci TNode<Object> if_found_value = is_find_variant ? element : k; 19491cb0ef41Sopenharmony_ci TNode<Number> next_k = NumberInc(k); 19501cb0ef41Sopenharmony_ci 19511cb0ef41Sopenharmony_ci // The callback result states whether the desired element was found. 19521cb0ef41Sopenharmony_ci TNode<Object> v = 19531cb0ef41Sopenharmony_ci JSCall3(fncallback, this_arg, element, k, receiver, 19541cb0ef41Sopenharmony_ci FindLoopAfterCallbackLazyFrameState(frame_state_params, next_k, 19551cb0ef41Sopenharmony_ci if_found_value, variant)); 19561cb0ef41Sopenharmony_ci 19571cb0ef41Sopenharmony_ci GotoIf(ToBoolean(v), &out, if_found_value); 19581cb0ef41Sopenharmony_ci }); 19591cb0ef41Sopenharmony_ci 19601cb0ef41Sopenharmony_ci // If the loop completed, the element was not found. 19611cb0ef41Sopenharmony_ci TNode<Object> if_not_found_value = 19621cb0ef41Sopenharmony_ci is_find_variant ? TNode<Object>::UncheckedCast(UndefinedConstant()) 19631cb0ef41Sopenharmony_ci : TNode<Object>::UncheckedCast(MinusOneConstant()); 19641cb0ef41Sopenharmony_ci Goto(&out, if_not_found_value); 19651cb0ef41Sopenharmony_ci 19661cb0ef41Sopenharmony_ci Bind(&out); 19671cb0ef41Sopenharmony_ci return out.PhiAt<Object>(0); 19681cb0ef41Sopenharmony_ci} 19691cb0ef41Sopenharmony_ci 19701cb0ef41Sopenharmony_cinamespace { 19711cb0ef41Sopenharmony_ci 19721cb0ef41Sopenharmony_cistruct EverySomeFrameStateParams { 19731cb0ef41Sopenharmony_ci JSGraph* jsgraph; 19741cb0ef41Sopenharmony_ci SharedFunctionInfoRef shared; 19751cb0ef41Sopenharmony_ci TNode<Context> context; 19761cb0ef41Sopenharmony_ci TNode<Object> target; 19771cb0ef41Sopenharmony_ci FrameState outer_frame_state; 19781cb0ef41Sopenharmony_ci TNode<Object> receiver; 19791cb0ef41Sopenharmony_ci TNode<Object> callback; 19801cb0ef41Sopenharmony_ci TNode<Object> this_arg; 19811cb0ef41Sopenharmony_ci TNode<Object> original_length; 19821cb0ef41Sopenharmony_ci}; 19831cb0ef41Sopenharmony_ci 19841cb0ef41Sopenharmony_ciFrameState EverySomeLoopLazyFrameState(const EverySomeFrameStateParams& params, 19851cb0ef41Sopenharmony_ci TNode<Number> k, 19861cb0ef41Sopenharmony_ci ArrayEverySomeVariant variant) { 19871cb0ef41Sopenharmony_ci Builtin builtin = (variant == ArrayEverySomeVariant::kEvery) 19881cb0ef41Sopenharmony_ci ? Builtin::kArrayEveryLoopLazyDeoptContinuation 19891cb0ef41Sopenharmony_ci : Builtin::kArraySomeLoopLazyDeoptContinuation; 19901cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {params.receiver, params.callback, 19911cb0ef41Sopenharmony_ci params.this_arg, k, params.original_length}; 19921cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 19931cb0ef41Sopenharmony_ci params.jsgraph, params.shared, builtin, params.target, params.context, 19941cb0ef41Sopenharmony_ci checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, 19951cb0ef41Sopenharmony_ci ContinuationFrameStateMode::LAZY); 19961cb0ef41Sopenharmony_ci} 19971cb0ef41Sopenharmony_ci 19981cb0ef41Sopenharmony_ciFrameState EverySomeLoopEagerFrameState(const EverySomeFrameStateParams& params, 19991cb0ef41Sopenharmony_ci TNode<Number> k, 20001cb0ef41Sopenharmony_ci ArrayEverySomeVariant variant) { 20011cb0ef41Sopenharmony_ci Builtin builtin = (variant == ArrayEverySomeVariant::kEvery) 20021cb0ef41Sopenharmony_ci ? Builtin::kArrayEveryLoopEagerDeoptContinuation 20031cb0ef41Sopenharmony_ci : Builtin::kArraySomeLoopEagerDeoptContinuation; 20041cb0ef41Sopenharmony_ci Node* checkpoint_params[] = {params.receiver, params.callback, 20051cb0ef41Sopenharmony_ci params.this_arg, k, params.original_length}; 20061cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 20071cb0ef41Sopenharmony_ci params.jsgraph, params.shared, builtin, params.target, params.context, 20081cb0ef41Sopenharmony_ci checkpoint_params, arraysize(checkpoint_params), params.outer_frame_state, 20091cb0ef41Sopenharmony_ci ContinuationFrameStateMode::EAGER); 20101cb0ef41Sopenharmony_ci} 20111cb0ef41Sopenharmony_ci 20121cb0ef41Sopenharmony_ci} // namespace 20131cb0ef41Sopenharmony_ci 20141cb0ef41Sopenharmony_ciTNode<Boolean> 20151cb0ef41Sopenharmony_ciIteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeEverySome( 20161cb0ef41Sopenharmony_ci MapInference* inference, const bool has_stability_dependency, 20171cb0ef41Sopenharmony_ci ElementsKind kind, const SharedFunctionInfoRef& shared, 20181cb0ef41Sopenharmony_ci const NativeContextRef& native_context, ArrayEverySomeVariant variant) { 20191cb0ef41Sopenharmony_ci FrameState outer_frame_state = FrameStateInput(); 20201cb0ef41Sopenharmony_ci TNode<Context> context = ContextInput(); 20211cb0ef41Sopenharmony_ci TNode<Object> target = TargetInput(); 20221cb0ef41Sopenharmony_ci TNode<JSArray> receiver = ReceiverInputAs<JSArray>(); 20231cb0ef41Sopenharmony_ci TNode<Object> fncallback = ArgumentOrUndefined(0); 20241cb0ef41Sopenharmony_ci TNode<Object> this_arg = ArgumentOrUndefined(1); 20251cb0ef41Sopenharmony_ci 20261cb0ef41Sopenharmony_ci TNode<Number> original_length = LoadJSArrayLength(receiver, kind); 20271cb0ef41Sopenharmony_ci 20281cb0ef41Sopenharmony_ci EverySomeFrameStateParams frame_state_params{ 20291cb0ef41Sopenharmony_ci jsgraph(), shared, context, target, outer_frame_state, 20301cb0ef41Sopenharmony_ci receiver, fncallback, this_arg, original_length}; 20311cb0ef41Sopenharmony_ci 20321cb0ef41Sopenharmony_ci ThrowIfNotCallable( 20331cb0ef41Sopenharmony_ci fncallback, 20341cb0ef41Sopenharmony_ci EverySomeLoopLazyFrameState(frame_state_params, ZeroConstant(), variant)); 20351cb0ef41Sopenharmony_ci 20361cb0ef41Sopenharmony_ci auto out = MakeLabel(MachineRepresentation::kTagged); 20371cb0ef41Sopenharmony_ci 20381cb0ef41Sopenharmony_ci ForZeroUntil(original_length).Do([&](TNode<Number> k) { 20391cb0ef41Sopenharmony_ci Checkpoint(EverySomeLoopEagerFrameState(frame_state_params, k, variant)); 20401cb0ef41Sopenharmony_ci MaybeInsertMapChecks(inference, has_stability_dependency); 20411cb0ef41Sopenharmony_ci 20421cb0ef41Sopenharmony_ci TNode<Object> element; 20431cb0ef41Sopenharmony_ci std::tie(k, element) = SafeLoadElement(kind, receiver, k); 20441cb0ef41Sopenharmony_ci 20451cb0ef41Sopenharmony_ci auto continue_label = MakeLabel(); 20461cb0ef41Sopenharmony_ci element = MaybeSkipHole(element, kind, &continue_label); 20471cb0ef41Sopenharmony_ci 20481cb0ef41Sopenharmony_ci TNode<Object> v = 20491cb0ef41Sopenharmony_ci JSCall3(fncallback, this_arg, element, k, receiver, 20501cb0ef41Sopenharmony_ci EverySomeLoopLazyFrameState(frame_state_params, k, variant)); 20511cb0ef41Sopenharmony_ci 20521cb0ef41Sopenharmony_ci if (variant == ArrayEverySomeVariant::kEvery) { 20531cb0ef41Sopenharmony_ci GotoIfNot(ToBoolean(v), &out, FalseConstant()); 20541cb0ef41Sopenharmony_ci } else { 20551cb0ef41Sopenharmony_ci DCHECK_EQ(variant, ArrayEverySomeVariant::kSome); 20561cb0ef41Sopenharmony_ci GotoIf(ToBoolean(v), &out, TrueConstant()); 20571cb0ef41Sopenharmony_ci } 20581cb0ef41Sopenharmony_ci Goto(&continue_label); 20591cb0ef41Sopenharmony_ci Bind(&continue_label); 20601cb0ef41Sopenharmony_ci }); 20611cb0ef41Sopenharmony_ci 20621cb0ef41Sopenharmony_ci Goto(&out, (variant == ArrayEverySomeVariant::kEvery) ? TrueConstant() 20631cb0ef41Sopenharmony_ci : FalseConstant()); 20641cb0ef41Sopenharmony_ci 20651cb0ef41Sopenharmony_ci Bind(&out); 20661cb0ef41Sopenharmony_ci return out.PhiAt<Boolean>(0); 20671cb0ef41Sopenharmony_ci} 20681cb0ef41Sopenharmony_ci 20691cb0ef41Sopenharmony_cinamespace { 20701cb0ef41Sopenharmony_ci 20711cb0ef41Sopenharmony_ciCallable GetCallableForArrayIndexOfIncludes(ArrayIndexOfIncludesVariant variant, 20721cb0ef41Sopenharmony_ci ElementsKind elements_kind, 20731cb0ef41Sopenharmony_ci Isolate* isolate) { 20741cb0ef41Sopenharmony_ci if (variant == ArrayIndexOfIncludesVariant::kIndexOf) { 20751cb0ef41Sopenharmony_ci switch (elements_kind) { 20761cb0ef41Sopenharmony_ci case PACKED_SMI_ELEMENTS: 20771cb0ef41Sopenharmony_ci case HOLEY_SMI_ELEMENTS: 20781cb0ef41Sopenharmony_ci case PACKED_ELEMENTS: 20791cb0ef41Sopenharmony_ci case HOLEY_ELEMENTS: 20801cb0ef41Sopenharmony_ci return Builtins::CallableFor(isolate, 20811cb0ef41Sopenharmony_ci Builtin::kArrayIndexOfSmiOrObject); 20821cb0ef41Sopenharmony_ci case PACKED_DOUBLE_ELEMENTS: 20831cb0ef41Sopenharmony_ci return Builtins::CallableFor(isolate, 20841cb0ef41Sopenharmony_ci Builtin::kArrayIndexOfPackedDoubles); 20851cb0ef41Sopenharmony_ci default: 20861cb0ef41Sopenharmony_ci DCHECK_EQ(HOLEY_DOUBLE_ELEMENTS, elements_kind); 20871cb0ef41Sopenharmony_ci return Builtins::CallableFor(isolate, 20881cb0ef41Sopenharmony_ci Builtin::kArrayIndexOfHoleyDoubles); 20891cb0ef41Sopenharmony_ci } 20901cb0ef41Sopenharmony_ci } else { 20911cb0ef41Sopenharmony_ci DCHECK_EQ(variant, ArrayIndexOfIncludesVariant::kIncludes); 20921cb0ef41Sopenharmony_ci switch (elements_kind) { 20931cb0ef41Sopenharmony_ci case PACKED_SMI_ELEMENTS: 20941cb0ef41Sopenharmony_ci case HOLEY_SMI_ELEMENTS: 20951cb0ef41Sopenharmony_ci case PACKED_ELEMENTS: 20961cb0ef41Sopenharmony_ci case HOLEY_ELEMENTS: 20971cb0ef41Sopenharmony_ci return Builtins::CallableFor(isolate, 20981cb0ef41Sopenharmony_ci Builtin::kArrayIncludesSmiOrObject); 20991cb0ef41Sopenharmony_ci case PACKED_DOUBLE_ELEMENTS: 21001cb0ef41Sopenharmony_ci return Builtins::CallableFor(isolate, 21011cb0ef41Sopenharmony_ci Builtin::kArrayIncludesPackedDoubles); 21021cb0ef41Sopenharmony_ci default: 21031cb0ef41Sopenharmony_ci DCHECK_EQ(HOLEY_DOUBLE_ELEMENTS, elements_kind); 21041cb0ef41Sopenharmony_ci return Builtins::CallableFor(isolate, 21051cb0ef41Sopenharmony_ci Builtin::kArrayIncludesHoleyDoubles); 21061cb0ef41Sopenharmony_ci } 21071cb0ef41Sopenharmony_ci } 21081cb0ef41Sopenharmony_ci UNREACHABLE(); 21091cb0ef41Sopenharmony_ci} 21101cb0ef41Sopenharmony_ci 21111cb0ef41Sopenharmony_ci} // namespace 21121cb0ef41Sopenharmony_ci 21131cb0ef41Sopenharmony_ciTNode<Object> 21141cb0ef41Sopenharmony_ciIteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeIndexOfIncludes( 21151cb0ef41Sopenharmony_ci ElementsKind kind, ArrayIndexOfIncludesVariant variant) { 21161cb0ef41Sopenharmony_ci TNode<Context> context = ContextInput(); 21171cb0ef41Sopenharmony_ci TNode<JSArray> receiver = ReceiverInputAs<JSArray>(); 21181cb0ef41Sopenharmony_ci TNode<Object> search_element = ArgumentOrUndefined(0); 21191cb0ef41Sopenharmony_ci TNode<Object> from_index = ArgumentOrZero(1); 21201cb0ef41Sopenharmony_ci 21211cb0ef41Sopenharmony_ci // TODO(jgruber): This currently only reduces to a stub call. Create a full 21221cb0ef41Sopenharmony_ci // reduction (similar to other higher-order array builtins) instead of 21231cb0ef41Sopenharmony_ci // lowering to a builtin call. E.g. Array.p.every and Array.p.some have almost 21241cb0ef41Sopenharmony_ci // identical functionality. 21251cb0ef41Sopenharmony_ci 21261cb0ef41Sopenharmony_ci TNode<Number> length = LoadJSArrayLength(receiver, kind); 21271cb0ef41Sopenharmony_ci TNode<FixedArrayBase> elements = LoadElements(receiver); 21281cb0ef41Sopenharmony_ci 21291cb0ef41Sopenharmony_ci const bool have_from_index = ArgumentCount() > 1; 21301cb0ef41Sopenharmony_ci if (have_from_index) { 21311cb0ef41Sopenharmony_ci TNode<Smi> from_index_smi = CheckSmi(from_index); 21321cb0ef41Sopenharmony_ci 21331cb0ef41Sopenharmony_ci // If the index is negative, it means the offset from the end and 21341cb0ef41Sopenharmony_ci // therefore needs to be added to the length. If the result is still 21351cb0ef41Sopenharmony_ci // negative, it needs to be clamped to 0. 21361cb0ef41Sopenharmony_ci TNode<Boolean> cond = NumberLessThan(from_index_smi, ZeroConstant()); 21371cb0ef41Sopenharmony_ci from_index = SelectIf<Number>(cond) 21381cb0ef41Sopenharmony_ci .Then(_ { 21391cb0ef41Sopenharmony_ci return NumberMax(NumberAdd(length, from_index_smi), 21401cb0ef41Sopenharmony_ci ZeroConstant()); 21411cb0ef41Sopenharmony_ci }) 21421cb0ef41Sopenharmony_ci .Else(_ { return from_index_smi; }) 21431cb0ef41Sopenharmony_ci .ExpectFalse() 21441cb0ef41Sopenharmony_ci .Value(); 21451cb0ef41Sopenharmony_ci } 21461cb0ef41Sopenharmony_ci 21471cb0ef41Sopenharmony_ci return Call4(GetCallableForArrayIndexOfIncludes(variant, kind, isolate()), 21481cb0ef41Sopenharmony_ci context, elements, search_element, length, from_index); 21491cb0ef41Sopenharmony_ci} 21501cb0ef41Sopenharmony_ci 21511cb0ef41Sopenharmony_cinamespace { 21521cb0ef41Sopenharmony_ci 21531cb0ef41Sopenharmony_cistruct PromiseCtorFrameStateParams { 21541cb0ef41Sopenharmony_ci JSGraph* jsgraph; 21551cb0ef41Sopenharmony_ci SharedFunctionInfoRef shared; 21561cb0ef41Sopenharmony_ci Node* node_ptr; 21571cb0ef41Sopenharmony_ci TNode<Context> context; 21581cb0ef41Sopenharmony_ci TNode<Object> target; 21591cb0ef41Sopenharmony_ci FrameState outer_frame_state; 21601cb0ef41Sopenharmony_ci}; 21611cb0ef41Sopenharmony_ci 21621cb0ef41Sopenharmony_ci// Remnant of old-style JSCallReducer code. Could be ported to graph assembler, 21631cb0ef41Sopenharmony_ci// but probably not worth the effort. 21641cb0ef41Sopenharmony_ciFrameState CreateArtificialFrameState( 21651cb0ef41Sopenharmony_ci Node* node, Node* outer_frame_state, int parameter_count, 21661cb0ef41Sopenharmony_ci BytecodeOffset bailout_id, FrameStateType frame_state_type, 21671cb0ef41Sopenharmony_ci const SharedFunctionInfoRef& shared, Node* context, 21681cb0ef41Sopenharmony_ci CommonOperatorBuilder* common, Graph* graph) { 21691cb0ef41Sopenharmony_ci const FrameStateFunctionInfo* state_info = 21701cb0ef41Sopenharmony_ci common->CreateFrameStateFunctionInfo( 21711cb0ef41Sopenharmony_ci frame_state_type, parameter_count + 1, 0, shared.object()); 21721cb0ef41Sopenharmony_ci 21731cb0ef41Sopenharmony_ci const Operator* op = common->FrameState( 21741cb0ef41Sopenharmony_ci bailout_id, OutputFrameStateCombine::Ignore(), state_info); 21751cb0ef41Sopenharmony_ci const Operator* op0 = common->StateValues(0, SparseInputMask::Dense()); 21761cb0ef41Sopenharmony_ci Node* node0 = graph->NewNode(op0); 21771cb0ef41Sopenharmony_ci 21781cb0ef41Sopenharmony_ci static constexpr int kTargetInputIndex = 0; 21791cb0ef41Sopenharmony_ci static constexpr int kReceiverInputIndex = 1; 21801cb0ef41Sopenharmony_ci const int parameter_count_with_receiver = parameter_count + 1; 21811cb0ef41Sopenharmony_ci std::vector<Node*> params; 21821cb0ef41Sopenharmony_ci params.reserve(parameter_count_with_receiver); 21831cb0ef41Sopenharmony_ci for (int i = 0; i < parameter_count_with_receiver; i++) { 21841cb0ef41Sopenharmony_ci params.push_back(node->InputAt(kReceiverInputIndex + i)); 21851cb0ef41Sopenharmony_ci } 21861cb0ef41Sopenharmony_ci const Operator* op_param = common->StateValues( 21871cb0ef41Sopenharmony_ci static_cast<int>(params.size()), SparseInputMask::Dense()); 21881cb0ef41Sopenharmony_ci Node* params_node = graph->NewNode(op_param, static_cast<int>(params.size()), 21891cb0ef41Sopenharmony_ci ¶ms.front()); 21901cb0ef41Sopenharmony_ci DCHECK(context); 21911cb0ef41Sopenharmony_ci return FrameState(graph->NewNode(op, params_node, node0, node0, context, 21921cb0ef41Sopenharmony_ci node->InputAt(kTargetInputIndex), 21931cb0ef41Sopenharmony_ci outer_frame_state)); 21941cb0ef41Sopenharmony_ci} 21951cb0ef41Sopenharmony_ci 21961cb0ef41Sopenharmony_ciFrameState PromiseConstructorFrameState( 21971cb0ef41Sopenharmony_ci const PromiseCtorFrameStateParams& params, CommonOperatorBuilder* common, 21981cb0ef41Sopenharmony_ci Graph* graph) { 21991cb0ef41Sopenharmony_ci DCHECK_EQ(1, 22001cb0ef41Sopenharmony_ci params.shared.internal_formal_parameter_count_without_receiver()); 22011cb0ef41Sopenharmony_ci return CreateArtificialFrameState( 22021cb0ef41Sopenharmony_ci params.node_ptr, params.outer_frame_state, 1, 22031cb0ef41Sopenharmony_ci BytecodeOffset::ConstructStubInvoke(), FrameStateType::kConstructStub, 22041cb0ef41Sopenharmony_ci params.shared, params.context, common, graph); 22051cb0ef41Sopenharmony_ci} 22061cb0ef41Sopenharmony_ci 22071cb0ef41Sopenharmony_ciFrameState PromiseConstructorLazyFrameState( 22081cb0ef41Sopenharmony_ci const PromiseCtorFrameStateParams& params, 22091cb0ef41Sopenharmony_ci FrameState constructor_frame_state) { 22101cb0ef41Sopenharmony_ci // The deopt continuation of this frame state is never called; the frame state 22111cb0ef41Sopenharmony_ci // is only necessary to obtain the right stack trace. 22121cb0ef41Sopenharmony_ci JSGraph* jsgraph = params.jsgraph; 22131cb0ef41Sopenharmony_ci Node* checkpoint_params[] = { 22141cb0ef41Sopenharmony_ci jsgraph->UndefinedConstant(), /* receiver */ 22151cb0ef41Sopenharmony_ci jsgraph->UndefinedConstant(), /* promise */ 22161cb0ef41Sopenharmony_ci jsgraph->UndefinedConstant(), /* reject function */ 22171cb0ef41Sopenharmony_ci jsgraph->TheHoleConstant() /* exception */ 22181cb0ef41Sopenharmony_ci }; 22191cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 22201cb0ef41Sopenharmony_ci jsgraph, params.shared, Builtin::kPromiseConstructorLazyDeoptContinuation, 22211cb0ef41Sopenharmony_ci params.target, params.context, checkpoint_params, 22221cb0ef41Sopenharmony_ci arraysize(checkpoint_params), constructor_frame_state, 22231cb0ef41Sopenharmony_ci ContinuationFrameStateMode::LAZY); 22241cb0ef41Sopenharmony_ci} 22251cb0ef41Sopenharmony_ci 22261cb0ef41Sopenharmony_ciFrameState PromiseConstructorLazyWithCatchFrameState( 22271cb0ef41Sopenharmony_ci const PromiseCtorFrameStateParams& params, 22281cb0ef41Sopenharmony_ci FrameState constructor_frame_state, TNode<JSPromise> promise, 22291cb0ef41Sopenharmony_ci TNode<JSFunction> reject) { 22301cb0ef41Sopenharmony_ci // This continuation just returns the created promise and takes care of 22311cb0ef41Sopenharmony_ci // exceptions thrown by the executor. 22321cb0ef41Sopenharmony_ci Node* checkpoint_params[] = { 22331cb0ef41Sopenharmony_ci params.jsgraph->UndefinedConstant(), /* receiver */ 22341cb0ef41Sopenharmony_ci promise, reject}; 22351cb0ef41Sopenharmony_ci return CreateJavaScriptBuiltinContinuationFrameState( 22361cb0ef41Sopenharmony_ci params.jsgraph, params.shared, 22371cb0ef41Sopenharmony_ci Builtin::kPromiseConstructorLazyDeoptContinuation, params.target, 22381cb0ef41Sopenharmony_ci params.context, checkpoint_params, arraysize(checkpoint_params), 22391cb0ef41Sopenharmony_ci constructor_frame_state, ContinuationFrameStateMode::LAZY_WITH_CATCH); 22401cb0ef41Sopenharmony_ci} 22411cb0ef41Sopenharmony_ci 22421cb0ef41Sopenharmony_ci} // namespace 22431cb0ef41Sopenharmony_ci 22441cb0ef41Sopenharmony_ciTNode<Object> PromiseBuiltinReducerAssembler::ReducePromiseConstructor( 22451cb0ef41Sopenharmony_ci const NativeContextRef& native_context) { 22461cb0ef41Sopenharmony_ci DCHECK_GE(ConstructArity(), 1); 22471cb0ef41Sopenharmony_ci 22481cb0ef41Sopenharmony_ci JSConstructNode n(node_ptr()); 22491cb0ef41Sopenharmony_ci FrameState outer_frame_state = FrameStateInput(); 22501cb0ef41Sopenharmony_ci TNode<Context> context = ContextInput(); 22511cb0ef41Sopenharmony_ci TNode<Object> target = TargetInput(); 22521cb0ef41Sopenharmony_ci TNode<Object> executor = n.Argument(0); 22531cb0ef41Sopenharmony_ci DCHECK_EQ(target, NewTargetInput()); 22541cb0ef41Sopenharmony_ci 22551cb0ef41Sopenharmony_ci SharedFunctionInfoRef promise_shared = 22561cb0ef41Sopenharmony_ci native_context.promise_function().shared(); 22571cb0ef41Sopenharmony_ci 22581cb0ef41Sopenharmony_ci PromiseCtorFrameStateParams frame_state_params{jsgraph(), promise_shared, 22591cb0ef41Sopenharmony_ci node_ptr(), context, 22601cb0ef41Sopenharmony_ci target, outer_frame_state}; 22611cb0ef41Sopenharmony_ci 22621cb0ef41Sopenharmony_ci // Insert a construct stub frame into the chain of frame states. This will 22631cb0ef41Sopenharmony_ci // reconstruct the proper frame when deoptimizing within the constructor. 22641cb0ef41Sopenharmony_ci // For the frame state, we only provide the executor parameter, even if more 22651cb0ef41Sopenharmony_ci // arguments were passed. This is not observable from JS. 22661cb0ef41Sopenharmony_ci FrameState constructor_frame_state = 22671cb0ef41Sopenharmony_ci PromiseConstructorFrameState(frame_state_params, common(), graph()); 22681cb0ef41Sopenharmony_ci 22691cb0ef41Sopenharmony_ci ThrowIfNotCallable(executor, 22701cb0ef41Sopenharmony_ci PromiseConstructorLazyFrameState(frame_state_params, 22711cb0ef41Sopenharmony_ci constructor_frame_state)); 22721cb0ef41Sopenharmony_ci 22731cb0ef41Sopenharmony_ci TNode<JSPromise> promise = CreatePromise(context); 22741cb0ef41Sopenharmony_ci 22751cb0ef41Sopenharmony_ci // 8. CreatePromiseResolvingFunctions 22761cb0ef41Sopenharmony_ci // Allocate a promise context for the closures below. 22771cb0ef41Sopenharmony_ci TNode<Context> promise_context = CreateFunctionContext( 22781cb0ef41Sopenharmony_ci native_context, context, PromiseBuiltins::kPromiseContextLength); 22791cb0ef41Sopenharmony_ci StoreContextSlot(promise_context, PromiseBuiltins::kPromiseSlot, promise); 22801cb0ef41Sopenharmony_ci StoreContextSlot(promise_context, PromiseBuiltins::kAlreadyResolvedSlot, 22811cb0ef41Sopenharmony_ci FalseConstant()); 22821cb0ef41Sopenharmony_ci StoreContextSlot(promise_context, PromiseBuiltins::kDebugEventSlot, 22831cb0ef41Sopenharmony_ci TrueConstant()); 22841cb0ef41Sopenharmony_ci 22851cb0ef41Sopenharmony_ci // Allocate closures for the resolve and reject cases. 22861cb0ef41Sopenharmony_ci SharedFunctionInfoRef resolve_sfi = 22871cb0ef41Sopenharmony_ci MakeRef(broker_, broker_->isolate() 22881cb0ef41Sopenharmony_ci ->factory() 22891cb0ef41Sopenharmony_ci ->promise_capability_default_resolve_shared_fun()); 22901cb0ef41Sopenharmony_ci TNode<JSFunction> resolve = 22911cb0ef41Sopenharmony_ci CreateClosureFromBuiltinSharedFunctionInfo(resolve_sfi, promise_context); 22921cb0ef41Sopenharmony_ci 22931cb0ef41Sopenharmony_ci SharedFunctionInfoRef reject_sfi = 22941cb0ef41Sopenharmony_ci MakeRef(broker_, broker_->isolate() 22951cb0ef41Sopenharmony_ci ->factory() 22961cb0ef41Sopenharmony_ci ->promise_capability_default_reject_shared_fun()); 22971cb0ef41Sopenharmony_ci TNode<JSFunction> reject = 22981cb0ef41Sopenharmony_ci CreateClosureFromBuiltinSharedFunctionInfo(reject_sfi, promise_context); 22991cb0ef41Sopenharmony_ci 23001cb0ef41Sopenharmony_ci FrameState lazy_with_catch_frame_state = 23011cb0ef41Sopenharmony_ci PromiseConstructorLazyWithCatchFrameState( 23021cb0ef41Sopenharmony_ci frame_state_params, constructor_frame_state, promise, reject); 23031cb0ef41Sopenharmony_ci 23041cb0ef41Sopenharmony_ci // 9. Call executor with both resolving functions. 23051cb0ef41Sopenharmony_ci // 10a. Call reject if the call to executor threw. 23061cb0ef41Sopenharmony_ci Try(_ { 23071cb0ef41Sopenharmony_ci CallPromiseExecutor(executor, resolve, reject, lazy_with_catch_frame_state); 23081cb0ef41Sopenharmony_ci }).Catch([&](TNode<Object> exception) { 23091cb0ef41Sopenharmony_ci CallPromiseReject(reject, exception, lazy_with_catch_frame_state); 23101cb0ef41Sopenharmony_ci }); 23111cb0ef41Sopenharmony_ci 23121cb0ef41Sopenharmony_ci return promise; 23131cb0ef41Sopenharmony_ci} 23141cb0ef41Sopenharmony_ci 23151cb0ef41Sopenharmony_ci#undef _ 23161cb0ef41Sopenharmony_ci 23171cb0ef41Sopenharmony_ciReduction JSCallReducer::ReplaceWithSubgraph(JSCallReducerAssembler* gasm, 23181cb0ef41Sopenharmony_ci Node* subgraph) { 23191cb0ef41Sopenharmony_ci // TODO(jgruber): Consider a less fiddly way of integrating the new subgraph 23201cb0ef41Sopenharmony_ci // into the outer graph. For instance, the subgraph could be created in 23211cb0ef41Sopenharmony_ci // complete isolation, and then plugged into the outer graph in one go. 23221cb0ef41Sopenharmony_ci // Instead of manually tracking IfException nodes, we could iterate the 23231cb0ef41Sopenharmony_ci // subgraph. 23241cb0ef41Sopenharmony_ci 23251cb0ef41Sopenharmony_ci // Replace the Call node with the newly-produced subgraph. 23261cb0ef41Sopenharmony_ci ReplaceWithValue(gasm->node_ptr(), subgraph, gasm->effect(), gasm->control()); 23271cb0ef41Sopenharmony_ci 23281cb0ef41Sopenharmony_ci // Wire exception edges contained in the newly-produced subgraph into the 23291cb0ef41Sopenharmony_ci // outer graph. 23301cb0ef41Sopenharmony_ci auto catch_scope = gasm->catch_scope(); 23311cb0ef41Sopenharmony_ci DCHECK(catch_scope->is_outermost()); 23321cb0ef41Sopenharmony_ci 23331cb0ef41Sopenharmony_ci if (catch_scope->has_handler() && 23341cb0ef41Sopenharmony_ci catch_scope->has_exceptional_control_flow()) { 23351cb0ef41Sopenharmony_ci TNode<Object> handler_exception; 23361cb0ef41Sopenharmony_ci Effect handler_effect{nullptr}; 23371cb0ef41Sopenharmony_ci Control handler_control{nullptr}; 23381cb0ef41Sopenharmony_ci gasm->catch_scope()->MergeExceptionalPaths( 23391cb0ef41Sopenharmony_ci &handler_exception, &handler_effect, &handler_control); 23401cb0ef41Sopenharmony_ci 23411cb0ef41Sopenharmony_ci ReplaceWithValue(gasm->outermost_handler(), handler_exception, 23421cb0ef41Sopenharmony_ci handler_effect, handler_control); 23431cb0ef41Sopenharmony_ci } 23441cb0ef41Sopenharmony_ci 23451cb0ef41Sopenharmony_ci return Replace(subgraph); 23461cb0ef41Sopenharmony_ci} 23471cb0ef41Sopenharmony_ci 23481cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceMathUnary(Node* node, const Operator* op) { 23491cb0ef41Sopenharmony_ci JSCallNode n(node); 23501cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 23511cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 23521cb0ef41Sopenharmony_ci return NoChange(); 23531cb0ef41Sopenharmony_ci } 23541cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) { 23551cb0ef41Sopenharmony_ci Node* value = jsgraph()->NaNConstant(); 23561cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 23571cb0ef41Sopenharmony_ci return Replace(value); 23581cb0ef41Sopenharmony_ci } 23591cb0ef41Sopenharmony_ci 23601cb0ef41Sopenharmony_ci JSCallReducerAssembler a(this, node); 23611cb0ef41Sopenharmony_ci Node* subgraph = a.ReduceMathUnary(op); 23621cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 23631cb0ef41Sopenharmony_ci} 23641cb0ef41Sopenharmony_ci 23651cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceMathBinary(Node* node, const Operator* op) { 23661cb0ef41Sopenharmony_ci JSCallNode n(node); 23671cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 23681cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 23691cb0ef41Sopenharmony_ci return NoChange(); 23701cb0ef41Sopenharmony_ci } 23711cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) { 23721cb0ef41Sopenharmony_ci Node* value = jsgraph()->NaNConstant(); 23731cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 23741cb0ef41Sopenharmony_ci return Replace(value); 23751cb0ef41Sopenharmony_ci } 23761cb0ef41Sopenharmony_ci 23771cb0ef41Sopenharmony_ci JSCallReducerAssembler a(this, node); 23781cb0ef41Sopenharmony_ci Node* subgraph = a.ReduceMathBinary(op); 23791cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 23801cb0ef41Sopenharmony_ci} 23811cb0ef41Sopenharmony_ci 23821cb0ef41Sopenharmony_ci// ES6 section 20.2.2.19 Math.imul ( x, y ) 23831cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceMathImul(Node* node) { 23841cb0ef41Sopenharmony_ci JSCallNode n(node); 23851cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 23861cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 23871cb0ef41Sopenharmony_ci return NoChange(); 23881cb0ef41Sopenharmony_ci } 23891cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) { 23901cb0ef41Sopenharmony_ci Node* value = jsgraph()->ZeroConstant(); 23911cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 23921cb0ef41Sopenharmony_ci return Replace(value); 23931cb0ef41Sopenharmony_ci } 23941cb0ef41Sopenharmony_ci Node* left = n.Argument(0); 23951cb0ef41Sopenharmony_ci Node* right = n.ArgumentOr(1, jsgraph()->ZeroConstant()); 23961cb0ef41Sopenharmony_ci Effect effect = n.effect(); 23971cb0ef41Sopenharmony_ci Control control = n.control(); 23981cb0ef41Sopenharmony_ci 23991cb0ef41Sopenharmony_ci left = effect = 24001cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->SpeculativeToNumber( 24011cb0ef41Sopenharmony_ci NumberOperationHint::kNumberOrOddball, p.feedback()), 24021cb0ef41Sopenharmony_ci left, effect, control); 24031cb0ef41Sopenharmony_ci right = effect = 24041cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->SpeculativeToNumber( 24051cb0ef41Sopenharmony_ci NumberOperationHint::kNumberOrOddball, p.feedback()), 24061cb0ef41Sopenharmony_ci right, effect, control); 24071cb0ef41Sopenharmony_ci left = graph()->NewNode(simplified()->NumberToUint32(), left); 24081cb0ef41Sopenharmony_ci right = graph()->NewNode(simplified()->NumberToUint32(), right); 24091cb0ef41Sopenharmony_ci Node* value = graph()->NewNode(simplified()->NumberImul(), left, right); 24101cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect); 24111cb0ef41Sopenharmony_ci return Replace(value); 24121cb0ef41Sopenharmony_ci} 24131cb0ef41Sopenharmony_ci 24141cb0ef41Sopenharmony_ci// ES6 section 20.2.2.11 Math.clz32 ( x ) 24151cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceMathClz32(Node* node) { 24161cb0ef41Sopenharmony_ci JSCallNode n(node); 24171cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 24181cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 24191cb0ef41Sopenharmony_ci return NoChange(); 24201cb0ef41Sopenharmony_ci } 24211cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) { 24221cb0ef41Sopenharmony_ci Node* value = jsgraph()->Constant(32); 24231cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 24241cb0ef41Sopenharmony_ci return Replace(value); 24251cb0ef41Sopenharmony_ci } 24261cb0ef41Sopenharmony_ci Node* input = n.Argument(0); 24271cb0ef41Sopenharmony_ci Effect effect = n.effect(); 24281cb0ef41Sopenharmony_ci Control control = n.control(); 24291cb0ef41Sopenharmony_ci 24301cb0ef41Sopenharmony_ci input = effect = 24311cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->SpeculativeToNumber( 24321cb0ef41Sopenharmony_ci NumberOperationHint::kNumberOrOddball, p.feedback()), 24331cb0ef41Sopenharmony_ci input, effect, control); 24341cb0ef41Sopenharmony_ci input = graph()->NewNode(simplified()->NumberToUint32(), input); 24351cb0ef41Sopenharmony_ci Node* value = graph()->NewNode(simplified()->NumberClz32(), input); 24361cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect); 24371cb0ef41Sopenharmony_ci return Replace(value); 24381cb0ef41Sopenharmony_ci} 24391cb0ef41Sopenharmony_ci 24401cb0ef41Sopenharmony_ci// ES6 section 20.2.2.24 Math.max ( value1, value2, ...values ) 24411cb0ef41Sopenharmony_ci// ES6 section 20.2.2.25 Math.min ( value1, value2, ...values ) 24421cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceMathMinMax(Node* node, const Operator* op, 24431cb0ef41Sopenharmony_ci Node* empty_value) { 24441cb0ef41Sopenharmony_ci JSCallNode n(node); 24451cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 24461cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 24471cb0ef41Sopenharmony_ci return NoChange(); 24481cb0ef41Sopenharmony_ci } 24491cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) { 24501cb0ef41Sopenharmony_ci ReplaceWithValue(node, empty_value); 24511cb0ef41Sopenharmony_ci return Replace(empty_value); 24521cb0ef41Sopenharmony_ci } 24531cb0ef41Sopenharmony_ci Node* effect = NodeProperties::GetEffectInput(node); 24541cb0ef41Sopenharmony_ci Node* control = NodeProperties::GetControlInput(node); 24551cb0ef41Sopenharmony_ci 24561cb0ef41Sopenharmony_ci Node* value = effect = 24571cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->SpeculativeToNumber( 24581cb0ef41Sopenharmony_ci NumberOperationHint::kNumberOrOddball, p.feedback()), 24591cb0ef41Sopenharmony_ci n.Argument(0), effect, control); 24601cb0ef41Sopenharmony_ci for (int i = 1; i < n.ArgumentCount(); i++) { 24611cb0ef41Sopenharmony_ci Node* input = effect = graph()->NewNode( 24621cb0ef41Sopenharmony_ci simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball, 24631cb0ef41Sopenharmony_ci p.feedback()), 24641cb0ef41Sopenharmony_ci n.Argument(i), effect, control); 24651cb0ef41Sopenharmony_ci value = graph()->NewNode(op, value, input); 24661cb0ef41Sopenharmony_ci } 24671cb0ef41Sopenharmony_ci 24681cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect); 24691cb0ef41Sopenharmony_ci return Replace(value); 24701cb0ef41Sopenharmony_ci} 24711cb0ef41Sopenharmony_ci 24721cb0ef41Sopenharmony_ciReduction JSCallReducer::Reduce(Node* node) { 24731cb0ef41Sopenharmony_ci switch (node->opcode()) { 24741cb0ef41Sopenharmony_ci case IrOpcode::kJSConstruct: 24751cb0ef41Sopenharmony_ci return ReduceJSConstruct(node); 24761cb0ef41Sopenharmony_ci case IrOpcode::kJSConstructWithArrayLike: 24771cb0ef41Sopenharmony_ci return ReduceJSConstructWithArrayLike(node); 24781cb0ef41Sopenharmony_ci case IrOpcode::kJSConstructWithSpread: 24791cb0ef41Sopenharmony_ci return ReduceJSConstructWithSpread(node); 24801cb0ef41Sopenharmony_ci case IrOpcode::kJSCall: 24811cb0ef41Sopenharmony_ci return ReduceJSCall(node); 24821cb0ef41Sopenharmony_ci case IrOpcode::kJSCallWithArrayLike: 24831cb0ef41Sopenharmony_ci return ReduceJSCallWithArrayLike(node); 24841cb0ef41Sopenharmony_ci case IrOpcode::kJSCallWithSpread: 24851cb0ef41Sopenharmony_ci return ReduceJSCallWithSpread(node); 24861cb0ef41Sopenharmony_ci default: 24871cb0ef41Sopenharmony_ci break; 24881cb0ef41Sopenharmony_ci } 24891cb0ef41Sopenharmony_ci return NoChange(); 24901cb0ef41Sopenharmony_ci} 24911cb0ef41Sopenharmony_ci 24921cb0ef41Sopenharmony_civoid JSCallReducer::Finalize() { 24931cb0ef41Sopenharmony_ci // TODO(turbofan): This is not the best solution; ideally we would be able 24941cb0ef41Sopenharmony_ci // to teach the GraphReducer about arbitrary dependencies between different 24951cb0ef41Sopenharmony_ci // nodes, even if they don't show up in the use list of the other node. 24961cb0ef41Sopenharmony_ci std::set<Node*> const waitlist = std::move(waitlist_); 24971cb0ef41Sopenharmony_ci for (Node* node : waitlist) { 24981cb0ef41Sopenharmony_ci if (!node->IsDead()) { 24991cb0ef41Sopenharmony_ci Reduction const reduction = Reduce(node); 25001cb0ef41Sopenharmony_ci if (reduction.Changed()) { 25011cb0ef41Sopenharmony_ci Node* replacement = reduction.replacement(); 25021cb0ef41Sopenharmony_ci if (replacement != node) { 25031cb0ef41Sopenharmony_ci Replace(node, replacement); 25041cb0ef41Sopenharmony_ci } 25051cb0ef41Sopenharmony_ci } 25061cb0ef41Sopenharmony_ci } 25071cb0ef41Sopenharmony_ci } 25081cb0ef41Sopenharmony_ci} 25091cb0ef41Sopenharmony_ci 25101cb0ef41Sopenharmony_ci// ES6 section 22.1.1 The Array Constructor 25111cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayConstructor(Node* node) { 25121cb0ef41Sopenharmony_ci JSCallNode n(node); 25131cb0ef41Sopenharmony_ci Node* target = n.target(); 25141cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 25151cb0ef41Sopenharmony_ci 25161cb0ef41Sopenharmony_ci // Turn the {node} into a {JSCreateArray} call. 25171cb0ef41Sopenharmony_ci size_t const arity = p.arity_without_implicit_args(); 25181cb0ef41Sopenharmony_ci node->RemoveInput(n.FeedbackVectorIndex()); 25191cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInput(node, target, 0); 25201cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInput(node, target, 1); 25211cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, 25221cb0ef41Sopenharmony_ci javascript()->CreateArray(arity, base::nullopt)); 25231cb0ef41Sopenharmony_ci return Changed(node); 25241cb0ef41Sopenharmony_ci} 25251cb0ef41Sopenharmony_ci 25261cb0ef41Sopenharmony_ci// ES6 section 19.3.1.1 Boolean ( value ) 25271cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceBooleanConstructor(Node* node) { 25281cb0ef41Sopenharmony_ci // Replace the {node} with a proper {ToBoolean} operator. 25291cb0ef41Sopenharmony_ci JSCallNode n(node); 25301cb0ef41Sopenharmony_ci Node* value = n.ArgumentOrUndefined(0, jsgraph()); 25311cb0ef41Sopenharmony_ci value = graph()->NewNode(simplified()->ToBoolean(), value); 25321cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 25331cb0ef41Sopenharmony_ci return Replace(value); 25341cb0ef41Sopenharmony_ci} 25351cb0ef41Sopenharmony_ci 25361cb0ef41Sopenharmony_ci// ES section #sec-object-constructor 25371cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceObjectConstructor(Node* node) { 25381cb0ef41Sopenharmony_ci JSCallNode n(node); 25391cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) return NoChange(); 25401cb0ef41Sopenharmony_ci Node* value = n.Argument(0); 25411cb0ef41Sopenharmony_ci Effect effect = n.effect(); 25421cb0ef41Sopenharmony_ci 25431cb0ef41Sopenharmony_ci // We can fold away the Object(x) call if |x| is definitely not a primitive. 25441cb0ef41Sopenharmony_ci if (NodeProperties::CanBePrimitive(broker(), value, effect)) { 25451cb0ef41Sopenharmony_ci if (!NodeProperties::CanBeNullOrUndefined(broker(), value, effect)) { 25461cb0ef41Sopenharmony_ci // Turn the {node} into a {JSToObject} call if we know that 25471cb0ef41Sopenharmony_ci // the {value} cannot be null or undefined. 25481cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInputs(node, value); 25491cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, javascript()->ToObject()); 25501cb0ef41Sopenharmony_ci return Changed(node); 25511cb0ef41Sopenharmony_ci } 25521cb0ef41Sopenharmony_ci } else { 25531cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 25541cb0ef41Sopenharmony_ci return Replace(value); 25551cb0ef41Sopenharmony_ci } 25561cb0ef41Sopenharmony_ci return NoChange(); 25571cb0ef41Sopenharmony_ci} 25581cb0ef41Sopenharmony_ci 25591cb0ef41Sopenharmony_ci// ES6 section 19.2.3.1 Function.prototype.apply ( thisArg, argArray ) 25601cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) { 25611cb0ef41Sopenharmony_ci JSCallNode n(node); 25621cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 25631cb0ef41Sopenharmony_ci CallFeedbackRelation new_feedback_relation = 25641cb0ef41Sopenharmony_ci p.feedback_relation() == CallFeedbackRelation::kReceiver 25651cb0ef41Sopenharmony_ci ? CallFeedbackRelation::kTarget 25661cb0ef41Sopenharmony_ci : CallFeedbackRelation::kUnrelated; 25671cb0ef41Sopenharmony_ci int arity = p.arity_without_implicit_args(); 25681cb0ef41Sopenharmony_ci 25691cb0ef41Sopenharmony_ci if (arity < 2) { 25701cb0ef41Sopenharmony_ci // Degenerate cases. 25711cb0ef41Sopenharmony_ci ConvertReceiverMode convert_mode; 25721cb0ef41Sopenharmony_ci if (arity == 0) { 25731cb0ef41Sopenharmony_ci // Neither thisArg nor argArray was provided. 25741cb0ef41Sopenharmony_ci convert_mode = ConvertReceiverMode::kNullOrUndefined; 25751cb0ef41Sopenharmony_ci node->ReplaceInput(n.TargetIndex(), n.receiver()); 25761cb0ef41Sopenharmony_ci node->ReplaceInput(n.ReceiverIndex(), jsgraph()->UndefinedConstant()); 25771cb0ef41Sopenharmony_ci } else { 25781cb0ef41Sopenharmony_ci DCHECK_EQ(arity, 1); 25791cb0ef41Sopenharmony_ci // The argArray was not provided, just remove the {target}. 25801cb0ef41Sopenharmony_ci convert_mode = ConvertReceiverMode::kAny; 25811cb0ef41Sopenharmony_ci node->RemoveInput(n.TargetIndex()); 25821cb0ef41Sopenharmony_ci --arity; 25831cb0ef41Sopenharmony_ci } 25841cb0ef41Sopenharmony_ci // Change {node} to a {JSCall} and try to reduce further. 25851cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 25861cb0ef41Sopenharmony_ci node, javascript()->Call(JSCallNode::ArityForArgc(arity), p.frequency(), 25871cb0ef41Sopenharmony_ci p.feedback(), convert_mode, 25881cb0ef41Sopenharmony_ci p.speculation_mode(), new_feedback_relation)); 25891cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSCall(node)); 25901cb0ef41Sopenharmony_ci } 25911cb0ef41Sopenharmony_ci 25921cb0ef41Sopenharmony_ci // Turn the JSCall into a JSCallWithArrayLike. 25931cb0ef41Sopenharmony_ci // If {argArray} can be null or undefined, we have to generate branches since 25941cb0ef41Sopenharmony_ci // JSCallWithArrayLike would throw for null or undefined. 25951cb0ef41Sopenharmony_ci 25961cb0ef41Sopenharmony_ci Node* target = n.receiver(); 25971cb0ef41Sopenharmony_ci Node* this_argument = n.Argument(0); 25981cb0ef41Sopenharmony_ci Node* arguments_list = n.Argument(1); 25991cb0ef41Sopenharmony_ci Node* context = n.context(); 26001cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 26011cb0ef41Sopenharmony_ci Effect effect = n.effect(); 26021cb0ef41Sopenharmony_ci Control control = n.control(); 26031cb0ef41Sopenharmony_ci 26041cb0ef41Sopenharmony_ci // If {arguments_list} cannot be null or undefined, we don't need 26051cb0ef41Sopenharmony_ci // to expand this {node} to control-flow. 26061cb0ef41Sopenharmony_ci if (!NodeProperties::CanBeNullOrUndefined(broker(), arguments_list, effect)) { 26071cb0ef41Sopenharmony_ci // Massage the value inputs appropriately. 26081cb0ef41Sopenharmony_ci node->ReplaceInput(n.TargetIndex(), target); 26091cb0ef41Sopenharmony_ci node->ReplaceInput(n.ReceiverIndex(), this_argument); 26101cb0ef41Sopenharmony_ci node->ReplaceInput(n.ArgumentIndex(0), arguments_list); 26111cb0ef41Sopenharmony_ci while (arity-- > 1) node->RemoveInput(n.ArgumentIndex(1)); 26121cb0ef41Sopenharmony_ci 26131cb0ef41Sopenharmony_ci // Morph the {node} to a {JSCallWithArrayLike}. 26141cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 26151cb0ef41Sopenharmony_ci node, javascript()->CallWithArrayLike(p.frequency(), p.feedback(), 26161cb0ef41Sopenharmony_ci p.speculation_mode(), 26171cb0ef41Sopenharmony_ci new_feedback_relation)); 26181cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSCallWithArrayLike(node)); 26191cb0ef41Sopenharmony_ci } 26201cb0ef41Sopenharmony_ci 26211cb0ef41Sopenharmony_ci // Check whether {arguments_list} is null. 26221cb0ef41Sopenharmony_ci Node* check_null = 26231cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->ReferenceEqual(), arguments_list, 26241cb0ef41Sopenharmony_ci jsgraph()->NullConstant()); 26251cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Branch(BranchHint::kFalse), check_null, 26261cb0ef41Sopenharmony_ci control); 26271cb0ef41Sopenharmony_ci Node* if_null = graph()->NewNode(common()->IfTrue(), control); 26281cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->IfFalse(), control); 26291cb0ef41Sopenharmony_ci 26301cb0ef41Sopenharmony_ci // Check whether {arguments_list} is undefined. 26311cb0ef41Sopenharmony_ci Node* check_undefined = 26321cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->ReferenceEqual(), arguments_list, 26331cb0ef41Sopenharmony_ci jsgraph()->UndefinedConstant()); 26341cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Branch(BranchHint::kFalse), 26351cb0ef41Sopenharmony_ci check_undefined, control); 26361cb0ef41Sopenharmony_ci Node* if_undefined = graph()->NewNode(common()->IfTrue(), control); 26371cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->IfFalse(), control); 26381cb0ef41Sopenharmony_ci 26391cb0ef41Sopenharmony_ci // Lower to {JSCallWithArrayLike} if {arguments_list} is neither null 26401cb0ef41Sopenharmony_ci // nor undefined. 26411cb0ef41Sopenharmony_ci Node* effect0 = effect; 26421cb0ef41Sopenharmony_ci Node* control0 = control; 26431cb0ef41Sopenharmony_ci Node* value0 = effect0 = control0 = graph()->NewNode( 26441cb0ef41Sopenharmony_ci javascript()->CallWithArrayLike(p.frequency(), p.feedback(), 26451cb0ef41Sopenharmony_ci p.speculation_mode(), 26461cb0ef41Sopenharmony_ci new_feedback_relation), 26471cb0ef41Sopenharmony_ci target, this_argument, arguments_list, n.feedback_vector(), context, 26481cb0ef41Sopenharmony_ci frame_state, effect0, control0); 26491cb0ef41Sopenharmony_ci 26501cb0ef41Sopenharmony_ci // Lower to {JSCall} if {arguments_list} is either null or undefined. 26511cb0ef41Sopenharmony_ci Node* effect1 = effect; 26521cb0ef41Sopenharmony_ci Node* control1 = graph()->NewNode(common()->Merge(2), if_null, if_undefined); 26531cb0ef41Sopenharmony_ci Node* value1 = effect1 = control1 = graph()->NewNode( 26541cb0ef41Sopenharmony_ci javascript()->Call(JSCallNode::ArityForArgc(0)), target, this_argument, 26551cb0ef41Sopenharmony_ci n.feedback_vector(), context, frame_state, effect1, control1); 26561cb0ef41Sopenharmony_ci 26571cb0ef41Sopenharmony_ci // Rewire potential exception edges. 26581cb0ef41Sopenharmony_ci Node* if_exception = nullptr; 26591cb0ef41Sopenharmony_ci if (NodeProperties::IsExceptionalCall(node, &if_exception)) { 26601cb0ef41Sopenharmony_ci // Create appropriate {IfException} and {IfSuccess} nodes. 26611cb0ef41Sopenharmony_ci Node* if_exception0 = 26621cb0ef41Sopenharmony_ci graph()->NewNode(common()->IfException(), control0, effect0); 26631cb0ef41Sopenharmony_ci control0 = graph()->NewNode(common()->IfSuccess(), control0); 26641cb0ef41Sopenharmony_ci Node* if_exception1 = 26651cb0ef41Sopenharmony_ci graph()->NewNode(common()->IfException(), control1, effect1); 26661cb0ef41Sopenharmony_ci control1 = graph()->NewNode(common()->IfSuccess(), control1); 26671cb0ef41Sopenharmony_ci 26681cb0ef41Sopenharmony_ci // Join the exception edges. 26691cb0ef41Sopenharmony_ci Node* merge = 26701cb0ef41Sopenharmony_ci graph()->NewNode(common()->Merge(2), if_exception0, if_exception1); 26711cb0ef41Sopenharmony_ci Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception0, 26721cb0ef41Sopenharmony_ci if_exception1, merge); 26731cb0ef41Sopenharmony_ci Node* phi = 26741cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 26751cb0ef41Sopenharmony_ci if_exception0, if_exception1, merge); 26761cb0ef41Sopenharmony_ci ReplaceWithValue(if_exception, phi, ephi, merge); 26771cb0ef41Sopenharmony_ci } 26781cb0ef41Sopenharmony_ci 26791cb0ef41Sopenharmony_ci // Join control paths. 26801cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Merge(2), control0, control1); 26811cb0ef41Sopenharmony_ci effect = graph()->NewNode(common()->EffectPhi(2), effect0, effect1, control); 26821cb0ef41Sopenharmony_ci Node* value = 26831cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), value0, 26841cb0ef41Sopenharmony_ci value1, control); 26851cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 26861cb0ef41Sopenharmony_ci return Replace(value); 26871cb0ef41Sopenharmony_ci} 26881cb0ef41Sopenharmony_ci 26891cb0ef41Sopenharmony_ci// ES section #sec-function.prototype.bind 26901cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) { 26911cb0ef41Sopenharmony_ci JSCallNode n(node); 26921cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 26931cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 26941cb0ef41Sopenharmony_ci return NoChange(); 26951cb0ef41Sopenharmony_ci } 26961cb0ef41Sopenharmony_ci 26971cb0ef41Sopenharmony_ci // Value inputs to the {node} are as follows: 26981cb0ef41Sopenharmony_ci // 26991cb0ef41Sopenharmony_ci // - target, which is Function.prototype.bind JSFunction 27001cb0ef41Sopenharmony_ci // - receiver, which is the [[BoundTargetFunction]] 27011cb0ef41Sopenharmony_ci // - bound_this (optional), which is the [[BoundThis]] 27021cb0ef41Sopenharmony_ci // - and all the remaining value inputs are [[BoundArguments]] 27031cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 27041cb0ef41Sopenharmony_ci Node* context = n.context(); 27051cb0ef41Sopenharmony_ci Effect effect = n.effect(); 27061cb0ef41Sopenharmony_ci Control control = n.control(); 27071cb0ef41Sopenharmony_ci 27081cb0ef41Sopenharmony_ci // Ensure that the {receiver} is known to be a JSBoundFunction or 27091cb0ef41Sopenharmony_ci // a JSFunction with the same [[Prototype]], and all maps we've 27101cb0ef41Sopenharmony_ci // seen for the {receiver} so far indicate that {receiver} is 27111cb0ef41Sopenharmony_ci // definitely a constructor or not a constructor. 27121cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 27131cb0ef41Sopenharmony_ci if (!inference.HaveMaps()) return NoChange(); 27141cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& receiver_maps = inference.GetMaps(); 27151cb0ef41Sopenharmony_ci 27161cb0ef41Sopenharmony_ci MapRef first_receiver_map = receiver_maps[0]; 27171cb0ef41Sopenharmony_ci bool const is_constructor = first_receiver_map.is_constructor(); 27181cb0ef41Sopenharmony_ci 27191cb0ef41Sopenharmony_ci HeapObjectRef prototype = first_receiver_map.prototype(); 27201cb0ef41Sopenharmony_ci 27211cb0ef41Sopenharmony_ci for (const MapRef& receiver_map : receiver_maps) { 27221cb0ef41Sopenharmony_ci HeapObjectRef map_prototype = receiver_map.prototype(); 27231cb0ef41Sopenharmony_ci 27241cb0ef41Sopenharmony_ci // Check for consistency among the {receiver_maps}. 27251cb0ef41Sopenharmony_ci if (!map_prototype.equals(prototype) || 27261cb0ef41Sopenharmony_ci receiver_map.is_constructor() != is_constructor || 27271cb0ef41Sopenharmony_ci !InstanceTypeChecker::IsJSFunctionOrBoundFunctionOrWrappedFunction( 27281cb0ef41Sopenharmony_ci receiver_map.instance_type())) { 27291cb0ef41Sopenharmony_ci return inference.NoChange(); 27301cb0ef41Sopenharmony_ci } 27311cb0ef41Sopenharmony_ci 27321cb0ef41Sopenharmony_ci // Disallow binding of slow-mode functions. We need to figure out 27331cb0ef41Sopenharmony_ci // whether the length and name property are in the original state. 27341cb0ef41Sopenharmony_ci if (receiver_map.is_dictionary_map()) return inference.NoChange(); 27351cb0ef41Sopenharmony_ci 27361cb0ef41Sopenharmony_ci // Check whether the length and name properties are still present 27371cb0ef41Sopenharmony_ci // as AccessorInfo objects. In that case, their values can be 27381cb0ef41Sopenharmony_ci // recomputed even if the actual value of the object changes. 27391cb0ef41Sopenharmony_ci // This mirrors the checks done in builtins-function-gen.cc at 27401cb0ef41Sopenharmony_ci // runtime otherwise. 27411cb0ef41Sopenharmony_ci int minimum_nof_descriptors = 27421cb0ef41Sopenharmony_ci std::max( 27431cb0ef41Sopenharmony_ci {JSFunctionOrBoundFunctionOrWrappedFunction::kLengthDescriptorIndex, 27441cb0ef41Sopenharmony_ci JSFunctionOrBoundFunctionOrWrappedFunction:: 27451cb0ef41Sopenharmony_ci kNameDescriptorIndex}) + 27461cb0ef41Sopenharmony_ci 1; 27471cb0ef41Sopenharmony_ci if (receiver_map.NumberOfOwnDescriptors() < minimum_nof_descriptors) { 27481cb0ef41Sopenharmony_ci return inference.NoChange(); 27491cb0ef41Sopenharmony_ci } 27501cb0ef41Sopenharmony_ci const InternalIndex kLengthIndex( 27511cb0ef41Sopenharmony_ci JSFunctionOrBoundFunctionOrWrappedFunction::kLengthDescriptorIndex); 27521cb0ef41Sopenharmony_ci const InternalIndex kNameIndex( 27531cb0ef41Sopenharmony_ci JSFunctionOrBoundFunctionOrWrappedFunction::kNameDescriptorIndex); 27541cb0ef41Sopenharmony_ci ReadOnlyRoots roots(isolate()); 27551cb0ef41Sopenharmony_ci StringRef length_string = MakeRef(broker(), roots.length_string_handle()); 27561cb0ef41Sopenharmony_ci StringRef name_string = MakeRef(broker(), roots.name_string_handle()); 27571cb0ef41Sopenharmony_ci 27581cb0ef41Sopenharmony_ci base::Optional<ObjectRef> length_value( 27591cb0ef41Sopenharmony_ci receiver_map.GetStrongValue(kLengthIndex)); 27601cb0ef41Sopenharmony_ci base::Optional<ObjectRef> name_value( 27611cb0ef41Sopenharmony_ci receiver_map.GetStrongValue(kNameIndex)); 27621cb0ef41Sopenharmony_ci if (!length_value || !name_value) { 27631cb0ef41Sopenharmony_ci TRACE_BROKER_MISSING( 27641cb0ef41Sopenharmony_ci broker(), "name or length descriptors on map " << receiver_map); 27651cb0ef41Sopenharmony_ci return inference.NoChange(); 27661cb0ef41Sopenharmony_ci } 27671cb0ef41Sopenharmony_ci if (!receiver_map.GetPropertyKey(kLengthIndex).equals(length_string) || 27681cb0ef41Sopenharmony_ci !length_value->IsAccessorInfo() || 27691cb0ef41Sopenharmony_ci !receiver_map.GetPropertyKey(kNameIndex).equals(name_string) || 27701cb0ef41Sopenharmony_ci !name_value->IsAccessorInfo()) { 27711cb0ef41Sopenharmony_ci return inference.NoChange(); 27721cb0ef41Sopenharmony_ci } 27731cb0ef41Sopenharmony_ci } 27741cb0ef41Sopenharmony_ci 27751cb0ef41Sopenharmony_ci // Choose the map for the resulting JSBoundFunction (but bail out in case of a 27761cb0ef41Sopenharmony_ci // custom prototype). 27771cb0ef41Sopenharmony_ci MapRef map = is_constructor 27781cb0ef41Sopenharmony_ci ? native_context().bound_function_with_constructor_map() 27791cb0ef41Sopenharmony_ci : native_context().bound_function_without_constructor_map(); 27801cb0ef41Sopenharmony_ci if (!map.prototype().equals(prototype)) return inference.NoChange(); 27811cb0ef41Sopenharmony_ci 27821cb0ef41Sopenharmony_ci inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect, 27831cb0ef41Sopenharmony_ci control, p.feedback()); 27841cb0ef41Sopenharmony_ci 27851cb0ef41Sopenharmony_ci // Replace the {node} with a JSCreateBoundFunction. 27861cb0ef41Sopenharmony_ci static constexpr int kBoundThis = 1; 27871cb0ef41Sopenharmony_ci static constexpr int kReceiverContextEffectAndControl = 4; 27881cb0ef41Sopenharmony_ci int const arity = n.ArgumentCount(); 27891cb0ef41Sopenharmony_ci 27901cb0ef41Sopenharmony_ci if (arity > 0) { 27911cb0ef41Sopenharmony_ci MapRef fixed_array_map = MakeRef(broker(), factory()->fixed_array_map()); 27921cb0ef41Sopenharmony_ci AllocationBuilder ab(jsgraph(), effect, control); 27931cb0ef41Sopenharmony_ci if (!ab.CanAllocateArray(arity, fixed_array_map)) { 27941cb0ef41Sopenharmony_ci return NoChange(); 27951cb0ef41Sopenharmony_ci } 27961cb0ef41Sopenharmony_ci } 27971cb0ef41Sopenharmony_ci 27981cb0ef41Sopenharmony_ci int const arity_with_bound_this = std::max(arity, kBoundThis); 27991cb0ef41Sopenharmony_ci int const input_count = 28001cb0ef41Sopenharmony_ci arity_with_bound_this + kReceiverContextEffectAndControl; 28011cb0ef41Sopenharmony_ci Node** inputs = graph()->zone()->NewArray<Node*>(input_count); 28021cb0ef41Sopenharmony_ci int cursor = 0; 28031cb0ef41Sopenharmony_ci inputs[cursor++] = receiver; 28041cb0ef41Sopenharmony_ci inputs[cursor++] = n.ArgumentOrUndefined(0, jsgraph()); // bound_this. 28051cb0ef41Sopenharmony_ci for (int i = 1; i < arity; ++i) { 28061cb0ef41Sopenharmony_ci inputs[cursor++] = n.Argument(i); 28071cb0ef41Sopenharmony_ci } 28081cb0ef41Sopenharmony_ci inputs[cursor++] = context; 28091cb0ef41Sopenharmony_ci inputs[cursor++] = effect; 28101cb0ef41Sopenharmony_ci inputs[cursor++] = control; 28111cb0ef41Sopenharmony_ci DCHECK_EQ(cursor, input_count); 28121cb0ef41Sopenharmony_ci Node* value = effect = 28131cb0ef41Sopenharmony_ci graph()->NewNode(javascript()->CreateBoundFunction( 28141cb0ef41Sopenharmony_ci arity_with_bound_this - kBoundThis, map), 28151cb0ef41Sopenharmony_ci input_count, inputs); 28161cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 28171cb0ef41Sopenharmony_ci return Replace(value); 28181cb0ef41Sopenharmony_ci} 28191cb0ef41Sopenharmony_ci 28201cb0ef41Sopenharmony_ci// ES6 section 19.2.3.3 Function.prototype.call (thisArg, ...args) 28211cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) { 28221cb0ef41Sopenharmony_ci JSCallNode n(node); 28231cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 28241cb0ef41Sopenharmony_ci Node* target = n.target(); 28251cb0ef41Sopenharmony_ci Effect effect = n.effect(); 28261cb0ef41Sopenharmony_ci Control control = n.control(); 28271cb0ef41Sopenharmony_ci 28281cb0ef41Sopenharmony_ci // Change context of {node} to the Function.prototype.call context, 28291cb0ef41Sopenharmony_ci // to ensure any exception is thrown in the correct context. 28301cb0ef41Sopenharmony_ci Node* context; 28311cb0ef41Sopenharmony_ci HeapObjectMatcher m(target); 28321cb0ef41Sopenharmony_ci if (m.HasResolvedValue() && m.Ref(broker()).IsJSFunction()) { 28331cb0ef41Sopenharmony_ci JSFunctionRef function = m.Ref(broker()).AsJSFunction(); 28341cb0ef41Sopenharmony_ci context = jsgraph()->Constant(function.context()); 28351cb0ef41Sopenharmony_ci } else { 28361cb0ef41Sopenharmony_ci context = effect = graph()->NewNode( 28371cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSFunctionContext()), target, 28381cb0ef41Sopenharmony_ci effect, control); 28391cb0ef41Sopenharmony_ci } 28401cb0ef41Sopenharmony_ci NodeProperties::ReplaceContextInput(node, context); 28411cb0ef41Sopenharmony_ci NodeProperties::ReplaceEffectInput(node, effect); 28421cb0ef41Sopenharmony_ci 28431cb0ef41Sopenharmony_ci // Remove the target from {node} and use the receiver as target instead, and 28441cb0ef41Sopenharmony_ci // the thisArg becomes the new target. If thisArg was not provided, insert 28451cb0ef41Sopenharmony_ci // undefined instead. 28461cb0ef41Sopenharmony_ci int arity = p.arity_without_implicit_args(); 28471cb0ef41Sopenharmony_ci ConvertReceiverMode convert_mode; 28481cb0ef41Sopenharmony_ci if (arity == 0) { 28491cb0ef41Sopenharmony_ci // The thisArg was not provided, use undefined as receiver. 28501cb0ef41Sopenharmony_ci convert_mode = ConvertReceiverMode::kNullOrUndefined; 28511cb0ef41Sopenharmony_ci node->ReplaceInput(n.TargetIndex(), n.receiver()); 28521cb0ef41Sopenharmony_ci node->ReplaceInput(n.ReceiverIndex(), jsgraph()->UndefinedConstant()); 28531cb0ef41Sopenharmony_ci } else { 28541cb0ef41Sopenharmony_ci // Just remove the target, which is the first value input. 28551cb0ef41Sopenharmony_ci convert_mode = ConvertReceiverMode::kAny; 28561cb0ef41Sopenharmony_ci node->RemoveInput(n.TargetIndex()); 28571cb0ef41Sopenharmony_ci --arity; 28581cb0ef41Sopenharmony_ci } 28591cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 28601cb0ef41Sopenharmony_ci node, javascript()->Call(JSCallNode::ArityForArgc(arity), p.frequency(), 28611cb0ef41Sopenharmony_ci p.feedback(), convert_mode, p.speculation_mode(), 28621cb0ef41Sopenharmony_ci CallFeedbackRelation::kUnrelated)); 28631cb0ef41Sopenharmony_ci // Try to further reduce the JSCall {node}. 28641cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSCall(node)); 28651cb0ef41Sopenharmony_ci} 28661cb0ef41Sopenharmony_ci 28671cb0ef41Sopenharmony_ci// ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] (V) 28681cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceFunctionPrototypeHasInstance(Node* node) { 28691cb0ef41Sopenharmony_ci JSCallNode n(node); 28701cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 28711cb0ef41Sopenharmony_ci Node* object = n.ArgumentOrUndefined(0, jsgraph()); 28721cb0ef41Sopenharmony_ci Node* context = n.context(); 28731cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 28741cb0ef41Sopenharmony_ci Effect effect = n.effect(); 28751cb0ef41Sopenharmony_ci Control control = n.control(); 28761cb0ef41Sopenharmony_ci 28771cb0ef41Sopenharmony_ci // TODO(turbofan): If JSOrdinaryToInstance raises an exception, the 28781cb0ef41Sopenharmony_ci // stack trace doesn't contain the @@hasInstance call; we have the 28791cb0ef41Sopenharmony_ci // corresponding bug in the baseline case. Some massaging of the frame 28801cb0ef41Sopenharmony_ci // state would be necessary here. 28811cb0ef41Sopenharmony_ci 28821cb0ef41Sopenharmony_ci // Morph this {node} into a JSOrdinaryHasInstance node. 28831cb0ef41Sopenharmony_ci node->ReplaceInput(0, receiver); 28841cb0ef41Sopenharmony_ci node->ReplaceInput(1, object); 28851cb0ef41Sopenharmony_ci node->ReplaceInput(2, context); 28861cb0ef41Sopenharmony_ci node->ReplaceInput(3, frame_state); 28871cb0ef41Sopenharmony_ci node->ReplaceInput(4, effect); 28881cb0ef41Sopenharmony_ci node->ReplaceInput(5, control); 28891cb0ef41Sopenharmony_ci node->TrimInputCount(6); 28901cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance()); 28911cb0ef41Sopenharmony_ci return Changed(node); 28921cb0ef41Sopenharmony_ci} 28931cb0ef41Sopenharmony_ci 28941cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceObjectGetPrototype(Node* node, Node* object) { 28951cb0ef41Sopenharmony_ci Effect effect{NodeProperties::GetEffectInput(node)}; 28961cb0ef41Sopenharmony_ci 28971cb0ef41Sopenharmony_ci // Try to determine the {object} map. 28981cb0ef41Sopenharmony_ci MapInference inference(broker(), object, effect); 28991cb0ef41Sopenharmony_ci if (!inference.HaveMaps()) return NoChange(); 29001cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& object_maps = inference.GetMaps(); 29011cb0ef41Sopenharmony_ci 29021cb0ef41Sopenharmony_ci MapRef candidate_map = object_maps[0]; 29031cb0ef41Sopenharmony_ci HeapObjectRef candidate_prototype = candidate_map.prototype(); 29041cb0ef41Sopenharmony_ci 29051cb0ef41Sopenharmony_ci // Check if we can constant-fold the {candidate_prototype}. 29061cb0ef41Sopenharmony_ci for (size_t i = 0; i < object_maps.size(); ++i) { 29071cb0ef41Sopenharmony_ci MapRef object_map = object_maps[i]; 29081cb0ef41Sopenharmony_ci HeapObjectRef map_prototype = object_map.prototype(); 29091cb0ef41Sopenharmony_ci if (IsSpecialReceiverInstanceType(object_map.instance_type()) || 29101cb0ef41Sopenharmony_ci !map_prototype.equals(candidate_prototype)) { 29111cb0ef41Sopenharmony_ci // We exclude special receivers, like JSProxy or API objects that 29121cb0ef41Sopenharmony_ci // might require access checks here; we also don't want to deal 29131cb0ef41Sopenharmony_ci // with hidden prototypes at this point. 29141cb0ef41Sopenharmony_ci return inference.NoChange(); 29151cb0ef41Sopenharmony_ci } 29161cb0ef41Sopenharmony_ci // The above check also excludes maps for primitive values, which is 29171cb0ef41Sopenharmony_ci // important because we are not applying [[ToObject]] here as expected. 29181cb0ef41Sopenharmony_ci DCHECK(!object_map.IsPrimitiveMap() && object_map.IsJSReceiverMap()); 29191cb0ef41Sopenharmony_ci } 29201cb0ef41Sopenharmony_ci if (!inference.RelyOnMapsViaStability(dependencies())) { 29211cb0ef41Sopenharmony_ci return inference.NoChange(); 29221cb0ef41Sopenharmony_ci } 29231cb0ef41Sopenharmony_ci Node* value = jsgraph()->Constant(candidate_prototype); 29241cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 29251cb0ef41Sopenharmony_ci return Replace(value); 29261cb0ef41Sopenharmony_ci} 29271cb0ef41Sopenharmony_ci 29281cb0ef41Sopenharmony_ci// ES6 section 19.1.2.11 Object.getPrototypeOf ( O ) 29291cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceObjectGetPrototypeOf(Node* node) { 29301cb0ef41Sopenharmony_ci JSCallNode n(node); 29311cb0ef41Sopenharmony_ci Node* object = n.ArgumentOrUndefined(0, jsgraph()); 29321cb0ef41Sopenharmony_ci return ReduceObjectGetPrototype(node, object); 29331cb0ef41Sopenharmony_ci} 29341cb0ef41Sopenharmony_ci 29351cb0ef41Sopenharmony_ci// ES section #sec-object.is 29361cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceObjectIs(Node* node) { 29371cb0ef41Sopenharmony_ci JSCallNode n(node); 29381cb0ef41Sopenharmony_ci Node* lhs = n.ArgumentOrUndefined(0, jsgraph()); 29391cb0ef41Sopenharmony_ci Node* rhs = n.ArgumentOrUndefined(1, jsgraph()); 29401cb0ef41Sopenharmony_ci Node* value = graph()->NewNode(simplified()->SameValue(), lhs, rhs); 29411cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 29421cb0ef41Sopenharmony_ci return Replace(value); 29431cb0ef41Sopenharmony_ci} 29441cb0ef41Sopenharmony_ci 29451cb0ef41Sopenharmony_ci// ES6 section B.2.2.1.1 get Object.prototype.__proto__ 29461cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) { 29471cb0ef41Sopenharmony_ci JSCallNode n(node); 29481cb0ef41Sopenharmony_ci return ReduceObjectGetPrototype(node, n.receiver()); 29491cb0ef41Sopenharmony_ci} 29501cb0ef41Sopenharmony_ci 29511cb0ef41Sopenharmony_ci// ES #sec-object.prototype.hasownproperty 29521cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceObjectPrototypeHasOwnProperty(Node* node) { 29531cb0ef41Sopenharmony_ci JSCallNode call_node(node); 29541cb0ef41Sopenharmony_ci Node* receiver = call_node.receiver(); 29551cb0ef41Sopenharmony_ci Node* name = call_node.ArgumentOrUndefined(0, jsgraph()); 29561cb0ef41Sopenharmony_ci Effect effect = call_node.effect(); 29571cb0ef41Sopenharmony_ci Control control = call_node.control(); 29581cb0ef41Sopenharmony_ci 29591cb0ef41Sopenharmony_ci // We can optimize a call to Object.prototype.hasOwnProperty if it's being 29601cb0ef41Sopenharmony_ci // used inside a fast-mode for..in, so for code like this: 29611cb0ef41Sopenharmony_ci // 29621cb0ef41Sopenharmony_ci // for (name in receiver) { 29631cb0ef41Sopenharmony_ci // if (receiver.hasOwnProperty(name)) { 29641cb0ef41Sopenharmony_ci // ... 29651cb0ef41Sopenharmony_ci // } 29661cb0ef41Sopenharmony_ci // } 29671cb0ef41Sopenharmony_ci // 29681cb0ef41Sopenharmony_ci // If the for..in is in fast-mode, we know that the {receiver} has {name} 29691cb0ef41Sopenharmony_ci // as own property, otherwise the enumeration wouldn't include it. The graph 29701cb0ef41Sopenharmony_ci // constructed by the BytecodeGraphBuilder in this case looks like this: 29711cb0ef41Sopenharmony_ci 29721cb0ef41Sopenharmony_ci // receiver 29731cb0ef41Sopenharmony_ci // ^ ^ 29741cb0ef41Sopenharmony_ci // | | 29751cb0ef41Sopenharmony_ci // | +-+ 29761cb0ef41Sopenharmony_ci // | | 29771cb0ef41Sopenharmony_ci // | JSToObject 29781cb0ef41Sopenharmony_ci // | ^ 29791cb0ef41Sopenharmony_ci // | | 29801cb0ef41Sopenharmony_ci // | JSForInNext 29811cb0ef41Sopenharmony_ci // | ^ 29821cb0ef41Sopenharmony_ci // +----+ | 29831cb0ef41Sopenharmony_ci // | | 29841cb0ef41Sopenharmony_ci // JSCall[hasOwnProperty] 29851cb0ef41Sopenharmony_ci 29861cb0ef41Sopenharmony_ci // We can constant-fold the {node} to True in this case, and insert 29871cb0ef41Sopenharmony_ci // a (potentially redundant) map check to guard the fact that the 29881cb0ef41Sopenharmony_ci // {receiver} map didn't change since the dominating JSForInNext. This 29891cb0ef41Sopenharmony_ci // map check is only necessary when TurboFan cannot prove that there 29901cb0ef41Sopenharmony_ci // is no observable side effect between the {JSForInNext} and the 29911cb0ef41Sopenharmony_ci // {JSCall} to Object.prototype.hasOwnProperty. 29921cb0ef41Sopenharmony_ci // 29931cb0ef41Sopenharmony_ci // Also note that it's safe to look through the {JSToObject}, since the 29941cb0ef41Sopenharmony_ci // Object.prototype.hasOwnProperty does an implicit ToObject anyway, and 29951cb0ef41Sopenharmony_ci // these operations are not observable. 29961cb0ef41Sopenharmony_ci if (name->opcode() == IrOpcode::kJSForInNext) { 29971cb0ef41Sopenharmony_ci JSForInNextNode n(name); 29981cb0ef41Sopenharmony_ci if (n.Parameters().mode() != ForInMode::kGeneric) { 29991cb0ef41Sopenharmony_ci Node* object = n.receiver(); 30001cb0ef41Sopenharmony_ci Node* cache_type = n.cache_type(); 30011cb0ef41Sopenharmony_ci if (object->opcode() == IrOpcode::kJSToObject) { 30021cb0ef41Sopenharmony_ci object = NodeProperties::GetValueInput(object, 0); 30031cb0ef41Sopenharmony_ci } 30041cb0ef41Sopenharmony_ci if (object == receiver) { 30051cb0ef41Sopenharmony_ci // No need to repeat the map check if we can prove that there's no 30061cb0ef41Sopenharmony_ci // observable side effect between {effect} and {name]. 30071cb0ef41Sopenharmony_ci if (!NodeProperties::NoObservableSideEffectBetween(effect, name)) { 30081cb0ef41Sopenharmony_ci Node* receiver_map = effect = 30091cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 30101cb0ef41Sopenharmony_ci receiver, effect, control); 30111cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->ReferenceEqual(), 30121cb0ef41Sopenharmony_ci receiver_map, cache_type); 30131cb0ef41Sopenharmony_ci effect = graph()->NewNode( 30141cb0ef41Sopenharmony_ci simplified()->CheckIf(DeoptimizeReason::kWrongMap), check, effect, 30151cb0ef41Sopenharmony_ci control); 30161cb0ef41Sopenharmony_ci } 30171cb0ef41Sopenharmony_ci Node* value = jsgraph()->TrueConstant(); 30181cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 30191cb0ef41Sopenharmony_ci return Replace(value); 30201cb0ef41Sopenharmony_ci } 30211cb0ef41Sopenharmony_ci } 30221cb0ef41Sopenharmony_ci } 30231cb0ef41Sopenharmony_ci 30241cb0ef41Sopenharmony_ci return NoChange(); 30251cb0ef41Sopenharmony_ci} 30261cb0ef41Sopenharmony_ci 30271cb0ef41Sopenharmony_ci// ES #sec-object.prototype.isprototypeof 30281cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceObjectPrototypeIsPrototypeOf(Node* node) { 30291cb0ef41Sopenharmony_ci JSCallNode n(node); 30301cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 30311cb0ef41Sopenharmony_ci Node* value = n.ArgumentOrUndefined(0, jsgraph()); 30321cb0ef41Sopenharmony_ci Effect effect = n.effect(); 30331cb0ef41Sopenharmony_ci 30341cb0ef41Sopenharmony_ci // Ensure that the {receiver} is known to be a JSReceiver (so that 30351cb0ef41Sopenharmony_ci // the ToObject step of Object.prototype.isPrototypeOf is a no-op). 30361cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 30371cb0ef41Sopenharmony_ci if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAreJSReceiver()) { 30381cb0ef41Sopenharmony_ci return NoChange(); 30391cb0ef41Sopenharmony_ci } 30401cb0ef41Sopenharmony_ci 30411cb0ef41Sopenharmony_ci // We don't check whether {value} is a proper JSReceiver here explicitly, 30421cb0ef41Sopenharmony_ci // and don't explicitly rule out Primitive {value}s, since all of them 30431cb0ef41Sopenharmony_ci // have null as their prototype, so the prototype chain walk inside the 30441cb0ef41Sopenharmony_ci // JSHasInPrototypeChain operator immediately aborts and yields false. 30451cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInput(node, value, n.TargetIndex()); 30461cb0ef41Sopenharmony_ci for (int i = node->op()->ValueInputCount(); i > 2; i--) { 30471cb0ef41Sopenharmony_ci node->RemoveInput(2); 30481cb0ef41Sopenharmony_ci } 30491cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, javascript()->HasInPrototypeChain()); 30501cb0ef41Sopenharmony_ci return Changed(node); 30511cb0ef41Sopenharmony_ci} 30521cb0ef41Sopenharmony_ci 30531cb0ef41Sopenharmony_ci// ES6 section 26.1.1 Reflect.apply ( target, thisArgument, argumentsList ) 30541cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceReflectApply(Node* node) { 30551cb0ef41Sopenharmony_ci JSCallNode n(node); 30561cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 30571cb0ef41Sopenharmony_ci int arity = p.arity_without_implicit_args(); 30581cb0ef41Sopenharmony_ci // Massage value inputs appropriately. 30591cb0ef41Sopenharmony_ci STATIC_ASSERT(n.ReceiverIndex() > n.TargetIndex()); 30601cb0ef41Sopenharmony_ci node->RemoveInput(n.ReceiverIndex()); 30611cb0ef41Sopenharmony_ci node->RemoveInput(n.TargetIndex()); 30621cb0ef41Sopenharmony_ci while (arity < 3) { 30631cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), arity++, jsgraph()->UndefinedConstant()); 30641cb0ef41Sopenharmony_ci } 30651cb0ef41Sopenharmony_ci while (arity-- > 3) { 30661cb0ef41Sopenharmony_ci node->RemoveInput(arity); 30671cb0ef41Sopenharmony_ci } 30681cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 30691cb0ef41Sopenharmony_ci node, javascript()->CallWithArrayLike(p.frequency(), p.feedback(), 30701cb0ef41Sopenharmony_ci p.speculation_mode(), 30711cb0ef41Sopenharmony_ci CallFeedbackRelation::kUnrelated)); 30721cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSCallWithArrayLike(node)); 30731cb0ef41Sopenharmony_ci} 30741cb0ef41Sopenharmony_ci 30751cb0ef41Sopenharmony_ci// ES6 section 26.1.2 Reflect.construct ( target, argumentsList [, newTarget] ) 30761cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceReflectConstruct(Node* node) { 30771cb0ef41Sopenharmony_ci JSCallNode n(node); 30781cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 30791cb0ef41Sopenharmony_ci int arity = p.arity_without_implicit_args(); 30801cb0ef41Sopenharmony_ci // Massage value inputs appropriately. 30811cb0ef41Sopenharmony_ci Node* arg_target = n.ArgumentOrUndefined(0, jsgraph()); 30821cb0ef41Sopenharmony_ci Node* arg_argument_list = n.ArgumentOrUndefined(1, jsgraph()); 30831cb0ef41Sopenharmony_ci Node* arg_new_target = n.ArgumentOr(2, arg_target); 30841cb0ef41Sopenharmony_ci 30851cb0ef41Sopenharmony_ci STATIC_ASSERT(n.ReceiverIndex() > n.TargetIndex()); 30861cb0ef41Sopenharmony_ci node->RemoveInput(n.ReceiverIndex()); 30871cb0ef41Sopenharmony_ci node->RemoveInput(n.TargetIndex()); 30881cb0ef41Sopenharmony_ci 30891cb0ef41Sopenharmony_ci // TODO(jgruber): This pattern essentially ensures that we have the correct 30901cb0ef41Sopenharmony_ci // number of inputs for a given argument count. Wrap it in a helper function. 30911cb0ef41Sopenharmony_ci STATIC_ASSERT(JSConstructNode::FirstArgumentIndex() == 2); 30921cb0ef41Sopenharmony_ci while (arity < 3) { 30931cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), arity++, jsgraph()->UndefinedConstant()); 30941cb0ef41Sopenharmony_ci } 30951cb0ef41Sopenharmony_ci while (arity-- > 3) { 30961cb0ef41Sopenharmony_ci node->RemoveInput(arity); 30971cb0ef41Sopenharmony_ci } 30981cb0ef41Sopenharmony_ci 30991cb0ef41Sopenharmony_ci STATIC_ASSERT(JSConstructNode::TargetIndex() == 0); 31001cb0ef41Sopenharmony_ci STATIC_ASSERT(JSConstructNode::NewTargetIndex() == 1); 31011cb0ef41Sopenharmony_ci STATIC_ASSERT(JSConstructNode::kFeedbackVectorIsLastInput); 31021cb0ef41Sopenharmony_ci node->ReplaceInput(JSConstructNode::TargetIndex(), arg_target); 31031cb0ef41Sopenharmony_ci node->ReplaceInput(JSConstructNode::NewTargetIndex(), arg_new_target); 31041cb0ef41Sopenharmony_ci node->ReplaceInput(JSConstructNode::ArgumentIndex(0), arg_argument_list); 31051cb0ef41Sopenharmony_ci 31061cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 31071cb0ef41Sopenharmony_ci node, javascript()->ConstructWithArrayLike(p.frequency(), p.feedback())); 31081cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSConstructWithArrayLike(node)); 31091cb0ef41Sopenharmony_ci} 31101cb0ef41Sopenharmony_ci 31111cb0ef41Sopenharmony_ci// ES6 section 26.1.7 Reflect.getPrototypeOf ( target ) 31121cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) { 31131cb0ef41Sopenharmony_ci JSCallNode n(node); 31141cb0ef41Sopenharmony_ci Node* target = n.ArgumentOrUndefined(0, jsgraph()); 31151cb0ef41Sopenharmony_ci return ReduceObjectGetPrototype(node, target); 31161cb0ef41Sopenharmony_ci} 31171cb0ef41Sopenharmony_ci 31181cb0ef41Sopenharmony_ci// ES6 section #sec-object.create Object.create(proto, properties) 31191cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceObjectCreate(Node* node) { 31201cb0ef41Sopenharmony_ci JSCallNode n(node); 31211cb0ef41Sopenharmony_ci Node* properties = n.ArgumentOrUndefined(1, jsgraph()); 31221cb0ef41Sopenharmony_ci if (properties != jsgraph()->UndefinedConstant()) return NoChange(); 31231cb0ef41Sopenharmony_ci 31241cb0ef41Sopenharmony_ci Node* context = n.context(); 31251cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 31261cb0ef41Sopenharmony_ci Effect effect = n.effect(); 31271cb0ef41Sopenharmony_ci Control control = n.control(); 31281cb0ef41Sopenharmony_ci Node* prototype = n.ArgumentOrUndefined(0, jsgraph()); 31291cb0ef41Sopenharmony_ci node->ReplaceInput(0, prototype); 31301cb0ef41Sopenharmony_ci node->ReplaceInput(1, context); 31311cb0ef41Sopenharmony_ci node->ReplaceInput(2, frame_state); 31321cb0ef41Sopenharmony_ci node->ReplaceInput(3, effect); 31331cb0ef41Sopenharmony_ci node->ReplaceInput(4, control); 31341cb0ef41Sopenharmony_ci node->TrimInputCount(5); 31351cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, javascript()->CreateObject()); 31361cb0ef41Sopenharmony_ci return Changed(node); 31371cb0ef41Sopenharmony_ci} 31381cb0ef41Sopenharmony_ci 31391cb0ef41Sopenharmony_ci// ES section #sec-reflect.get 31401cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceReflectGet(Node* node) { 31411cb0ef41Sopenharmony_ci JSCallNode n(node); 31421cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 31431cb0ef41Sopenharmony_ci int arity = p.arity_without_implicit_args(); 31441cb0ef41Sopenharmony_ci if (arity != 2) return NoChange(); 31451cb0ef41Sopenharmony_ci Node* target = n.Argument(0); 31461cb0ef41Sopenharmony_ci Node* key = n.Argument(1); 31471cb0ef41Sopenharmony_ci Node* context = n.context(); 31481cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 31491cb0ef41Sopenharmony_ci Effect effect = n.effect(); 31501cb0ef41Sopenharmony_ci Control control = n.control(); 31511cb0ef41Sopenharmony_ci 31521cb0ef41Sopenharmony_ci // Check whether {target} is a JSReceiver. 31531cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), target); 31541cb0ef41Sopenharmony_ci Node* branch = 31551cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); 31561cb0ef41Sopenharmony_ci 31571cb0ef41Sopenharmony_ci // Throw an appropriate TypeError if the {target} is not a JSReceiver. 31581cb0ef41Sopenharmony_ci Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 31591cb0ef41Sopenharmony_ci Node* efalse = effect; 31601cb0ef41Sopenharmony_ci { 31611cb0ef41Sopenharmony_ci if_false = efalse = graph()->NewNode( 31621cb0ef41Sopenharmony_ci javascript()->CallRuntime(Runtime::kThrowTypeError, 2), 31631cb0ef41Sopenharmony_ci jsgraph()->Constant( 31641cb0ef41Sopenharmony_ci static_cast<int>(MessageTemplate::kCalledOnNonObject)), 31651cb0ef41Sopenharmony_ci jsgraph()->HeapConstant(factory()->ReflectGet_string()), context, 31661cb0ef41Sopenharmony_ci frame_state, efalse, if_false); 31671cb0ef41Sopenharmony_ci } 31681cb0ef41Sopenharmony_ci 31691cb0ef41Sopenharmony_ci // Otherwise just use the existing GetPropertyStub. 31701cb0ef41Sopenharmony_ci Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 31711cb0ef41Sopenharmony_ci Node* etrue = effect; 31721cb0ef41Sopenharmony_ci Node* vtrue; 31731cb0ef41Sopenharmony_ci { 31741cb0ef41Sopenharmony_ci Callable callable = Builtins::CallableFor(isolate(), Builtin::kGetProperty); 31751cb0ef41Sopenharmony_ci auto call_descriptor = Linkage::GetStubCallDescriptor( 31761cb0ef41Sopenharmony_ci graph()->zone(), callable.descriptor(), 31771cb0ef41Sopenharmony_ci callable.descriptor().GetStackParameterCount(), 31781cb0ef41Sopenharmony_ci CallDescriptor::kNeedsFrameState, Operator::kNoProperties); 31791cb0ef41Sopenharmony_ci Node* stub_code = jsgraph()->HeapConstant(callable.code()); 31801cb0ef41Sopenharmony_ci vtrue = etrue = if_true = 31811cb0ef41Sopenharmony_ci graph()->NewNode(common()->Call(call_descriptor), stub_code, target, 31821cb0ef41Sopenharmony_ci key, context, frame_state, etrue, if_true); 31831cb0ef41Sopenharmony_ci } 31841cb0ef41Sopenharmony_ci 31851cb0ef41Sopenharmony_ci // Rewire potential exception edges. 31861cb0ef41Sopenharmony_ci Node* on_exception = nullptr; 31871cb0ef41Sopenharmony_ci if (NodeProperties::IsExceptionalCall(node, &on_exception)) { 31881cb0ef41Sopenharmony_ci // Create appropriate {IfException} and {IfSuccess} nodes. 31891cb0ef41Sopenharmony_ci Node* extrue = graph()->NewNode(common()->IfException(), etrue, if_true); 31901cb0ef41Sopenharmony_ci if_true = graph()->NewNode(common()->IfSuccess(), if_true); 31911cb0ef41Sopenharmony_ci Node* exfalse = graph()->NewNode(common()->IfException(), efalse, if_false); 31921cb0ef41Sopenharmony_ci if_false = graph()->NewNode(common()->IfSuccess(), if_false); 31931cb0ef41Sopenharmony_ci 31941cb0ef41Sopenharmony_ci // Join the exception edges. 31951cb0ef41Sopenharmony_ci Node* merge = graph()->NewNode(common()->Merge(2), extrue, exfalse); 31961cb0ef41Sopenharmony_ci Node* ephi = 31971cb0ef41Sopenharmony_ci graph()->NewNode(common()->EffectPhi(2), extrue, exfalse, merge); 31981cb0ef41Sopenharmony_ci Node* phi = 31991cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 32001cb0ef41Sopenharmony_ci extrue, exfalse, merge); 32011cb0ef41Sopenharmony_ci ReplaceWithValue(on_exception, phi, ephi, merge); 32021cb0ef41Sopenharmony_ci } 32031cb0ef41Sopenharmony_ci 32041cb0ef41Sopenharmony_ci // Connect the throwing path to end. 32051cb0ef41Sopenharmony_ci if_false = graph()->NewNode(common()->Throw(), efalse, if_false); 32061cb0ef41Sopenharmony_ci NodeProperties::MergeControlToEnd(graph(), common(), if_false); 32071cb0ef41Sopenharmony_ci 32081cb0ef41Sopenharmony_ci // Continue on the regular path. 32091cb0ef41Sopenharmony_ci ReplaceWithValue(node, vtrue, etrue, if_true); 32101cb0ef41Sopenharmony_ci return Changed(vtrue); 32111cb0ef41Sopenharmony_ci} 32121cb0ef41Sopenharmony_ci 32131cb0ef41Sopenharmony_ci// ES section #sec-reflect.has 32141cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceReflectHas(Node* node) { 32151cb0ef41Sopenharmony_ci JSCallNode n(node); 32161cb0ef41Sopenharmony_ci Node* target = n.ArgumentOrUndefined(0, jsgraph()); 32171cb0ef41Sopenharmony_ci Node* key = n.ArgumentOrUndefined(1, jsgraph()); 32181cb0ef41Sopenharmony_ci Node* context = n.context(); 32191cb0ef41Sopenharmony_ci Effect effect = n.effect(); 32201cb0ef41Sopenharmony_ci Control control = n.control(); 32211cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 32221cb0ef41Sopenharmony_ci 32231cb0ef41Sopenharmony_ci // Check whether {target} is a JSReceiver. 32241cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->ObjectIsReceiver(), target); 32251cb0ef41Sopenharmony_ci Node* branch = 32261cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); 32271cb0ef41Sopenharmony_ci 32281cb0ef41Sopenharmony_ci // Throw an appropriate TypeError if the {target} is not a JSReceiver. 32291cb0ef41Sopenharmony_ci Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 32301cb0ef41Sopenharmony_ci Node* efalse = effect; 32311cb0ef41Sopenharmony_ci { 32321cb0ef41Sopenharmony_ci if_false = efalse = graph()->NewNode( 32331cb0ef41Sopenharmony_ci javascript()->CallRuntime(Runtime::kThrowTypeError, 2), 32341cb0ef41Sopenharmony_ci jsgraph()->Constant( 32351cb0ef41Sopenharmony_ci static_cast<int>(MessageTemplate::kCalledOnNonObject)), 32361cb0ef41Sopenharmony_ci jsgraph()->HeapConstant(factory()->ReflectHas_string()), context, 32371cb0ef41Sopenharmony_ci frame_state, efalse, if_false); 32381cb0ef41Sopenharmony_ci } 32391cb0ef41Sopenharmony_ci 32401cb0ef41Sopenharmony_ci // Otherwise just use the existing {JSHasProperty} logic. 32411cb0ef41Sopenharmony_ci Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 32421cb0ef41Sopenharmony_ci Node* etrue = effect; 32431cb0ef41Sopenharmony_ci Node* vtrue; 32441cb0ef41Sopenharmony_ci { 32451cb0ef41Sopenharmony_ci // TODO(magardn): collect feedback so this can be optimized 32461cb0ef41Sopenharmony_ci vtrue = etrue = if_true = graph()->NewNode( 32471cb0ef41Sopenharmony_ci javascript()->HasProperty(FeedbackSource()), target, key, 32481cb0ef41Sopenharmony_ci jsgraph()->UndefinedConstant(), context, frame_state, etrue, if_true); 32491cb0ef41Sopenharmony_ci } 32501cb0ef41Sopenharmony_ci 32511cb0ef41Sopenharmony_ci // Rewire potential exception edges. 32521cb0ef41Sopenharmony_ci Node* on_exception = nullptr; 32531cb0ef41Sopenharmony_ci if (NodeProperties::IsExceptionalCall(node, &on_exception)) { 32541cb0ef41Sopenharmony_ci // Create appropriate {IfException} and {IfSuccess} nodes. 32551cb0ef41Sopenharmony_ci Node* extrue = graph()->NewNode(common()->IfException(), etrue, if_true); 32561cb0ef41Sopenharmony_ci if_true = graph()->NewNode(common()->IfSuccess(), if_true); 32571cb0ef41Sopenharmony_ci Node* exfalse = graph()->NewNode(common()->IfException(), efalse, if_false); 32581cb0ef41Sopenharmony_ci if_false = graph()->NewNode(common()->IfSuccess(), if_false); 32591cb0ef41Sopenharmony_ci 32601cb0ef41Sopenharmony_ci // Join the exception edges. 32611cb0ef41Sopenharmony_ci Node* merge = graph()->NewNode(common()->Merge(2), extrue, exfalse); 32621cb0ef41Sopenharmony_ci Node* ephi = 32631cb0ef41Sopenharmony_ci graph()->NewNode(common()->EffectPhi(2), extrue, exfalse, merge); 32641cb0ef41Sopenharmony_ci Node* phi = 32651cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 32661cb0ef41Sopenharmony_ci extrue, exfalse, merge); 32671cb0ef41Sopenharmony_ci ReplaceWithValue(on_exception, phi, ephi, merge); 32681cb0ef41Sopenharmony_ci } 32691cb0ef41Sopenharmony_ci 32701cb0ef41Sopenharmony_ci // Connect the throwing path to end. 32711cb0ef41Sopenharmony_ci if_false = graph()->NewNode(common()->Throw(), efalse, if_false); 32721cb0ef41Sopenharmony_ci NodeProperties::MergeControlToEnd(graph(), common(), if_false); 32731cb0ef41Sopenharmony_ci 32741cb0ef41Sopenharmony_ci // Continue on the regular path. 32751cb0ef41Sopenharmony_ci ReplaceWithValue(node, vtrue, etrue, if_true); 32761cb0ef41Sopenharmony_ci return Changed(vtrue); 32771cb0ef41Sopenharmony_ci} 32781cb0ef41Sopenharmony_ci 32791cb0ef41Sopenharmony_cinamespace { 32801cb0ef41Sopenharmony_ci 32811cb0ef41Sopenharmony_cibool CanInlineArrayIteratingBuiltin(JSHeapBroker* broker, 32821cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& receiver_maps, 32831cb0ef41Sopenharmony_ci ElementsKind* kind_return) { 32841cb0ef41Sopenharmony_ci DCHECK_NE(0, receiver_maps.size()); 32851cb0ef41Sopenharmony_ci *kind_return = receiver_maps[0].elements_kind(); 32861cb0ef41Sopenharmony_ci for (const MapRef& map : receiver_maps) { 32871cb0ef41Sopenharmony_ci if (!map.supports_fast_array_iteration() || 32881cb0ef41Sopenharmony_ci !UnionElementsKindUptoSize(kind_return, map.elements_kind())) { 32891cb0ef41Sopenharmony_ci return false; 32901cb0ef41Sopenharmony_ci } 32911cb0ef41Sopenharmony_ci } 32921cb0ef41Sopenharmony_ci return true; 32931cb0ef41Sopenharmony_ci} 32941cb0ef41Sopenharmony_ci 32951cb0ef41Sopenharmony_cibool CanInlineArrayResizingBuiltin(JSHeapBroker* broker, 32961cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& receiver_maps, 32971cb0ef41Sopenharmony_ci std::vector<ElementsKind>* kinds, 32981cb0ef41Sopenharmony_ci bool builtin_is_push = false) { 32991cb0ef41Sopenharmony_ci DCHECK_NE(0, receiver_maps.size()); 33001cb0ef41Sopenharmony_ci for (const MapRef& map : receiver_maps) { 33011cb0ef41Sopenharmony_ci if (!map.supports_fast_array_resize()) return false; 33021cb0ef41Sopenharmony_ci // TODO(turbofan): We should also handle fast holey double elements once 33031cb0ef41Sopenharmony_ci // we got the hole NaN mess sorted out in TurboFan/V8. 33041cb0ef41Sopenharmony_ci if (map.elements_kind() == HOLEY_DOUBLE_ELEMENTS && !builtin_is_push) { 33051cb0ef41Sopenharmony_ci return false; 33061cb0ef41Sopenharmony_ci } 33071cb0ef41Sopenharmony_ci ElementsKind current_kind = map.elements_kind(); 33081cb0ef41Sopenharmony_ci auto kind_ptr = kinds->data(); 33091cb0ef41Sopenharmony_ci size_t i; 33101cb0ef41Sopenharmony_ci for (i = 0; i < kinds->size(); i++, kind_ptr++) { 33111cb0ef41Sopenharmony_ci if (UnionElementsKindUptoPackedness(kind_ptr, current_kind)) { 33121cb0ef41Sopenharmony_ci break; 33131cb0ef41Sopenharmony_ci } 33141cb0ef41Sopenharmony_ci } 33151cb0ef41Sopenharmony_ci if (i == kinds->size()) kinds->push_back(current_kind); 33161cb0ef41Sopenharmony_ci } 33171cb0ef41Sopenharmony_ci return true; 33181cb0ef41Sopenharmony_ci} 33191cb0ef41Sopenharmony_ci 33201cb0ef41Sopenharmony_ci// Wraps common setup code for iterating array builtins. 33211cb0ef41Sopenharmony_ciclass IteratingArrayBuiltinHelper { 33221cb0ef41Sopenharmony_ci public: 33231cb0ef41Sopenharmony_ci IteratingArrayBuiltinHelper(Node* node, JSHeapBroker* broker, 33241cb0ef41Sopenharmony_ci JSGraph* jsgraph, 33251cb0ef41Sopenharmony_ci CompilationDependencies* dependencies) 33261cb0ef41Sopenharmony_ci : receiver_(NodeProperties::GetValueInput(node, 1)), 33271cb0ef41Sopenharmony_ci effect_(NodeProperties::GetEffectInput(node)), 33281cb0ef41Sopenharmony_ci control_(NodeProperties::GetControlInput(node)), 33291cb0ef41Sopenharmony_ci inference_(broker, receiver_, effect_) { 33301cb0ef41Sopenharmony_ci if (!FLAG_turbo_inline_array_builtins) return; 33311cb0ef41Sopenharmony_ci 33321cb0ef41Sopenharmony_ci DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); 33331cb0ef41Sopenharmony_ci const CallParameters& p = CallParametersOf(node->op()); 33341cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 33351cb0ef41Sopenharmony_ci return; 33361cb0ef41Sopenharmony_ci } 33371cb0ef41Sopenharmony_ci 33381cb0ef41Sopenharmony_ci // Try to determine the {receiver} map. 33391cb0ef41Sopenharmony_ci if (!inference_.HaveMaps()) return; 33401cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& receiver_maps = inference_.GetMaps(); 33411cb0ef41Sopenharmony_ci 33421cb0ef41Sopenharmony_ci if (!CanInlineArrayIteratingBuiltin(broker, receiver_maps, 33431cb0ef41Sopenharmony_ci &elements_kind_)) { 33441cb0ef41Sopenharmony_ci return; 33451cb0ef41Sopenharmony_ci } 33461cb0ef41Sopenharmony_ci 33471cb0ef41Sopenharmony_ci // TODO(jgruber): May only be needed for holey elements kinds. 33481cb0ef41Sopenharmony_ci if (!dependencies->DependOnNoElementsProtector()) return; 33491cb0ef41Sopenharmony_ci 33501cb0ef41Sopenharmony_ci has_stability_dependency_ = inference_.RelyOnMapsPreferStability( 33511cb0ef41Sopenharmony_ci dependencies, jsgraph, &effect_, control_, p.feedback()); 33521cb0ef41Sopenharmony_ci 33531cb0ef41Sopenharmony_ci can_reduce_ = true; 33541cb0ef41Sopenharmony_ci } 33551cb0ef41Sopenharmony_ci 33561cb0ef41Sopenharmony_ci bool can_reduce() const { return can_reduce_; } 33571cb0ef41Sopenharmony_ci bool has_stability_dependency() const { return has_stability_dependency_; } 33581cb0ef41Sopenharmony_ci Effect effect() const { return effect_; } 33591cb0ef41Sopenharmony_ci Control control() const { return control_; } 33601cb0ef41Sopenharmony_ci MapInference* inference() { return &inference_; } 33611cb0ef41Sopenharmony_ci ElementsKind elements_kind() const { return elements_kind_; } 33621cb0ef41Sopenharmony_ci 33631cb0ef41Sopenharmony_ci private: 33641cb0ef41Sopenharmony_ci bool can_reduce_ = false; 33651cb0ef41Sopenharmony_ci bool has_stability_dependency_ = false; 33661cb0ef41Sopenharmony_ci Node* receiver_; 33671cb0ef41Sopenharmony_ci Effect effect_; 33681cb0ef41Sopenharmony_ci Control control_; 33691cb0ef41Sopenharmony_ci MapInference inference_; 33701cb0ef41Sopenharmony_ci ElementsKind elements_kind_; 33711cb0ef41Sopenharmony_ci}; 33721cb0ef41Sopenharmony_ci 33731cb0ef41Sopenharmony_ci} // namespace 33741cb0ef41Sopenharmony_ci 33751cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayForEach( 33761cb0ef41Sopenharmony_ci Node* node, const SharedFunctionInfoRef& shared) { 33771cb0ef41Sopenharmony_ci IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); 33781cb0ef41Sopenharmony_ci if (!h.can_reduce()) return h.inference()->NoChange(); 33791cb0ef41Sopenharmony_ci 33801cb0ef41Sopenharmony_ci IteratingArrayBuiltinReducerAssembler a(this, node); 33811cb0ef41Sopenharmony_ci a.InitializeEffectControl(h.effect(), h.control()); 33821cb0ef41Sopenharmony_ci TNode<Object> subgraph = a.ReduceArrayPrototypeForEach( 33831cb0ef41Sopenharmony_ci h.inference(), h.has_stability_dependency(), h.elements_kind(), shared); 33841cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 33851cb0ef41Sopenharmony_ci} 33861cb0ef41Sopenharmony_ci 33871cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayReduce( 33881cb0ef41Sopenharmony_ci Node* node, const SharedFunctionInfoRef& shared) { 33891cb0ef41Sopenharmony_ci IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); 33901cb0ef41Sopenharmony_ci if (!h.can_reduce()) return h.inference()->NoChange(); 33911cb0ef41Sopenharmony_ci 33921cb0ef41Sopenharmony_ci IteratingArrayBuiltinReducerAssembler a(this, node); 33931cb0ef41Sopenharmony_ci a.InitializeEffectControl(h.effect(), h.control()); 33941cb0ef41Sopenharmony_ci TNode<Object> subgraph = a.ReduceArrayPrototypeReduce( 33951cb0ef41Sopenharmony_ci h.inference(), h.has_stability_dependency(), h.elements_kind(), 33961cb0ef41Sopenharmony_ci ArrayReduceDirection::kLeft, shared); 33971cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 33981cb0ef41Sopenharmony_ci} 33991cb0ef41Sopenharmony_ci 34001cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayReduceRight( 34011cb0ef41Sopenharmony_ci Node* node, const SharedFunctionInfoRef& shared) { 34021cb0ef41Sopenharmony_ci IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); 34031cb0ef41Sopenharmony_ci if (!h.can_reduce()) return h.inference()->NoChange(); 34041cb0ef41Sopenharmony_ci 34051cb0ef41Sopenharmony_ci IteratingArrayBuiltinReducerAssembler a(this, node); 34061cb0ef41Sopenharmony_ci a.InitializeEffectControl(h.effect(), h.control()); 34071cb0ef41Sopenharmony_ci TNode<Object> subgraph = a.ReduceArrayPrototypeReduce( 34081cb0ef41Sopenharmony_ci h.inference(), h.has_stability_dependency(), h.elements_kind(), 34091cb0ef41Sopenharmony_ci ArrayReduceDirection::kRight, shared); 34101cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 34111cb0ef41Sopenharmony_ci} 34121cb0ef41Sopenharmony_ci 34131cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayMap(Node* node, 34141cb0ef41Sopenharmony_ci const SharedFunctionInfoRef& shared) { 34151cb0ef41Sopenharmony_ci IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); 34161cb0ef41Sopenharmony_ci if (!h.can_reduce()) return h.inference()->NoChange(); 34171cb0ef41Sopenharmony_ci 34181cb0ef41Sopenharmony_ci // Calls CreateArray and thus requires this additional protector dependency. 34191cb0ef41Sopenharmony_ci if (!dependencies()->DependOnArraySpeciesProtector()) { 34201cb0ef41Sopenharmony_ci return h.inference()->NoChange(); 34211cb0ef41Sopenharmony_ci } 34221cb0ef41Sopenharmony_ci 34231cb0ef41Sopenharmony_ci IteratingArrayBuiltinReducerAssembler a(this, node); 34241cb0ef41Sopenharmony_ci a.InitializeEffectControl(h.effect(), h.control()); 34251cb0ef41Sopenharmony_ci 34261cb0ef41Sopenharmony_ci TNode<Object> subgraph = 34271cb0ef41Sopenharmony_ci a.ReduceArrayPrototypeMap(h.inference(), h.has_stability_dependency(), 34281cb0ef41Sopenharmony_ci h.elements_kind(), shared, native_context()); 34291cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 34301cb0ef41Sopenharmony_ci} 34311cb0ef41Sopenharmony_ci 34321cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayFilter( 34331cb0ef41Sopenharmony_ci Node* node, const SharedFunctionInfoRef& shared) { 34341cb0ef41Sopenharmony_ci IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); 34351cb0ef41Sopenharmony_ci if (!h.can_reduce()) return h.inference()->NoChange(); 34361cb0ef41Sopenharmony_ci 34371cb0ef41Sopenharmony_ci // Calls CreateArray and thus requires this additional protector dependency. 34381cb0ef41Sopenharmony_ci if (!dependencies()->DependOnArraySpeciesProtector()) { 34391cb0ef41Sopenharmony_ci return h.inference()->NoChange(); 34401cb0ef41Sopenharmony_ci } 34411cb0ef41Sopenharmony_ci 34421cb0ef41Sopenharmony_ci IteratingArrayBuiltinReducerAssembler a(this, node); 34431cb0ef41Sopenharmony_ci a.InitializeEffectControl(h.effect(), h.control()); 34441cb0ef41Sopenharmony_ci 34451cb0ef41Sopenharmony_ci TNode<Object> subgraph = 34461cb0ef41Sopenharmony_ci a.ReduceArrayPrototypeFilter(h.inference(), h.has_stability_dependency(), 34471cb0ef41Sopenharmony_ci h.elements_kind(), shared, native_context()); 34481cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 34491cb0ef41Sopenharmony_ci} 34501cb0ef41Sopenharmony_ci 34511cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayFind(Node* node, 34521cb0ef41Sopenharmony_ci const SharedFunctionInfoRef& shared) { 34531cb0ef41Sopenharmony_ci IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); 34541cb0ef41Sopenharmony_ci if (!h.can_reduce()) return h.inference()->NoChange(); 34551cb0ef41Sopenharmony_ci 34561cb0ef41Sopenharmony_ci IteratingArrayBuiltinReducerAssembler a(this, node); 34571cb0ef41Sopenharmony_ci a.InitializeEffectControl(h.effect(), h.control()); 34581cb0ef41Sopenharmony_ci 34591cb0ef41Sopenharmony_ci TNode<Object> subgraph = a.ReduceArrayPrototypeFind( 34601cb0ef41Sopenharmony_ci h.inference(), h.has_stability_dependency(), h.elements_kind(), shared, 34611cb0ef41Sopenharmony_ci native_context(), ArrayFindVariant::kFind); 34621cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 34631cb0ef41Sopenharmony_ci} 34641cb0ef41Sopenharmony_ci 34651cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayFindIndex( 34661cb0ef41Sopenharmony_ci Node* node, const SharedFunctionInfoRef& shared) { 34671cb0ef41Sopenharmony_ci IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); 34681cb0ef41Sopenharmony_ci if (!h.can_reduce()) return h.inference()->NoChange(); 34691cb0ef41Sopenharmony_ci 34701cb0ef41Sopenharmony_ci IteratingArrayBuiltinReducerAssembler a(this, node); 34711cb0ef41Sopenharmony_ci a.InitializeEffectControl(h.effect(), h.control()); 34721cb0ef41Sopenharmony_ci 34731cb0ef41Sopenharmony_ci TNode<Object> subgraph = a.ReduceArrayPrototypeFind( 34741cb0ef41Sopenharmony_ci h.inference(), h.has_stability_dependency(), h.elements_kind(), shared, 34751cb0ef41Sopenharmony_ci native_context(), ArrayFindVariant::kFindIndex); 34761cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 34771cb0ef41Sopenharmony_ci} 34781cb0ef41Sopenharmony_ci 34791cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayEvery(Node* node, 34801cb0ef41Sopenharmony_ci const SharedFunctionInfoRef& shared) { 34811cb0ef41Sopenharmony_ci IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); 34821cb0ef41Sopenharmony_ci if (!h.can_reduce()) return h.inference()->NoChange(); 34831cb0ef41Sopenharmony_ci 34841cb0ef41Sopenharmony_ci IteratingArrayBuiltinReducerAssembler a(this, node); 34851cb0ef41Sopenharmony_ci a.InitializeEffectControl(h.effect(), h.control()); 34861cb0ef41Sopenharmony_ci 34871cb0ef41Sopenharmony_ci TNode<Object> subgraph = a.ReduceArrayPrototypeEverySome( 34881cb0ef41Sopenharmony_ci h.inference(), h.has_stability_dependency(), h.elements_kind(), shared, 34891cb0ef41Sopenharmony_ci native_context(), ArrayEverySomeVariant::kEvery); 34901cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 34911cb0ef41Sopenharmony_ci} 34921cb0ef41Sopenharmony_ci 34931cb0ef41Sopenharmony_ci// ES7 Array.prototype.inludes(searchElement[, fromIndex]) 34941cb0ef41Sopenharmony_ci// #sec-array.prototype.includes 34951cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayIncludes(Node* node) { 34961cb0ef41Sopenharmony_ci IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); 34971cb0ef41Sopenharmony_ci if (!h.can_reduce()) return h.inference()->NoChange(); 34981cb0ef41Sopenharmony_ci 34991cb0ef41Sopenharmony_ci IteratingArrayBuiltinReducerAssembler a(this, node); 35001cb0ef41Sopenharmony_ci a.InitializeEffectControl(h.effect(), h.control()); 35011cb0ef41Sopenharmony_ci 35021cb0ef41Sopenharmony_ci TNode<Object> subgraph = a.ReduceArrayPrototypeIndexOfIncludes( 35031cb0ef41Sopenharmony_ci h.elements_kind(), ArrayIndexOfIncludesVariant::kIncludes); 35041cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 35051cb0ef41Sopenharmony_ci} 35061cb0ef41Sopenharmony_ci 35071cb0ef41Sopenharmony_ci// ES6 Array.prototype.indexOf(searchElement[, fromIndex]) 35081cb0ef41Sopenharmony_ci// #sec-array.prototype.indexof 35091cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayIndexOf(Node* node) { 35101cb0ef41Sopenharmony_ci IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); 35111cb0ef41Sopenharmony_ci if (!h.can_reduce()) return h.inference()->NoChange(); 35121cb0ef41Sopenharmony_ci 35131cb0ef41Sopenharmony_ci IteratingArrayBuiltinReducerAssembler a(this, node); 35141cb0ef41Sopenharmony_ci a.InitializeEffectControl(h.effect(), h.control()); 35151cb0ef41Sopenharmony_ci 35161cb0ef41Sopenharmony_ci TNode<Object> subgraph = a.ReduceArrayPrototypeIndexOfIncludes( 35171cb0ef41Sopenharmony_ci h.elements_kind(), ArrayIndexOfIncludesVariant::kIndexOf); 35181cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 35191cb0ef41Sopenharmony_ci} 35201cb0ef41Sopenharmony_ci 35211cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArraySome(Node* node, 35221cb0ef41Sopenharmony_ci const SharedFunctionInfoRef& shared) { 35231cb0ef41Sopenharmony_ci IteratingArrayBuiltinHelper h(node, broker(), jsgraph(), dependencies()); 35241cb0ef41Sopenharmony_ci if (!h.can_reduce()) return h.inference()->NoChange(); 35251cb0ef41Sopenharmony_ci 35261cb0ef41Sopenharmony_ci IteratingArrayBuiltinReducerAssembler a(this, node); 35271cb0ef41Sopenharmony_ci a.InitializeEffectControl(h.effect(), h.control()); 35281cb0ef41Sopenharmony_ci 35291cb0ef41Sopenharmony_ci TNode<Object> subgraph = a.ReduceArrayPrototypeEverySome( 35301cb0ef41Sopenharmony_ci h.inference(), h.has_stability_dependency(), h.elements_kind(), shared, 35311cb0ef41Sopenharmony_ci native_context(), ArrayEverySomeVariant::kSome); 35321cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 35331cb0ef41Sopenharmony_ci} 35341cb0ef41Sopenharmony_ci 35351cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY 35361cb0ef41Sopenharmony_ci 35371cb0ef41Sopenharmony_cinamespace { 35381cb0ef41Sopenharmony_ci 35391cb0ef41Sopenharmony_cibool CanInlineJSToWasmCall(const wasm::FunctionSig* wasm_signature) { 35401cb0ef41Sopenharmony_ci if (wasm_signature->return_count() > 1) { 35411cb0ef41Sopenharmony_ci return false; 35421cb0ef41Sopenharmony_ci } 35431cb0ef41Sopenharmony_ci 35441cb0ef41Sopenharmony_ci for (auto type : wasm_signature->all()) { 35451cb0ef41Sopenharmony_ci#if defined(V8_TARGET_ARCH_32_BIT) 35461cb0ef41Sopenharmony_ci if (type == wasm::kWasmI64) return false; 35471cb0ef41Sopenharmony_ci#endif 35481cb0ef41Sopenharmony_ci if (type != wasm::kWasmI32 && type != wasm::kWasmI64 && 35491cb0ef41Sopenharmony_ci type != wasm::kWasmF32 && type != wasm::kWasmF64) { 35501cb0ef41Sopenharmony_ci return false; 35511cb0ef41Sopenharmony_ci } 35521cb0ef41Sopenharmony_ci } 35531cb0ef41Sopenharmony_ci 35541cb0ef41Sopenharmony_ci return true; 35551cb0ef41Sopenharmony_ci} 35561cb0ef41Sopenharmony_ci 35571cb0ef41Sopenharmony_ci} // namespace 35581cb0ef41Sopenharmony_ci 35591cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceCallWasmFunction( 35601cb0ef41Sopenharmony_ci Node* node, const SharedFunctionInfoRef& shared) { 35611cb0ef41Sopenharmony_ci DCHECK(flags() & kInlineJSToWasmCalls); 35621cb0ef41Sopenharmony_ci 35631cb0ef41Sopenharmony_ci JSCallNode n(node); 35641cb0ef41Sopenharmony_ci const CallParameters& p = n.Parameters(); 35651cb0ef41Sopenharmony_ci 35661cb0ef41Sopenharmony_ci // Avoid deoptimization loops 35671cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 35681cb0ef41Sopenharmony_ci return NoChange(); 35691cb0ef41Sopenharmony_ci } 35701cb0ef41Sopenharmony_ci 35711cb0ef41Sopenharmony_ci const wasm::FunctionSig* wasm_signature = shared.wasm_function_signature(); 35721cb0ef41Sopenharmony_ci if (!CanInlineJSToWasmCall(wasm_signature)) { 35731cb0ef41Sopenharmony_ci return NoChange(); 35741cb0ef41Sopenharmony_ci } 35751cb0ef41Sopenharmony_ci 35761cb0ef41Sopenharmony_ci // Signal TurboFan that it should run the 'wasm-inlining' phase. 35771cb0ef41Sopenharmony_ci has_wasm_calls_ = true; 35781cb0ef41Sopenharmony_ci 35791cb0ef41Sopenharmony_ci const wasm::WasmModule* wasm_module = shared.wasm_module(); 35801cb0ef41Sopenharmony_ci const Operator* op = 35811cb0ef41Sopenharmony_ci javascript()->CallWasm(wasm_module, wasm_signature, p.feedback()); 35821cb0ef41Sopenharmony_ci 35831cb0ef41Sopenharmony_ci // Remove additional inputs 35841cb0ef41Sopenharmony_ci size_t actual_arity = n.ArgumentCount(); 35851cb0ef41Sopenharmony_ci DCHECK(JSCallNode::kFeedbackVectorIsLastInput); 35861cb0ef41Sopenharmony_ci DCHECK_EQ(actual_arity + JSWasmCallNode::kExtraInputCount - 1, 35871cb0ef41Sopenharmony_ci n.FeedbackVectorIndex()); 35881cb0ef41Sopenharmony_ci size_t expected_arity = wasm_signature->parameter_count(); 35891cb0ef41Sopenharmony_ci 35901cb0ef41Sopenharmony_ci while (actual_arity > expected_arity) { 35911cb0ef41Sopenharmony_ci int removal_index = 35921cb0ef41Sopenharmony_ci static_cast<int>(n.FirstArgumentIndex() + expected_arity); 35931cb0ef41Sopenharmony_ci DCHECK_LT(removal_index, static_cast<int>(node->InputCount())); 35941cb0ef41Sopenharmony_ci node->RemoveInput(removal_index); 35951cb0ef41Sopenharmony_ci actual_arity--; 35961cb0ef41Sopenharmony_ci } 35971cb0ef41Sopenharmony_ci 35981cb0ef41Sopenharmony_ci // Add missing inputs 35991cb0ef41Sopenharmony_ci while (actual_arity < expected_arity) { 36001cb0ef41Sopenharmony_ci int insertion_index = n.ArgumentIndex(n.ArgumentCount()); 36011cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), insertion_index, 36021cb0ef41Sopenharmony_ci jsgraph()->UndefinedConstant()); 36031cb0ef41Sopenharmony_ci actual_arity++; 36041cb0ef41Sopenharmony_ci } 36051cb0ef41Sopenharmony_ci 36061cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, op); 36071cb0ef41Sopenharmony_ci return Changed(node); 36081cb0ef41Sopenharmony_ci} 36091cb0ef41Sopenharmony_ci#endif // V8_ENABLE_WEBASSEMBLY 36101cb0ef41Sopenharmony_ci 36111cb0ef41Sopenharmony_ci// Given a FunctionTemplateInfo, checks whether the fast API call can be 36121cb0ef41Sopenharmony_ci// optimized, applying the initial step of the overload resolution algorithm: 36131cb0ef41Sopenharmony_ci// Given an overload set function_template_info.c_signatures, and a list of 36141cb0ef41Sopenharmony_ci// arguments of size argc: 36151cb0ef41Sopenharmony_ci// 1. Let max_arg be the length of the longest type list of the entries in 36161cb0ef41Sopenharmony_ci// function_template_info.c_signatures. 36171cb0ef41Sopenharmony_ci// 2. Let argc be the size of the arguments list. 36181cb0ef41Sopenharmony_ci// 3. Initialize arg_count = min(max_arg, argc). 36191cb0ef41Sopenharmony_ci// 4. Remove from the set all entries whose type list is not of length 36201cb0ef41Sopenharmony_ci// arg_count. 36211cb0ef41Sopenharmony_ci// Returns an array with the indexes of the remaining entries in S, which 36221cb0ef41Sopenharmony_ci// represents the set of "optimizable" function overloads. 36231cb0ef41Sopenharmony_ci 36241cb0ef41Sopenharmony_ciFastApiCallFunctionVector CanOptimizeFastCall( 36251cb0ef41Sopenharmony_ci Zone* zone, const FunctionTemplateInfoRef& function_template_info, 36261cb0ef41Sopenharmony_ci size_t argc) { 36271cb0ef41Sopenharmony_ci FastApiCallFunctionVector result(zone); 36281cb0ef41Sopenharmony_ci if (!FLAG_turbo_fast_api_calls) return result; 36291cb0ef41Sopenharmony_ci 36301cb0ef41Sopenharmony_ci static constexpr int kReceiver = 1; 36311cb0ef41Sopenharmony_ci 36321cb0ef41Sopenharmony_ci ZoneVector<Address> functions = function_template_info.c_functions(); 36331cb0ef41Sopenharmony_ci ZoneVector<const CFunctionInfo*> signatures = 36341cb0ef41Sopenharmony_ci function_template_info.c_signatures(); 36351cb0ef41Sopenharmony_ci const size_t overloads_count = signatures.size(); 36361cb0ef41Sopenharmony_ci 36371cb0ef41Sopenharmony_ci // Calculates the length of the longest type list of the entries in 36381cb0ef41Sopenharmony_ci // function_template_info. 36391cb0ef41Sopenharmony_ci size_t max_arg = 0; 36401cb0ef41Sopenharmony_ci for (size_t i = 0; i < overloads_count; i++) { 36411cb0ef41Sopenharmony_ci const CFunctionInfo* c_signature = signatures[i]; 36421cb0ef41Sopenharmony_ci // C arguments should include the receiver at index 0. 36431cb0ef41Sopenharmony_ci DCHECK_GE(c_signature->ArgumentCount(), kReceiver); 36441cb0ef41Sopenharmony_ci const size_t len = c_signature->ArgumentCount() - kReceiver; 36451cb0ef41Sopenharmony_ci if (len > max_arg) max_arg = len; 36461cb0ef41Sopenharmony_ci } 36471cb0ef41Sopenharmony_ci const size_t arg_count = std::min(max_arg, argc); 36481cb0ef41Sopenharmony_ci 36491cb0ef41Sopenharmony_ci // Only considers entries whose type list length matches arg_count. 36501cb0ef41Sopenharmony_ci for (size_t i = 0; i < overloads_count; i++) { 36511cb0ef41Sopenharmony_ci const CFunctionInfo* c_signature = signatures[i]; 36521cb0ef41Sopenharmony_ci const size_t len = c_signature->ArgumentCount() - kReceiver; 36531cb0ef41Sopenharmony_ci bool optimize_to_fast_call = (len == arg_count); 36541cb0ef41Sopenharmony_ci 36551cb0ef41Sopenharmony_ci optimize_to_fast_call = 36561cb0ef41Sopenharmony_ci optimize_to_fast_call && 36571cb0ef41Sopenharmony_ci fast_api_call::CanOptimizeFastSignature(c_signature); 36581cb0ef41Sopenharmony_ci 36591cb0ef41Sopenharmony_ci if (optimize_to_fast_call) { 36601cb0ef41Sopenharmony_ci result.push_back({functions[i], c_signature}); 36611cb0ef41Sopenharmony_ci } 36621cb0ef41Sopenharmony_ci } 36631cb0ef41Sopenharmony_ci 36641cb0ef41Sopenharmony_ci return result; 36651cb0ef41Sopenharmony_ci} 36661cb0ef41Sopenharmony_ci 36671cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceCallApiFunction( 36681cb0ef41Sopenharmony_ci Node* node, const SharedFunctionInfoRef& shared) { 36691cb0ef41Sopenharmony_ci JSCallNode n(node); 36701cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 36711cb0ef41Sopenharmony_ci int const argc = p.arity_without_implicit_args(); 36721cb0ef41Sopenharmony_ci Node* target = n.target(); 36731cb0ef41Sopenharmony_ci Node* global_proxy = 36741cb0ef41Sopenharmony_ci jsgraph()->Constant(native_context().global_proxy_object()); 36751cb0ef41Sopenharmony_ci Node* receiver = (p.convert_mode() == ConvertReceiverMode::kNullOrUndefined) 36761cb0ef41Sopenharmony_ci ? global_proxy 36771cb0ef41Sopenharmony_ci : n.receiver(); 36781cb0ef41Sopenharmony_ci Node* holder; 36791cb0ef41Sopenharmony_ci Node* context = n.context(); 36801cb0ef41Sopenharmony_ci Effect effect = n.effect(); 36811cb0ef41Sopenharmony_ci Control control = n.control(); 36821cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 36831cb0ef41Sopenharmony_ci 36841cb0ef41Sopenharmony_ci if (!shared.function_template_info().has_value()) { 36851cb0ef41Sopenharmony_ci TRACE_BROKER_MISSING( 36861cb0ef41Sopenharmony_ci broker(), "FunctionTemplateInfo for function with SFI " << shared); 36871cb0ef41Sopenharmony_ci return NoChange(); 36881cb0ef41Sopenharmony_ci } 36891cb0ef41Sopenharmony_ci 36901cb0ef41Sopenharmony_ci // See if we can optimize this API call to {shared}. 36911cb0ef41Sopenharmony_ci FunctionTemplateInfoRef function_template_info( 36921cb0ef41Sopenharmony_ci shared.function_template_info().value()); 36931cb0ef41Sopenharmony_ci 36941cb0ef41Sopenharmony_ci if (function_template_info.accept_any_receiver() && 36951cb0ef41Sopenharmony_ci function_template_info.is_signature_undefined()) { 36961cb0ef41Sopenharmony_ci // We might be able to 36971cb0ef41Sopenharmony_ci // optimize the API call depending on the {function_template_info}. 36981cb0ef41Sopenharmony_ci // If the API function accepts any kind of {receiver}, we only need to 36991cb0ef41Sopenharmony_ci // ensure that the {receiver} is actually a JSReceiver at this point, 37001cb0ef41Sopenharmony_ci // and also pass that as the {holder}. There are two independent bits 37011cb0ef41Sopenharmony_ci // here: 37021cb0ef41Sopenharmony_ci // 37031cb0ef41Sopenharmony_ci // a. When the "accept any receiver" bit is set, it means we don't 37041cb0ef41Sopenharmony_ci // need to perform access checks, even if the {receiver}'s map 37051cb0ef41Sopenharmony_ci // has the "needs access check" bit set. 37061cb0ef41Sopenharmony_ci // b. When the {function_template_info} has no signature, we don't 37071cb0ef41Sopenharmony_ci // need to do the compatible receiver check, since all receivers 37081cb0ef41Sopenharmony_ci // are considered compatible at that point, and the {receiver} 37091cb0ef41Sopenharmony_ci // will be pass as the {holder}. 37101cb0ef41Sopenharmony_ci // 37111cb0ef41Sopenharmony_ci receiver = holder = effect = 37121cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->ConvertReceiver(p.convert_mode()), 37131cb0ef41Sopenharmony_ci receiver, global_proxy, effect, control); 37141cb0ef41Sopenharmony_ci } else { 37151cb0ef41Sopenharmony_ci // Try to infer the {receiver} maps from the graph. 37161cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 37171cb0ef41Sopenharmony_ci if (inference.HaveMaps()) { 37181cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& receiver_maps = inference.GetMaps(); 37191cb0ef41Sopenharmony_ci MapRef first_receiver_map = receiver_maps[0]; 37201cb0ef41Sopenharmony_ci 37211cb0ef41Sopenharmony_ci // See if we can constant-fold the compatible receiver checks. 37221cb0ef41Sopenharmony_ci HolderLookupResult api_holder = 37231cb0ef41Sopenharmony_ci function_template_info.LookupHolderOfExpectedType(first_receiver_map); 37241cb0ef41Sopenharmony_ci if (api_holder.lookup == CallOptimization::kHolderNotFound) { 37251cb0ef41Sopenharmony_ci return inference.NoChange(); 37261cb0ef41Sopenharmony_ci } 37271cb0ef41Sopenharmony_ci 37281cb0ef41Sopenharmony_ci // Check that all {receiver_maps} are actually JSReceiver maps and 37291cb0ef41Sopenharmony_ci // that the {function_template_info} accepts them without access 37301cb0ef41Sopenharmony_ci // checks (even if "access check needed" is set for {receiver}). 37311cb0ef41Sopenharmony_ci // 37321cb0ef41Sopenharmony_ci // Note that we don't need to know the concrete {receiver} maps here, 37331cb0ef41Sopenharmony_ci // meaning it's fine if the {receiver_maps} are unreliable, and we also 37341cb0ef41Sopenharmony_ci // don't need to install any stability dependencies, since the only 37351cb0ef41Sopenharmony_ci // relevant information regarding the {receiver} is the Map::constructor 37361cb0ef41Sopenharmony_ci // field on the root map (which is different from the JavaScript exposed 37371cb0ef41Sopenharmony_ci // "constructor" property) and that field cannot change. 37381cb0ef41Sopenharmony_ci // 37391cb0ef41Sopenharmony_ci // So if we know that {receiver} had a certain constructor at some point 37401cb0ef41Sopenharmony_ci // in the past (i.e. it had a certain map), then this constructor is going 37411cb0ef41Sopenharmony_ci // to be the same later, since this information cannot change with map 37421cb0ef41Sopenharmony_ci // transitions. 37431cb0ef41Sopenharmony_ci // 37441cb0ef41Sopenharmony_ci // The same is true for the instance type, e.g. we still know that the 37451cb0ef41Sopenharmony_ci // instance type is JSObject even if that information is unreliable, and 37461cb0ef41Sopenharmony_ci // the "access check needed" bit, which also cannot change later. 37471cb0ef41Sopenharmony_ci CHECK(first_receiver_map.IsJSReceiverMap()); 37481cb0ef41Sopenharmony_ci CHECK(!first_receiver_map.is_access_check_needed() || 37491cb0ef41Sopenharmony_ci function_template_info.accept_any_receiver()); 37501cb0ef41Sopenharmony_ci 37511cb0ef41Sopenharmony_ci for (size_t i = 1; i < receiver_maps.size(); ++i) { 37521cb0ef41Sopenharmony_ci MapRef receiver_map = receiver_maps[i]; 37531cb0ef41Sopenharmony_ci HolderLookupResult holder_i = 37541cb0ef41Sopenharmony_ci function_template_info.LookupHolderOfExpectedType(receiver_map); 37551cb0ef41Sopenharmony_ci 37561cb0ef41Sopenharmony_ci if (api_holder.lookup != holder_i.lookup) return inference.NoChange(); 37571cb0ef41Sopenharmony_ci DCHECK(holder_i.lookup == CallOptimization::kHolderFound || 37581cb0ef41Sopenharmony_ci holder_i.lookup == CallOptimization::kHolderIsReceiver); 37591cb0ef41Sopenharmony_ci if (holder_i.lookup == CallOptimization::kHolderFound) { 37601cb0ef41Sopenharmony_ci DCHECK(api_holder.holder.has_value() && holder_i.holder.has_value()); 37611cb0ef41Sopenharmony_ci if (!api_holder.holder->equals(*holder_i.holder)) { 37621cb0ef41Sopenharmony_ci return inference.NoChange(); 37631cb0ef41Sopenharmony_ci } 37641cb0ef41Sopenharmony_ci } 37651cb0ef41Sopenharmony_ci 37661cb0ef41Sopenharmony_ci CHECK(receiver_map.IsJSReceiverMap()); 37671cb0ef41Sopenharmony_ci CHECK(!receiver_map.is_access_check_needed() || 37681cb0ef41Sopenharmony_ci function_template_info.accept_any_receiver()); 37691cb0ef41Sopenharmony_ci } 37701cb0ef41Sopenharmony_ci 37711cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation && 37721cb0ef41Sopenharmony_ci !inference.RelyOnMapsViaStability(dependencies())) { 37731cb0ef41Sopenharmony_ci // We were not able to make the receiver maps reliable without map 37741cb0ef41Sopenharmony_ci // checks but doing map checks would lead to deopt loops, so give up. 37751cb0ef41Sopenharmony_ci return inference.NoChange(); 37761cb0ef41Sopenharmony_ci } 37771cb0ef41Sopenharmony_ci 37781cb0ef41Sopenharmony_ci // TODO(neis): The maps were used in a way that does not actually require 37791cb0ef41Sopenharmony_ci // map checks or stability dependencies. 37801cb0ef41Sopenharmony_ci inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect, 37811cb0ef41Sopenharmony_ci control, p.feedback()); 37821cb0ef41Sopenharmony_ci 37831cb0ef41Sopenharmony_ci // Determine the appropriate holder for the {lookup}. 37841cb0ef41Sopenharmony_ci holder = api_holder.lookup == CallOptimization::kHolderFound 37851cb0ef41Sopenharmony_ci ? jsgraph()->Constant(*api_holder.holder) 37861cb0ef41Sopenharmony_ci : receiver; 37871cb0ef41Sopenharmony_ci } else { 37881cb0ef41Sopenharmony_ci // We don't have enough information to eliminate the access check 37891cb0ef41Sopenharmony_ci // and/or the compatible receiver check, so use the generic builtin 37901cb0ef41Sopenharmony_ci // that does those checks dynamically. This is still significantly 37911cb0ef41Sopenharmony_ci // faster than the generic call sequence. 37921cb0ef41Sopenharmony_ci Builtin builtin_name; 37931cb0ef41Sopenharmony_ci if (function_template_info.accept_any_receiver()) { 37941cb0ef41Sopenharmony_ci builtin_name = Builtin::kCallFunctionTemplate_CheckCompatibleReceiver; 37951cb0ef41Sopenharmony_ci } else if (function_template_info.is_signature_undefined()) { 37961cb0ef41Sopenharmony_ci builtin_name = Builtin::kCallFunctionTemplate_CheckAccess; 37971cb0ef41Sopenharmony_ci } else { 37981cb0ef41Sopenharmony_ci builtin_name = 37991cb0ef41Sopenharmony_ci Builtin::kCallFunctionTemplate_CheckAccessAndCompatibleReceiver; 38001cb0ef41Sopenharmony_ci } 38011cb0ef41Sopenharmony_ci 38021cb0ef41Sopenharmony_ci // The CallFunctionTemplate builtin requires the {receiver} to be 38031cb0ef41Sopenharmony_ci // an actual JSReceiver, so make sure we do the proper conversion 38041cb0ef41Sopenharmony_ci // first if necessary. 38051cb0ef41Sopenharmony_ci receiver = holder = effect = 38061cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->ConvertReceiver(p.convert_mode()), 38071cb0ef41Sopenharmony_ci receiver, global_proxy, effect, control); 38081cb0ef41Sopenharmony_ci 38091cb0ef41Sopenharmony_ci Callable callable = Builtins::CallableFor(isolate(), builtin_name); 38101cb0ef41Sopenharmony_ci auto call_descriptor = Linkage::GetStubCallDescriptor( 38111cb0ef41Sopenharmony_ci graph()->zone(), callable.descriptor(), 38121cb0ef41Sopenharmony_ci argc + 1 /* implicit receiver */, CallDescriptor::kNeedsFrameState); 38131cb0ef41Sopenharmony_ci node->RemoveInput(n.FeedbackVectorIndex()); 38141cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), 0, 38151cb0ef41Sopenharmony_ci jsgraph()->HeapConstant(callable.code())); 38161cb0ef41Sopenharmony_ci node->ReplaceInput(1, jsgraph()->Constant(function_template_info)); 38171cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), 2, 38181cb0ef41Sopenharmony_ci jsgraph()->Constant(JSParameterCount(argc))); 38191cb0ef41Sopenharmony_ci node->ReplaceInput(3, receiver); // Update receiver input. 38201cb0ef41Sopenharmony_ci node->ReplaceInput(6 + argc, effect); // Update effect input. 38211cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); 38221cb0ef41Sopenharmony_ci return Changed(node); 38231cb0ef41Sopenharmony_ci } 38241cb0ef41Sopenharmony_ci } 38251cb0ef41Sopenharmony_ci 38261cb0ef41Sopenharmony_ci // TODO(turbofan): Consider introducing a JSCallApiCallback operator for 38271cb0ef41Sopenharmony_ci // this and lower it during JSGenericLowering, and unify this with the 38281cb0ef41Sopenharmony_ci // JSNativeContextSpecialization::InlineApiCall method a bit. 38291cb0ef41Sopenharmony_ci if (!function_template_info.call_code().has_value()) { 38301cb0ef41Sopenharmony_ci TRACE_BROKER_MISSING(broker(), "call code for function template info " 38311cb0ef41Sopenharmony_ci << function_template_info); 38321cb0ef41Sopenharmony_ci return NoChange(); 38331cb0ef41Sopenharmony_ci } 38341cb0ef41Sopenharmony_ci 38351cb0ef41Sopenharmony_ci // Handles overloaded functions. 38361cb0ef41Sopenharmony_ci 38371cb0ef41Sopenharmony_ci FastApiCallFunctionVector c_candidate_functions = 38381cb0ef41Sopenharmony_ci CanOptimizeFastCall(graph()->zone(), function_template_info, argc); 38391cb0ef41Sopenharmony_ci DCHECK_LE(c_candidate_functions.size(), 2); 38401cb0ef41Sopenharmony_ci 38411cb0ef41Sopenharmony_ci if (!c_candidate_functions.empty()) { 38421cb0ef41Sopenharmony_ci FastApiCallReducerAssembler a(this, node, function_template_info, 38431cb0ef41Sopenharmony_ci c_candidate_functions, receiver, holder, 38441cb0ef41Sopenharmony_ci shared, target, argc, effect); 38451cb0ef41Sopenharmony_ci Node* fast_call_subgraph = a.ReduceFastApiCall(); 38461cb0ef41Sopenharmony_ci ReplaceWithSubgraph(&a, fast_call_subgraph); 38471cb0ef41Sopenharmony_ci 38481cb0ef41Sopenharmony_ci return Replace(fast_call_subgraph); 38491cb0ef41Sopenharmony_ci } 38501cb0ef41Sopenharmony_ci 38511cb0ef41Sopenharmony_ci // Slow call 38521cb0ef41Sopenharmony_ci 38531cb0ef41Sopenharmony_ci CallHandlerInfoRef call_handler_info = *function_template_info.call_code(); 38541cb0ef41Sopenharmony_ci Callable call_api_callback = CodeFactory::CallApiCallback(isolate()); 38551cb0ef41Sopenharmony_ci CallInterfaceDescriptor cid = call_api_callback.descriptor(); 38561cb0ef41Sopenharmony_ci auto call_descriptor = 38571cb0ef41Sopenharmony_ci Linkage::GetStubCallDescriptor(graph()->zone(), cid, argc + 1 /* 38581cb0ef41Sopenharmony_ci implicit receiver */, CallDescriptor::kNeedsFrameState); 38591cb0ef41Sopenharmony_ci ApiFunction api_function(call_handler_info.callback()); 38601cb0ef41Sopenharmony_ci ExternalReference function_reference = ExternalReference::Create( 38611cb0ef41Sopenharmony_ci &api_function, ExternalReference::DIRECT_API_CALL); 38621cb0ef41Sopenharmony_ci 38631cb0ef41Sopenharmony_ci Node* continuation_frame_state = CreateGenericLazyDeoptContinuationFrameState( 38641cb0ef41Sopenharmony_ci jsgraph(), shared, target, context, receiver, frame_state); 38651cb0ef41Sopenharmony_ci 38661cb0ef41Sopenharmony_ci node->RemoveInput(n.FeedbackVectorIndex()); 38671cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), 0, 38681cb0ef41Sopenharmony_ci jsgraph()->HeapConstant(call_api_callback.code())); 38691cb0ef41Sopenharmony_ci node->ReplaceInput(1, jsgraph()->ExternalConstant(function_reference)); 38701cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), 2, jsgraph()->Constant(argc)); 38711cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), 3, 38721cb0ef41Sopenharmony_ci jsgraph()->Constant(call_handler_info.data())); 38731cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), 4, holder); 38741cb0ef41Sopenharmony_ci node->ReplaceInput(5, receiver); // Update receiver input. 38751cb0ef41Sopenharmony_ci // 6 + argc is context input. 38761cb0ef41Sopenharmony_ci node->ReplaceInput(6 + argc + 1, continuation_frame_state); 38771cb0ef41Sopenharmony_ci node->ReplaceInput(6 + argc + 2, effect); 38781cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); 38791cb0ef41Sopenharmony_ci return Changed(node); 38801cb0ef41Sopenharmony_ci} 38811cb0ef41Sopenharmony_ci 38821cb0ef41Sopenharmony_cinamespace { 38831cb0ef41Sopenharmony_ci 38841cb0ef41Sopenharmony_ci// Check whether elements aren't mutated; we play it extremely safe here by 38851cb0ef41Sopenharmony_ci// explicitly checking that {node} is only used by {LoadField} or 38861cb0ef41Sopenharmony_ci// {LoadElement}. 38871cb0ef41Sopenharmony_cibool IsSafeArgumentsElements(Node* node) { 38881cb0ef41Sopenharmony_ci for (Edge const edge : node->use_edges()) { 38891cb0ef41Sopenharmony_ci if (!NodeProperties::IsValueEdge(edge)) continue; 38901cb0ef41Sopenharmony_ci if (edge.from()->opcode() != IrOpcode::kLoadField && 38911cb0ef41Sopenharmony_ci edge.from()->opcode() != IrOpcode::kLoadElement) { 38921cb0ef41Sopenharmony_ci return false; 38931cb0ef41Sopenharmony_ci } 38941cb0ef41Sopenharmony_ci } 38951cb0ef41Sopenharmony_ci return true; 38961cb0ef41Sopenharmony_ci} 38971cb0ef41Sopenharmony_ci 38981cb0ef41Sopenharmony_ci#ifdef DEBUG 38991cb0ef41Sopenharmony_cibool IsCallOrConstructWithArrayLike(Node* node) { 39001cb0ef41Sopenharmony_ci return node->opcode() == IrOpcode::kJSCallWithArrayLike || 39011cb0ef41Sopenharmony_ci node->opcode() == IrOpcode::kJSConstructWithArrayLike; 39021cb0ef41Sopenharmony_ci} 39031cb0ef41Sopenharmony_ci#endif 39041cb0ef41Sopenharmony_ci 39051cb0ef41Sopenharmony_cibool IsCallOrConstructWithSpread(Node* node) { 39061cb0ef41Sopenharmony_ci return node->opcode() == IrOpcode::kJSCallWithSpread || 39071cb0ef41Sopenharmony_ci node->opcode() == IrOpcode::kJSConstructWithSpread; 39081cb0ef41Sopenharmony_ci} 39091cb0ef41Sopenharmony_ci 39101cb0ef41Sopenharmony_cibool IsCallWithArrayLikeOrSpread(Node* node) { 39111cb0ef41Sopenharmony_ci return node->opcode() == IrOpcode::kJSCallWithArrayLike || 39121cb0ef41Sopenharmony_ci node->opcode() == IrOpcode::kJSCallWithSpread; 39131cb0ef41Sopenharmony_ci} 39141cb0ef41Sopenharmony_ci 39151cb0ef41Sopenharmony_ci} // namespace 39161cb0ef41Sopenharmony_ci 39171cb0ef41Sopenharmony_civoid JSCallReducer::CheckIfConstructor(Node* construct) { 39181cb0ef41Sopenharmony_ci JSConstructNode n(construct); 39191cb0ef41Sopenharmony_ci Node* new_target = n.new_target(); 39201cb0ef41Sopenharmony_ci Control control = n.control(); 39211cb0ef41Sopenharmony_ci 39221cb0ef41Sopenharmony_ci Node* check = 39231cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->ObjectIsConstructor(), new_target); 39241cb0ef41Sopenharmony_ci Node* check_branch = 39251cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); 39261cb0ef41Sopenharmony_ci Node* check_fail = graph()->NewNode(common()->IfFalse(), check_branch); 39271cb0ef41Sopenharmony_ci Node* check_throw = check_fail = graph()->NewNode( 39281cb0ef41Sopenharmony_ci javascript()->CallRuntime(Runtime::kThrowTypeError, 2), 39291cb0ef41Sopenharmony_ci jsgraph()->Constant(static_cast<int>(MessageTemplate::kNotConstructor)), 39301cb0ef41Sopenharmony_ci new_target, n.context(), n.frame_state(), n.effect(), check_fail); 39311cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->IfTrue(), check_branch); 39321cb0ef41Sopenharmony_ci NodeProperties::ReplaceControlInput(construct, control); 39331cb0ef41Sopenharmony_ci 39341cb0ef41Sopenharmony_ci // Rewire potential exception edges. 39351cb0ef41Sopenharmony_ci Node* on_exception = nullptr; 39361cb0ef41Sopenharmony_ci if (NodeProperties::IsExceptionalCall(construct, &on_exception)) { 39371cb0ef41Sopenharmony_ci // Create appropriate {IfException} and {IfSuccess} nodes. 39381cb0ef41Sopenharmony_ci Node* if_exception = 39391cb0ef41Sopenharmony_ci graph()->NewNode(common()->IfException(), check_throw, check_fail); 39401cb0ef41Sopenharmony_ci check_fail = graph()->NewNode(common()->IfSuccess(), check_fail); 39411cb0ef41Sopenharmony_ci 39421cb0ef41Sopenharmony_ci // Join the exception edges. 39431cb0ef41Sopenharmony_ci Node* merge = 39441cb0ef41Sopenharmony_ci graph()->NewNode(common()->Merge(2), if_exception, on_exception); 39451cb0ef41Sopenharmony_ci Node* ephi = graph()->NewNode(common()->EffectPhi(2), if_exception, 39461cb0ef41Sopenharmony_ci on_exception, merge); 39471cb0ef41Sopenharmony_ci Node* phi = 39481cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 39491cb0ef41Sopenharmony_ci if_exception, on_exception, merge); 39501cb0ef41Sopenharmony_ci ReplaceWithValue(on_exception, phi, ephi, merge); 39511cb0ef41Sopenharmony_ci merge->ReplaceInput(1, on_exception); 39521cb0ef41Sopenharmony_ci ephi->ReplaceInput(1, on_exception); 39531cb0ef41Sopenharmony_ci phi->ReplaceInput(1, on_exception); 39541cb0ef41Sopenharmony_ci } 39551cb0ef41Sopenharmony_ci 39561cb0ef41Sopenharmony_ci // The above %ThrowTypeError runtime call is an unconditional throw, 39571cb0ef41Sopenharmony_ci // making it impossible to return a successful completion in this case. We 39581cb0ef41Sopenharmony_ci // simply connect the successful completion to the graph end. 39591cb0ef41Sopenharmony_ci Node* throw_node = 39601cb0ef41Sopenharmony_ci graph()->NewNode(common()->Throw(), check_throw, check_fail); 39611cb0ef41Sopenharmony_ci NodeProperties::MergeControlToEnd(graph(), common(), throw_node); 39621cb0ef41Sopenharmony_ci} 39631cb0ef41Sopenharmony_ci 39641cb0ef41Sopenharmony_cinamespace { 39651cb0ef41Sopenharmony_ci 39661cb0ef41Sopenharmony_cibool ShouldUseCallICFeedback(Node* node) { 39671cb0ef41Sopenharmony_ci HeapObjectMatcher m(node); 39681cb0ef41Sopenharmony_ci if (m.HasResolvedValue() || m.IsCheckClosure() || m.IsJSCreateClosure()) { 39691cb0ef41Sopenharmony_ci // Don't use CallIC feedback when we know the function 39701cb0ef41Sopenharmony_ci // being called, i.e. either know the closure itself or 39711cb0ef41Sopenharmony_ci // at least the SharedFunctionInfo. 39721cb0ef41Sopenharmony_ci return false; 39731cb0ef41Sopenharmony_ci } else if (m.IsPhi()) { 39741cb0ef41Sopenharmony_ci // Protect against endless loops here. 39751cb0ef41Sopenharmony_ci Node* control = NodeProperties::GetControlInput(node); 39761cb0ef41Sopenharmony_ci if (control->opcode() == IrOpcode::kLoop || 39771cb0ef41Sopenharmony_ci control->opcode() == IrOpcode::kDead) 39781cb0ef41Sopenharmony_ci return false; 39791cb0ef41Sopenharmony_ci // Check if {node} is a Phi of nodes which shouldn't 39801cb0ef41Sopenharmony_ci // use CallIC feedback (not looking through loops). 39811cb0ef41Sopenharmony_ci int const value_input_count = m.node()->op()->ValueInputCount(); 39821cb0ef41Sopenharmony_ci for (int n = 0; n < value_input_count; ++n) { 39831cb0ef41Sopenharmony_ci if (ShouldUseCallICFeedback(node->InputAt(n))) return true; 39841cb0ef41Sopenharmony_ci } 39851cb0ef41Sopenharmony_ci return false; 39861cb0ef41Sopenharmony_ci } 39871cb0ef41Sopenharmony_ci return true; 39881cb0ef41Sopenharmony_ci} 39891cb0ef41Sopenharmony_ci 39901cb0ef41Sopenharmony_ci} // namespace 39911cb0ef41Sopenharmony_ci 39921cb0ef41Sopenharmony_ciNode* JSCallReducer::CheckArrayLength(Node* array, ElementsKind elements_kind, 39931cb0ef41Sopenharmony_ci uint32_t array_length, 39941cb0ef41Sopenharmony_ci const FeedbackSource& feedback_source, 39951cb0ef41Sopenharmony_ci Effect effect, Control control) { 39961cb0ef41Sopenharmony_ci Node* length = effect = graph()->NewNode( 39971cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSArrayLength(elements_kind)), 39981cb0ef41Sopenharmony_ci array, effect, control); 39991cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->NumberEqual(), length, 40001cb0ef41Sopenharmony_ci jsgraph()->Constant(array_length)); 40011cb0ef41Sopenharmony_ci return graph()->NewNode( 40021cb0ef41Sopenharmony_ci simplified()->CheckIf(DeoptimizeReason::kArrayLengthChanged, 40031cb0ef41Sopenharmony_ci feedback_source), 40041cb0ef41Sopenharmony_ci check, effect, control); 40051cb0ef41Sopenharmony_ci} 40061cb0ef41Sopenharmony_ci 40071cb0ef41Sopenharmony_ciReduction 40081cb0ef41Sopenharmony_ciJSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpreadOfCreateArguments( 40091cb0ef41Sopenharmony_ci Node* node, Node* arguments_list, int arraylike_or_spread_index, 40101cb0ef41Sopenharmony_ci CallFrequency const& frequency, FeedbackSource const& feedback, 40111cb0ef41Sopenharmony_ci SpeculationMode speculation_mode, CallFeedbackRelation feedback_relation) { 40121cb0ef41Sopenharmony_ci DCHECK_EQ(arguments_list->opcode(), IrOpcode::kJSCreateArguments); 40131cb0ef41Sopenharmony_ci 40141cb0ef41Sopenharmony_ci // Check if {node} is the only value user of {arguments_list} (except for 40151cb0ef41Sopenharmony_ci // value uses in frame states). If not, we give up for now. 40161cb0ef41Sopenharmony_ci for (Edge edge : arguments_list->use_edges()) { 40171cb0ef41Sopenharmony_ci if (!NodeProperties::IsValueEdge(edge)) continue; 40181cb0ef41Sopenharmony_ci Node* const user = edge.from(); 40191cb0ef41Sopenharmony_ci switch (user->opcode()) { 40201cb0ef41Sopenharmony_ci case IrOpcode::kCheckMaps: 40211cb0ef41Sopenharmony_ci case IrOpcode::kFrameState: 40221cb0ef41Sopenharmony_ci case IrOpcode::kStateValues: 40231cb0ef41Sopenharmony_ci case IrOpcode::kReferenceEqual: 40241cb0ef41Sopenharmony_ci case IrOpcode::kReturn: 40251cb0ef41Sopenharmony_ci // Ignore safe uses that definitely don't mess with the arguments. 40261cb0ef41Sopenharmony_ci continue; 40271cb0ef41Sopenharmony_ci case IrOpcode::kLoadField: { 40281cb0ef41Sopenharmony_ci DCHECK_EQ(arguments_list, user->InputAt(0)); 40291cb0ef41Sopenharmony_ci FieldAccess const& access = FieldAccessOf(user->op()); 40301cb0ef41Sopenharmony_ci if (access.offset == JSArray::kLengthOffset) { 40311cb0ef41Sopenharmony_ci // Ignore uses for arguments#length. 40321cb0ef41Sopenharmony_ci STATIC_ASSERT( 40331cb0ef41Sopenharmony_ci static_cast<int>(JSArray::kLengthOffset) == 40341cb0ef41Sopenharmony_ci static_cast<int>(JSStrictArgumentsObject::kLengthOffset)); 40351cb0ef41Sopenharmony_ci STATIC_ASSERT( 40361cb0ef41Sopenharmony_ci static_cast<int>(JSArray::kLengthOffset) == 40371cb0ef41Sopenharmony_ci static_cast<int>(JSSloppyArgumentsObject::kLengthOffset)); 40381cb0ef41Sopenharmony_ci continue; 40391cb0ef41Sopenharmony_ci } else if (access.offset == JSObject::kElementsOffset) { 40401cb0ef41Sopenharmony_ci // Ignore safe uses for arguments#elements. 40411cb0ef41Sopenharmony_ci if (IsSafeArgumentsElements(user)) continue; 40421cb0ef41Sopenharmony_ci } 40431cb0ef41Sopenharmony_ci break; 40441cb0ef41Sopenharmony_ci } 40451cb0ef41Sopenharmony_ci case IrOpcode::kJSCallWithArrayLike: { 40461cb0ef41Sopenharmony_ci // Ignore uses as argumentsList input to calls with array like. 40471cb0ef41Sopenharmony_ci JSCallWithArrayLikeNode n(user); 40481cb0ef41Sopenharmony_ci if (n.Argument(0) == arguments_list) continue; 40491cb0ef41Sopenharmony_ci break; 40501cb0ef41Sopenharmony_ci } 40511cb0ef41Sopenharmony_ci case IrOpcode::kJSConstructWithArrayLike: { 40521cb0ef41Sopenharmony_ci // Ignore uses as argumentsList input to calls with array like. 40531cb0ef41Sopenharmony_ci JSConstructWithArrayLikeNode n(user); 40541cb0ef41Sopenharmony_ci if (n.Argument(0) == arguments_list) continue; 40551cb0ef41Sopenharmony_ci break; 40561cb0ef41Sopenharmony_ci } 40571cb0ef41Sopenharmony_ci case IrOpcode::kJSCallWithSpread: { 40581cb0ef41Sopenharmony_ci // Ignore uses as spread input to calls with spread. 40591cb0ef41Sopenharmony_ci JSCallWithSpreadNode n(user); 40601cb0ef41Sopenharmony_ci if (n.LastArgument() == arguments_list) continue; 40611cb0ef41Sopenharmony_ci break; 40621cb0ef41Sopenharmony_ci } 40631cb0ef41Sopenharmony_ci case IrOpcode::kJSConstructWithSpread: { 40641cb0ef41Sopenharmony_ci // Ignore uses as spread input to construct with spread. 40651cb0ef41Sopenharmony_ci JSConstructWithSpreadNode n(user); 40661cb0ef41Sopenharmony_ci if (n.LastArgument() == arguments_list) continue; 40671cb0ef41Sopenharmony_ci break; 40681cb0ef41Sopenharmony_ci } 40691cb0ef41Sopenharmony_ci default: 40701cb0ef41Sopenharmony_ci break; 40711cb0ef41Sopenharmony_ci } 40721cb0ef41Sopenharmony_ci // We cannot currently reduce the {node} to something better than what 40731cb0ef41Sopenharmony_ci // it already is, but we might be able to do something about the {node} 40741cb0ef41Sopenharmony_ci // later, so put it on the waitlist and try again during finalization. 40751cb0ef41Sopenharmony_ci waitlist_.insert(node); 40761cb0ef41Sopenharmony_ci return NoChange(); 40771cb0ef41Sopenharmony_ci } 40781cb0ef41Sopenharmony_ci 40791cb0ef41Sopenharmony_ci // Get to the actual frame state from which to extract the arguments; 40801cb0ef41Sopenharmony_ci // we can only optimize this in case the {node} was already inlined into 40811cb0ef41Sopenharmony_ci // some other function (and same for the {arguments_list}). 40821cb0ef41Sopenharmony_ci CreateArgumentsType const type = CreateArgumentsTypeOf(arguments_list->op()); 40831cb0ef41Sopenharmony_ci FrameState frame_state = 40841cb0ef41Sopenharmony_ci FrameState{NodeProperties::GetFrameStateInput(arguments_list)}; 40851cb0ef41Sopenharmony_ci 40861cb0ef41Sopenharmony_ci int formal_parameter_count; 40871cb0ef41Sopenharmony_ci { 40881cb0ef41Sopenharmony_ci Handle<SharedFunctionInfo> shared; 40891cb0ef41Sopenharmony_ci if (!frame_state.frame_state_info().shared_info().ToHandle(&shared)) { 40901cb0ef41Sopenharmony_ci return NoChange(); 40911cb0ef41Sopenharmony_ci } 40921cb0ef41Sopenharmony_ci formal_parameter_count = 40931cb0ef41Sopenharmony_ci MakeRef(broker(), shared) 40941cb0ef41Sopenharmony_ci .internal_formal_parameter_count_without_receiver(); 40951cb0ef41Sopenharmony_ci } 40961cb0ef41Sopenharmony_ci 40971cb0ef41Sopenharmony_ci if (type == CreateArgumentsType::kMappedArguments) { 40981cb0ef41Sopenharmony_ci // Mapped arguments (sloppy mode) that are aliased can only be handled 40991cb0ef41Sopenharmony_ci // here if there's no side-effect between the {node} and the {arg_array}. 41001cb0ef41Sopenharmony_ci // TODO(turbofan): Further relax this constraint. 41011cb0ef41Sopenharmony_ci if (formal_parameter_count != 0) { 41021cb0ef41Sopenharmony_ci Node* effect = NodeProperties::GetEffectInput(node); 41031cb0ef41Sopenharmony_ci if (!NodeProperties::NoObservableSideEffectBetween(effect, 41041cb0ef41Sopenharmony_ci arguments_list)) { 41051cb0ef41Sopenharmony_ci return NoChange(); 41061cb0ef41Sopenharmony_ci } 41071cb0ef41Sopenharmony_ci } 41081cb0ef41Sopenharmony_ci } 41091cb0ef41Sopenharmony_ci 41101cb0ef41Sopenharmony_ci // For call/construct with spread, we need to also install a code 41111cb0ef41Sopenharmony_ci // dependency on the array iterator lookup protector cell to ensure 41121cb0ef41Sopenharmony_ci // that no one messed with the %ArrayIteratorPrototype%.next method. 41131cb0ef41Sopenharmony_ci if (IsCallOrConstructWithSpread(node)) { 41141cb0ef41Sopenharmony_ci if (!dependencies()->DependOnArrayIteratorProtector()) return NoChange(); 41151cb0ef41Sopenharmony_ci } 41161cb0ef41Sopenharmony_ci 41171cb0ef41Sopenharmony_ci // Remove the {arguments_list} input from the {node}. 41181cb0ef41Sopenharmony_ci node->RemoveInput(arraylike_or_spread_index); 41191cb0ef41Sopenharmony_ci 41201cb0ef41Sopenharmony_ci // The index of the first relevant parameter. Only non-zero when looking at 41211cb0ef41Sopenharmony_ci // rest parameters, in which case it is set to the index of the first rest 41221cb0ef41Sopenharmony_ci // parameter. 41231cb0ef41Sopenharmony_ci const int start_index = (type == CreateArgumentsType::kRestParameter) 41241cb0ef41Sopenharmony_ci ? formal_parameter_count 41251cb0ef41Sopenharmony_ci : 0; 41261cb0ef41Sopenharmony_ci 41271cb0ef41Sopenharmony_ci // After removing the arraylike or spread object, the argument count is: 41281cb0ef41Sopenharmony_ci int argc = 41291cb0ef41Sopenharmony_ci arraylike_or_spread_index - JSCallOrConstructNode::FirstArgumentIndex(); 41301cb0ef41Sopenharmony_ci // Check if are spreading to inlined arguments or to the arguments of 41311cb0ef41Sopenharmony_ci // the outermost function. 41321cb0ef41Sopenharmony_ci if (frame_state.outer_frame_state()->opcode() != IrOpcode::kFrameState) { 41331cb0ef41Sopenharmony_ci Operator const* op; 41341cb0ef41Sopenharmony_ci if (IsCallWithArrayLikeOrSpread(node)) { 41351cb0ef41Sopenharmony_ci static constexpr int kTargetAndReceiver = 2; 41361cb0ef41Sopenharmony_ci op = javascript()->CallForwardVarargs(argc + kTargetAndReceiver, 41371cb0ef41Sopenharmony_ci start_index); 41381cb0ef41Sopenharmony_ci } else { 41391cb0ef41Sopenharmony_ci static constexpr int kTargetAndNewTarget = 2; 41401cb0ef41Sopenharmony_ci op = javascript()->ConstructForwardVarargs(argc + kTargetAndNewTarget, 41411cb0ef41Sopenharmony_ci start_index); 41421cb0ef41Sopenharmony_ci } 41431cb0ef41Sopenharmony_ci node->RemoveInput(JSCallOrConstructNode::FeedbackVectorIndexForArgc(argc)); 41441cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, op); 41451cb0ef41Sopenharmony_ci return Changed(node); 41461cb0ef41Sopenharmony_ci } 41471cb0ef41Sopenharmony_ci // Get to the actual frame state from which to extract the arguments; 41481cb0ef41Sopenharmony_ci // we can only optimize this in case the {node} was already inlined into 41491cb0ef41Sopenharmony_ci // some other function (and same for the {arg_array}). 41501cb0ef41Sopenharmony_ci FrameState outer_state{frame_state.outer_frame_state()}; 41511cb0ef41Sopenharmony_ci FrameStateInfo outer_info = outer_state.frame_state_info(); 41521cb0ef41Sopenharmony_ci if (outer_info.type() == FrameStateType::kArgumentsAdaptor) { 41531cb0ef41Sopenharmony_ci // Need to take the parameters from the arguments adaptor. 41541cb0ef41Sopenharmony_ci frame_state = outer_state; 41551cb0ef41Sopenharmony_ci } 41561cb0ef41Sopenharmony_ci // Add the actual parameters to the {node}, skipping the receiver. 41571cb0ef41Sopenharmony_ci StateValuesAccess parameters_access(frame_state.parameters()); 41581cb0ef41Sopenharmony_ci for (auto it = parameters_access.begin_without_receiver_and_skip(start_index); 41591cb0ef41Sopenharmony_ci !it.done(); ++it) { 41601cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(it.node()); 41611cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), 41621cb0ef41Sopenharmony_ci JSCallOrConstructNode::ArgumentIndex(argc++), it.node()); 41631cb0ef41Sopenharmony_ci } 41641cb0ef41Sopenharmony_ci 41651cb0ef41Sopenharmony_ci if (IsCallWithArrayLikeOrSpread(node)) { 41661cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 41671cb0ef41Sopenharmony_ci node, javascript()->Call(JSCallNode::ArityForArgc(argc), frequency, 41681cb0ef41Sopenharmony_ci feedback, ConvertReceiverMode::kAny, 41691cb0ef41Sopenharmony_ci speculation_mode, feedback_relation)); 41701cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSCall(node)); 41711cb0ef41Sopenharmony_ci } else { 41721cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 41731cb0ef41Sopenharmony_ci node, javascript()->Construct(JSConstructNode::ArityForArgc(argc), 41741cb0ef41Sopenharmony_ci frequency, feedback)); 41751cb0ef41Sopenharmony_ci 41761cb0ef41Sopenharmony_ci // Check whether the given new target value is a constructor function. The 41771cb0ef41Sopenharmony_ci // replacement {JSConstruct} operator only checks the passed target value 41781cb0ef41Sopenharmony_ci // but relies on the new target value to be implicitly valid. 41791cb0ef41Sopenharmony_ci CheckIfConstructor(node); 41801cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSConstruct(node)); 41811cb0ef41Sopenharmony_ci } 41821cb0ef41Sopenharmony_ci} 41831cb0ef41Sopenharmony_ci 41841cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread( 41851cb0ef41Sopenharmony_ci Node* node, int argument_count, int arraylike_or_spread_index, 41861cb0ef41Sopenharmony_ci CallFrequency const& frequency, FeedbackSource const& feedback_source, 41871cb0ef41Sopenharmony_ci SpeculationMode speculation_mode, CallFeedbackRelation feedback_relation, 41881cb0ef41Sopenharmony_ci Node* target, Effect effect, Control control) { 41891cb0ef41Sopenharmony_ci DCHECK(IsCallOrConstructWithArrayLike(node) || 41901cb0ef41Sopenharmony_ci IsCallOrConstructWithSpread(node)); 41911cb0ef41Sopenharmony_ci DCHECK_IMPLIES(speculation_mode == SpeculationMode::kAllowSpeculation, 41921cb0ef41Sopenharmony_ci feedback_source.IsValid()); 41931cb0ef41Sopenharmony_ci 41941cb0ef41Sopenharmony_ci Node* arguments_list = 41951cb0ef41Sopenharmony_ci NodeProperties::GetValueInput(node, arraylike_or_spread_index); 41961cb0ef41Sopenharmony_ci 41971cb0ef41Sopenharmony_ci if (arguments_list->opcode() == IrOpcode::kJSCreateArguments) { 41981cb0ef41Sopenharmony_ci return ReduceCallOrConstructWithArrayLikeOrSpreadOfCreateArguments( 41991cb0ef41Sopenharmony_ci node, arguments_list, arraylike_or_spread_index, frequency, 42001cb0ef41Sopenharmony_ci feedback_source, speculation_mode, feedback_relation); 42011cb0ef41Sopenharmony_ci } 42021cb0ef41Sopenharmony_ci 42031cb0ef41Sopenharmony_ci if (!FLAG_turbo_optimize_apply) return NoChange(); 42041cb0ef41Sopenharmony_ci 42051cb0ef41Sopenharmony_ci // Optimization of construct nodes not supported yet. 42061cb0ef41Sopenharmony_ci if (!IsCallWithArrayLikeOrSpread(node)) return NoChange(); 42071cb0ef41Sopenharmony_ci 42081cb0ef41Sopenharmony_ci // Avoid deoptimization loops. 42091cb0ef41Sopenharmony_ci if (speculation_mode != SpeculationMode::kAllowSpeculation) return NoChange(); 42101cb0ef41Sopenharmony_ci 42111cb0ef41Sopenharmony_ci // Only optimize with array literals. 42121cb0ef41Sopenharmony_ci if (arguments_list->opcode() != IrOpcode::kJSCreateLiteralArray && 42131cb0ef41Sopenharmony_ci arguments_list->opcode() != IrOpcode::kJSCreateEmptyLiteralArray) { 42141cb0ef41Sopenharmony_ci return NoChange(); 42151cb0ef41Sopenharmony_ci } 42161cb0ef41Sopenharmony_ci 42171cb0ef41Sopenharmony_ci // For call/construct with spread, we need to also install a code 42181cb0ef41Sopenharmony_ci // dependency on the array iterator lookup protector cell to ensure 42191cb0ef41Sopenharmony_ci // that no one messed with the %ArrayIteratorPrototype%.next method. 42201cb0ef41Sopenharmony_ci if (IsCallOrConstructWithSpread(node)) { 42211cb0ef41Sopenharmony_ci if (!dependencies()->DependOnArrayIteratorProtector()) return NoChange(); 42221cb0ef41Sopenharmony_ci } 42231cb0ef41Sopenharmony_ci 42241cb0ef41Sopenharmony_ci if (arguments_list->opcode() == IrOpcode::kJSCreateEmptyLiteralArray) { 42251cb0ef41Sopenharmony_ci if (generated_calls_with_array_like_or_spread_.count(node)) { 42261cb0ef41Sopenharmony_ci return NoChange(); // Avoid infinite recursion. 42271cb0ef41Sopenharmony_ci } 42281cb0ef41Sopenharmony_ci JSCallReducerAssembler a(this, node); 42291cb0ef41Sopenharmony_ci Node* subgraph = a.ReduceJSCallWithArrayLikeOrSpreadOfEmpty( 42301cb0ef41Sopenharmony_ci &generated_calls_with_array_like_or_spread_); 42311cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 42321cb0ef41Sopenharmony_ci } 42331cb0ef41Sopenharmony_ci 42341cb0ef41Sopenharmony_ci DCHECK_EQ(arguments_list->opcode(), IrOpcode::kJSCreateLiteralArray); 42351cb0ef41Sopenharmony_ci int new_argument_count; 42361cb0ef41Sopenharmony_ci 42371cb0ef41Sopenharmony_ci // Find array length and elements' kind from the feedback's allocation 42381cb0ef41Sopenharmony_ci // site's boilerplate JSArray. 42391cb0ef41Sopenharmony_ci JSCreateLiteralOpNode args_node(arguments_list); 42401cb0ef41Sopenharmony_ci CreateLiteralParameters const& args_params = args_node.Parameters(); 42411cb0ef41Sopenharmony_ci const FeedbackSource& array_feedback = args_params.feedback(); 42421cb0ef41Sopenharmony_ci const ProcessedFeedback& feedback = 42431cb0ef41Sopenharmony_ci broker()->GetFeedbackForArrayOrObjectLiteral(array_feedback); 42441cb0ef41Sopenharmony_ci if (feedback.IsInsufficient()) return NoChange(); 42451cb0ef41Sopenharmony_ci 42461cb0ef41Sopenharmony_ci AllocationSiteRef site = feedback.AsLiteral().value(); 42471cb0ef41Sopenharmony_ci if (!site.boilerplate().has_value()) return NoChange(); 42481cb0ef41Sopenharmony_ci 42491cb0ef41Sopenharmony_ci JSArrayRef boilerplate_array = site.boilerplate()->AsJSArray(); 42501cb0ef41Sopenharmony_ci int const array_length = boilerplate_array.GetBoilerplateLength().AsSmi(); 42511cb0ef41Sopenharmony_ci 42521cb0ef41Sopenharmony_ci // We'll replace the arguments_list input with {array_length} element loads. 42531cb0ef41Sopenharmony_ci new_argument_count = argument_count - 1 + array_length; 42541cb0ef41Sopenharmony_ci 42551cb0ef41Sopenharmony_ci // Do not optimize calls with a large number of arguments. 42561cb0ef41Sopenharmony_ci // Arbitrarily sets the limit to 32 arguments. 42571cb0ef41Sopenharmony_ci const int kMaxArityForOptimizedFunctionApply = 32; 42581cb0ef41Sopenharmony_ci if (new_argument_count > kMaxArityForOptimizedFunctionApply) { 42591cb0ef41Sopenharmony_ci return NoChange(); 42601cb0ef41Sopenharmony_ci } 42611cb0ef41Sopenharmony_ci 42621cb0ef41Sopenharmony_ci // Determine the array's map. 42631cb0ef41Sopenharmony_ci MapRef array_map = boilerplate_array.map(); 42641cb0ef41Sopenharmony_ci if (!array_map.supports_fast_array_iteration()) { 42651cb0ef41Sopenharmony_ci return NoChange(); 42661cb0ef41Sopenharmony_ci } 42671cb0ef41Sopenharmony_ci 42681cb0ef41Sopenharmony_ci // Check and depend on NoElementsProtector. 42691cb0ef41Sopenharmony_ci if (!dependencies()->DependOnNoElementsProtector()) { 42701cb0ef41Sopenharmony_ci return NoChange(); 42711cb0ef41Sopenharmony_ci } 42721cb0ef41Sopenharmony_ci 42731cb0ef41Sopenharmony_ci // Remove the {arguments_list} node which will be replaced by a sequence of 42741cb0ef41Sopenharmony_ci // LoadElement nodes. 42751cb0ef41Sopenharmony_ci node->RemoveInput(arraylike_or_spread_index); 42761cb0ef41Sopenharmony_ci 42771cb0ef41Sopenharmony_ci // Speculate on that array's map is still equal to the dynamic map of 42781cb0ef41Sopenharmony_ci // arguments_list; generate a map check. 42791cb0ef41Sopenharmony_ci effect = graph()->NewNode( 42801cb0ef41Sopenharmony_ci simplified()->CheckMaps(CheckMapsFlag::kNone, 42811cb0ef41Sopenharmony_ci ZoneHandleSet<Map>(array_map.object()), 42821cb0ef41Sopenharmony_ci feedback_source), 42831cb0ef41Sopenharmony_ci arguments_list, effect, control); 42841cb0ef41Sopenharmony_ci 42851cb0ef41Sopenharmony_ci // Speculate on that array's length being equal to the dynamic length of 42861cb0ef41Sopenharmony_ci // arguments_list; generate a deopt check. 42871cb0ef41Sopenharmony_ci ElementsKind elements_kind = array_map.elements_kind(); 42881cb0ef41Sopenharmony_ci effect = CheckArrayLength(arguments_list, elements_kind, array_length, 42891cb0ef41Sopenharmony_ci feedback_source, effect, control); 42901cb0ef41Sopenharmony_ci 42911cb0ef41Sopenharmony_ci // Generate N element loads to replace the {arguments_list} node with a set 42921cb0ef41Sopenharmony_ci // of arguments loaded from it. 42931cb0ef41Sopenharmony_ci Node* elements = effect = graph()->NewNode( 42941cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSObjectElements()), 42951cb0ef41Sopenharmony_ci arguments_list, effect, control); 42961cb0ef41Sopenharmony_ci for (int i = 0; i < array_length; i++) { 42971cb0ef41Sopenharmony_ci // Load the i-th element from the array. 42981cb0ef41Sopenharmony_ci Node* index = jsgraph()->Constant(i); 42991cb0ef41Sopenharmony_ci Node* load = effect = graph()->NewNode( 43001cb0ef41Sopenharmony_ci simplified()->LoadElement( 43011cb0ef41Sopenharmony_ci AccessBuilder::ForFixedArrayElement(elements_kind)), 43021cb0ef41Sopenharmony_ci elements, index, effect, control); 43031cb0ef41Sopenharmony_ci 43041cb0ef41Sopenharmony_ci // In "holey" arrays some arguments might be missing and we pass 43051cb0ef41Sopenharmony_ci // 'undefined' instead. 43061cb0ef41Sopenharmony_ci if (IsHoleyElementsKind(elements_kind)) { 43071cb0ef41Sopenharmony_ci if (elements_kind == HOLEY_DOUBLE_ELEMENTS) { 43081cb0ef41Sopenharmony_ci // May deopt for holey double elements. 43091cb0ef41Sopenharmony_ci load = effect = graph()->NewNode( 43101cb0ef41Sopenharmony_ci simplified()->CheckFloat64Hole( 43111cb0ef41Sopenharmony_ci CheckFloat64HoleMode::kAllowReturnHole, feedback_source), 43121cb0ef41Sopenharmony_ci load, effect, control); 43131cb0ef41Sopenharmony_ci } else { 43141cb0ef41Sopenharmony_ci load = graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), 43151cb0ef41Sopenharmony_ci load); 43161cb0ef41Sopenharmony_ci } 43171cb0ef41Sopenharmony_ci } 43181cb0ef41Sopenharmony_ci 43191cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), arraylike_or_spread_index + i, load); 43201cb0ef41Sopenharmony_ci } 43211cb0ef41Sopenharmony_ci 43221cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 43231cb0ef41Sopenharmony_ci node, 43241cb0ef41Sopenharmony_ci javascript()->Call(JSCallNode::ArityForArgc(new_argument_count), 43251cb0ef41Sopenharmony_ci frequency, feedback_source, ConvertReceiverMode::kAny, 43261cb0ef41Sopenharmony_ci speculation_mode, CallFeedbackRelation::kUnrelated)); 43271cb0ef41Sopenharmony_ci NodeProperties::ReplaceEffectInput(node, effect); 43281cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSCall(node)); 43291cb0ef41Sopenharmony_ci} 43301cb0ef41Sopenharmony_ci 43311cb0ef41Sopenharmony_cibool JSCallReducer::IsBuiltinOrApiFunction(JSFunctionRef function) const { 43321cb0ef41Sopenharmony_ci // TODO(neis): Add a way to check if function template info isn't serialized 43331cb0ef41Sopenharmony_ci // and add a warning in such cases. Currently we can't tell if function 43341cb0ef41Sopenharmony_ci // template info doesn't exist or wasn't serialized. 43351cb0ef41Sopenharmony_ci return function.shared().HasBuiltinId() || 43361cb0ef41Sopenharmony_ci function.shared().function_template_info().has_value(); 43371cb0ef41Sopenharmony_ci} 43381cb0ef41Sopenharmony_ci 43391cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceJSCall(Node* node) { 43401cb0ef41Sopenharmony_ci if (broker()->StackHasOverflowed()) return NoChange(); 43411cb0ef41Sopenharmony_ci 43421cb0ef41Sopenharmony_ci JSCallNode n(node); 43431cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 43441cb0ef41Sopenharmony_ci Node* target = n.target(); 43451cb0ef41Sopenharmony_ci Effect effect = n.effect(); 43461cb0ef41Sopenharmony_ci Control control = n.control(); 43471cb0ef41Sopenharmony_ci int arity = p.arity_without_implicit_args(); 43481cb0ef41Sopenharmony_ci 43491cb0ef41Sopenharmony_ci // Try to specialize JSCall {node}s with constant {target}s. 43501cb0ef41Sopenharmony_ci HeapObjectMatcher m(target); 43511cb0ef41Sopenharmony_ci if (m.HasResolvedValue()) { 43521cb0ef41Sopenharmony_ci ObjectRef target_ref = m.Ref(broker()); 43531cb0ef41Sopenharmony_ci if (target_ref.IsJSFunction()) { 43541cb0ef41Sopenharmony_ci JSFunctionRef function = target_ref.AsJSFunction(); 43551cb0ef41Sopenharmony_ci 43561cb0ef41Sopenharmony_ci // Don't inline cross native context. 43571cb0ef41Sopenharmony_ci if (!function.native_context().equals(native_context())) { 43581cb0ef41Sopenharmony_ci return NoChange(); 43591cb0ef41Sopenharmony_ci } 43601cb0ef41Sopenharmony_ci 43611cb0ef41Sopenharmony_ci return ReduceJSCall(node, function.shared()); 43621cb0ef41Sopenharmony_ci } else if (target_ref.IsJSBoundFunction()) { 43631cb0ef41Sopenharmony_ci JSBoundFunctionRef function = target_ref.AsJSBoundFunction(); 43641cb0ef41Sopenharmony_ci ObjectRef bound_this = function.bound_this(); 43651cb0ef41Sopenharmony_ci ConvertReceiverMode const convert_mode = 43661cb0ef41Sopenharmony_ci bound_this.IsNullOrUndefined() 43671cb0ef41Sopenharmony_ci ? ConvertReceiverMode::kNullOrUndefined 43681cb0ef41Sopenharmony_ci : ConvertReceiverMode::kNotNullOrUndefined; 43691cb0ef41Sopenharmony_ci 43701cb0ef41Sopenharmony_ci // TODO(jgruber): Inline this block below once TryGet is guaranteed to 43711cb0ef41Sopenharmony_ci // succeed. 43721cb0ef41Sopenharmony_ci FixedArrayRef bound_arguments = function.bound_arguments(); 43731cb0ef41Sopenharmony_ci const int bound_arguments_length = bound_arguments.length(); 43741cb0ef41Sopenharmony_ci static constexpr int kInlineSize = 16; // Arbitrary. 43751cb0ef41Sopenharmony_ci base::SmallVector<Node*, kInlineSize> args; 43761cb0ef41Sopenharmony_ci for (int i = 0; i < bound_arguments_length; ++i) { 43771cb0ef41Sopenharmony_ci base::Optional<ObjectRef> maybe_arg = bound_arguments.TryGet(i); 43781cb0ef41Sopenharmony_ci if (!maybe_arg.has_value()) { 43791cb0ef41Sopenharmony_ci TRACE_BROKER_MISSING(broker(), "bound argument"); 43801cb0ef41Sopenharmony_ci return NoChange(); 43811cb0ef41Sopenharmony_ci } 43821cb0ef41Sopenharmony_ci args.emplace_back(jsgraph()->Constant(maybe_arg.value())); 43831cb0ef41Sopenharmony_ci } 43841cb0ef41Sopenharmony_ci 43851cb0ef41Sopenharmony_ci // Patch {node} to use [[BoundTargetFunction]] and [[BoundThis]]. 43861cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInput( 43871cb0ef41Sopenharmony_ci node, jsgraph()->Constant(function.bound_target_function()), 43881cb0ef41Sopenharmony_ci JSCallNode::TargetIndex()); 43891cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInput(node, jsgraph()->Constant(bound_this), 43901cb0ef41Sopenharmony_ci JSCallNode::ReceiverIndex()); 43911cb0ef41Sopenharmony_ci 43921cb0ef41Sopenharmony_ci // Insert the [[BoundArguments]] for {node}. 43931cb0ef41Sopenharmony_ci for (int i = 0; i < bound_arguments_length; ++i) { 43941cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), i + 2, args[i]); 43951cb0ef41Sopenharmony_ci arity++; 43961cb0ef41Sopenharmony_ci } 43971cb0ef41Sopenharmony_ci 43981cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 43991cb0ef41Sopenharmony_ci node, 44001cb0ef41Sopenharmony_ci javascript()->Call(JSCallNode::ArityForArgc(arity), p.frequency(), 44011cb0ef41Sopenharmony_ci p.feedback(), convert_mode, p.speculation_mode(), 44021cb0ef41Sopenharmony_ci CallFeedbackRelation::kUnrelated)); 44031cb0ef41Sopenharmony_ci 44041cb0ef41Sopenharmony_ci // Try to further reduce the JSCall {node}. 44051cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSCall(node)); 44061cb0ef41Sopenharmony_ci } 44071cb0ef41Sopenharmony_ci 44081cb0ef41Sopenharmony_ci // Don't mess with other {node}s that have a constant {target}. 44091cb0ef41Sopenharmony_ci // TODO(bmeurer): Also support proxies here. 44101cb0ef41Sopenharmony_ci return NoChange(); 44111cb0ef41Sopenharmony_ci } 44121cb0ef41Sopenharmony_ci 44131cb0ef41Sopenharmony_ci // If {target} is the result of a JSCreateClosure operation, we can 44141cb0ef41Sopenharmony_ci // just immediately try to inline based on the SharedFunctionInfo, 44151cb0ef41Sopenharmony_ci // since TurboFan generally doesn't inline cross-context, and hence 44161cb0ef41Sopenharmony_ci // the {target} must have the same native context as the call site. 44171cb0ef41Sopenharmony_ci // Same if the {target} is the result of a CheckClosure operation. 44181cb0ef41Sopenharmony_ci if (target->opcode() == IrOpcode::kJSCreateClosure) { 44191cb0ef41Sopenharmony_ci CreateClosureParameters const& params = 44201cb0ef41Sopenharmony_ci JSCreateClosureNode{target}.Parameters(); 44211cb0ef41Sopenharmony_ci return ReduceJSCall(node, params.shared_info(broker())); 44221cb0ef41Sopenharmony_ci } else if (target->opcode() == IrOpcode::kCheckClosure) { 44231cb0ef41Sopenharmony_ci FeedbackCellRef cell = MakeRef(broker(), FeedbackCellOf(target->op())); 44241cb0ef41Sopenharmony_ci base::Optional<SharedFunctionInfoRef> shared = cell.shared_function_info(); 44251cb0ef41Sopenharmony_ci if (!shared.has_value()) { 44261cb0ef41Sopenharmony_ci TRACE_BROKER_MISSING(broker(), "Unable to reduce JSCall. FeedbackCell " 44271cb0ef41Sopenharmony_ci << cell << " has no FeedbackVector"); 44281cb0ef41Sopenharmony_ci return NoChange(); 44291cb0ef41Sopenharmony_ci } 44301cb0ef41Sopenharmony_ci return ReduceJSCall(node, *shared); 44311cb0ef41Sopenharmony_ci } 44321cb0ef41Sopenharmony_ci 44331cb0ef41Sopenharmony_ci // If {target} is the result of a JSCreateBoundFunction operation, 44341cb0ef41Sopenharmony_ci // we can just fold the construction and call the bound target 44351cb0ef41Sopenharmony_ci // function directly instead. 44361cb0ef41Sopenharmony_ci if (target->opcode() == IrOpcode::kJSCreateBoundFunction) { 44371cb0ef41Sopenharmony_ci Node* bound_target_function = NodeProperties::GetValueInput(target, 0); 44381cb0ef41Sopenharmony_ci Node* bound_this = NodeProperties::GetValueInput(target, 1); 44391cb0ef41Sopenharmony_ci int const bound_arguments_length = 44401cb0ef41Sopenharmony_ci static_cast<int>(CreateBoundFunctionParametersOf(target->op()).arity()); 44411cb0ef41Sopenharmony_ci 44421cb0ef41Sopenharmony_ci // Patch the {node} to use [[BoundTargetFunction]] and [[BoundThis]]. 44431cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInput(node, bound_target_function, 44441cb0ef41Sopenharmony_ci n.TargetIndex()); 44451cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInput(node, bound_this, n.ReceiverIndex()); 44461cb0ef41Sopenharmony_ci 44471cb0ef41Sopenharmony_ci // Insert the [[BoundArguments]] for {node}. 44481cb0ef41Sopenharmony_ci for (int i = 0; i < bound_arguments_length; ++i) { 44491cb0ef41Sopenharmony_ci Node* value = NodeProperties::GetValueInput(target, 2 + i); 44501cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), n.ArgumentIndex(i), value); 44511cb0ef41Sopenharmony_ci arity++; 44521cb0ef41Sopenharmony_ci } 44531cb0ef41Sopenharmony_ci 44541cb0ef41Sopenharmony_ci // Update the JSCall operator on {node}. 44551cb0ef41Sopenharmony_ci ConvertReceiverMode const convert_mode = 44561cb0ef41Sopenharmony_ci NodeProperties::CanBeNullOrUndefined(broker(), bound_this, effect) 44571cb0ef41Sopenharmony_ci ? ConvertReceiverMode::kAny 44581cb0ef41Sopenharmony_ci : ConvertReceiverMode::kNotNullOrUndefined; 44591cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 44601cb0ef41Sopenharmony_ci node, 44611cb0ef41Sopenharmony_ci javascript()->Call(JSCallNode::ArityForArgc(arity), p.frequency(), 44621cb0ef41Sopenharmony_ci p.feedback(), convert_mode, p.speculation_mode(), 44631cb0ef41Sopenharmony_ci CallFeedbackRelation::kUnrelated)); 44641cb0ef41Sopenharmony_ci 44651cb0ef41Sopenharmony_ci // Try to further reduce the JSCall {node}. 44661cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSCall(node)); 44671cb0ef41Sopenharmony_ci } 44681cb0ef41Sopenharmony_ci 44691cb0ef41Sopenharmony_ci if (!ShouldUseCallICFeedback(target) || 44701cb0ef41Sopenharmony_ci p.feedback_relation() == CallFeedbackRelation::kUnrelated || 44711cb0ef41Sopenharmony_ci !p.feedback().IsValid()) { 44721cb0ef41Sopenharmony_ci return NoChange(); 44731cb0ef41Sopenharmony_ci } 44741cb0ef41Sopenharmony_ci 44751cb0ef41Sopenharmony_ci ProcessedFeedback const& feedback = 44761cb0ef41Sopenharmony_ci broker()->GetFeedbackForCall(p.feedback()); 44771cb0ef41Sopenharmony_ci if (feedback.IsInsufficient()) { 44781cb0ef41Sopenharmony_ci return ReduceForInsufficientFeedback( 44791cb0ef41Sopenharmony_ci node, DeoptimizeReason::kInsufficientTypeFeedbackForCall); 44801cb0ef41Sopenharmony_ci } 44811cb0ef41Sopenharmony_ci 44821cb0ef41Sopenharmony_ci base::Optional<HeapObjectRef> feedback_target; 44831cb0ef41Sopenharmony_ci if (p.feedback_relation() == CallFeedbackRelation::kTarget) { 44841cb0ef41Sopenharmony_ci feedback_target = feedback.AsCall().target(); 44851cb0ef41Sopenharmony_ci } else { 44861cb0ef41Sopenharmony_ci DCHECK_EQ(p.feedback_relation(), CallFeedbackRelation::kReceiver); 44871cb0ef41Sopenharmony_ci feedback_target = native_context().function_prototype_apply(); 44881cb0ef41Sopenharmony_ci } 44891cb0ef41Sopenharmony_ci 44901cb0ef41Sopenharmony_ci if (feedback_target.has_value() && feedback_target->map().is_callable()) { 44911cb0ef41Sopenharmony_ci Node* target_function = jsgraph()->Constant(*feedback_target); 44921cb0ef41Sopenharmony_ci 44931cb0ef41Sopenharmony_ci // Check that the {target} is still the {target_function}. 44941cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target, 44951cb0ef41Sopenharmony_ci target_function); 44961cb0ef41Sopenharmony_ci effect = graph()->NewNode( 44971cb0ef41Sopenharmony_ci simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check, 44981cb0ef41Sopenharmony_ci effect, control); 44991cb0ef41Sopenharmony_ci 45001cb0ef41Sopenharmony_ci // Specialize the JSCall node to the {target_function}. 45011cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInput(node, target_function, n.TargetIndex()); 45021cb0ef41Sopenharmony_ci NodeProperties::ReplaceEffectInput(node, effect); 45031cb0ef41Sopenharmony_ci 45041cb0ef41Sopenharmony_ci // Try to further reduce the JSCall {node}. 45051cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSCall(node)); 45061cb0ef41Sopenharmony_ci } else if (feedback_target.has_value() && feedback_target->IsFeedbackCell()) { 45071cb0ef41Sopenharmony_ci FeedbackCellRef feedback_cell = feedback_target.value().AsFeedbackCell(); 45081cb0ef41Sopenharmony_ci // TODO(neis): This check seems unnecessary. 45091cb0ef41Sopenharmony_ci if (feedback_cell.feedback_vector().has_value()) { 45101cb0ef41Sopenharmony_ci // Check that {target} is a closure with given {feedback_cell}, 45111cb0ef41Sopenharmony_ci // which uniquely identifies a given function inside a native context. 45121cb0ef41Sopenharmony_ci Node* target_closure = effect = 45131cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->CheckClosure(feedback_cell.object()), 45141cb0ef41Sopenharmony_ci target, effect, control); 45151cb0ef41Sopenharmony_ci 45161cb0ef41Sopenharmony_ci // Specialize the JSCall node to the {target_closure}. 45171cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInput(node, target_closure, n.TargetIndex()); 45181cb0ef41Sopenharmony_ci NodeProperties::ReplaceEffectInput(node, effect); 45191cb0ef41Sopenharmony_ci 45201cb0ef41Sopenharmony_ci // Try to further reduce the JSCall {node}. 45211cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSCall(node)); 45221cb0ef41Sopenharmony_ci } 45231cb0ef41Sopenharmony_ci } 45241cb0ef41Sopenharmony_ci return NoChange(); 45251cb0ef41Sopenharmony_ci} 45261cb0ef41Sopenharmony_ci 45271cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceJSCall(Node* node, 45281cb0ef41Sopenharmony_ci const SharedFunctionInfoRef& shared) { 45291cb0ef41Sopenharmony_ci JSCallNode n(node); 45301cb0ef41Sopenharmony_ci Node* target = n.target(); 45311cb0ef41Sopenharmony_ci 45321cb0ef41Sopenharmony_ci // Do not reduce calls to functions with break points. 45331cb0ef41Sopenharmony_ci // If this state changes during background compilation, the compilation 45341cb0ef41Sopenharmony_ci // job will be aborted from the main thread (see 45351cb0ef41Sopenharmony_ci // Debug::PrepareFunctionForDebugExecution()). 45361cb0ef41Sopenharmony_ci if (shared.HasBreakInfo()) return NoChange(); 45371cb0ef41Sopenharmony_ci 45381cb0ef41Sopenharmony_ci // Class constructors are callable, but [[Call]] will raise an exception. 45391cb0ef41Sopenharmony_ci // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). 45401cb0ef41Sopenharmony_ci if (IsClassConstructor(shared.kind())) { 45411cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInputs(node, target); 45421cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 45431cb0ef41Sopenharmony_ci node, javascript()->CallRuntime( 45441cb0ef41Sopenharmony_ci Runtime::kThrowConstructorNonCallableError, 1)); 45451cb0ef41Sopenharmony_ci return Changed(node); 45461cb0ef41Sopenharmony_ci } 45471cb0ef41Sopenharmony_ci 45481cb0ef41Sopenharmony_ci // Check for known builtin functions. 45491cb0ef41Sopenharmony_ci 45501cb0ef41Sopenharmony_ci Builtin builtin = 45511cb0ef41Sopenharmony_ci shared.HasBuiltinId() ? shared.builtin_id() : Builtin::kNoBuiltinId; 45521cb0ef41Sopenharmony_ci switch (builtin) { 45531cb0ef41Sopenharmony_ci case Builtin::kArrayConstructor: 45541cb0ef41Sopenharmony_ci return ReduceArrayConstructor(node); 45551cb0ef41Sopenharmony_ci case Builtin::kBooleanConstructor: 45561cb0ef41Sopenharmony_ci return ReduceBooleanConstructor(node); 45571cb0ef41Sopenharmony_ci case Builtin::kFunctionPrototypeApply: 45581cb0ef41Sopenharmony_ci return ReduceFunctionPrototypeApply(node); 45591cb0ef41Sopenharmony_ci case Builtin::kFastFunctionPrototypeBind: 45601cb0ef41Sopenharmony_ci return ReduceFunctionPrototypeBind(node); 45611cb0ef41Sopenharmony_ci case Builtin::kFunctionPrototypeCall: 45621cb0ef41Sopenharmony_ci return ReduceFunctionPrototypeCall(node); 45631cb0ef41Sopenharmony_ci case Builtin::kFunctionPrototypeHasInstance: 45641cb0ef41Sopenharmony_ci return ReduceFunctionPrototypeHasInstance(node); 45651cb0ef41Sopenharmony_ci case Builtin::kObjectConstructor: 45661cb0ef41Sopenharmony_ci return ReduceObjectConstructor(node); 45671cb0ef41Sopenharmony_ci case Builtin::kObjectCreate: 45681cb0ef41Sopenharmony_ci return ReduceObjectCreate(node); 45691cb0ef41Sopenharmony_ci case Builtin::kObjectGetPrototypeOf: 45701cb0ef41Sopenharmony_ci return ReduceObjectGetPrototypeOf(node); 45711cb0ef41Sopenharmony_ci case Builtin::kObjectIs: 45721cb0ef41Sopenharmony_ci return ReduceObjectIs(node); 45731cb0ef41Sopenharmony_ci case Builtin::kObjectPrototypeGetProto: 45741cb0ef41Sopenharmony_ci return ReduceObjectPrototypeGetProto(node); 45751cb0ef41Sopenharmony_ci case Builtin::kObjectPrototypeHasOwnProperty: 45761cb0ef41Sopenharmony_ci return ReduceObjectPrototypeHasOwnProperty(node); 45771cb0ef41Sopenharmony_ci case Builtin::kObjectPrototypeIsPrototypeOf: 45781cb0ef41Sopenharmony_ci return ReduceObjectPrototypeIsPrototypeOf(node); 45791cb0ef41Sopenharmony_ci case Builtin::kReflectApply: 45801cb0ef41Sopenharmony_ci return ReduceReflectApply(node); 45811cb0ef41Sopenharmony_ci case Builtin::kReflectConstruct: 45821cb0ef41Sopenharmony_ci return ReduceReflectConstruct(node); 45831cb0ef41Sopenharmony_ci case Builtin::kReflectGet: 45841cb0ef41Sopenharmony_ci return ReduceReflectGet(node); 45851cb0ef41Sopenharmony_ci case Builtin::kReflectGetPrototypeOf: 45861cb0ef41Sopenharmony_ci return ReduceReflectGetPrototypeOf(node); 45871cb0ef41Sopenharmony_ci case Builtin::kReflectHas: 45881cb0ef41Sopenharmony_ci return ReduceReflectHas(node); 45891cb0ef41Sopenharmony_ci case Builtin::kArrayForEach: 45901cb0ef41Sopenharmony_ci return ReduceArrayForEach(node, shared); 45911cb0ef41Sopenharmony_ci case Builtin::kArrayMap: 45921cb0ef41Sopenharmony_ci return ReduceArrayMap(node, shared); 45931cb0ef41Sopenharmony_ci case Builtin::kArrayFilter: 45941cb0ef41Sopenharmony_ci return ReduceArrayFilter(node, shared); 45951cb0ef41Sopenharmony_ci case Builtin::kArrayReduce: 45961cb0ef41Sopenharmony_ci return ReduceArrayReduce(node, shared); 45971cb0ef41Sopenharmony_ci case Builtin::kArrayReduceRight: 45981cb0ef41Sopenharmony_ci return ReduceArrayReduceRight(node, shared); 45991cb0ef41Sopenharmony_ci case Builtin::kArrayPrototypeFind: 46001cb0ef41Sopenharmony_ci return ReduceArrayFind(node, shared); 46011cb0ef41Sopenharmony_ci case Builtin::kArrayPrototypeFindIndex: 46021cb0ef41Sopenharmony_ci return ReduceArrayFindIndex(node, shared); 46031cb0ef41Sopenharmony_ci case Builtin::kArrayEvery: 46041cb0ef41Sopenharmony_ci return ReduceArrayEvery(node, shared); 46051cb0ef41Sopenharmony_ci case Builtin::kArrayIndexOf: 46061cb0ef41Sopenharmony_ci return ReduceArrayIndexOf(node); 46071cb0ef41Sopenharmony_ci case Builtin::kArrayIncludes: 46081cb0ef41Sopenharmony_ci return ReduceArrayIncludes(node); 46091cb0ef41Sopenharmony_ci case Builtin::kArraySome: 46101cb0ef41Sopenharmony_ci return ReduceArraySome(node, shared); 46111cb0ef41Sopenharmony_ci case Builtin::kArrayPrototypePush: 46121cb0ef41Sopenharmony_ci return ReduceArrayPrototypePush(node); 46131cb0ef41Sopenharmony_ci case Builtin::kArrayPrototypePop: 46141cb0ef41Sopenharmony_ci return ReduceArrayPrototypePop(node); 46151cb0ef41Sopenharmony_ci case Builtin::kArrayPrototypeShift: 46161cb0ef41Sopenharmony_ci return ReduceArrayPrototypeShift(node); 46171cb0ef41Sopenharmony_ci case Builtin::kArrayPrototypeSlice: 46181cb0ef41Sopenharmony_ci return ReduceArrayPrototypeSlice(node); 46191cb0ef41Sopenharmony_ci case Builtin::kArrayPrototypeEntries: 46201cb0ef41Sopenharmony_ci return ReduceArrayIterator(node, ArrayIteratorKind::kArrayLike, 46211cb0ef41Sopenharmony_ci IterationKind::kEntries); 46221cb0ef41Sopenharmony_ci case Builtin::kArrayPrototypeKeys: 46231cb0ef41Sopenharmony_ci return ReduceArrayIterator(node, ArrayIteratorKind::kArrayLike, 46241cb0ef41Sopenharmony_ci IterationKind::kKeys); 46251cb0ef41Sopenharmony_ci case Builtin::kArrayPrototypeValues: 46261cb0ef41Sopenharmony_ci return ReduceArrayIterator(node, ArrayIteratorKind::kArrayLike, 46271cb0ef41Sopenharmony_ci IterationKind::kValues); 46281cb0ef41Sopenharmony_ci case Builtin::kArrayIteratorPrototypeNext: 46291cb0ef41Sopenharmony_ci return ReduceArrayIteratorPrototypeNext(node); 46301cb0ef41Sopenharmony_ci case Builtin::kArrayIsArray: 46311cb0ef41Sopenharmony_ci return ReduceArrayIsArray(node); 46321cb0ef41Sopenharmony_ci case Builtin::kArrayBufferIsView: 46331cb0ef41Sopenharmony_ci return ReduceArrayBufferIsView(node); 46341cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeGetByteLength: 46351cb0ef41Sopenharmony_ci return ReduceArrayBufferViewAccessor( 46361cb0ef41Sopenharmony_ci node, JS_DATA_VIEW_TYPE, 46371cb0ef41Sopenharmony_ci AccessBuilder::ForJSArrayBufferViewByteLength()); 46381cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeGetByteOffset: 46391cb0ef41Sopenharmony_ci return ReduceArrayBufferViewAccessor( 46401cb0ef41Sopenharmony_ci node, JS_DATA_VIEW_TYPE, 46411cb0ef41Sopenharmony_ci AccessBuilder::ForJSArrayBufferViewByteOffset()); 46421cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeGetUint8: 46431cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kGet, 46441cb0ef41Sopenharmony_ci ExternalArrayType::kExternalUint8Array); 46451cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeGetInt8: 46461cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kGet, 46471cb0ef41Sopenharmony_ci ExternalArrayType::kExternalInt8Array); 46481cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeGetUint16: 46491cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kGet, 46501cb0ef41Sopenharmony_ci ExternalArrayType::kExternalUint16Array); 46511cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeGetInt16: 46521cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kGet, 46531cb0ef41Sopenharmony_ci ExternalArrayType::kExternalInt16Array); 46541cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeGetUint32: 46551cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kGet, 46561cb0ef41Sopenharmony_ci ExternalArrayType::kExternalUint32Array); 46571cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeGetInt32: 46581cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kGet, 46591cb0ef41Sopenharmony_ci ExternalArrayType::kExternalInt32Array); 46601cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeGetFloat32: 46611cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kGet, 46621cb0ef41Sopenharmony_ci ExternalArrayType::kExternalFloat32Array); 46631cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeGetFloat64: 46641cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kGet, 46651cb0ef41Sopenharmony_ci ExternalArrayType::kExternalFloat64Array); 46661cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeSetUint8: 46671cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kSet, 46681cb0ef41Sopenharmony_ci ExternalArrayType::kExternalUint8Array); 46691cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeSetInt8: 46701cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kSet, 46711cb0ef41Sopenharmony_ci ExternalArrayType::kExternalInt8Array); 46721cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeSetUint16: 46731cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kSet, 46741cb0ef41Sopenharmony_ci ExternalArrayType::kExternalUint16Array); 46751cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeSetInt16: 46761cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kSet, 46771cb0ef41Sopenharmony_ci ExternalArrayType::kExternalInt16Array); 46781cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeSetUint32: 46791cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kSet, 46801cb0ef41Sopenharmony_ci ExternalArrayType::kExternalUint32Array); 46811cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeSetInt32: 46821cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kSet, 46831cb0ef41Sopenharmony_ci ExternalArrayType::kExternalInt32Array); 46841cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeSetFloat32: 46851cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kSet, 46861cb0ef41Sopenharmony_ci ExternalArrayType::kExternalFloat32Array); 46871cb0ef41Sopenharmony_ci case Builtin::kDataViewPrototypeSetFloat64: 46881cb0ef41Sopenharmony_ci return ReduceDataViewAccess(node, DataViewAccess::kSet, 46891cb0ef41Sopenharmony_ci ExternalArrayType::kExternalFloat64Array); 46901cb0ef41Sopenharmony_ci case Builtin::kTypedArrayPrototypeByteLength: 46911cb0ef41Sopenharmony_ci return ReduceArrayBufferViewAccessor( 46921cb0ef41Sopenharmony_ci node, JS_TYPED_ARRAY_TYPE, 46931cb0ef41Sopenharmony_ci AccessBuilder::ForJSArrayBufferViewByteLength()); 46941cb0ef41Sopenharmony_ci case Builtin::kTypedArrayPrototypeByteOffset: 46951cb0ef41Sopenharmony_ci return ReduceArrayBufferViewAccessor( 46961cb0ef41Sopenharmony_ci node, JS_TYPED_ARRAY_TYPE, 46971cb0ef41Sopenharmony_ci AccessBuilder::ForJSArrayBufferViewByteOffset()); 46981cb0ef41Sopenharmony_ci case Builtin::kTypedArrayPrototypeLength: 46991cb0ef41Sopenharmony_ci return ReduceArrayBufferViewAccessor( 47001cb0ef41Sopenharmony_ci node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength()); 47011cb0ef41Sopenharmony_ci case Builtin::kTypedArrayPrototypeToStringTag: 47021cb0ef41Sopenharmony_ci return ReduceTypedArrayPrototypeToStringTag(node); 47031cb0ef41Sopenharmony_ci case Builtin::kMathAbs: 47041cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberAbs()); 47051cb0ef41Sopenharmony_ci case Builtin::kMathAcos: 47061cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberAcos()); 47071cb0ef41Sopenharmony_ci case Builtin::kMathAcosh: 47081cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberAcosh()); 47091cb0ef41Sopenharmony_ci case Builtin::kMathAsin: 47101cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberAsin()); 47111cb0ef41Sopenharmony_ci case Builtin::kMathAsinh: 47121cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberAsinh()); 47131cb0ef41Sopenharmony_ci case Builtin::kMathAtan: 47141cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberAtan()); 47151cb0ef41Sopenharmony_ci case Builtin::kMathAtanh: 47161cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberAtanh()); 47171cb0ef41Sopenharmony_ci case Builtin::kMathCbrt: 47181cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberCbrt()); 47191cb0ef41Sopenharmony_ci case Builtin::kMathCeil: 47201cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberCeil()); 47211cb0ef41Sopenharmony_ci case Builtin::kMathCos: 47221cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberCos()); 47231cb0ef41Sopenharmony_ci case Builtin::kMathCosh: 47241cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberCosh()); 47251cb0ef41Sopenharmony_ci case Builtin::kMathExp: 47261cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberExp()); 47271cb0ef41Sopenharmony_ci case Builtin::kMathExpm1: 47281cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberExpm1()); 47291cb0ef41Sopenharmony_ci case Builtin::kMathFloor: 47301cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberFloor()); 47311cb0ef41Sopenharmony_ci case Builtin::kMathFround: 47321cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberFround()); 47331cb0ef41Sopenharmony_ci case Builtin::kMathLog: 47341cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberLog()); 47351cb0ef41Sopenharmony_ci case Builtin::kMathLog1p: 47361cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberLog1p()); 47371cb0ef41Sopenharmony_ci case Builtin::kMathLog10: 47381cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberLog10()); 47391cb0ef41Sopenharmony_ci case Builtin::kMathLog2: 47401cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberLog2()); 47411cb0ef41Sopenharmony_ci case Builtin::kMathRound: 47421cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberRound()); 47431cb0ef41Sopenharmony_ci case Builtin::kMathSign: 47441cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberSign()); 47451cb0ef41Sopenharmony_ci case Builtin::kMathSin: 47461cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberSin()); 47471cb0ef41Sopenharmony_ci case Builtin::kMathSinh: 47481cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberSinh()); 47491cb0ef41Sopenharmony_ci case Builtin::kMathSqrt: 47501cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberSqrt()); 47511cb0ef41Sopenharmony_ci case Builtin::kMathTan: 47521cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberTan()); 47531cb0ef41Sopenharmony_ci case Builtin::kMathTanh: 47541cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberTanh()); 47551cb0ef41Sopenharmony_ci case Builtin::kMathTrunc: 47561cb0ef41Sopenharmony_ci return ReduceMathUnary(node, simplified()->NumberTrunc()); 47571cb0ef41Sopenharmony_ci case Builtin::kMathAtan2: 47581cb0ef41Sopenharmony_ci return ReduceMathBinary(node, simplified()->NumberAtan2()); 47591cb0ef41Sopenharmony_ci case Builtin::kMathPow: 47601cb0ef41Sopenharmony_ci return ReduceMathBinary(node, simplified()->NumberPow()); 47611cb0ef41Sopenharmony_ci case Builtin::kMathClz32: 47621cb0ef41Sopenharmony_ci return ReduceMathClz32(node); 47631cb0ef41Sopenharmony_ci case Builtin::kMathImul: 47641cb0ef41Sopenharmony_ci return ReduceMathImul(node); 47651cb0ef41Sopenharmony_ci case Builtin::kMathMax: 47661cb0ef41Sopenharmony_ci return ReduceMathMinMax(node, simplified()->NumberMax(), 47671cb0ef41Sopenharmony_ci jsgraph()->Constant(-V8_INFINITY)); 47681cb0ef41Sopenharmony_ci case Builtin::kMathMin: 47691cb0ef41Sopenharmony_ci return ReduceMathMinMax(node, simplified()->NumberMin(), 47701cb0ef41Sopenharmony_ci jsgraph()->Constant(V8_INFINITY)); 47711cb0ef41Sopenharmony_ci case Builtin::kNumberIsFinite: 47721cb0ef41Sopenharmony_ci return ReduceNumberIsFinite(node); 47731cb0ef41Sopenharmony_ci case Builtin::kNumberIsInteger: 47741cb0ef41Sopenharmony_ci return ReduceNumberIsInteger(node); 47751cb0ef41Sopenharmony_ci case Builtin::kNumberIsSafeInteger: 47761cb0ef41Sopenharmony_ci return ReduceNumberIsSafeInteger(node); 47771cb0ef41Sopenharmony_ci case Builtin::kNumberIsNaN: 47781cb0ef41Sopenharmony_ci return ReduceNumberIsNaN(node); 47791cb0ef41Sopenharmony_ci case Builtin::kNumberParseInt: 47801cb0ef41Sopenharmony_ci return ReduceNumberParseInt(node); 47811cb0ef41Sopenharmony_ci case Builtin::kGlobalIsFinite: 47821cb0ef41Sopenharmony_ci return ReduceGlobalIsFinite(node); 47831cb0ef41Sopenharmony_ci case Builtin::kGlobalIsNaN: 47841cb0ef41Sopenharmony_ci return ReduceGlobalIsNaN(node); 47851cb0ef41Sopenharmony_ci case Builtin::kMapPrototypeGet: 47861cb0ef41Sopenharmony_ci return ReduceMapPrototypeGet(node); 47871cb0ef41Sopenharmony_ci case Builtin::kMapPrototypeHas: 47881cb0ef41Sopenharmony_ci return ReduceMapPrototypeHas(node); 47891cb0ef41Sopenharmony_ci case Builtin::kRegExpPrototypeTest: 47901cb0ef41Sopenharmony_ci return ReduceRegExpPrototypeTest(node); 47911cb0ef41Sopenharmony_ci case Builtin::kReturnReceiver: 47921cb0ef41Sopenharmony_ci return ReduceReturnReceiver(node); 47931cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeIndexOf: 47941cb0ef41Sopenharmony_ci return ReduceStringPrototypeIndexOfIncludes( 47951cb0ef41Sopenharmony_ci node, StringIndexOfIncludesVariant::kIndexOf); 47961cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeIncludes: 47971cb0ef41Sopenharmony_ci return ReduceStringPrototypeIndexOfIncludes( 47981cb0ef41Sopenharmony_ci node, StringIndexOfIncludesVariant::kIncludes); 47991cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeCharAt: 48001cb0ef41Sopenharmony_ci return ReduceStringPrototypeCharAt(node); 48011cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeCharCodeAt: 48021cb0ef41Sopenharmony_ci return ReduceStringPrototypeStringAt(simplified()->StringCharCodeAt(), 48031cb0ef41Sopenharmony_ci node); 48041cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeCodePointAt: 48051cb0ef41Sopenharmony_ci return ReduceStringPrototypeStringAt(simplified()->StringCodePointAt(), 48061cb0ef41Sopenharmony_ci node); 48071cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeSubstring: 48081cb0ef41Sopenharmony_ci return ReduceStringPrototypeSubstring(node); 48091cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeSlice: 48101cb0ef41Sopenharmony_ci return ReduceStringPrototypeSlice(node); 48111cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeSubstr: 48121cb0ef41Sopenharmony_ci return ReduceStringPrototypeSubstr(node); 48131cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeStartsWith: 48141cb0ef41Sopenharmony_ci return ReduceStringPrototypeStartsWith(node); 48151cb0ef41Sopenharmony_ci#ifdef V8_INTL_SUPPORT 48161cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeToLowerCaseIntl: 48171cb0ef41Sopenharmony_ci return ReduceStringPrototypeToLowerCaseIntl(node); 48181cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeToUpperCaseIntl: 48191cb0ef41Sopenharmony_ci return ReduceStringPrototypeToUpperCaseIntl(node); 48201cb0ef41Sopenharmony_ci#endif // V8_INTL_SUPPORT 48211cb0ef41Sopenharmony_ci case Builtin::kStringFromCharCode: 48221cb0ef41Sopenharmony_ci return ReduceStringFromCharCode(node); 48231cb0ef41Sopenharmony_ci case Builtin::kStringFromCodePoint: 48241cb0ef41Sopenharmony_ci return ReduceStringFromCodePoint(node); 48251cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeIterator: 48261cb0ef41Sopenharmony_ci return ReduceStringPrototypeIterator(node); 48271cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeLocaleCompare: 48281cb0ef41Sopenharmony_ci return ReduceStringPrototypeLocaleCompare(node); 48291cb0ef41Sopenharmony_ci case Builtin::kStringIteratorPrototypeNext: 48301cb0ef41Sopenharmony_ci return ReduceStringIteratorPrototypeNext(node); 48311cb0ef41Sopenharmony_ci case Builtin::kStringPrototypeConcat: 48321cb0ef41Sopenharmony_ci return ReduceStringPrototypeConcat(node); 48331cb0ef41Sopenharmony_ci case Builtin::kTypedArrayPrototypeEntries: 48341cb0ef41Sopenharmony_ci return ReduceArrayIterator(node, ArrayIteratorKind::kTypedArray, 48351cb0ef41Sopenharmony_ci IterationKind::kEntries); 48361cb0ef41Sopenharmony_ci case Builtin::kTypedArrayPrototypeKeys: 48371cb0ef41Sopenharmony_ci return ReduceArrayIterator(node, ArrayIteratorKind::kTypedArray, 48381cb0ef41Sopenharmony_ci IterationKind::kKeys); 48391cb0ef41Sopenharmony_ci case Builtin::kTypedArrayPrototypeValues: 48401cb0ef41Sopenharmony_ci return ReduceArrayIterator(node, ArrayIteratorKind::kTypedArray, 48411cb0ef41Sopenharmony_ci IterationKind::kValues); 48421cb0ef41Sopenharmony_ci case Builtin::kPromisePrototypeCatch: 48431cb0ef41Sopenharmony_ci return ReducePromisePrototypeCatch(node); 48441cb0ef41Sopenharmony_ci case Builtin::kPromisePrototypeFinally: 48451cb0ef41Sopenharmony_ci return ReducePromisePrototypeFinally(node); 48461cb0ef41Sopenharmony_ci case Builtin::kPromisePrototypeThen: 48471cb0ef41Sopenharmony_ci return ReducePromisePrototypeThen(node); 48481cb0ef41Sopenharmony_ci case Builtin::kPromiseResolveTrampoline: 48491cb0ef41Sopenharmony_ci return ReducePromiseResolveTrampoline(node); 48501cb0ef41Sopenharmony_ci case Builtin::kMapPrototypeEntries: 48511cb0ef41Sopenharmony_ci return ReduceCollectionIteration(node, CollectionKind::kMap, 48521cb0ef41Sopenharmony_ci IterationKind::kEntries); 48531cb0ef41Sopenharmony_ci case Builtin::kMapPrototypeKeys: 48541cb0ef41Sopenharmony_ci return ReduceCollectionIteration(node, CollectionKind::kMap, 48551cb0ef41Sopenharmony_ci IterationKind::kKeys); 48561cb0ef41Sopenharmony_ci case Builtin::kMapPrototypeGetSize: 48571cb0ef41Sopenharmony_ci return ReduceCollectionPrototypeSize(node, CollectionKind::kMap); 48581cb0ef41Sopenharmony_ci case Builtin::kMapPrototypeValues: 48591cb0ef41Sopenharmony_ci return ReduceCollectionIteration(node, CollectionKind::kMap, 48601cb0ef41Sopenharmony_ci IterationKind::kValues); 48611cb0ef41Sopenharmony_ci case Builtin::kMapIteratorPrototypeNext: 48621cb0ef41Sopenharmony_ci return ReduceCollectionIteratorPrototypeNext( 48631cb0ef41Sopenharmony_ci node, OrderedHashMap::kEntrySize, factory()->empty_ordered_hash_map(), 48641cb0ef41Sopenharmony_ci FIRST_JS_MAP_ITERATOR_TYPE, LAST_JS_MAP_ITERATOR_TYPE); 48651cb0ef41Sopenharmony_ci case Builtin::kSetPrototypeEntries: 48661cb0ef41Sopenharmony_ci return ReduceCollectionIteration(node, CollectionKind::kSet, 48671cb0ef41Sopenharmony_ci IterationKind::kEntries); 48681cb0ef41Sopenharmony_ci case Builtin::kSetPrototypeGetSize: 48691cb0ef41Sopenharmony_ci return ReduceCollectionPrototypeSize(node, CollectionKind::kSet); 48701cb0ef41Sopenharmony_ci case Builtin::kSetPrototypeValues: 48711cb0ef41Sopenharmony_ci return ReduceCollectionIteration(node, CollectionKind::kSet, 48721cb0ef41Sopenharmony_ci IterationKind::kValues); 48731cb0ef41Sopenharmony_ci case Builtin::kSetIteratorPrototypeNext: 48741cb0ef41Sopenharmony_ci return ReduceCollectionIteratorPrototypeNext( 48751cb0ef41Sopenharmony_ci node, OrderedHashSet::kEntrySize, factory()->empty_ordered_hash_set(), 48761cb0ef41Sopenharmony_ci FIRST_JS_SET_ITERATOR_TYPE, LAST_JS_SET_ITERATOR_TYPE); 48771cb0ef41Sopenharmony_ci case Builtin::kDatePrototypeGetTime: 48781cb0ef41Sopenharmony_ci return ReduceDatePrototypeGetTime(node); 48791cb0ef41Sopenharmony_ci case Builtin::kDateNow: 48801cb0ef41Sopenharmony_ci return ReduceDateNow(node); 48811cb0ef41Sopenharmony_ci case Builtin::kNumberConstructor: 48821cb0ef41Sopenharmony_ci return ReduceNumberConstructor(node); 48831cb0ef41Sopenharmony_ci case Builtin::kBigIntAsIntN: 48841cb0ef41Sopenharmony_ci case Builtin::kBigIntAsUintN: 48851cb0ef41Sopenharmony_ci return ReduceBigIntAsN(node, builtin); 48861cb0ef41Sopenharmony_ci default: 48871cb0ef41Sopenharmony_ci break; 48881cb0ef41Sopenharmony_ci } 48891cb0ef41Sopenharmony_ci 48901cb0ef41Sopenharmony_ci if (shared.function_template_info().has_value()) { 48911cb0ef41Sopenharmony_ci return ReduceCallApiFunction(node, shared); 48921cb0ef41Sopenharmony_ci } 48931cb0ef41Sopenharmony_ci 48941cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY 48951cb0ef41Sopenharmony_ci if ((flags() & kInlineJSToWasmCalls) && shared.wasm_function_signature()) { 48961cb0ef41Sopenharmony_ci return ReduceCallWasmFunction(node, shared); 48971cb0ef41Sopenharmony_ci } 48981cb0ef41Sopenharmony_ci#endif // V8_ENABLE_WEBASSEMBLY 48991cb0ef41Sopenharmony_ci 49001cb0ef41Sopenharmony_ci return NoChange(); 49011cb0ef41Sopenharmony_ci} 49021cb0ef41Sopenharmony_ci 49031cb0ef41Sopenharmony_ciTNode<Object> JSCallReducerAssembler::ReduceJSCallWithArrayLikeOrSpreadOfEmpty( 49041cb0ef41Sopenharmony_ci std::unordered_set<Node*>* generated_calls_with_array_like_or_spread) { 49051cb0ef41Sopenharmony_ci DCHECK_EQ(generated_calls_with_array_like_or_spread->count(node_ptr()), 0); 49061cb0ef41Sopenharmony_ci JSCallWithArrayLikeOrSpreadNode n(node_ptr()); 49071cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 49081cb0ef41Sopenharmony_ci TNode<Object> arguments_list = n.LastArgument(); 49091cb0ef41Sopenharmony_ci DCHECK_EQ(static_cast<Node*>(arguments_list)->opcode(), 49101cb0ef41Sopenharmony_ci IrOpcode::kJSCreateEmptyLiteralArray); 49111cb0ef41Sopenharmony_ci 49121cb0ef41Sopenharmony_ci // Turn the JSCallWithArrayLike or JSCallWithSpread roughly into: 49131cb0ef41Sopenharmony_ci // 49141cb0ef41Sopenharmony_ci // "arguments_list array is still empty?" 49151cb0ef41Sopenharmony_ci // | 49161cb0ef41Sopenharmony_ci // | 49171cb0ef41Sopenharmony_ci // Branch 49181cb0ef41Sopenharmony_ci // / \ 49191cb0ef41Sopenharmony_ci // / \ 49201cb0ef41Sopenharmony_ci // IfTrue IfFalse 49211cb0ef41Sopenharmony_ci // | | 49221cb0ef41Sopenharmony_ci // | | 49231cb0ef41Sopenharmony_ci // JSCall JSCallWithArrayLike/JSCallWithSpread 49241cb0ef41Sopenharmony_ci // \ / 49251cb0ef41Sopenharmony_ci // \ / 49261cb0ef41Sopenharmony_ci // Merge 49271cb0ef41Sopenharmony_ci 49281cb0ef41Sopenharmony_ci TNode<Number> length = TNode<Number>::UncheckedCast( 49291cb0ef41Sopenharmony_ci LoadField(AccessBuilder::ForJSArrayLength(NO_ELEMENTS), arguments_list)); 49301cb0ef41Sopenharmony_ci return SelectIf<Object>(NumberEqual(length, ZeroConstant())) 49311cb0ef41Sopenharmony_ci .Then([&]() { 49321cb0ef41Sopenharmony_ci TNode<Object> call = CopyNode(); 49331cb0ef41Sopenharmony_ci static_cast<Node*>(call)->RemoveInput(n.LastArgumentIndex()); 49341cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 49351cb0ef41Sopenharmony_ci call, javascript()->Call(p.arity() - 1, p.frequency(), p.feedback(), 49361cb0ef41Sopenharmony_ci p.convert_mode(), p.speculation_mode(), 49371cb0ef41Sopenharmony_ci p.feedback_relation())); 49381cb0ef41Sopenharmony_ci return call; 49391cb0ef41Sopenharmony_ci }) 49401cb0ef41Sopenharmony_ci .Else([&]() { 49411cb0ef41Sopenharmony_ci TNode<Object> call = CopyNode(); 49421cb0ef41Sopenharmony_ci generated_calls_with_array_like_or_spread->insert(call); 49431cb0ef41Sopenharmony_ci return call; 49441cb0ef41Sopenharmony_ci }) 49451cb0ef41Sopenharmony_ci .ExpectFalse() 49461cb0ef41Sopenharmony_ci .Value(); 49471cb0ef41Sopenharmony_ci} 49481cb0ef41Sopenharmony_ci 49491cb0ef41Sopenharmony_cinamespace { 49501cb0ef41Sopenharmony_ci 49511cb0ef41Sopenharmony_ci// Check if the target is a class constructor. 49521cb0ef41Sopenharmony_ci// We need to check all cases where the target will be typed as Function 49531cb0ef41Sopenharmony_ci// to prevent later optimizations from using the CallFunction trampoline, 49541cb0ef41Sopenharmony_ci// skipping the instance type check. 49551cb0ef41Sopenharmony_cibool TargetIsClassConstructor(Node* node, JSHeapBroker* broker) { 49561cb0ef41Sopenharmony_ci Node* target = NodeProperties::GetValueInput(node, 0); 49571cb0ef41Sopenharmony_ci base::Optional<SharedFunctionInfoRef> shared; 49581cb0ef41Sopenharmony_ci HeapObjectMatcher m(target); 49591cb0ef41Sopenharmony_ci if (m.HasResolvedValue()) { 49601cb0ef41Sopenharmony_ci ObjectRef target_ref = m.Ref(broker); 49611cb0ef41Sopenharmony_ci if (target_ref.IsJSFunction()) { 49621cb0ef41Sopenharmony_ci JSFunctionRef function = target_ref.AsJSFunction(); 49631cb0ef41Sopenharmony_ci shared = function.shared(); 49641cb0ef41Sopenharmony_ci } 49651cb0ef41Sopenharmony_ci } else if (target->opcode() == IrOpcode::kJSCreateClosure) { 49661cb0ef41Sopenharmony_ci CreateClosureParameters const& ccp = 49671cb0ef41Sopenharmony_ci JSCreateClosureNode{target}.Parameters(); 49681cb0ef41Sopenharmony_ci shared = ccp.shared_info(broker); 49691cb0ef41Sopenharmony_ci } else if (target->opcode() == IrOpcode::kCheckClosure) { 49701cb0ef41Sopenharmony_ci FeedbackCellRef cell = MakeRef(broker, FeedbackCellOf(target->op())); 49711cb0ef41Sopenharmony_ci shared = cell.shared_function_info(); 49721cb0ef41Sopenharmony_ci } 49731cb0ef41Sopenharmony_ci 49741cb0ef41Sopenharmony_ci if (shared.has_value() && IsClassConstructor(shared->kind())) return true; 49751cb0ef41Sopenharmony_ci 49761cb0ef41Sopenharmony_ci return false; 49771cb0ef41Sopenharmony_ci} 49781cb0ef41Sopenharmony_ci 49791cb0ef41Sopenharmony_ci} // namespace 49801cb0ef41Sopenharmony_ci 49811cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceJSCallWithArrayLike(Node* node) { 49821cb0ef41Sopenharmony_ci JSCallWithArrayLikeNode n(node); 49831cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 49841cb0ef41Sopenharmony_ci DCHECK_EQ(p.arity_without_implicit_args(), 1); // The arraylike object. 49851cb0ef41Sopenharmony_ci // Class constructors are callable, but [[Call]] will raise an exception. 49861cb0ef41Sopenharmony_ci // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). 49871cb0ef41Sopenharmony_ci if (TargetIsClassConstructor(node, broker())) { 49881cb0ef41Sopenharmony_ci return NoChange(); 49891cb0ef41Sopenharmony_ci } 49901cb0ef41Sopenharmony_ci return ReduceCallOrConstructWithArrayLikeOrSpread( 49911cb0ef41Sopenharmony_ci node, n.ArgumentCount(), n.LastArgumentIndex(), p.frequency(), 49921cb0ef41Sopenharmony_ci p.feedback(), p.speculation_mode(), p.feedback_relation(), n.target(), 49931cb0ef41Sopenharmony_ci n.effect(), n.control()); 49941cb0ef41Sopenharmony_ci} 49951cb0ef41Sopenharmony_ci 49961cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceJSCallWithSpread(Node* node) { 49971cb0ef41Sopenharmony_ci JSCallWithSpreadNode n(node); 49981cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 49991cb0ef41Sopenharmony_ci DCHECK_GE(p.arity_without_implicit_args(), 1); // At least the spread. 50001cb0ef41Sopenharmony_ci // Class constructors are callable, but [[Call]] will raise an exception. 50011cb0ef41Sopenharmony_ci // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList ). 50021cb0ef41Sopenharmony_ci if (TargetIsClassConstructor(node, broker())) { 50031cb0ef41Sopenharmony_ci return NoChange(); 50041cb0ef41Sopenharmony_ci } 50051cb0ef41Sopenharmony_ci return ReduceCallOrConstructWithArrayLikeOrSpread( 50061cb0ef41Sopenharmony_ci node, n.ArgumentCount(), n.LastArgumentIndex(), p.frequency(), 50071cb0ef41Sopenharmony_ci p.feedback(), p.speculation_mode(), p.feedback_relation(), n.target(), 50081cb0ef41Sopenharmony_ci n.effect(), n.control()); 50091cb0ef41Sopenharmony_ci} 50101cb0ef41Sopenharmony_ci 50111cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceJSConstruct(Node* node) { 50121cb0ef41Sopenharmony_ci if (broker()->StackHasOverflowed()) return NoChange(); 50131cb0ef41Sopenharmony_ci 50141cb0ef41Sopenharmony_ci JSConstructNode n(node); 50151cb0ef41Sopenharmony_ci ConstructParameters const& p = n.Parameters(); 50161cb0ef41Sopenharmony_ci int arity = p.arity_without_implicit_args(); 50171cb0ef41Sopenharmony_ci Node* target = n.target(); 50181cb0ef41Sopenharmony_ci Node* new_target = n.new_target(); 50191cb0ef41Sopenharmony_ci Effect effect = n.effect(); 50201cb0ef41Sopenharmony_ci Control control = n.control(); 50211cb0ef41Sopenharmony_ci 50221cb0ef41Sopenharmony_ci if (p.feedback().IsValid()) { 50231cb0ef41Sopenharmony_ci ProcessedFeedback const& feedback = 50241cb0ef41Sopenharmony_ci broker()->GetFeedbackForCall(p.feedback()); 50251cb0ef41Sopenharmony_ci if (feedback.IsInsufficient()) { 50261cb0ef41Sopenharmony_ci return ReduceForInsufficientFeedback( 50271cb0ef41Sopenharmony_ci node, DeoptimizeReason::kInsufficientTypeFeedbackForConstruct); 50281cb0ef41Sopenharmony_ci } 50291cb0ef41Sopenharmony_ci 50301cb0ef41Sopenharmony_ci base::Optional<HeapObjectRef> feedback_target = feedback.AsCall().target(); 50311cb0ef41Sopenharmony_ci if (feedback_target.has_value() && feedback_target->IsAllocationSite()) { 50321cb0ef41Sopenharmony_ci // The feedback is an AllocationSite, which means we have called the 50331cb0ef41Sopenharmony_ci // Array function and collected transition (and pretenuring) feedback 50341cb0ef41Sopenharmony_ci // for the resulting arrays. This has to be kept in sync with the 50351cb0ef41Sopenharmony_ci // implementation in Ignition. 50361cb0ef41Sopenharmony_ci 50371cb0ef41Sopenharmony_ci Node* array_function = 50381cb0ef41Sopenharmony_ci jsgraph()->Constant(native_context().array_function()); 50391cb0ef41Sopenharmony_ci 50401cb0ef41Sopenharmony_ci // Check that the {target} is still the {array_function}. 50411cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->ReferenceEqual(), target, 50421cb0ef41Sopenharmony_ci array_function); 50431cb0ef41Sopenharmony_ci effect = graph()->NewNode( 50441cb0ef41Sopenharmony_ci simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check, 50451cb0ef41Sopenharmony_ci effect, control); 50461cb0ef41Sopenharmony_ci 50471cb0ef41Sopenharmony_ci // Turn the {node} into a {JSCreateArray} call. 50481cb0ef41Sopenharmony_ci NodeProperties::ReplaceEffectInput(node, effect); 50491cb0ef41Sopenharmony_ci STATIC_ASSERT(JSConstructNode::NewTargetIndex() == 1); 50501cb0ef41Sopenharmony_ci node->ReplaceInput(n.NewTargetIndex(), array_function); 50511cb0ef41Sopenharmony_ci node->RemoveInput(n.FeedbackVectorIndex()); 50521cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 50531cb0ef41Sopenharmony_ci node, javascript()->CreateArray(arity, 50541cb0ef41Sopenharmony_ci feedback_target->AsAllocationSite())); 50551cb0ef41Sopenharmony_ci return Changed(node); 50561cb0ef41Sopenharmony_ci } else if (feedback_target.has_value() && 50571cb0ef41Sopenharmony_ci !HeapObjectMatcher(new_target).HasResolvedValue() && 50581cb0ef41Sopenharmony_ci feedback_target->map().is_constructor()) { 50591cb0ef41Sopenharmony_ci Node* new_target_feedback = jsgraph()->Constant(*feedback_target); 50601cb0ef41Sopenharmony_ci 50611cb0ef41Sopenharmony_ci // Check that the {new_target} is still the {new_target_feedback}. 50621cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->ReferenceEqual(), new_target, 50631cb0ef41Sopenharmony_ci new_target_feedback); 50641cb0ef41Sopenharmony_ci effect = graph()->NewNode( 50651cb0ef41Sopenharmony_ci simplified()->CheckIf(DeoptimizeReason::kWrongCallTarget), check, 50661cb0ef41Sopenharmony_ci effect, control); 50671cb0ef41Sopenharmony_ci 50681cb0ef41Sopenharmony_ci // Specialize the JSConstruct node to the {new_target_feedback}. 50691cb0ef41Sopenharmony_ci node->ReplaceInput(n.NewTargetIndex(), new_target_feedback); 50701cb0ef41Sopenharmony_ci NodeProperties::ReplaceEffectInput(node, effect); 50711cb0ef41Sopenharmony_ci if (target == new_target) { 50721cb0ef41Sopenharmony_ci node->ReplaceInput(n.TargetIndex(), new_target_feedback); 50731cb0ef41Sopenharmony_ci } 50741cb0ef41Sopenharmony_ci 50751cb0ef41Sopenharmony_ci // Try to further reduce the JSConstruct {node}. 50761cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSConstruct(node)); 50771cb0ef41Sopenharmony_ci } 50781cb0ef41Sopenharmony_ci } 50791cb0ef41Sopenharmony_ci 50801cb0ef41Sopenharmony_ci // Try to specialize JSConstruct {node}s with constant {target}s. 50811cb0ef41Sopenharmony_ci HeapObjectMatcher m(target); 50821cb0ef41Sopenharmony_ci if (m.HasResolvedValue()) { 50831cb0ef41Sopenharmony_ci HeapObjectRef target_ref = m.Ref(broker()); 50841cb0ef41Sopenharmony_ci 50851cb0ef41Sopenharmony_ci // Raise a TypeError if the {target} is not a constructor. 50861cb0ef41Sopenharmony_ci if (!target_ref.map().is_constructor()) { 50871cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInputs(node, target); 50881cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, 50891cb0ef41Sopenharmony_ci javascript()->CallRuntime( 50901cb0ef41Sopenharmony_ci Runtime::kThrowConstructedNonConstructable)); 50911cb0ef41Sopenharmony_ci return Changed(node); 50921cb0ef41Sopenharmony_ci } 50931cb0ef41Sopenharmony_ci 50941cb0ef41Sopenharmony_ci if (target_ref.IsJSFunction()) { 50951cb0ef41Sopenharmony_ci JSFunctionRef function = target_ref.AsJSFunction(); 50961cb0ef41Sopenharmony_ci 50971cb0ef41Sopenharmony_ci // Do not reduce constructors with break points. 50981cb0ef41Sopenharmony_ci // If this state changes during background compilation, the compilation 50991cb0ef41Sopenharmony_ci // job will be aborted from the main thread (see 51001cb0ef41Sopenharmony_ci // Debug::PrepareFunctionForDebugExecution()). 51011cb0ef41Sopenharmony_ci SharedFunctionInfoRef sfi = function.shared(); 51021cb0ef41Sopenharmony_ci if (sfi.HasBreakInfo()) return NoChange(); 51031cb0ef41Sopenharmony_ci 51041cb0ef41Sopenharmony_ci // Don't inline cross native context. 51051cb0ef41Sopenharmony_ci if (!function.native_context().equals(native_context())) { 51061cb0ef41Sopenharmony_ci return NoChange(); 51071cb0ef41Sopenharmony_ci } 51081cb0ef41Sopenharmony_ci 51091cb0ef41Sopenharmony_ci // Check for known builtin functions. 51101cb0ef41Sopenharmony_ci Builtin builtin = 51111cb0ef41Sopenharmony_ci sfi.HasBuiltinId() ? sfi.builtin_id() : Builtin::kNoBuiltinId; 51121cb0ef41Sopenharmony_ci switch (builtin) { 51131cb0ef41Sopenharmony_ci case Builtin::kArrayConstructor: { 51141cb0ef41Sopenharmony_ci // TODO(bmeurer): Deal with Array subclasses here. 51151cb0ef41Sopenharmony_ci // Turn the {node} into a {JSCreateArray} call. 51161cb0ef41Sopenharmony_ci STATIC_ASSERT(JSConstructNode::NewTargetIndex() == 1); 51171cb0ef41Sopenharmony_ci node->ReplaceInput(n.NewTargetIndex(), new_target); 51181cb0ef41Sopenharmony_ci node->RemoveInput(n.FeedbackVectorIndex()); 51191cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 51201cb0ef41Sopenharmony_ci node, javascript()->CreateArray(arity, base::nullopt)); 51211cb0ef41Sopenharmony_ci return Changed(node); 51221cb0ef41Sopenharmony_ci } 51231cb0ef41Sopenharmony_ci case Builtin::kObjectConstructor: { 51241cb0ef41Sopenharmony_ci // If no value is passed, we can immediately lower to a simple 51251cb0ef41Sopenharmony_ci // JSCreate and don't need to do any massaging of the {node}. 51261cb0ef41Sopenharmony_ci if (arity == 0) { 51271cb0ef41Sopenharmony_ci node->RemoveInput(n.FeedbackVectorIndex()); 51281cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, javascript()->Create()); 51291cb0ef41Sopenharmony_ci return Changed(node); 51301cb0ef41Sopenharmony_ci } 51311cb0ef41Sopenharmony_ci 51321cb0ef41Sopenharmony_ci // If {target} is not the same as {new_target} (i.e. the Object 51331cb0ef41Sopenharmony_ci // constructor), {value} will be ignored and therefore we can lower 51341cb0ef41Sopenharmony_ci // to {JSCreate}. See https://tc39.es/ecma262/#sec-object-value. 51351cb0ef41Sopenharmony_ci HeapObjectMatcher mnew_target(new_target); 51361cb0ef41Sopenharmony_ci if (mnew_target.HasResolvedValue() && 51371cb0ef41Sopenharmony_ci !mnew_target.Ref(broker()).equals(function)) { 51381cb0ef41Sopenharmony_ci // Drop the value inputs. 51391cb0ef41Sopenharmony_ci node->RemoveInput(n.FeedbackVectorIndex()); 51401cb0ef41Sopenharmony_ci for (int i = n.ArgumentCount() - 1; i >= 0; i--) { 51411cb0ef41Sopenharmony_ci node->RemoveInput(n.ArgumentIndex(i)); 51421cb0ef41Sopenharmony_ci } 51431cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, javascript()->Create()); 51441cb0ef41Sopenharmony_ci return Changed(node); 51451cb0ef41Sopenharmony_ci } 51461cb0ef41Sopenharmony_ci break; 51471cb0ef41Sopenharmony_ci } 51481cb0ef41Sopenharmony_ci case Builtin::kPromiseConstructor: 51491cb0ef41Sopenharmony_ci return ReducePromiseConstructor(node); 51501cb0ef41Sopenharmony_ci case Builtin::kTypedArrayConstructor: 51511cb0ef41Sopenharmony_ci return ReduceTypedArrayConstructor(node, function.shared()); 51521cb0ef41Sopenharmony_ci default: 51531cb0ef41Sopenharmony_ci break; 51541cb0ef41Sopenharmony_ci } 51551cb0ef41Sopenharmony_ci } else if (target_ref.IsJSBoundFunction()) { 51561cb0ef41Sopenharmony_ci JSBoundFunctionRef function = target_ref.AsJSBoundFunction(); 51571cb0ef41Sopenharmony_ci JSReceiverRef bound_target_function = function.bound_target_function(); 51581cb0ef41Sopenharmony_ci FixedArrayRef bound_arguments = function.bound_arguments(); 51591cb0ef41Sopenharmony_ci const int bound_arguments_length = bound_arguments.length(); 51601cb0ef41Sopenharmony_ci 51611cb0ef41Sopenharmony_ci // TODO(jgruber): Inline this block below once TryGet is guaranteed to 51621cb0ef41Sopenharmony_ci // succeed. 51631cb0ef41Sopenharmony_ci static constexpr int kInlineSize = 16; // Arbitrary. 51641cb0ef41Sopenharmony_ci base::SmallVector<Node*, kInlineSize> args; 51651cb0ef41Sopenharmony_ci for (int i = 0; i < bound_arguments_length; ++i) { 51661cb0ef41Sopenharmony_ci base::Optional<ObjectRef> maybe_arg = bound_arguments.TryGet(i); 51671cb0ef41Sopenharmony_ci if (!maybe_arg.has_value()) { 51681cb0ef41Sopenharmony_ci TRACE_BROKER_MISSING(broker(), "bound argument"); 51691cb0ef41Sopenharmony_ci return NoChange(); 51701cb0ef41Sopenharmony_ci } 51711cb0ef41Sopenharmony_ci args.emplace_back(jsgraph()->Constant(maybe_arg.value())); 51721cb0ef41Sopenharmony_ci } 51731cb0ef41Sopenharmony_ci 51741cb0ef41Sopenharmony_ci // Patch {node} to use [[BoundTargetFunction]]. 51751cb0ef41Sopenharmony_ci node->ReplaceInput(n.TargetIndex(), 51761cb0ef41Sopenharmony_ci jsgraph()->Constant(bound_target_function)); 51771cb0ef41Sopenharmony_ci 51781cb0ef41Sopenharmony_ci // Patch {node} to use [[BoundTargetFunction]] 51791cb0ef41Sopenharmony_ci // as new.target if {new_target} equals {target}. 51801cb0ef41Sopenharmony_ci if (target == new_target) { 51811cb0ef41Sopenharmony_ci node->ReplaceInput(n.NewTargetIndex(), 51821cb0ef41Sopenharmony_ci jsgraph()->Constant(bound_target_function)); 51831cb0ef41Sopenharmony_ci } else { 51841cb0ef41Sopenharmony_ci node->ReplaceInput( 51851cb0ef41Sopenharmony_ci n.NewTargetIndex(), 51861cb0ef41Sopenharmony_ci graph()->NewNode(common()->Select(MachineRepresentation::kTagged), 51871cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->ReferenceEqual(), 51881cb0ef41Sopenharmony_ci target, new_target), 51891cb0ef41Sopenharmony_ci jsgraph()->Constant(bound_target_function), 51901cb0ef41Sopenharmony_ci new_target)); 51911cb0ef41Sopenharmony_ci } 51921cb0ef41Sopenharmony_ci 51931cb0ef41Sopenharmony_ci // Insert the [[BoundArguments]] for {node}. 51941cb0ef41Sopenharmony_ci for (int i = 0; i < bound_arguments_length; ++i) { 51951cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), n.ArgumentIndex(i), args[i]); 51961cb0ef41Sopenharmony_ci arity++; 51971cb0ef41Sopenharmony_ci } 51981cb0ef41Sopenharmony_ci 51991cb0ef41Sopenharmony_ci // Update the JSConstruct operator on {node}. 52001cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 52011cb0ef41Sopenharmony_ci node, javascript()->Construct(JSConstructNode::ArityForArgc(arity), 52021cb0ef41Sopenharmony_ci p.frequency(), FeedbackSource())); 52031cb0ef41Sopenharmony_ci 52041cb0ef41Sopenharmony_ci // Try to further reduce the JSConstruct {node}. 52051cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSConstruct(node)); 52061cb0ef41Sopenharmony_ci } 52071cb0ef41Sopenharmony_ci 52081cb0ef41Sopenharmony_ci // TODO(bmeurer): Also support optimizing proxies here. 52091cb0ef41Sopenharmony_ci } 52101cb0ef41Sopenharmony_ci 52111cb0ef41Sopenharmony_ci // If {target} is the result of a JSCreateBoundFunction operation, 52121cb0ef41Sopenharmony_ci // we can just fold the construction and construct the bound target 52131cb0ef41Sopenharmony_ci // function directly instead. 52141cb0ef41Sopenharmony_ci if (target->opcode() == IrOpcode::kJSCreateBoundFunction) { 52151cb0ef41Sopenharmony_ci Node* bound_target_function = NodeProperties::GetValueInput(target, 0); 52161cb0ef41Sopenharmony_ci int const bound_arguments_length = 52171cb0ef41Sopenharmony_ci static_cast<int>(CreateBoundFunctionParametersOf(target->op()).arity()); 52181cb0ef41Sopenharmony_ci 52191cb0ef41Sopenharmony_ci // Patch the {node} to use [[BoundTargetFunction]]. 52201cb0ef41Sopenharmony_ci node->ReplaceInput(n.TargetIndex(), bound_target_function); 52211cb0ef41Sopenharmony_ci 52221cb0ef41Sopenharmony_ci // Patch {node} to use [[BoundTargetFunction]] 52231cb0ef41Sopenharmony_ci // as new.target if {new_target} equals {target}. 52241cb0ef41Sopenharmony_ci if (target == new_target) { 52251cb0ef41Sopenharmony_ci node->ReplaceInput(n.NewTargetIndex(), bound_target_function); 52261cb0ef41Sopenharmony_ci } else { 52271cb0ef41Sopenharmony_ci node->ReplaceInput( 52281cb0ef41Sopenharmony_ci n.NewTargetIndex(), 52291cb0ef41Sopenharmony_ci graph()->NewNode(common()->Select(MachineRepresentation::kTagged), 52301cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->ReferenceEqual(), 52311cb0ef41Sopenharmony_ci target, new_target), 52321cb0ef41Sopenharmony_ci bound_target_function, new_target)); 52331cb0ef41Sopenharmony_ci } 52341cb0ef41Sopenharmony_ci 52351cb0ef41Sopenharmony_ci // Insert the [[BoundArguments]] for {node}. 52361cb0ef41Sopenharmony_ci for (int i = 0; i < bound_arguments_length; ++i) { 52371cb0ef41Sopenharmony_ci Node* value = NodeProperties::GetValueInput(target, 2 + i); 52381cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), n.ArgumentIndex(i), value); 52391cb0ef41Sopenharmony_ci arity++; 52401cb0ef41Sopenharmony_ci } 52411cb0ef41Sopenharmony_ci 52421cb0ef41Sopenharmony_ci // Update the JSConstruct operator on {node}. 52431cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 52441cb0ef41Sopenharmony_ci node, javascript()->Construct(JSConstructNode::ArityForArgc(arity), 52451cb0ef41Sopenharmony_ci p.frequency(), FeedbackSource())); 52461cb0ef41Sopenharmony_ci 52471cb0ef41Sopenharmony_ci // Try to further reduce the JSConstruct {node}. 52481cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReduceJSConstruct(node)); 52491cb0ef41Sopenharmony_ci } 52501cb0ef41Sopenharmony_ci 52511cb0ef41Sopenharmony_ci return NoChange(); 52521cb0ef41Sopenharmony_ci} 52531cb0ef41Sopenharmony_ci 52541cb0ef41Sopenharmony_ci// ES #sec-string.prototype.indexof 52551cb0ef41Sopenharmony_ci// ES #sec-string.prototype.includes 52561cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringPrototypeIndexOfIncludes( 52571cb0ef41Sopenharmony_ci Node* node, StringIndexOfIncludesVariant variant) { 52581cb0ef41Sopenharmony_ci JSCallNode n(node); 52591cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 52601cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 52611cb0ef41Sopenharmony_ci return NoChange(); 52621cb0ef41Sopenharmony_ci } 52631cb0ef41Sopenharmony_ci 52641cb0ef41Sopenharmony_ci Effect effect = n.effect(); 52651cb0ef41Sopenharmony_ci Control control = n.control(); 52661cb0ef41Sopenharmony_ci if (n.ArgumentCount() > 0) { 52671cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 52681cb0ef41Sopenharmony_ci Node* new_receiver = effect = graph()->NewNode( 52691cb0ef41Sopenharmony_ci simplified()->CheckString(p.feedback()), receiver, effect, control); 52701cb0ef41Sopenharmony_ci 52711cb0ef41Sopenharmony_ci Node* search_string = n.Argument(0); 52721cb0ef41Sopenharmony_ci Node* new_search_string = effect = 52731cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->CheckString(p.feedback()), search_string, 52741cb0ef41Sopenharmony_ci effect, control); 52751cb0ef41Sopenharmony_ci 52761cb0ef41Sopenharmony_ci Node* new_position = jsgraph()->ZeroConstant(); 52771cb0ef41Sopenharmony_ci if (n.ArgumentCount() > 1) { 52781cb0ef41Sopenharmony_ci Node* position = n.Argument(1); 52791cb0ef41Sopenharmony_ci new_position = effect = graph()->NewNode( 52801cb0ef41Sopenharmony_ci simplified()->CheckSmi(p.feedback()), position, effect, control); 52811cb0ef41Sopenharmony_ci 52821cb0ef41Sopenharmony_ci Node* receiver_length = 52831cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->StringLength(), new_receiver); 52841cb0ef41Sopenharmony_ci new_position = graph()->NewNode( 52851cb0ef41Sopenharmony_ci simplified()->NumberMin(), 52861cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberMax(), new_position, 52871cb0ef41Sopenharmony_ci jsgraph()->ZeroConstant()), 52881cb0ef41Sopenharmony_ci receiver_length); 52891cb0ef41Sopenharmony_ci } 52901cb0ef41Sopenharmony_ci 52911cb0ef41Sopenharmony_ci NodeProperties::ReplaceEffectInput(node, effect); 52921cb0ef41Sopenharmony_ci RelaxEffectsAndControls(node); 52931cb0ef41Sopenharmony_ci node->ReplaceInput(0, new_receiver); 52941cb0ef41Sopenharmony_ci node->ReplaceInput(1, new_search_string); 52951cb0ef41Sopenharmony_ci node->ReplaceInput(2, new_position); 52961cb0ef41Sopenharmony_ci node->TrimInputCount(3); 52971cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, simplified()->StringIndexOf()); 52981cb0ef41Sopenharmony_ci 52991cb0ef41Sopenharmony_ci if (variant == StringIndexOfIncludesVariant::kIndexOf) { 53001cb0ef41Sopenharmony_ci return Changed(node); 53011cb0ef41Sopenharmony_ci } else { 53021cb0ef41Sopenharmony_ci DCHECK(variant == StringIndexOfIncludesVariant::kIncludes); 53031cb0ef41Sopenharmony_ci Node* result = 53041cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->BooleanNot(), 53051cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberEqual(), node, 53061cb0ef41Sopenharmony_ci jsgraph()->SmiConstant(-1))); 53071cb0ef41Sopenharmony_ci return Replace(result); 53081cb0ef41Sopenharmony_ci } 53091cb0ef41Sopenharmony_ci } 53101cb0ef41Sopenharmony_ci return NoChange(); 53111cb0ef41Sopenharmony_ci} 53121cb0ef41Sopenharmony_ci 53131cb0ef41Sopenharmony_ci// ES #sec-string.prototype.substring 53141cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringPrototypeSubstring(Node* node) { 53151cb0ef41Sopenharmony_ci JSCallNode n(node); 53161cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 53171cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) return NoChange(); 53181cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 53191cb0ef41Sopenharmony_ci return NoChange(); 53201cb0ef41Sopenharmony_ci } 53211cb0ef41Sopenharmony_ci 53221cb0ef41Sopenharmony_ci JSCallReducerAssembler a(this, node); 53231cb0ef41Sopenharmony_ci Node* subgraph = a.ReduceStringPrototypeSubstring(); 53241cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 53251cb0ef41Sopenharmony_ci} 53261cb0ef41Sopenharmony_ci 53271cb0ef41Sopenharmony_ci// ES #sec-string.prototype.slice 53281cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringPrototypeSlice(Node* node) { 53291cb0ef41Sopenharmony_ci JSCallNode n(node); 53301cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 53311cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) return NoChange(); 53321cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 53331cb0ef41Sopenharmony_ci return NoChange(); 53341cb0ef41Sopenharmony_ci } 53351cb0ef41Sopenharmony_ci 53361cb0ef41Sopenharmony_ci JSCallReducerAssembler a(this, node); 53371cb0ef41Sopenharmony_ci Node* subgraph = a.ReduceStringPrototypeSlice(); 53381cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 53391cb0ef41Sopenharmony_ci} 53401cb0ef41Sopenharmony_ci 53411cb0ef41Sopenharmony_ci// ES #sec-string.prototype.substr 53421cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringPrototypeSubstr(Node* node) { 53431cb0ef41Sopenharmony_ci JSCallNode n(node); 53441cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 53451cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) return NoChange(); 53461cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 53471cb0ef41Sopenharmony_ci return NoChange(); 53481cb0ef41Sopenharmony_ci } 53491cb0ef41Sopenharmony_ci 53501cb0ef41Sopenharmony_ci Effect effect = n.effect(); 53511cb0ef41Sopenharmony_ci Control control = n.control(); 53521cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 53531cb0ef41Sopenharmony_ci Node* start = n.Argument(0); 53541cb0ef41Sopenharmony_ci Node* end = n.ArgumentOrUndefined(1, jsgraph()); 53551cb0ef41Sopenharmony_ci 53561cb0ef41Sopenharmony_ci receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()), 53571cb0ef41Sopenharmony_ci receiver, effect, control); 53581cb0ef41Sopenharmony_ci 53591cb0ef41Sopenharmony_ci start = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()), start, 53601cb0ef41Sopenharmony_ci effect, control); 53611cb0ef41Sopenharmony_ci 53621cb0ef41Sopenharmony_ci Node* length = graph()->NewNode(simplified()->StringLength(), receiver); 53631cb0ef41Sopenharmony_ci 53641cb0ef41Sopenharmony_ci // Replace {end} argument with {length} if it is undefined. 53651cb0ef41Sopenharmony_ci { 53661cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->ReferenceEqual(), end, 53671cb0ef41Sopenharmony_ci jsgraph()->UndefinedConstant()); 53681cb0ef41Sopenharmony_ci Node* branch = 53691cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); 53701cb0ef41Sopenharmony_ci 53711cb0ef41Sopenharmony_ci Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 53721cb0ef41Sopenharmony_ci Node* etrue = effect; 53731cb0ef41Sopenharmony_ci Node* vtrue = length; 53741cb0ef41Sopenharmony_ci 53751cb0ef41Sopenharmony_ci Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 53761cb0ef41Sopenharmony_ci Node* efalse = effect; 53771cb0ef41Sopenharmony_ci Node* vfalse = efalse = graph()->NewNode( 53781cb0ef41Sopenharmony_ci simplified()->CheckSmi(p.feedback()), end, efalse, if_false); 53791cb0ef41Sopenharmony_ci 53801cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Merge(2), if_true, if_false); 53811cb0ef41Sopenharmony_ci effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); 53821cb0ef41Sopenharmony_ci end = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 53831cb0ef41Sopenharmony_ci vtrue, vfalse, control); 53841cb0ef41Sopenharmony_ci } 53851cb0ef41Sopenharmony_ci 53861cb0ef41Sopenharmony_ci Node* initStart = graph()->NewNode( 53871cb0ef41Sopenharmony_ci common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse), 53881cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberLessThan(), start, 53891cb0ef41Sopenharmony_ci jsgraph()->ZeroConstant()), 53901cb0ef41Sopenharmony_ci graph()->NewNode( 53911cb0ef41Sopenharmony_ci simplified()->NumberMax(), 53921cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberAdd(), length, start), 53931cb0ef41Sopenharmony_ci jsgraph()->ZeroConstant()), 53941cb0ef41Sopenharmony_ci start); 53951cb0ef41Sopenharmony_ci // The select above guarantees that initStart is non-negative, but 53961cb0ef41Sopenharmony_ci // our typer can't figure that out yet. 53971cb0ef41Sopenharmony_ci initStart = effect = graph()->NewNode( 53981cb0ef41Sopenharmony_ci common()->TypeGuard(Type::UnsignedSmall()), initStart, effect, control); 53991cb0ef41Sopenharmony_ci 54001cb0ef41Sopenharmony_ci Node* resultLength = graph()->NewNode( 54011cb0ef41Sopenharmony_ci simplified()->NumberMin(), 54021cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberMax(), end, 54031cb0ef41Sopenharmony_ci jsgraph()->ZeroConstant()), 54041cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberSubtract(), length, initStart)); 54051cb0ef41Sopenharmony_ci 54061cb0ef41Sopenharmony_ci // The the select below uses {resultLength} only if {resultLength > 0}, 54071cb0ef41Sopenharmony_ci // but our typer can't figure that out yet. 54081cb0ef41Sopenharmony_ci Node* to = effect = graph()->NewNode( 54091cb0ef41Sopenharmony_ci common()->TypeGuard(Type::UnsignedSmall()), 54101cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberAdd(), initStart, resultLength), 54111cb0ef41Sopenharmony_ci effect, control); 54121cb0ef41Sopenharmony_ci 54131cb0ef41Sopenharmony_ci Node* result_string = nullptr; 54141cb0ef41Sopenharmony_ci // Return empty string if {from} is smaller than {to}. 54151cb0ef41Sopenharmony_ci { 54161cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->NumberLessThan(), 54171cb0ef41Sopenharmony_ci jsgraph()->ZeroConstant(), resultLength); 54181cb0ef41Sopenharmony_ci 54191cb0ef41Sopenharmony_ci Node* branch = 54201cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); 54211cb0ef41Sopenharmony_ci 54221cb0ef41Sopenharmony_ci Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 54231cb0ef41Sopenharmony_ci Node* etrue = effect; 54241cb0ef41Sopenharmony_ci Node* vtrue = etrue = 54251cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->StringSubstring(), receiver, initStart, 54261cb0ef41Sopenharmony_ci to, etrue, if_true); 54271cb0ef41Sopenharmony_ci 54281cb0ef41Sopenharmony_ci Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 54291cb0ef41Sopenharmony_ci Node* efalse = effect; 54301cb0ef41Sopenharmony_ci Node* vfalse = jsgraph()->EmptyStringConstant(); 54311cb0ef41Sopenharmony_ci 54321cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Merge(2), if_true, if_false); 54331cb0ef41Sopenharmony_ci effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); 54341cb0ef41Sopenharmony_ci result_string = 54351cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 54361cb0ef41Sopenharmony_ci vtrue, vfalse, control); 54371cb0ef41Sopenharmony_ci } 54381cb0ef41Sopenharmony_ci 54391cb0ef41Sopenharmony_ci ReplaceWithValue(node, result_string, effect, control); 54401cb0ef41Sopenharmony_ci return Replace(result_string); 54411cb0ef41Sopenharmony_ci} 54421cb0ef41Sopenharmony_ci 54431cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceJSConstructWithArrayLike(Node* node) { 54441cb0ef41Sopenharmony_ci JSConstructWithArrayLikeNode n(node); 54451cb0ef41Sopenharmony_ci ConstructParameters const& p = n.Parameters(); 54461cb0ef41Sopenharmony_ci const int arraylike_index = n.LastArgumentIndex(); 54471cb0ef41Sopenharmony_ci DCHECK_EQ(n.ArgumentCount(), 1); // The arraylike object. 54481cb0ef41Sopenharmony_ci return ReduceCallOrConstructWithArrayLikeOrSpread( 54491cb0ef41Sopenharmony_ci node, n.ArgumentCount(), arraylike_index, p.frequency(), p.feedback(), 54501cb0ef41Sopenharmony_ci SpeculationMode::kDisallowSpeculation, CallFeedbackRelation::kTarget, 54511cb0ef41Sopenharmony_ci n.target(), n.effect(), n.control()); 54521cb0ef41Sopenharmony_ci} 54531cb0ef41Sopenharmony_ci 54541cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceJSConstructWithSpread(Node* node) { 54551cb0ef41Sopenharmony_ci JSConstructWithSpreadNode n(node); 54561cb0ef41Sopenharmony_ci ConstructParameters const& p = n.Parameters(); 54571cb0ef41Sopenharmony_ci const int spread_index = n.LastArgumentIndex(); 54581cb0ef41Sopenharmony_ci DCHECK_GE(n.ArgumentCount(), 1); // At least the spread. 54591cb0ef41Sopenharmony_ci return ReduceCallOrConstructWithArrayLikeOrSpread( 54601cb0ef41Sopenharmony_ci node, n.ArgumentCount(), spread_index, p.frequency(), p.feedback(), 54611cb0ef41Sopenharmony_ci SpeculationMode::kDisallowSpeculation, CallFeedbackRelation::kTarget, 54621cb0ef41Sopenharmony_ci n.target(), n.effect(), n.control()); 54631cb0ef41Sopenharmony_ci} 54641cb0ef41Sopenharmony_ci 54651cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceReturnReceiver(Node* node) { 54661cb0ef41Sopenharmony_ci JSCallNode n(node); 54671cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 54681cb0ef41Sopenharmony_ci ReplaceWithValue(node, receiver); 54691cb0ef41Sopenharmony_ci return Replace(receiver); 54701cb0ef41Sopenharmony_ci} 54711cb0ef41Sopenharmony_ci 54721cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceForInsufficientFeedback( 54731cb0ef41Sopenharmony_ci Node* node, DeoptimizeReason reason) { 54741cb0ef41Sopenharmony_ci DCHECK(node->opcode() == IrOpcode::kJSCall || 54751cb0ef41Sopenharmony_ci node->opcode() == IrOpcode::kJSConstruct); 54761cb0ef41Sopenharmony_ci if (!(flags() & kBailoutOnUninitialized)) return NoChange(); 54771cb0ef41Sopenharmony_ci 54781cb0ef41Sopenharmony_ci Node* effect = NodeProperties::GetEffectInput(node); 54791cb0ef41Sopenharmony_ci Node* control = NodeProperties::GetControlInput(node); 54801cb0ef41Sopenharmony_ci Node* frame_state = 54811cb0ef41Sopenharmony_ci NodeProperties::FindFrameStateBefore(node, jsgraph()->Dead()); 54821cb0ef41Sopenharmony_ci Node* deoptimize = 54831cb0ef41Sopenharmony_ci graph()->NewNode(common()->Deoptimize(reason, FeedbackSource()), 54841cb0ef41Sopenharmony_ci frame_state, effect, control); 54851cb0ef41Sopenharmony_ci // TODO(bmeurer): This should be on the AdvancedReducer somehow. 54861cb0ef41Sopenharmony_ci NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); 54871cb0ef41Sopenharmony_ci Revisit(graph()->end()); 54881cb0ef41Sopenharmony_ci node->TrimInputCount(0); 54891cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, common()->Dead()); 54901cb0ef41Sopenharmony_ci return Changed(node); 54911cb0ef41Sopenharmony_ci} 54921cb0ef41Sopenharmony_ci 54931cb0ef41Sopenharmony_ciNode* JSCallReducer::LoadReceiverElementsKind(Node* receiver, Effect* effect, 54941cb0ef41Sopenharmony_ci Control control) { 54951cb0ef41Sopenharmony_ci Node* effect_node = *effect; 54961cb0ef41Sopenharmony_ci Node* receiver_map = effect_node = 54971cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 54981cb0ef41Sopenharmony_ci receiver, effect_node, control); 54991cb0ef41Sopenharmony_ci Node* receiver_bit_field2 = effect_node = graph()->NewNode( 55001cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForMapBitField2()), receiver_map, 55011cb0ef41Sopenharmony_ci effect_node, control); 55021cb0ef41Sopenharmony_ci Node* receiver_elements_kind = graph()->NewNode( 55031cb0ef41Sopenharmony_ci simplified()->NumberShiftRightLogical(), 55041cb0ef41Sopenharmony_ci graph()->NewNode( 55051cb0ef41Sopenharmony_ci simplified()->NumberBitwiseAnd(), receiver_bit_field2, 55061cb0ef41Sopenharmony_ci jsgraph()->Constant(Map::Bits2::ElementsKindBits::kMask)), 55071cb0ef41Sopenharmony_ci jsgraph()->Constant(Map::Bits2::ElementsKindBits::kShift)); 55081cb0ef41Sopenharmony_ci *effect = effect_node; 55091cb0ef41Sopenharmony_ci return receiver_elements_kind; 55101cb0ef41Sopenharmony_ci} 55111cb0ef41Sopenharmony_ci 55121cb0ef41Sopenharmony_civoid JSCallReducer::CheckIfElementsKind(Node* receiver_elements_kind, 55131cb0ef41Sopenharmony_ci ElementsKind kind, Node* control, 55141cb0ef41Sopenharmony_ci Node** if_true, Node** if_false) { 55151cb0ef41Sopenharmony_ci Node* is_packed_kind = 55161cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberEqual(), receiver_elements_kind, 55171cb0ef41Sopenharmony_ci jsgraph()->Constant(GetPackedElementsKind(kind))); 55181cb0ef41Sopenharmony_ci Node* packed_branch = 55191cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(), is_packed_kind, control); 55201cb0ef41Sopenharmony_ci Node* if_packed = graph()->NewNode(common()->IfTrue(), packed_branch); 55211cb0ef41Sopenharmony_ci 55221cb0ef41Sopenharmony_ci if (IsHoleyElementsKind(kind)) { 55231cb0ef41Sopenharmony_ci Node* if_not_packed = graph()->NewNode(common()->IfFalse(), packed_branch); 55241cb0ef41Sopenharmony_ci Node* is_holey_kind = 55251cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberEqual(), receiver_elements_kind, 55261cb0ef41Sopenharmony_ci jsgraph()->Constant(GetHoleyElementsKind(kind))); 55271cb0ef41Sopenharmony_ci Node* holey_branch = 55281cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(), is_holey_kind, if_not_packed); 55291cb0ef41Sopenharmony_ci Node* if_holey = graph()->NewNode(common()->IfTrue(), holey_branch); 55301cb0ef41Sopenharmony_ci 55311cb0ef41Sopenharmony_ci Node* if_not_packed_not_holey = 55321cb0ef41Sopenharmony_ci graph()->NewNode(common()->IfFalse(), holey_branch); 55331cb0ef41Sopenharmony_ci 55341cb0ef41Sopenharmony_ci *if_true = graph()->NewNode(common()->Merge(2), if_packed, if_holey); 55351cb0ef41Sopenharmony_ci *if_false = if_not_packed_not_holey; 55361cb0ef41Sopenharmony_ci } else { 55371cb0ef41Sopenharmony_ci *if_true = if_packed; 55381cb0ef41Sopenharmony_ci *if_false = graph()->NewNode(common()->IfFalse(), packed_branch); 55391cb0ef41Sopenharmony_ci } 55401cb0ef41Sopenharmony_ci} 55411cb0ef41Sopenharmony_ci 55421cb0ef41Sopenharmony_ci// ES6 section 22.1.3.18 Array.prototype.push ( ) 55431cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayPrototypePush(Node* node) { 55441cb0ef41Sopenharmony_ci JSCallNode n(node); 55451cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 55461cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 55471cb0ef41Sopenharmony_ci return NoChange(); 55481cb0ef41Sopenharmony_ci } 55491cb0ef41Sopenharmony_ci 55501cb0ef41Sopenharmony_ci int const num_values = n.ArgumentCount(); 55511cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 55521cb0ef41Sopenharmony_ci Effect effect = n.effect(); 55531cb0ef41Sopenharmony_ci Control control = n.control(); 55541cb0ef41Sopenharmony_ci 55551cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 55561cb0ef41Sopenharmony_ci if (!inference.HaveMaps()) return NoChange(); 55571cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& receiver_maps = inference.GetMaps(); 55581cb0ef41Sopenharmony_ci 55591cb0ef41Sopenharmony_ci std::vector<ElementsKind> kinds; 55601cb0ef41Sopenharmony_ci if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kinds, true)) { 55611cb0ef41Sopenharmony_ci return inference.NoChange(); 55621cb0ef41Sopenharmony_ci } 55631cb0ef41Sopenharmony_ci if (!dependencies()->DependOnNoElementsProtector()) { 55641cb0ef41Sopenharmony_ci return inference.NoChange(); 55651cb0ef41Sopenharmony_ci } 55661cb0ef41Sopenharmony_ci inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect, 55671cb0ef41Sopenharmony_ci control, p.feedback()); 55681cb0ef41Sopenharmony_ci 55691cb0ef41Sopenharmony_ci std::vector<Node*> controls_to_merge; 55701cb0ef41Sopenharmony_ci std::vector<Node*> effects_to_merge; 55711cb0ef41Sopenharmony_ci std::vector<Node*> values_to_merge; 55721cb0ef41Sopenharmony_ci Node* return_value = jsgraph()->UndefinedConstant(); 55731cb0ef41Sopenharmony_ci 55741cb0ef41Sopenharmony_ci Node* receiver_elements_kind = 55751cb0ef41Sopenharmony_ci LoadReceiverElementsKind(receiver, &effect, control); 55761cb0ef41Sopenharmony_ci Node* next_control = control; 55771cb0ef41Sopenharmony_ci Node* next_effect = effect; 55781cb0ef41Sopenharmony_ci for (size_t i = 0; i < kinds.size(); i++) { 55791cb0ef41Sopenharmony_ci ElementsKind kind = kinds[i]; 55801cb0ef41Sopenharmony_ci control = next_control; 55811cb0ef41Sopenharmony_ci effect = next_effect; 55821cb0ef41Sopenharmony_ci // We do not need branch for the last elements kind. 55831cb0ef41Sopenharmony_ci if (i != kinds.size() - 1) { 55841cb0ef41Sopenharmony_ci Node* control_node = control; 55851cb0ef41Sopenharmony_ci CheckIfElementsKind(receiver_elements_kind, kind, control_node, 55861cb0ef41Sopenharmony_ci &control_node, &next_control); 55871cb0ef41Sopenharmony_ci control = control_node; 55881cb0ef41Sopenharmony_ci } 55891cb0ef41Sopenharmony_ci 55901cb0ef41Sopenharmony_ci // Collect the value inputs to push. 55911cb0ef41Sopenharmony_ci std::vector<Node*> values(num_values); 55921cb0ef41Sopenharmony_ci for (int j = 0; j < num_values; ++j) { 55931cb0ef41Sopenharmony_ci values[j] = n.Argument(j); 55941cb0ef41Sopenharmony_ci } 55951cb0ef41Sopenharmony_ci 55961cb0ef41Sopenharmony_ci for (auto& value : values) { 55971cb0ef41Sopenharmony_ci if (IsSmiElementsKind(kind)) { 55981cb0ef41Sopenharmony_ci value = effect = graph()->NewNode(simplified()->CheckSmi(p.feedback()), 55991cb0ef41Sopenharmony_ci value, effect, control); 56001cb0ef41Sopenharmony_ci } else if (IsDoubleElementsKind(kind)) { 56011cb0ef41Sopenharmony_ci value = effect = graph()->NewNode( 56021cb0ef41Sopenharmony_ci simplified()->CheckNumber(p.feedback()), value, effect, control); 56031cb0ef41Sopenharmony_ci // Make sure we do not store signaling NaNs into double arrays. 56041cb0ef41Sopenharmony_ci value = graph()->NewNode(simplified()->NumberSilenceNaN(), value); 56051cb0ef41Sopenharmony_ci } 56061cb0ef41Sopenharmony_ci } 56071cb0ef41Sopenharmony_ci 56081cb0ef41Sopenharmony_ci // Load the "length" property of the {receiver}. 56091cb0ef41Sopenharmony_ci Node* length = effect = graph()->NewNode( 56101cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), 56111cb0ef41Sopenharmony_ci receiver, effect, control); 56121cb0ef41Sopenharmony_ci return_value = length; 56131cb0ef41Sopenharmony_ci 56141cb0ef41Sopenharmony_ci // Check if we have any {values} to push. 56151cb0ef41Sopenharmony_ci if (num_values > 0) { 56161cb0ef41Sopenharmony_ci // Compute the resulting "length" of the {receiver}. 56171cb0ef41Sopenharmony_ci Node* new_length = return_value = graph()->NewNode( 56181cb0ef41Sopenharmony_ci simplified()->NumberAdd(), length, jsgraph()->Constant(num_values)); 56191cb0ef41Sopenharmony_ci 56201cb0ef41Sopenharmony_ci // Load the elements backing store of the {receiver}. 56211cb0ef41Sopenharmony_ci Node* elements = effect = graph()->NewNode( 56221cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSObjectElements()), 56231cb0ef41Sopenharmony_ci receiver, effect, control); 56241cb0ef41Sopenharmony_ci Node* elements_length = effect = graph()->NewNode( 56251cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), 56261cb0ef41Sopenharmony_ci elements, effect, control); 56271cb0ef41Sopenharmony_ci 56281cb0ef41Sopenharmony_ci GrowFastElementsMode mode = 56291cb0ef41Sopenharmony_ci IsDoubleElementsKind(kind) 56301cb0ef41Sopenharmony_ci ? GrowFastElementsMode::kDoubleElements 56311cb0ef41Sopenharmony_ci : GrowFastElementsMode::kSmiOrObjectElements; 56321cb0ef41Sopenharmony_ci elements = effect = graph()->NewNode( 56331cb0ef41Sopenharmony_ci simplified()->MaybeGrowFastElements(mode, p.feedback()), receiver, 56341cb0ef41Sopenharmony_ci elements, 56351cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberAdd(), length, 56361cb0ef41Sopenharmony_ci jsgraph()->Constant(num_values - 1)), 56371cb0ef41Sopenharmony_ci elements_length, effect, control); 56381cb0ef41Sopenharmony_ci 56391cb0ef41Sopenharmony_ci // Update the JSArray::length field. Since this is observable, 56401cb0ef41Sopenharmony_ci // there must be no other check after this. 56411cb0ef41Sopenharmony_ci effect = graph()->NewNode( 56421cb0ef41Sopenharmony_ci simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)), 56431cb0ef41Sopenharmony_ci receiver, new_length, effect, control); 56441cb0ef41Sopenharmony_ci 56451cb0ef41Sopenharmony_ci // Append the {values} to the {elements}. 56461cb0ef41Sopenharmony_ci for (int j = 0; j < num_values; ++j) { 56471cb0ef41Sopenharmony_ci Node* value = values[j]; 56481cb0ef41Sopenharmony_ci Node* index = graph()->NewNode(simplified()->NumberAdd(), length, 56491cb0ef41Sopenharmony_ci jsgraph()->Constant(j)); 56501cb0ef41Sopenharmony_ci effect = 56511cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->StoreElement( 56521cb0ef41Sopenharmony_ci AccessBuilder::ForFixedArrayElement(kind)), 56531cb0ef41Sopenharmony_ci elements, index, value, effect, control); 56541cb0ef41Sopenharmony_ci } 56551cb0ef41Sopenharmony_ci } 56561cb0ef41Sopenharmony_ci 56571cb0ef41Sopenharmony_ci controls_to_merge.push_back(control); 56581cb0ef41Sopenharmony_ci effects_to_merge.push_back(effect); 56591cb0ef41Sopenharmony_ci values_to_merge.push_back(return_value); 56601cb0ef41Sopenharmony_ci } 56611cb0ef41Sopenharmony_ci 56621cb0ef41Sopenharmony_ci if (controls_to_merge.size() > 1) { 56631cb0ef41Sopenharmony_ci int const count = static_cast<int>(controls_to_merge.size()); 56641cb0ef41Sopenharmony_ci 56651cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Merge(count), count, 56661cb0ef41Sopenharmony_ci &controls_to_merge.front()); 56671cb0ef41Sopenharmony_ci effects_to_merge.push_back(control); 56681cb0ef41Sopenharmony_ci effect = graph()->NewNode(common()->EffectPhi(count), count + 1, 56691cb0ef41Sopenharmony_ci &effects_to_merge.front()); 56701cb0ef41Sopenharmony_ci values_to_merge.push_back(control); 56711cb0ef41Sopenharmony_ci return_value = 56721cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count), 56731cb0ef41Sopenharmony_ci count + 1, &values_to_merge.front()); 56741cb0ef41Sopenharmony_ci } 56751cb0ef41Sopenharmony_ci 56761cb0ef41Sopenharmony_ci ReplaceWithValue(node, return_value, effect, control); 56771cb0ef41Sopenharmony_ci return Replace(return_value); 56781cb0ef41Sopenharmony_ci} 56791cb0ef41Sopenharmony_ci 56801cb0ef41Sopenharmony_ci// ES6 section 22.1.3.17 Array.prototype.pop ( ) 56811cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayPrototypePop(Node* node) { 56821cb0ef41Sopenharmony_ci JSCallNode n(node); 56831cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 56841cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 56851cb0ef41Sopenharmony_ci return NoChange(); 56861cb0ef41Sopenharmony_ci } 56871cb0ef41Sopenharmony_ci 56881cb0ef41Sopenharmony_ci Effect effect = n.effect(); 56891cb0ef41Sopenharmony_ci Control control = n.control(); 56901cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 56911cb0ef41Sopenharmony_ci 56921cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 56931cb0ef41Sopenharmony_ci if (!inference.HaveMaps()) return NoChange(); 56941cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& receiver_maps = inference.GetMaps(); 56951cb0ef41Sopenharmony_ci 56961cb0ef41Sopenharmony_ci std::vector<ElementsKind> kinds; 56971cb0ef41Sopenharmony_ci if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kinds)) { 56981cb0ef41Sopenharmony_ci return inference.NoChange(); 56991cb0ef41Sopenharmony_ci } 57001cb0ef41Sopenharmony_ci if (!dependencies()->DependOnNoElementsProtector()) { 57011cb0ef41Sopenharmony_ci return inference.NoChange(); 57021cb0ef41Sopenharmony_ci } 57031cb0ef41Sopenharmony_ci inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect, 57041cb0ef41Sopenharmony_ci control, p.feedback()); 57051cb0ef41Sopenharmony_ci 57061cb0ef41Sopenharmony_ci std::vector<Node*> controls_to_merge; 57071cb0ef41Sopenharmony_ci std::vector<Node*> effects_to_merge; 57081cb0ef41Sopenharmony_ci std::vector<Node*> values_to_merge; 57091cb0ef41Sopenharmony_ci Node* value = jsgraph()->UndefinedConstant(); 57101cb0ef41Sopenharmony_ci 57111cb0ef41Sopenharmony_ci Node* receiver_elements_kind = 57121cb0ef41Sopenharmony_ci LoadReceiverElementsKind(receiver, &effect, control); 57131cb0ef41Sopenharmony_ci Node* next_control = control; 57141cb0ef41Sopenharmony_ci Node* next_effect = effect; 57151cb0ef41Sopenharmony_ci for (size_t i = 0; i < kinds.size(); i++) { 57161cb0ef41Sopenharmony_ci ElementsKind kind = kinds[i]; 57171cb0ef41Sopenharmony_ci control = next_control; 57181cb0ef41Sopenharmony_ci effect = next_effect; 57191cb0ef41Sopenharmony_ci // We do not need branch for the last elements kind. 57201cb0ef41Sopenharmony_ci if (i != kinds.size() - 1) { 57211cb0ef41Sopenharmony_ci Node* control_node = control; 57221cb0ef41Sopenharmony_ci CheckIfElementsKind(receiver_elements_kind, kind, control_node, 57231cb0ef41Sopenharmony_ci &control_node, &next_control); 57241cb0ef41Sopenharmony_ci control = control_node; 57251cb0ef41Sopenharmony_ci } 57261cb0ef41Sopenharmony_ci 57271cb0ef41Sopenharmony_ci // Load the "length" property of the {receiver}. 57281cb0ef41Sopenharmony_ci Node* length = effect = graph()->NewNode( 57291cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), 57301cb0ef41Sopenharmony_ci receiver, effect, control); 57311cb0ef41Sopenharmony_ci 57321cb0ef41Sopenharmony_ci // Check if the {receiver} has any elements. 57331cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->NumberEqual(), length, 57341cb0ef41Sopenharmony_ci jsgraph()->ZeroConstant()); 57351cb0ef41Sopenharmony_ci Node* branch = 57361cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); 57371cb0ef41Sopenharmony_ci 57381cb0ef41Sopenharmony_ci Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 57391cb0ef41Sopenharmony_ci Node* etrue = effect; 57401cb0ef41Sopenharmony_ci Node* vtrue = jsgraph()->UndefinedConstant(); 57411cb0ef41Sopenharmony_ci 57421cb0ef41Sopenharmony_ci Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 57431cb0ef41Sopenharmony_ci Node* efalse = effect; 57441cb0ef41Sopenharmony_ci Node* vfalse; 57451cb0ef41Sopenharmony_ci { 57461cb0ef41Sopenharmony_ci // TODO(turbofan): We should trim the backing store if the capacity is too 57471cb0ef41Sopenharmony_ci // big, as implemented in elements.cc:ElementsAccessorBase::SetLengthImpl. 57481cb0ef41Sopenharmony_ci 57491cb0ef41Sopenharmony_ci // Load the elements backing store from the {receiver}. 57501cb0ef41Sopenharmony_ci Node* elements = efalse = graph()->NewNode( 57511cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSObjectElements()), 57521cb0ef41Sopenharmony_ci receiver, efalse, if_false); 57531cb0ef41Sopenharmony_ci 57541cb0ef41Sopenharmony_ci // Ensure that we aren't popping from a copy-on-write backing store. 57551cb0ef41Sopenharmony_ci if (IsSmiOrObjectElementsKind(kind)) { 57561cb0ef41Sopenharmony_ci elements = efalse = 57571cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->EnsureWritableFastElements(), 57581cb0ef41Sopenharmony_ci receiver, elements, efalse, if_false); 57591cb0ef41Sopenharmony_ci } 57601cb0ef41Sopenharmony_ci 57611cb0ef41Sopenharmony_ci // Compute the new {length}. 57621cb0ef41Sopenharmony_ci Node* new_length = graph()->NewNode(simplified()->NumberSubtract(), 57631cb0ef41Sopenharmony_ci length, jsgraph()->OneConstant()); 57641cb0ef41Sopenharmony_ci 57651cb0ef41Sopenharmony_ci // This extra check exists solely to break an exploitation technique 57661cb0ef41Sopenharmony_ci // that abuses typer mismatches. 57671cb0ef41Sopenharmony_ci new_length = efalse = graph()->NewNode( 57681cb0ef41Sopenharmony_ci simplified()->CheckBounds(p.feedback(), 57691cb0ef41Sopenharmony_ci CheckBoundsFlag::kAbortOnOutOfBounds), 57701cb0ef41Sopenharmony_ci new_length, length, efalse, if_false); 57711cb0ef41Sopenharmony_ci 57721cb0ef41Sopenharmony_ci // Store the new {length} to the {receiver}. 57731cb0ef41Sopenharmony_ci efalse = graph()->NewNode( 57741cb0ef41Sopenharmony_ci simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)), 57751cb0ef41Sopenharmony_ci receiver, new_length, efalse, if_false); 57761cb0ef41Sopenharmony_ci 57771cb0ef41Sopenharmony_ci // Load the last entry from the {elements}. 57781cb0ef41Sopenharmony_ci vfalse = efalse = graph()->NewNode( 57791cb0ef41Sopenharmony_ci simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(kind)), 57801cb0ef41Sopenharmony_ci elements, new_length, efalse, if_false); 57811cb0ef41Sopenharmony_ci 57821cb0ef41Sopenharmony_ci // Store a hole to the element we just removed from the {receiver}. 57831cb0ef41Sopenharmony_ci efalse = graph()->NewNode( 57841cb0ef41Sopenharmony_ci simplified()->StoreElement( 57851cb0ef41Sopenharmony_ci AccessBuilder::ForFixedArrayElement(GetHoleyElementsKind(kind))), 57861cb0ef41Sopenharmony_ci elements, new_length, jsgraph()->TheHoleConstant(), efalse, if_false); 57871cb0ef41Sopenharmony_ci } 57881cb0ef41Sopenharmony_ci 57891cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Merge(2), if_true, if_false); 57901cb0ef41Sopenharmony_ci effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); 57911cb0ef41Sopenharmony_ci value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 57921cb0ef41Sopenharmony_ci vtrue, vfalse, control); 57931cb0ef41Sopenharmony_ci 57941cb0ef41Sopenharmony_ci // Convert the hole to undefined. Do this last, so that we can optimize 57951cb0ef41Sopenharmony_ci // conversion operator via some smart strength reduction in many cases. 57961cb0ef41Sopenharmony_ci if (IsHoleyElementsKind(kind)) { 57971cb0ef41Sopenharmony_ci value = 57981cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value); 57991cb0ef41Sopenharmony_ci } 58001cb0ef41Sopenharmony_ci 58011cb0ef41Sopenharmony_ci controls_to_merge.push_back(control); 58021cb0ef41Sopenharmony_ci effects_to_merge.push_back(effect); 58031cb0ef41Sopenharmony_ci values_to_merge.push_back(value); 58041cb0ef41Sopenharmony_ci } 58051cb0ef41Sopenharmony_ci 58061cb0ef41Sopenharmony_ci if (controls_to_merge.size() > 1) { 58071cb0ef41Sopenharmony_ci int const count = static_cast<int>(controls_to_merge.size()); 58081cb0ef41Sopenharmony_ci 58091cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Merge(count), count, 58101cb0ef41Sopenharmony_ci &controls_to_merge.front()); 58111cb0ef41Sopenharmony_ci effects_to_merge.push_back(control); 58121cb0ef41Sopenharmony_ci effect = graph()->NewNode(common()->EffectPhi(count), count + 1, 58131cb0ef41Sopenharmony_ci &effects_to_merge.front()); 58141cb0ef41Sopenharmony_ci values_to_merge.push_back(control); 58151cb0ef41Sopenharmony_ci value = 58161cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count), 58171cb0ef41Sopenharmony_ci count + 1, &values_to_merge.front()); 58181cb0ef41Sopenharmony_ci } 58191cb0ef41Sopenharmony_ci 58201cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 58211cb0ef41Sopenharmony_ci return Replace(value); 58221cb0ef41Sopenharmony_ci} 58231cb0ef41Sopenharmony_ci 58241cb0ef41Sopenharmony_ci// ES6 section 22.1.3.22 Array.prototype.shift ( ) 58251cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) { 58261cb0ef41Sopenharmony_ci JSCallNode n(node); 58271cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 58281cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 58291cb0ef41Sopenharmony_ci return NoChange(); 58301cb0ef41Sopenharmony_ci } 58311cb0ef41Sopenharmony_ci 58321cb0ef41Sopenharmony_ci Node* target = n.target(); 58331cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 58341cb0ef41Sopenharmony_ci Node* context = n.context(); 58351cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 58361cb0ef41Sopenharmony_ci Effect effect = n.effect(); 58371cb0ef41Sopenharmony_ci Control control = n.control(); 58381cb0ef41Sopenharmony_ci 58391cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 58401cb0ef41Sopenharmony_ci if (!inference.HaveMaps()) return NoChange(); 58411cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& receiver_maps = inference.GetMaps(); 58421cb0ef41Sopenharmony_ci 58431cb0ef41Sopenharmony_ci std::vector<ElementsKind> kinds; 58441cb0ef41Sopenharmony_ci if (!CanInlineArrayResizingBuiltin(broker(), receiver_maps, &kinds)) { 58451cb0ef41Sopenharmony_ci return inference.NoChange(); 58461cb0ef41Sopenharmony_ci } 58471cb0ef41Sopenharmony_ci if (!dependencies()->DependOnNoElementsProtector()) { 58481cb0ef41Sopenharmony_ci return inference.NoChange(); 58491cb0ef41Sopenharmony_ci } 58501cb0ef41Sopenharmony_ci inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect, 58511cb0ef41Sopenharmony_ci control, p.feedback()); 58521cb0ef41Sopenharmony_ci 58531cb0ef41Sopenharmony_ci std::vector<Node*> controls_to_merge; 58541cb0ef41Sopenharmony_ci std::vector<Node*> effects_to_merge; 58551cb0ef41Sopenharmony_ci std::vector<Node*> values_to_merge; 58561cb0ef41Sopenharmony_ci Node* value = jsgraph()->UndefinedConstant(); 58571cb0ef41Sopenharmony_ci 58581cb0ef41Sopenharmony_ci Node* receiver_elements_kind = 58591cb0ef41Sopenharmony_ci LoadReceiverElementsKind(receiver, &effect, control); 58601cb0ef41Sopenharmony_ci Node* next_control = control; 58611cb0ef41Sopenharmony_ci Node* next_effect = effect; 58621cb0ef41Sopenharmony_ci for (size_t i = 0; i < kinds.size(); i++) { 58631cb0ef41Sopenharmony_ci ElementsKind kind = kinds[i]; 58641cb0ef41Sopenharmony_ci control = next_control; 58651cb0ef41Sopenharmony_ci effect = next_effect; 58661cb0ef41Sopenharmony_ci // We do not need branch for the last elements kind. 58671cb0ef41Sopenharmony_ci if (i != kinds.size() - 1) { 58681cb0ef41Sopenharmony_ci Node* control_node = control; 58691cb0ef41Sopenharmony_ci CheckIfElementsKind(receiver_elements_kind, kind, control_node, 58701cb0ef41Sopenharmony_ci &control_node, &next_control); 58711cb0ef41Sopenharmony_ci control = control_node; 58721cb0ef41Sopenharmony_ci } 58731cb0ef41Sopenharmony_ci 58741cb0ef41Sopenharmony_ci // Load length of the {receiver}. 58751cb0ef41Sopenharmony_ci Node* length = effect = graph()->NewNode( 58761cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), 58771cb0ef41Sopenharmony_ci receiver, effect, control); 58781cb0ef41Sopenharmony_ci 58791cb0ef41Sopenharmony_ci // Return undefined if {receiver} has no elements. 58801cb0ef41Sopenharmony_ci Node* check0 = graph()->NewNode(simplified()->NumberEqual(), length, 58811cb0ef41Sopenharmony_ci jsgraph()->ZeroConstant()); 58821cb0ef41Sopenharmony_ci Node* branch0 = 58831cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control); 58841cb0ef41Sopenharmony_ci 58851cb0ef41Sopenharmony_ci Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 58861cb0ef41Sopenharmony_ci Node* etrue0 = effect; 58871cb0ef41Sopenharmony_ci Node* vtrue0 = jsgraph()->UndefinedConstant(); 58881cb0ef41Sopenharmony_ci 58891cb0ef41Sopenharmony_ci Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 58901cb0ef41Sopenharmony_ci Node* efalse0 = effect; 58911cb0ef41Sopenharmony_ci Node* vfalse0; 58921cb0ef41Sopenharmony_ci { 58931cb0ef41Sopenharmony_ci // Check if we should take the fast-path. 58941cb0ef41Sopenharmony_ci Node* check1 = 58951cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberLessThanOrEqual(), length, 58961cb0ef41Sopenharmony_ci jsgraph()->Constant(JSArray::kMaxCopyElements)); 58971cb0ef41Sopenharmony_ci Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue), 58981cb0ef41Sopenharmony_ci check1, if_false0); 58991cb0ef41Sopenharmony_ci 59001cb0ef41Sopenharmony_ci Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1); 59011cb0ef41Sopenharmony_ci Node* etrue1 = efalse0; 59021cb0ef41Sopenharmony_ci Node* vtrue1; 59031cb0ef41Sopenharmony_ci { 59041cb0ef41Sopenharmony_ci Node* elements = etrue1 = graph()->NewNode( 59051cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSObjectElements()), 59061cb0ef41Sopenharmony_ci receiver, etrue1, if_true1); 59071cb0ef41Sopenharmony_ci 59081cb0ef41Sopenharmony_ci // Load the first element here, which we return below. 59091cb0ef41Sopenharmony_ci vtrue1 = etrue1 = graph()->NewNode( 59101cb0ef41Sopenharmony_ci simplified()->LoadElement( 59111cb0ef41Sopenharmony_ci AccessBuilder::ForFixedArrayElement(kind)), 59121cb0ef41Sopenharmony_ci elements, jsgraph()->ZeroConstant(), etrue1, if_true1); 59131cb0ef41Sopenharmony_ci 59141cb0ef41Sopenharmony_ci // Ensure that we aren't shifting a copy-on-write backing store. 59151cb0ef41Sopenharmony_ci if (IsSmiOrObjectElementsKind(kind)) { 59161cb0ef41Sopenharmony_ci elements = etrue1 = 59171cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->EnsureWritableFastElements(), 59181cb0ef41Sopenharmony_ci receiver, elements, etrue1, if_true1); 59191cb0ef41Sopenharmony_ci } 59201cb0ef41Sopenharmony_ci 59211cb0ef41Sopenharmony_ci // Shift the remaining {elements} by one towards the start. 59221cb0ef41Sopenharmony_ci Node* loop = graph()->NewNode(common()->Loop(2), if_true1, if_true1); 59231cb0ef41Sopenharmony_ci Node* eloop = 59241cb0ef41Sopenharmony_ci graph()->NewNode(common()->EffectPhi(2), etrue1, etrue1, loop); 59251cb0ef41Sopenharmony_ci Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop); 59261cb0ef41Sopenharmony_ci NodeProperties::MergeControlToEnd(graph(), common(), terminate); 59271cb0ef41Sopenharmony_ci 59281cb0ef41Sopenharmony_ci Node* index = graph()->NewNode( 59291cb0ef41Sopenharmony_ci common()->Phi(MachineRepresentation::kTagged, 2), 59301cb0ef41Sopenharmony_ci jsgraph()->OneConstant(), 59311cb0ef41Sopenharmony_ci jsgraph()->Constant(JSArray::kMaxCopyElements - 1), loop); 59321cb0ef41Sopenharmony_ci 59331cb0ef41Sopenharmony_ci { 59341cb0ef41Sopenharmony_ci Node* check2 = 59351cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberLessThan(), index, length); 59361cb0ef41Sopenharmony_ci Node* branch2 = graph()->NewNode(common()->Branch(), check2, loop); 59371cb0ef41Sopenharmony_ci 59381cb0ef41Sopenharmony_ci if_true1 = graph()->NewNode(common()->IfFalse(), branch2); 59391cb0ef41Sopenharmony_ci etrue1 = eloop; 59401cb0ef41Sopenharmony_ci 59411cb0ef41Sopenharmony_ci Node* control2 = graph()->NewNode(common()->IfTrue(), branch2); 59421cb0ef41Sopenharmony_ci Node* effect2 = etrue1; 59431cb0ef41Sopenharmony_ci 59441cb0ef41Sopenharmony_ci ElementAccess const access = 59451cb0ef41Sopenharmony_ci AccessBuilder::ForFixedArrayElement(kind); 59461cb0ef41Sopenharmony_ci 59471cb0ef41Sopenharmony_ci // When disable FLAG_turbo_loop_variable, typer cannot infer index 59481cb0ef41Sopenharmony_ci // is in [1, kMaxCopyElements-1], and will break in representing 59491cb0ef41Sopenharmony_ci // kRepFloat64 (Range(1, inf)) to kRepWord64 when converting 59501cb0ef41Sopenharmony_ci // input for kLoadElement. So we need to add type guard here. 59511cb0ef41Sopenharmony_ci // And we need to use index when using NumberLessThan to check 59521cb0ef41Sopenharmony_ci // terminate and updating index, otherwise which will break inducing 59531cb0ef41Sopenharmony_ci // variables in LoopVariableOptimizer. 59541cb0ef41Sopenharmony_ci STATIC_ASSERT(JSArray::kMaxCopyElements < kSmiMaxValue); 59551cb0ef41Sopenharmony_ci Node* index_retyped = effect2 = 59561cb0ef41Sopenharmony_ci graph()->NewNode(common()->TypeGuard(Type::UnsignedSmall()), 59571cb0ef41Sopenharmony_ci index, effect2, control2); 59581cb0ef41Sopenharmony_ci 59591cb0ef41Sopenharmony_ci Node* value2 = effect2 = 59601cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->LoadElement(access), elements, 59611cb0ef41Sopenharmony_ci index_retyped, effect2, control2); 59621cb0ef41Sopenharmony_ci effect2 = graph()->NewNode( 59631cb0ef41Sopenharmony_ci simplified()->StoreElement(access), elements, 59641cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberSubtract(), index_retyped, 59651cb0ef41Sopenharmony_ci jsgraph()->OneConstant()), 59661cb0ef41Sopenharmony_ci value2, effect2, control2); 59671cb0ef41Sopenharmony_ci 59681cb0ef41Sopenharmony_ci loop->ReplaceInput(1, control2); 59691cb0ef41Sopenharmony_ci eloop->ReplaceInput(1, effect2); 59701cb0ef41Sopenharmony_ci index->ReplaceInput(1, 59711cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberAdd(), index, 59721cb0ef41Sopenharmony_ci jsgraph()->OneConstant())); 59731cb0ef41Sopenharmony_ci } 59741cb0ef41Sopenharmony_ci 59751cb0ef41Sopenharmony_ci // Compute the new {length}. 59761cb0ef41Sopenharmony_ci Node* new_length = graph()->NewNode(simplified()->NumberSubtract(), 59771cb0ef41Sopenharmony_ci length, jsgraph()->OneConstant()); 59781cb0ef41Sopenharmony_ci 59791cb0ef41Sopenharmony_ci // This extra check exists solely to break an exploitation technique 59801cb0ef41Sopenharmony_ci // that abuses typer mismatches. 59811cb0ef41Sopenharmony_ci new_length = etrue1 = graph()->NewNode( 59821cb0ef41Sopenharmony_ci simplified()->CheckBounds(p.feedback(), 59831cb0ef41Sopenharmony_ci CheckBoundsFlag::kAbortOnOutOfBounds), 59841cb0ef41Sopenharmony_ci new_length, length, etrue1, if_true1); 59851cb0ef41Sopenharmony_ci 59861cb0ef41Sopenharmony_ci // Store the new {length} to the {receiver}. 59871cb0ef41Sopenharmony_ci etrue1 = graph()->NewNode( 59881cb0ef41Sopenharmony_ci simplified()->StoreField(AccessBuilder::ForJSArrayLength(kind)), 59891cb0ef41Sopenharmony_ci receiver, new_length, etrue1, if_true1); 59901cb0ef41Sopenharmony_ci 59911cb0ef41Sopenharmony_ci // Store a hole to the element we just removed from the {receiver}. 59921cb0ef41Sopenharmony_ci etrue1 = graph()->NewNode( 59931cb0ef41Sopenharmony_ci simplified()->StoreElement(AccessBuilder::ForFixedArrayElement( 59941cb0ef41Sopenharmony_ci GetHoleyElementsKind(kind))), 59951cb0ef41Sopenharmony_ci elements, new_length, jsgraph()->TheHoleConstant(), etrue1, 59961cb0ef41Sopenharmony_ci if_true1); 59971cb0ef41Sopenharmony_ci } 59981cb0ef41Sopenharmony_ci 59991cb0ef41Sopenharmony_ci Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1); 60001cb0ef41Sopenharmony_ci Node* efalse1 = efalse0; 60011cb0ef41Sopenharmony_ci Node* vfalse1; 60021cb0ef41Sopenharmony_ci { 60031cb0ef41Sopenharmony_ci // Call the generic C++ implementation. 60041cb0ef41Sopenharmony_ci const Builtin builtin = Builtin::kArrayShift; 60051cb0ef41Sopenharmony_ci auto call_descriptor = Linkage::GetCEntryStubCallDescriptor( 60061cb0ef41Sopenharmony_ci graph()->zone(), 1, BuiltinArguments::kNumExtraArgsWithReceiver, 60071cb0ef41Sopenharmony_ci Builtins::name(builtin), node->op()->properties(), 60081cb0ef41Sopenharmony_ci CallDescriptor::kNeedsFrameState); 60091cb0ef41Sopenharmony_ci Node* stub_code = jsgraph()->CEntryStubConstant( 60101cb0ef41Sopenharmony_ci 1, SaveFPRegsMode::kIgnore, ArgvMode::kStack, true); 60111cb0ef41Sopenharmony_ci Address builtin_entry = Builtins::CppEntryOf(builtin); 60121cb0ef41Sopenharmony_ci Node* entry = jsgraph()->ExternalConstant( 60131cb0ef41Sopenharmony_ci ExternalReference::Create(builtin_entry)); 60141cb0ef41Sopenharmony_ci Node* argc = 60151cb0ef41Sopenharmony_ci jsgraph()->Constant(BuiltinArguments::kNumExtraArgsWithReceiver); 60161cb0ef41Sopenharmony_ci if_false1 = efalse1 = vfalse1 = 60171cb0ef41Sopenharmony_ci graph()->NewNode(common()->Call(call_descriptor), stub_code, 60181cb0ef41Sopenharmony_ci receiver, jsgraph()->PaddingConstant(), argc, 60191cb0ef41Sopenharmony_ci target, jsgraph()->UndefinedConstant(), entry, 60201cb0ef41Sopenharmony_ci argc, context, frame_state, efalse1, if_false1); 60211cb0ef41Sopenharmony_ci } 60221cb0ef41Sopenharmony_ci 60231cb0ef41Sopenharmony_ci if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1); 60241cb0ef41Sopenharmony_ci efalse0 = 60251cb0ef41Sopenharmony_ci graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0); 60261cb0ef41Sopenharmony_ci vfalse0 = 60271cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 60281cb0ef41Sopenharmony_ci vtrue1, vfalse1, if_false0); 60291cb0ef41Sopenharmony_ci } 60301cb0ef41Sopenharmony_ci 60311cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); 60321cb0ef41Sopenharmony_ci effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control); 60331cb0ef41Sopenharmony_ci value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 60341cb0ef41Sopenharmony_ci vtrue0, vfalse0, control); 60351cb0ef41Sopenharmony_ci 60361cb0ef41Sopenharmony_ci // Convert the hole to undefined. Do this last, so that we can optimize 60371cb0ef41Sopenharmony_ci // conversion operator via some smart strength reduction in many cases. 60381cb0ef41Sopenharmony_ci if (IsHoleyElementsKind(kind)) { 60391cb0ef41Sopenharmony_ci value = 60401cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value); 60411cb0ef41Sopenharmony_ci } 60421cb0ef41Sopenharmony_ci 60431cb0ef41Sopenharmony_ci controls_to_merge.push_back(control); 60441cb0ef41Sopenharmony_ci effects_to_merge.push_back(effect); 60451cb0ef41Sopenharmony_ci values_to_merge.push_back(value); 60461cb0ef41Sopenharmony_ci } 60471cb0ef41Sopenharmony_ci 60481cb0ef41Sopenharmony_ci if (controls_to_merge.size() > 1) { 60491cb0ef41Sopenharmony_ci int const count = static_cast<int>(controls_to_merge.size()); 60501cb0ef41Sopenharmony_ci 60511cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Merge(count), count, 60521cb0ef41Sopenharmony_ci &controls_to_merge.front()); 60531cb0ef41Sopenharmony_ci effects_to_merge.push_back(control); 60541cb0ef41Sopenharmony_ci effect = graph()->NewNode(common()->EffectPhi(count), count + 1, 60551cb0ef41Sopenharmony_ci &effects_to_merge.front()); 60561cb0ef41Sopenharmony_ci values_to_merge.push_back(control); 60571cb0ef41Sopenharmony_ci value = 60581cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count), 60591cb0ef41Sopenharmony_ci count + 1, &values_to_merge.front()); 60601cb0ef41Sopenharmony_ci } 60611cb0ef41Sopenharmony_ci 60621cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 60631cb0ef41Sopenharmony_ci return Replace(value); 60641cb0ef41Sopenharmony_ci} 60651cb0ef41Sopenharmony_ci 60661cb0ef41Sopenharmony_ci// ES6 section 22.1.3.23 Array.prototype.slice ( ) 60671cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayPrototypeSlice(Node* node) { 60681cb0ef41Sopenharmony_ci if (!FLAG_turbo_inline_array_builtins) return NoChange(); 60691cb0ef41Sopenharmony_ci JSCallNode n(node); 60701cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 60711cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 60721cb0ef41Sopenharmony_ci return NoChange(); 60731cb0ef41Sopenharmony_ci } 60741cb0ef41Sopenharmony_ci 60751cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 60761cb0ef41Sopenharmony_ci Node* start = n.ArgumentOr(0, jsgraph()->ZeroConstant()); 60771cb0ef41Sopenharmony_ci Node* end = n.ArgumentOrUndefined(1, jsgraph()); 60781cb0ef41Sopenharmony_ci Node* context = n.context(); 60791cb0ef41Sopenharmony_ci Effect effect = n.effect(); 60801cb0ef41Sopenharmony_ci Control control = n.control(); 60811cb0ef41Sopenharmony_ci 60821cb0ef41Sopenharmony_ci // Optimize for the case where we simply clone the {receiver}, i.e. when the 60831cb0ef41Sopenharmony_ci // {start} is zero and the {end} is undefined (meaning it will be set to 60841cb0ef41Sopenharmony_ci // {receiver}s "length" property). This logic should be in sync with 60851cb0ef41Sopenharmony_ci // ReduceArrayPrototypeSlice (to a reasonable degree). This is because 60861cb0ef41Sopenharmony_ci // CloneFastJSArray produces arrays which are potentially COW. If there's a 60871cb0ef41Sopenharmony_ci // discrepancy, TF generates code which produces a COW array and then expects 60881cb0ef41Sopenharmony_ci // it to be non-COW (or the other way around) -> immediate deopt. 60891cb0ef41Sopenharmony_ci if (!NumberMatcher(start).Is(0) || 60901cb0ef41Sopenharmony_ci !HeapObjectMatcher(end).Is(factory()->undefined_value())) { 60911cb0ef41Sopenharmony_ci return NoChange(); 60921cb0ef41Sopenharmony_ci } 60931cb0ef41Sopenharmony_ci 60941cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 60951cb0ef41Sopenharmony_ci if (!inference.HaveMaps()) return NoChange(); 60961cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& receiver_maps = inference.GetMaps(); 60971cb0ef41Sopenharmony_ci 60981cb0ef41Sopenharmony_ci // Check that the maps are of JSArray (and more). 60991cb0ef41Sopenharmony_ci // TODO(turbofan): Consider adding special case for the common pattern 61001cb0ef41Sopenharmony_ci // `slice.call(arguments)`, for example jQuery makes heavy use of that. 61011cb0ef41Sopenharmony_ci bool can_be_holey = false; 61021cb0ef41Sopenharmony_ci for (const MapRef& receiver_map : receiver_maps) { 61031cb0ef41Sopenharmony_ci if (!receiver_map.supports_fast_array_iteration()) { 61041cb0ef41Sopenharmony_ci return inference.NoChange(); 61051cb0ef41Sopenharmony_ci } 61061cb0ef41Sopenharmony_ci if (IsHoleyElementsKind(receiver_map.elements_kind())) { 61071cb0ef41Sopenharmony_ci can_be_holey = true; 61081cb0ef41Sopenharmony_ci } 61091cb0ef41Sopenharmony_ci } 61101cb0ef41Sopenharmony_ci 61111cb0ef41Sopenharmony_ci if (!dependencies()->DependOnArraySpeciesProtector()) { 61121cb0ef41Sopenharmony_ci return inference.NoChange(); 61131cb0ef41Sopenharmony_ci } 61141cb0ef41Sopenharmony_ci if (can_be_holey && !dependencies()->DependOnNoElementsProtector()) { 61151cb0ef41Sopenharmony_ci return inference.NoChange(); 61161cb0ef41Sopenharmony_ci } 61171cb0ef41Sopenharmony_ci inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect, 61181cb0ef41Sopenharmony_ci control, p.feedback()); 61191cb0ef41Sopenharmony_ci 61201cb0ef41Sopenharmony_ci // TODO(turbofan): We can do even better here, either adding a CloneArray 61211cb0ef41Sopenharmony_ci // simplified operator, whose output type indicates that it's an Array, 61221cb0ef41Sopenharmony_ci // saving subsequent checks, or yet better, by introducing new operators 61231cb0ef41Sopenharmony_ci // CopySmiOrObjectElements / CopyDoubleElements and inlining the JSArray 61241cb0ef41Sopenharmony_ci // allocation in here. That way we'd even get escape analysis and scalar 61251cb0ef41Sopenharmony_ci // replacement to help in some cases. 61261cb0ef41Sopenharmony_ci Callable callable = 61271cb0ef41Sopenharmony_ci Builtins::CallableFor(isolate(), Builtin::kCloneFastJSArray); 61281cb0ef41Sopenharmony_ci auto call_descriptor = Linkage::GetStubCallDescriptor( 61291cb0ef41Sopenharmony_ci graph()->zone(), callable.descriptor(), 61301cb0ef41Sopenharmony_ci callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags, 61311cb0ef41Sopenharmony_ci Operator::kNoThrow | Operator::kNoDeopt); 61321cb0ef41Sopenharmony_ci 61331cb0ef41Sopenharmony_ci // Calls to Builtin::kCloneFastJSArray produce COW arrays 61341cb0ef41Sopenharmony_ci // if the original array is COW 61351cb0ef41Sopenharmony_ci Node* clone = effect = graph()->NewNode( 61361cb0ef41Sopenharmony_ci common()->Call(call_descriptor), jsgraph()->HeapConstant(callable.code()), 61371cb0ef41Sopenharmony_ci receiver, context, effect, control); 61381cb0ef41Sopenharmony_ci 61391cb0ef41Sopenharmony_ci ReplaceWithValue(node, clone, effect, control); 61401cb0ef41Sopenharmony_ci return Replace(clone); 61411cb0ef41Sopenharmony_ci} 61421cb0ef41Sopenharmony_ci 61431cb0ef41Sopenharmony_ci// ES6 section 22.1.2.2 Array.isArray ( arg ) 61441cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayIsArray(Node* node) { 61451cb0ef41Sopenharmony_ci // We certainly know that undefined is not an array. 61461cb0ef41Sopenharmony_ci JSCallNode n(node); 61471cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) { 61481cb0ef41Sopenharmony_ci Node* value = jsgraph()->FalseConstant(); 61491cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 61501cb0ef41Sopenharmony_ci return Replace(value); 61511cb0ef41Sopenharmony_ci } 61521cb0ef41Sopenharmony_ci 61531cb0ef41Sopenharmony_ci Effect effect = n.effect(); 61541cb0ef41Sopenharmony_ci Control control = n.control(); 61551cb0ef41Sopenharmony_ci Node* context = n.context(); 61561cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 61571cb0ef41Sopenharmony_ci Node* object = n.Argument(0); 61581cb0ef41Sopenharmony_ci node->ReplaceInput(0, object); 61591cb0ef41Sopenharmony_ci node->ReplaceInput(1, context); 61601cb0ef41Sopenharmony_ci node->ReplaceInput(2, frame_state); 61611cb0ef41Sopenharmony_ci node->ReplaceInput(3, effect); 61621cb0ef41Sopenharmony_ci node->ReplaceInput(4, control); 61631cb0ef41Sopenharmony_ci node->TrimInputCount(5); 61641cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, javascript()->ObjectIsArray()); 61651cb0ef41Sopenharmony_ci return Changed(node); 61661cb0ef41Sopenharmony_ci} 61671cb0ef41Sopenharmony_ci 61681cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayIterator(Node* node, 61691cb0ef41Sopenharmony_ci ArrayIteratorKind array_kind, 61701cb0ef41Sopenharmony_ci IterationKind iteration_kind) { 61711cb0ef41Sopenharmony_ci JSCallNode n(node); 61721cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 61731cb0ef41Sopenharmony_ci Node* context = n.context(); 61741cb0ef41Sopenharmony_ci Effect effect = n.effect(); 61751cb0ef41Sopenharmony_ci Control control = n.control(); 61761cb0ef41Sopenharmony_ci 61771cb0ef41Sopenharmony_ci // Check if we know that {receiver} is a valid JSReceiver. 61781cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 61791cb0ef41Sopenharmony_ci if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAreJSReceiver()) { 61801cb0ef41Sopenharmony_ci return NoChange(); 61811cb0ef41Sopenharmony_ci } 61821cb0ef41Sopenharmony_ci 61831cb0ef41Sopenharmony_ci // TypedArray iteration is stricter: it throws if the receiver is not a typed 61841cb0ef41Sopenharmony_ci // array. So don't bother optimizing in that case. 61851cb0ef41Sopenharmony_ci if (array_kind == ArrayIteratorKind::kTypedArray && 61861cb0ef41Sopenharmony_ci !inference.AllOfInstanceTypesAre(InstanceType::JS_TYPED_ARRAY_TYPE)) { 61871cb0ef41Sopenharmony_ci return NoChange(); 61881cb0ef41Sopenharmony_ci } 61891cb0ef41Sopenharmony_ci 61901cb0ef41Sopenharmony_ci if (array_kind == ArrayIteratorKind::kTypedArray) { 61911cb0ef41Sopenharmony_ci // Make sure we deopt when the JSArrayBuffer is detached. 61921cb0ef41Sopenharmony_ci if (!dependencies()->DependOnArrayBufferDetachingProtector()) { 61931cb0ef41Sopenharmony_ci CallParameters const& p = CallParametersOf(node->op()); 61941cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 61951cb0ef41Sopenharmony_ci return NoChange(); 61961cb0ef41Sopenharmony_ci } 61971cb0ef41Sopenharmony_ci Node* buffer = effect = graph()->NewNode( 61981cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), 61991cb0ef41Sopenharmony_ci receiver, effect, control); 62001cb0ef41Sopenharmony_ci Node* buffer_bit_field = effect = graph()->NewNode( 62011cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()), 62021cb0ef41Sopenharmony_ci buffer, effect, control); 62031cb0ef41Sopenharmony_ci Node* check = graph()->NewNode( 62041cb0ef41Sopenharmony_ci simplified()->NumberEqual(), 62051cb0ef41Sopenharmony_ci graph()->NewNode( 62061cb0ef41Sopenharmony_ci simplified()->NumberBitwiseAnd(), buffer_bit_field, 62071cb0ef41Sopenharmony_ci jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)), 62081cb0ef41Sopenharmony_ci jsgraph()->ZeroConstant()); 62091cb0ef41Sopenharmony_ci effect = graph()->NewNode( 62101cb0ef41Sopenharmony_ci simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached, 62111cb0ef41Sopenharmony_ci p.feedback()), 62121cb0ef41Sopenharmony_ci check, effect, control); 62131cb0ef41Sopenharmony_ci } 62141cb0ef41Sopenharmony_ci } 62151cb0ef41Sopenharmony_ci 62161cb0ef41Sopenharmony_ci // Morph the {node} into a JSCreateArrayIterator with the given {kind}. 62171cb0ef41Sopenharmony_ci RelaxControls(node); 62181cb0ef41Sopenharmony_ci node->ReplaceInput(0, receiver); 62191cb0ef41Sopenharmony_ci node->ReplaceInput(1, context); 62201cb0ef41Sopenharmony_ci node->ReplaceInput(2, effect); 62211cb0ef41Sopenharmony_ci node->ReplaceInput(3, control); 62221cb0ef41Sopenharmony_ci node->TrimInputCount(4); 62231cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, 62241cb0ef41Sopenharmony_ci javascript()->CreateArrayIterator(iteration_kind)); 62251cb0ef41Sopenharmony_ci return Changed(node); 62261cb0ef41Sopenharmony_ci} 62271cb0ef41Sopenharmony_ci 62281cb0ef41Sopenharmony_ci// ES #sec-%arrayiteratorprototype%.next 62291cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) { 62301cb0ef41Sopenharmony_ci JSCallNode n(node); 62311cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 62321cb0ef41Sopenharmony_ci Node* iterator = n.receiver(); 62331cb0ef41Sopenharmony_ci Node* context = n.context(); 62341cb0ef41Sopenharmony_ci Effect effect = n.effect(); 62351cb0ef41Sopenharmony_ci Control control = n.control(); 62361cb0ef41Sopenharmony_ci 62371cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 62381cb0ef41Sopenharmony_ci return NoChange(); 62391cb0ef41Sopenharmony_ci } 62401cb0ef41Sopenharmony_ci 62411cb0ef41Sopenharmony_ci if (iterator->opcode() != IrOpcode::kJSCreateArrayIterator) return NoChange(); 62421cb0ef41Sopenharmony_ci 62431cb0ef41Sopenharmony_ci IterationKind const iteration_kind = 62441cb0ef41Sopenharmony_ci CreateArrayIteratorParametersOf(iterator->op()).kind(); 62451cb0ef41Sopenharmony_ci Node* iterated_object = NodeProperties::GetValueInput(iterator, 0); 62461cb0ef41Sopenharmony_ci Effect iterator_effect{NodeProperties::GetEffectInput(iterator)}; 62471cb0ef41Sopenharmony_ci 62481cb0ef41Sopenharmony_ci MapInference inference(broker(), iterated_object, iterator_effect); 62491cb0ef41Sopenharmony_ci if (!inference.HaveMaps()) return NoChange(); 62501cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& iterated_object_maps = inference.GetMaps(); 62511cb0ef41Sopenharmony_ci 62521cb0ef41Sopenharmony_ci // Check that various {iterated_object_maps} have compatible elements kinds. 62531cb0ef41Sopenharmony_ci ElementsKind elements_kind = iterated_object_maps[0].elements_kind(); 62541cb0ef41Sopenharmony_ci if (IsTypedArrayElementsKind(elements_kind)) { 62551cb0ef41Sopenharmony_ci // TurboFan doesn't support loading from BigInt typed arrays yet. 62561cb0ef41Sopenharmony_ci if (elements_kind == BIGUINT64_ELEMENTS || 62571cb0ef41Sopenharmony_ci elements_kind == BIGINT64_ELEMENTS) { 62581cb0ef41Sopenharmony_ci return inference.NoChange(); 62591cb0ef41Sopenharmony_ci } 62601cb0ef41Sopenharmony_ci for (const MapRef& iterated_object_map : iterated_object_maps) { 62611cb0ef41Sopenharmony_ci if (iterated_object_map.elements_kind() != elements_kind) { 62621cb0ef41Sopenharmony_ci return inference.NoChange(); 62631cb0ef41Sopenharmony_ci } 62641cb0ef41Sopenharmony_ci } 62651cb0ef41Sopenharmony_ci } else { 62661cb0ef41Sopenharmony_ci if (!CanInlineArrayIteratingBuiltin(broker(), iterated_object_maps, 62671cb0ef41Sopenharmony_ci &elements_kind)) { 62681cb0ef41Sopenharmony_ci return inference.NoChange(); 62691cb0ef41Sopenharmony_ci } 62701cb0ef41Sopenharmony_ci } 62711cb0ef41Sopenharmony_ci 62721cb0ef41Sopenharmony_ci if (IsHoleyElementsKind(elements_kind) && 62731cb0ef41Sopenharmony_ci !dependencies()->DependOnNoElementsProtector()) { 62741cb0ef41Sopenharmony_ci return inference.NoChange(); 62751cb0ef41Sopenharmony_ci } 62761cb0ef41Sopenharmony_ci 62771cb0ef41Sopenharmony_ci // Since the map inference was done relative to {iterator_effect} rather than 62781cb0ef41Sopenharmony_ci // {effect}, we need to guard the use of the map(s) even when the inference 62791cb0ef41Sopenharmony_ci // was reliable. 62801cb0ef41Sopenharmony_ci inference.InsertMapChecks(jsgraph(), &effect, control, p.feedback()); 62811cb0ef41Sopenharmony_ci 62821cb0ef41Sopenharmony_ci if (IsTypedArrayElementsKind(elements_kind)) { 62831cb0ef41Sopenharmony_ci // See if we can skip the detaching check. 62841cb0ef41Sopenharmony_ci if (!dependencies()->DependOnArrayBufferDetachingProtector()) { 62851cb0ef41Sopenharmony_ci // Bail out if the {iterated_object}s JSArrayBuffer was detached. 62861cb0ef41Sopenharmony_ci Node* buffer = effect = graph()->NewNode( 62871cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), 62881cb0ef41Sopenharmony_ci iterated_object, effect, control); 62891cb0ef41Sopenharmony_ci Node* buffer_bit_field = effect = graph()->NewNode( 62901cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()), 62911cb0ef41Sopenharmony_ci buffer, effect, control); 62921cb0ef41Sopenharmony_ci Node* check = graph()->NewNode( 62931cb0ef41Sopenharmony_ci simplified()->NumberEqual(), 62941cb0ef41Sopenharmony_ci graph()->NewNode( 62951cb0ef41Sopenharmony_ci simplified()->NumberBitwiseAnd(), buffer_bit_field, 62961cb0ef41Sopenharmony_ci jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)), 62971cb0ef41Sopenharmony_ci jsgraph()->ZeroConstant()); 62981cb0ef41Sopenharmony_ci effect = graph()->NewNode( 62991cb0ef41Sopenharmony_ci simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached, 63001cb0ef41Sopenharmony_ci p.feedback()), 63011cb0ef41Sopenharmony_ci check, effect, control); 63021cb0ef41Sopenharmony_ci } 63031cb0ef41Sopenharmony_ci } 63041cb0ef41Sopenharmony_ci 63051cb0ef41Sopenharmony_ci // Load the [[NextIndex]] from the {iterator} and leverage the fact 63061cb0ef41Sopenharmony_ci // that we definitely know that it's in Unsigned32 range since the 63071cb0ef41Sopenharmony_ci // {iterated_object} is either a JSArray or a JSTypedArray. For the 63081cb0ef41Sopenharmony_ci // latter case we even know that it's a Smi in UnsignedSmall range. 63091cb0ef41Sopenharmony_ci FieldAccess index_access = AccessBuilder::ForJSArrayIteratorNextIndex(); 63101cb0ef41Sopenharmony_ci if (IsTypedArrayElementsKind(elements_kind)) { 63111cb0ef41Sopenharmony_ci index_access.type = TypeCache::Get()->kJSTypedArrayLengthType; 63121cb0ef41Sopenharmony_ci } else { 63131cb0ef41Sopenharmony_ci index_access.type = TypeCache::Get()->kJSArrayLengthType; 63141cb0ef41Sopenharmony_ci } 63151cb0ef41Sopenharmony_ci Node* index = effect = graph()->NewNode(simplified()->LoadField(index_access), 63161cb0ef41Sopenharmony_ci iterator, effect, control); 63171cb0ef41Sopenharmony_ci 63181cb0ef41Sopenharmony_ci // Load the elements of the {iterated_object}. While it feels 63191cb0ef41Sopenharmony_ci // counter-intuitive to place the elements pointer load before 63201cb0ef41Sopenharmony_ci // the condition below, as it might not be needed (if the {index} 63211cb0ef41Sopenharmony_ci // is out of bounds for the {iterated_object}), it's better this 63221cb0ef41Sopenharmony_ci // way as it allows the LoadElimination to eliminate redundant 63231cb0ef41Sopenharmony_ci // reloads of the elements pointer. 63241cb0ef41Sopenharmony_ci Node* elements = effect = graph()->NewNode( 63251cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSObjectElements()), 63261cb0ef41Sopenharmony_ci iterated_object, effect, control); 63271cb0ef41Sopenharmony_ci 63281cb0ef41Sopenharmony_ci // Load the length of the {iterated_object}. Due to the map checks we 63291cb0ef41Sopenharmony_ci // already know something about the length here, which we can leverage 63301cb0ef41Sopenharmony_ci // to generate Word32 operations below without additional checking. 63311cb0ef41Sopenharmony_ci FieldAccess length_access = 63321cb0ef41Sopenharmony_ci IsTypedArrayElementsKind(elements_kind) 63331cb0ef41Sopenharmony_ci ? AccessBuilder::ForJSTypedArrayLength() 63341cb0ef41Sopenharmony_ci : AccessBuilder::ForJSArrayLength(elements_kind); 63351cb0ef41Sopenharmony_ci Node* length = effect = graph()->NewNode( 63361cb0ef41Sopenharmony_ci simplified()->LoadField(length_access), iterated_object, effect, control); 63371cb0ef41Sopenharmony_ci 63381cb0ef41Sopenharmony_ci // Check whether {index} is within the valid range for the {iterated_object}. 63391cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->NumberLessThan(), index, length); 63401cb0ef41Sopenharmony_ci Node* branch = 63411cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(BranchHint::kNone), check, control); 63421cb0ef41Sopenharmony_ci 63431cb0ef41Sopenharmony_ci Node* done_true; 63441cb0ef41Sopenharmony_ci Node* value_true; 63451cb0ef41Sopenharmony_ci Node* etrue = effect; 63461cb0ef41Sopenharmony_ci Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 63471cb0ef41Sopenharmony_ci { 63481cb0ef41Sopenharmony_ci // This extra check exists to refine the type of {index} but also to break 63491cb0ef41Sopenharmony_ci // an exploitation technique that abuses typer mismatches. 63501cb0ef41Sopenharmony_ci index = etrue = graph()->NewNode( 63511cb0ef41Sopenharmony_ci simplified()->CheckBounds(p.feedback(), 63521cb0ef41Sopenharmony_ci CheckBoundsFlag::kAbortOnOutOfBounds), 63531cb0ef41Sopenharmony_ci index, length, etrue, if_true); 63541cb0ef41Sopenharmony_ci 63551cb0ef41Sopenharmony_ci done_true = jsgraph()->FalseConstant(); 63561cb0ef41Sopenharmony_ci if (iteration_kind == IterationKind::kKeys) { 63571cb0ef41Sopenharmony_ci // Just return the {index}. 63581cb0ef41Sopenharmony_ci value_true = index; 63591cb0ef41Sopenharmony_ci } else { 63601cb0ef41Sopenharmony_ci DCHECK(iteration_kind == IterationKind::kEntries || 63611cb0ef41Sopenharmony_ci iteration_kind == IterationKind::kValues); 63621cb0ef41Sopenharmony_ci 63631cb0ef41Sopenharmony_ci if (IsTypedArrayElementsKind(elements_kind)) { 63641cb0ef41Sopenharmony_ci Node* base_ptr = etrue = 63651cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->LoadField( 63661cb0ef41Sopenharmony_ci AccessBuilder::ForJSTypedArrayBasePointer()), 63671cb0ef41Sopenharmony_ci iterated_object, etrue, if_true); 63681cb0ef41Sopenharmony_ci Node* external_ptr = etrue = graph()->NewNode( 63691cb0ef41Sopenharmony_ci simplified()->LoadField( 63701cb0ef41Sopenharmony_ci AccessBuilder::ForJSTypedArrayExternalPointer()), 63711cb0ef41Sopenharmony_ci iterated_object, etrue, if_true); 63721cb0ef41Sopenharmony_ci 63731cb0ef41Sopenharmony_ci ExternalArrayType array_type = kExternalInt8Array; 63741cb0ef41Sopenharmony_ci switch (elements_kind) { 63751cb0ef41Sopenharmony_ci#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \ 63761cb0ef41Sopenharmony_ci case TYPE##_ELEMENTS: \ 63771cb0ef41Sopenharmony_ci array_type = kExternal##Type##Array; \ 63781cb0ef41Sopenharmony_ci break; 63791cb0ef41Sopenharmony_ci TYPED_ARRAYS(TYPED_ARRAY_CASE) 63801cb0ef41Sopenharmony_ci default: 63811cb0ef41Sopenharmony_ci UNREACHABLE(); 63821cb0ef41Sopenharmony_ci#undef TYPED_ARRAY_CASE 63831cb0ef41Sopenharmony_ci } 63841cb0ef41Sopenharmony_ci 63851cb0ef41Sopenharmony_ci Node* buffer = etrue = 63861cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->LoadField( 63871cb0ef41Sopenharmony_ci AccessBuilder::ForJSArrayBufferViewBuffer()), 63881cb0ef41Sopenharmony_ci iterated_object, etrue, if_true); 63891cb0ef41Sopenharmony_ci 63901cb0ef41Sopenharmony_ci value_true = etrue = 63911cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->LoadTypedElement(array_type), buffer, 63921cb0ef41Sopenharmony_ci base_ptr, external_ptr, index, etrue, if_true); 63931cb0ef41Sopenharmony_ci } else { 63941cb0ef41Sopenharmony_ci value_true = etrue = graph()->NewNode( 63951cb0ef41Sopenharmony_ci simplified()->LoadElement( 63961cb0ef41Sopenharmony_ci AccessBuilder::ForFixedArrayElement(elements_kind)), 63971cb0ef41Sopenharmony_ci elements, index, etrue, if_true); 63981cb0ef41Sopenharmony_ci 63991cb0ef41Sopenharmony_ci // Convert hole to undefined if needed. 64001cb0ef41Sopenharmony_ci if (elements_kind == HOLEY_ELEMENTS || 64011cb0ef41Sopenharmony_ci elements_kind == HOLEY_SMI_ELEMENTS) { 64021cb0ef41Sopenharmony_ci value_true = graph()->NewNode( 64031cb0ef41Sopenharmony_ci simplified()->ConvertTaggedHoleToUndefined(), value_true); 64041cb0ef41Sopenharmony_ci } else if (elements_kind == HOLEY_DOUBLE_ELEMENTS) { 64051cb0ef41Sopenharmony_ci // TODO(6587): avoid deopt if not all uses of value are truncated. 64061cb0ef41Sopenharmony_ci CheckFloat64HoleMode mode = CheckFloat64HoleMode::kAllowReturnHole; 64071cb0ef41Sopenharmony_ci value_true = etrue = graph()->NewNode( 64081cb0ef41Sopenharmony_ci simplified()->CheckFloat64Hole(mode, p.feedback()), value_true, 64091cb0ef41Sopenharmony_ci etrue, if_true); 64101cb0ef41Sopenharmony_ci } 64111cb0ef41Sopenharmony_ci } 64121cb0ef41Sopenharmony_ci 64131cb0ef41Sopenharmony_ci if (iteration_kind == IterationKind::kEntries) { 64141cb0ef41Sopenharmony_ci // Allocate elements for key/value pair 64151cb0ef41Sopenharmony_ci value_true = etrue = 64161cb0ef41Sopenharmony_ci graph()->NewNode(javascript()->CreateKeyValueArray(), index, 64171cb0ef41Sopenharmony_ci value_true, context, etrue); 64181cb0ef41Sopenharmony_ci } else { 64191cb0ef41Sopenharmony_ci DCHECK_EQ(IterationKind::kValues, iteration_kind); 64201cb0ef41Sopenharmony_ci } 64211cb0ef41Sopenharmony_ci } 64221cb0ef41Sopenharmony_ci 64231cb0ef41Sopenharmony_ci // Increment the [[NextIndex]] field in the {iterator}. The TypeGuards 64241cb0ef41Sopenharmony_ci // above guarantee that the {next_index} is in the UnsignedSmall range. 64251cb0ef41Sopenharmony_ci Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index, 64261cb0ef41Sopenharmony_ci jsgraph()->OneConstant()); 64271cb0ef41Sopenharmony_ci etrue = graph()->NewNode(simplified()->StoreField(index_access), iterator, 64281cb0ef41Sopenharmony_ci next_index, etrue, if_true); 64291cb0ef41Sopenharmony_ci } 64301cb0ef41Sopenharmony_ci 64311cb0ef41Sopenharmony_ci Node* done_false; 64321cb0ef41Sopenharmony_ci Node* value_false; 64331cb0ef41Sopenharmony_ci Node* efalse = effect; 64341cb0ef41Sopenharmony_ci Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 64351cb0ef41Sopenharmony_ci { 64361cb0ef41Sopenharmony_ci // iterator.[[NextIndex]] >= array.length, stop iterating. 64371cb0ef41Sopenharmony_ci done_false = jsgraph()->TrueConstant(); 64381cb0ef41Sopenharmony_ci value_false = jsgraph()->UndefinedConstant(); 64391cb0ef41Sopenharmony_ci 64401cb0ef41Sopenharmony_ci if (!IsTypedArrayElementsKind(elements_kind)) { 64411cb0ef41Sopenharmony_ci // Mark the {iterator} as exhausted by setting the [[NextIndex]] to a 64421cb0ef41Sopenharmony_ci // value that will never pass the length check again (aka the maximum 64431cb0ef41Sopenharmony_ci // value possible for the specific iterated object). Note that this is 64441cb0ef41Sopenharmony_ci // different from what the specification says, which is changing the 64451cb0ef41Sopenharmony_ci // [[IteratedObject]] field to undefined, but that makes it difficult 64461cb0ef41Sopenharmony_ci // to eliminate the map checks and "length" accesses in for..of loops. 64471cb0ef41Sopenharmony_ci // 64481cb0ef41Sopenharmony_ci // This is not necessary for JSTypedArray's, since the length of those 64491cb0ef41Sopenharmony_ci // cannot change later and so if we were ever out of bounds for them 64501cb0ef41Sopenharmony_ci // we will stay out-of-bounds forever. 64511cb0ef41Sopenharmony_ci Node* end_index = jsgraph()->Constant(index_access.type.Max()); 64521cb0ef41Sopenharmony_ci efalse = graph()->NewNode(simplified()->StoreField(index_access), 64531cb0ef41Sopenharmony_ci iterator, end_index, efalse, if_false); 64541cb0ef41Sopenharmony_ci } 64551cb0ef41Sopenharmony_ci } 64561cb0ef41Sopenharmony_ci 64571cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Merge(2), if_true, if_false); 64581cb0ef41Sopenharmony_ci effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); 64591cb0ef41Sopenharmony_ci Node* value = 64601cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 64611cb0ef41Sopenharmony_ci value_true, value_false, control); 64621cb0ef41Sopenharmony_ci Node* done = 64631cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 64641cb0ef41Sopenharmony_ci done_true, done_false, control); 64651cb0ef41Sopenharmony_ci 64661cb0ef41Sopenharmony_ci // Create IteratorResult object. 64671cb0ef41Sopenharmony_ci value = effect = graph()->NewNode(javascript()->CreateIterResultObject(), 64681cb0ef41Sopenharmony_ci value, done, context, effect); 64691cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 64701cb0ef41Sopenharmony_ci return Replace(value); 64711cb0ef41Sopenharmony_ci} 64721cb0ef41Sopenharmony_ci 64731cb0ef41Sopenharmony_ci// ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) 64741cb0ef41Sopenharmony_ci// ES6 section 21.1.3.3 String.prototype.codePointAt ( pos ) 64751cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringPrototypeStringAt( 64761cb0ef41Sopenharmony_ci const Operator* string_access_operator, Node* node) { 64771cb0ef41Sopenharmony_ci DCHECK(string_access_operator->opcode() == IrOpcode::kStringCharCodeAt || 64781cb0ef41Sopenharmony_ci string_access_operator->opcode() == IrOpcode::kStringCodePointAt); 64791cb0ef41Sopenharmony_ci JSCallNode n(node); 64801cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 64811cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 64821cb0ef41Sopenharmony_ci return NoChange(); 64831cb0ef41Sopenharmony_ci } 64841cb0ef41Sopenharmony_ci 64851cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 64861cb0ef41Sopenharmony_ci Node* index = n.ArgumentOr(0, jsgraph()->ZeroConstant()); 64871cb0ef41Sopenharmony_ci Effect effect = n.effect(); 64881cb0ef41Sopenharmony_ci Control control = n.control(); 64891cb0ef41Sopenharmony_ci 64901cb0ef41Sopenharmony_ci // Ensure that the {receiver} is actually a String. 64911cb0ef41Sopenharmony_ci receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()), 64921cb0ef41Sopenharmony_ci receiver, effect, control); 64931cb0ef41Sopenharmony_ci 64941cb0ef41Sopenharmony_ci // Determine the {receiver} length. 64951cb0ef41Sopenharmony_ci Node* receiver_length = 64961cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->StringLength(), receiver); 64971cb0ef41Sopenharmony_ci 64981cb0ef41Sopenharmony_ci // Check that the {index} is within range. 64991cb0ef41Sopenharmony_ci index = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()), 65001cb0ef41Sopenharmony_ci index, receiver_length, effect, control); 65011cb0ef41Sopenharmony_ci 65021cb0ef41Sopenharmony_ci // Return the character from the {receiver} as single character string. 65031cb0ef41Sopenharmony_ci Node* value = effect = graph()->NewNode(string_access_operator, receiver, 65041cb0ef41Sopenharmony_ci index, effect, control); 65051cb0ef41Sopenharmony_ci 65061cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 65071cb0ef41Sopenharmony_ci return Replace(value); 65081cb0ef41Sopenharmony_ci} 65091cb0ef41Sopenharmony_ci 65101cb0ef41Sopenharmony_ci// ES section 21.1.3.20 65111cb0ef41Sopenharmony_ci// String.prototype.startsWith ( searchString [ , position ] ) 65121cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringPrototypeStartsWith(Node* node) { 65131cb0ef41Sopenharmony_ci JSCallNode n(node); 65141cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 65151cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 65161cb0ef41Sopenharmony_ci return NoChange(); 65171cb0ef41Sopenharmony_ci } 65181cb0ef41Sopenharmony_ci 65191cb0ef41Sopenharmony_ci TNode<Object> search_element = n.ArgumentOrUndefined(0, jsgraph()); 65201cb0ef41Sopenharmony_ci 65211cb0ef41Sopenharmony_ci // Here are three conditions: 65221cb0ef41Sopenharmony_ci // First, If search_element is definitely not a string, we make no change. 65231cb0ef41Sopenharmony_ci // Second, If search_element is definitely a string and its length is less 65241cb0ef41Sopenharmony_ci // or equal than max inline matching sequence threshold, we could inline 65251cb0ef41Sopenharmony_ci // the entire matching sequence. 65261cb0ef41Sopenharmony_ci // Third, we try to inline, and have a runtime deopt if search_element is 65271cb0ef41Sopenharmony_ci // not a string. 65281cb0ef41Sopenharmony_ci HeapObjectMatcher search_element_matcher(search_element); 65291cb0ef41Sopenharmony_ci if (search_element_matcher.HasResolvedValue()) { 65301cb0ef41Sopenharmony_ci ObjectRef target_ref = search_element_matcher.Ref(broker()); 65311cb0ef41Sopenharmony_ci if (!target_ref.IsString()) return NoChange(); 65321cb0ef41Sopenharmony_ci StringRef search_element_string = target_ref.AsString(); 65331cb0ef41Sopenharmony_ci if (search_element_string.length().has_value()) { 65341cb0ef41Sopenharmony_ci int length = search_element_string.length().value(); 65351cb0ef41Sopenharmony_ci // If search_element's length is less or equal than 65361cb0ef41Sopenharmony_ci // kMaxInlineMatchSequence, we inline the entire 65371cb0ef41Sopenharmony_ci // matching sequence. 65381cb0ef41Sopenharmony_ci if (length <= kMaxInlineMatchSequence) { 65391cb0ef41Sopenharmony_ci JSCallReducerAssembler a(this, node); 65401cb0ef41Sopenharmony_ci Node* subgraph = 65411cb0ef41Sopenharmony_ci a.ReduceStringPrototypeStartsWith(search_element_string); 65421cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 65431cb0ef41Sopenharmony_ci } 65441cb0ef41Sopenharmony_ci } 65451cb0ef41Sopenharmony_ci } 65461cb0ef41Sopenharmony_ci 65471cb0ef41Sopenharmony_ci JSCallReducerAssembler a(this, node); 65481cb0ef41Sopenharmony_ci Node* subgraph = a.ReduceStringPrototypeStartsWith(); 65491cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 65501cb0ef41Sopenharmony_ci} 65511cb0ef41Sopenharmony_ci 65521cb0ef41Sopenharmony_ci// ES section 21.1.3.1 String.prototype.charAt ( pos ) 65531cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringPrototypeCharAt(Node* node) { 65541cb0ef41Sopenharmony_ci JSCallNode n(node); 65551cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 65561cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 65571cb0ef41Sopenharmony_ci return NoChange(); 65581cb0ef41Sopenharmony_ci } 65591cb0ef41Sopenharmony_ci 65601cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 65611cb0ef41Sopenharmony_ci Node* index = n.ArgumentOr(0, jsgraph()->ZeroConstant()); 65621cb0ef41Sopenharmony_ci Effect effect = n.effect(); 65631cb0ef41Sopenharmony_ci Control control = n.control(); 65641cb0ef41Sopenharmony_ci 65651cb0ef41Sopenharmony_ci // Ensure that the {receiver} is actually a String. 65661cb0ef41Sopenharmony_ci receiver = effect = graph()->NewNode(simplified()->CheckString(p.feedback()), 65671cb0ef41Sopenharmony_ci receiver, effect, control); 65681cb0ef41Sopenharmony_ci 65691cb0ef41Sopenharmony_ci // Determine the {receiver} length. 65701cb0ef41Sopenharmony_ci Node* receiver_length = 65711cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->StringLength(), receiver); 65721cb0ef41Sopenharmony_ci 65731cb0ef41Sopenharmony_ci // Check that the {index} is within range. 65741cb0ef41Sopenharmony_ci index = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()), 65751cb0ef41Sopenharmony_ci index, receiver_length, effect, control); 65761cb0ef41Sopenharmony_ci 65771cb0ef41Sopenharmony_ci // Return the character from the {receiver} as single character string. 65781cb0ef41Sopenharmony_ci Node* value = effect = graph()->NewNode(simplified()->StringCharCodeAt(), 65791cb0ef41Sopenharmony_ci receiver, index, effect, control); 65801cb0ef41Sopenharmony_ci value = graph()->NewNode(simplified()->StringFromSingleCharCode(), value); 65811cb0ef41Sopenharmony_ci 65821cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 65831cb0ef41Sopenharmony_ci return Replace(value); 65841cb0ef41Sopenharmony_ci} 65851cb0ef41Sopenharmony_ci 65861cb0ef41Sopenharmony_ci#ifdef V8_INTL_SUPPORT 65871cb0ef41Sopenharmony_ci 65881cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringPrototypeToLowerCaseIntl(Node* node) { 65891cb0ef41Sopenharmony_ci JSCallNode n(node); 65901cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 65911cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 65921cb0ef41Sopenharmony_ci return NoChange(); 65931cb0ef41Sopenharmony_ci } 65941cb0ef41Sopenharmony_ci Effect effect = n.effect(); 65951cb0ef41Sopenharmony_ci Control control = n.control(); 65961cb0ef41Sopenharmony_ci 65971cb0ef41Sopenharmony_ci Node* receiver = effect = graph()->NewNode( 65981cb0ef41Sopenharmony_ci simplified()->CheckString(p.feedback()), n.receiver(), effect, control); 65991cb0ef41Sopenharmony_ci 66001cb0ef41Sopenharmony_ci NodeProperties::ReplaceEffectInput(node, effect); 66011cb0ef41Sopenharmony_ci RelaxEffectsAndControls(node); 66021cb0ef41Sopenharmony_ci node->ReplaceInput(0, receiver); 66031cb0ef41Sopenharmony_ci node->TrimInputCount(1); 66041cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, simplified()->StringToLowerCaseIntl()); 66051cb0ef41Sopenharmony_ci NodeProperties::SetType(node, Type::String()); 66061cb0ef41Sopenharmony_ci return Changed(node); 66071cb0ef41Sopenharmony_ci} 66081cb0ef41Sopenharmony_ci 66091cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringPrototypeToUpperCaseIntl(Node* node) { 66101cb0ef41Sopenharmony_ci JSCallNode n(node); 66111cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 66121cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 66131cb0ef41Sopenharmony_ci return NoChange(); 66141cb0ef41Sopenharmony_ci } 66151cb0ef41Sopenharmony_ci Effect effect = n.effect(); 66161cb0ef41Sopenharmony_ci Control control = n.control(); 66171cb0ef41Sopenharmony_ci 66181cb0ef41Sopenharmony_ci Node* receiver = effect = graph()->NewNode( 66191cb0ef41Sopenharmony_ci simplified()->CheckString(p.feedback()), n.receiver(), effect, control); 66201cb0ef41Sopenharmony_ci 66211cb0ef41Sopenharmony_ci NodeProperties::ReplaceEffectInput(node, effect); 66221cb0ef41Sopenharmony_ci RelaxEffectsAndControls(node); 66231cb0ef41Sopenharmony_ci node->ReplaceInput(0, receiver); 66241cb0ef41Sopenharmony_ci node->TrimInputCount(1); 66251cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, simplified()->StringToUpperCaseIntl()); 66261cb0ef41Sopenharmony_ci NodeProperties::SetType(node, Type::String()); 66271cb0ef41Sopenharmony_ci return Changed(node); 66281cb0ef41Sopenharmony_ci} 66291cb0ef41Sopenharmony_ci 66301cb0ef41Sopenharmony_ci#endif // V8_INTL_SUPPORT 66311cb0ef41Sopenharmony_ci 66321cb0ef41Sopenharmony_ci// ES #sec-string.fromcharcode 66331cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringFromCharCode(Node* node) { 66341cb0ef41Sopenharmony_ci JSCallNode n(node); 66351cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 66361cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 66371cb0ef41Sopenharmony_ci return NoChange(); 66381cb0ef41Sopenharmony_ci } 66391cb0ef41Sopenharmony_ci if (n.ArgumentCount() == 1) { 66401cb0ef41Sopenharmony_ci Effect effect = n.effect(); 66411cb0ef41Sopenharmony_ci Control control = n.control(); 66421cb0ef41Sopenharmony_ci Node* input = n.Argument(0); 66431cb0ef41Sopenharmony_ci 66441cb0ef41Sopenharmony_ci input = effect = graph()->NewNode( 66451cb0ef41Sopenharmony_ci simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball, 66461cb0ef41Sopenharmony_ci p.feedback()), 66471cb0ef41Sopenharmony_ci input, effect, control); 66481cb0ef41Sopenharmony_ci 66491cb0ef41Sopenharmony_ci Node* value = 66501cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->StringFromSingleCharCode(), input); 66511cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect); 66521cb0ef41Sopenharmony_ci return Replace(value); 66531cb0ef41Sopenharmony_ci } 66541cb0ef41Sopenharmony_ci return NoChange(); 66551cb0ef41Sopenharmony_ci} 66561cb0ef41Sopenharmony_ci 66571cb0ef41Sopenharmony_ci// ES #sec-string.fromcodepoint 66581cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringFromCodePoint(Node* node) { 66591cb0ef41Sopenharmony_ci JSCallNode n(node); 66601cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 66611cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 66621cb0ef41Sopenharmony_ci return NoChange(); 66631cb0ef41Sopenharmony_ci } 66641cb0ef41Sopenharmony_ci if (n.ArgumentCount() != 1) return NoChange(); 66651cb0ef41Sopenharmony_ci 66661cb0ef41Sopenharmony_ci Effect effect = n.effect(); 66671cb0ef41Sopenharmony_ci Control control = n.control(); 66681cb0ef41Sopenharmony_ci Node* input = n.Argument(0); 66691cb0ef41Sopenharmony_ci 66701cb0ef41Sopenharmony_ci input = effect = graph()->NewNode( 66711cb0ef41Sopenharmony_ci simplified()->CheckBounds(p.feedback(), 66721cb0ef41Sopenharmony_ci CheckBoundsFlag::kConvertStringAndMinusZero), 66731cb0ef41Sopenharmony_ci input, jsgraph()->Constant(0x10FFFF + 1), effect, control); 66741cb0ef41Sopenharmony_ci 66751cb0ef41Sopenharmony_ci Node* value = 66761cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->StringFromSingleCodePoint(), input); 66771cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect); 66781cb0ef41Sopenharmony_ci return Replace(value); 66791cb0ef41Sopenharmony_ci} 66801cb0ef41Sopenharmony_ci 66811cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringPrototypeIterator(Node* node) { 66821cb0ef41Sopenharmony_ci JSCallNode n(node); 66831cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 66841cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 66851cb0ef41Sopenharmony_ci return NoChange(); 66861cb0ef41Sopenharmony_ci } 66871cb0ef41Sopenharmony_ci Node* effect = NodeProperties::GetEffectInput(node); 66881cb0ef41Sopenharmony_ci Node* control = NodeProperties::GetControlInput(node); 66891cb0ef41Sopenharmony_ci Node* receiver = effect = graph()->NewNode( 66901cb0ef41Sopenharmony_ci simplified()->CheckString(p.feedback()), n.receiver(), effect, control); 66911cb0ef41Sopenharmony_ci Node* iterator = effect = 66921cb0ef41Sopenharmony_ci graph()->NewNode(javascript()->CreateStringIterator(), receiver, 66931cb0ef41Sopenharmony_ci jsgraph()->NoContextConstant(), effect); 66941cb0ef41Sopenharmony_ci ReplaceWithValue(node, iterator, effect, control); 66951cb0ef41Sopenharmony_ci return Replace(iterator); 66961cb0ef41Sopenharmony_ci} 66971cb0ef41Sopenharmony_ci 66981cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringPrototypeLocaleCompare(Node* node) { 66991cb0ef41Sopenharmony_ci#ifdef V8_INTL_SUPPORT 67001cb0ef41Sopenharmony_ci JSCallNode n(node); 67011cb0ef41Sopenharmony_ci // Signature: receiver.localeCompare(compareString, locales, options) 67021cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1 || n.ArgumentCount() > 3) { 67031cb0ef41Sopenharmony_ci return NoChange(); 67041cb0ef41Sopenharmony_ci } 67051cb0ef41Sopenharmony_ci 67061cb0ef41Sopenharmony_ci { 67071cb0ef41Sopenharmony_ci Handle<Object> locales; 67081cb0ef41Sopenharmony_ci { 67091cb0ef41Sopenharmony_ci HeapObjectMatcher m(n.ArgumentOrUndefined(1, jsgraph())); 67101cb0ef41Sopenharmony_ci if (!m.HasResolvedValue()) return NoChange(); 67111cb0ef41Sopenharmony_ci if (m.Is(factory()->undefined_value())) { 67121cb0ef41Sopenharmony_ci locales = factory()->undefined_value(); 67131cb0ef41Sopenharmony_ci } else { 67141cb0ef41Sopenharmony_ci ObjectRef ref = m.Ref(broker()); 67151cb0ef41Sopenharmony_ci if (!ref.IsString()) return NoChange(); 67161cb0ef41Sopenharmony_ci StringRef sref = ref.AsString(); 67171cb0ef41Sopenharmony_ci if (base::Optional<Handle<String>> maybe_locales = 67181cb0ef41Sopenharmony_ci sref.ObjectIfContentAccessible()) { 67191cb0ef41Sopenharmony_ci locales = *maybe_locales; 67201cb0ef41Sopenharmony_ci } else { 67211cb0ef41Sopenharmony_ci return NoChange(); 67221cb0ef41Sopenharmony_ci } 67231cb0ef41Sopenharmony_ci } 67241cb0ef41Sopenharmony_ci } 67251cb0ef41Sopenharmony_ci 67261cb0ef41Sopenharmony_ci TNode<Object> options = n.ArgumentOrUndefined(2, jsgraph()); 67271cb0ef41Sopenharmony_ci { 67281cb0ef41Sopenharmony_ci HeapObjectMatcher m(options); 67291cb0ef41Sopenharmony_ci if (!m.Is(factory()->undefined_value())) { 67301cb0ef41Sopenharmony_ci return NoChange(); 67311cb0ef41Sopenharmony_ci } 67321cb0ef41Sopenharmony_ci } 67331cb0ef41Sopenharmony_ci 67341cb0ef41Sopenharmony_ci if (Intl::CompareStringsOptionsFor(broker()->local_isolate_or_isolate(), 67351cb0ef41Sopenharmony_ci locales, factory()->undefined_value()) != 67361cb0ef41Sopenharmony_ci Intl::CompareStringsOptions::kTryFastPath) { 67371cb0ef41Sopenharmony_ci return NoChange(); 67381cb0ef41Sopenharmony_ci } 67391cb0ef41Sopenharmony_ci } 67401cb0ef41Sopenharmony_ci 67411cb0ef41Sopenharmony_ci Callable callable = 67421cb0ef41Sopenharmony_ci Builtins::CallableFor(isolate(), Builtin::kStringFastLocaleCompare); 67431cb0ef41Sopenharmony_ci auto call_descriptor = Linkage::GetStubCallDescriptor( 67441cb0ef41Sopenharmony_ci graph()->zone(), callable.descriptor(), 67451cb0ef41Sopenharmony_ci callable.descriptor().GetStackParameterCount(), 67461cb0ef41Sopenharmony_ci CallDescriptor::kNeedsFrameState); 67471cb0ef41Sopenharmony_ci node->RemoveInput(n.FeedbackVectorIndex()); 67481cb0ef41Sopenharmony_ci if (n.ArgumentCount() == 3) { 67491cb0ef41Sopenharmony_ci node->RemoveInput(n.ArgumentIndex(2)); 67501cb0ef41Sopenharmony_ci } else if (n.ArgumentCount() == 1) { 67511cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), n.LastArgumentIndex() + 1, 67521cb0ef41Sopenharmony_ci jsgraph()->UndefinedConstant()); 67531cb0ef41Sopenharmony_ci } else { 67541cb0ef41Sopenharmony_ci DCHECK_EQ(2, n.ArgumentCount()); 67551cb0ef41Sopenharmony_ci } 67561cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), 0, 67571cb0ef41Sopenharmony_ci jsgraph()->HeapConstant(callable.code())); 67581cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); 67591cb0ef41Sopenharmony_ci return Changed(node); 67601cb0ef41Sopenharmony_ci#else 67611cb0ef41Sopenharmony_ci return NoChange(); 67621cb0ef41Sopenharmony_ci#endif 67631cb0ef41Sopenharmony_ci} 67641cb0ef41Sopenharmony_ci 67651cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringIteratorPrototypeNext(Node* node) { 67661cb0ef41Sopenharmony_ci JSCallNode n(node); 67671cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 67681cb0ef41Sopenharmony_ci Effect effect = n.effect(); 67691cb0ef41Sopenharmony_ci Control control = n.control(); 67701cb0ef41Sopenharmony_ci Node* context = n.context(); 67711cb0ef41Sopenharmony_ci 67721cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 67731cb0ef41Sopenharmony_ci if (!inference.HaveMaps() || 67741cb0ef41Sopenharmony_ci !inference.AllOfInstanceTypesAre(JS_STRING_ITERATOR_TYPE)) { 67751cb0ef41Sopenharmony_ci return NoChange(); 67761cb0ef41Sopenharmony_ci } 67771cb0ef41Sopenharmony_ci 67781cb0ef41Sopenharmony_ci Node* string = effect = graph()->NewNode( 67791cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSStringIteratorString()), 67801cb0ef41Sopenharmony_ci receiver, effect, control); 67811cb0ef41Sopenharmony_ci Node* index = effect = graph()->NewNode( 67821cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSStringIteratorIndex()), 67831cb0ef41Sopenharmony_ci receiver, effect, control); 67841cb0ef41Sopenharmony_ci Node* length = graph()->NewNode(simplified()->StringLength(), string); 67851cb0ef41Sopenharmony_ci 67861cb0ef41Sopenharmony_ci // branch0: if (index < length) 67871cb0ef41Sopenharmony_ci Node* check0 = 67881cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberLessThan(), index, length); 67891cb0ef41Sopenharmony_ci Node* branch0 = 67901cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(BranchHint::kNone), check0, control); 67911cb0ef41Sopenharmony_ci 67921cb0ef41Sopenharmony_ci Node* etrue0 = effect; 67931cb0ef41Sopenharmony_ci Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 67941cb0ef41Sopenharmony_ci Node* done_true; 67951cb0ef41Sopenharmony_ci Node* vtrue0; 67961cb0ef41Sopenharmony_ci { 67971cb0ef41Sopenharmony_ci done_true = jsgraph()->FalseConstant(); 67981cb0ef41Sopenharmony_ci vtrue0 = etrue0 = graph()->NewNode(simplified()->StringFromCodePointAt(), 67991cb0ef41Sopenharmony_ci string, index, etrue0, if_true0); 68001cb0ef41Sopenharmony_ci 68011cb0ef41Sopenharmony_ci // Update iterator.[[NextIndex]] 68021cb0ef41Sopenharmony_ci Node* char_length = graph()->NewNode(simplified()->StringLength(), vtrue0); 68031cb0ef41Sopenharmony_ci index = graph()->NewNode(simplified()->NumberAdd(), index, char_length); 68041cb0ef41Sopenharmony_ci etrue0 = graph()->NewNode( 68051cb0ef41Sopenharmony_ci simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()), 68061cb0ef41Sopenharmony_ci receiver, index, etrue0, if_true0); 68071cb0ef41Sopenharmony_ci } 68081cb0ef41Sopenharmony_ci 68091cb0ef41Sopenharmony_ci Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 68101cb0ef41Sopenharmony_ci Node* done_false; 68111cb0ef41Sopenharmony_ci Node* vfalse0; 68121cb0ef41Sopenharmony_ci { 68131cb0ef41Sopenharmony_ci vfalse0 = jsgraph()->UndefinedConstant(); 68141cb0ef41Sopenharmony_ci done_false = jsgraph()->TrueConstant(); 68151cb0ef41Sopenharmony_ci } 68161cb0ef41Sopenharmony_ci 68171cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Merge(2), if_true0, if_false0); 68181cb0ef41Sopenharmony_ci effect = graph()->NewNode(common()->EffectPhi(2), etrue0, effect, control); 68191cb0ef41Sopenharmony_ci Node* value = 68201cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), vtrue0, 68211cb0ef41Sopenharmony_ci vfalse0, control); 68221cb0ef41Sopenharmony_ci Node* done = 68231cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 68241cb0ef41Sopenharmony_ci done_true, done_false, control); 68251cb0ef41Sopenharmony_ci 68261cb0ef41Sopenharmony_ci value = effect = graph()->NewNode(javascript()->CreateIterResultObject(), 68271cb0ef41Sopenharmony_ci value, done, context, effect); 68281cb0ef41Sopenharmony_ci 68291cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 68301cb0ef41Sopenharmony_ci return Replace(value); 68311cb0ef41Sopenharmony_ci} 68321cb0ef41Sopenharmony_ci 68331cb0ef41Sopenharmony_ci// ES #sec-string.prototype.concat 68341cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceStringPrototypeConcat(Node* node) { 68351cb0ef41Sopenharmony_ci JSCallNode n(node); 68361cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 68371cb0ef41Sopenharmony_ci const int parameter_count = n.ArgumentCount(); 68381cb0ef41Sopenharmony_ci if (parameter_count > 1) return NoChange(); 68391cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 68401cb0ef41Sopenharmony_ci return NoChange(); 68411cb0ef41Sopenharmony_ci } 68421cb0ef41Sopenharmony_ci 68431cb0ef41Sopenharmony_ci Effect effect = n.effect(); 68441cb0ef41Sopenharmony_ci Control control = n.control(); 68451cb0ef41Sopenharmony_ci Node* receiver = effect = graph()->NewNode( 68461cb0ef41Sopenharmony_ci simplified()->CheckString(p.feedback()), n.receiver(), effect, control); 68471cb0ef41Sopenharmony_ci 68481cb0ef41Sopenharmony_ci if (parameter_count == 0) { 68491cb0ef41Sopenharmony_ci ReplaceWithValue(node, receiver, effect, control); 68501cb0ef41Sopenharmony_ci return Replace(receiver); 68511cb0ef41Sopenharmony_ci } 68521cb0ef41Sopenharmony_ci 68531cb0ef41Sopenharmony_ci Node* argument = effect = graph()->NewNode( 68541cb0ef41Sopenharmony_ci simplified()->CheckString(p.feedback()), n.Argument(0), effect, control); 68551cb0ef41Sopenharmony_ci Node* receiver_length = 68561cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->StringLength(), receiver); 68571cb0ef41Sopenharmony_ci Node* argument_length = 68581cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->StringLength(), argument); 68591cb0ef41Sopenharmony_ci Node* length = graph()->NewNode(simplified()->NumberAdd(), receiver_length, 68601cb0ef41Sopenharmony_ci argument_length); 68611cb0ef41Sopenharmony_ci length = effect = graph()->NewNode( 68621cb0ef41Sopenharmony_ci simplified()->CheckBounds(p.feedback()), length, 68631cb0ef41Sopenharmony_ci jsgraph()->Constant(String::kMaxLength + 1), effect, control); 68641cb0ef41Sopenharmony_ci 68651cb0ef41Sopenharmony_ci Node* value = graph()->NewNode(simplified()->StringConcat(), length, receiver, 68661cb0ef41Sopenharmony_ci argument); 68671cb0ef41Sopenharmony_ci 68681cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 68691cb0ef41Sopenharmony_ci return Replace(value); 68701cb0ef41Sopenharmony_ci} 68711cb0ef41Sopenharmony_ci 68721cb0ef41Sopenharmony_ciReduction JSCallReducer::ReducePromiseConstructor(Node* node) { 68731cb0ef41Sopenharmony_ci PromiseBuiltinReducerAssembler a(this, node, broker()); 68741cb0ef41Sopenharmony_ci 68751cb0ef41Sopenharmony_ci // We only inline when we have the executor. 68761cb0ef41Sopenharmony_ci if (a.ConstructArity() < 1) return NoChange(); 68771cb0ef41Sopenharmony_ci // Only handle builtins Promises, not subclasses. 68781cb0ef41Sopenharmony_ci if (a.TargetInput() != a.NewTargetInput()) return NoChange(); 68791cb0ef41Sopenharmony_ci if (!dependencies()->DependOnPromiseHookProtector()) return NoChange(); 68801cb0ef41Sopenharmony_ci 68811cb0ef41Sopenharmony_ci TNode<Object> subgraph = a.ReducePromiseConstructor(native_context()); 68821cb0ef41Sopenharmony_ci return ReplaceWithSubgraph(&a, subgraph); 68831cb0ef41Sopenharmony_ci} 68841cb0ef41Sopenharmony_ci 68851cb0ef41Sopenharmony_cibool JSCallReducer::DoPromiseChecks(MapInference* inference) { 68861cb0ef41Sopenharmony_ci if (!inference->HaveMaps()) return false; 68871cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& receiver_maps = inference->GetMaps(); 68881cb0ef41Sopenharmony_ci 68891cb0ef41Sopenharmony_ci // Check whether all {receiver_maps} are JSPromise maps and 68901cb0ef41Sopenharmony_ci // have the initial Promise.prototype as their [[Prototype]]. 68911cb0ef41Sopenharmony_ci for (const MapRef& receiver_map : receiver_maps) { 68921cb0ef41Sopenharmony_ci if (!receiver_map.IsJSPromiseMap()) return false; 68931cb0ef41Sopenharmony_ci HeapObjectRef prototype = receiver_map.prototype(); 68941cb0ef41Sopenharmony_ci if (!prototype.equals(native_context().promise_prototype())) { 68951cb0ef41Sopenharmony_ci return false; 68961cb0ef41Sopenharmony_ci } 68971cb0ef41Sopenharmony_ci } 68981cb0ef41Sopenharmony_ci 68991cb0ef41Sopenharmony_ci return true; 69001cb0ef41Sopenharmony_ci} 69011cb0ef41Sopenharmony_ci 69021cb0ef41Sopenharmony_ci// ES section #sec-promise.prototype.catch 69031cb0ef41Sopenharmony_ciReduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) { 69041cb0ef41Sopenharmony_ci JSCallNode n(node); 69051cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 69061cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 69071cb0ef41Sopenharmony_ci return NoChange(); 69081cb0ef41Sopenharmony_ci } 69091cb0ef41Sopenharmony_ci int arity = p.arity_without_implicit_args(); 69101cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 69111cb0ef41Sopenharmony_ci Effect effect = n.effect(); 69121cb0ef41Sopenharmony_ci Control control = n.control(); 69131cb0ef41Sopenharmony_ci 69141cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 69151cb0ef41Sopenharmony_ci if (!DoPromiseChecks(&inference)) return inference.NoChange(); 69161cb0ef41Sopenharmony_ci 69171cb0ef41Sopenharmony_ci if (!dependencies()->DependOnPromiseThenProtector()) { 69181cb0ef41Sopenharmony_ci return inference.NoChange(); 69191cb0ef41Sopenharmony_ci } 69201cb0ef41Sopenharmony_ci inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect, 69211cb0ef41Sopenharmony_ci control, p.feedback()); 69221cb0ef41Sopenharmony_ci 69231cb0ef41Sopenharmony_ci // Massage the {node} to call "then" instead by first removing all inputs 69241cb0ef41Sopenharmony_ci // following the onRejected parameter, and then filling up the parameters 69251cb0ef41Sopenharmony_ci // to two inputs from the left with undefined. 69261cb0ef41Sopenharmony_ci Node* target = jsgraph()->Constant(native_context().promise_then()); 69271cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInput(node, target, 0); 69281cb0ef41Sopenharmony_ci NodeProperties::ReplaceEffectInput(node, effect); 69291cb0ef41Sopenharmony_ci for (; arity > 1; --arity) node->RemoveInput(3); 69301cb0ef41Sopenharmony_ci for (; arity < 2; ++arity) { 69311cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), 2, jsgraph()->UndefinedConstant()); 69321cb0ef41Sopenharmony_ci } 69331cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 69341cb0ef41Sopenharmony_ci node, javascript()->Call( 69351cb0ef41Sopenharmony_ci JSCallNode::ArityForArgc(arity), p.frequency(), p.feedback(), 69361cb0ef41Sopenharmony_ci ConvertReceiverMode::kNotNullOrUndefined, p.speculation_mode(), 69371cb0ef41Sopenharmony_ci CallFeedbackRelation::kUnrelated)); 69381cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReducePromisePrototypeThen(node)); 69391cb0ef41Sopenharmony_ci} 69401cb0ef41Sopenharmony_ci 69411cb0ef41Sopenharmony_ciNode* JSCallReducer::CreateClosureFromBuiltinSharedFunctionInfo( 69421cb0ef41Sopenharmony_ci SharedFunctionInfoRef shared, Node* context, Node* effect, Node* control) { 69431cb0ef41Sopenharmony_ci DCHECK(shared.HasBuiltinId()); 69441cb0ef41Sopenharmony_ci Handle<FeedbackCell> feedback_cell = 69451cb0ef41Sopenharmony_ci isolate()->factory()->many_closures_cell(); 69461cb0ef41Sopenharmony_ci Callable const callable = 69471cb0ef41Sopenharmony_ci Builtins::CallableFor(isolate(), shared.builtin_id()); 69481cb0ef41Sopenharmony_ci CodeTRef code = MakeRef(broker(), *callable.code()); 69491cb0ef41Sopenharmony_ci return graph()->NewNode(javascript()->CreateClosure(shared, code), 69501cb0ef41Sopenharmony_ci jsgraph()->HeapConstant(feedback_cell), context, 69511cb0ef41Sopenharmony_ci effect, control); 69521cb0ef41Sopenharmony_ci} 69531cb0ef41Sopenharmony_ci 69541cb0ef41Sopenharmony_ci// ES section #sec-promise.prototype.finally 69551cb0ef41Sopenharmony_ciReduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) { 69561cb0ef41Sopenharmony_ci JSCallNode n(node); 69571cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 69581cb0ef41Sopenharmony_ci int arity = p.arity_without_implicit_args(); 69591cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 69601cb0ef41Sopenharmony_ci Node* on_finally = n.ArgumentOrUndefined(0, jsgraph()); 69611cb0ef41Sopenharmony_ci Effect effect = n.effect(); 69621cb0ef41Sopenharmony_ci Control control = n.control(); 69631cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 69641cb0ef41Sopenharmony_ci return NoChange(); 69651cb0ef41Sopenharmony_ci } 69661cb0ef41Sopenharmony_ci 69671cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 69681cb0ef41Sopenharmony_ci if (!DoPromiseChecks(&inference)) return inference.NoChange(); 69691cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& receiver_maps = inference.GetMaps(); 69701cb0ef41Sopenharmony_ci 69711cb0ef41Sopenharmony_ci if (!dependencies()->DependOnPromiseHookProtector()) { 69721cb0ef41Sopenharmony_ci return inference.NoChange(); 69731cb0ef41Sopenharmony_ci } 69741cb0ef41Sopenharmony_ci if (!dependencies()->DependOnPromiseThenProtector()) { 69751cb0ef41Sopenharmony_ci return inference.NoChange(); 69761cb0ef41Sopenharmony_ci } 69771cb0ef41Sopenharmony_ci if (!dependencies()->DependOnPromiseSpeciesProtector()) { 69781cb0ef41Sopenharmony_ci return inference.NoChange(); 69791cb0ef41Sopenharmony_ci } 69801cb0ef41Sopenharmony_ci inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect, 69811cb0ef41Sopenharmony_ci control, p.feedback()); 69821cb0ef41Sopenharmony_ci 69831cb0ef41Sopenharmony_ci // Check if {on_finally} is callable, and if so wrap it into appropriate 69841cb0ef41Sopenharmony_ci // closures that perform the finalization. 69851cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->ObjectIsCallable(), on_finally); 69861cb0ef41Sopenharmony_ci Node* branch = 69871cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); 69881cb0ef41Sopenharmony_ci 69891cb0ef41Sopenharmony_ci Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 69901cb0ef41Sopenharmony_ci Node* etrue = effect; 69911cb0ef41Sopenharmony_ci Node* catch_true; 69921cb0ef41Sopenharmony_ci Node* then_true; 69931cb0ef41Sopenharmony_ci { 69941cb0ef41Sopenharmony_ci Node* context = jsgraph()->Constant(native_context()); 69951cb0ef41Sopenharmony_ci Node* constructor = 69961cb0ef41Sopenharmony_ci jsgraph()->Constant(native_context().promise_function()); 69971cb0ef41Sopenharmony_ci 69981cb0ef41Sopenharmony_ci // Allocate shared context for the closures below. 69991cb0ef41Sopenharmony_ci context = etrue = 70001cb0ef41Sopenharmony_ci graph()->NewNode(javascript()->CreateFunctionContext( 70011cb0ef41Sopenharmony_ci native_context().scope_info(), 70021cb0ef41Sopenharmony_ci PromiseBuiltins::kPromiseFinallyContextLength - 70031cb0ef41Sopenharmony_ci Context::MIN_CONTEXT_SLOTS, 70041cb0ef41Sopenharmony_ci FUNCTION_SCOPE), 70051cb0ef41Sopenharmony_ci context, etrue, if_true); 70061cb0ef41Sopenharmony_ci etrue = graph()->NewNode( 70071cb0ef41Sopenharmony_ci simplified()->StoreField( 70081cb0ef41Sopenharmony_ci AccessBuilder::ForContextSlot(PromiseBuiltins::kOnFinallySlot)), 70091cb0ef41Sopenharmony_ci context, on_finally, etrue, if_true); 70101cb0ef41Sopenharmony_ci etrue = graph()->NewNode( 70111cb0ef41Sopenharmony_ci simplified()->StoreField( 70121cb0ef41Sopenharmony_ci AccessBuilder::ForContextSlot(PromiseBuiltins::kConstructorSlot)), 70131cb0ef41Sopenharmony_ci context, constructor, etrue, if_true); 70141cb0ef41Sopenharmony_ci 70151cb0ef41Sopenharmony_ci // Allocate the closure for the reject case. 70161cb0ef41Sopenharmony_ci SharedFunctionInfoRef promise_catch_finally = 70171cb0ef41Sopenharmony_ci MakeRef(broker(), factory()->promise_catch_finally_shared_fun()); 70181cb0ef41Sopenharmony_ci catch_true = etrue = CreateClosureFromBuiltinSharedFunctionInfo( 70191cb0ef41Sopenharmony_ci promise_catch_finally, context, etrue, if_true); 70201cb0ef41Sopenharmony_ci 70211cb0ef41Sopenharmony_ci // Allocate the closure for the fulfill case. 70221cb0ef41Sopenharmony_ci SharedFunctionInfoRef promise_then_finally = 70231cb0ef41Sopenharmony_ci MakeRef(broker(), factory()->promise_then_finally_shared_fun()); 70241cb0ef41Sopenharmony_ci then_true = etrue = CreateClosureFromBuiltinSharedFunctionInfo( 70251cb0ef41Sopenharmony_ci promise_then_finally, context, etrue, if_true); 70261cb0ef41Sopenharmony_ci } 70271cb0ef41Sopenharmony_ci 70281cb0ef41Sopenharmony_ci Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 70291cb0ef41Sopenharmony_ci Node* efalse = effect; 70301cb0ef41Sopenharmony_ci Node* catch_false = on_finally; 70311cb0ef41Sopenharmony_ci Node* then_false = on_finally; 70321cb0ef41Sopenharmony_ci 70331cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Merge(2), if_true, if_false); 70341cb0ef41Sopenharmony_ci effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); 70351cb0ef41Sopenharmony_ci Node* catch_finally = 70361cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 70371cb0ef41Sopenharmony_ci catch_true, catch_false, control); 70381cb0ef41Sopenharmony_ci Node* then_finally = 70391cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 70401cb0ef41Sopenharmony_ci then_true, then_false, control); 70411cb0ef41Sopenharmony_ci 70421cb0ef41Sopenharmony_ci // At this point we definitely know that {receiver} has one of the 70431cb0ef41Sopenharmony_ci // {receiver_maps}, so insert a MapGuard as a hint for the lowering 70441cb0ef41Sopenharmony_ci // of the call to "then" below. 70451cb0ef41Sopenharmony_ci { 70461cb0ef41Sopenharmony_ci ZoneHandleSet<Map> maps; 70471cb0ef41Sopenharmony_ci for (const MapRef& map : receiver_maps) { 70481cb0ef41Sopenharmony_ci maps.insert(map.object(), graph()->zone()); 70491cb0ef41Sopenharmony_ci } 70501cb0ef41Sopenharmony_ci effect = graph()->NewNode(simplified()->MapGuard(maps), receiver, effect, 70511cb0ef41Sopenharmony_ci control); 70521cb0ef41Sopenharmony_ci } 70531cb0ef41Sopenharmony_ci 70541cb0ef41Sopenharmony_ci // Massage the {node} to call "then" instead by first removing all inputs 70551cb0ef41Sopenharmony_ci // following the onFinally parameter, and then replacing the only parameter 70561cb0ef41Sopenharmony_ci // input with the {on_finally} value. 70571cb0ef41Sopenharmony_ci Node* target = jsgraph()->Constant(native_context().promise_then()); 70581cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInput(node, target, n.TargetIndex()); 70591cb0ef41Sopenharmony_ci NodeProperties::ReplaceEffectInput(node, effect); 70601cb0ef41Sopenharmony_ci NodeProperties::ReplaceControlInput(node, control); 70611cb0ef41Sopenharmony_ci for (; arity > 2; --arity) node->RemoveInput(2); 70621cb0ef41Sopenharmony_ci for (; arity < 2; ++arity) { 70631cb0ef41Sopenharmony_ci node->InsertInput(graph()->zone(), 2, then_finally); 70641cb0ef41Sopenharmony_ci } 70651cb0ef41Sopenharmony_ci node->ReplaceInput(2, then_finally); 70661cb0ef41Sopenharmony_ci node->ReplaceInput(3, catch_finally); 70671cb0ef41Sopenharmony_ci NodeProperties::ChangeOp( 70681cb0ef41Sopenharmony_ci node, javascript()->Call( 70691cb0ef41Sopenharmony_ci JSCallNode::ArityForArgc(arity), p.frequency(), p.feedback(), 70701cb0ef41Sopenharmony_ci ConvertReceiverMode::kNotNullOrUndefined, p.speculation_mode(), 70711cb0ef41Sopenharmony_ci CallFeedbackRelation::kUnrelated)); 70721cb0ef41Sopenharmony_ci return Changed(node).FollowedBy(ReducePromisePrototypeThen(node)); 70731cb0ef41Sopenharmony_ci} 70741cb0ef41Sopenharmony_ci 70751cb0ef41Sopenharmony_ciReduction JSCallReducer::ReducePromisePrototypeThen(Node* node) { 70761cb0ef41Sopenharmony_ci JSCallNode n(node); 70771cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 70781cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 70791cb0ef41Sopenharmony_ci return NoChange(); 70801cb0ef41Sopenharmony_ci } 70811cb0ef41Sopenharmony_ci 70821cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 70831cb0ef41Sopenharmony_ci Node* on_fulfilled = n.ArgumentOrUndefined(0, jsgraph()); 70841cb0ef41Sopenharmony_ci Node* on_rejected = n.ArgumentOrUndefined(1, jsgraph()); 70851cb0ef41Sopenharmony_ci Node* context = n.context(); 70861cb0ef41Sopenharmony_ci Effect effect = n.effect(); 70871cb0ef41Sopenharmony_ci Control control = n.control(); 70881cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 70891cb0ef41Sopenharmony_ci 70901cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 70911cb0ef41Sopenharmony_ci if (!DoPromiseChecks(&inference)) return inference.NoChange(); 70921cb0ef41Sopenharmony_ci 70931cb0ef41Sopenharmony_ci if (!dependencies()->DependOnPromiseHookProtector()) { 70941cb0ef41Sopenharmony_ci return inference.NoChange(); 70951cb0ef41Sopenharmony_ci } 70961cb0ef41Sopenharmony_ci if (!dependencies()->DependOnPromiseSpeciesProtector()) { 70971cb0ef41Sopenharmony_ci return inference.NoChange(); 70981cb0ef41Sopenharmony_ci } 70991cb0ef41Sopenharmony_ci inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect, 71001cb0ef41Sopenharmony_ci control, p.feedback()); 71011cb0ef41Sopenharmony_ci 71021cb0ef41Sopenharmony_ci // Check that {on_fulfilled} is callable. 71031cb0ef41Sopenharmony_ci on_fulfilled = graph()->NewNode( 71041cb0ef41Sopenharmony_ci common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue), 71051cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->ObjectIsCallable(), on_fulfilled), 71061cb0ef41Sopenharmony_ci on_fulfilled, jsgraph()->UndefinedConstant()); 71071cb0ef41Sopenharmony_ci 71081cb0ef41Sopenharmony_ci // Check that {on_rejected} is callable. 71091cb0ef41Sopenharmony_ci on_rejected = graph()->NewNode( 71101cb0ef41Sopenharmony_ci common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue), 71111cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->ObjectIsCallable(), on_rejected), 71121cb0ef41Sopenharmony_ci on_rejected, jsgraph()->UndefinedConstant()); 71131cb0ef41Sopenharmony_ci 71141cb0ef41Sopenharmony_ci // Create the resulting JSPromise. 71151cb0ef41Sopenharmony_ci Node* promise = effect = 71161cb0ef41Sopenharmony_ci graph()->NewNode(javascript()->CreatePromise(), context, effect); 71171cb0ef41Sopenharmony_ci 71181cb0ef41Sopenharmony_ci // Chain {result} onto {receiver}. 71191cb0ef41Sopenharmony_ci promise = effect = graph()->NewNode( 71201cb0ef41Sopenharmony_ci javascript()->PerformPromiseThen(), receiver, on_fulfilled, on_rejected, 71211cb0ef41Sopenharmony_ci promise, context, frame_state, effect, control); 71221cb0ef41Sopenharmony_ci 71231cb0ef41Sopenharmony_ci // At this point we know that {promise} is going to have the 71241cb0ef41Sopenharmony_ci // initial Promise map, since even if {PerformPromiseThen} 71251cb0ef41Sopenharmony_ci // above called into the host rejection tracker, the {promise} 71261cb0ef41Sopenharmony_ci // doesn't escape to user JavaScript. So bake this information 71271cb0ef41Sopenharmony_ci // into the graph such that subsequent passes can use the 71281cb0ef41Sopenharmony_ci // information for further optimizations. 71291cb0ef41Sopenharmony_ci MapRef promise_map = 71301cb0ef41Sopenharmony_ci native_context().promise_function().initial_map(dependencies()); 71311cb0ef41Sopenharmony_ci effect = graph()->NewNode( 71321cb0ef41Sopenharmony_ci simplified()->MapGuard(ZoneHandleSet<Map>(promise_map.object())), promise, 71331cb0ef41Sopenharmony_ci effect, control); 71341cb0ef41Sopenharmony_ci 71351cb0ef41Sopenharmony_ci ReplaceWithValue(node, promise, effect, control); 71361cb0ef41Sopenharmony_ci return Replace(promise); 71371cb0ef41Sopenharmony_ci} 71381cb0ef41Sopenharmony_ci 71391cb0ef41Sopenharmony_ci// ES section #sec-promise.resolve 71401cb0ef41Sopenharmony_ciReduction JSCallReducer::ReducePromiseResolveTrampoline(Node* node) { 71411cb0ef41Sopenharmony_ci JSCallNode n(node); 71421cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 71431cb0ef41Sopenharmony_ci Node* value = n.ArgumentOrUndefined(0, jsgraph()); 71441cb0ef41Sopenharmony_ci Node* context = n.context(); 71451cb0ef41Sopenharmony_ci Effect effect = n.effect(); 71461cb0ef41Sopenharmony_ci Control control = n.control(); 71471cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 71481cb0ef41Sopenharmony_ci 71491cb0ef41Sopenharmony_ci // Only reduce when the receiver is guaranteed to be a JSReceiver. 71501cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 71511cb0ef41Sopenharmony_ci if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAreJSReceiver()) { 71521cb0ef41Sopenharmony_ci return NoChange(); 71531cb0ef41Sopenharmony_ci } 71541cb0ef41Sopenharmony_ci 71551cb0ef41Sopenharmony_ci // Morph the {node} into a JSPromiseResolve operation. 71561cb0ef41Sopenharmony_ci node->ReplaceInput(0, receiver); 71571cb0ef41Sopenharmony_ci node->ReplaceInput(1, value); 71581cb0ef41Sopenharmony_ci node->ReplaceInput(2, context); 71591cb0ef41Sopenharmony_ci node->ReplaceInput(3, frame_state); 71601cb0ef41Sopenharmony_ci node->ReplaceInput(4, effect); 71611cb0ef41Sopenharmony_ci node->ReplaceInput(5, control); 71621cb0ef41Sopenharmony_ci node->TrimInputCount(6); 71631cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, javascript()->PromiseResolve()); 71641cb0ef41Sopenharmony_ci return Changed(node); 71651cb0ef41Sopenharmony_ci} 71661cb0ef41Sopenharmony_ci 71671cb0ef41Sopenharmony_ci// ES #sec-typedarray-constructors 71681cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceTypedArrayConstructor( 71691cb0ef41Sopenharmony_ci Node* node, const SharedFunctionInfoRef& shared) { 71701cb0ef41Sopenharmony_ci JSConstructNode n(node); 71711cb0ef41Sopenharmony_ci ConstructParameters const& p = n.Parameters(); 71721cb0ef41Sopenharmony_ci int arity = p.arity_without_implicit_args(); 71731cb0ef41Sopenharmony_ci Node* target = n.target(); 71741cb0ef41Sopenharmony_ci Node* arg0 = n.ArgumentOrUndefined(0, jsgraph()); 71751cb0ef41Sopenharmony_ci Node* arg1 = n.ArgumentOrUndefined(1, jsgraph()); 71761cb0ef41Sopenharmony_ci Node* arg2 = n.ArgumentOrUndefined(2, jsgraph()); 71771cb0ef41Sopenharmony_ci Node* new_target = n.new_target(); 71781cb0ef41Sopenharmony_ci Node* context = n.context(); 71791cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 71801cb0ef41Sopenharmony_ci Effect effect = n.effect(); 71811cb0ef41Sopenharmony_ci Control control = n.control(); 71821cb0ef41Sopenharmony_ci 71831cb0ef41Sopenharmony_ci // Insert a construct stub frame into the chain of frame states. This will 71841cb0ef41Sopenharmony_ci // reconstruct the proper frame when deoptimizing within the constructor. 71851cb0ef41Sopenharmony_ci frame_state = CreateArtificialFrameState( 71861cb0ef41Sopenharmony_ci node, frame_state, arity, BytecodeOffset::ConstructStubInvoke(), 71871cb0ef41Sopenharmony_ci FrameStateType::kConstructStub, shared, context, common(), graph()); 71881cb0ef41Sopenharmony_ci 71891cb0ef41Sopenharmony_ci // This continuation just returns the newly created JSTypedArray. We 71901cb0ef41Sopenharmony_ci // pass the_hole as the receiver, just like the builtin construct stub 71911cb0ef41Sopenharmony_ci // does in this case. 71921cb0ef41Sopenharmony_ci Node* const parameters[] = {jsgraph()->TheHoleConstant()}; 71931cb0ef41Sopenharmony_ci int const num_parameters = static_cast<int>(arraysize(parameters)); 71941cb0ef41Sopenharmony_ci frame_state = CreateJavaScriptBuiltinContinuationFrameState( 71951cb0ef41Sopenharmony_ci jsgraph(), shared, Builtin::kGenericLazyDeoptContinuation, target, 71961cb0ef41Sopenharmony_ci context, parameters, num_parameters, frame_state, 71971cb0ef41Sopenharmony_ci ContinuationFrameStateMode::LAZY); 71981cb0ef41Sopenharmony_ci 71991cb0ef41Sopenharmony_ci Node* result = 72001cb0ef41Sopenharmony_ci graph()->NewNode(javascript()->CreateTypedArray(), target, new_target, 72011cb0ef41Sopenharmony_ci arg0, arg1, arg2, context, frame_state, effect, control); 72021cb0ef41Sopenharmony_ci return Replace(result); 72031cb0ef41Sopenharmony_ci} 72041cb0ef41Sopenharmony_ci 72051cb0ef41Sopenharmony_ci// ES #sec-get-%typedarray%.prototype-@@tostringtag 72061cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceTypedArrayPrototypeToStringTag(Node* node) { 72071cb0ef41Sopenharmony_ci Node* receiver = NodeProperties::GetValueInput(node, 1); 72081cb0ef41Sopenharmony_ci Node* effect = NodeProperties::GetEffectInput(node); 72091cb0ef41Sopenharmony_ci Node* control = NodeProperties::GetControlInput(node); 72101cb0ef41Sopenharmony_ci 72111cb0ef41Sopenharmony_ci NodeVector values(graph()->zone()); 72121cb0ef41Sopenharmony_ci NodeVector effects(graph()->zone()); 72131cb0ef41Sopenharmony_ci NodeVector controls(graph()->zone()); 72141cb0ef41Sopenharmony_ci 72151cb0ef41Sopenharmony_ci Node* smi_check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); 72161cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Branch(BranchHint::kFalse), smi_check, 72171cb0ef41Sopenharmony_ci control); 72181cb0ef41Sopenharmony_ci 72191cb0ef41Sopenharmony_ci values.push_back(jsgraph()->UndefinedConstant()); 72201cb0ef41Sopenharmony_ci effects.push_back(effect); 72211cb0ef41Sopenharmony_ci controls.push_back(graph()->NewNode(common()->IfTrue(), control)); 72221cb0ef41Sopenharmony_ci 72231cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->IfFalse(), control); 72241cb0ef41Sopenharmony_ci Node* receiver_map = effect = 72251cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), 72261cb0ef41Sopenharmony_ci receiver, effect, control); 72271cb0ef41Sopenharmony_ci Node* receiver_bit_field2 = effect = graph()->NewNode( 72281cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForMapBitField2()), receiver_map, 72291cb0ef41Sopenharmony_ci effect, control); 72301cb0ef41Sopenharmony_ci Node* receiver_elements_kind = graph()->NewNode( 72311cb0ef41Sopenharmony_ci simplified()->NumberShiftRightLogical(), 72321cb0ef41Sopenharmony_ci graph()->NewNode( 72331cb0ef41Sopenharmony_ci simplified()->NumberBitwiseAnd(), receiver_bit_field2, 72341cb0ef41Sopenharmony_ci jsgraph()->Constant(Map::Bits2::ElementsKindBits::kMask)), 72351cb0ef41Sopenharmony_ci jsgraph()->Constant(Map::Bits2::ElementsKindBits::kShift)); 72361cb0ef41Sopenharmony_ci 72371cb0ef41Sopenharmony_ci // Offset the elements kind by FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND, 72381cb0ef41Sopenharmony_ci // so that the branch cascade below is turned into a simple table 72391cb0ef41Sopenharmony_ci // switch by the ControlFlowOptimizer later. 72401cb0ef41Sopenharmony_ci receiver_elements_kind = graph()->NewNode( 72411cb0ef41Sopenharmony_ci simplified()->NumberSubtract(), receiver_elements_kind, 72421cb0ef41Sopenharmony_ci jsgraph()->Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)); 72431cb0ef41Sopenharmony_ci 72441cb0ef41Sopenharmony_ci#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \ 72451cb0ef41Sopenharmony_ci do { \ 72461cb0ef41Sopenharmony_ci Node* check = graph()->NewNode( \ 72471cb0ef41Sopenharmony_ci simplified()->NumberEqual(), receiver_elements_kind, \ 72481cb0ef41Sopenharmony_ci jsgraph()->Constant(TYPE##_ELEMENTS - \ 72491cb0ef41Sopenharmony_ci FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)); \ 72501cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Branch(), check, control); \ 72511cb0ef41Sopenharmony_ci values.push_back(jsgraph()->Constant( \ 72521cb0ef41Sopenharmony_ci broker()->GetTypedArrayStringTag(TYPE##_ELEMENTS))); \ 72531cb0ef41Sopenharmony_ci effects.push_back(effect); \ 72541cb0ef41Sopenharmony_ci controls.push_back(graph()->NewNode(common()->IfTrue(), control)); \ 72551cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->IfFalse(), control); \ 72561cb0ef41Sopenharmony_ci } while (false); 72571cb0ef41Sopenharmony_ci TYPED_ARRAYS(TYPED_ARRAY_CASE) 72581cb0ef41Sopenharmony_ci#undef TYPED_ARRAY_CASE 72591cb0ef41Sopenharmony_ci 72601cb0ef41Sopenharmony_ci values.push_back(jsgraph()->UndefinedConstant()); 72611cb0ef41Sopenharmony_ci effects.push_back(effect); 72621cb0ef41Sopenharmony_ci controls.push_back(control); 72631cb0ef41Sopenharmony_ci 72641cb0ef41Sopenharmony_ci int const count = static_cast<int>(controls.size()); 72651cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Merge(count), count, &controls.front()); 72661cb0ef41Sopenharmony_ci effects.push_back(control); 72671cb0ef41Sopenharmony_ci effect = 72681cb0ef41Sopenharmony_ci graph()->NewNode(common()->EffectPhi(count), count + 1, &effects.front()); 72691cb0ef41Sopenharmony_ci values.push_back(control); 72701cb0ef41Sopenharmony_ci Node* value = 72711cb0ef41Sopenharmony_ci graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, count), 72721cb0ef41Sopenharmony_ci count + 1, &values.front()); 72731cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 72741cb0ef41Sopenharmony_ci return Replace(value); 72751cb0ef41Sopenharmony_ci} 72761cb0ef41Sopenharmony_ci 72771cb0ef41Sopenharmony_ci// ES #sec-number.isfinite 72781cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceNumberIsFinite(Node* node) { 72791cb0ef41Sopenharmony_ci JSCallNode n(node); 72801cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) { 72811cb0ef41Sopenharmony_ci Node* value = jsgraph()->FalseConstant(); 72821cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 72831cb0ef41Sopenharmony_ci return Replace(value); 72841cb0ef41Sopenharmony_ci } 72851cb0ef41Sopenharmony_ci Node* input = n.Argument(0); 72861cb0ef41Sopenharmony_ci Node* value = graph()->NewNode(simplified()->ObjectIsFiniteNumber(), input); 72871cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 72881cb0ef41Sopenharmony_ci return Replace(value); 72891cb0ef41Sopenharmony_ci} 72901cb0ef41Sopenharmony_ci 72911cb0ef41Sopenharmony_ci// ES #sec-number.isfinite 72921cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceNumberIsInteger(Node* node) { 72931cb0ef41Sopenharmony_ci JSCallNode n(node); 72941cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) { 72951cb0ef41Sopenharmony_ci Node* value = jsgraph()->FalseConstant(); 72961cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 72971cb0ef41Sopenharmony_ci return Replace(value); 72981cb0ef41Sopenharmony_ci } 72991cb0ef41Sopenharmony_ci Node* input = n.Argument(0); 73001cb0ef41Sopenharmony_ci Node* value = graph()->NewNode(simplified()->ObjectIsInteger(), input); 73011cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 73021cb0ef41Sopenharmony_ci return Replace(value); 73031cb0ef41Sopenharmony_ci} 73041cb0ef41Sopenharmony_ci 73051cb0ef41Sopenharmony_ci// ES #sec-number.issafeinteger 73061cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceNumberIsSafeInteger(Node* node) { 73071cb0ef41Sopenharmony_ci JSCallNode n(node); 73081cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) { 73091cb0ef41Sopenharmony_ci Node* value = jsgraph()->FalseConstant(); 73101cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 73111cb0ef41Sopenharmony_ci return Replace(value); 73121cb0ef41Sopenharmony_ci } 73131cb0ef41Sopenharmony_ci Node* input = n.Argument(0); 73141cb0ef41Sopenharmony_ci Node* value = graph()->NewNode(simplified()->ObjectIsSafeInteger(), input); 73151cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 73161cb0ef41Sopenharmony_ci return Replace(value); 73171cb0ef41Sopenharmony_ci} 73181cb0ef41Sopenharmony_ci 73191cb0ef41Sopenharmony_ci// ES #sec-number.isnan 73201cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceNumberIsNaN(Node* node) { 73211cb0ef41Sopenharmony_ci JSCallNode n(node); 73221cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) { 73231cb0ef41Sopenharmony_ci Node* value = jsgraph()->FalseConstant(); 73241cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 73251cb0ef41Sopenharmony_ci return Replace(value); 73261cb0ef41Sopenharmony_ci } 73271cb0ef41Sopenharmony_ci Node* input = n.Argument(0); 73281cb0ef41Sopenharmony_ci Node* value = graph()->NewNode(simplified()->ObjectIsNaN(), input); 73291cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 73301cb0ef41Sopenharmony_ci return Replace(value); 73311cb0ef41Sopenharmony_ci} 73321cb0ef41Sopenharmony_ci 73331cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceMapPrototypeGet(Node* node) { 73341cb0ef41Sopenharmony_ci // We only optimize if we have target, receiver and key parameters. 73351cb0ef41Sopenharmony_ci JSCallNode n(node); 73361cb0ef41Sopenharmony_ci if (n.ArgumentCount() != 1) return NoChange(); 73371cb0ef41Sopenharmony_ci Node* receiver = NodeProperties::GetValueInput(node, 1); 73381cb0ef41Sopenharmony_ci Effect effect{NodeProperties::GetEffectInput(node)}; 73391cb0ef41Sopenharmony_ci Control control{NodeProperties::GetControlInput(node)}; 73401cb0ef41Sopenharmony_ci Node* key = NodeProperties::GetValueInput(node, 2); 73411cb0ef41Sopenharmony_ci 73421cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 73431cb0ef41Sopenharmony_ci if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(JS_MAP_TYPE)) { 73441cb0ef41Sopenharmony_ci return NoChange(); 73451cb0ef41Sopenharmony_ci } 73461cb0ef41Sopenharmony_ci 73471cb0ef41Sopenharmony_ci Node* table = effect = graph()->NewNode( 73481cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver, 73491cb0ef41Sopenharmony_ci effect, control); 73501cb0ef41Sopenharmony_ci 73511cb0ef41Sopenharmony_ci Node* entry = effect = graph()->NewNode( 73521cb0ef41Sopenharmony_ci simplified()->FindOrderedHashMapEntry(), table, key, effect, control); 73531cb0ef41Sopenharmony_ci 73541cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->NumberEqual(), entry, 73551cb0ef41Sopenharmony_ci jsgraph()->MinusOneConstant()); 73561cb0ef41Sopenharmony_ci 73571cb0ef41Sopenharmony_ci Node* branch = graph()->NewNode(common()->Branch(), check, control); 73581cb0ef41Sopenharmony_ci 73591cb0ef41Sopenharmony_ci // Key not found. 73601cb0ef41Sopenharmony_ci Node* if_true = graph()->NewNode(common()->IfTrue(), branch); 73611cb0ef41Sopenharmony_ci Node* etrue = effect; 73621cb0ef41Sopenharmony_ci Node* vtrue = jsgraph()->UndefinedConstant(); 73631cb0ef41Sopenharmony_ci 73641cb0ef41Sopenharmony_ci // Key found. 73651cb0ef41Sopenharmony_ci Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 73661cb0ef41Sopenharmony_ci Node* efalse = effect; 73671cb0ef41Sopenharmony_ci Node* vfalse = efalse = graph()->NewNode( 73681cb0ef41Sopenharmony_ci simplified()->LoadElement(AccessBuilder::ForOrderedHashMapEntryValue()), 73691cb0ef41Sopenharmony_ci table, entry, efalse, if_false); 73701cb0ef41Sopenharmony_ci 73711cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->Merge(2), if_true, if_false); 73721cb0ef41Sopenharmony_ci Node* value = graph()->NewNode( 73731cb0ef41Sopenharmony_ci common()->Phi(MachineRepresentation::kTagged, 2), vtrue, vfalse, control); 73741cb0ef41Sopenharmony_ci effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); 73751cb0ef41Sopenharmony_ci 73761cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 73771cb0ef41Sopenharmony_ci return Replace(value); 73781cb0ef41Sopenharmony_ci} 73791cb0ef41Sopenharmony_ci 73801cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceMapPrototypeHas(Node* node) { 73811cb0ef41Sopenharmony_ci // We only optimize if we have target, receiver and key parameters. 73821cb0ef41Sopenharmony_ci JSCallNode n(node); 73831cb0ef41Sopenharmony_ci if (n.ArgumentCount() != 1) return NoChange(); 73841cb0ef41Sopenharmony_ci Node* receiver = NodeProperties::GetValueInput(node, 1); 73851cb0ef41Sopenharmony_ci Effect effect{NodeProperties::GetEffectInput(node)}; 73861cb0ef41Sopenharmony_ci Control control{NodeProperties::GetControlInput(node)}; 73871cb0ef41Sopenharmony_ci Node* key = NodeProperties::GetValueInput(node, 2); 73881cb0ef41Sopenharmony_ci 73891cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 73901cb0ef41Sopenharmony_ci if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(JS_MAP_TYPE)) { 73911cb0ef41Sopenharmony_ci return NoChange(); 73921cb0ef41Sopenharmony_ci } 73931cb0ef41Sopenharmony_ci 73941cb0ef41Sopenharmony_ci Node* table = effect = graph()->NewNode( 73951cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver, 73961cb0ef41Sopenharmony_ci effect, control); 73971cb0ef41Sopenharmony_ci 73981cb0ef41Sopenharmony_ci Node* index = effect = graph()->NewNode( 73991cb0ef41Sopenharmony_ci simplified()->FindOrderedHashMapEntry(), table, key, effect, control); 74001cb0ef41Sopenharmony_ci 74011cb0ef41Sopenharmony_ci Node* value = graph()->NewNode(simplified()->NumberEqual(), index, 74021cb0ef41Sopenharmony_ci jsgraph()->MinusOneConstant()); 74031cb0ef41Sopenharmony_ci value = graph()->NewNode(simplified()->BooleanNot(), value); 74041cb0ef41Sopenharmony_ci 74051cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 74061cb0ef41Sopenharmony_ci return Replace(value); 74071cb0ef41Sopenharmony_ci} 74081cb0ef41Sopenharmony_ci 74091cb0ef41Sopenharmony_cinamespace { 74101cb0ef41Sopenharmony_ci 74111cb0ef41Sopenharmony_ciInstanceType InstanceTypeForCollectionKind(CollectionKind kind) { 74121cb0ef41Sopenharmony_ci switch (kind) { 74131cb0ef41Sopenharmony_ci case CollectionKind::kMap: 74141cb0ef41Sopenharmony_ci return JS_MAP_TYPE; 74151cb0ef41Sopenharmony_ci case CollectionKind::kSet: 74161cb0ef41Sopenharmony_ci return JS_SET_TYPE; 74171cb0ef41Sopenharmony_ci } 74181cb0ef41Sopenharmony_ci UNREACHABLE(); 74191cb0ef41Sopenharmony_ci} 74201cb0ef41Sopenharmony_ci 74211cb0ef41Sopenharmony_ci} // namespace 74221cb0ef41Sopenharmony_ci 74231cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceCollectionIteration( 74241cb0ef41Sopenharmony_ci Node* node, CollectionKind collection_kind, IterationKind iteration_kind) { 74251cb0ef41Sopenharmony_ci DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); 74261cb0ef41Sopenharmony_ci Node* receiver = NodeProperties::GetValueInput(node, 1); 74271cb0ef41Sopenharmony_ci Node* context = NodeProperties::GetContextInput(node); 74281cb0ef41Sopenharmony_ci Effect effect{NodeProperties::GetEffectInput(node)}; 74291cb0ef41Sopenharmony_ci Control control{NodeProperties::GetControlInput(node)}; 74301cb0ef41Sopenharmony_ci 74311cb0ef41Sopenharmony_ci InstanceType type = InstanceTypeForCollectionKind(collection_kind); 74321cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 74331cb0ef41Sopenharmony_ci if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(type)) { 74341cb0ef41Sopenharmony_ci return NoChange(); 74351cb0ef41Sopenharmony_ci } 74361cb0ef41Sopenharmony_ci 74371cb0ef41Sopenharmony_ci Node* js_create_iterator = effect = graph()->NewNode( 74381cb0ef41Sopenharmony_ci javascript()->CreateCollectionIterator(collection_kind, iteration_kind), 74391cb0ef41Sopenharmony_ci receiver, context, effect, control); 74401cb0ef41Sopenharmony_ci ReplaceWithValue(node, js_create_iterator, effect); 74411cb0ef41Sopenharmony_ci return Replace(js_create_iterator); 74421cb0ef41Sopenharmony_ci} 74431cb0ef41Sopenharmony_ci 74441cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceCollectionPrototypeSize( 74451cb0ef41Sopenharmony_ci Node* node, CollectionKind collection_kind) { 74461cb0ef41Sopenharmony_ci DCHECK_EQ(IrOpcode::kJSCall, node->opcode()); 74471cb0ef41Sopenharmony_ci Node* receiver = NodeProperties::GetValueInput(node, 1); 74481cb0ef41Sopenharmony_ci Effect effect{NodeProperties::GetEffectInput(node)}; 74491cb0ef41Sopenharmony_ci Control control{NodeProperties::GetControlInput(node)}; 74501cb0ef41Sopenharmony_ci 74511cb0ef41Sopenharmony_ci InstanceType type = InstanceTypeForCollectionKind(collection_kind); 74521cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 74531cb0ef41Sopenharmony_ci if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(type)) { 74541cb0ef41Sopenharmony_ci return NoChange(); 74551cb0ef41Sopenharmony_ci } 74561cb0ef41Sopenharmony_ci 74571cb0ef41Sopenharmony_ci Node* table = effect = graph()->NewNode( 74581cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver, 74591cb0ef41Sopenharmony_ci effect, control); 74601cb0ef41Sopenharmony_ci Node* value = effect = graph()->NewNode( 74611cb0ef41Sopenharmony_ci simplified()->LoadField( 74621cb0ef41Sopenharmony_ci AccessBuilder::ForOrderedHashMapOrSetNumberOfElements()), 74631cb0ef41Sopenharmony_ci table, effect, control); 74641cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 74651cb0ef41Sopenharmony_ci return Replace(value); 74661cb0ef41Sopenharmony_ci} 74671cb0ef41Sopenharmony_ci 74681cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceCollectionIteratorPrototypeNext( 74691cb0ef41Sopenharmony_ci Node* node, int entry_size, Handle<HeapObject> empty_collection, 74701cb0ef41Sopenharmony_ci InstanceType collection_iterator_instance_type_first, 74711cb0ef41Sopenharmony_ci InstanceType collection_iterator_instance_type_last) { 74721cb0ef41Sopenharmony_ci JSCallNode n(node); 74731cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 74741cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 74751cb0ef41Sopenharmony_ci return NoChange(); 74761cb0ef41Sopenharmony_ci } 74771cb0ef41Sopenharmony_ci 74781cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 74791cb0ef41Sopenharmony_ci Node* context = n.context(); 74801cb0ef41Sopenharmony_ci Effect effect = n.effect(); 74811cb0ef41Sopenharmony_ci Control control = n.control(); 74821cb0ef41Sopenharmony_ci 74831cb0ef41Sopenharmony_ci // A word of warning to begin with: This whole method might look a bit 74841cb0ef41Sopenharmony_ci // strange at times, but that's mostly because it was carefully handcrafted 74851cb0ef41Sopenharmony_ci // to allow for full escape analysis and scalar replacement of both the 74861cb0ef41Sopenharmony_ci // collection iterator object and the iterator results, including the 74871cb0ef41Sopenharmony_ci // key-value arrays in case of Set/Map entry iteration. 74881cb0ef41Sopenharmony_ci // 74891cb0ef41Sopenharmony_ci // TODO(turbofan): Currently the escape analysis (and the store-load 74901cb0ef41Sopenharmony_ci // forwarding) is unable to eliminate the allocations for the key-value 74911cb0ef41Sopenharmony_ci // arrays in case of Set/Map entry iteration, and we should investigate 74921cb0ef41Sopenharmony_ci // how to update the escape analysis / arrange the graph in a way that 74931cb0ef41Sopenharmony_ci // this becomes possible. 74941cb0ef41Sopenharmony_ci 74951cb0ef41Sopenharmony_ci InstanceType receiver_instance_type; 74961cb0ef41Sopenharmony_ci { 74971cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 74981cb0ef41Sopenharmony_ci if (!inference.HaveMaps()) return NoChange(); 74991cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& receiver_maps = inference.GetMaps(); 75001cb0ef41Sopenharmony_ci receiver_instance_type = receiver_maps[0].instance_type(); 75011cb0ef41Sopenharmony_ci for (size_t i = 1; i < receiver_maps.size(); ++i) { 75021cb0ef41Sopenharmony_ci if (receiver_maps[i].instance_type() != receiver_instance_type) { 75031cb0ef41Sopenharmony_ci return inference.NoChange(); 75041cb0ef41Sopenharmony_ci } 75051cb0ef41Sopenharmony_ci } 75061cb0ef41Sopenharmony_ci if (receiver_instance_type < collection_iterator_instance_type_first || 75071cb0ef41Sopenharmony_ci receiver_instance_type > collection_iterator_instance_type_last) { 75081cb0ef41Sopenharmony_ci return inference.NoChange(); 75091cb0ef41Sopenharmony_ci } 75101cb0ef41Sopenharmony_ci inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect, 75111cb0ef41Sopenharmony_ci control, p.feedback()); 75121cb0ef41Sopenharmony_ci } 75131cb0ef41Sopenharmony_ci 75141cb0ef41Sopenharmony_ci // Transition the JSCollectionIterator {receiver} if necessary 75151cb0ef41Sopenharmony_ci // (i.e. there were certain mutations while we're iterating). 75161cb0ef41Sopenharmony_ci { 75171cb0ef41Sopenharmony_ci Node* done_loop; 75181cb0ef41Sopenharmony_ci Node* done_eloop; 75191cb0ef41Sopenharmony_ci Node* loop = control = 75201cb0ef41Sopenharmony_ci graph()->NewNode(common()->Loop(2), control, control); 75211cb0ef41Sopenharmony_ci Node* eloop = effect = 75221cb0ef41Sopenharmony_ci graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); 75231cb0ef41Sopenharmony_ci Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop); 75241cb0ef41Sopenharmony_ci NodeProperties::MergeControlToEnd(graph(), common(), terminate); 75251cb0ef41Sopenharmony_ci 75261cb0ef41Sopenharmony_ci // Check if reached the final table of the {receiver}. 75271cb0ef41Sopenharmony_ci Node* table = effect = graph()->NewNode( 75281cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorTable()), 75291cb0ef41Sopenharmony_ci receiver, effect, control); 75301cb0ef41Sopenharmony_ci Node* next_table = effect = 75311cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->LoadField( 75321cb0ef41Sopenharmony_ci AccessBuilder::ForOrderedHashMapOrSetNextTable()), 75331cb0ef41Sopenharmony_ci table, effect, control); 75341cb0ef41Sopenharmony_ci Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), next_table); 75351cb0ef41Sopenharmony_ci control = 75361cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); 75371cb0ef41Sopenharmony_ci 75381cb0ef41Sopenharmony_ci // Abort the {loop} when we reach the final table. 75391cb0ef41Sopenharmony_ci done_loop = graph()->NewNode(common()->IfTrue(), control); 75401cb0ef41Sopenharmony_ci done_eloop = effect; 75411cb0ef41Sopenharmony_ci 75421cb0ef41Sopenharmony_ci // Migrate to the {next_table} otherwise. 75431cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->IfFalse(), control); 75441cb0ef41Sopenharmony_ci 75451cb0ef41Sopenharmony_ci // Self-heal the {receiver}s index. 75461cb0ef41Sopenharmony_ci Node* index = effect = graph()->NewNode( 75471cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorIndex()), 75481cb0ef41Sopenharmony_ci receiver, effect, control); 75491cb0ef41Sopenharmony_ci Callable const callable = 75501cb0ef41Sopenharmony_ci Builtins::CallableFor(isolate(), Builtin::kOrderedHashTableHealIndex); 75511cb0ef41Sopenharmony_ci auto call_descriptor = Linkage::GetStubCallDescriptor( 75521cb0ef41Sopenharmony_ci graph()->zone(), callable.descriptor(), 75531cb0ef41Sopenharmony_ci callable.descriptor().GetStackParameterCount(), 75541cb0ef41Sopenharmony_ci CallDescriptor::kNoFlags, Operator::kEliminatable); 75551cb0ef41Sopenharmony_ci index = effect = 75561cb0ef41Sopenharmony_ci graph()->NewNode(common()->Call(call_descriptor), 75571cb0ef41Sopenharmony_ci jsgraph()->HeapConstant(callable.code()), table, index, 75581cb0ef41Sopenharmony_ci jsgraph()->NoContextConstant(), effect); 75591cb0ef41Sopenharmony_ci 75601cb0ef41Sopenharmony_ci index = effect = graph()->NewNode( 75611cb0ef41Sopenharmony_ci common()->TypeGuard(TypeCache::Get()->kFixedArrayLengthType), index, 75621cb0ef41Sopenharmony_ci effect, control); 75631cb0ef41Sopenharmony_ci 75641cb0ef41Sopenharmony_ci // Update the {index} and {table} on the {receiver}. 75651cb0ef41Sopenharmony_ci effect = graph()->NewNode( 75661cb0ef41Sopenharmony_ci simplified()->StoreField(AccessBuilder::ForJSCollectionIteratorIndex()), 75671cb0ef41Sopenharmony_ci receiver, index, effect, control); 75681cb0ef41Sopenharmony_ci effect = graph()->NewNode( 75691cb0ef41Sopenharmony_ci simplified()->StoreField(AccessBuilder::ForJSCollectionIteratorTable()), 75701cb0ef41Sopenharmony_ci receiver, next_table, effect, control); 75711cb0ef41Sopenharmony_ci 75721cb0ef41Sopenharmony_ci // Tie the knot. 75731cb0ef41Sopenharmony_ci loop->ReplaceInput(1, control); 75741cb0ef41Sopenharmony_ci eloop->ReplaceInput(1, effect); 75751cb0ef41Sopenharmony_ci 75761cb0ef41Sopenharmony_ci control = done_loop; 75771cb0ef41Sopenharmony_ci effect = done_eloop; 75781cb0ef41Sopenharmony_ci } 75791cb0ef41Sopenharmony_ci 75801cb0ef41Sopenharmony_ci // Get current index and table from the JSCollectionIterator {receiver}. 75811cb0ef41Sopenharmony_ci Node* index = effect = graph()->NewNode( 75821cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorIndex()), 75831cb0ef41Sopenharmony_ci receiver, effect, control); 75841cb0ef41Sopenharmony_ci Node* table = effect = graph()->NewNode( 75851cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSCollectionIteratorTable()), 75861cb0ef41Sopenharmony_ci receiver, effect, control); 75871cb0ef41Sopenharmony_ci 75881cb0ef41Sopenharmony_ci // Create the {JSIteratorResult} first to ensure that we always have 75891cb0ef41Sopenharmony_ci // a dominating Allocate node for the allocation folding phase. 75901cb0ef41Sopenharmony_ci Node* iterator_result = effect = graph()->NewNode( 75911cb0ef41Sopenharmony_ci javascript()->CreateIterResultObject(), jsgraph()->UndefinedConstant(), 75921cb0ef41Sopenharmony_ci jsgraph()->TrueConstant(), context, effect); 75931cb0ef41Sopenharmony_ci 75941cb0ef41Sopenharmony_ci // Look for the next non-holey key, starting from {index} in the {table}. 75951cb0ef41Sopenharmony_ci Node* controls[2]; 75961cb0ef41Sopenharmony_ci Node* effects[3]; 75971cb0ef41Sopenharmony_ci { 75981cb0ef41Sopenharmony_ci // Compute the currently used capacity. 75991cb0ef41Sopenharmony_ci Node* number_of_buckets = effect = graph()->NewNode( 76001cb0ef41Sopenharmony_ci simplified()->LoadField( 76011cb0ef41Sopenharmony_ci AccessBuilder::ForOrderedHashMapOrSetNumberOfBuckets()), 76021cb0ef41Sopenharmony_ci table, effect, control); 76031cb0ef41Sopenharmony_ci Node* number_of_elements = effect = graph()->NewNode( 76041cb0ef41Sopenharmony_ci simplified()->LoadField( 76051cb0ef41Sopenharmony_ci AccessBuilder::ForOrderedHashMapOrSetNumberOfElements()), 76061cb0ef41Sopenharmony_ci table, effect, control); 76071cb0ef41Sopenharmony_ci Node* number_of_deleted_elements = effect = graph()->NewNode( 76081cb0ef41Sopenharmony_ci simplified()->LoadField( 76091cb0ef41Sopenharmony_ci AccessBuilder::ForOrderedHashMapOrSetNumberOfDeletedElements()), 76101cb0ef41Sopenharmony_ci table, effect, control); 76111cb0ef41Sopenharmony_ci Node* used_capacity = 76121cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberAdd(), number_of_elements, 76131cb0ef41Sopenharmony_ci number_of_deleted_elements); 76141cb0ef41Sopenharmony_ci 76151cb0ef41Sopenharmony_ci // Skip holes and update the {index}. 76161cb0ef41Sopenharmony_ci Node* loop = graph()->NewNode(common()->Loop(2), control, control); 76171cb0ef41Sopenharmony_ci Node* eloop = 76181cb0ef41Sopenharmony_ci graph()->NewNode(common()->EffectPhi(2), effect, effect, loop); 76191cb0ef41Sopenharmony_ci Node* terminate = graph()->NewNode(common()->Terminate(), eloop, loop); 76201cb0ef41Sopenharmony_ci NodeProperties::MergeControlToEnd(graph(), common(), terminate); 76211cb0ef41Sopenharmony_ci Node* iloop = graph()->NewNode( 76221cb0ef41Sopenharmony_ci common()->Phi(MachineRepresentation::kTagged, 2), index, index, loop); 76231cb0ef41Sopenharmony_ci 76241cb0ef41Sopenharmony_ci index = effect = graph()->NewNode( 76251cb0ef41Sopenharmony_ci common()->TypeGuard(TypeCache::Get()->kFixedArrayLengthType), iloop, 76261cb0ef41Sopenharmony_ci eloop, control); 76271cb0ef41Sopenharmony_ci { 76281cb0ef41Sopenharmony_ci Node* check0 = graph()->NewNode(simplified()->NumberLessThan(), index, 76291cb0ef41Sopenharmony_ci used_capacity); 76301cb0ef41Sopenharmony_ci Node* branch0 = 76311cb0ef41Sopenharmony_ci graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, loop); 76321cb0ef41Sopenharmony_ci 76331cb0ef41Sopenharmony_ci Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0); 76341cb0ef41Sopenharmony_ci Node* efalse0 = effect; 76351cb0ef41Sopenharmony_ci { 76361cb0ef41Sopenharmony_ci // Mark the {receiver} as exhausted. 76371cb0ef41Sopenharmony_ci efalse0 = graph()->NewNode( 76381cb0ef41Sopenharmony_ci simplified()->StoreField( 76391cb0ef41Sopenharmony_ci AccessBuilder::ForJSCollectionIteratorTable()), 76401cb0ef41Sopenharmony_ci receiver, jsgraph()->HeapConstant(empty_collection), efalse0, 76411cb0ef41Sopenharmony_ci if_false0); 76421cb0ef41Sopenharmony_ci 76431cb0ef41Sopenharmony_ci controls[0] = if_false0; 76441cb0ef41Sopenharmony_ci effects[0] = efalse0; 76451cb0ef41Sopenharmony_ci } 76461cb0ef41Sopenharmony_ci 76471cb0ef41Sopenharmony_ci Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0); 76481cb0ef41Sopenharmony_ci Node* etrue0 = effect; 76491cb0ef41Sopenharmony_ci { 76501cb0ef41Sopenharmony_ci // Load the key of the entry. 76511cb0ef41Sopenharmony_ci STATIC_ASSERT(OrderedHashMap::HashTableStartIndex() == 76521cb0ef41Sopenharmony_ci OrderedHashSet::HashTableStartIndex()); 76531cb0ef41Sopenharmony_ci Node* entry_start_position = graph()->NewNode( 76541cb0ef41Sopenharmony_ci simplified()->NumberAdd(), 76551cb0ef41Sopenharmony_ci graph()->NewNode( 76561cb0ef41Sopenharmony_ci simplified()->NumberAdd(), 76571cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberMultiply(), index, 76581cb0ef41Sopenharmony_ci jsgraph()->Constant(entry_size)), 76591cb0ef41Sopenharmony_ci number_of_buckets), 76601cb0ef41Sopenharmony_ci jsgraph()->Constant(OrderedHashMap::HashTableStartIndex())); 76611cb0ef41Sopenharmony_ci Node* entry_key = etrue0 = graph()->NewNode( 76621cb0ef41Sopenharmony_ci simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), 76631cb0ef41Sopenharmony_ci table, entry_start_position, etrue0, if_true0); 76641cb0ef41Sopenharmony_ci 76651cb0ef41Sopenharmony_ci // Advance the index. 76661cb0ef41Sopenharmony_ci index = graph()->NewNode(simplified()->NumberAdd(), index, 76671cb0ef41Sopenharmony_ci jsgraph()->OneConstant()); 76681cb0ef41Sopenharmony_ci 76691cb0ef41Sopenharmony_ci Node* check1 = 76701cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->ReferenceEqual(), entry_key, 76711cb0ef41Sopenharmony_ci jsgraph()->TheHoleConstant()); 76721cb0ef41Sopenharmony_ci Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse), 76731cb0ef41Sopenharmony_ci check1, if_true0); 76741cb0ef41Sopenharmony_ci 76751cb0ef41Sopenharmony_ci { 76761cb0ef41Sopenharmony_ci // Abort loop with resulting value. 76771cb0ef41Sopenharmony_ci control = graph()->NewNode(common()->IfFalse(), branch1); 76781cb0ef41Sopenharmony_ci effect = etrue0; 76791cb0ef41Sopenharmony_ci Node* value = effect = 76801cb0ef41Sopenharmony_ci graph()->NewNode(common()->TypeGuard(Type::NonInternal()), 76811cb0ef41Sopenharmony_ci entry_key, effect, control); 76821cb0ef41Sopenharmony_ci Node* done = jsgraph()->FalseConstant(); 76831cb0ef41Sopenharmony_ci 76841cb0ef41Sopenharmony_ci // Advance the index on the {receiver}. 76851cb0ef41Sopenharmony_ci effect = graph()->NewNode( 76861cb0ef41Sopenharmony_ci simplified()->StoreField( 76871cb0ef41Sopenharmony_ci AccessBuilder::ForJSCollectionIteratorIndex()), 76881cb0ef41Sopenharmony_ci receiver, index, effect, control); 76891cb0ef41Sopenharmony_ci 76901cb0ef41Sopenharmony_ci // The actual {value} depends on the {receiver} iteration type. 76911cb0ef41Sopenharmony_ci switch (receiver_instance_type) { 76921cb0ef41Sopenharmony_ci case JS_MAP_KEY_ITERATOR_TYPE: 76931cb0ef41Sopenharmony_ci case JS_SET_VALUE_ITERATOR_TYPE: 76941cb0ef41Sopenharmony_ci break; 76951cb0ef41Sopenharmony_ci 76961cb0ef41Sopenharmony_ci case JS_SET_KEY_VALUE_ITERATOR_TYPE: 76971cb0ef41Sopenharmony_ci value = effect = 76981cb0ef41Sopenharmony_ci graph()->NewNode(javascript()->CreateKeyValueArray(), value, 76991cb0ef41Sopenharmony_ci value, context, effect); 77001cb0ef41Sopenharmony_ci break; 77011cb0ef41Sopenharmony_ci 77021cb0ef41Sopenharmony_ci case JS_MAP_VALUE_ITERATOR_TYPE: 77031cb0ef41Sopenharmony_ci value = effect = graph()->NewNode( 77041cb0ef41Sopenharmony_ci simplified()->LoadElement( 77051cb0ef41Sopenharmony_ci AccessBuilder::ForFixedArrayElement()), 77061cb0ef41Sopenharmony_ci table, 77071cb0ef41Sopenharmony_ci graph()->NewNode( 77081cb0ef41Sopenharmony_ci simplified()->NumberAdd(), entry_start_position, 77091cb0ef41Sopenharmony_ci jsgraph()->Constant(OrderedHashMap::kValueOffset)), 77101cb0ef41Sopenharmony_ci effect, control); 77111cb0ef41Sopenharmony_ci break; 77121cb0ef41Sopenharmony_ci 77131cb0ef41Sopenharmony_ci case JS_MAP_KEY_VALUE_ITERATOR_TYPE: 77141cb0ef41Sopenharmony_ci value = effect = graph()->NewNode( 77151cb0ef41Sopenharmony_ci simplified()->LoadElement( 77161cb0ef41Sopenharmony_ci AccessBuilder::ForFixedArrayElement()), 77171cb0ef41Sopenharmony_ci table, 77181cb0ef41Sopenharmony_ci graph()->NewNode( 77191cb0ef41Sopenharmony_ci simplified()->NumberAdd(), entry_start_position, 77201cb0ef41Sopenharmony_ci jsgraph()->Constant(OrderedHashMap::kValueOffset)), 77211cb0ef41Sopenharmony_ci effect, control); 77221cb0ef41Sopenharmony_ci value = effect = 77231cb0ef41Sopenharmony_ci graph()->NewNode(javascript()->CreateKeyValueArray(), 77241cb0ef41Sopenharmony_ci entry_key, value, context, effect); 77251cb0ef41Sopenharmony_ci break; 77261cb0ef41Sopenharmony_ci 77271cb0ef41Sopenharmony_ci default: 77281cb0ef41Sopenharmony_ci UNREACHABLE(); 77291cb0ef41Sopenharmony_ci } 77301cb0ef41Sopenharmony_ci 77311cb0ef41Sopenharmony_ci // Store final {value} and {done} into the {iterator_result}. 77321cb0ef41Sopenharmony_ci effect = 77331cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->StoreField( 77341cb0ef41Sopenharmony_ci AccessBuilder::ForJSIteratorResultValue()), 77351cb0ef41Sopenharmony_ci iterator_result, value, effect, control); 77361cb0ef41Sopenharmony_ci effect = 77371cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->StoreField( 77381cb0ef41Sopenharmony_ci AccessBuilder::ForJSIteratorResultDone()), 77391cb0ef41Sopenharmony_ci iterator_result, done, effect, control); 77401cb0ef41Sopenharmony_ci 77411cb0ef41Sopenharmony_ci controls[1] = control; 77421cb0ef41Sopenharmony_ci effects[1] = effect; 77431cb0ef41Sopenharmony_ci } 77441cb0ef41Sopenharmony_ci 77451cb0ef41Sopenharmony_ci // Continue with next loop index. 77461cb0ef41Sopenharmony_ci loop->ReplaceInput(1, graph()->NewNode(common()->IfTrue(), branch1)); 77471cb0ef41Sopenharmony_ci eloop->ReplaceInput(1, etrue0); 77481cb0ef41Sopenharmony_ci iloop->ReplaceInput(1, index); 77491cb0ef41Sopenharmony_ci } 77501cb0ef41Sopenharmony_ci } 77511cb0ef41Sopenharmony_ci 77521cb0ef41Sopenharmony_ci control = effects[2] = graph()->NewNode(common()->Merge(2), 2, controls); 77531cb0ef41Sopenharmony_ci effect = graph()->NewNode(common()->EffectPhi(2), 3, effects); 77541cb0ef41Sopenharmony_ci } 77551cb0ef41Sopenharmony_ci 77561cb0ef41Sopenharmony_ci // Yield the final {iterator_result}. 77571cb0ef41Sopenharmony_ci ReplaceWithValue(node, iterator_result, effect, control); 77581cb0ef41Sopenharmony_ci return Replace(iterator_result); 77591cb0ef41Sopenharmony_ci} 77601cb0ef41Sopenharmony_ci 77611cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayBufferIsView(Node* node) { 77621cb0ef41Sopenharmony_ci JSCallNode n(node); 77631cb0ef41Sopenharmony_ci Node* value = n.ArgumentOrUndefined(0, jsgraph()); 77641cb0ef41Sopenharmony_ci RelaxEffectsAndControls(node); 77651cb0ef41Sopenharmony_ci node->ReplaceInput(0, value); 77661cb0ef41Sopenharmony_ci node->TrimInputCount(1); 77671cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, simplified()->ObjectIsArrayBufferView()); 77681cb0ef41Sopenharmony_ci return Changed(node); 77691cb0ef41Sopenharmony_ci} 77701cb0ef41Sopenharmony_ci 77711cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceArrayBufferViewAccessor( 77721cb0ef41Sopenharmony_ci Node* node, InstanceType instance_type, FieldAccess const& access) { 77731cb0ef41Sopenharmony_ci Node* receiver = NodeProperties::GetValueInput(node, 1); 77741cb0ef41Sopenharmony_ci Effect effect{NodeProperties::GetEffectInput(node)}; 77751cb0ef41Sopenharmony_ci Control control{NodeProperties::GetControlInput(node)}; 77761cb0ef41Sopenharmony_ci 77771cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 77781cb0ef41Sopenharmony_ci if (!inference.HaveMaps() || 77791cb0ef41Sopenharmony_ci !inference.AllOfInstanceTypesAre(instance_type)) { 77801cb0ef41Sopenharmony_ci return NoChange(); 77811cb0ef41Sopenharmony_ci } 77821cb0ef41Sopenharmony_ci 77831cb0ef41Sopenharmony_ci // Load the {receiver}s field. 77841cb0ef41Sopenharmony_ci Node* value = effect = graph()->NewNode(simplified()->LoadField(access), 77851cb0ef41Sopenharmony_ci receiver, effect, control); 77861cb0ef41Sopenharmony_ci 77871cb0ef41Sopenharmony_ci // See if we can skip the detaching check. 77881cb0ef41Sopenharmony_ci if (!dependencies()->DependOnArrayBufferDetachingProtector()) { 77891cb0ef41Sopenharmony_ci // Check whether {receiver}s JSArrayBuffer was detached. 77901cb0ef41Sopenharmony_ci Node* buffer = effect = graph()->NewNode( 77911cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), 77921cb0ef41Sopenharmony_ci receiver, effect, control); 77931cb0ef41Sopenharmony_ci Node* buffer_bit_field = effect = graph()->NewNode( 77941cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()), 77951cb0ef41Sopenharmony_ci buffer, effect, control); 77961cb0ef41Sopenharmony_ci Node* check = graph()->NewNode( 77971cb0ef41Sopenharmony_ci simplified()->NumberEqual(), 77981cb0ef41Sopenharmony_ci graph()->NewNode( 77991cb0ef41Sopenharmony_ci simplified()->NumberBitwiseAnd(), buffer_bit_field, 78001cb0ef41Sopenharmony_ci jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)), 78011cb0ef41Sopenharmony_ci jsgraph()->ZeroConstant()); 78021cb0ef41Sopenharmony_ci 78031cb0ef41Sopenharmony_ci // TODO(turbofan): Ideally we would bail out here if the {receiver}s 78041cb0ef41Sopenharmony_ci // JSArrayBuffer was detached, but there's no way to guard against 78051cb0ef41Sopenharmony_ci // deoptimization loops right now, since the JSCall {node} is usually 78061cb0ef41Sopenharmony_ci // created from a LOAD_IC inlining, and so there's no CALL_IC slot 78071cb0ef41Sopenharmony_ci // from which we could use the speculation bit. 78081cb0ef41Sopenharmony_ci value = graph()->NewNode( 78091cb0ef41Sopenharmony_ci common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue), 78101cb0ef41Sopenharmony_ci check, value, jsgraph()->ZeroConstant()); 78111cb0ef41Sopenharmony_ci } 78121cb0ef41Sopenharmony_ci 78131cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 78141cb0ef41Sopenharmony_ci return Replace(value); 78151cb0ef41Sopenharmony_ci} 78161cb0ef41Sopenharmony_ci 78171cb0ef41Sopenharmony_cinamespace { 78181cb0ef41Sopenharmony_ciuint32_t ExternalArrayElementSize(const ExternalArrayType element_type) { 78191cb0ef41Sopenharmony_ci switch (element_type) { 78201cb0ef41Sopenharmony_ci#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype) \ 78211cb0ef41Sopenharmony_ci case kExternal##Type##Array: \ 78221cb0ef41Sopenharmony_ci DCHECK_LE(sizeof(ctype), 8); \ 78231cb0ef41Sopenharmony_ci return sizeof(ctype); 78241cb0ef41Sopenharmony_ci TYPED_ARRAYS(TYPED_ARRAY_CASE) 78251cb0ef41Sopenharmony_ci default: 78261cb0ef41Sopenharmony_ci UNREACHABLE(); 78271cb0ef41Sopenharmony_ci#undef TYPED_ARRAY_CASE 78281cb0ef41Sopenharmony_ci } 78291cb0ef41Sopenharmony_ci} 78301cb0ef41Sopenharmony_ci} // namespace 78311cb0ef41Sopenharmony_ci 78321cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceDataViewAccess(Node* node, DataViewAccess access, 78331cb0ef41Sopenharmony_ci ExternalArrayType element_type) { 78341cb0ef41Sopenharmony_ci JSCallNode n(node); 78351cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 78361cb0ef41Sopenharmony_ci size_t const element_size = ExternalArrayElementSize(element_type); 78371cb0ef41Sopenharmony_ci Effect effect = n.effect(); 78381cb0ef41Sopenharmony_ci Control control = n.control(); 78391cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 78401cb0ef41Sopenharmony_ci Node* offset = n.ArgumentOr(0, jsgraph()->ZeroConstant()); 78411cb0ef41Sopenharmony_ci Node* value = nullptr; 78421cb0ef41Sopenharmony_ci if (access == DataViewAccess::kSet) { 78431cb0ef41Sopenharmony_ci value = n.ArgumentOrUndefined(1, jsgraph()); 78441cb0ef41Sopenharmony_ci } 78451cb0ef41Sopenharmony_ci const int endian_index = (access == DataViewAccess::kGet ? 1 : 2); 78461cb0ef41Sopenharmony_ci Node* is_little_endian = 78471cb0ef41Sopenharmony_ci n.ArgumentOr(endian_index, jsgraph()->FalseConstant()); 78481cb0ef41Sopenharmony_ci 78491cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 78501cb0ef41Sopenharmony_ci return NoChange(); 78511cb0ef41Sopenharmony_ci } 78521cb0ef41Sopenharmony_ci 78531cb0ef41Sopenharmony_ci // Only do stuff if the {receiver} is really a DataView. 78541cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 78551cb0ef41Sopenharmony_ci if (!inference.HaveMaps() || 78561cb0ef41Sopenharmony_ci !inference.AllOfInstanceTypesAre(JS_DATA_VIEW_TYPE)) { 78571cb0ef41Sopenharmony_ci return NoChange(); 78581cb0ef41Sopenharmony_ci } 78591cb0ef41Sopenharmony_ci 78601cb0ef41Sopenharmony_ci // Check that the {offset} is within range for the {receiver}. 78611cb0ef41Sopenharmony_ci HeapObjectMatcher m(receiver); 78621cb0ef41Sopenharmony_ci if (m.HasResolvedValue() && m.Ref(broker()).IsJSDataView()) { 78631cb0ef41Sopenharmony_ci // We only deal with DataViews here whose [[ByteLength]] is at least 78641cb0ef41Sopenharmony_ci // {element_size}, as for all other DataViews it'll be out-of-bounds. 78651cb0ef41Sopenharmony_ci JSDataViewRef dataview = m.Ref(broker()).AsJSDataView(); 78661cb0ef41Sopenharmony_ci size_t length = dataview.byte_length(); 78671cb0ef41Sopenharmony_ci if (length < element_size) return NoChange(); 78681cb0ef41Sopenharmony_ci 78691cb0ef41Sopenharmony_ci // Check that the {offset} is within range of the {length}. 78701cb0ef41Sopenharmony_ci Node* byte_length = jsgraph()->Constant(length - (element_size - 1)); 78711cb0ef41Sopenharmony_ci offset = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()), 78721cb0ef41Sopenharmony_ci offset, byte_length, effect, control); 78731cb0ef41Sopenharmony_ci } else { 78741cb0ef41Sopenharmony_ci // We only deal with DataViews here that have Smi [[ByteLength]]s. 78751cb0ef41Sopenharmony_ci Node* byte_length = effect = 78761cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->LoadField( 78771cb0ef41Sopenharmony_ci AccessBuilder::ForJSArrayBufferViewByteLength()), 78781cb0ef41Sopenharmony_ci receiver, effect, control); 78791cb0ef41Sopenharmony_ci 78801cb0ef41Sopenharmony_ci if (element_size > 1) { 78811cb0ef41Sopenharmony_ci // For non-byte accesses we also need to check that the {offset} 78821cb0ef41Sopenharmony_ci // plus the {element_size}-1 fits within the given {byte_length}. 78831cb0ef41Sopenharmony_ci // So to keep this as a single check on the {offset}, we subtract 78841cb0ef41Sopenharmony_ci // the {element_size}-1 from the {byte_length} here (clamped to 78851cb0ef41Sopenharmony_ci // positive safe integer range), and perform a check against that 78861cb0ef41Sopenharmony_ci // with the {offset} below. 78871cb0ef41Sopenharmony_ci byte_length = graph()->NewNode( 78881cb0ef41Sopenharmony_ci simplified()->NumberMax(), jsgraph()->ZeroConstant(), 78891cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->NumberSubtract(), byte_length, 78901cb0ef41Sopenharmony_ci jsgraph()->Constant(element_size - 1))); 78911cb0ef41Sopenharmony_ci } 78921cb0ef41Sopenharmony_ci 78931cb0ef41Sopenharmony_ci // Check that the {offset} is within range of the {byte_length}. 78941cb0ef41Sopenharmony_ci offset = effect = graph()->NewNode(simplified()->CheckBounds(p.feedback()), 78951cb0ef41Sopenharmony_ci offset, byte_length, effect, control); 78961cb0ef41Sopenharmony_ci } 78971cb0ef41Sopenharmony_ci 78981cb0ef41Sopenharmony_ci // Coerce {is_little_endian} to boolean. 78991cb0ef41Sopenharmony_ci is_little_endian = 79001cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->ToBoolean(), is_little_endian); 79011cb0ef41Sopenharmony_ci 79021cb0ef41Sopenharmony_ci // Coerce {value} to Number. 79031cb0ef41Sopenharmony_ci if (access == DataViewAccess::kSet) { 79041cb0ef41Sopenharmony_ci value = effect = graph()->NewNode( 79051cb0ef41Sopenharmony_ci simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball, 79061cb0ef41Sopenharmony_ci p.feedback()), 79071cb0ef41Sopenharmony_ci value, effect, control); 79081cb0ef41Sopenharmony_ci } 79091cb0ef41Sopenharmony_ci 79101cb0ef41Sopenharmony_ci // We need to retain either the {receiver} itself or it's backing 79111cb0ef41Sopenharmony_ci // JSArrayBuffer to make sure that the GC doesn't collect the raw 79121cb0ef41Sopenharmony_ci // memory. We default to {receiver} here, and only use the buffer 79131cb0ef41Sopenharmony_ci // if we anyways have to load it (to reduce register pressure). 79141cb0ef41Sopenharmony_ci Node* buffer_or_receiver = receiver; 79151cb0ef41Sopenharmony_ci 79161cb0ef41Sopenharmony_ci if (!dependencies()->DependOnArrayBufferDetachingProtector()) { 79171cb0ef41Sopenharmony_ci // Get the underlying buffer and check that it has not been detached. 79181cb0ef41Sopenharmony_ci Node* buffer = effect = graph()->NewNode( 79191cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), 79201cb0ef41Sopenharmony_ci receiver, effect, control); 79211cb0ef41Sopenharmony_ci 79221cb0ef41Sopenharmony_ci // Bail out if the {buffer} was detached. 79231cb0ef41Sopenharmony_ci Node* buffer_bit_field = effect = graph()->NewNode( 79241cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()), 79251cb0ef41Sopenharmony_ci buffer, effect, control); 79261cb0ef41Sopenharmony_ci Node* check = graph()->NewNode( 79271cb0ef41Sopenharmony_ci simplified()->NumberEqual(), 79281cb0ef41Sopenharmony_ci graph()->NewNode( 79291cb0ef41Sopenharmony_ci simplified()->NumberBitwiseAnd(), buffer_bit_field, 79301cb0ef41Sopenharmony_ci jsgraph()->Constant(JSArrayBuffer::WasDetachedBit::kMask)), 79311cb0ef41Sopenharmony_ci jsgraph()->ZeroConstant()); 79321cb0ef41Sopenharmony_ci effect = graph()->NewNode( 79331cb0ef41Sopenharmony_ci simplified()->CheckIf(DeoptimizeReason::kArrayBufferWasDetached, 79341cb0ef41Sopenharmony_ci p.feedback()), 79351cb0ef41Sopenharmony_ci check, effect, control); 79361cb0ef41Sopenharmony_ci 79371cb0ef41Sopenharmony_ci // We can reduce register pressure by holding on to the {buffer} 79381cb0ef41Sopenharmony_ci // now to retain the backing store memory. 79391cb0ef41Sopenharmony_ci buffer_or_receiver = buffer; 79401cb0ef41Sopenharmony_ci } 79411cb0ef41Sopenharmony_ci 79421cb0ef41Sopenharmony_ci // Load the {receiver}s data pointer. 79431cb0ef41Sopenharmony_ci Node* data_pointer = effect = graph()->NewNode( 79441cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSDataViewDataPointer()), 79451cb0ef41Sopenharmony_ci receiver, effect, control); 79461cb0ef41Sopenharmony_ci 79471cb0ef41Sopenharmony_ci switch (access) { 79481cb0ef41Sopenharmony_ci case DataViewAccess::kGet: 79491cb0ef41Sopenharmony_ci // Perform the load. 79501cb0ef41Sopenharmony_ci value = effect = graph()->NewNode( 79511cb0ef41Sopenharmony_ci simplified()->LoadDataViewElement(element_type), buffer_or_receiver, 79521cb0ef41Sopenharmony_ci data_pointer, offset, is_little_endian, effect, control); 79531cb0ef41Sopenharmony_ci break; 79541cb0ef41Sopenharmony_ci case DataViewAccess::kSet: 79551cb0ef41Sopenharmony_ci // Perform the store. 79561cb0ef41Sopenharmony_ci effect = graph()->NewNode( 79571cb0ef41Sopenharmony_ci simplified()->StoreDataViewElement(element_type), buffer_or_receiver, 79581cb0ef41Sopenharmony_ci data_pointer, offset, value, is_little_endian, effect, control); 79591cb0ef41Sopenharmony_ci value = jsgraph()->UndefinedConstant(); 79601cb0ef41Sopenharmony_ci break; 79611cb0ef41Sopenharmony_ci } 79621cb0ef41Sopenharmony_ci 79631cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 79641cb0ef41Sopenharmony_ci return Changed(value); 79651cb0ef41Sopenharmony_ci} 79661cb0ef41Sopenharmony_ci 79671cb0ef41Sopenharmony_ci// ES6 section 18.2.2 isFinite ( number ) 79681cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceGlobalIsFinite(Node* node) { 79691cb0ef41Sopenharmony_ci JSCallNode n(node); 79701cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 79711cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 79721cb0ef41Sopenharmony_ci return NoChange(); 79731cb0ef41Sopenharmony_ci } 79741cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) { 79751cb0ef41Sopenharmony_ci Node* value = jsgraph()->FalseConstant(); 79761cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 79771cb0ef41Sopenharmony_ci return Replace(value); 79781cb0ef41Sopenharmony_ci } 79791cb0ef41Sopenharmony_ci 79801cb0ef41Sopenharmony_ci Effect effect = n.effect(); 79811cb0ef41Sopenharmony_ci Control control = n.control(); 79821cb0ef41Sopenharmony_ci Node* input = n.Argument(0); 79831cb0ef41Sopenharmony_ci 79841cb0ef41Sopenharmony_ci input = effect = 79851cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->SpeculativeToNumber( 79861cb0ef41Sopenharmony_ci NumberOperationHint::kNumberOrOddball, p.feedback()), 79871cb0ef41Sopenharmony_ci input, effect, control); 79881cb0ef41Sopenharmony_ci Node* value = graph()->NewNode(simplified()->NumberIsFinite(), input); 79891cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect); 79901cb0ef41Sopenharmony_ci return Replace(value); 79911cb0ef41Sopenharmony_ci} 79921cb0ef41Sopenharmony_ci 79931cb0ef41Sopenharmony_ci// ES6 section 18.2.3 isNaN ( number ) 79941cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceGlobalIsNaN(Node* node) { 79951cb0ef41Sopenharmony_ci JSCallNode n(node); 79961cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 79971cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 79981cb0ef41Sopenharmony_ci return NoChange(); 79991cb0ef41Sopenharmony_ci } 80001cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) { 80011cb0ef41Sopenharmony_ci Node* value = jsgraph()->TrueConstant(); 80021cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 80031cb0ef41Sopenharmony_ci return Replace(value); 80041cb0ef41Sopenharmony_ci } 80051cb0ef41Sopenharmony_ci 80061cb0ef41Sopenharmony_ci Effect effect = n.effect(); 80071cb0ef41Sopenharmony_ci Control control = n.control(); 80081cb0ef41Sopenharmony_ci Node* input = n.Argument(0); 80091cb0ef41Sopenharmony_ci 80101cb0ef41Sopenharmony_ci input = effect = 80111cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->SpeculativeToNumber( 80121cb0ef41Sopenharmony_ci NumberOperationHint::kNumberOrOddball, p.feedback()), 80131cb0ef41Sopenharmony_ci input, effect, control); 80141cb0ef41Sopenharmony_ci Node* value = graph()->NewNode(simplified()->NumberIsNaN(), input); 80151cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect); 80161cb0ef41Sopenharmony_ci return Replace(value); 80171cb0ef41Sopenharmony_ci} 80181cb0ef41Sopenharmony_ci 80191cb0ef41Sopenharmony_ci// ES6 section 20.3.4.10 Date.prototype.getTime ( ) 80201cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceDatePrototypeGetTime(Node* node) { 80211cb0ef41Sopenharmony_ci Node* receiver = NodeProperties::GetValueInput(node, 1); 80221cb0ef41Sopenharmony_ci Effect effect{NodeProperties::GetEffectInput(node)}; 80231cb0ef41Sopenharmony_ci Control control{NodeProperties::GetControlInput(node)}; 80241cb0ef41Sopenharmony_ci 80251cb0ef41Sopenharmony_ci MapInference inference(broker(), receiver, effect); 80261cb0ef41Sopenharmony_ci if (!inference.HaveMaps() || !inference.AllOfInstanceTypesAre(JS_DATE_TYPE)) { 80271cb0ef41Sopenharmony_ci return NoChange(); 80281cb0ef41Sopenharmony_ci } 80291cb0ef41Sopenharmony_ci 80301cb0ef41Sopenharmony_ci Node* value = effect = 80311cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->LoadField(AccessBuilder::ForJSDateValue()), 80321cb0ef41Sopenharmony_ci receiver, effect, control); 80331cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 80341cb0ef41Sopenharmony_ci return Replace(value); 80351cb0ef41Sopenharmony_ci} 80361cb0ef41Sopenharmony_ci 80371cb0ef41Sopenharmony_ci// ES6 section 20.3.3.1 Date.now ( ) 80381cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceDateNow(Node* node) { 80391cb0ef41Sopenharmony_ci Node* effect = NodeProperties::GetEffectInput(node); 80401cb0ef41Sopenharmony_ci Node* control = NodeProperties::GetControlInput(node); 80411cb0ef41Sopenharmony_ci Node* value = effect = 80421cb0ef41Sopenharmony_ci graph()->NewNode(simplified()->DateNow(), effect, control); 80431cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect, control); 80441cb0ef41Sopenharmony_ci return Replace(value); 80451cb0ef41Sopenharmony_ci} 80461cb0ef41Sopenharmony_ci 80471cb0ef41Sopenharmony_ci// ES6 section 20.1.2.13 Number.parseInt ( string, radix ) 80481cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceNumberParseInt(Node* node) { 80491cb0ef41Sopenharmony_ci JSCallNode n(node); 80501cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) { 80511cb0ef41Sopenharmony_ci Node* value = jsgraph()->NaNConstant(); 80521cb0ef41Sopenharmony_ci ReplaceWithValue(node, value); 80531cb0ef41Sopenharmony_ci return Replace(value); 80541cb0ef41Sopenharmony_ci } 80551cb0ef41Sopenharmony_ci 80561cb0ef41Sopenharmony_ci Effect effect = n.effect(); 80571cb0ef41Sopenharmony_ci Control control = n.control(); 80581cb0ef41Sopenharmony_ci Node* context = n.context(); 80591cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 80601cb0ef41Sopenharmony_ci Node* object = n.Argument(0); 80611cb0ef41Sopenharmony_ci Node* radix = n.ArgumentOrUndefined(1, jsgraph()); 80621cb0ef41Sopenharmony_ci node->ReplaceInput(0, object); 80631cb0ef41Sopenharmony_ci node->ReplaceInput(1, radix); 80641cb0ef41Sopenharmony_ci node->ReplaceInput(2, context); 80651cb0ef41Sopenharmony_ci node->ReplaceInput(3, frame_state); 80661cb0ef41Sopenharmony_ci node->ReplaceInput(4, effect); 80671cb0ef41Sopenharmony_ci node->ReplaceInput(5, control); 80681cb0ef41Sopenharmony_ci node->TrimInputCount(6); 80691cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, javascript()->ParseInt()); 80701cb0ef41Sopenharmony_ci return Changed(node); 80711cb0ef41Sopenharmony_ci} 80721cb0ef41Sopenharmony_ci 80731cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) { 80741cb0ef41Sopenharmony_ci JSCallNode n(node); 80751cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 80761cb0ef41Sopenharmony_ci if (FLAG_force_slow_path) return NoChange(); 80771cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 1) return NoChange(); 80781cb0ef41Sopenharmony_ci 80791cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 80801cb0ef41Sopenharmony_ci return NoChange(); 80811cb0ef41Sopenharmony_ci } 80821cb0ef41Sopenharmony_ci 80831cb0ef41Sopenharmony_ci Effect effect = n.effect(); 80841cb0ef41Sopenharmony_ci Control control = n.control(); 80851cb0ef41Sopenharmony_ci Node* regexp = n.receiver(); 80861cb0ef41Sopenharmony_ci 80871cb0ef41Sopenharmony_ci // Only the initial JSRegExp map is valid here, since the following lastIndex 80881cb0ef41Sopenharmony_ci // check as well as the lowered builtin call rely on a known location of the 80891cb0ef41Sopenharmony_ci // lastIndex field. 80901cb0ef41Sopenharmony_ci MapRef regexp_initial_map = 80911cb0ef41Sopenharmony_ci native_context().regexp_function().initial_map(dependencies()); 80921cb0ef41Sopenharmony_ci 80931cb0ef41Sopenharmony_ci MapInference inference(broker(), regexp, effect); 80941cb0ef41Sopenharmony_ci if (!inference.Is(regexp_initial_map)) return inference.NoChange(); 80951cb0ef41Sopenharmony_ci ZoneVector<MapRef> const& regexp_maps = inference.GetMaps(); 80961cb0ef41Sopenharmony_ci 80971cb0ef41Sopenharmony_ci ZoneVector<PropertyAccessInfo> access_infos(graph()->zone()); 80981cb0ef41Sopenharmony_ci AccessInfoFactory access_info_factory(broker(), dependencies(), 80991cb0ef41Sopenharmony_ci graph()->zone()); 81001cb0ef41Sopenharmony_ci 81011cb0ef41Sopenharmony_ci for (const MapRef& map : regexp_maps) { 81021cb0ef41Sopenharmony_ci access_infos.push_back(broker()->GetPropertyAccessInfo( 81031cb0ef41Sopenharmony_ci map, MakeRef(broker(), isolate()->factory()->exec_string()), 81041cb0ef41Sopenharmony_ci AccessMode::kLoad, dependencies())); 81051cb0ef41Sopenharmony_ci } 81061cb0ef41Sopenharmony_ci 81071cb0ef41Sopenharmony_ci PropertyAccessInfo ai_exec = 81081cb0ef41Sopenharmony_ci access_info_factory.FinalizePropertyAccessInfosAsOne(access_infos, 81091cb0ef41Sopenharmony_ci AccessMode::kLoad); 81101cb0ef41Sopenharmony_ci if (ai_exec.IsInvalid()) return inference.NoChange(); 81111cb0ef41Sopenharmony_ci if (!ai_exec.IsFastDataConstant()) return inference.NoChange(); 81121cb0ef41Sopenharmony_ci 81131cb0ef41Sopenharmony_ci // Do not reduce if the exec method is not on the prototype chain. 81141cb0ef41Sopenharmony_ci base::Optional<JSObjectRef> holder = ai_exec.holder(); 81151cb0ef41Sopenharmony_ci if (!holder.has_value()) return inference.NoChange(); 81161cb0ef41Sopenharmony_ci 81171cb0ef41Sopenharmony_ci // Bail out if the exec method is not the original one. 81181cb0ef41Sopenharmony_ci base::Optional<ObjectRef> constant = holder->GetOwnFastDataProperty( 81191cb0ef41Sopenharmony_ci ai_exec.field_representation(), ai_exec.field_index(), dependencies()); 81201cb0ef41Sopenharmony_ci if (!constant.has_value() || 81211cb0ef41Sopenharmony_ci !constant->equals(native_context().regexp_exec_function())) { 81221cb0ef41Sopenharmony_ci return inference.NoChange(); 81231cb0ef41Sopenharmony_ci } 81241cb0ef41Sopenharmony_ci 81251cb0ef41Sopenharmony_ci // Add proper dependencies on the {regexp}s [[Prototype]]s. 81261cb0ef41Sopenharmony_ci dependencies()->DependOnStablePrototypeChains( 81271cb0ef41Sopenharmony_ci ai_exec.lookup_start_object_maps(), kStartAtPrototype, holder.value()); 81281cb0ef41Sopenharmony_ci 81291cb0ef41Sopenharmony_ci inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect, 81301cb0ef41Sopenharmony_ci control, p.feedback()); 81311cb0ef41Sopenharmony_ci 81321cb0ef41Sopenharmony_ci Node* context = n.context(); 81331cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 81341cb0ef41Sopenharmony_ci Node* search = n.Argument(0); 81351cb0ef41Sopenharmony_ci Node* search_string = effect = graph()->NewNode( 81361cb0ef41Sopenharmony_ci simplified()->CheckString(p.feedback()), search, effect, control); 81371cb0ef41Sopenharmony_ci 81381cb0ef41Sopenharmony_ci Node* lastIndex = effect = graph()->NewNode( 81391cb0ef41Sopenharmony_ci simplified()->LoadField(AccessBuilder::ForJSRegExpLastIndex()), regexp, 81401cb0ef41Sopenharmony_ci effect, control); 81411cb0ef41Sopenharmony_ci 81421cb0ef41Sopenharmony_ci Node* lastIndexSmi = effect = graph()->NewNode( 81431cb0ef41Sopenharmony_ci simplified()->CheckSmi(p.feedback()), lastIndex, effect, control); 81441cb0ef41Sopenharmony_ci 81451cb0ef41Sopenharmony_ci Node* is_positive = graph()->NewNode(simplified()->NumberLessThanOrEqual(), 81461cb0ef41Sopenharmony_ci jsgraph()->ZeroConstant(), lastIndexSmi); 81471cb0ef41Sopenharmony_ci 81481cb0ef41Sopenharmony_ci effect = graph()->NewNode( 81491cb0ef41Sopenharmony_ci simplified()->CheckIf(DeoptimizeReason::kNotASmi, p.feedback()), 81501cb0ef41Sopenharmony_ci is_positive, effect, control); 81511cb0ef41Sopenharmony_ci 81521cb0ef41Sopenharmony_ci node->ReplaceInput(0, regexp); 81531cb0ef41Sopenharmony_ci node->ReplaceInput(1, search_string); 81541cb0ef41Sopenharmony_ci node->ReplaceInput(2, context); 81551cb0ef41Sopenharmony_ci node->ReplaceInput(3, frame_state); 81561cb0ef41Sopenharmony_ci node->ReplaceInput(4, effect); 81571cb0ef41Sopenharmony_ci node->ReplaceInput(5, control); 81581cb0ef41Sopenharmony_ci node->TrimInputCount(6); 81591cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, javascript()->RegExpTest()); 81601cb0ef41Sopenharmony_ci return Changed(node); 81611cb0ef41Sopenharmony_ci} 81621cb0ef41Sopenharmony_ci 81631cb0ef41Sopenharmony_ci// ES section #sec-number-constructor 81641cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceNumberConstructor(Node* node) { 81651cb0ef41Sopenharmony_ci JSCallNode n(node); 81661cb0ef41Sopenharmony_ci Node* target = n.target(); 81671cb0ef41Sopenharmony_ci Node* receiver = n.receiver(); 81681cb0ef41Sopenharmony_ci Node* value = n.ArgumentOr(0, jsgraph()->ZeroConstant()); 81691cb0ef41Sopenharmony_ci Node* context = n.context(); 81701cb0ef41Sopenharmony_ci FrameState frame_state = n.frame_state(); 81711cb0ef41Sopenharmony_ci 81721cb0ef41Sopenharmony_ci // Create the artificial frame state in the middle of the Number constructor. 81731cb0ef41Sopenharmony_ci SharedFunctionInfoRef shared_info = 81741cb0ef41Sopenharmony_ci native_context().number_function().shared(); 81751cb0ef41Sopenharmony_ci Node* stack_parameters[] = {receiver}; 81761cb0ef41Sopenharmony_ci int stack_parameter_count = arraysize(stack_parameters); 81771cb0ef41Sopenharmony_ci Node* continuation_frame_state = 81781cb0ef41Sopenharmony_ci CreateJavaScriptBuiltinContinuationFrameState( 81791cb0ef41Sopenharmony_ci jsgraph(), shared_info, Builtin::kGenericLazyDeoptContinuation, 81801cb0ef41Sopenharmony_ci target, context, stack_parameters, stack_parameter_count, frame_state, 81811cb0ef41Sopenharmony_ci ContinuationFrameStateMode::LAZY); 81821cb0ef41Sopenharmony_ci 81831cb0ef41Sopenharmony_ci // Convert the {value} to a Number. 81841cb0ef41Sopenharmony_ci NodeProperties::ReplaceValueInputs(node, value); 81851cb0ef41Sopenharmony_ci NodeProperties::ChangeOp(node, javascript()->ToNumberConvertBigInt()); 81861cb0ef41Sopenharmony_ci NodeProperties::ReplaceFrameStateInput(node, continuation_frame_state); 81871cb0ef41Sopenharmony_ci return Changed(node); 81881cb0ef41Sopenharmony_ci} 81891cb0ef41Sopenharmony_ci 81901cb0ef41Sopenharmony_ciReduction JSCallReducer::ReduceBigIntAsN(Node* node, Builtin builtin) { 81911cb0ef41Sopenharmony_ci DCHECK(builtin == Builtin::kBigIntAsIntN || 81921cb0ef41Sopenharmony_ci builtin == Builtin::kBigIntAsUintN); 81931cb0ef41Sopenharmony_ci 81941cb0ef41Sopenharmony_ci if (!jsgraph()->machine()->Is64()) return NoChange(); 81951cb0ef41Sopenharmony_ci 81961cb0ef41Sopenharmony_ci JSCallNode n(node); 81971cb0ef41Sopenharmony_ci CallParameters const& p = n.Parameters(); 81981cb0ef41Sopenharmony_ci if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) { 81991cb0ef41Sopenharmony_ci return NoChange(); 82001cb0ef41Sopenharmony_ci } 82011cb0ef41Sopenharmony_ci if (n.ArgumentCount() < 2) { 82021cb0ef41Sopenharmony_ci return NoChange(); 82031cb0ef41Sopenharmony_ci } 82041cb0ef41Sopenharmony_ci 82051cb0ef41Sopenharmony_ci Effect effect = n.effect(); 82061cb0ef41Sopenharmony_ci Control control = n.control(); 82071cb0ef41Sopenharmony_ci Node* bits = n.Argument(0); 82081cb0ef41Sopenharmony_ci Node* value = n.Argument(1); 82091cb0ef41Sopenharmony_ci 82101cb0ef41Sopenharmony_ci NumberMatcher matcher(bits); 82111cb0ef41Sopenharmony_ci if (matcher.IsInteger() && matcher.IsInRange(0, 64)) { 82121cb0ef41Sopenharmony_ci const int bits_value = static_cast<int>(matcher.ResolvedValue()); 82131cb0ef41Sopenharmony_ci value = effect = graph()->NewNode( 82141cb0ef41Sopenharmony_ci (builtin == Builtin::kBigIntAsIntN 82151cb0ef41Sopenharmony_ci ? simplified()->SpeculativeBigIntAsIntN(bits_value, p.feedback()) 82161cb0ef41Sopenharmony_ci : simplified()->SpeculativeBigIntAsUintN(bits_value, 82171cb0ef41Sopenharmony_ci p.feedback())), 82181cb0ef41Sopenharmony_ci value, effect, control); 82191cb0ef41Sopenharmony_ci ReplaceWithValue(node, value, effect); 82201cb0ef41Sopenharmony_ci return Replace(value); 82211cb0ef41Sopenharmony_ci } 82221cb0ef41Sopenharmony_ci 82231cb0ef41Sopenharmony_ci return NoChange(); 82241cb0ef41Sopenharmony_ci} 82251cb0ef41Sopenharmony_ci 82261cb0ef41Sopenharmony_ciCompilationDependencies* JSCallReducer::dependencies() const { 82271cb0ef41Sopenharmony_ci return broker()->dependencies(); 82281cb0ef41Sopenharmony_ci} 82291cb0ef41Sopenharmony_ci 82301cb0ef41Sopenharmony_ciGraph* JSCallReducer::graph() const { return jsgraph()->graph(); } 82311cb0ef41Sopenharmony_ci 82321cb0ef41Sopenharmony_ciIsolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); } 82331cb0ef41Sopenharmony_ci 82341cb0ef41Sopenharmony_ciFactory* JSCallReducer::factory() const { return isolate()->factory(); } 82351cb0ef41Sopenharmony_ci 82361cb0ef41Sopenharmony_ciNativeContextRef JSCallReducer::native_context() const { 82371cb0ef41Sopenharmony_ci return broker()->target_native_context(); 82381cb0ef41Sopenharmony_ci} 82391cb0ef41Sopenharmony_ci 82401cb0ef41Sopenharmony_ciCommonOperatorBuilder* JSCallReducer::common() const { 82411cb0ef41Sopenharmony_ci return jsgraph()->common(); 82421cb0ef41Sopenharmony_ci} 82431cb0ef41Sopenharmony_ci 82441cb0ef41Sopenharmony_ciJSOperatorBuilder* JSCallReducer::javascript() const { 82451cb0ef41Sopenharmony_ci return jsgraph()->javascript(); 82461cb0ef41Sopenharmony_ci} 82471cb0ef41Sopenharmony_ci 82481cb0ef41Sopenharmony_ciSimplifiedOperatorBuilder* JSCallReducer::simplified() const { 82491cb0ef41Sopenharmony_ci return jsgraph()->simplified(); 82501cb0ef41Sopenharmony_ci} 82511cb0ef41Sopenharmony_ci 82521cb0ef41Sopenharmony_ci} // namespace compiler 82531cb0ef41Sopenharmony_ci} // namespace internal 82541cb0ef41Sopenharmony_ci} // namespace v8 8255