javascript|V8 编译浅谈( 五 )


在这里 V8 会对 JavaScript 像强类型语言那样对形参 x 和 y 进行推测 , 这样就可以在运行的过程中排除一些副作用分支代码 , 同时这里也会预测代码不会抛出异常 , 因此可以对代码进行优化 , 从而达到最高的运行性能 。 在 Ignition 中通过字节码来收集反馈信息(Feedback Vector) , 如下所示:

为了查看 add 函数的运行时反馈信息 , 我们可以通过 V8 提供的 Native API 来打印 add 函数的运行时信息 , 具体如下所示:
function add(x y) { return x + y// 注意这里默认采用了 ClosureFeedbackCellArray , 为了查看效果 , 强制开启 FeedbackVector// 更多信息查看: A lighter V8:https://v8.dev/blog/v8-lite%EnsureFeedbackVectorForFunction(add);add(1 2);// 打印 add 详细的运行时信息%DebugPrint(add); 通过 --allow-natives-syntax 参数可以在 JavaScript 中调用 %DebugPrint 底层 Native API(更多 API 可以查看 V8 的 runtime.h 头文件):



这里的 SharedFunctionInfo(SFI)中保留了一个 InterpreterEntryTrampoline 指针信息 , 每个函数都会有一个指向 Ignition 解释器的 trampoline 指针 , 每当 V8 需要进去去优化时 , 就会使用此指针使代码回退到解释器相应的函数执行位置 。
为了使得 add 函数可以像 HotSpot 代码一样被优化 , 在这里强制做一次函数优化:

通过 --trace-opt 参数可以跟踪 add 函数的编译优化信息:




需要注意的是 V8 会自动监测代码的结构变化 , 从而执行去优化 。 例如下述代码:
function add(x y) { return x + y%EnsureFeedbackVectorForFunction(add);add(1 2); %OptimizeFunctionOnNextCall(add);add(1 2); // 改变 add 函数的传入参数类型 , 之前都是 number 类型 , 这里传入 string 类型add(1 '2'); %DebugPrint(add); 我们可以通过 --trace-deopt 参数跟踪 add 函数的去优化信息:



需要注意的是代码在执行去优化的过程中会产生性能损耗 , 因此在日常的开发中 , 建议使用 TypeScript 对代码进行类型声明 , 这样可以一定程度提升代码的性能 。
五 总结 本文对于 V8 的研究还处在一个感性的认知阶段 , 并没有深入到 V8 底层的源码 。 通过本文可以对 V8 的编译原理有一个感性的认知 , 同时也建议大家可以使用 TypeScript , 它确实能在一定程度上对 JavaScript 代码的编写产生更好的指导作用 。
作者 | 子弈
本文为阿里云原创内容 , 未经允许不得转载 。