RFC-0026:到处都有信封 | |
---|---|
状态 | 已拒绝 |
领域 |
|
说明 | 通过将信封缩减两倍以上,提高现有信封格式的效率。使用信封作为引用所有脱线对象的唯一方式。这样可提高传输格式的一致性,以及协议设计和实现的一致性。 |
作者 | |
提交日期(年-月-日) | 2019-01-19 |
审核日期(年-月-日) | 2019-02-04 |
遭拒原因
考虑到此 RFC 收到的反馈和评论数量,我们决定 撤回(即自行拒绝)提案。 尽管如此,仍有一些很棒的想法:我们会采纳这些想法, 将它们作为范围较小的单独 RFC 发布 并将独立的功能划分到各自的 RFC 中。
RFC-0032 是从此 RFC 中衍生出来的。
摘要
此 RFC 有两个目标:
- 提高现有
envelope
格式的效率, 是较小的两倍以上。 - 使用信封作为引用所有脱机对象的唯一方式。 这样可提高电线格式的一致性, 设计和实现协议
(1) 和 (2) 都有副作用,即可选性(可为 null)可以是 可针对所有类型高效实现,而不仅仅是结构体、句柄、矢量 字符串、表和(可扩展)联合1。
设计初衷
信封是可扩展、可进化的数据结构的基础 (表和可扩展联合)。 使信封更加高效,能够让这些可扩展结构 在性能和电线尺寸很重要的更多情境下应用
FIDL 还有几种普遍类型,用于动态大小 数据:矢量和字符串。 由于 FIDL 主实例的大小, 对象预计是静态已知的。 如果可以使用信封来表示所有离线数据,我们可以简化 从而减少实现费用和 错误。
此外,FIDL 还将受益于全面、一致的方法来 。 这样可以提高人体工程学,并且比当前更多类型更具可选性 并简化用户思维模式。 信封通过为 以一致的方式呈现
设计
信封可以指以下任意数据:
- out-of-line(与现有信包格式类似),或者
- inline:其中数据存储在信封本身中。 可用于“小型”工作负载即具有固定大小、 超过 64 位。
异装信封
例外信封是指:
以 C 结构体表示:
typedef struct {
uint64_t size:48; // Low bit will be 0
uint16_t handle_count;
} fidl_out_of_line_envelope_t;
与现有的信封相比,例外信封具有以下变化 格式:
- 大小(字节数)由 32 位改成 48 位,支持更大的
负载
- 大小包括可能以递归方式返回的任何子对象的大小
编码。
- 例如,
vector<string>
的大小包含 外向量的内部字符串子对象。 - 这与当前信封的现有行为一致 尺寸字段。
- 例如,
- 合法的外行对象的大小始终为
8,因为排外对象采用 8 字节对齐。
这意味着
size % 8 == 0
,也就是说, <ph type="x-smartling-placeholder">- </ph>
- 大小字段的最低三位,也就是 LSB 值 - 将为零,因此
- 信包的 LSB - 因为大小字段是 信封 — 始终为零。
- 这非常重要,如下面的标记位所述。
- 请参阅针对离线的编码大小 信封下方, 计算递归大小对性能的影响。
- 大小包括可能以递归方式返回的任何子对象的大小
编码。
handle_count
是 16 位,而不是 32 位。- 目前无法将 >Zircon 频道上的 64 个句柄; 我们认为 16 位有足够的提升空间来满足未来的需求。
handle_count
包含所有递归的句柄计数 子对象。
- 存在/缺失字段被丢弃。
- 在线状态由
size
或handle_count
字段。 - 缺失用
size
和handle_count
字段均有 为零。- 我们称之为“零信封”。
- 在线状态由
解码器可以使用指向信封数据的指针覆盖信封。 假设他们知道信封内容的静态类型(架构)。 如需了解有关相关建议,请参阅解码器回调部分 如何处理信封。
标记位
外围信封明确表示其尺寸占据 有效位,以及占据最高有效位的句柄计数。 如信封部分所述,
- 因为 size 字段的最低位始终为零(由于 大小为 8 的倍数),
- 包封的最低位也将始终为零。
我们将信封的最低位称为“标记位”。
- 如果该标记位为零,则包封的数据为脱线。
- 如果标记位为 1,则信封的数据为内嵌。
由于标记位是用于内联数据的标记位,因此内联信封也无法 需要 64 位对齐的架构的实际指针,因为 指针将是 8 的倍数,并且还需要最低 3 位 零。 这对于解码器能够区分内联信封和 实际的指针,因为解码器通常会覆盖外行的信封 而不是内联信封 - 以及指向信封 内容。
内插信封
内嵌信封编码为:
以 C 结构体表示:
typedef struct {
uint8_t tag:1; // == 1
uint32_t reserved:31;
union {
_Bool bool;
uint32_t uint32;
int32_t int32;
uint16_t uint16;
int16_t int16;
uint8_t uint8;
int8_t int8;
float float32;
zx_handle_t handle; // Only when decoded (see Handles for more details)
};
} fidl_inline_envelope_t;
- 内嵌信封的 LSB 设为 1,以便与 出行的信封和实际指针。
- 信封的上 32 位用于表示内嵌值,
可以是
int8
、uint8
、int16
、uint16
、int32
、uint32
float32
、bool
或标识名。- 较高 32 位的最低位用于表示值 如果值小于 32 位宽,这是标准 小端字节序表示法。
- 除非将来的 RFC 指定,否则编码器必须将预留位编码为零 这些位的解释方式。
- 除非未来有 RFC,否则解码器和验证器必须忽略预留位 指定这些位的解释方式。
- 解码器在解码期间应让内嵌信包保持不变。
- 由于内嵌数据采用内嵌数据,而不需要 外行引用,则解码器无需将其替换为 就地解码(不同于逐行信封不同)时显示的指针。
编码器应编码为离线还是内联?
编码器必须:
- 当且仅当类型为
bool
、(u
)int8
、(u
)int16
时,对数据进行内嵌编码, (u
)int32
、float32
或标识名。 (通俗地说:如果类型是固定大小且小于等于 32 位。) - 对于所有其他类型的数据进行异常编码。 (通俗地说:如果类型大于或等于 64 位或大小可变。)
句柄
句柄声明有三种上下文:
- 不可扩展容器中的非可选句柄,例如
struct S { handle h; };
- 非可扩展容器中的可选句柄,例如
struct S { handle? h; };
- 可扩展容器中的句柄,例如
table T { handle h; }
对于 (1),我们提议在非可扩展容器中提供一个非可选句柄,
保留现有的传输格式,即 uint32
。
无需非可扩展容器中的非可选句柄
不能是信封,因为信封可用于装运可选的或
动态大小的数据。
对于 (3),扩展容器中的句柄:因为信封是
是可扩展容器的基础,因此必须使用信封
标识名。
要对句柄进行编码,编码器必须将其编码为外包信封。
将 size
设置为 0,将 handle_count
设置为 1:
此编码指示解码器在 外行句柄表。 如果解码器想要就地解码,则解码器应:
- 在外行标识名表中查找该标识名, 实际句柄值。
- 将标记位设置为 1,这会将信包从非在线更改为内插。
- 将 fidl_inline_envelope_t 结构体的句柄字段设置为实际的 句柄值。
如需查看编码/解码句柄的示例,请参阅示例部分。
我们之所以选择这种双重编码/解码形式,是因为它与 外联和内联信封编码。 虽然这会导致信封中针对标识名产生专门的代码, 我们认为数据编码的统一程度越高(即数据编码越少), 与需要更多编码的更简单代码进行权衡。
对于 (2),非可扩展容器中的可选句柄:我们还建议
针对线上格式使用与上下文 (3) 相同的信封表示法,
即双行外编码/内联解码形式。
遗憾的是,可选句柄的这种表示形式不如
现有的可选句柄传输格式(即
uint32
。
不过,我们仍然提倡使用基于信封的表示法,因为
- 对可选句柄使用信封与使用 提供任意可选类型的信封
- 可选句柄在 FIDL 消息中相对较少(与其他消息相比) 类型2,因此额外的 4 个字节的信封开销应该 不会显著影响邮件大小
- 如果保留可选句柄的现有
uint32
传输格式, 会产生三种编码和三个单独的标识名代码路径: 非可选、可选和信封句柄。 对可选参数使用信包表示法可以消除一种编码 和 1 个代码路径,这可以提高统一性,并降低专业化程度, 代码。
(2) 的编码 — 非可扩展容器中的可选句柄
已在设计决策中明确列出
因为可选参数以更加紧凑的 uint32
表示法,
可能值得考虑
弦与矢量
不可为 null 的 Strings 和 向量存储为 16 个字节:
- 用于表示元素数量(矢量)或字节数(字符串)的
uint64
; - 用于存在/缺失/指针的
uint64
。
我们提议使用信封来表示字符串和向量, 可为 null 或不可为 null:
- 元素数(矢量)或字节数(字符串)移出原行。
- 这使得矢量/字符串能够用信封(仅)表示, 因此信封成为引用任何例外项的唯一方式 数据,为所有 FIDL 类型实现一致的表示, 所有离线数据
- 矢量/字符串内容位于单独的外行对象中,并且 紧跟在元素/字节数之后。
- 存在/缺失由信封确定,要么是 0, 非零值。
请注意,矢量元素计数与信封的大小不同:
- 信封的大小是矢量元素数量乘以该元素 。
- 如果矢量包含子对象(例如
vector<Table>
、vector<vector<string>>
),则信封的尺寸包含所有尺寸 递归子对象。
可为 null 的字符串/向量,以及可扩展容器中的字符串/向量; 与不可为 null 的字符串和向量的表示方式相同:零 信封用于表示不存在字符串/矢量。
反之,如果字符串/矢量不可为 null,出现以下情况时,验证程序必须出错 遇到零信包。
对于使用 C 绑定的代码而言,这可能是一项破坏源代码的更改,
它们需要 fidl_vector_t
和 fidl_string_t
的内存布局
与传输格式完全匹配。
不过,我们可以在传输格式变更之前实施过渡计划
(例如,更改 C API 以使用函数或宏),使其成为
软过渡。
请注意,这个新的字符串/矢量布局仍然可以表示为
通过灵活数组成员使用 C 结构体(例如 struct {
uint64 element_count; element_type data[]; };
)。
可选(可为 null)类型
目前,结构体、字符串、矢量、句柄、联合体、表和可扩展元素 联合可以是可选(可为 null)。
在所有地方使用信封即可使所有类型都是可选的:
- 当前可选数据使用信封进行存储,无论该数据是否 或内嵌。
- 如果缺少可选数据,则将其存储为零信封。
请注意,对于小型类型,内嵌数据可将可选类型存储为 压缩为非可选类型,具体取决于容器的对齐方式 要求。
编码/解码表单的 C/C++ 结构体
信封的编码形式可以由一个 内联或外行信封。 同样,解码的信封可以是内联的,也可以是指向信封的指针。 数据或回调确定的值(请参阅解码器 Callback 部分)。
typedef union {
fidl_inline_envelope_t inline; // Low bit is 1
fidl_out_of_line_envelope_t out_of_line; // Low bit is 0
} fidl_encoded_envelope_t;
typedef union {
fidl_inline_envelope_t inline; // Low bit is 1
void* data; // Low bit is 0
uintptr_t callback_data; // Value determined by callback (see Decoder Callback)
} fidl_decoded_envelope_t;
static_assert(sizeof(fidl_encoded_envelope_t) == sizeof(void*));
static_assert(sizeof(fidl_decoded_envelope_t) == sizeof(void*));
未知数据
接收器 - 验证器和解码器 - 可能不知道 用于可进化的数据结构(例如表 或可扩展联合。 如果收件人不知道信包类型:
- 您可以放心地忽略内嵌信封。
- 标识名必须使用外联信封(而不是内联)进行编码 信封,这样可以安全忽略所有内嵌信封。
- 出线信封可以极简地解析和跳过。
- 信封的大小决定了要跳过的外行数据量。
- 如果信封的句柄计数为非零,验证程序必须处理
指定数量的句柄。
- 默认处理行为必须为关闭所有手柄。
- 解码器可以使用指向
信封的内容(如果要就地解码)。
- 如果解码器确实用指针覆盖了信封, 减小了处理信封中的计数信息。 如果此方法存在问题,请参阅解码器回调 部分,了解替代方案。
请注意,将尺寸嵌入非在线信封中可以实现快速线性 如果需要跳过许多未知类型,则搜寻 FIDL 消息。
解码器回调
正如未知数据部分所述, 信封可能会被解码器覆盖:如果发生这种情况,解码器 会丢失大小和句柄计数信息。 作为替代方案,解码器可以附加一个回调, 处理信封并覆盖默认行为。 回调 API 可能类似于以下函数原型:
void set_unknown_envelope_callback(
unknown_envelope_callback_t callback, // a callback
void* context // client-specific data storage
);
typedef uintptr_t (*unknown_envelope_callback_t)(
const void* message, // pointer to the envelope's containing message
size_t offset, // offset in the message where the unknown envelope is
size_t size, // the envelope's size
size_t handle_count, // the envelope's handle count
const char* bytes, // pointer to the envelope's data
void* context // a context pointer set via set_unknown_envelope_callback()
);
该回调返回一个 uintptr_t
,解码器可以使用它覆盖
包含未知的信封
这样,解码器就可以从未知的
信封,并使用指向解码器自身
自定义数据结构。
对外来信封的编码尺寸
此 RFC 要求,外行信封必须具有正确的(递归) 当前离线数据的大小。 此要求可能会给编码器加重负担,因为如果 信封的类型应该为接收者已知的信息,因此大小字段为 不需要,因为解码器可以计算大小 3。 因此,可以说,编码器在没有明显效果的情况下 好处。 此参数也适用于句柄计数。
不过,我们仍建议必须包含大小和句柄计数。 原因如下:
- 一致性:要求尺寸意味着信封编码 无论是在可扩展的容器内, 。 更高的统一性可以减少代码量,并简化认知模型。
- 我们以后可以更改此设置。
未来的 RFC 360 可以选择使用标记值来表示大小(例如
UINT48_MAX
),或者在大小字段中保留三个 LSB 中的一个,以 指示大小未知,在这种情况下,解码器必须遍历 并计算其大小本身。 这项更改不会影响线路格式,因为 会保持不变 它也可能被视为软过渡,因为解码器可以实现 更新编码器之前的逻辑。
总体而言,RFC 作者认为,对于未知的 可提前优化尺寸,因此建议从简单的 更加一致、统一的设计。 如果我们认为今后应重新考虑这项决定,例如 零复制矢量化 I/O 编码器可用, 不必为了写出合适的大小而贴上贴膜 明确地将其实现为软过渡。
示例
可选的内嵌存储 uint
:
uint32? u = 0xdeadbeef; // an optional uint: stored inline.
C++ 表示法:
vector<uint8_t> object{
0x01, 0x00, 0x00, 0x00, // inline tag
0xEF, 0xBE, 0xAD, 0xDE, // inline data
};
外联存储的可选 vector<uint16>
:
vector<uint16>? v = { 10, 11, 12, 13, 14 }; // an optional vector<uint16>; stored out-of-line.
外行大小为 24:
- 8 个字节,表示元素计数在行外作为其自己的次要对象存储;
- 矢量内容 + 10(5 个元素 *
sizeof(uint16_t)
), - = 18,舍入到 24 以进行对齐。
C++ 表示法:
vector<uint8_t> object{
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // envelope size (24)
0x00, 0x00, // handle count
};
vector<uint8_t> sub_objects{
// element count
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// vector data
0x0A, 0x00, 0x0B, 0x00, 0x0C, 0x00, 0x0D, 0x00,
0x0E, 0x00,
// padding
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
包含以下三个字段的 table
:
table T { 1: int8 i; 2: reserved; 3: int64 j; } = { .i: 241, .j: 71279031231 };
C++ 表示法:
// a table is a vector<envelope>, which is represented with an
// out-of-line envelope
vector<uint8_t> object{
0x28, 0x00, 0x00, 0x00, 0x00, 0x00, // envelope size (40)
0x00, 0x00, // handle count
};
vector<uint8_t> sub_objects{
// vector element count (max table ordinal)
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// vector[0], 1: int8, stored inline
0x01, 0x00, 0x00, 0x00, // inline tag
0xF1, 0x00, 0x00, 0x00 // 241
// vector[1], 2: reserved
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // zero envelope
// vector[2], 3: int64, stored out-of-line
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, // envelope size
0x00, 0x00, // handle count
// vector[2] content
0xBF, 0xB3, 0x8F, 0x98, 0x10, 0x00, 0x00, 0x00 // 71279031231
};
标识名:
handle h; // decoded to 0xCAFEF00D
C++ 表示法:
vector<uint8_t> encoded_form{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // envelope size
0x01, 0x00, // handle count
};
vector<uint8_t> decoded_form{
0x01, 0x00, 0x00, 0x00, // inline tag
0x0D, 0xF0, 0xFE, 0xCA, // inline data
};
实施策略
此 RFC 是一项重大的传输格式更改。 两个 FIDL 对等方都需要了解新的传输格式,并且 将这种理解传达给同事,以供双方使用 新格式。
可以进行软过渡。 下面介绍了两种方法:
- 事务性消息中包含
uint32
预留/标志字段 标头。 我们可以为发起对等端预留 1 位,以表明它 能够理解新的传输格式,以及分阶段的软转换: <ph type="x-smartling-placeholder">- </ph>
- 确保所有客户和服务器可以识别新的线上传输格式 我们继续使用旧有的传输格式。
- 通过让对等设备在 事务消息标头。 如果双方都设置了位,则双方都可以切换到新的位 线上传输格式。
- 当软过渡经过所有层之后, Fuchsia 可以使用新的数据线格式。 我们可以取消在事务邮件标头中设置位。
- 删除旧传输格式的代码,并取消保留 事务消息标头位。
- 我们可以使用
[WireFormat=EnvelopeV2]
属性(或类似属性),指示 message/interface 应使用新的传输格式。- 使用
[WireFormat]
属性装饰接口似乎 最好能与传输格式更改保持一致, 在结构体上实施 WireFormat 更改,因为结构体可以是 并且绑定需要额外的逻辑来 确定使用结构体的上下文。 - 我们建议让接口
[WireFormat]
属性影响 仅采用接口方法参数的传输格式, 以递归方式影响参数的结构。 - 这样可以实现部分迁移并选择采用新的有线格式,并且 让团队按照自己的节奏前进
- 一旦所有结构体和接口都具有
[WireFormat]
属性,我们 可以丢弃旧的传输格式,假设所有结构体和接口使用 新的线上格式,并忽略该属性。
- 使用
这两种软过渡方法都需要大量开发时间, 测试时间和出错空间 通过实现代码来正确执行任一方法,按计划执行, 而成功跟进并删除旧代码将是一项艰巨的工作。
我们可能会使用代码来处理旧版和新的线上传输格式 否则,就无法逐步 实现对新传输格式的支持时使用的 CL。 鉴于会有处理这两种传输格式的代码,我们建议 原型设计使用任一方法进行软过渡是否可行。 如果没有,c'est la vie;非常困难
对于软过渡或硬过渡,如果 FIDL 手动处理的邮件也可能需要升级为新的电汇格式。
我们还应该利用这条线格式更改来折叠 (例如,提议的序数大小更改)。
请注意,这比从 FIDL1 转换到 FIDL2 更容易,后者 语言绑定。 我们不建议调用此 FIDL3,因为没有用户可见的 变更4。
向后兼容性
提议的传输格式更改与 API(源)兼容,具有一个 异常:如果我们将 矢量/字符串元素计数超出行。 我们可以提前规划并提取当前的 C 绑定来缓解这种情况 。
传输格式更改与 ABI 不兼容,但可以实现 ABI 实施 策略部分。
性能
此 RFC 大大缩小了信封所需的大小 认为这是从整体上而言显著的净收益。 但是,总体性能影响不太明确。 为了获得更好的效果:
- 使用可扩展数据结构(表和可扩展 并集)将变得明显更紧凑。
- 对信封和可选性采用统一的表示方式可能会降低 信封代码可以共享,因此有助于优化代码大小并优化缓存位置。
不过:
- 如果可扩展数据结构因其自身优越的 但使用量的增加可能会抵消这方面的影响, 与使用后者相比, 非可扩展数据结构。
- 针对所有类型引入可选功能可能会使 FIDL 消息略微 因为用户可能会使用该功能 非可选类型可选。
- 如果我们决定使用信封 可选句柄的编码。
- 如针对离线内容的编码大小 信封、对尺寸进行编码 以及一个信封中的句柄计数,用于表示接收方知道的类型 当前行为导致性能下降。
工效学设计
- 可为所有 FIDL 类型启用可选性。 这是一种人机工程学的改进,由于可选性变得一致, 而不是仅适用于特定类型
- 更高效的可扩展数据结构使其能
效率至关重要的环境,因此用户无需担心
并且可在需要构建容器时
以前需要使用非可扩展结构。
- 我们甚至可能建议默认使用表 数据结构,而结构体应保留以用于 高性能环境
- 可扩展联合 (RFC-0061) 已尝试 移除静态联合体。
文档
- 线上传输格式文档需要更新。
- 更新文档时, 一流概念:这有助于提高认知 分块。 可扩展数据结构。
- 我们应更新 FIDL 样式指南,以便针对 应使用可选类型(而非具有标记值的非可选类型)。
安全
- 此 RFC 应该没有明显的安全隐患。
- 然而,位扭曲需要操纵 内联信封格式应该经过充分的测试, 以确保代码正确处理极端情况。 我们确实认为,使用标准 C/C++结构体/并集来表示 与手动位移和遮盖 — 大大提高了我们对代码正确性的信心。
测试
- 由于此 RFC 将改变信封的电线格式,因此我们认为 现有的 FIDL 测试套件,尤其是兼容性测试 )能够充分测试使用信封的所有场景。
- 我们将添加单元测试,以便进行信封解析、编码和解码, 外联表单和内联表单,因为这可能容易出错。
- 如果我们同意采用软过渡的方式传输有线格式更改(请参阅 实现策略部分),我们将添加 以便对等方进行协商,并可能改用新的有线格式。
- 如果我们同意在此次变更中针对所有类型提供可选性, 我们需要为任何可能成为可选的类型添加测试。
缺点、替代方案和未知问题
- 如果我们认为可以提高效率,就可以继续使用现有的线上传输格式 不会物有所值。 如果是,我们将寻找一种替代策略来实现 。
- 针对可扩展容器使用专用表示法, 可能比针对所有情况使用信封更高效。 不过,既然 RFC 存在,我们显然认为, 通用性和统一性超过了 往往能获得特化性表征的益处。
设计决策
在 RFC 提出建议的同时,我们也在积极寻求反馈意见,并就以下决策达成共识:
- 请参阅字符串和矢量部分。 如何移动元素计数(矢量)和字节计数(字符串) 这会影响 C 绑定。 我们可以选择不这样做,但代价是不够统一:字符串和 矢量会成为用于所有例外项的信封的例外情况 参考。 (信包还可用于指代异常矢量/字符串 data.)
- 我们要考虑软转换还是硬转换?请参阅 实施策略部分(面向专业人士和缺点
- 我们建议在 出线的信封。 为便于比较,当前的信包格式使用 32/32 位。 48 位的大小合理吗?
- 我们提议使用信封在
非可扩展容器,该容器不如当前可选容器
句柄编码(8 个字节与 4 个字节)。
- 您需要在紧凑性与相较于 这里的一致性 我们认为,一致性和一致性比 由于可选的句柄是 可能比较罕见的用例。 (代码中的可选用途为 37 个,非可选用途为 187。)
- 我们是否会立即启用可选功能?
- 我们提议在一个单独的 因为这种变化 逐步完成。
- 要实现这种可选性,需要对解析器进行更改, 编码器、验证器和解码器,它们感觉足够大, 保证是自身的过渡。
- 我们建议内联类型不超过 32 位;我们可以内联更多
激进。
- 我们可以内嵌任何小于等于 63 位的数据,因为标记位仅使用一个 64 位信封中的位。
- 我们可以内嵌小字符串和分别使用一种专业化的 表示法,例如元素/字节计数为 1 个字节, 然后是字符串/矢量数据。(请参阅上一节 从艺术中汲取灵感)。
- 我们舍弃了这些方法,尽管它们效率更高, 因为基于内容而非类型进行内联意味着 (1) 解码器无法提前知道是期望使用内联函数还是 出行或并非基于类型,以及 (2) 更改 字段的内容意味着可以采用不同的编码方式, 似乎与 FIDL 的目标和静态侧重点相悖。
先验技术和参考资料
作者从标记的现有用法中汲取了很多灵感 指针,长度为 动态和功能语言的历史。 特别是,Objective-C 64 位运行时大量使用 以获得更好的效果(甚至使用专门的 内嵌字符串的 5/6 位编码)。
由于当前的 64 位平台倾向于使用 48 位(或更小)来对 我们考虑窃取更多 通过位移从已解码指针中获取的位,以尝试对 和指针内超出行的对象的大小。 然而,一些架构已经在扩展其物理地址 超过 48 位的空间(ARM64、x64-64 5 级) 分页),因此窃取更多的指针位可能并不是 。