YC Yc.W home Systems · C++ · AI Infrastructure
Programming · Note

Node.js C++ Plug-In v8

Explore all Programming notes →

几个重要的类:

  • V8:这个是个大杂烩的工具类,从初始化到关闭平台都离不开它;
  • ArrayBuffer是v8的数据类型;
  • Isolate是v8中最重要的功能类,代表了一个v8引擎的实例。它不是线程安全的,如果在线程不安全情况下运行需要加锁;
  • Local是v8中存储对象的结构,代表了被GC管理的对象引用。与其对应的就是持久性对象,如Global和Persistent;
  • Context代表了在沙箱中运行的上下文。与Java一样,JavaScript也运行在一个沙箱安全环境中;
  • Script代表了运行在v8中的脚本;

对象与句柄 与C/C++与Rust等存在栈式管理的语言不同,JavaScript并没有栈上分配这样的概念。但是在v8的实现中,是有通过栈式管理作用域的数据结构,就是例程中我们所看到的HandleScope。 另外还有SealHandleScope类,将当前的HandleScope封装起来,强制需要创建新的HandleScope. v8中的对象按生命周期可以分为两类,由GC管理的局部对象Local,还有持久性的对象。 持久性的对象分为:一次性的永续对象Eternal,和全局性的PersistentBase。 PersistentBase根据管理所有权方式的不同,采用赋值和复制方式的叫做Persistent,采用移动语义的叫做Global. 还有个UniquePersistent的模块类,其实是Global的别名。C++11中定义模板别名的方式,之前我们有文章讲过了: template using UniquePersistent = Global;

从例子中我们可以看到,通常我们使用的变量都是Local为主。不管是Context,String,Script还是Value都是通过Local模板来进行管理的: // Create a new context. Local context = Context::New(isolate); Local source = String::NewFromUtf8(isolate, "'Hello' + ', World!'", NewStringType::kNormal).ToLocalChecked(); // Compile the source code. Local

现在并没有一个共同的Handle基类,Local,Eternal和PersistentBase之间没有共基类的关系。 由于返回值也大部分是Local,为了强制代码判空,v8经常使用MaybeLocal的模块,它是Local的一个封装。

脚本相关的API 脚本相关的API主要涉及到三个部分:源代码,编译后的脚本代码和编译器三部分。 源代码表示的类是ScriptOrigin和ScriptOriginOptions. 编译之后的脚本,按照是否跟上下文绑定,分为UnboundScript和Script两种。 编译器是ScriptCompiler. 另外,脚本的运行时信息也是很重要的结构,v8提供了包装错误信息的Message类,提供跟踪栈信息的StackTrace和StackFrame。

所有的v8数据类型都继承自Data类

Value类是所有的JavaScript类型的基类,它有两个巨大的子类,一个是代表原始类型的Primitive,一个就是所有js对象之根Object类。当然,还有个实现上用途的包装C++ void*指针的External类。 ES6新增了Symbol类型,它和String共同派生自Name类型。 虽然JavaScript的数都是浮点数,但是在v8的实现里,整数仍然是大行其道的。 对象类型中,Promise, Proxy, ArrayBufferView这些都是ES6新增的。有些还需要–harmony选项的支持。 剩下是对于原始类型的包装,如NumberObject, BooleanObject, StringObject, SymbolObject。 还有的就是Date日期类和RegExp正则表达式类两个内置类的支持,也在API中。 最后,直接继承自Data的,还有4个类:

  • Private:私有的符号
  • Template:模板,分为函数模板和对象模板。这两个在后面我们分析v8的实现中有重要意义,因为它们是将JavaScript函数或者对象绑定到C++相应的对象上的重要工具。
  • 两个签名类,用于调用时检验用

v8提供了可供外部调用的一系列的API:

  • Isolate:提供了一个v8虚拟机的实例
  • Context:提供了一个沙箱,也就是独立的上下文可以运行Isolate
  • v8通过HandleScope栈式管理内存
  • Local<>是最常用的变量分配方式
  • v8的数据类型基类是Data,所有js对象的基类是Value。Value下面分Primitive和Object 最后引用一个新概念,v8为了提升性能,引入了一个高效的编译器Crankshaft.

  • Demo
    void _Action(const FunctionCallbackInfo<v8::Value>& args) {
          printf("_Action: Enter the function!\n");
          Isolate* isolate = args.GetIsolate();
    
          // Check the number of arguments passed.
          if (args.Length() != 1)
          {
              // Throw an Error that is passed back to JavaScript
              isolate->ThrowException(Exception::TypeError(
                  String::NewFromUtf8(isolate,
                      "Wrong number of arguments",
                      NewStringType::kNormal).ToLocalChecked()));
    
              Local<Number> nReturn = Number::New(isolate, -1);
              args.GetReturnValue().Set(nReturn);
              return;
          }
    
          // Check the argument types
          if (!args[0]->IsString())
          {
              isolate->ThrowException(Exception::TypeError(
                  String::NewFromUtf8(isolate,
                      "Wrong arguments",
                      NewStringType::kNormal).ToLocalChecked()));
    
              Local<Number> nReturn = Number::New(isolate, -1);
              args.GetReturnValue().Set(nReturn);
              return;
          }
    
          int nRes = 1;
          std::string strValue;
          ////string
          //GetInputParameterString(isolate, args[0], strValue);
          Local<v8::Value> vInputParam = args[0];
          if (!vInputParam.IsEmpty())
          {
              strValue = *String::Utf8Value(isolate, vInputParam);
              if (strValue != "undefined")
              {
              }
          }
    
          ////Object
          //std::string strValue;
          //int GetInputParameterObject(Isolate* pIsolate, Local<v8::Value> vInputParamter,char* pszKeyName, std::string& strValue)
          Local<Object> ObjInfo = args[0]->ToObject(isolate);
          vInputParam = ObjInfo->Get(String::NewFromUtf8(isolate, "ID"));
          if (!vInputParam.IsEmpty())
          {
              strValue = *String::Utf8Value(isolate, vInputParam);
              if (strValue != "undefined")
              {
              }
          }
    
          //函数返回值
          Local<Number> nReturn = Number::New(isolate, nRes);
          args.GetReturnValue().Set(nReturn);
      }
    
  • Tool Function:
    
      void SetObjectInfo(const char* pszKeyName, char* pszInfo, Local<Object> objInfo)
      {
          printf("SetObjectInfo: Enter the function!\n");
          Isolate* isolate = Isolate::GetCurrent();
          Local<v8::Context> context = isolate->GetCurrentContext();
          //v8::MaybeLocal<Object> objLicenseLockInfo = args[0]->ToObject(context);
    
          if ((pszInfo != NULL) && (pszKeyName != NULL))
          {
              //objInfo->Set(String::NewFromUtf8(isolate, pszKeyName), String::NewFromUtf8(isolate, pszInfo));
              objInfo->Set(context, String::NewFromUtf8(isolate, pszKeyName, v8::NewStringType::kNormal).ToLocalChecked(), String::NewFromUtf8(isolate, pszInfo, v8::NewStringType::kNormal).ToLocalChecked()).FromJust();
              printf("SetObjectInfo: Successfully exit from the function!\n");
          }
          else
          {
              //objInfo->Set(String::NewFromUtf8(isolate, "Default"), String::NewFromUtf8(isolate, "{}"));
              objInfo->Set(context, String::NewFromUtf8(isolate, "Default", v8::NewStringType::kNormal).ToLocalChecked(), String::NewFromUtf8(isolate, pszInfo, v8::NewStringType::kNormal).ToLocalChecked()).FromJust();
    
              printf("SetObjectInfo: Param is NULL, exit from the function!\n");
          }
      }
    
      int GetInputParameterString(Isolate* pIsolate, Local<v8::Value> vInputParamter, std::string& strValue)
      {
          if (!vInputParamter.IsEmpty())
          {
              strValue = *String::Utf8Value(pIsolate, vInputParamter);  //if none, "undefined"
              if (strValue != "undefined")
              {
    
              }
              return 0;
          }
          return -1;
      }
    
      int GetInputParameterObject(Isolate* pIsolate, Local<v8::Value> vInputParamter,char* pszKeyName, std::string& strValue)
      {
    
          Local<Object> ObjUserAccountInfo = vInputParamter->ToObject(pIsolate);
          Local<v8::Value> varUserDesc = ObjUserAccountInfo->Get(String::NewFromUtf8(pIsolate, pszKeyName));
          if (!varUserDesc.IsEmpty())
          {
              strValue = *String::Utf8Value(pIsolate, varUserDesc);
              if (strValue != "undefined")
              {
              }
              return 0;
          }
          return -1;
      }
    

← Previous Node.js Error