revert_fastapi_remove_dynamic_overload_resolution.patch 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: John Kleinschmidt <[email protected]>
  3. Date: Fri, 15 Nov 2024 10:46:43 -0500
  4. Subject: Revert "[fastapi] Remove dynamic overload resolution"
  5. Revert this until Node.js decides how to proceed and then pick up their fix.
  6. Refs: https://github.com/nodejs/node/issues/55452
  7. Refs: https://chromium-review.googlesource.com/c/v8/v8/+/5956408
  8. Refs: https://chromium-review.googlesource.com/c/v8/v8/+/5982984
  9. Refs: https://chromium-review.googlesource.com/c/v8/v8/+/5979766
  10. This reverts commit c41f7a0ef99bd1c9752ee79923f634145ebc4153.
  11. diff --git a/src/api/api.cc b/src/api/api.cc
  12. index d76e52da63748acfb37b31179b3428de77362413..0b30c6568d1a38237f3629fb88a5c9cbf1650f98 100644
  13. --- a/src/api/api.cc
  14. +++ b/src/api/api.cc
  15. @@ -1349,16 +1349,6 @@ Local<FunctionTemplate> FunctionTemplate::NewWithCFunctionOverloads(
  16. i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
  17. API_RCS_SCOPE(i_isolate, FunctionTemplate, New);
  18. - // Check that all overloads of the fast API callback have different numbers of
  19. - // parameters. Since the number of overloads is supposed to be small, just
  20. - // comparing them with each other should be fine.
  21. - for (size_t i = 0; i < c_function_overloads.size(); ++i) {
  22. - for (size_t j = i + 1; j < c_function_overloads.size(); ++j) {
  23. - CHECK_NE(c_function_overloads.data()[i].ArgumentCount(),
  24. - c_function_overloads.data()[j].ArgumentCount());
  25. - }
  26. - }
  27. -
  28. if (!Utils::ApiCheck(
  29. c_function_overloads.empty() ||
  30. behavior == ConstructorBehavior::kThrow,
  31. diff --git a/src/compiler/fast-api-calls.cc b/src/compiler/fast-api-calls.cc
  32. index 2dc99dc83e0f78d2bbb0875cc04064b565deaf06..d560afa2ee9f4384738cddf659a51d4c42b4fe67 100644
  33. --- a/src/compiler/fast-api-calls.cc
  34. +++ b/src/compiler/fast-api-calls.cc
  35. @@ -62,6 +62,52 @@ ElementsKind GetTypedArrayElementsKind(CTypeInfo::Type type) {
  36. }
  37. }
  38. +OverloadsResolutionResult ResolveOverloads(
  39. + const FastApiCallFunctionVector& candidates, unsigned int arg_count) {
  40. + DCHECK_GT(arg_count, 0);
  41. +
  42. + static constexpr int kReceiver = 1;
  43. +
  44. + // Only the case of the overload resolution of two functions, one with a
  45. + // JSArray param and the other with a typed array param is currently
  46. + // supported.
  47. + DCHECK_EQ(candidates.size(), 2);
  48. +
  49. + for (unsigned int arg_index = kReceiver; arg_index < arg_count; arg_index++) {
  50. + int index_of_func_with_js_array_arg = -1;
  51. + int index_of_func_with_typed_array_arg = -1;
  52. + CTypeInfo::Type element_type = CTypeInfo::Type::kVoid;
  53. +
  54. + for (size_t i = 0; i < candidates.size(); i++) {
  55. + const CTypeInfo& type_info =
  56. + candidates[i].signature->ArgumentInfo(arg_index);
  57. + CTypeInfo::SequenceType sequence_type = type_info.GetSequenceType();
  58. +
  59. + START_ALLOW_USE_DEPRECATED()
  60. + if (sequence_type == CTypeInfo::SequenceType::kIsSequence) {
  61. + DCHECK_LT(index_of_func_with_js_array_arg, 0);
  62. + index_of_func_with_js_array_arg = static_cast<int>(i);
  63. + } else if (sequence_type == CTypeInfo::SequenceType::kIsTypedArray) {
  64. + DCHECK_LT(index_of_func_with_typed_array_arg, 0);
  65. + index_of_func_with_typed_array_arg = static_cast<int>(i);
  66. + element_type = type_info.GetType();
  67. + } else {
  68. + DCHECK_LT(index_of_func_with_js_array_arg, 0);
  69. + DCHECK_LT(index_of_func_with_typed_array_arg, 0);
  70. + }
  71. + END_ALLOW_USE_DEPRECATED()
  72. + }
  73. +
  74. + if (index_of_func_with_js_array_arg >= 0 &&
  75. + index_of_func_with_typed_array_arg >= 0) {
  76. + return {static_cast<int>(arg_index), element_type};
  77. + }
  78. + }
  79. +
  80. + // No overload found with a JSArray and a typed array as i-th argument.
  81. + return OverloadsResolutionResult::Invalid();
  82. +}
  83. +
  84. bool CanOptimizeFastSignature(const CFunctionInfo* c_signature) {
  85. USE(c_signature);
  86. @@ -149,7 +195,8 @@ class FastApiCallBuilder {
  87. initialize_options_(initialize_options),
  88. generate_slow_api_call_(generate_slow_api_call) {}
  89. - Node* Build(FastApiCallFunction c_function, Node* data_argument);
  90. + Node* Build(const FastApiCallFunctionVector& c_functions,
  91. + const CFunctionInfo* c_signature, Node* data_argument);
  92. private:
  93. Node* WrapFastCall(const CallDescriptor* call_descriptor, int inputs_size,
  94. @@ -230,15 +277,35 @@ void FastApiCallBuilder::PropagateException() {
  95. __ Call(call_descriptor, count, inputs);
  96. }
  97. -Node* FastApiCallBuilder::Build(FastApiCallFunction c_function,
  98. +Node* FastApiCallBuilder::Build(const FastApiCallFunctionVector& c_functions,
  99. + const CFunctionInfo* c_signature,
  100. Node* data_argument) {
  101. - const CFunctionInfo* c_signature = c_function.signature;
  102. const int c_arg_count = c_signature->ArgumentCount();
  103. // Hint to fast path.
  104. auto if_success = __ MakeLabel();
  105. auto if_error = __ MakeDeferredLabel();
  106. + // Overload resolution
  107. + bool generate_fast_call = false;
  108. + OverloadsResolutionResult overloads_resolution_result =
  109. + OverloadsResolutionResult::Invalid();
  110. +
  111. + if (c_functions.size() == 1) {
  112. + generate_fast_call = true;
  113. + } else {
  114. + DCHECK_EQ(c_functions.size(), 2);
  115. + overloads_resolution_result = ResolveOverloads(c_functions, c_arg_count);
  116. + if (overloads_resolution_result.is_valid()) {
  117. + generate_fast_call = true;
  118. + }
  119. + }
  120. +
  121. + if (!generate_fast_call) {
  122. + // Only generate the slow call.
  123. + return generate_slow_api_call_();
  124. + }
  125. +
  126. // Generate fast call.
  127. const int kFastTargetAddressInputIndex = 0;
  128. @@ -263,11 +330,18 @@ Node* FastApiCallBuilder::Build(FastApiCallFunction c_function,
  129. // address associated to the first and only element in the c_functions vector.
  130. // If there are multiple overloads the value of this input will be set later
  131. // with a Phi node created by AdaptOverloadedFastCallArgument.
  132. - inputs[kFastTargetAddressInputIndex] = __ ExternalConstant(
  133. - ExternalReference::Create(c_function.address, ref_type));
  134. + inputs[kFastTargetAddressInputIndex] =
  135. + (c_functions.size() == 1) ? __ ExternalConstant(ExternalReference::Create(
  136. + c_functions[0].address, ref_type))
  137. + : nullptr;
  138. for (int i = 0; i < c_arg_count; ++i) {
  139. - inputs[i + kFastTargetAddressInputCount] = get_parameter_(i, &if_error);
  140. + inputs[i + kFastTargetAddressInputCount] =
  141. + get_parameter_(i, overloads_resolution_result, &if_error);
  142. + if (overloads_resolution_result.target_address) {
  143. + inputs[kFastTargetAddressInputIndex] =
  144. + overloads_resolution_result.target_address;
  145. + }
  146. }
  147. DCHECK_NOT_NULL(inputs[kFastTargetAddressInputIndex]);
  148. @@ -368,7 +442,8 @@ Node* FastApiCallBuilder::Build(FastApiCallFunction c_function,
  149. Node* BuildFastApiCall(Isolate* isolate, Graph* graph,
  150. GraphAssembler* graph_assembler,
  151. - FastApiCallFunction c_function, Node* data_argument,
  152. + const FastApiCallFunctionVector& c_functions,
  153. + const CFunctionInfo* c_signature, Node* data_argument,
  154. const GetParameter& get_parameter,
  155. const ConvertReturnValue& convert_return_value,
  156. const InitializeOptions& initialize_options,
  157. @@ -376,7 +451,7 @@ Node* BuildFastApiCall(Isolate* isolate, Graph* graph,
  158. FastApiCallBuilder builder(isolate, graph, graph_assembler, get_parameter,
  159. convert_return_value, initialize_options,
  160. generate_slow_api_call);
  161. - return builder.Build(c_function, data_argument);
  162. + return builder.Build(c_functions, c_signature, data_argument);
  163. }
  164. } // namespace fast_api_call
  165. diff --git a/src/compiler/fast-api-calls.h b/src/compiler/fast-api-calls.h
  166. index 171e66c427991bfe7db5c2875d12559767a24b55..b97b37e5746433d3801de19d4666a19afc223cdc 100644
  167. --- a/src/compiler/fast-api-calls.h
  168. +++ b/src/compiler/fast-api-calls.h
  169. @@ -40,16 +40,21 @@ struct OverloadsResolutionResult {
  170. ElementsKind GetTypedArrayElementsKind(CTypeInfo::Type type);
  171. +OverloadsResolutionResult ResolveOverloads(
  172. + const FastApiCallFunctionVector& candidates, unsigned int arg_count);
  173. +
  174. bool CanOptimizeFastSignature(const CFunctionInfo* c_signature);
  175. -using GetParameter = std::function<Node*(int, GraphAssemblerLabel<0>*)>;
  176. +using GetParameter = std::function<Node*(int, OverloadsResolutionResult&,
  177. + GraphAssemblerLabel<0>*)>;
  178. using ConvertReturnValue = std::function<Node*(const CFunctionInfo*, Node*)>;
  179. using InitializeOptions = std::function<void(Node*)>;
  180. using GenerateSlowApiCall = std::function<Node*()>;
  181. Node* BuildFastApiCall(Isolate* isolate, Graph* graph,
  182. GraphAssembler* graph_assembler,
  183. - FastApiCallFunction c_function, Node* data_argument,
  184. + const FastApiCallFunctionVector& c_functions,
  185. + const CFunctionInfo* c_signature, Node* data_argument,
  186. const GetParameter& get_parameter,
  187. const ConvertReturnValue& convert_return_value,
  188. const InitializeOptions& initialize_options,
  189. diff --git a/src/compiler/js-call-reducer.cc b/src/compiler/js-call-reducer.cc
  190. index d75a38769d582cd6e5a807f9670732dc92d77b7e..a29bd4a5be0c9a268386898f8a52e98933211b6c 100644
  191. --- a/src/compiler/js-call-reducer.cc
  192. +++ b/src/compiler/js-call-reducer.cc
  193. @@ -631,11 +631,11 @@ class FastApiCallReducerAssembler : public JSCallReducerAssembler {
  194. FastApiCallReducerAssembler(
  195. JSCallReducer* reducer, Node* node,
  196. const FunctionTemplateInfoRef function_template_info,
  197. - FastApiCallFunction c_function, Node* receiver, Node* holder,
  198. - const SharedFunctionInfoRef shared, Node* target, const int arity,
  199. - Node* effect)
  200. + const FastApiCallFunctionVector& c_candidate_functions, Node* receiver,
  201. + Node* holder, const SharedFunctionInfoRef shared, Node* target,
  202. + const int arity, Node* effect)
  203. : JSCallReducerAssembler(reducer, node),
  204. - c_function_(c_function),
  205. + c_candidate_functions_(c_candidate_functions),
  206. function_template_info_(function_template_info),
  207. receiver_(receiver),
  208. holder_(holder),
  209. @@ -643,6 +643,7 @@ class FastApiCallReducerAssembler : public JSCallReducerAssembler {
  210. target_(target),
  211. arity_(arity) {
  212. DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
  213. + CHECK_GT(c_candidate_functions.size(), 0);
  214. InitializeEffectControl(effect, NodeProperties::GetControlInput(node));
  215. }
  216. @@ -654,7 +655,7 @@ class FastApiCallReducerAssembler : public JSCallReducerAssembler {
  217. // All functions in c_candidate_functions_ have the same number of
  218. // arguments, so extract c_argument_count from the first function.
  219. const int c_argument_count =
  220. - static_cast<int>(c_function_.signature->ArgumentCount());
  221. + static_cast<int>(c_candidate_functions_[0].signature->ArgumentCount());
  222. CHECK_GE(c_argument_count, kReceiver);
  223. const int slow_arg_count =
  224. @@ -755,12 +756,13 @@ class FastApiCallReducerAssembler : public JSCallReducerAssembler {
  225. TNode<Object> FastApiCall(CallDescriptor* descriptor, Node** inputs,
  226. size_t inputs_size) {
  227. - return AddNode<Object>(graph()->NewNode(
  228. - simplified()->FastApiCall(c_function_, feedback(), descriptor),
  229. - static_cast<int>(inputs_size), inputs));
  230. + return AddNode<Object>(
  231. + graph()->NewNode(simplified()->FastApiCall(c_candidate_functions_,
  232. + feedback(), descriptor),
  233. + static_cast<int>(inputs_size), inputs));
  234. }
  235. - FastApiCallFunction c_function_;
  236. + const FastApiCallFunctionVector c_candidate_functions_;
  237. const FunctionTemplateInfoRef function_template_info_;
  238. Node* const receiver_;
  239. Node* const holder_;
  240. @@ -3886,10 +3888,11 @@ Reduction JSCallReducer::ReduceCallWasmFunction(Node* node,
  241. // Returns an array with the indexes of the remaining entries in S, which
  242. // represents the set of "optimizable" function overloads.
  243. -FastApiCallFunction GetFastApiCallTarget(
  244. - JSHeapBroker* broker, FunctionTemplateInfoRef function_template_info,
  245. - size_t arg_count) {
  246. - if (!v8_flags.turbo_fast_api_calls) return {0, nullptr};
  247. +FastApiCallFunctionVector CanOptimizeFastCall(
  248. + JSHeapBroker* broker, Zone* zone,
  249. + FunctionTemplateInfoRef function_template_info, size_t arg_count) {
  250. + FastApiCallFunctionVector result(zone);
  251. + if (!v8_flags.turbo_fast_api_calls) return result;
  252. static constexpr int kReceiver = 1;
  253. @@ -3918,15 +3921,15 @@ FastApiCallFunction GetFastApiCallTarget(
  254. static_cast<uint8_t>(c_signature->ArgumentInfo(i).GetFlags());
  255. if (flags & static_cast<uint8_t>(CTypeInfo::Flags::kEnforceRangeBit)) {
  256. // Bailout
  257. - return {0, nullptr};
  258. + return FastApiCallFunctionVector(zone);
  259. }
  260. }
  261. #endif
  262. - return {functions[i], c_signature};
  263. + result.push_back({functions[i], c_signature});
  264. }
  265. }
  266. - return {0, nullptr};
  267. + return result;
  268. }
  269. Reduction JSCallReducer::ReduceCallApiFunction(Node* node,
  270. @@ -4109,13 +4112,15 @@ Reduction JSCallReducer::ReduceCallApiFunction(Node* node,
  271. }
  272. // Handles overloaded functions.
  273. - FastApiCallFunction c_function =
  274. - GetFastApiCallTarget(broker(), function_template_info, argc);
  275. - if (c_function.address) {
  276. + FastApiCallFunctionVector c_candidate_functions = CanOptimizeFastCall(
  277. + broker(), graph()->zone(), function_template_info, argc);
  278. + DCHECK_LE(c_candidate_functions.size(), 2);
  279. +
  280. + if (!c_candidate_functions.empty()) {
  281. FastApiCallReducerAssembler a(this, node, function_template_info,
  282. - c_function, receiver, holder, shared, target,
  283. - argc, effect);
  284. + c_candidate_functions, receiver, holder,
  285. + shared, target, argc, effect);
  286. Node* fast_call_subgraph = a.ReduceFastApiCall();
  287. return Replace(fast_call_subgraph);
  288. diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc
  289. index 377d36b1d880892d0d446ee386d21028d3ffec16..ebb8bcd585f6b185e355922fd97c94bd0136d968 100644
  290. --- a/src/compiler/simplified-lowering.cc
  291. +++ b/src/compiler/simplified-lowering.cc
  292. @@ -2015,7 +2015,7 @@ class RepresentationSelector {
  293. // argument, which must be a JSArray in one function and a TypedArray in the
  294. // other function, and both JSArrays and TypedArrays have the same UseInfo
  295. // UseInfo::AnyTagged(). All the other argument types must match.
  296. - const CFunctionInfo* c_signature = op_params.c_function().signature;
  297. + const CFunctionInfo* c_signature = op_params.c_functions()[0].signature;
  298. const int c_arg_count = c_signature->ArgumentCount();
  299. CallDescriptor* call_descriptor = op_params.descriptor();
  300. // Arguments for CallApiCallbackOptimizedXXX builtin (including context)
  301. @@ -2057,8 +2057,12 @@ class RepresentationSelector {
  302. // Effect and Control.
  303. ProcessRemainingInputs<T>(node, value_input_count);
  304. + if (op_params.c_functions().empty()) {
  305. + SetOutput<T>(node, MachineRepresentation::kTagged);
  306. + return;
  307. + }
  308. - CTypeInfo return_type = op_params.c_function().signature->ReturnInfo();
  309. + CTypeInfo return_type = op_params.c_functions()[0].signature->ReturnInfo();
  310. switch (return_type.GetType()) {
  311. case CTypeInfo::Type::kBool:
  312. SetOutput<T>(node, MachineRepresentation::kBit);
  313. diff --git a/src/compiler/simplified-operator.cc b/src/compiler/simplified-operator.cc
  314. index d0405cf5bc25d47b7cf8bfd03b0bb639df4eddd4..f5810d72d99f4ecfe668d9e1fd9b3ad2ea123875 100644
  315. --- a/src/compiler/simplified-operator.cc
  316. +++ b/src/compiler/simplified-operator.cc
  317. @@ -2096,21 +2096,26 @@ FastApiCallParameters const& FastApiCallParametersOf(const Operator* op) {
  318. }
  319. std::ostream& operator<<(std::ostream& os, FastApiCallParameters const& p) {
  320. - FastApiCallFunction c_function = p.c_function();
  321. - os << c_function.address << ":" << c_function.signature << ", ";
  322. + const auto& c_functions = p.c_functions();
  323. + for (size_t i = 0; i < c_functions.size(); i++) {
  324. + os << c_functions[i].address << ":" << c_functions[i].signature << ", ";
  325. + }
  326. return os << p.feedback() << ", " << p.descriptor();
  327. }
  328. size_t hash_value(FastApiCallParameters const& p) {
  329. - FastApiCallFunction c_function = p.c_function();
  330. - size_t hash = base::hash_combine(c_function.address, c_function.signature);
  331. + const auto& c_functions = p.c_functions();
  332. + size_t hash = 0;
  333. + for (size_t i = 0; i < c_functions.size(); i++) {
  334. + hash = base::hash_combine(c_functions[i].address, c_functions[i].signature);
  335. + }
  336. return base::hash_combine(hash, FeedbackSource::Hash()(p.feedback()),
  337. p.descriptor());
  338. }
  339. bool operator==(FastApiCallParameters const& lhs,
  340. FastApiCallParameters const& rhs) {
  341. - return lhs.c_function() == rhs.c_function() &&
  342. + return lhs.c_functions() == rhs.c_functions() &&
  343. lhs.feedback() == rhs.feedback() &&
  344. lhs.descriptor() == rhs.descriptor();
  345. }
  346. @@ -2320,11 +2325,19 @@ const Operator* SimplifiedOperatorBuilder::TransitionAndStoreNonNumberElement(
  347. }
  348. const Operator* SimplifiedOperatorBuilder::FastApiCall(
  349. - FastApiCallFunction c_function, FeedbackSource const& feedback,
  350. - CallDescriptor* descriptor) {
  351. - CHECK_NOT_NULL(c_function.signature);
  352. - const CFunctionInfo* signature = c_function.signature;
  353. + const FastApiCallFunctionVector& c_functions,
  354. + FeedbackSource const& feedback, CallDescriptor* descriptor) {
  355. + DCHECK(!c_functions.empty());
  356. +
  357. + // All function overloads have the same number of arguments and options.
  358. + const CFunctionInfo* signature = c_functions[0].signature;
  359. const int c_arg_count = signature->ArgumentCount();
  360. + for (size_t i = 1; i < c_functions.size(); i++) {
  361. + CHECK_NOT_NULL(c_functions[i].signature);
  362. + DCHECK_EQ(c_functions[i].signature->ArgumentCount(), c_arg_count);
  363. + DCHECK_EQ(c_functions[i].signature->HasOptions(),
  364. + c_functions[0].signature->HasOptions());
  365. + }
  366. // Arguments for CallApiCallbackOptimizedXXX builtin (including context)
  367. // plus JS arguments (including receiver).
  368. int slow_arg_count = static_cast<int>(descriptor->ParameterCount());
  369. @@ -2334,13 +2347,13 @@ const Operator* SimplifiedOperatorBuilder::FastApiCall(
  370. return zone()->New<Operator1<FastApiCallParameters>>(
  371. IrOpcode::kFastApiCall, Operator::kNoProperties, "FastApiCall",
  372. value_input_count, 1, 1, 1, 1, 2,
  373. - FastApiCallParameters(c_function, feedback, descriptor));
  374. + FastApiCallParameters(c_functions, feedback, descriptor));
  375. }
  376. // static
  377. int FastApiCallNode::FastCallArgumentCount(Node* node) {
  378. FastApiCallParameters p = FastApiCallParametersOf(node->op());
  379. - const CFunctionInfo* signature = p.c_function().signature;
  380. + const CFunctionInfo* signature = p.c_functions()[0].signature;
  381. CHECK_NOT_NULL(signature);
  382. return signature->ArgumentCount();
  383. }
  384. diff --git a/src/compiler/simplified-operator.h b/src/compiler/simplified-operator.h
  385. index 5cb305f8db8419bcaedc89dbd9d68226bcf90551..19cc23394d5dd729974ff4faf0e4f7cf54c4710e 100644
  386. --- a/src/compiler/simplified-operator.h
  387. +++ b/src/compiler/simplified-operator.h
  388. @@ -742,25 +742,35 @@ struct FastApiCallFunction {
  389. return address == rhs.address && signature == rhs.signature;
  390. }
  391. };
  392. +typedef ZoneVector<FastApiCallFunction> FastApiCallFunctionVector;
  393. class FastApiCallParameters {
  394. public:
  395. - explicit FastApiCallParameters(FastApiCallFunction c_function,
  396. + explicit FastApiCallParameters(const FastApiCallFunctionVector& c_functions,
  397. FeedbackSource const& feedback,
  398. CallDescriptor* descriptor)
  399. - : c_function_(c_function), feedback_(feedback), descriptor_(descriptor) {}
  400. + : c_functions_(c_functions),
  401. + feedback_(feedback),
  402. + descriptor_(descriptor) {}
  403. - FastApiCallFunction c_function() const { return c_function_; }
  404. + const FastApiCallFunctionVector& c_functions() const { return c_functions_; }
  405. FeedbackSource const& feedback() const { return feedback_; }
  406. CallDescriptor* descriptor() const { return descriptor_; }
  407. - const CFunctionInfo* signature() const { return c_function_.signature; }
  408. + const CFunctionInfo* signature() const {
  409. + DCHECK(!c_functions_.empty());
  410. + return c_functions_[0].signature;
  411. + }
  412. unsigned int argument_count() const {
  413. const unsigned int count = signature()->ArgumentCount();
  414. + DCHECK(base::all_of(c_functions_, [count](const auto& f) {
  415. + return f.signature->ArgumentCount() == count;
  416. + }));
  417. return count;
  418. }
  419. private:
  420. - FastApiCallFunction c_function_;
  421. + // A single FastApiCall node can represent multiple overloaded functions.
  422. + const FastApiCallFunctionVector c_functions_;
  423. const FeedbackSource feedback_;
  424. CallDescriptor* descriptor_;
  425. @@ -1233,9 +1243,9 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
  426. const Operator* Unsigned32Divide();
  427. // Represents the inputs necessary to construct a fast and a slow API call.
  428. - const Operator* FastApiCall(FastApiCallFunction c_function,
  429. - FeedbackSource const& feedback,
  430. - CallDescriptor* descriptor);
  431. + const Operator* FastApiCall(
  432. + const FastApiCallFunctionVector& c_candidate_functions,
  433. + FeedbackSource const& feedback, CallDescriptor* descriptor);
  434. #ifdef V8_ENABLE_CONTINUATION_PRESERVED_EMBEDDER_DATA
  435. const Operator* GetContinuationPreservedEmbedderData();
  436. diff --git a/src/compiler/turbofan-typer.cc b/src/compiler/turbofan-typer.cc
  437. index 811c9c5ab82ebbdf6ca14a2fd99c3b154609d506..f36916c1a0d39293f01eca84cac6ef83096cd25e 100644
  438. --- a/src/compiler/turbofan-typer.cc
  439. +++ b/src/compiler/turbofan-typer.cc
  440. @@ -1190,8 +1190,11 @@ Type Typer::Visitor::TypeCall(Node* node) { return Type::Any(); }
  441. Type Typer::Visitor::TypeFastApiCall(Node* node) {
  442. FastApiCallParameters const& op_params = FastApiCallParametersOf(node->op());
  443. + if (op_params.c_functions().empty()) {
  444. + return Type::Undefined();
  445. + }
  446. - const CFunctionInfo* c_signature = op_params.c_function().signature;
  447. + const CFunctionInfo* c_signature = op_params.c_functions()[0].signature;
  448. CTypeInfo return_type = c_signature->ReturnInfo();
  449. switch (return_type.GetType()) {
  450. diff --git a/src/compiler/turboshaft/fast-api-call-lowering-reducer.h b/src/compiler/turboshaft/fast-api-call-lowering-reducer.h
  451. index 2dec266f9e648391fe61a62931cca1ad20de719c..dc27e91ad0da93a5b68053f132f219f95f641ca1 100644
  452. --- a/src/compiler/turboshaft/fast-api-call-lowering-reducer.h
  453. +++ b/src/compiler/turboshaft/fast-api-call-lowering-reducer.h
  454. @@ -29,23 +29,41 @@ class FastApiCallLoweringReducer : public Next {
  455. base::Vector<const OpIndex> arguments,
  456. const FastApiCallParameters* parameters,
  457. base::Vector<const RegisterRepresentation> out_reps) {
  458. - FastApiCallFunction c_function = parameters->c_function;
  459. + const auto& c_functions = parameters->c_functions;
  460. const auto& c_signature = parameters->c_signature();
  461. const int c_arg_count = c_signature->ArgumentCount();
  462. DCHECK_EQ(c_arg_count, arguments.size());
  463. + const auto& resolution_result = parameters->resolution_result;
  464. Label<> handle_error(this);
  465. Label<Word32> done(this);
  466. Variable result = __ NewVariable(RegisterRepresentation::FromCTypeInfo(
  467. c_signature->ReturnInfo(), c_signature->GetInt64Representation()));
  468. - OpIndex callee = __ ExternalConstant(ExternalReference::Create(
  469. - c_function.address, ExternalReference::FAST_C_CALL));
  470. -
  471. + OpIndex callee;
  472. base::SmallVector<OpIndex, 16> args;
  473. for (int i = 0; i < c_arg_count; ++i) {
  474. + // Check if this is the argument on which we need to perform overload
  475. + // resolution.
  476. + if (i == resolution_result.distinguishable_arg_index) {
  477. + DCHECK_GT(c_functions.size(), 1);
  478. + // This only happens when the FastApiCall node represents multiple
  479. + // overloaded functions and {i} is the index of the distinguishable
  480. + // argument.
  481. + OpIndex arg_i;
  482. + std::tie(callee, arg_i) = AdaptOverloadedFastCallArgument(
  483. + arguments[i], c_functions, resolution_result, handle_error);
  484. + args.push_back(arg_i);
  485. + } else {
  486. CTypeInfo type = c_signature->ArgumentInfo(i);
  487. args.push_back(AdaptFastCallArgument(arguments[i], type, handle_error));
  488. + }
  489. + }
  490. +
  491. + if (c_functions.size() == 1) {
  492. + DCHECK(!callee.valid());
  493. + callee = __ ExternalConstant(ExternalReference::Create(
  494. + c_functions[0].address, ExternalReference::FAST_C_CALL));
  495. }
  496. // While adapting the arguments, we might have noticed an inconsistency that
  497. @@ -137,6 +155,56 @@ class FastApiCallLoweringReducer : public Next {
  498. }
  499. private:
  500. + std::pair<OpIndex, OpIndex> AdaptOverloadedFastCallArgument(
  501. + OpIndex argument, const FastApiCallFunctionVector& c_functions,
  502. + const fast_api_call::OverloadsResolutionResult& resolution_result,
  503. + Label<>& handle_error) {
  504. + Label<WordPtr, WordPtr> done(this);
  505. +
  506. + for (size_t func_index = 0; func_index < c_functions.size(); ++func_index) {
  507. + const CFunctionInfo* c_signature = c_functions[func_index].signature;
  508. + CTypeInfo arg_type = c_signature->ArgumentInfo(
  509. + resolution_result.distinguishable_arg_index);
  510. +
  511. + Label<> next(this);
  512. +
  513. + // Check that the value is a HeapObject.
  514. + GOTO_IF(__ ObjectIsSmi(argument), handle_error);
  515. +
  516. + switch (arg_type.GetSequenceType()) {
  517. + case CTypeInfo::SequenceType::kIsSequence: {
  518. + CHECK_EQ(arg_type.GetType(), CTypeInfo::Type::kVoid);
  519. +
  520. + // Check that the value is a JSArray.
  521. + V<Map> map = __ LoadMapField(argument);
  522. + V<Word32> instance_type = __ LoadInstanceTypeField(map);
  523. + GOTO_IF_NOT(__ Word32Equal(instance_type, JS_ARRAY_TYPE), next);
  524. +
  525. + OpIndex argument_to_pass = __ AdaptLocalArgument(argument);
  526. + OpIndex target_address = __ ExternalConstant(
  527. + ExternalReference::Create(c_functions[func_index].address,
  528. + ExternalReference::FAST_C_CALL));
  529. + GOTO(done, target_address, argument_to_pass);
  530. + break;
  531. + }
  532. + START_ALLOW_USE_DEPRECATED()
  533. + case CTypeInfo::SequenceType::kIsTypedArray:
  534. + UNREACHABLE();
  535. + END_ALLOW_USE_DEPRECATED()
  536. +
  537. + default: {
  538. + UNREACHABLE();
  539. + }
  540. + }
  541. +
  542. + BIND(next);
  543. + }
  544. + GOTO(handle_error);
  545. +
  546. + BIND(done, callee, arg);
  547. + return {callee, arg};
  548. + }
  549. +
  550. template <typename T>
  551. V<T> Checked(V<Tuple<T, Word32>> result, Label<>& otherwise) {
  552. V<Word32> result_state = __ template Projection<1>(result);
  553. diff --git a/src/compiler/turboshaft/graph-builder.cc b/src/compiler/turboshaft/graph-builder.cc
  554. index f24cd884bf7810aaed5e58b2044c2770653266f1..d79f6c801d2562a3cd65597d79050791fee3ad08 100644
  555. --- a/src/compiler/turboshaft/graph-builder.cc
  556. +++ b/src/compiler/turboshaft/graph-builder.cc
  557. @@ -1974,7 +1974,7 @@ OpIndex GraphBuilder::Process(
  558. DCHECK(dominating_frame_state.valid());
  559. FastApiCallNode n(node);
  560. const auto& params = n.Parameters();
  561. - FastApiCallFunction c_function = params.c_function();
  562. + const FastApiCallFunctionVector& c_functions = params.c_functions();
  563. const int c_arg_count = params.argument_count();
  564. base::SmallVector<OpIndex, 16> slow_call_arguments;
  565. @@ -2141,6 +2141,40 @@ OpIndex GraphBuilder::Process(
  566. Block* catch_block = Map(block->SuccessorAt(1));
  567. catch_scope.emplace(assembler, catch_block);
  568. }
  569. + // Overload resolution.
  570. + auto resolution_result =
  571. + fast_api_call::OverloadsResolutionResult::Invalid();
  572. + if (c_functions.size() != 1) {
  573. + DCHECK_EQ(c_functions.size(), 2);
  574. + resolution_result =
  575. + fast_api_call::ResolveOverloads(c_functions, c_arg_count);
  576. + if (!resolution_result.is_valid()) {
  577. + V<Object> fallback_result = V<Object>::Cast(__ Call(
  578. + slow_call_callee, dominating_frame_state,
  579. + base::VectorOf(slow_call_arguments),
  580. + TSCallDescriptor::Create(params.descriptor(), CanThrow::kYes,
  581. + LazyDeoptOnThrow::kNo,
  582. + __ graph_zone())));
  583. + Variable result =
  584. + __ NewVariable(RegisterRepresentation::FromCTypeInfo(
  585. + c_functions[0].signature->ReturnInfo(),
  586. + c_functions[0].signature->GetInt64Representation()));
  587. + convert_fallback_return(
  588. + result, c_functions[0].signature->GetInt64Representation(),
  589. + c_functions[0].signature->ReturnInfo().GetType(),
  590. + fallback_result);
  591. + V<Any> value = __ GetVariable(result);
  592. + if (is_final_control) {
  593. + // The `__ Call()` before has already created exceptional
  594. + // control flow and bound a new block for the success case. So we
  595. + // can just `Goto` the block that Turbofan designated as the
  596. + // `IfSuccess` successor.
  597. + __ Goto(Map(block->SuccessorAt(0)));
  598. + }
  599. + return value;
  600. + }
  601. + }
  602. +
  603. // Prepare FastCallApiOp parameters.
  604. base::SmallVector<OpIndex, 16> arguments;
  605. for (int i = 0; i < c_arg_count; ++i) {
  606. @@ -2150,8 +2184,8 @@ OpIndex GraphBuilder::Process(
  607. V<Context> context = Map(n.Context());
  608. - const FastApiCallParameters* parameters =
  609. - FastApiCallParameters::Create(c_function, __ graph_zone());
  610. + const FastApiCallParameters* parameters = FastApiCallParameters::Create(
  611. + c_functions, resolution_result, __ graph_zone());
  612. // There is one return in addition to the return value of the C function,
  613. // which indicates if a fast API call actually happened.
  614. diff --git a/src/compiler/turboshaft/operations.h b/src/compiler/turboshaft/operations.h
  615. index a26611708f2dd162e127d7a7c9af9135892d0b40..b04639190b239af92a2845886e5852080e6e454a 100644
  616. --- a/src/compiler/turboshaft/operations.h
  617. +++ b/src/compiler/turboshaft/operations.h
  618. @@ -6386,16 +6386,24 @@ struct Float64SameValueOp : FixedArityOperationT<2, Float64SameValueOp> {
  619. };
  620. struct FastApiCallParameters : public NON_EXPORTED_BASE(ZoneObject) {
  621. - FastApiCallFunction c_function;
  622. + const FastApiCallFunctionVector c_functions;
  623. + fast_api_call::OverloadsResolutionResult resolution_result;
  624. - const CFunctionInfo* c_signature() const { return c_function.signature; }
  625. + const CFunctionInfo* c_signature() const { return c_functions[0].signature; }
  626. - explicit FastApiCallParameters(FastApiCallFunction c_function)
  627. - : c_function(c_function) {}
  628. + FastApiCallParameters(
  629. + const FastApiCallFunctionVector& c_functions,
  630. + const fast_api_call::OverloadsResolutionResult& resolution_result)
  631. + : c_functions(c_functions), resolution_result(resolution_result) {
  632. + DCHECK_LT(0, c_functions.size());
  633. + }
  634. - static const FastApiCallParameters* Create(FastApiCallFunction c_function,
  635. - Zone* graph_zone) {
  636. - return graph_zone->New<FastApiCallParameters>(c_function);
  637. + static const FastApiCallParameters* Create(
  638. + const FastApiCallFunctionVector& c_functions,
  639. + const fast_api_call::OverloadsResolutionResult& resolution_result,
  640. + Zone* graph_zone) {
  641. + return graph_zone->New<FastApiCallParameters>(std::move(c_functions),
  642. + resolution_result);
  643. }
  644. };
  645. diff --git a/src/compiler/wasm-compiler.cc b/src/compiler/wasm-compiler.cc
  646. index 5ad805a11f7de73f06518ee3cf878ca492c0c652..2571f2800450cb8582198dc7cb7ef58311c52dae 100644
  647. --- a/src/compiler/wasm-compiler.cc
  648. +++ b/src/compiler/wasm-compiler.cc
  649. @@ -8356,13 +8356,19 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
  650. wasm::ObjectAccess::ToTagged(
  651. FunctionTemplateInfo::kCallbackDataOffset));
  652. - FastApiCallFunction c_function{c_address, c_signature};
  653. + FastApiCallFunctionVector fast_api_call_function_vector(mcgraph()->zone());
  654. + fast_api_call_function_vector.push_back({c_address, c_signature});
  655. Node* call = fast_api_call::BuildFastApiCall(
  656. - target->GetIsolate(), graph(), gasm_.get(), c_function,
  657. - api_data_argument,
  658. + target->GetIsolate(), graph(), gasm_.get(),
  659. + fast_api_call_function_vector, c_signature, api_data_argument,
  660. // Load and convert parameters passed to C function
  661. - [this, c_signature, receiver_node](int param_index,
  662. - GraphAssemblerLabel<0>*) {
  663. + [this, c_signature, receiver_node](
  664. + int param_index,
  665. + fast_api_call::OverloadsResolutionResult& overloads,
  666. + GraphAssemblerLabel<0>*) {
  667. + // Wasm does not currently support overloads
  668. + CHECK(!overloads.is_valid());
  669. +
  670. if (param_index == 0) {
  671. return gasm_->AdaptLocalArgument(receiver_node);
  672. }
  673. diff --git a/src/d8/d8-test.cc b/src/d8/d8-test.cc
  674. index 6467930fbb39a67a10d6822545e985965ced83ad..1c99e4d89cbc605c6c1b75ce31b09b67334a10ee 100644
  675. --- a/src/d8/d8-test.cc
  676. +++ b/src/d8/d8-test.cc
  677. @@ -443,6 +443,20 @@ class FastCApiObject {
  678. }
  679. }
  680. + static int32_t AddAllIntInvalidCallback(Local<Object> receiver,
  681. + int32_t arg_i32,
  682. + FastApiCallbackOptions& options) {
  683. + // This should never be called
  684. + UNREACHABLE();
  685. + }
  686. +
  687. + static int32_t AddAllIntInvalidOverloadCallback(
  688. + Local<Object> receiver, Local<Object> seq_arg,
  689. + FastApiCallbackOptions& options) {
  690. + // This should never be called
  691. + UNREACHABLE();
  692. + }
  693. +
  694. #ifdef V8_USE_SIMULATOR_WITH_GENERIC_C_CALLS
  695. static AnyCType Add32BitIntFastCallbackPatch(AnyCType receiver,
  696. AnyCType arg_i32,
  697. @@ -1553,6 +1567,22 @@ Local<FunctionTemplate> Shell::CreateTestFastCApiTemplate(Isolate* isolate) {
  698. signature, 1, ConstructorBehavior::kThrow,
  699. SideEffectType::kHasSideEffect, {add_all_overloads, 2}));
  700. + CFunction add_all_int_invalid_func =
  701. + CFunction::Make(FastCApiObject::AddAllIntInvalidCallback);
  702. + CFunction add_all_int_invalid_overload =
  703. + CFunction::Make(FastCApiObject::AddAllIntInvalidOverloadCallback);
  704. +
  705. + const CFunction add_all_invalid_overloads[] = {
  706. + add_all_int_invalid_func,
  707. + add_all_int_invalid_overload,
  708. + };
  709. + api_obj_ctor->PrototypeTemplate()->Set(
  710. + isolate, "add_all_invalid_overload",
  711. + FunctionTemplate::NewWithCFunctionOverloads(
  712. + isolate, FastCApiObject::AddAllSequenceSlowCallback, Local<Value>(),
  713. + signature, 1, ConstructorBehavior::kThrow,
  714. + SideEffectType::kHasSideEffect, {add_all_invalid_overloads, 2}));
  715. +
  716. CFunction add_all_32bit_int_8args_c_func = CFunction::Make(
  717. FastCApiObject::AddAll32BitIntFastCallback_8Args V8_IF_USE_SIMULATOR(
  718. FastCApiObject::AddAll32BitIntFastCallback_8ArgsPatch));
  719. diff --git a/test/mjsunit/compiler/fast-api-sequences.js b/test/mjsunit/compiler/fast-api-sequences.js
  720. index 6a982bbbfe13ae792a3d3a1d3376f71b6b00d38a..4318f60fc70f0a2684c6f233861e513063f8e542 100644
  721. --- a/test/mjsunit/compiler/fast-api-sequences.js
  722. +++ b/test/mjsunit/compiler/fast-api-sequences.js
  723. @@ -81,6 +81,30 @@ for (let i = 0; i < 100; i++) {
  724. ExpectFastCall(overloaded_test, 62);
  725. })();
  726. +// Test function with invalid overloads.
  727. +(function () {
  728. + function overloaded_test() {
  729. + return fast_c_api.add_all_invalid_overload(
  730. + [26, -6, 42]);
  731. + }
  732. +
  733. + %PrepareFunctionForOptimization(overloaded_test);
  734. + result = overloaded_test();
  735. + assertEquals(62, result);
  736. +
  737. + fast_c_api.reset_counts();
  738. + %OptimizeFunctionOnNextCall(overloaded_test);
  739. + result = overloaded_test();
  740. + assertEquals(62, result);
  741. + // Here we deopt because with this invalid overload:
  742. + // - add_all_int_invalid_func(Receiver, Bool, Int32, Options)
  743. + // - add_all_seq_c_func(Receiver, Bool, JSArray, Options)
  744. + // we expect that a number will be passed as 3rd argument
  745. + // (SimplifiedLowering takes the type from the first overloaded function).
  746. + assertUnoptimized(overloaded_test);
  747. + assertEquals(0, fast_c_api.fast_call_count());
  748. +})();
  749. +
  750. // ----------- Test different TypedArray functions. -----------
  751. // ----------- add_all_<TYPE>_typed_array -----------
  752. // `add_all_<TYPE>_typed_array` have the following signature:
  753. diff --git a/test/mjsunit/regress/regress-335548148.js b/test/mjsunit/regress/regress-335548148.js
  754. new file mode 100644
  755. index 0000000000000000000000000000000000000000..4725c48990767fc2a469a5ab3c04ba96e11bf54c
  756. --- /dev/null
  757. +++ b/test/mjsunit/regress/regress-335548148.js
  758. @@ -0,0 +1,29 @@
  759. +// Copyright 2024 the V8 project authors. All rights reserved.
  760. +// Use of this source code is governed by a BSD-style license that can be
  761. +// found in the LICENSE file.
  762. +
  763. +// Flags: --turbo-fast-api-calls --expose-fast-api --allow-natives-syntax --turbofan
  764. +// --always-turbofan is disabled because we rely on particular feedback for
  765. +// optimizing to the fastest path.
  766. +// Flags: --no-always-turbofan
  767. +// The test relies on optimizing/deoptimizing at predictable moments, so
  768. +// it's not suitable for deoptimization fuzzing.
  769. +// Flags: --deopt-every-n-times=0
  770. +// Flags: --fast-api-allow-float-in-sim
  771. +
  772. +const __v_0 = new d8.test.FastCAPI();
  773. +
  774. +function __f_0(__v_4, __v_5) {
  775. + try {
  776. + // Call the API function with an invalid parameter. Because of the invalid
  777. + // parameter the overload resolution of the fast API cannot figure out
  778. + // which function should be called, and therefore emits code for a normal
  779. + // API call.
  780. + __v_0.add_all_invalid_overload(__v_5, Object.prototype);
  781. + } catch (e) {}
  782. +}
  783. +
  784. +%PrepareFunctionForOptimization(__f_0);
  785. +__f_0(Number.MIN_VALUE, Number.MIN_VALUE);
  786. +%OptimizeFunctionOnNextCall(__f_0);
  787. +__f_0(Number.MIN_VALUE, Number.MIN_VALUE);