菜单

WebAssembly 后端

相关源文件

本文档描述了 Kotlin WebAssembly (Wasm) 后端,该后端能够将 Kotlin 代码编译为 WebAssembly。Wasm 后端将 Kotlin IR (中间表示) 转换为 WebAssembly IR,然后再转换为二进制或文本格式。本页重点介绍后端本身的实现细节,而不是如何作为开发者使用 Kotlin/Wasm。

架构概述

WebAssembly 后端作为 Kotlin 编译器后端基础设施的一部分实现,将 Kotlin IR 转换为 WebAssembly 模块。它包含代码生成、序列化和优化组件。

高层架构

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compilerWithIC.kt compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleFragmentGenerator.kt compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt

编译管道

WebAssembly 后端遵循以下主要步骤将 Kotlin IR 转换为 WebAssembly

  1. 简化 IR:应用针对 WebAssembly 的专门简化
  2. 生成 Wasm IR:将 Kotlin IR 转换为 WebAssembly IR
  3. 优化:执行类似垃圾回收(Dead Code Elimination)的优化
  4. 序列化:转换为二进制或文本格式

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleFragmentGenerator.kt compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt

核心组件

WasmCompiledFileFragment

这是表示已编译的 WebAssembly 模块片段的核心数据结构。它包含生成 WebAssembly 代码所需的所有必要信息。

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt51-78

声明生成器

DeclarationGenerator 负责将 Kotlin IR 声明(类、函数、属性)转换为 WebAssembly 声明。

主要职责

  • 从 Kotlin IR 函数生成函数类型
  • 为类字段创建 Wasm 全局变量
  • 为类继承构建虚函数表 (vtables)
  • 处理运行时类型信息 (RTTI)

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/DeclarationGenerator.kt

Body 生成器

BodyGenerator 将 Kotlin IR 函数体转换为 WebAssembly 指令。它处理各种 Kotlin 结构,例如

  • 函数调用
  • 控制流(if/else、循环、try/catch)
  • 字段访问
  • 类型操作

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt

模块元数据缓存

WasmModuleMetadataCache 维护编译期间所需的 Kotlin 类和接口信息

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmModuleCodegenContext.kt196-213

函数上下文

WasmFunctionCodegenContext 跟踪与正在编译的特定函数相关的信息

  • 局部变量和参数
  • 循环控制信息
  • 临时变量

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmFunctionCodegenContext.kt

序列化和二进制格式

WebAssembly 后端包含序列化组件,用于在内存表示和二进制/文本格式之间进行转换。

WasmSerializer

WasmSerializer 将 WebAssembly IR 转换为二进制格式,它实现了一种复杂的引用表方法来处理共享对象。

主要功能

  • 用于去重化的引用表
  • 用于多态类型的类型标签编码
  • 用于布尔字段的标志位集

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/serialization/WasmSerializer.kt

WasmDeserializer

WasmDeserializer 从二进制格式中重建 WebAssembly IR。它是序列化器的精确反操作。

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/serialization/WasmDeserializer.kt

序列化过程遵循以下顺序

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/serialization/WasmSerializer.kt compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/serialization/WasmDeserializer.kt

WebAssembly 模块结构

最终的 WebAssembly 模块包含几个关键部分

章节目的
类型函数、结构和数组类型声明
导入从 JS 导入的外部函数、内存和标签
功能函数声明
表格函数表(用于动态分派)
内存线性内存声明
全局全局变量声明
导出暴露给宿主环境的项
代码包含 WebAssembly 指令的函数实现
数据静态数据段

来源: wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt97-198

JavaScript 互操作性

WebAssembly 后端支持 JavaScript 互操作性,这对于 Web 应用程序至关重要。

JS 外部函数

对于外部 JavaScript 函数,后端会创建适当的包装器和适配器

后端会创建专门的适配器来处理 Kotlin 和 JavaScript 之间的类型转换

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsInteropFunctionsLowering.kt compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/ComplexExternalDeclarationsToTopLevelFunctionsLowering.kt

JS 导出

后端支持使用 @JsExport 注解导出 Kotlin 函数到 JavaScript。这会在 WebAssembly 模块中创建适当的导出声明。

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsInteropFunctionsLowering.kt

链接和模块初始化

生成最终的 WebAssembly 模块时,后端会执行几项重要任务

  1. 符号绑定:解析片段中未绑定的符号
  2. 字段初始化:为全局字段生成初始化代码
  3. 主初始化函数:创建一个用于初始化模块的函数
  4. 异常处理:设置异常标签处理
  5. RTTI:生成运行时类型信息

主初始化函数在正确初始化模块方面起着关键作用

_initialize():
  1. Call kotlin.Unit_getInstance()
  2. Call _fieldInitialize() to initialize all global fields
  3. Call main function wrappers (if present)

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt140-222 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/WasmCompiledModuleFragment.kt477-458

异常处理

WebAssembly 后端支持两种基于 WebAssembly 异常处理提案的异常处理方法

  1. 新异常提案:使用 try_tablecatch
  2. 旧异常提案:使用更简单的 try/catch 机制
  3. 陷阱(Trap)回退:如果配置为使用陷阱而不是异常

异常处理适应目标 WebAssembly 环境的功能

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/BodyGenerator.kt190-432

死代码消除

WebAssembly 后端实现了垃圾回收(Dead Code Elimination, DCE)以通过移除未使用的代码来减小生成模块的大小

  1. 标记阶段:识别根声明(导出、入口点)并将其标记为可达
  2. 跟踪阶段:递归标记可达声明使用的所有声明
  3. 清除阶段:移除所有未标记的声明

DCE 通过消除运行时不需要的代码,显著减小了二进制文件的大小。

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/dce/Dce.kt

增量编译

WebAssembly 后端通过 IC (Incremental Compilation) 基础设施支持增量编译

这使得在开发过程中只重新编译更改的文件变得高效。

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compilerWithIC.kt24-60 compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ic/IrFactoryImplForWasmIC.kt

Lowerings

WebAssembly 后端应用了若干专门的 lowering 来适配 Kotlin IR 到 WebAssembly。

Lowering目的
ComplexExternalDeclarationsToTopLevelFunctionsLowering将外部声明转换为顶层函数
JsInteropFunctionsLowering为 JS 互操作创建适配器
WasmTypeOperatorLowering处理类型操作,如 instanceof
BuiltInsLowering将内建函数替换为 WebAssembly 等效项
UnitToVoidLowering在适当的情况下将 Unit 返回类型转换为 void

来源: compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/ComplexExternalDeclarationsToTopLevelFunctionsLowering.kt compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsInteropFunctionsLowering.kt compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/WasmTypeOperatorLowering.kt compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/BuiltInsLowering.kt compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/UnitToVoidLowering.kt

结论

Kotlin WebAssembly 后端是一个复杂的编译器组件,它使 Kotlin 代码能够在 WebAssembly 目标上运行。它负责从 Kotlin IR 到 WebAssembly 模块的完整编译管线,并提供对 JavaScript 互操作、异常处理和优化的专门支持。

该后端在设计上考虑了模块化,将声明生成、体生成和序列化等关注点分离开来。这种架构有利于随着 WebAssembly 的发展来维护和扩展后端。