原本打算是把node源码看得差不多了再去深入V8的,但是这两者基本上没办法分开讲。

  与express是基于node的封装不同,node是基于V8的一个应用,源码内容已经渗透到V8层面,因此这章简述一下我目前理解的V8引擎吧。

  首先需要理解的是V8是一个JS代码运行平台,可以将JS代码编译执行。

  本节就非常浅显的讲一下V8内部一些常见类,以及一个运行JS代码的简单demo。

  (由于研究V8引擎原理的人非常多,本人学识浅薄,可以去参考别人的博客)

参考资料:

  1、很多大佬的博客

  2、V8引擎API文档:https://v8docs.nodesource.com/

  3、github:https://github.com/v8/v8

  

  本节先列举一些核心类,示例代码大部分来源于node中的源码。

Isolate

  该类代表一个V8引擎实例,有自己独立的状态,用法如下。

1、不能使用new关键字来生成一个实例,只能通过类方法Isolate::New(params)来创建。

Isolate* const isolate = Isolate::New(params);

2、该类的方法都是设置V8引擎的一些处理细节。

// 添加error的信息监听器
isolate->AddMessageListener(OnMessage);
// 从名字能看出来 设置未捕捉中断异常的回调函数
isolate->SetAbortOnUncaughtExceptionCallback(ShouldAbortOnUncaughtException);
// 设置Microtask的执行方式(有三种)
isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit);
// 设置致命错误的回调函数
isolate->SetFatalErrorHandler(OnFatalError);
// WebAssembly代码生成回调函数
isolate->SetAllowWasmCodeGenerationCallback(AllowWasmCodeGenerationCallback);

3、作为一个参数传入其余的V8工具类中。

// 单线程运行V8的Isolate
Locker locker(isolate);
Isolate::Scope isolate_scope(isolate);

Local/Persistent - Handle

  这个地方我之前一直比较混乱,因为有文章指出:Handle类定义在v8.h中,它是一个模板类,而且有两个派生类Local和Persistent。

  出处:https://blog.csdn.net/sunbxonline/article/details/20310897

  但是从源码来看,无论是Local<T>还是MaybeLocal<T>,均不继承于任何类(在V8中确实存在一个Handle的类,但是跟这两个没有继承关系)。

  这是因为V8版本不一致,所以我这里只讲当前版本的情况,源码注释如下:

#if !defined(V8_IMMINENT_DEPRECATION_WARNINGS)
// Handle is an alias for Local for historical reasons.
template <class T>
using Handle = Local<T>;
#endif

  这两个类从作用上讲都是handle,但实际上并不继承于同一个父类。

1、Local/Persistent是V8的两个类,指向底层的原始数据。

2、所有对象的引用都需要被V8的垃圾回收管理,在管理中可能出现移动对象的情况(参考网上大量关于V8垃圾回收的博客),这会导致对象指针产生错误,所以不能直接使用原始的数据类型,诸如String,而需要使用Local<String>,Local被V8引擎管理,会在对象移动时更新指针指向,并在合适的时候进行回收。

3、Persistent属于全局对象(可参考Global),独立于HanldeScope,可使用Reset方法清空。

Value

  所以JS数据类型映射到C++的根类,继承关系如下:

  具体的内部实现后面做分析。

HandleScope

  一个管理handle的容器,在当前作用域开头声明一个HanldeScope,在域结束时会自动清理所有的handle。

HandleScope handle_scope(isolate);

  嵌套使用时,作用域会自动进行切换。

Context

  执行上下文,有自己独立的函数与对象。与Isolate相似,通过类方法New来生成。

auto context = Context::New(isolate, nullptr, object_template);

  可通过内部Scope类来进行上下文的切换。

Context::Scope context_scope(context);

Script

  该类主要负责对JS代码字符串进行编译和执行,核心方法为Compile、Run。

  Script::Compile可以编译JS代码字符串,返回一个Local<Script>对象

  Script::Run可以执行编译后的JS代码,返回一个Handle<Value>对象

  另外,还有FunctionTemplate/ObjectTemplate可以封装C++的对象、函数提供给JS代码调用,示例代码如下:

// 将C++的GetBinding函数包装提供给JS代码调用
// NewFunctionTemplate是v8::FunctionTemplate::New()方法的包装
v8::Local<v8::Function> get_binding_fn =
env->NewFunctionTemplate(GetBinding)->GetFunction(env->context())
.ToLocalChecked();

  基本上大部分用到的东西就是上面所列举的,GC暂时不讨论,以一个非常简单的网上案例把上面的东西串起来:

// 创建一个Isolate实例
Isolate::CreateParams params;
Isolate* const isolate = Isolate::New(params);
// 创建一个HandleScope管理handle
HandleScope handle_scope(isolate);
// 创建一个上下文执行环境
Local<Context> context = Context::New(isolate);
// 切换到当前上下文
Context::Scope context_scope(context);
// 新建一个Local
// 类型可以类比JS的源字符串
Local<String> source = v8::String::NewFromOneByte(isolate , "");
// 编译该JS字符串
MaybeLocal<v8::Script> script = v8::Script::Compile(context , source);
// 执行上面返回的编译对象
Local<Value> result = script.ToLocalChecked()->Run(context).ToLocalChecked();
// 这个result就是对JS源字符串编译执行后的C++代码
Local<String> str = result->ToString(context ).ToLocalChecked();

  这样,对V8引擎就有了一个基本的认识,可以帮助我们更好的学习nodejs源码。

深入出不来nodejs源码-V8引擎初探的更多相关文章

  1. 深入出不来nodejs源码-内置模块引入初探

    重新审视了一下上一篇的内容,配合源码发现有些地方说的不太对,或者不太严谨. 主要是关于内置模块引入的问题,当时我是这样描述的: 需要关注的只要那个RegisterBuiltinModules方法,从名 ...

  2. 深入出不来nodejs源码-timer模块(JS篇)

    鸽了好久,最近沉迷游戏,继续写点什么吧,也不知道有没有人看. 其实这个node的源码也不知道该怎么写了,很多模块涉及的东西比较深,JS和C++两头看,中间被工作耽搁回来就一脸懵逼了,所以还是挑一些简单 ...

  3. 深入出不来nodejs源码-编译启动(1)

    整整弄了两天,踩了无数的坑,各种奇怪的error,最后终于编译成功了. 网上的教程基本上都过时了,或者是版本不对,都会报一些奇怪的错误,这里总结一下目前可行的流程. node版本:v10.1.0. 首 ...

  4. 深入出不来nodejs源码-events模块

    这一节内容超级简单,纯JS,就当给自己放个假了,V8引擎和node的C++代码看得有点脑阔疼. 学过DOM的应该都知道一个API,叫addeventlistener,即事件绑定.这个东西贯穿了整个JS ...

  5. 深入出不来nodejs源码-从fs.stat方法来看node架构

    node的源码分析还挺多的,不过像我这样愣头完全平铺源码做解析的貌似还没有,所以开个先例,从一个API来了解node的调用链. 首先上一张整体的图,网上翻到的,自己懒得画: 这里的层次结构十分的清晰, ...

  6. 深入出不来nodejs源码-内置模块引入再探

    我发现每次细看源码都能发现我之前写的一些东西是错误的,去改掉吧,又很不协调,不改吧,看着又脑阔疼…… 所以,这一节再探,是对之前一些说法的纠正,另外再缝缝补补一些新的内容. 错误在哪呢?在之前的初探中 ...

  7. 深入出不来nodejs源码-流程总览

    花了差不多两周时间过了下primer C++5th,完成了<C++从入门到精通>.(手动滑稽) 这两天看了下node源码的一些入口方法,其实还是比较懵逼的,语法倒不是难点,主要是大量的宏造 ...

  8. 深入出不来nodejs源码-timer模块(C++篇)

    终于可以填上坑了. 简单回顾一下之前JS篇内容,每一次setTimeout的调用,会在一个对象中添加一个键值对,键为延迟时间,值为一个链表,将所有该时间对应的事件串起来,图如下: 而每一个延迟键值对的 ...

  9. Django 源码小剖: 初探 WSGI

    Django 源码小剖: 初探 WSGI python 作为一种脚本语言, 已经逐渐大量用于 web 后台开发中, 而基于 python 的 web 应用程序框架也越来越多, Bottle, Djan ...

随机推荐

  1. [LintCode] Permutations II

    Given a collection of numbers that might contain duplicates, return all possible unique permutations ...

  2. jQuery ajax 302跨域

    一.ajax 302 ajax用于异步获取服务器数据,但是某天有这么一个使用场景: > 基于安全考虑,登录的用户的信息失效时,系统的所有ajax接口都由服务器直接重定向到系统的登录页面,此时登录 ...

  3. BZOJ百题版切计划(不咕)

    传送门 BZOJ 前言 听说最近要省选,那么我就写一下吧.QwQ! 1000 过于简单,不写了. 1001 不会对偶图,直接优化最小割 题解 1002 高精度套公式计算 题解 (Code by hey ...

  4. CS231-Multi-calss SVM的求导

    接着上周的更,上周我们更到,在对图像的线性分类中,我们只用multi-class 的svm,然后我们得到以下的损失函数 这里每个数值代表为下: X 是一个 N by D 的矩阵,N 代表 traini ...

  5. PHP中正则表达式函数(Perl兼容)

    PHP为使用Perl兼容的正则表达式搜索字符串提供了7个函数,分别是preg_grep().preg_match().preg_match_all().preg_quote().preg_replac ...

  6. Android根据字符串型的资源名获取对应资源id

    有时候我们想动态的根据一个字符串资源名获得到对应的资源id,如根据不同的图片名称获得对应的图片,此时就应该考虑如何实现. 大家知道,在编译Android工程时,系统会自动生成一个静态资源类R,里面根据 ...

  7. flask_ Mongodb 的语法-排序

    MOngoDB的排序是挺有用的   ,跟MySQL有明显的区别 .. 它的原生语法的第一个参数为条件限定,第二个参数为排序字段 db.news.find({},{'_id':1})   #1是升序  ...

  8. java 简单认识移位运算符和位运算符

    移位运算符和位运算符本质上都是操作二进制位,因为计算机存储的是二进制数据,运算效率相对较高. 移位运算符:把整数的二进制位进行左移或右移 .左移一位,相当于这个数乘以2, 右移一位,相当于这个数除以2 ...

  9. git提交的问题

    1. Pull is not possible because you have unmerged files.症状:pull的时候$ git pull Pull is not possible be ...

  10. 安装eclipse启动时报错

    1.在安装eclipse后,点击exe文件时,提示出现错误,记录在log文件中,因为log文件就是日志文件,可以方便我们排查错误,打开log文件,可以看到文件记录了每次出错的时间和错误栈信息,最新一次 ...