作者:布丁宝宝-_932 | 来源:互联网 | 2020-09-12 22:57
JIT是一种编译器策略,它将代码表述为一种中间状态,在运行时将其转换为依赖于体系结构的机器码,并即时执行,这意味着在PHP8中,ZendVM不需要解释某些操作码,并且这些指令将直接作为CPU级指令执行。
JIT是一种编译器策略,它将代码表述为一种中间状态,在运行时将其转换为依赖于体系结构的机器码,并即时执行,在PHP8中,Zend VM不需要解释某些操作码,并且这些指令将直接作为CPU级指令执行。
JIT 编译有什么效果?
听了 Zeev 在 PHP Internals News 发表的 PHP 和 JIT 广播 之后,我弄清了 JIT 实际做了什么事情。
如果说 Opcache 扩展可以更快的获取 Opcodes 将其直接转到 Zend VM,则 JIT 让它们完全不使用 Zend VM 即可运行。
Zend VM 是用 C 编写的程序,充当 Opcodes 和 CPU 之间的一层。 JIT 在运行时直接生成编译后的代码,因此 PHP 可以
跳过 Zend VM 并直接被 CPU 执行。 从理论上说,性能会更好。
这听起来很奇怪,因为在编译成机器码之前,需要为每种类型的结构体编写一个具体的实现。但实际上这也是合理的。
PHP 的 JIT 使用了名为 DynASM (Dynamic Assembler) 的库,该库将一种特定格式的一组 CPU 指令映射为许多不同 CPU 类型的汇编代码。因此,编译器只需要使用 DynASM 就可以将 Opcodes 转换为特定结构体的机器码。
但是,有一个问题困扰了我很久。
如果预加载能够在执行之前将 PHP 代码解析为 Opcodes,并且 DynASM 可以将 Opcodes 编译为机器码 (Just In Time 编译) ,为什么我们不立即使用运行前编译 (Ahead of Time 编译) 立即编译 PHP 呢?
通过收听 Zeev 的广播,我找到的原因之一就是 PHP 是弱类型语言,这意味着在 Zend VM 尝试执行某个操作码之前, PHP 通常不知道变量的类型。
可以查看 Zend_value 联合类型 得知,很多指针指向不同类型的变量。每当 Zend VM 尝试从 Zend_value 获取值时,它都会使用像 ZSTR_VAL 这样的宏,获取联合类型中字符串的指针。
例如,这个 Zend VM handler 是处理「小于或等于」(<=) 表达式。看看它编码这么多的 if else 分支,只是为了类型推断。
使用机器码执行类型推断逻辑是不可行的,并且可能变得更慢。
先求值再编译也不是一个好选择,因为编译为机器码是 CPU 密集型任务。因此,在运行时编译所有内容也不好。
推荐教程:《PHP》《PHP7》
以上就是PHP8 的 JIT 是什么?的详细内容,更多请关注 第一PHP社区 其它相关文章!