javascript|V8 编译浅谈( 三 )


这里的去优化是指让代码回退到 Ignition 进行解释执行 , 去优化本质是因为机器码已经不能满足运行诉求 , 例如一个变量从 string 类型转变成 number 类型 , 机器码编译的是 string 类型 , 此时已经无法再满足运行诉求 , 因此 V8 会执行去优化动作 , 将代码回退到 Ignition 进行解释执行 。
四 V8 的运行时表现 在了解 V8 的编译原理之后 , 接下来需要使用 V8 的调试工具来具体查看 JavaScript 的编译和运行信息 , 从而加深我们对 V8 的编译过程认知 。
1 D8 调试工具
如果想了解 JavaScript 在 V8 中的编译时和运行时信息 , 可以使用调试工具 D8 。 D8 是 V8 引擎的命令行 Shell , 可以查看 AST 生成、中间代码 ByteCode、优化代码、反优化代码、优化编译器的统计数据、代码的 GC 等信息 。 D8 的安装方式有很多 , 如下所示:
方法一:根据 V8 官方文档 Using d8 以及 Building V8 with GN 进行工具链的下载和编译 方法二:使用别人已经编译好的 D8 工具 , 可能版本会有滞后性 , 例如 Mac 版 方法三:使用 JavaScript 引擎版本管理工具 , 例如 jsvu , 可以下载到最新编译好的 JavaScript 引擎 本文使用方法三安装 v8-debug 工具 , 安装完成后执行 v8-debug --help 可以查看有哪些命令:
# 执行 help 命令查看支持的参数v8-debug --helpSynopsis: shell [options
[--shell
[file...
d8 [options
[-estring
[--shell
[[--module|--web-snapshot
file...
-e execute a string in V8 --shell run an interactive JavaScript shell --module execute a file as a JavaScript module --web-snapshot execute a file as a web snapshotSSE3=1 SSSE3=1 SSE4_1=1 SSE4_2=1 SAHF=1 AVX=1 AVX2=1 FMA3=1 BMI1=1 BMI2=1 LZCNT=1 POPCNT=1 ATOM=0The following syntax for options is accepted (both '-' and '--' are ok): --flag (bool flags only) --no-flag (bool flags only) --flag=value (non-bool flags only no spaces around '=') --flag value (non-bool flags only) -- (captures all remaining args in JavaScript)Options: # 打印生成的字节码 --print-bytecode (print bytecode generated by ignition interpreter) type: bool default: --noprint-bytecode # 跟踪被优化的信息 --trace-opt (trace optimized compilation) type: bool default: --notrace-opt --trace-opt-verbose (extra verbose optimized compilation tracing) type: bool default: --notrace-opt-verbose --trace-opt-stats (trace optimized compilation statistics) type: bool default: --notrace-opt-stats # 跟踪去优化的信息 --trace-deopt (trace deoptimization) type: bool default: --notrace-deopt --log-deopt (log deoptimization) type: bool default: --nolog-deopt --trace-deopt-verbose (extra verbose deoptimization tracing) type: bool default: --notrace-deopt-verbose --print-deopt-stress (print number of possible deopt points) # 查看编译生成的 AST --print-ast (print source AST) type: bool default: --noprint-ast # 查看编译生成的代码 --print-code (print generated code) type: bool default: --noprint-code # 查看优化后的代码 --print-opt-code (print optimized code) type: bool default: --noprint-opt-code # 允许在源代码中使用 V8 提供的原生 API 语法 --allow-natives-syntax (allow natives syntax) type: bool default: --noallow-natives-syntax 2 生成 AST
我们编写一个 index.js 文件 , 在文件中写入 JavaScript 代码 , 执行一个简单的 add 函数:
function add(x y) { return x + yconsole.log(add(1 2)); 使用 --print-ast 参数可以打印 add 函数的 AST 信息:
v8-debug --print-ast ./index.js[generating bytecode for function:
--- AST ---FUNC at 0. KIND 0. LITERAL ID 0. SUSPEND COUNT 0. NAME \"\". INFERRED NAME \"\". DECLS. . FUNCTION \"add\" = function add. EXPRESSION STATEMENT at 41. . ASSIGN at -1. . . VAR PROXY local[0
(0x7fb8c080e630) (mode = TEMPORARY assigned = true) \".result\". . . CALL. . . . PROPERTY at 49. . . . . VAR PROXY unallocated (0x7fb8c080e6f0) (mode = DYNAMIC_GLOBAL assigned = false) \"console\". . . . . NAME log. . . . CALL. . . . . VAR PROXY unallocated (0x7fb8c080e470) (mode = VAR assigned = true) \"add\". . . . . LITERAL 1. . . . . LITERAL 2. RETURN at -1. . VAR PROXY local[0