快速 API 调用路径


🌐 Fast API call path

Fast API 调用路径将封装器绑定为 V8 Fast API 函数。当 JavaScript 代码调用这个封装器并被 V8 优化时,调用会从优化后的代码直接进入一个小型的本地跳板——这是 Node.js 在创建函数时为精确签名生成的。这个跳板会把参数移动到本地符号期望的寄存器中并调用它。对于标量入口点,C++ 中没有中间的参数转换。

🌐 The Fast API call path binds the wrapper as a V8 Fast API function. When JavaScript code calling the wrapper is optimized by V8, the call goes from the optimized code straight into a small native trampoline that Node.js generates for the exact signature when the function is created. The trampoline moves the arguments into the registers expected by the native symbol and calls it. For the scalar entry point, there is no intermediate argument conversion in C++.

这个路径上的函数也保持了一个常规的本地入口点。来自 V8 未优化的代码,或者 V8 取消优化的代码的调用,会使用那个入口点,它的行为就像 通用调用路径。这对调用方来说是透明的。

🌐 Functions on this path keep a conventional native entry point as well. Calls from code that V8 has not optimized, or that V8 deoptimizes, use that entry point, which behaves like the generic call path. This is transparent to the caller.

在 trampoline 运行之前,类似指针的参数会在 JavaScript 中准备好:

🌐 Pointer-like arguments are prepared in JavaScript before the trampoline runs:

  • null 和 undefined 变成了空指针。
  • string 的值会被复制到临时的 NUL 结尾 UTF-8 缓冲区中,以便在调用期间使用。
  • Buffer、类型化数组、DataView 和 ArrayBuffer 的值会被转换为原始指针 bigint 的值,除非下面描述的备用入口点处理它们。
  • bigint 的值会保持不变地传递。

对于只带有单个 pointer、buffer 或 arraybuffer 参数的签名,Node.js 还会创建一个备用的快速 API 入口点,可以直接接收 Buffer、类型化数组、DataView 和 ArrayBuffer 值。当参数是这样的值时,JavaScript 封装器会将调用分派给它,而本地辅助程序则直接从后端存储中提取指针,而不是在 JavaScript 中转换值。

🌐 For signatures with a single pointer, buffer, or arraybuffer argument, Node.js also creates an alternate Fast API entry point that receives Buffer, typed array, DataView, and ArrayBuffer values directly. The JavaScript wrapper dispatches to it when the argument is such a value, and a native helper extracts the pointer from the backing store instead of converting the value in JavaScript.

只有在满足以下所有条件时,函数才会使用此调用路径:

🌐 A function uses this call path only when all of the following conditions are met:

  • 该进程在支持的 64 位架构上运行:AArch64、x86-64、PPC64LE、LoongArch64、RISC-V 64 或 s390x。32 位平台和大端的 PPC64 总是使用另一条调用路径。
  • 这个过程可以分配可执行内存。Node.js 每个进程会检查一次是否可以分配内存并标记为可执行。如果检查失败,这条路径在整个进程中都会被禁用。
  • 返回类型和任何参数类型都不是 function。
  • 这个签名最多有 8 个参数,并且每个参数都能放在当前平台上 trampoline 可用的参数寄存器里。必须传到原生栈上的参数是不支持的。

寄存器限制是特定于平台的。整数和类似指针的参数共享一组寄存器,浮点参数共享另一组。每种架构的限制列在 类型名称 中。

🌐 The register limits are platform-specific. Integer and pointer-like arguments share one set of registers, and floating-point arguments share another. The limits for each architecture are listed in Type names.

未通过这些检查的签名并不是错误。该函数会在下一个支持它的调用路径上被创建。

🌐 A signature that fails any of these checks is not an error. The function is created on the next call path that supports it.