- 编程语言
- 编译器
- 语言运行时
- 标准库
- 开发工具
【免费下载链接】sdk
The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
Dart Kernel是 Dart SDK 中一个从 Dart 派生的"小而精"的高层中间语言(Intermediate Representation,IR),专为全程序分析(whole-program analysis)与变换(transformations)设计,最终被代码生成(codegen)与执行后端消费。本文以 pkg/kernel/README.md 为核心骨架,结合 pkg/kernel/binary.md、pkg/kernel/problems.md 以及pkg/kernel/lib/下的实际实现,完整讲解 Kernel 语言的内存表示、二进制序列化格式、文本格式与诊断信息格式,让读者掌握"如何读懂一个 .dill 文件"以及"Dart 编译器各阶段如何通过 Kernel 衔接"的完整脉络。
一、Dart Kernel 是什么:定位与设计动机
Dart SDK 的编译管线(frontend 解析与类型检查、VM、dart2js、dart2wasm 等后端)需要一个共同的程序表示层。Dart Kernel 正是这一层的载体:
- 它是一个独立的高层语言:由 Dart 派生而来,但刻意保持"小"(small),只保留后端真正需要的语言构造;
- 面向全程序分析与变换:整棵程序被表示为可遍历、可原地替换节点的树结构,便于实现类型推断、常量折叠、各种 lowering 等整程序级的优化;
- 面向代码生成与执行后端:VM(JIT/AOT)、dart2js、dart2wasm、DDC 等后端直接以 Kernel 为输入生成目标代码或字节码;
- 三种形态统一:同一个 Kernel 程序可以在内存中表示为 Dart 对象图(in-memory),也可以序列化为二进制格式(binary)或输出为文本格式(text)。
从当前仓库的结构看,Kernel 贯穿于整个编译链:pkg/front_end(前端)、pkg/kernel(本包)、pkg/vm(VM 编译器)、pkg/compiler(dart2js)等都以不同方式消费 Kernel。README 明确警告:Kernel 语言与其实现都处于不稳定状态,仍在持续开发中。
1.1 本包(pkg/kernel)包含什么
README 指出,本包包含 Kernel 的 Dart 实现部分,具体两大块:
- 可变换的 IR(transformable IR)——即 pkg/kernel/lib/ast.dart 中定义的内存表示;
- Kernel 代码的序列化(serialization)——即
pkg/kernel/lib/binary/目录下的二进制读写,以及pkg/kernel/lib/text/目录下的文本输出。
1.2 API 稳定性:没有 semver 契约
README 特别强调:本包 API 仍处于早期状态,没有 semver 版本契约。开发者若依赖本包,应直接锁定具体版本(depend directly on individual versions),而不是使用范围约束。这一点也在 pkg/kernel/pubspec.yaml 中得到印证——该文件注释写明 "kernel API is not stable and users should not depend on semver semantics",且publish_to: none(不发布到 pub.dev,仅作为 SDK 内部包使用),当前环境要求 SDK^3.13.0-0,依赖_fe_analyzer_shared: any。
二、内存中的 IR:ast.dart 与可变换 AST
README 指引读者从 ast.dart 入手了解内存 IR。该文件是 Kernel AST 的唯一权威定义,其头部注释本身就是一份开发者手册,明确规定了修改 AST 时必须同步更新的文件清单:
binary/ast_to_binary.dart(写二进制)binary/ast_from_binary.dart(读二进制)text/ast_to_text.dart(输出文本)clone.dart(AST 克隆)binary.md(二进制格式文档)type_checker.dart(如涉及类型)
这六件套保证内存表示、二进制格式与文本格式三者始终一致——这是 Kernel 包最重要的工程约束。
2.1 语义约定(来自 ast.dart 注释)
- 错误处理:能被静态检测的错误由前端(frontend)负责,通常翻译成
throw或noSuchMethod调用。例如静态调用中不存在参数数量不匹配,也不会出现对抽象类的直接构造调用; - Static 与 Top-level:术语
static同时涵盖静态类成员和顶层成员。静态类成员不会被提升(lift)到库层面,因为 mirrors 和栈回溯可以观察到它们是类成员; - Procedure 的定义:"Procedure" 是方法、getter、setter、索引 getter/setter、运算符重载和工厂构造函数的统称;生成构造函数、字段初始化器和局部函数不是procedure;
- 变换方式:AST 变换可通过
TreeNode.replaceWith(适合稀疏变换,只改少量节点)或Transformervisitor 类(适合批量变换)完成;也可以直接修改字段,但那样必须手动维护 parent 指针。
2.2 顶层类型体系
Kernel AST 的核心抽象基类是TreeNode,其子类体系覆盖了程序的所有要素:
- 组件级:
Component(整个编译产物,对应二进制中的 ComponentFile)、Library、Class、Extension、ExtensionTypeDeclaration、Typedef; - 成员级:
Member→Field、Constructor、Procedure; - 函数体:
FunctionNode(携带asyncMarker,区分 Sync / SyncStar / Async / AsyncStar,还有独立的dartAsyncMarker); - 初始化器:
Initializer→InvalidInitializer、FieldInitializer、SuperInitializer、RedirectingInitializer、LocalInitializer、AssertInitializer; - 表达式:
Expression→ 字面量、变量读写、属性访问、方法调用、逻辑/条件表达式、集合字面量、await、闭包、类型测试(is/as)等数十种; - 语句:
Statement→Block、If、While、For、ForIn、Switch、TryCatch、TryFinally、Return、Yield、断言等; - 类型:
DartType→InterfaceType、FunctionType、RecordType、TypeParameterType、IntersectionType、ExtensionType、FutureOrType等; - 模式:
Pattern→ 覆盖 Dart 3 的模式匹配特性(ListPattern、MapPattern、ObjectPattern、OrPattern、RelationalPattern等); - 常量:
Constant→ 各类常量值(NullConstant、IntConstant、StringConstant、ListConstant、MapConstant、InstanceConstant等)。
每个节点类型都在二进制格式中拥有一个唯一 tag(见下文),例如Class的 tag 为 2、Procedure为 6、VariableGet为 20。
三、二进制序列化格式:读懂 .dill 文件
README 指向 binary.md 了解二进制格式。这是 Kernel 最重要的规格文档,详细到每一个字节的布局。实际读写实现位于 pkg/kernel/lib/binary/ast_to_binary.dart 与 pkg/kernel/lib/binary/ast_from_binary.dart,节点 tag 常量统一维护在 pkg/kernel/lib/binary/tag.dart。
3.1 记号约定(Notation)
binary.md 使用类 Scala 的类型描述语法:
- 位掩码:
Byte flags (flag1, flag2, ..., flagN),其中flagN是第 N 个最低有效位(flag1 即最低位); - 带标记位的字节:
Byte byte (10xxxxxx),其中x是需要抽取的位,0/1是标记位,最左边是最高位。
3.2 基础数据类型(Primitives)
二进制格式的全部基础类型定义如下:
type Byte = a byte abstract type UInt {} type UInt7 extends UInt { Byte byte1(0xxxxxxx); } type UInt14 extends UInt { Byte byte1(10xxxxxx); // most significant byte, discard the high bit Byte byte2(xxxxxxxx); // least significant byte } type UInt30 extends UInt { Byte byte1(11xxxxxx); // most significant byte, discard the two high bits. Byte byte2(xxxxxxxx); Byte byte3(xxxxxxxx); Byte byte4(xxxxxxxx); // least significant byte } type UInt32 = big endian 32-bit unsigned integer type Double = Double-precision floating-point number type List<T> { UInt length; T[length] items; } type RList<T> { T[length] elements; UInt32 length; } type Pair<T0, T1> { T0 first; T1 second; }解读要点:
- UInt 是变长编码:第一个字节的最高位(bit7、bit6)充当长度标记——
0xxxxxxx表示 7 位值(UInt7),10xxxxxx表示 14 位值(UInt14,丢弃高位标记),11xxxxxx表示 30 位值(UInt30,丢弃两个高位标记)。这种编码让小的整数(如大量节点 tag 和索引)只占 1 字节,从而显著压缩 .dill 体积; List<T>前置长度:先写UInt length,再写 length 个元素,适合顺序遍历;RList<T>后置长度:先写元素再写UInt32 length,支持从文件尾部快速定位(配合 ComponentIndex 实现"半随机访问")。
3.3 字符串表(StringTable)
二进制格式对字符串做**表化(interned)**处理:一个 StringTable 由"结束偏移数组"和"WTF-8 编码的字符串负载数组"组成。索引 N 的字符串从偏移endOffset[N-1](含)延伸到endOffset[N](不含),其中字符串 0 从偏移 0 开始:
type StringTable { List<UInt> endOffsets; Byte[endOffsets.last] utf8Bytes; } type StringReference { UInt index; // Index into the Component's strings. }程序中的字符串(标识符、字面量、URI 等)一律以StringReference(即索引)形式出现,既压缩体积又保证同一字符串只存储一次。注意编码是WTF-8(对 Unicode 代理对的宽松变体),而非严格 UTF-8。
3.4 组件文件(ComponentFile):整体布局
一个编译产物(如 VM 的platform.dill或前端输出的.dill文件)对应一个ComponentFile,其完整布局如下:
type ComponentFile { UInt32 magic = 0x90ABCDEF; UInt32 formatVersion = 141; Byte[10] shortSdkHash; List<String> problemsAsJson; // Described in problems.md. Library[] libraries; UriSource sourceMap; List<Constant> constants; RList<UInt32> constantsMapping; // Byte offset into the Component's constants. List<CanonicalName> canonicalNames; MetadataPayload[] metadataPayloads; RList<MetadataMapping> metadataMappings; StringTable strings; ComponentIndex componentIndex; }要点:
- magic = 0x90ABCDEF、formatVersion = 141(当前仓库的版本):文件头的魔数与格式版本,用于校验文件合法性;格式版本演进时旧文件可能不再兼容;
- shortSdkHash:10 字节的 SDK 哈希,用于跨版本缓存失效判断(比如检查热重载/增量编译时 SDK 是否变化);
- problemsAsJson:编译期诊断问题,格式见本文第六节;
- constants 与 constantsMapping:常量池及其字节偏移映射;
- canonicalNames:全局规范名表,是跨节点引用(库/类/成员)的基础;
- metadataPayloads / metadataMappings:供后端附加自定义元数据的扩展点(如 VM 或编译器的特定信息),
metadataMappings中节点偏移是绝对偏移,元数据偏移相对metadataPayloads; - componentIndex:文件尾部的索引区,实现"半随机访问"(见 3.5)。
3.5 组件索引(ComponentIndex):半随机访问
ComponentIndex 是二进制格式最精巧的设计之一。它全部由定长的 32 位整数组成,使得"只读最后 4 个字节就知道库的数量,从而可以跳过组件索引中的任何其他字段,进而跳转到其指向的位置":
type ComponentIndex { Byte[] 8bitAlignment; // 0-bytes to make the entire component (!) 8-byte aligned. UInt32 binaryOffsetForSourceTable; UInt32 binaryOffsetForConstantTable; UInt32 binaryOffsetForConstantTableIndex; UInt32 binaryOffsetForCanonicalNames; UInt32 binaryOffsetForMetadataPayloads; UInt32 binaryOffsetForMetadataMappings; UInt32 binaryOffsetForStringTable; UInt32 binaryOffsetForStartOfComponentIndex; UInt32 mainMethodReference; // This is a ProcedureReference with a fixed-size integer. UInt32[libraryCount + 1] libraryOffsets; UInt32 libraryCount; UInt32 componentFileSizeInBytes; }这使得加载器(如 pkg/kernel/lib/binary/multi_binary_loader.dart)不必逐字节解析整个文件,即可直接定位字符串表、常量表、库表等关键区段,是 Kernel 二进制能够被 VM 快速加载的关键。
3.6 引用机制:CanonicalName 与各类 Reference
二进制中的跨节点引用不使用指针或绝对偏移(组件索引区除外),而是通过**规范名(CanonicalName)**的层级索引:
type CanonicalNameReference { UInt biasedIndex; // 0 if null, otherwise N+1 where N is index of parent } type CanonicalName { CanonicalNameReference parent; StringReference name; }CanonicalNameReference的biasedIndex语义为:0 表示 null,否则为"父节点索引 + 1"。这样每个规范名形成一棵树(根是 Component,往下是库 → 类 → 成员)。二进制中几乎所有实体都带有"指向它的规范名"(如Library的canonicalName、Class的canonicalName、Procedure的canonicalName等),而引用方则使用LibraryReference、ClassReference、MemberReference、FieldReference、ConstructorReference、ProcedureReference、TypedefReference、ExtensionTypeDeclarationReference等——它们内部都是同一个CanonicalNameReference。binary.md 中特别注明这些引用"必须由(可能位于文件中更靠后位置的)库/类/成员来填充",即允许前向引用,这也是整个文件能被单遍写出、加载时再解析索引的原因。
3.7 Library 的结构与索引
Library携带语言版本(languageVersionMajor/Minor)、NNBD 模式位(nnbdModeBit1/2)、isSynthetic/isUnsupported等标志,以及完整的成员列表。同样,它带有两个"成员索引区",便于快速定位库中的类与过程:
UInt32 sourceReferencesOffset; UInt32[classes.length + 1] classOffsets; UInt32 classCount = classes.length; UInt32[procedures.length + 1] procedureOffsets; UInt32 procedureCount = procedures.length;偏移用于取得某个类或过程的起始(含)与结束(不含)字节位置,末尾+1是为了记录最后一项的结束位置。Class内部对procedures也有同样的procedureOffsets + procedureCount结构。
3.8 Node、Tag 与各类实体
二进制中所有可序列化的 AST 节点都以一个字节的tag开头(abstract type Node { Byte tag; }),tag 的值与 pkg/kernel/lib/binary/tag.dart 中Tag类的常量一一对应,也与ast.dart中的节点类一一对应。主要 tag 速查(选自 binary.md):
| 类别 | 节点 | tag |
|---|---|---|
| 类 | Class | 2 |
| 函数 | FunctionNode | 3 |
| 成员 | Field/Constructor/Procedure | 4 / 5 / 6 |
| 初始化器 | InvalidInitializer…AssertInitializer | 7 … 12 |
| 表达式 | VariableGet/VariableSet/StaticGet/StaticSet | 20 / 21 / 26 / 27 |
| 表达式 | InstanceGet/InstanceSet/InstanceInvocation | 118 / 119 / 120 |
| 表达式 | StringLiteral/DoubleLiteral/TrueLiteral/FalseLiteral/NullLiteral | 39 … 43 |
| 表达式 | ListLiteral/MapLiteral/AwaitExpression/FunctionExpression/Let/Instantiation | 49 / 50 / 51 / 52 / 53 / 54 |
| 语句 | ExpressionStatement/Block/EmptyStatement/AssertStatement… | 61 … 64 |
| 语句 | While/Do/For/ForIn/Switch/If/Return/TryCatch/TryFinally/Yield | 67 … 78 |
| 类型 | InvalidType/DynamicType/VoidType/InterfaceType/FunctionType/TypeParameterType | 90 … 95 |
| 类型 | NeverType/IntersectionType/RecordType/ExtensionType | 98 / 99 / 100 / 103 |
| 扩展 | Extension/ExtensionTypeDeclaration | 115 / 85 |
| 模式 | AndPattern(128) …WildcardPattern(144)、SwitchExpression(148)、PatternAssignment(150) 等 | 128 … 151 |
特殊编码技巧:
- 专用化 tag 区间:
SpecializedVariableGet使用224 + N(0 ≤ N < 8),等价于索引为 N 的VariableGet;SpecializedIntLiteral使用240 + N,直接编码值N - 3(即 -3..4 范围内的整数字面量)。这些"前缀代码"为最频繁出现的节点省去了额外的索引字段; - tag 乱序:部分节点(如
ConstStaticInvocation=18、ConstListLiteral=58、ConstMapLiteral=59、RecordLiteral=104、SetConstant=13、AsyncForInStatement=80、SimpleInterfaceType=96、SimpleFunctionType=97、TypedefType=87、SwitchExpression=148 等)的 tag 在数值上故意"乱序",binary.md 均以注释注明——这是历史上为保持向后兼容而保留的编号缺口; - fileOffset 编码:
FileOffset编码为offset + 1,以容纳 -1(表示无偏移)的情况。
3.9 变量引用与作用域规则
VariableReference是理解 Kernel 作用域模型的关键,它包含variableDeclarationPosition(变量声明的二进制字节偏移)和stackIndex(作用域栈索引,0 是最外层最先声明的变量)。binary.md 明确列出的规则值得完整引用:
- 函数参数从左到右索引,构成最外层作用域(包围函数体);
- 变量在自己的初始化器中不可见;在声明之前也不可见——这与 Dart 规范的作用域定义不同;
- 变量跨函数边界仍然可见(可用于闭包捕获);
- 声明后,变量保持可见直到直接包围它的
Block、Let、FunctionNode、ForStatement、ForInStatement或Catch结束; - 特例:构造函数参数在初始化器列表中同样可见,尽管树的嵌套与作用域并不一致。
3.10 语句、类型与模式
- 语句:覆盖
Block、If、While、Do、For、ForIn、AsyncForIn、Switch(含isExplicitlyExhaustive标志与SwitchCase)、Labeled、Break(以labelIndex引用外层 LabeledStatement)、ContinueSwitch(以caseIndex引用)、TryCatch(Catch含 guard 类型与可选的 exception/stackTrace 变量)、TryFinally、Yield(isYieldStar)、VariableStatement等; - 类型:所有
DartType节点都带nullability字节(枚举Nullability { nullable=0, nonNullable=1, neither=2 }),类型参数还带Variance(unrelated/covariant/contravariant/invariant/legacyCovariant)。SimpleInterfaceType、SimpleFunctionType是常见类型的紧凑变体(如无类型参数的接口类型、无类型参数且无命名参数且全部必选的函数类型);TypeParameterType通过index引用第 N 个在作用域内的类型参数(对类型参数边界有特殊索引规则);FunctionType以requiredParameterCount与totalParameterCount描述签名; - 模式(Pattern):完整支持 Dart 3 模式匹配:
ListPattern(含length、sublist、indexGet、minus等底层成员引用)、MapPattern(含containsKey、indexGet)、ObjectPattern、RecordPattern、OrPattern(含联合变量)、AndPattern、CastPattern、NullCheck/NullAssertPattern、RelationalPattern、ConstantPattern、VariablePattern、WildcardPattern、RestPattern等,以及SwitchExpression、IfCaseStatement、PatternAssignment、PatternVariableDeclaration、PatternSwitchStatement等语句级构造。
3.11 常量池
Constant体系独立于表达式体系(它也是Node的抽象子类),用于表示可在编译期求值的值:NullConstant、BoolConstant、IntConstant、DoubleConstant、StringConstant、SymbolConstant、MapConstant、ListConstant、SetConstant、InstanceConstant、InstantiationConstant、StaticTearOffConstant、TypeLiteralConstant、UnevaluatedConstant、TypedefTearOffConstant、ConstructorTearOffConstant、RedirectingFactoryTearOffConstant、RecordConstant。表达式侧通过ConstantExpression/FileUriConstantExpression(tag 106/108)以ConstantReference索引引用它们,避免重复内联常量内容。
3.12 元数据与源映射
- Metadata:
MetadataPayload(不透明的Byte[])与MetadataMapping(UInt32 tag+nodeOffsetToMetadataOffset对列表)让 VM 或编译后端在 .dill 中附带自定义数据而无需改动核心格式; - SourceInfo 与 UriSource:每个库的源码信息(URI、源码文本、增量编码的 lineStarts、import URI、构造器覆盖信息
constructorCoverage)保存在SourceInfo中;UriSource通过sourceIndex提供按 URI 索引源文件的映射。其中lineStarts采用增量编码:列表[0, 10, 25, 32, 42]编码为[0, 10, 15, 7, 10](记录行长度差)。
四、文本格式:adhoc 的可视化输出
README 明确指出:文本格式目前非常临时(ad-hoc),并且无法解析回内存表示——也就是说,文本格式是单向的(序列化输出),仅供人阅读,不具备 round-trip 能力。实现位于 pkg/kernel/lib/text/ast_to_text.dart(转换)与 pkg/kernel/lib/text/indentation.dart、pkg/kernel/lib/text/debug_printer.dart(缩进与调试打印)。lib/text/readme.md的描述也印证了这一点:"文本格式目前非常 ad-hoc,没有反向转换,但它是查看 IR 的一种愉快方式"。
实践中,文本格式主要用于:
- 调试(
debugPrinter、astToText); - 测试 diff(Kernel 包的测试大量使用文本比较来验证变换与序列化的等价性,例如
pkg/kernel/test/equivalence_test.dart、check_equivalence_test.dart); - 分析工具的输出展示。
五、序列化与加载的实现结构
pkg/kernel/lib/binary/目录的组成与职责:
| 文件 | 职责 |
|---|---|
| ast_to_binary.dart | 将内存 AST 写出为二进制字节流(writer) |
| ast_from_binary.dart | 从二进制字节流重建内存 AST(reader) |
| multi_binary_loader.dart | 批量/延迟加载多个 .dill(利用 ComponentIndex 的随机访问) |
| tag.dart | 节点 tag 常量定义,与 binary.md 逐条对应 |
pkg/kernel/lib/binary/readme.md明确:"二进制格式见 binary.md",即 pkg/kernel/binary.md。
与序列化配套的核心基础设施还有:
- canonical_name.dart:
CanonicalName树的构建与查询,二进制引用的基石; - visitor.dart:
Visitor/Transformer遍历框架,实现可变换 IR 的关键; - clone.dart:AST 深拷贝;
- verifier.dart:Kernel AST 一致性校验器;
- type_checker.dart、type_environment.dart:Kernel 层类型检查与环境(由前端在写出前保证 AST 类型正确);
- class_hierarchy.dart、import_table.dart、library_index.dart:类层次、导入表与库索引等分析辅助;
- text/ast_to_text.dart:文本输出;
- transformations/track_widget_constructor_locations.dart:一个具体的变换示例(跟踪 widget 构造函数位置,服务于 Flutter 相关的调试信息)。
六、problemsAsJson:编译诊断的内嵌格式
README 提到的problemsAsJson字段的完整格式由 pkg/kernel/problems.md 描述。每个字符串都是 JSON 对象,包含以下键:
| 键 | 含义 |
|---|---|
ansiFormatted | 字符串列表,包含编译器报告的带 ANSI 格式(如颜色)的问题文本 |
plainTextFormatted | 字符串列表,包含格式化的纯文本问题文本 |
severity | 整数,表示严重程度;应与package:_fe_analyzer_shared/src/messages/severity.dart中的索引一致 |
uri | 可能为 null 的 URI,本问题相关的主 URI;通常非 null(但也可能为 null) |
involvedFiles | 可能为 null 的 URI 列表,消息涉及的(其他)文件;通常为 null |
relatedUris | 可能为 null 的 URI 列表,消息上下文涉及的 URI;不包含已在uri或involvedFiles中的 URI |
codeName | 标识具体错误消息的字符串 |
文档还说明:这些值可能变化,但本文件会随变化同步更新;代码侧的定义位于package:front_end/src/codes/cfe_codes.dart(即 pkg/front_end 的源码 中的错误码定义)。problemsAsJson既出现在ComponentFile层面,也出现在单个Library层面——这允许库级问题与组件级问题分开记录。
七、测试与基准:Kernel 的验证体系
pkg/kernel/test/下的测试直接反映了 Kernel 包的核心关注点:
- 等价性验证:
equivalence_test.dart、check_equivalence_test.dart、dart_type_equivalence_test.dart——验证 AST 在往返(写二进制→读二进制)后保持等价,以及文本输出的一致性; - 序列化基准:
serialize_bench.dart、binary_bench.dart、ast_membench.dart——测量二进制序列化吞吐与 AST 内存占用; - 正确性验证:
verify_test.dart、verify_bench.dart——校验 AST 结构与类型约束; - 变换验证:
clone_test.dart、flatten_test.dart、norm_test.dart、convert_field_to_setter_getter_test.dart、generalized_tracking_test.dart、nnbd_top_merge_test.dart——验证各种 lowering/归一化变换; - 加载与重链接:
load_concat_dill_keeps_source_test.dart、load_field_and_procedure_overwrites_test.dart、relink_test.dart——验证多 .dill 加载与成员覆盖/重链接语义; - 类型系统:
type_hashcode_test.dart、type_parser_test.dart、type_substitute_bounds_test.dart、type_substitution_identity_test.dart、typedef_unalias_test.dart、non_null_test.dart——验证 Kernel 类型系统(含 nullability、类型参数代换、typedef 展开等)。
这些测试与binary.md、problems.md共同构成 Kernel 格式的"活文档",任何格式改动都必须同步更新文档与测试。
八、在编译管线中的位置与稳定性结论
综合仓库结构与各包源码,可以概括 Kernel 在 Dart SDK 编译管线中的典型流转:
- **前端(pkg/front_end)**解析 Dart 源码、做类型检查,生成 Kernel AST,并以二进制 .dill 形式写出(同时附带
problemsAsJson诊断); - 变换阶段(如
pkg/kernel/lib/transformations/、各 lowering)基于可变换 IR 对 Kernel AST 做全程序分析与改写; - 后端消费:pkg/vm(VM JIT/AOT)、pkg/compiler(dart2js)、pkg/dart2wasm、pkg/dev_compiler(DDC)等以 Kernel(或经各自变换后的 Kernel)为输入生成目标代码。
使用前提与限制(务必牢记):
- Kernel 语言与实现均为不稳定版本,处于持续开发中;
kernel包没有 semver 契约,应锁定具体版本依赖,不要使用^等范围约束;- 二进制格式的
formatVersion(当前仓库为 141)随格式演进,旧/新版本 .dill 可能互不兼容; - 文本格式为 ad-hoc、只出不进,不能用于 round-trip 解析;
- 本包仅供 SDK 内部使用(
publish_to: none)。
结语
Dart Kernel 是理解 Dart 编译器内部结构的最佳切入点:ast.dart定义"程序是什么",binary.md定义"程序如何被存储",ast_to_binary/ast_from_binary定义"两种形态如何转换",problems.md定义"诊断信息如何随程序传输",而pkg/kernel/test/的等价性测试则守护着这一切的一致性。无论你是想调试 .dill 文件、开发编译器插件,还是研究 Dart VM 的加载流程,本文所梳理的内存 IR、二进制布局(magic、formatVersion、ComponentIndex、CanonicalName 引用、tag 体系、字符串表与常量池)与文本输出机制,都是进入 Kernel 世界的完整路线图。
- 编程语言
- 编译器
- 语言运行时
- 标准库
- 开发工具
【免费下载链接】sdk
The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
相关推荐
Kernel中间表示:Dart SDK编译器的通用语言——AST、类型系统与二进制格式完全解析
Kernel中间表示:Dart SDK编译器的通用语言——AST、类型系统与二进制格式完全解析 如果你想知道 Dart SDK 编译器 内部如何工作,那么 Ke
编程语言编译器语言运行时标准库开发工具fck-nat性能调优技巧:最大化5Gbps带宽利用率
fck nat性能调优技巧:最大化5Gbps带宽利用率 fck nat作为一款基于Amazon Linux 2023构建的NAT实例AMI,能够在t4g.nan
编程语言编译器语言运行时标准库开发工具FlatBuffers 在 Dart 中的读写实践:从 flatc 代码生成到二进制序列化
FlatBuffers 在 Dart 中的读写实践:从 flatc 代码生成到二进制序列化 本指南围绕当前仓库 dart/ 目录下的 Dart 语言支持展开,系
序列化跨平台编译器
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考