花了5篇才把一个字符串词法给解析完,不知道要多久才能刷完整个流程,GC、复杂数据类型的V8实现那些估计又是几十篇,天呐,真是给自己挖了个大坑。

前面几篇实际上只是执行了scanner.Initialize方法,并未开始全面解析,继续跑流程。

FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
// ...
/**
* 前面完成了这一步
*/
scanner_.Initialize();
if (FLAG_harmony_hashbang) {
scanner_.SkipHashBang();
}
// 接下来进这个方法
FunctionLiteral* result = DoParseProgram(isolate, info);
// ...
return result;
}

后面的方法域都在Parser类下,毕竟这是整个AST的执行类,parseInfo只是一个编译信息的存储类,直接进DoParseProgram方法。

FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
// ...
FunctionLiteral* result = nullptr;
{
// ...
ScopedPtrList<Statement> body(pointer_buffer());
int beg_pos = scanner()->location().beg_pos;
if (parsing_module_) {
// ...
} else if (info->is_wrapped_as_function()) {
ParseWrapped(isolate, info, &body, scope, zone());
} else {
// 进入这里
this->scope()->SetLanguageMode(info->language_mode());
ParseStatementList(&body, Token::EOS);
}
// ...
}
// ...
return result;
}

这里对编译描述类进行查询,判断待编译字符串是否是模块、包装函数,会进入不同的分支,由于测试代码只是两个字符串相加,所以进入最后的分支。

void ParserBase<Impl>::ParseStatementList(StatementListT* body, Token::Value end_token) {
// ... /**
* 当之前初始化的第一个Token是字符串时
* 判断可能是设置模式
*/
while (peek() == Token::STRING) {
bool use_strict = false;
bool use_asm = false; Scanner::Location token_loc = scanner()->peek_location();
/**
* 做字符串严格判定
* 声明类似于"use strict"、"use \nstrict"、"use \x73trict"都是不合法的
*/
if (scanner()->NextLiteralExactlyEquals("use strict")) {
use_strict = true;
} else if (scanner()->NextLiteralExactlyEquals("use asm")) {
use_asm = true;
} // 这里提前进行解析
StatementT stat = ParseStatementListItem();
// ... if (use_strict) {
// 进入严格模式
} else if (use_asm) {
// 进入asm模式
} else {
// 非配置字符串 进入普通模式
RaiseLanguageMode(LanguageMode::kSloppy);
}
} TargetScopeT target_scope(this);
/**
* 其他情况全面解析AST
*/
while (peek() != end_token) {
StatementT stat = ParseStatementListItem();
if (impl()->IsNull(stat)) return;
if (stat->IsEmptyStatement()) continue;
body->Add(stat);
}
}

这一步v8对之前解析的第一个词法进行了判断,来选择是否开启严格模式或者asm模式,可以看一眼严格模式定义。

To invoke strict mode for an entire script, put the exact statement "use strict"; (or 'use strict';) before any other statements.

由于这个语句必须出现在最前面,所以会在进行全面转换前判断待编译字符串的第一个Token是不是严格等于这个字符串,来设置编译模式。

这里还有另外一个新鲜的配置,即"use asm",大部分人不会接触到这个东西,asm是JavaScript的一个子集,虽然语法总的来说也是JS的,但是非常难阅读,对于机器来说更加友好。如果用了这个配置,v8会跳过一些阶段,直接将代码编译成机器指令(贴一个介绍链接)。

如果不配置模式,v8会以普通模式来编译代码,随后底部的while循环指向了全面的AST转换。

先简单介绍一下AST的容器body,初始化代码如下。

/**
* 构造函数参数是一个指针 指向一个内容为任意指针的vector
* std::vector<void*>* pointer_buffer() { return &pointer_buffer_; }
* std::vector<void*> pointer_buffer_;
* ScopedPtrList<Statement>的简写类型为StatementListT 定义如下
* using StatementListT = typename Types::StatementList;
* using Types = ParserTypes<Impl>;
* struct ParserTypes<Parser> { using StatementList = ScopedPtrList<v8::internal::Statement>; }
*/
ScopedPtrList<Statement> body(pointer_buffer());

这里的类型包含两部分,一个是容器类ScopePtrList,一个是内容Statement,先看容器。

template <typename T>
class ScopedPtrList final {
public:
void Add(T* value) {
buffer_.push_back(value);
++end_;
}
private:
std::vector<void*>& buffer_;
size_t start_;
size_t end_;
}

象征性的给一些属性和方法,传统的vector一把梭,知道一个Add方法就差不多了,反正都那样。

至于Statement类则是标准的抽象语法树节点类,简单看一下定义就行了,其本身没有什么东西,大量的枚举类型都定义在父类上,暂时不展开。

class Statement : public AstNode {
protected:
Statement(int position, NodeType type) : AstNode(position, type) {} static const uint8_t kNextBitFieldIndex = AstNode::kNextBitFieldIndex;
};

转换的AST会以Statement类存储,并通过Add方法加到容器中。

这一篇感觉啥都没写,先这样吧,下一篇开始正式全面解析AST。

深入V8引擎-AST(6)的更多相关文章

  1. 深入V8引擎-AST(1)

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

  2. 深入V8引擎-AST(3)

    上篇简单介绍了入口方法的流程以及scanner类相关的部分内容,这一篇主要讲scanner的初始化,即 scanner_.Initialize(); 注意,这不是调用静态方法.实际上Parser实例生 ...

  3. 深入V8引擎-AST(2)

    先声明一下,这种长系列的大块头博客只能保证尽可能的深入到每一行源码,有些代码我不乐意深究就写个注释说明一下作用.另外,由于本地整理的比较好,博客就随心写了. 整个Compile过程目前只看到asmjs ...

  4. 深入V8引擎-AST(4)

    (再声明一下,为了简单暴力的讲解AST的转换过程,这里的编译内容以"'Hello' + ' World'"作为案例) 上一篇基本上花了一整篇讲完了scanner的Init方法,接下 ...

  5. 深入V8引擎-AST(5)

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

  6. [翻译] V8引擎的解析

    原文:Parsing in V8 explained 本文档介绍了 V8 引擎是如何解析 JavaScript 源代码的,以及我们将改进它的计划. 动机 我们有个解析器和一个更快的预解析器(~2x), ...

  7. 精读《V8 引擎 Lazy Parsing》

    1. 引言 本周精读的文章是 V8 引擎 Lazy Parsing,看看 V8 引擎为了优化性能,做了怎样的尝试吧! 这篇文章介绍的优化技术叫 preparser,是通过跳过不必要函数编译的方式优化性 ...

  8. Javascript的V8引擎研究

    1.针对上下文的Snapshot技术 什么是上下文(Contexts)?实际是JS应用程序的运行环境,避免应用程序的修改相互影响,例如一个页面js修改内置对象方法toString,不应该影响到另外页面 ...

  9. V8引擎——详解

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

随机推荐

  1. 搞NDK开发

    1.哪些场景下要用到NDK开发? 跨平台的库,如FFmpeg, skip,weex, 加固,防逆向 签名校验 图片压缩 音视频解码 OpenGL ES 高级特效 热修复 andfix 人脸识别 fac ...

  2. xcode6新建工程

    xcode6中新建空工程 (2014-10-29 13:14:44) 转载▼ 标签: it ios 分类: iOS 升级xcode6之后,直接建立Empty工程后发现,这是太坑,真的是什么都没有啊.只 ...

  3. JVM源码分析之MetaspaceSize和MaxMetaspaceSize的区别

    JVM加载类的时候,需要记录类的元数据,这些数据会保存在一个单独的内存区域内,在Java 7里,这个空间被称为永久代(Permgen),在Java 8里,使用元空间(Metaspace)代替了永久代. ...

  4. 3.UML中的类图及类图之间的关系

    统一建模语言简介 统一建模语言(Unified Modeling Language,UML)是用来设计软件蓝图的可视化建模语言,1997 年被国际对象管理组织(OMG)采纳为面向对象的建模语言的国际标 ...

  5. linux设备驱动程序-设备树(1)-dtb转换成device_node

    linux设备驱动程序-设备树(1)-dtb转换成device_node 本设备树解析基于arm平台 从start_kernel开始 linux最底层的初始化部分在HEAD.s中,这是汇编代码,我们暂 ...

  6. Spark之RDD

    Spark学习之路Spark之RDD 目录 一.RDD的概述 1.1 什么是RDD? RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数 ...

  7. mysql udf提权实战测试

    根据前天对大牛们的资料学习,进行一次mysql udf提权测试. 测试环境: 受害者系统:centos 7.7 ,docker部署mysql5.6.46, IP:192.168.226.128 攻击者 ...

  8. 201871020225-牟星源《面向对象程序设计(java)》第6-7周学习总结

    201871020225-牟星源<面向对象程序设计(java)>第6-7周学习总结 博文正文: 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu- ...

  9. SpringBoot相关的注解

    一.注解(annotations)列表 @SpringBootApplication:包含了@ComponentScan.@Configuration和@EnableAutoConfiguration ...

  10. 阿里云serverless使用笔记

    1.使用api网关服务,创建完api后,测试时,需要传“请求签名”,否则会报401 ‘Empty Signature’错误.相关文档<错误编码表,请求签名>.(错误信息放置与响应头的‘x- ...