欢迎光临
我们一直在努力

php方案 Side Exits: 解释 JIT 在类型推断失败时,是如何从生成好的机器码回退(De-optimize)到解释器的。

JIT Side Exits 反优化


大白话

JIT编译函数时会赌一把: “我猜这个变量一直是int” → 按int生成机器码

结果某次传进来个string,JIT赌输了: 立刻踩刹车,把控制权交还给解释器

这个"踩刹车"的出口就叫 Side Exit


代码复现

<?php
// JIT看前1000次调用都是int,生成了int专用机器码
function add($a, $b) {
return $a + $b;
}

// 前面正常,JIT优化生效
for ($i = 0; $i < 1000; $i++) add(1, 2);

// 突然传string,类型推断失败,触发Side Exit
add("hello", "world"); // JIT:我不行了,解释器你来


用vld看实际发生了什么

pecl install vld

php -d opcache.enable_cli=1 \\
-d opcache.jit=1255 \\
-d opcache.jit_buffer_size=64M \\
-d vld.active=1 \\
-d vld.execute=0 \\
test.php 2>&1

# 看到这个就是Side Exit埋的检查点:
GUARD_TYPE $a IS_LONG → 类型不对就跳出机器码
GUARD_TYPE $b IS_LONG → 回退到解释器


回退全过程

正常路径(快):
机器码: mov eax, [a]
add eax, [b] ← 直接CPU指令,飞快

类型不对时(Side Exit):
机器码: cmp type, IS_LONG
jne side_exit ← 跳到出口

恢复zval状态(把寄存器里的值写回PHP变量)

跳回解释器的opcode handler

按普通方式执行(慢,但正确)


验证Side Exit次数

<?php
$status = opcache_get_status();
// 看JIT缓冲区消耗
// Side Exit频繁会导致buffer_free不断减少
echo $status['jit']['buffer_free'] . "\\n";

// Side Exit太多,JIT会直接放弃这个函数
// 不再编译它,标记为 "too polymorphic"


结论

类型稳定 → JIT一路畅通,机器码跑到底
类型突变 → 踩Side Exit,溜回解释器
反复突变 → JIT直接放弃这个函数,不编译了

想让JIT发挥最大效果,函数里的变量类型别乱变。

赞(0)
未经允许不得转载:171主机测评 » php方案 Side Exits: 解释 JIT 在类型推断失败时,是如何从生成好的机器码回退(De-optimize)到解释器的。
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址