基于 Dart SDK 源码分析
Kernel 是 Dart 的中间表示 (IR),用于编译器和运行时之间传递程序信息
| 格式 | 扩展名 | 用途 |
|---|---|---|
| Kernel Binary | .dill | 编译产物,VM 加载 |
| Kernel AST | - | 内存中的抽象语法树 |
| Kernel Text | .txt | 调试用的文本格式 |
.dill 文件 (Kernel Binary)
│
├── Magic Number (0x90ABCDEF)
├── Version Information
│
├── String Table
│ └── 所有字符串常量
│
├── Canonical Name Table
│ └── 符号引用
│
├── Library List
│ ├── Library 1
│ │ ├── Class List
│ │ ├── Procedure List
│ │ └── Field List
│ └── Library 2 ...
│
├── Constant Pool
│ └── 所有常量值
│
└── Type Table
└── 所有类型定义
| 区域 | 内容 | 大小 |
|---|---|---|
| Header | 魔数、版本 | 固定 |
| String Table | 字符串池 | 可变 |
| Canonical Names | 符号表 | 可变 |
| Libraries | 库定义 | 可变 |
| Constants | 常量池 | 可变 |
使用变长整数编码减少文件体积
TreeNode (基类)
│
├── Library (库)
│ ├── Class (类)
│ │ ├── Constructor (构造函数)
│ │ ├── Procedure (方法)
│ │ └── Field (字段)
│ │
│ ├── Procedure (顶级函数)
│ └── Field (顶级变量)
│
├── Expression (表达式)
│ ├── VariableGet
│ ├── PropertyGet
│ ├── MethodInvocation
│ └── ...
│
└── Statement (语句)
├── Block
├── IfStatement
├── ForStatement
└── ...
class Library extends NamedNode {
final StringReference importUri;
final StringReference name;
final List<Class> classes;
final List<Field> fields;
final List<Procedure> procedures;
final List<LibraryDependency> dependencies;
// 导入的其他库
}
class Class extends NamedNode {
final Library enclosingLibrary;
final StringReference name;
final List<TypeParameter> typeParameters; // 泛型参数
final Supertype? superType; // 父类
final List<Supertype> implementedTypes; // 接口
final List<Field> fields;
final List<Constructor> constructors;
final List<Procedure> procedures;
}
class Procedure extends NamedNode {
final Name name;
final ProcedureKind kind;
// Method, Getter, Setter, Operator, Factory
final FunctionNode function;
// 函数体和参数
final List<TypeParameter> typeParameters;
// 泛型方法参数
}
| 类型 | Kernel 类 | 示例 |
|---|---|---|
| 基础类型 | InterfaceType | int, String |
| 泛型类型 | InterfaceType | List<int> |
| 类型参数 | TypeParameterType | T, S |
| 函数类型 | FunctionType | void Function(int) |
| 可空类型 | NullableType | String? |
| Never | NeverType | Never |
常量池存储所有编译时常量,减少重复
源码:runtime/vm/kernel_loader.cc
KernelLoader 负责解析 Kernel 二进制文件并创建 VM 运行时对象
class KernelLoader {
static ErrorPtr LoadProgram(
const uint8_t* buffer,
intptr_t buffer_size,
);
static ErrorPtr LoadLibrary(
const Library& library,
);
}
.dill 文件
│
▼
┌─────────────────┐
│ Read Header │ 读取魔数和版本
└────────┬────────┘
│
▼
┌─────────────────┐
│ Read Strings │ 加载字符串表
└────────┬────────┘
│
▼
┌─────────────────┐
│ Read Names │ 加载符号表
└────────┬────────┘
│
▼
┌─────────────────┐
│ Read Libraries │ 加载所有库
└────────┬────────┘
│
▼
┌─────────────────┐
│ Link Types │ 解析类型引用
└─────────────────┘
ErrorPtr KernelLoader::ReadProgram(
const uint8_t* buffer,
intptr_t size,
) {
// 1. 解析 Header
Reader reader(buffer, size);
auto magic = reader.ReadUInt32();
if (magic != kMagicNumber) {
return ILLEGAL_ARGUMENT;
}
// 2. 读取字符串表
reader.ReadStringTable();
// 3. 读取库列表
for (auto lib : libraries) {
ReadLibrary(lib);
}
}
void ReadLibrary(const Library& lib) {
// 1. 创建 VM Library 对象
auto vm_lib = Library::Handle();
vm_lib = Library::New(url, name);
// 2. 加载类
for (auto cls : lib.classes) {
ReadClass(cls, vm_lib);
}
// 3. 加载顶级成员
for (auto proc : lib.procedures) {
ReadProcedure(proc, vm_lib);
}
}
void ReadClass(const Class& cls, Library& lib) {
// 1. 创建 VM Class 对象
auto vm_cls = Class::New(lib, name);
// 2. 设置父类和接口
vm_cls.set_super_type(ReadType(cls.superType));
// 3. 加载字段
for (auto field : cls.fields) {
ReadField(field, vm_cls);
}
// 4. 加载方法
for (auto proc : cls.procedures) {
ReadProcedure(proc, vm_cls);
}
}
void ReadProcedure(
const Procedure& proc,
Class& owner,
) {
// 1. 创建 Function 对象
auto func = Function::New(
name,
kind, // Method, Getter, Setter
owner,
);
// 2. 设置签名
func.set_signature(ReadSignature(proc.function));
// 3. 延迟加载函数体
// 函数体在首次调用时编译
}
类型解析需要延迟处理,因为类型可能引用尚未加载的类
TypePtr ReadType(const DartType& type) {
switch (type.kind) {
case Interface:
return InterfaceType::New(
klass,
type_args,
);
case TypeParameter:
return TypeParameterType::New(param);
case Function:
return FunctionType::New(signature);
}
}
Hot Reload 使用增量 Kernel只加载修改的部分
ErrorPtr ReloadSources(
IsolateGroup* group,
const uint8_t* kernel_bytes,
intptr_t kernel_size,
) {
// 1. 加载增量 Kernel
auto delta = ReadDelta(kernel_bytes);
// 2. 更新修改的类
for (auto cls : delta.modified_classes) {
UpdateClass(cls);
}
// 3. 迁移现有实例
MorphInstances();
}
增量 Kernel (.dill)
│
▼
┌──────────────────┐
│ Parse Delta │ 解析增量部分
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Compare Classes │ 对比新旧类定义
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Create Mapping │ 创建字段映射
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Morph Instances │ 变换现有实例
└──────────────────┘
源码:runtime/vm/instance_morpher.cc
InstanceMorpher 负责将旧类实例变形为新类实例
Become 是 Dart VM 的指针置换机制
// Become 核心操作
void Become::ElementsForward(
const Array& old_arr,
const Array& new_arr,
) {
// 将所有指向 old_arr[i] 的指针
// 替换为指向 new_arr[i]
// 这包括:
// - 堆中的引用
// - 栈中的引用
// - 全局变量
}
| 修改类型 | 迁移策略 |
|---|---|
| 添加字段 | 新字段初始化为 null/默认值 |
| 删除字段 | 字段值被丢弃 |
| 重命名字段 | 值迁移到新位置 |
| 修改类型 | 尝试转换,失败则为 null |
| 调整顺序 | 按映射重新排列 |
以下修改无法通过 Hot Reload完成,需要 Hot Restart
每个 Isolate 都有独立的Kernel 加载状态
IsolateGroup 共享只读 Kernel 数据
┌─────────────────────────────────────┐ │ IsolateGroup │ │ ┌─────────────────────────────┐ │ │ │ Shared Kernel Data │ │ │ │ (classes, constants, ...) │ │ │ └───────────┬─────────────────┘ │ │ │ │ │ ┌──────────┴──────────┐ │ │ │ │ │ │ ▼ ▼ │ │ Isolate 1 Isolate 2 │ │ (独立堆) (独立堆) │ └─────────────────────────────────────┘
// IsolateGroup 共享机制
class IsolateGroup {
// 共享的 Kernel 程序
Program* shared_program_;
// 共享的类对象
ClassTable* shared_class_table_;
// 每个 Isolate 的独立数据
void ForEachIsolate([&](Isolate* isolate) {
// 处理独立堆
});
}
| 数据类型 | 存储位置 | 共享 |
|---|---|---|
| Kernel 二进制 | 只读内存 | ✅ |
| Class 对象 | 只读堆 | ✅ |
| 常量对象 | 只读堆 | ✅ |
| 实例对象 | 普通堆 | ❌ |
| 局部变量 | 栈 | ❌ |
VM 缓存已加载的 Kernel 减少重复解析
class KernelCache {
// 缓存已加载的程序
HashMap<String, Program*> programs_;
// 缓存已解析的类
HashMap<String, Class*> classes_;
Program* GetOrLoad(String url) {
if (programs_.contains(url)) {
return programs_[url];
}
return LoadAndCache(url);
}
}
CFE (Common Front End) 是 Dart 的统一前端编译器
Dart Source (.dart)
│
▼
┌─────────────────┐
│ Parser │ 词法/语法分析
└────────┬────────┘
│
▼
┌─────────────────┐
│ Body Builder │ 构建 AST
└────────┬────────┘
│
▼
┌─────────────────┐
│ Type Inference │ 类型推断
└────────┬────────┘
│
▼
┌─────────────────┐
│ Kernel Writer │ 序列化
└────────┬────────┘
│
▼
Kernel (.dill)
class IncrementalCompiler {
// 之前编译的状态
Program* previous_program_;
// 增量编译
Future<Program> compile(
List<Uri> modified_files,
) async {
// 1. 复用之前的 AST
// 2. 只重新编译修改的文件
// 3. 生成增量 Kernel
}
}
混合编译允许同时使用 AOT 和 JIT 编译的代码
| 特性 | AOT | JIT |
|---|---|---|
| 编译时机 | 构建时 | 运行时 |
| 启动速度 | 快 | 慢 |
| 热重载 | ❌ | ✅ |
| 代码优化 | 全局优化 | 运行时优化 |
| 包体积 | 较大 | 较小 |
Kernel (.dill)
│
▼
┌─────────────────┐
│ IL Generator │ 生成中间语言
└────────┬────────┘
│
▼
┌─────────────────┐
│ IL Optimizer │ 优化
└────────┬────────┘
│
▼
┌─────────────────┐
│ Code Generator │ 生成机器码
└────────┬────────┘
│
▼
Snapshot (.snapshot)
Kernel (.dill)
│
▼
┌─────────────────┐
│ KernelLoader │ 加载到内存
└────────┬────────┘
│
▼
┌─────────────────┐
│ Interpreter │ 解释执行
│ (首次调用) │
└────────┬────────┘
│ 热点检测
▼
┌─────────────────┐
│ JIT Compiler │ 编译为机器码
└─────────────────┘
快照将VM 状态序列化到文件,加速启动
| 快照类型 | 内容 | 用途 |
|---|---|---|
| Core Snapshot | 核心库 | 所有应用共享 |
| App Snapshot | 应用代码 | AOT 产物 |
| JIT Snapshot | JIT 状态 | 加速 JIT 启动 |
// Core Snapshot 包含
class CoreSnapshot {
// 核心库对象
Library dart_core;
Library dart_async;
Library dart_collection;
...
// 预创建的对象
Object* true_value;
Object* false_value;
Object* null_value;
}
// App Snapshot 包含
class AppSnapshot {
// 所有应用代码
List<Library> libraries;
// 编译后的代码
List<Code> compiled_code;
// 常量对象
List<Object> constants;
// 对象堆快照
HeapSnapshot heap;
}
Kernel 保留源码位置信息用于调试
class SourceLocation {
final Uri fileUri; // 文件路径
final int line; // 行号
final int column; // 列号
final int tokenPosition; // Token 位置
}
// 每个 AST 节点都有位置信息
node.location.fileUri
node.location.line
dart-sdk/runtime/vm/ ├── kernel_loader.cc # Kernel 加载 ├── kernel_loader.h ├── kernel_binary_flowgraph.cc ├── instance_morpher.cc # 实例变形 ├── become.cc # 指针置换 ├── object.cc # VM 对象 ├── isolate.cc # Isolate └── snapshot.cc # 快照 dart-sdk/pkg/kernel/ ├── lib/ # Kernel AST 定义 └── binary/ # 二进制格式
| 类名 | 职责 |
|---|---|
| KernelLoader | 加载 Kernel 文件 |
| InstanceMorpher | 实例变形 |
| Become | 指针置换 |
| Program | Kernel 程序 |
| Library/Class | AST 节点 |
# 查看 .dill 文件内容
dart kernel-service.dart temp.dill
# 打印 Kernel AST
dart pkg/kernel/tool/dump.dart app.dill
# VM 调试输出
dart --print-flow-graph script.dart
.dill → KernelLoader → VM Objects → InstanceMorpher (Hot Reload)
| 组件 | 职责 |
|---|---|
| CFE | 编译 Dart 到 Kernel |
| KernelLoader | 加载 Kernel 到 VM |
| InstanceMorpher | 热重载时变形实例 |
| Become | 指针置换 |
1. 前端编译 └─▶ CFE 编译 Dart → Kernel (.dill) 2. 加载解析 └─▶ KernelLoader 解析二进制 → VM 对象 3. 热重载更新 └─▶ 加载增量 Kernel → InstanceMorpher 变形 4. 指针置换 └─▶ Become 替换旧对象指针
🧬 Happy Coding!