尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
V8 内置函数(Built-in Functions)完全指南:从 JavaScript 实现到 Runtime 与 CSA 的多种实现路径
V8 内置函数Built-in Functions完全指南从 JavaScript 实现到 Runtime 与 CSA 的多种实现路径【免费下载链接】v8The official mirror of the V8 Git repository项目地址: https://gitcode.com/gh_mirrors/v81/v8本文基于官方文档 docs/builtin-functions.md 编写深入剖析 V8 引擎中内置函数的多种实现形态为什么有的内置函数用 JavaScript 写、有的用 C 写、有的用汇编写以及它们之间如何协作。读完本文你将掌握 V8 内置函数的完整分类体系、%前缀运行时函数的调用机制、--allow-natives-syntax调试标志的用法以及如何在源码中定位每一种实现的入口点。一、什么是 V8 的 Built-in FunctionsV8 中JavaScript 标准库中的绝大多数功能如Array.prototype.map、Object.create、String.prototype.replace等并非由用户代码实现而是由 V8 引擎在启动时预先准备好的一系列内置函数built-ins提供。根据 docs/builtin-functions.md 的定义这些内置函数在实现方式上存在多种不同风格具体取决于其功能特性、性能要求以及部分历史演进因素。这意味着同样是内置函数Array.prototype.push和Object.create的底层实现可能完全不同——一个可能直接编译为机器码另一个可能走 C 运行时调用。理解这些差异是深入阅读 V8 源码、分析性能瓶颈和调试引擎行为的基础。从当前仓库的源码结构看内置函数的实现主要集中在以下两个目录src/runtime/存放运行时函数Runtime Functions的声明与实现核心入口是 src/runtime/runtime.hsrc/builtins/存放 built-ins 本身的实现包括 C 实现、CodeStubAssemblerCSA实现和架构相关汇编实现核心入口是 src/builtins/builtins.h。二、内置函数的第一种形态直接用 JavaScript 实现部分内置函数直接用 JavaScript 编写并在运行时像普通用户 JavaScript 一样被解析、编译为可执行代码。这类实现方式通常用于那些逻辑相对复杂、但对极致性能要求不那么苛刻的功能。这种做法的好处是开发效率高语义直观便于维护可以利用 V8 的优化编译器如 Maglev、TurboFan对其进行自动优化与用户代码共享同一套优化管线无需维护独立的底层实现。在仓库中这类用 JavaScript 编写的内置函数集中体现在 src/builtins/ 目录下的大量.tqTorque文件以及部分以 JavaScript 语义定义的 built-in 中。Torque 是 V8 的领域特定语言其输出会被编译为 CSA 代码或 Turboshaft reducer最终由 TurboFan 生成机器码——这既保留了像写 JS 一样写内置函数的开发体验又获得了接近手写汇编的性能。关于 Torque 的详细架构可参考 docs/builtins/architecture.md 与 docs/torque/architecture.md。三、第二种形态Runtime Functions运行时函数3.1 什么是 Runtime Functions部分内置函数的功能部分依赖于所谓的运行时函数runtime functions。运行时函数是用 C 编写的JavaScript 通过%前缀来调用它们。例如在 V8 内部代码中可以看到类似%ArraySpeciesConstructor(...)、%ThrowTypeError(...)的调用——这些都是运行时函数。它们的特点是拥有完整的 C 实现可以直接访问 V8 引擎的底层内部结构通过%前缀从 JavaScript 侧调用通常只限于 V8 内部 JavaScript 代码使用。3.2 完整的运行时函数清单所有运行时函数的声明集中维护在 src/runtime/runtime.h 中。该文件通过一组FOR_EACH_INTRINSIC_*宏按功能领域分类列出所有 intrinsic内置调用原语例如FOR_EACH_INTRINSIC_ARRAY数组相关如ArrayIndexOf、ArrayIsArray、GrowArrayElements等FOR_EACH_INTRINSIC_ATOMICSAtomics 相关如AtomicsLoad64、AtomicsStore64、AtomicsCompareExchange等FOR_EACH_INTRINSIC_BIGINTBigInt 相关如BigIntCompareToNumber、BigIntExponentiate等FOR_EACH_INTRINSIC_CLASSESclass 语义相关如DefineClass、LoadFromSuper、StoreToSuper等FOR_EACH_THROWING_INTRINSIC_CLASSES抛错类如ThrowConstructorNonCallableError、ThrowStaticPrototypeError等FOR_EACH_INTRINSIC_COMPILER编译器相关如CompileLazy、CompileBaseline、NotifyDeoptimized、ResolvePossiblyDirectEval等FOR_EACH_INTRINSIC_TIERING分层编译tiering相关如OptimizeMaglevEager、OptimizeTurbofanEager、StartMaglevOptimizeJob等FOR_EACH_INTRINSIC_DEBUG调试相关如CollectGarbage、DebugOnFunctionCall、HandleDebuggerStatement等FOR_EACH_INTRINSIC_FORINfor-in相关如ForInEnumerate、ForInHasPropertyFOR_EACH_INTRINSIC_FUNCTION函数相关如Call、FunctionGetSourceCode、FunctionGetScriptId等FOR_EACH_INTRINSIC_GENERATOR生成器/异步函数相关如AsyncFunctionAwait、AsyncFunctionEnter、CreateJSGeneratorObject等FOR_EACH_INTRINSIC_INTL国际化相关在V8_INTL_SUPPORT开启时生效如FormatList、StringToLowerCaseIntl等FOR_EACH_INTRINSIC_INTERNAL内部通用功能如AllocateInYoungGeneration、PerformMicrotaskCheckpoint、StackGuard、TerminateExecution、Typeof等。每个条目通过F(name, nargs, ressize)宏定义其中nameintrinsic 的名称nargs参数个数-1表示可变参数源码注释中会用/* 3 */这类形式标注下限ressize返回值个数绝大多数为 1返回一个 tagged pointer。// src/runtime/runtime.h 中的实际条目示例 F(ArrayIndexOf, 3, 1) // 3 个参数返回 1 个值 F(NewArray, -1 /* 3 */, 1) // 可变参数至少 3 个 F(ThrowTypeError, -1 /* 1 */, 1) // 可变参数至少 1 个 F(BigIntEqualToBigInt, 2, 1, RuntimeCallProperty::kCannotTriggerGC) // 额外声明不会触发 GC此外个别条目会附加RuntimeCallProperty::kCannotTriggerGC属性声明该调用不会触发垃圾回收编译器可据此做更激进的优化。3.3 Intrinsic 的两种暴露形式%与%_根据 src/runtime/runtime.h 头部注释每个 intrinsic 在 JavaScript 中有两种暴露形式%name总是一次运行时调用对应IntrinsicType::RUNTIME函数 ID 为Runtime::k##name%_name可选可以被编译器内联也可以退化为运行时调用由具体编译器决定对应IntrinsicType::INLINE函数 ID 为Runtime::kInline##name。无论哪种形式所有 intrinsic 都拥有一个 C 实现命名统一为Runtime_##name#define F(name, nargs, ressize, ...) \ Address Runtime_##name(int args_length, Address* args_object, \ Isolate* isolate); FOR_EACH_INTRINSIC_RETURN_OBJECT(F)而每个编译器Ignition、Sparkplug、Maglev、TurboFan都维护一份自己支持的 intrinsic 列表对于不支持内联的 intrinsic 会回退为普通运行时调用。同时Runtime::Function结构体src/runtime/runtime.h记录了每个 intrinsic 的function_id、类型、JS 名称、C 入口地址、参数个数与返回值个数整个运行时函数表可通过Runtime::RuntimeFunctionTable(isolate)获取。3.4%前缀的限制与--allow-natives-syntax标志这些运行时函数通常只限于 V8 内部 JavaScript 代码使用。出于调试目的如果 V8 以--allow-natives-syntax标志运行普通 JavaScript 代码中也可以调用它们。在 src/flags/flag-definitions.h 中可以找到该标志的定义DEFINE_BOOL(allow_natives_syntax, false, allow natives syntax) DEFINE_BOOL(allow_natives_for_differential_fuzzing, false, allow only natives explicitly allowlisted for differential fuzzing) DEFINE_IMPLICATION(allow_natives_for_differential_fuzzing, allow_natives_syntax) DEFINE_IMPLICATION(allow_natives_for_differential_fuzzing, fuzzing)要点默认值为false即普通构建下%语法不可用allow_natives_for_differential_fuzzing是更受限的变体只放行明确列入差分模糊测试白名单的 natives且开启它隐式开启allow_natives_syntax与fuzzing该标志主要用于 V8 自身的测试尤其是test/mjsunit/下的测试与差分模糊测试differential fuzzing。典型用法以 d8 运行# 允许在 JS 代码中使用 % 前缀调用运行时函数 d8 --allow-natives-syntax test.js # 调试标志与常用调试手段组合使用 d8 --allow-natives-syntax --trace-opt test.js在测试代码中常见做法是利用%OptimizeFunctionOnNextCall、%GetOptimizationStatus等 intrinsic 来手动触发并检查优化状态——Runtime::OptimizationStatus枚举src/runtime/runtime.h正是为这类检查设计的其中的位定义需要与test/mjsunit/mjsunit.js保持同步源码注释明确说明了这一点。这就是为什么 mjsunit 测试在头部通常会带上// Flags: --allow-natives-syntax这样的注释。注意Runtime::IsEnabledForFuzzing()src/runtime/runtime.h表明并非所有 intrinsic 都向 fuzzer 开放只有明确放行的子集才可用于差分模糊测试这与上面的allow_natives_for_differential_fuzzing标志的设计互相印证。3.5 运行时函数的入口签名所有运行时函数拥有统一的 C 入口签名且通过RUNTIME_FUNCTION宏展开定义于 src/runtime/runtime.cc 附近Address Runtime_##name(int args_length, Address* args_object, Isolate* isolate);其中args_length为参数数量args_object为参数数组isolate为当前隔离区。runtime.h中还提供了一系列查询接口例如Runtime::NeedsExactContext(id)判断是否依赖当前上下文、Runtime::IsNonReturning(id)判断是否必定抛异常永不正常返回、Runtime::MayAllocate(id)判断是否可能触发堆分配这些元信息被编译器和 GC 相关逻辑广泛使用。四、第三种形态Built-ins 的多种实现方式除 JavaScript 实现和 runtime functions 之外另一些函数被实现为built-ins而 built-ins 本身又有数种不同的实现手段。根据 docs/builtin-functions.md 与 docs/builtins/architecture.md 的归纳主要有以下几种。4.1 平台相关汇编实现Architecture-Specific Assembler部分 built-ins直接用平台相关的汇编assembly实现。这类实现位于 src/builtins/ 下的架构子目录中例如x64、arm64、ia32、riscv、mips64、loong64、ppc、s390等对应src/builtins/[arch]/builtins-[arch].cc。它们通过 V8 的MacroAssembler直接发射原始机器指令用于底层入口点entry points与跳板trampolines需要操纵调用栈的操作压栈参数、建立解释器栈帧等——因为 TurboFan 生成的代码假定固定的栈布局这类操作只能用架构相关 built-in 完成对每条指令都极为敏感的热点路径。代价是必须为每个支持的架构分别编写。在 src/builtins/builtins-definitions.h 中这类 built-in 用ASM(name, interface_descriptor)宏登记例如反优化入口ASM(DeoptimizationEntry_Eager, DeoptimizationEntry)、写屏障TFC(RecordWriteSaveFP, WriteBarrier)等。4.2 CodeStubAssemblerCSA实现还有一部分 built-ins 使用CodeStubAssemblerCSA实现——一个平台无关的抽象层。CSA 提供一套 C API用编程方式直接发射 TurboFan 图节点如Parameter、Load、Branch、CallRuntime绕过了 JavaScript 的解析器和 AST最终由 TurboFan 后端生成机器码。CSA 的实现文件命名规律为builtins-*-gen.cc/builtins-*.h位于 src/builtins/。在 src/builtins/builtins-definitions.h 中CSA/TurboFan built-ins 按链接约定分为宏含义参数说明CPP纯 C built-in通过BUILTIN_EXITframe 进入name, formal parameter countTFJTurboFan 实现JS 链接可作为 JavaScript 函数调用name, formal parameter count, explicit argument names...TFSTurboFan 实现CodeStub 链接name, needs context, explicit argument names...TFCTurboFan 实现CodeStub 链接且带自定义描述符name, interface descriptorTFHTurboFan 实现的处理器handlerCodeStub 链接name, interface descriptorBCH字节码处理器bytecode handler带字节码分发链接name, OperandScale, BytecodeASM平台相关汇编 built-inname, interface descriptor同类的TFJ_TSA、TFC_TSA、BCH_TSA则是使用Turboshaft Assembler定义的版本V8 正逐步从 CSA 迁移到 Turboshaft参见 docs/builtins/architecture.md。built-ins 有时也被用来实现胶水代码glue code片段而不一定是完整函数。例如 src/builtins/builtins-definitions.h 中的LOAD_IC_HANDLER_LIST、LOAD_IC_IN_OBJECT_FIELD_WITH_INDEX_HANDLER_LIST等宏生成的是大量内联缓存IC处理器——它们不是标准库函数而是执行属性加载/存储的微型代码片段每个对应一种字段布局如 in-object 非 double 字段、out-of-object 字段、来自原型的常量等。这正是官方文档所说glue code不一定是完整函数的典型例证。4.3 纯 C 实现还有一部分 built-ins直接用 C 实现。这类函数以BUILTIN(Name)宏定义例如 src/builtins/builtins-array.cc 中的BUILTIN(ArrayPrototypeFill) { ... } // src/builtins/builtins-array.cc BUILTIN(ArrayPush) { ... } BUILTIN(ArrayPop) { ... } BUILTIN(ArrayShift) { ... } BUILTIN(ArrayUnshift) { ... } BUILTIN(ArrayConcat) { ... }纯 C built-in 的优缺点优点最容易编写拥有完整 C 标准库访问权限可以触及 V8 复杂的内部结构堆、句柄、对象布局等缺点由于需要在 JS 与 C 之间跨边界boundary crossing性能通常低于 Torque/CSA 实现。4.4 Builtins 的完整清单与枚举所有 built-ins 的完整清单由 src/builtins/builtins-definitions.h 中的BUILTIN_LIST(...)宏家族汇总它同时引入bytecodes-builtins-list.h与torque-generated/builtin-definitions.h而 src/builtins/builtins.h 则通过BUILTIN_LIST展开出enum class Builtin枚举并为每个枚举值提供k##Name形式enum class Builtin : int32_t { kNoBuiltinId -1, #define DEF_ENUM(Name, ...) k##Name, BUILTIN_LIST(DEF_ENUM, ...) #undef DEF_ENUM kFirstBytecodeHandler ..., kFirstLoadICHandler ..., kLastLoadICHandler kFirstLoadICHandler kBuiltinLoadICHandlerCount - 1 };同时src/builtins/builtins.h 提供便捷宏BUILTIN_CODE(isolate, name)用于在 C 侧获取指定 built-in 的 code handle#define BUILTIN_CODE(isolate, name) \ (isolate)-builtins()-code_handle(i::Builtin::k##name)Builtins类src/builtins/builtins.h负责管理这些 built-in 的加载、反汇编支持Lookup(Address pc)以及 tier0/tier1 分层kBuiltinCount、kBuiltinTier0Count等常量。tier0 built-in保证靠近 root register可以被高效地以 root-relative 方式调用src/builtins/builtins-definitions.h 明确指出 tier0 集合必须尽可能小且不应随意新增。五、Built-ins 的加载与嵌入机制built-ins 在V8 构建过程中或不使用快照时的启动过程中被编译并存储于**快照Snapshot**中从而保证 V8 启动时所有标准库函数已就绪无需在运行时解析和编译它们。同时同一进程内的所有 Isolate 与 context共享这些 built-ins参见 docs/builtins/architecture.md。为了降低启动时间并支持多 Isolate 间的内存共享V8 将 built-ins嵌入二进制文件Embedded Blobbuilt-ins 被编译并写入二进制的一个专用段embedded blob共享同一进程的多个 Isolate 共享同一份内置可执行代码节省内存。在某些条件下V8 会把嵌入的 built-ins复制或重映射remap到某个 Isolate 的CodeRange中在 x64、arm64 等架构上函数调用只有有限的相对寻址范围。如果CodeRange中生成的代码需要调用 built-in而 embedded blob 在内存中距离太远就无法使用高效的 PC 相对调用当v8_flags.short_builtin_calls开启通常取决于可用物理内存时V8 会把这些 built-ins 复制/重映射到CodeRange中使其靠近生成的代码若操作系统支持页重映射则采用remap保持共享避免制造私有脏页否则退化为memcpy 复制会增加私有内存占用。六、总结如何选择实现方式综合 docs/builtin-functions.md 与 docs/builtins/architecture.md 的说明可以总结出 V8 内置函数实现方式的选择逻辑实现方式代表位置优点缺点典型用途JavaScript含 Torquesrc/builtins/*.tq开发效率高、语义直观、可被优化管线优化需要经过解析/编译标准库方法的主体逻辑Runtime FunctionsCsrc/runtime/runtime.cc及runtime.h声明完整访问引擎内部、实现复杂语义JS/C 边界开销抛错、GC 触发、编译器辅助等CodeStubAssembler / Turboshaftsrc/builtins/builtins-*-gen.cc平台无关、高性能、贴近底层编写门槛高热点内建方法、IC 处理器、胶水代码平台相关汇编src/builtins/[arch]/builtins-[arch].cc极致性能、可精确操控栈每个架构都要写一份入口点、跳板、栈帧操作纯 CBUILTIN 宏src/builtins/builtins-*.cc最容易写、功能完整跨边界性能较差复杂但不极热的标准库函数因此built-ins 以多种方式实现并非历史包袱而是 V8 在开发效率、平台独立性、性能与底层控制力之间做出的工程权衡。理解这条主线之后再去看 src/builtins/ 和 src/runtime/ 目录下的源码就能快速判断每个函数背后的实现路径与性能特征。延伸阅读docs/builtins/architecture.mdbuilt-ins 架构的深入说明四种 flavor、加载与嵌入机制src/builtins/builtins.hBuiltin枚举与Builtins类src/builtins/builtins-definitions.h全部 built-in 的宏清单CPP/TFJ/TFS/TFC/TFH/BCH/ASM 分类src/runtime/runtime.h全部运行时函数intrinsic的宏清单与Runtime::Function结构docs/torque/architecture.mdTorque 语言架构docs/codegen/code-stub-assembler.mdCodeStubAssembler 详解src/flags/flag-definitions.h--allow-natives-syntax等调试标志定义。【免费下载链接】v8The official mirror of the V8 Git repository项目地址: https://gitcode.com/gh_mirrors/v81/v8创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

TensorFlow.js WebGPU 后端(tfjs-backend-webgpu)使用指南:安装、算子支持与性能调优

TensorFlow.js WebGPU 后端(tfjs-backend-webgpu)使用指南:安装、算子支持与性能调优

人工智能机器学习深度学习前端后端 【免费下载链接】tfjs A WebGL accelerated JavaScript library for training and deploying ML models. 项目地址: https://gitcode.com/gh_mirrors/tf/tfjs 点击查看 免费下载 本指南以 tfjs-backend-webgpu/README.md 为主体&…

📅 2026/9/20 22:51:46
AquaPulse:边缘AI如何实现管道漏水实时检测与预警

AquaPulse:边缘AI如何实现管道漏水实时检测与预警

1. 从一根漏水的水管说起:AquaPulse 到底想解决什么问题城市供水管网有个很反直觉的事实:漏损率长期居高不下,很多老城区的管网漏损能到20%甚至更高。也就是说,水厂送出去十吨水,有两吨在到达用户水表之前就已经渗进地…

📅 2026/9/20 22:46:45
Claude Code vs Codex:同一把 TaoToken Key 跑 gin 仓库中间件重构

Claude Code vs Codex:同一把 TaoToken Key 跑 gin 仓库中间件重构

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/20 22:46:45
MORE NEWS

更多资讯

📰

IsaacLab实战:Franka抓方块三步跑通,奖励函数一次调明白

IsaacLab实战:Franka抓方块三步跑通,奖励函数一次调明白 【免费下载链接】IsaacLab Unified framework for robot learning with multi-physics/renderer support 项目地址: https://gitcode.com/GitHub_Trending/is/IsaacLab 想让Franka夹爪稳稳…

📰

Atlas 300V 24G部署YOLOv8实战:NPU推理加速卡与OM模型转换全指南

先说实话,我第一次拿到Atlas 300V 24G这张卡的时候,心里冒出的问题和热搜里那位基本一样:这玩意到底算不算运算加速卡?插上去能不能像普通显卡一样把YOLO跑起来?我当时的处境是这样的:手头有一批YOLOv8检测…

📰

Lucky物联网对接指南:3步实现语音控制智能家居

Lucky物联网对接指南:3步实现语音控制智能家居 【免费下载链接】lucky 软硬路由公网神器,ipv6/ipv4 端口转发,反向代理,DDNS,WOL,ipv4 stun内网穿透,cron,acme,rclone,ftp,webdav,filebrowser 项目地址: https://gitcode.com/GitHub_Trending/luc/lucky 家里…

📰

无人值守直播人物检测实战:YOLO模型与MEDAI V2状态机解析

1. 无人值守直播的真正难题:镜头"看人"与"认人"的差异做无人值守直播,技术上有两件完全不同的麻烦事:一是怎么把画面稳定地推出去,二是怎么让机器知道"现在该播什么"。前者是流媒体工程&#xff0c…

📰

【EDA软件】【联合Modelsim仿真使用方法】

背景业界EDA工具仿真功能是必备的,例如Vivado自带仿真工具,且其无需联合外部仿真工具,当然也可以联合外部工具,例如MoodelSim。FUXI没有独立的仿真功能,需要联合第三方软件,Modelsim是常用的第三方软件。方…

📰

从零用MATLAB实现元胞自动机森林火灾模拟:规则、可视化与参数扫描

简介:基于元胞自动机的森林火灾模拟MATLAB代码包,面向本科、硕士阶段需要理解元胞自动机建模与仿真应用的教研学习者,可用于课程设计或算法演示。资源内含2个文件,包含一个实现森林火灾传播规则的MATLAB主程序以及对应的效果示意图…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬