几个重要的类:
- 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
从例子中我们可以看到,通常我们使用的变量都是Local为主。不管是Context,String,Script还是Value都是通过Local模板来进行管理的:
// Create a new context.
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; }