没办法了, 开坑吧, 接下来的几篇会讲述 JavaScript 字符串源码在 v8 中转换成 AST(抽象语法树)的过程.
JS 代码在 V8 的解析只有简单的几步, 其中第一步就是将源字符串转换为抽象语法树, 非常类似于 vue 中将 html 转换为 VNODE 的过程. 该过程涉及的类并不多, 均位于 / src/parsing 文件夹中, 包括 parsing,parser,scanner,token 等等, 先简单介绍一下各类的作用.
Parser => 核心类, 掌管了整个转换过程, 内部包含 scanner,parse-info 等私有属性, 产出抽象语法树
Parsing => 这只是命名空间, 全称为 v8::interval::parsing, 提供 ParseProgram,ParseFunction,ParseAny 作为 parse 的入口方法
ParseInfo => 编译信息的描述类, 包含大量配置参数与编译后的容器
Scanner => 负责逐字解析解析源字符串的类, 提供比较上层的 API, 初始化的 Initialize 方法会初始化所有变量并步进一格
Scanner-character-streams => 所有源字符串都需要根据类型转换为该类, 这个类提供解析的实际操作, 诸如 Peek(返回当前解析位置项),Advance(解析过程前进一步)等等
Token => 包含所有抽象语法树类型的枚举, 例如关键词 (const,if), 符号((,{) 等等
这些所有的类通过互相合作, 最后产出一个类型为 FunctionLiteral 的结果, 将其传入 asm 模块, 生成底层代码.
类型的继承关系树如下.
其实发现这个过程还是挺痛苦的, 因为从 Compile 一路看下来, 发现直接就进了 asm 变成了汇编语言, 可以说一切来的那么突然, 我根本找不到突破点. 当然, 如果去掉一些无关的配置和 CHECK, 可以找到编译核心属性, 比如说最后的 AsmJs 部分是这样调用的.
- MaybeHandle<SharedFunctionInfo> GenerateUnoptimizedCodeForToplevel(
- Isolate* isolate, ParseInfo* parse_info, AccountingAllocator* allocator,
- IsCompiledScope* is_compiled_scope) {
- // ...
- std::vector<FunctionLiteral*> functions_to_compile;
- functions_to_compile.push_back(parse_info->literal());
- while (!functions_to_compile.empty()) {
- FunctionLiteral* literal = functions_to_compile.back();
- functions_to_compile.pop_back();
- Handle<SharedFunctionInfo> shared_info =
- Compiler::GetSharedFunctionInfo(literal, script, isolate);
- if (shared_info->is_compiled()) continue;
- if (UseAsmWasm(literal, parse_info->is_asm_wasm_broken())) {
- std::unique_ptr<UnoptimizedCompilationJob> asm_job(
- AsmJs::NewCompilationJob(parse_info, literal, allocator));
- if (asm_job->ExecuteJob() == CompilationJob::SUCCEEDED &&
- FinalizeUnoptimizedCompilationJob(asm_job.get(), shared_info, isolate) == CompilationJob::SUCCEEDED) {
- continue;
- }
- }
- // ...
- }
- // ...
- return top_level;
- }
鬼一样的代码, 只看最后返回的话, 可以看出所有的调用都涉及那个 literal.
而这个 literal 是 parse_info 的一个属性, 初始化时是 NULL, 在 compile 的某一步一定进行处理了, 于是回头去翻了一遍整个编译过程.
最后终于在 CompileTopLevel 找到了关键的一行代码.
- if (parse_info->literal() == nullptr && !parsing::ParseProgram(parse_info, isolate)) {
- return MaybeHandle<SharedFunctionInfo>();
- }
而这里, 就是解析源代码成抽象语法树的地方, 后面会从这里入手, 边看边写吧.
来源: https://www.cnblogs.com/QH-Jimmy/p/11113303.html