深入V8引擎-AST(1)

╰+攻爆jí腚メ 2021-11-27 03:48 476阅读 0赞

  没办法了,开坑吧,接下来的几篇会讲述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模块,生成底层代码。

  类型的继承关系树如下。

858904-20190701114720838-648401312.png

  其实发现这个过程还是挺痛苦的,因为从Compile一路看下来,发现直接就进了asm变成了汇编语言,可以说一切来的那么突然,我根本找不到突破点。当然,如果去掉一些无关的配置和CHECK,可以找到编译核心属性,比如说最后的AsmJs部分是这样调用的。

  1. MaybeHandle<SharedFunctionInfo> GenerateUnoptimizedCodeForToplevel(
  2. Isolate* isolate, ParseInfo* parse_info, AccountingAllocator* allocator,
  3. IsCompiledScope* is_compiled_scope) {
  4. // ...
  5. std::vector<FunctionLiteral*> functions_to_compile;
  6. functions_to_compile.push_back(parse_info->literal());
  7. while (!functions_to_compile.empty()) {
  8. FunctionLiteral* literal = functions_to_compile.back();
  9. functions_to_compile.pop_back();
  10. Handle<SharedFunctionInfo> shared_info =
  11. Compiler::GetSharedFunctionInfo(literal, script, isolate);
  12. if (shared_info->is_compiled()) continue;
  13. if (UseAsmWasm(literal, parse_info->is_asm_wasm_broken())) {
  14. std::unique_ptr<UnoptimizedCompilationJob> asm_job(
  15. AsmJs::NewCompilationJob(parse_info, literal, allocator));
  16. if (asm_job->ExecuteJob() == CompilationJob::SUCCEEDED &&
  17. FinalizeUnoptimizedCompilationJob(asm_job.get(), shared_info, isolate) == CompilationJob::SUCCEEDED) {
  18. continue;
  19. }
  20. }
  21. // ...
  22. }
  23. // ...
  24. return top_level;
  25. }

  鬼一样的代码,只看最后返回的话,可以看出所有的调用都涉及那个literal。

  而这个literal是parse_info的一个属性,初始化时是NULL,在compile的某一步一定进行处理了,于是回头去翻了一遍整个编译过程。

858904-20190701123340797-1526365388.png

  最后终于在CompileTopLevel找到了关键的一行代码。

  1. if (parse_info->literal() == nullptr && !parsing::ParseProgram(parse_info, isolate)) {
  2. return MaybeHandle<SharedFunctionInfo>();
  3. }

  而这里,就是解析源代码成抽象语法树的地方,后面会从这里入手,边看边写吧。

转载于:https://www.cnblogs.com/QH-Jimmy/p/11113303.html

发表评论

表情:
评论列表 (有 0 条评论,476人围观)

还没有评论,来说两句吧...

相关阅读

    相关 V8引擎的内存收回

    V8引擎的内存收回 前言 JS语言不像C/C++, 让程序员自己去开辟或者释放内存,而是类似Java,采用自己的一套垃圾回收算法进行自动的内存管理。 我们知

    相关 谷歌v8引擎详解

    前言   JavaScript绝对是最火的编程语言之一,一直具有很大的用户群,随着在服务端的使用(NodeJs),更是爆发了极强的生命力。编程语言分为编译型语言和解释型语

    相关 深入V8引擎-AST(1)

      没办法了,开坑吧,接下来的几篇会讲述JavaScript字符串源码在v8中转换成AST(抽象语法树)的过程。   JS代码在V8的解析只有简单的几步,其中第一步就是将源字

    相关 深入V8引擎-AST(5)

    懒得发首页了,有时候因为贴的代码太多会被下,而且这东西本来也只是对自己学习的记录,阅读体验极差,所以就本地自娱自乐的写着吧! 由于是解析字符串,所以在开始之前介绍一下词法结构

    相关 v8引擎详解

    前言 `JavaScript`绝对是最火的编程语言之一,一直具有很大的用户群,随着在服务端的使用(`NodeJs`),更是爆发了极强的生命力。编程语言分为编译型语言和解释