• 深入出不来nodejs源码-V8引擎初探


      原本打算是把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 , "12345");
    // 编译该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源码。

  • 相关阅读:
    ios 动态监听键盘输入法和高度
    [置顶] Android常用UI控件之PopupWindow
    Subsets II
    采用移位方法获取汉字编码
    wxPython利用pytesser模块实现图片文字识别
    Ubuntu下搭建Java开发环境
    贴心设计:打造高可用性的移动产品
    java 静态方法和实例方法的区别
    sql 2005 update语句
    ios状态栏操作
  • 原文地址:https://www.cnblogs.com/QH-Jimmy/p/9212923.html
Copyright © 2020-2023  润新知