(按合格的 CS 教育背景)众所周知,历史上 SMC(self-modifying code) 在 pre-ISA / ISA 早期阶段普遍存在。这也是所谓的 von Neumann architecture 统一指令和数据存储的典型应用。随着高级语言的发展,这个功能逐渐被弱化。这主要是流行的语言中,都不支持需要 SMC 才能高效实现的功能(例如,ISO C 和 ISO C++ 都不要求支持运行时生成的程序和源代码经过翻译阶段处理后的代码具有同等的地位),因此体系结构设计弱化到去除 data as code 而纯软件实现也可以接受。
但是,现实是除了极端低成本的机器使用了 Harvard architecture 的设计,主流 ISA 在实现内部都保留了早期的 SMC/CMC(cross-modifiying code) 机能,而在上层才不强调这一点——因为 Lisp machine 式微之后的用户普遍不会使用 code as data 的思路元编程,高级语言中在这方面大多是残废。这表示微架构实现上必须做到这种跨风格的翻译——把底层的 von-Neumann style 翻译成上层显式区分 VM protection 并分别优化的设计。这种现代设计主要集中在缓存子系统(IA-32 方面记得专利实现是 victim cache),但原则上因为 ISA 上需要保留支持,core 内也需要对应调整。
因为接受动态输入的 data as code ,不论是在哪个层次上,SMC/CMC 原则上不可能用 AOT 风格的完全静态代码翻译解决,否则会有不可预料的正确性错误。
这方面的一个重要常识:在可预见的未来,主流 ISA 是不可能彻底抛弃这种兼容性的。断言在 ISA 这个层次上纯 AOT 能用,这是迷惑行为其一。
虽然这里的人都担不起,另一个更大的相关迷惑行为让消费者付出 IC 设计和制造的成本却阻碍他们取得功能。这方面的唯一“成功”典型是苹果:在商店审核规则中直接禁止 JIT ,放着符合 POSIX 标准能够合理利用硬件加速的实现不用,迫使开发者选择更低效的软件模拟的解释实现。就是这样的厂商,一边还有脸鼓吹降低碳排放,何等讽刺。另外,允许 Safiri 州官放火不许应用自己点灯这方面,明眼人自己看着办。
而背后更本质的共通迷惑行为是对 AOT 或者砍掉了 data as code 能力的残废编程风格的迷信(不管是使用低级语言还是高级语言)。
因为这类风格中,纯 AOT 才可能满足语言 spec 正确性要求,所以对 AOT 的盲目追捧还影响到了上层语言的功能限制。
这种迷信的来源是复杂的。至少有:
1. 使用个别缺乏 data as code 的语言的习惯性偷懒成自然,具体来讲现在主要是 C 和 C++ 。
不少人因为只会用这类语言,所以认为这类语言就应该具有统治地位,而不管缺乏合理功能时破坏可移植性带来的后果。
结果剩下意识到有必要打破这种限制的各显神通群魔乱舞,还有被州官当借口镇压的。
讽刺的是,打破这种限制的用户需求是普遍的,如 WG21 P1609 。
2. 因为教育背景不健全等原因导致的实现实用计算的普遍范式理解和独立思考能力上的残缺。
例子如 exception path 的假设(p/7102475556)和更普遍的调用机制的理解之类(p/6213333021 18L)。
3. 支持上述语言和范式为主的业界翻译实现的普遍无能——更习惯依赖 SSA-based intraprocedural style 的局部优化设施(而非 CPS/ANF 这类对 intra/interprocedural 更中立的)来提升目标代码质量。
这种决策下,翻译的实现不追求一般 control operator 优化的可实现性,而放松了 AOT 的门槛,反过来加大了可移植 JIT 的困难。
题外话,这种方式倒的确适合分离 backend 搞水平扩展——多 996 tuning 性能看来就就有机会更好。至于极限在哪呢?不知道,还有待继续 work hard 。而一般意义上 polyvariant online partial evaluation 之类的更普遍手段就别想了。
不过,不少搞 translation 的从业人员大概连 translation lemma 都没听过就赶鸭子上架了,这也是理固宜然。