news 2026/9/25 4:42:39

Dart SDK 中的 Dart Kernel:中间语言(IR)、二进制序列化与可变换 AST 全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dart SDK 中的 Dart Kernel:中间语言(IR)、二进制序列化与可变换 AST 全解析
  • 编程语言
  • 编译器
  • 语言运行时
  • 标准库
  • 开发工具

【免费下载链接】sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.

项目地址:https://gitcode.com/gh_mirrors/sdk1/sdk
点击查看免费下载

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 实现部分,具体两大块:

  1. 可变换的 IR(transformable IR)——即 pkg/kernel/lib/ast.dart 中定义的内存表示;
  2. 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
类Class2
函数FunctionNode3
成员Field/Constructor/Procedure4 / 5 / 6
初始化器InvalidInitializer…AssertInitializer7 … 12
表达式VariableGet/VariableSet/StaticGet/StaticSet20 / 21 / 26 / 27
表达式InstanceGet/InstanceSet/InstanceInvocation118 / 119 / 120
表达式StringLiteral/DoubleLiteral/TrueLiteral/FalseLiteral/NullLiteral39 … 43
表达式ListLiteral/MapLiteral/AwaitExpression/FunctionExpression/Let/Instantiation49 / 50 / 51 / 52 / 53 / 54
语句ExpressionStatement/Block/EmptyStatement/AssertStatement…61 … 64
语句While/Do/For/ForIn/Switch/If/Return/TryCatch/TryFinally/Yield67 … 78
类型InvalidType/DynamicType/VoidType/InterfaceType/FunctionType/TypeParameterType90 … 95
类型NeverType/IntersectionType/RecordType/ExtensionType98 / 99 / 100 / 103
扩展Extension/ExtensionTypeDeclaration115 / 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 编译管线中的典型流转:

  1. **前端(pkg/front_end)**解析 Dart 源码、做类型检查,生成 Kernel AST,并以二进制 .dill 形式写出(同时附带problemsAsJson诊断);
  2. 变换阶段(如pkg/kernel/lib/transformations/、各 lowering)基于可变换 IR 对 Kernel AST 做全程序分析与改写;
  3. 后端消费: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.

项目地址:https://gitcode.com/gh_mirrors/sdk1/sdk
点击查看免费下载

相关推荐

上一篇:typeahead.js第三方插件生态:精选扩展推荐
下一篇:SuperClaude并行任务处理:使用/spawn命令实现高效开发工作流自动化

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 4:42:29

RK3128通用固件刷机指南:华为EC6108V9A全网通去广告焕新

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

作者头像 李华
网站建设 2026/9/25 4:42:11

PMOS缓启动电路全解析:从RC参数计算到Multisim仿真实践

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

作者头像 李华
网站建设 2026/9/25 4:42:10

淘宝商品API与视频资源采集接口接入实战:电商运营与开发必读

做电商运营的人大概都经历过这样的早晨&#xff1a;打开表格&#xff0c;对着几百个商品链接&#xff0c;一个一个复制标题、主图、价格&#xff0c;再跑到另一个平台手动上传&#xff0c;顺便下载商品主图视频、详情页视频&#xff0c;给短视频账号做素材。一上午过去&#xf…

作者头像 李华
网站建设 2026/9/25 4:41:49

Mac 修改 iOS 定位全攻略:AnyGo 原理、实操与避坑指南

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

作者头像 李华
网站建设 2026/9/25 4:40:26

MOS管逻辑门实战:从焊台冒烟到稳定2MHz的CMOS电路设计

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

作者头像 李华
网站建设 2026/9/25 4:40:23

CTF逆向实战:用GDB和Ghidra层层剥出Hidden Key

Hidden Key&#xff0c;名字起得很直白&#xff0c;就是要让你在一堆东西里把真正的Key挖出来。这题我拿到之后&#xff0c;前后折腾了大概三个小时&#xff0c;最后在GDB和Ghidra的配合下把三个Key片段拼齐&#xff0c;顺利跑出了HKCTF{h1dden_k3y_1s_n0t_4lw4ys_h1dd3n}。这篇…

作者头像 李华