当前位置: 移动技术网 > IT编程>开发语言>JavaScript > 深入V8引擎-AST(1)

深入V8引擎-AST(1)

2019年07月01日  | 移动技术网IT编程  | 我要评论

  没办法了,开坑吧,接下来的几篇会讲述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>();
}

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网