js引擎v8源码分析之Handle(基于v8 0.1.5)

2024-03-27 21:32
文章标签 分析 源码 js 引擎 0.1 v8 handle

本文主要是介绍js引擎v8源码分析之Handle(基于v8 0.1.5),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Handle是使用v8的时候很重要的一个概念和类。他本质是堆对象的封装。我们通过Handle管理真正的对象,而不是直接操作对象。Handle在v8中有两个实现。一个是对外使用的一个是内部使用的。我们先看一下内部使用的。

1 内部handle

template<class T>
class Handle {public:INLINE(Handle(T** location))  { location_ = location; }INLINE(explicit Handle(T* obj));INLINE(Handle()) : location_(NULL) {}template <class S> Handle(Handle<S> handle) {location_ = reinterpret_cast<T**>(handle.location());}INLINE(T* operator ->() const)  { return operator*(); }bool is_identical_to(const Handle<T> other) const {return operator*() == *other;}INLINE(T* operator*() const);T** location() const {return location_;}template <class S> static Handle<T> cast(Handle<S> that) {T::cast(*that);return Handle<T>(reinterpret_cast<T**>(that.location()));}static Handle<T> null() { return Handle<T>(); }bool is_null() {return location_ == NULL; }inline Handle<T> EscapeFrom(HandleScope* scope);private:T** location_;
};

下面是实现。

template<class T>
Handle<T>::Handle(T* obj) {location_ = reinterpret_cast<T**>(HandleScope::CreateHandle(obj));
}template <class T>
inline T* Handle<T>::operator*() const {return *location_;
}

Handle类的定义没有太多的逻辑,就是对用户定义的对象指针进行封装。有一个重要的地址是构造函数。我们看到当我们定义一个Handle的时候,他会调HandleScope::CreateHandle生成一个Handle对象。在HandleScope那篇文章已经分析过了。handle对象的location对象指针一个内存,该内存保存了obj的地址。

2 外部handle

// T表示handle管理的对象的类型
template <class T> class Handle {public:Handle();explicit Handle(T* val) : val_(val) { }// *that得到指向handle管理的对象的指针,转成T类型,赋值给val_template <class S> inline Handle(Handle<S> that): val_(reinterpret_cast<T*>(*that)) {TYPE_CHECK(T, S);}bool IsEmpty() { return val_ == 0; }T* operator->();T* operator*();void Clear() { this->val_ = 0; }/*比较handle指向的对象的地址是否相等this是指向当前对象的指针,*this是当前对象,**this是返回val_的值,看重载运算符*的实现*that是val_的值*/template <class S> bool operator==(Handle<S> that) {void** a = reinterpret_cast<void**>(**this);void** b = reinterpret_cast<void**>(*that);// a等于0,则返回b是否等于0,是的话说明a==b,即trueif (a == 0) return b == 0;// a不等于0,如果b==0,则返回falseif (b == 0) return false;// 比较ab,即取val_里的内容比较return *a == *b;}template <class S> bool operator!=(Handle<S> that) {return !operator==(that);}template <class S> static inline Handle<T> Cast(Handle<S> that) {// 返回一个空的handle,即val_是nullif (that.IsEmpty()) return Handle<T>();// *that得到指向handle管理的对象的指针,转成T类型的对象,转成底层对象是类型T的handlereturn Handle<T>(T::Cast(*that));}private:T* val_;
};

下面是实现。只有两个运算符的重载。

template <class T>
T* Handle<T>::operator->() {return val_;
}template <class T>
T* Handle<T>::operator*() {return val_;
}

我们看到Handle的实现没有太内容,就是在对象和用户之前加了一层。下面看看他的两个子类Local和Persistent。

3 Local

1 Local类是基于栈分配的一种Handle,他在一个函数开始的时候,声明一个HandleScope,HandleScope下面所有的Handle都在最近的的HandleScope中分配,函数执行完后,会一起被释放。

template <class T> class Local : public Handle<T> {public:Local();// 调用Local函数的时候S被替换成that对应的类型,结果是Handle底层的val_指向一个T类型的对象template <class S> inline Local(Local<S> that)// *that即取得他底层对象的地址: Handle<T>(reinterpret_cast<T*>(*that)) {TYPE_CHECK(T, S);}template <class S> inline Local(S* that) : Handle<T>(that) { }template <class S> static inline Local<T> Cast(Local<S> that) {if (that.IsEmpty()) return Local<T>();return Local<T>(T::Cast(*that));}static Local<T> New(Handle<T> that);
};

Local没有做什么事情,是对基类Handle的简单继承。下面是实现。

template <class T>
Handle<T>::Handle() : val_(0) { }template <class T>
Local<T>::Local() : Handle<T>() { }template <class T>
Local<T> Local<T>::New(Handle<T> that) {if (that.IsEmpty()) return Local<T>();void** p = reinterpret_cast<void**>(*that);return Local<T>(reinterpret_cast<T*>(HandleScope::CreateHandle(*p)));
}

我们看看如果使用一个句柄。

HandleScope scope;
Local<String> source = String::New('hello');

我们看一下String::New的实现。

// i::Handle表示内部使用的handle
Local<String> v8::String::New(const char* data, int length) {if (length == -1) length = strlen(data);// 申请一个对象,由handle管理i::Handle<i::String> result = i::Factory::NewStringFromUtf8(i::Vector<const char>(data, length));return Utils::ToLocal(result);
}Local<v8::String> Utils::ToLocal(v8::internal::Handle<v8::internal::String> obj) { return Local<String>(reinterpret_cast<String*>(obj.location())); 
}

我们在看下HandleScope中的那个图。再来例假ToLocal函数的逻辑。
在这里插入图片描述
我们对着图来理解ToLocal,我们知道obj.location()返回的是指针,指向保存了对象地址的内存地址。然后转成String*,即拿到对象的地址。构造一个Local对象返回。即Local内部管理用户定义的对象(String::New函数执行完后,他里面定义的result,即handle被析构)。如下图。
在这里插入图片描述
当HandleScope析构的时候,他会释放用户定义的对象的内存,然后Local对象本身是在栈上分配的,也会被析构。这就是v8用本地handle(临时handle)管理堆对象的大致原理。一般来说handle在函数结束后就会被释放,如果想在函数执行完还使得句柄可用,可用使用逃逸(escape)。原理是销毁当前的HandleScope,然后在前一个HandleScope对象里分配一个handle。下面继续看看持久句柄。
4 Persisten

template <class T> class Persistent : public Handle<T> {public:Persistent();template <class S> inline Persistent(Persistent<S> that): Handle<T>(reinterpret_cast<T*>(*that)) {TYPE_CHECK(T, S);}template <class S> inline Persistent(S* that) : Handle<T>(that) { }template <class S> explicit inline Persistent(Handle<S> that): Handle<T>(*that) { }template <class S> static inline Persistent<T> Cast(Persistent<S> that) 		{if (that.IsEmpty()) return Persistent<T>();return Persistent<T>(T::Cast(*that));}static Persistent<T> New(Handle<T> that);void Dispose();void MakeWeak(void* parameters, WeakReferenceCallback callback);void ClearWeak();bool IsNearDeath();bool IsWeak();private:friend class ImplementationUtilities;friend class ObjectTemplate;
};

相对于基类Handle,Persistent多了几个功能,我们看一下使用用例。

Persistent<Context> context = Context::New();

我们看一下Context::New()的定义。

Persistent<Context> v8::Context::New(v8::ExtensionConfiguration* extensions,v8::Handle<ObjectTemplate> global_template,v8::Handle<Value> global_object) {i::Handle<i::Context> env = i::Bootstrapper::CreateEnvironment(Utils::OpenHandle(*global_object),global_template, extensions);return Persistent<Context>(Utils::ToLocal(env));
}

我们看一下CreateEnvironment的实现。

Handle<Context> Bootstrapper::CreateEnvironment(...参数) {Genesis genesis(global_object, global_template, extensions);return genesis.result();
}Genesis::Genesis(...参数) {CreateRoots(global_template, global_object);result_ = global_context_;}void Genesis::CreateRoots(...参数) {// 创建一个全局上下文对象,分配一个Context对象global_context_ =Handle<Context>::cast(GlobalHandles::Create(*Factory::NewGlobalContext()));
}Handle<Context> result() { return result_; }

通过上面的代码我们知道Persistent指向的是一个GlobalHandles::Create返回的地址。所以我们主要分析GlobalHandles这个类的实现。这个类的代码比较多,我们只分析相关的(Node类维护一个对象的信息,地址,状态)。后面会单独分析。

// 一个handle对应一个Node
Handle<Object> GlobalHandles::Create(Object* value) {Counters::global_handles.Increment();Node* result;/*有一个free_list,保存着DESTROYED状态但还没有被释放的Node,first_free指向第一个节点,为NULL说明没有待回收的节点,即没有可重用的节点 */if (first_free() == NULL) {// Allocate a new node.// 没有可重用的节点则分配一个新的result = new Node(value);// 头插法,设置新增的node的下一个节点是当前头结点result->set_next(head());// 头指针指向新增的nodeset_head(result);} else {// Take the first node in the free list.// 获取一个可以重用的节点result = first_free();// 获取重用节点在free_list中的第一个节点,first_free指向新的可重用节点 set_first_free(result->next_free());// 重新初始化该节点result->Initialize(value);}// 返回Node对象的首地址return result->handle();
}

从上面的代码中我们大概知道,有一个链表,每个node节点保存了一个持久对象的信息。持久句柄指向的对象都是在这个链表里管理的。持久句柄执行node的地址,最后要调Dispose释放。

template <class T>
void Persistent<T>::Dispose() {if (this->IsEmpty()) return;V8::DisposeGlobal(reinterpret_cast<void**>(**this));
}void V8::DisposeGlobal(void** obj) {LOG_API("DisposeGlobal");if (has_shut_down) return;i::GlobalHandles::Destroy(reinterpret_cast<i::Object**>(obj));
}// 销毁一个节点
void GlobalHandles::Destroy(Object** location) {Counters::global_handles.Decrement();if (location == NULL) return;Node* node = Node::FromLocation(location);node->Destroy();// Link the destroyed.// 设置待销毁节点在free_list链表里的下一个节点是当前的头结点node->set_next_free(first_free());// 头指针指向待销毁的节点,set_first_free(node);
}

大致是根据对象的地址转成node节点,销毁该节点。从链表中删除。

总结,这就是v8中关于handle的一些知识。

这篇关于js引擎v8源码分析之Handle(基于v8 0.1.5)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/853446

相关文章

LiteFlow轻量级工作流引擎使用示例详解

《LiteFlow轻量级工作流引擎使用示例详解》:本文主要介绍LiteFlow是一个灵活、简洁且轻量的工作流引擎,适合用于中小型项目和微服务架构中的流程编排,本文给大家介绍LiteFlow轻量级工... 目录1. LiteFlow 主要特点2. 工作流定义方式3. LiteFlow 流程示例4. LiteF

SpringBoot集成LiteFlow实现轻量级工作流引擎的详细过程

《SpringBoot集成LiteFlow实现轻量级工作流引擎的详细过程》LiteFlow是一款专注于逻辑驱动流程编排的轻量级框架,它以组件化方式快速构建和执行业务流程,有效解耦复杂业务逻辑,下面给大... 目录一、基础概念1.1 组件(Component)1.2 规则(Rule)1.3 上下文(Conte

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

Python主动抛出异常的各种用法和场景分析

《Python主动抛出异常的各种用法和场景分析》在Python中,我们不仅可以捕获和处理异常,还可以主动抛出异常,也就是以类的方式自定义错误的类型和提示信息,这在编程中非常有用,下面我将详细解释主动抛... 目录一、为什么要主动抛出异常?二、基本语法:raise关键字基本示例三、raise的多种用法1. 抛

Python基于微信OCR引擎实现高效图片文字识别

《Python基于微信OCR引擎实现高效图片文字识别》这篇文章主要为大家详细介绍了一款基于微信OCR引擎的图片文字识别桌面应用开发全过程,可以实现从图片拖拽识别到文字提取,感兴趣的小伙伴可以跟随小编一... 目录一、项目概述1.1 开发背景1.2 技术选型1.3 核心优势二、功能详解2.1 核心功能模块2.

github打不开的问题分析及解决

《github打不开的问题分析及解决》:本文主要介绍github打不开的问题分析及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、找到github.com域名解析的ip地址二、找到github.global.ssl.fastly.net网址解析的ip地址三

Mysql的主从同步/复制的原理分析

《Mysql的主从同步/复制的原理分析》:本文主要介绍Mysql的主从同步/复制的原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录为什么要主从同步?mysql主从同步架构有哪些?Mysql主从复制的原理/整体流程级联复制架构为什么好?Mysql主从复制注意

java -jar命令运行 jar包时运行外部依赖jar包的场景分析

《java-jar命令运行jar包时运行外部依赖jar包的场景分析》:本文主要介绍java-jar命令运行jar包时运行外部依赖jar包的场景分析,本文给大家介绍的非常详细,对大家的学习或工作... 目录Java -jar命令运行 jar包时如何运行外部依赖jar包场景:解决:方法一、启动参数添加: -Xb

Apache 高级配置实战之从连接保持到日志分析的完整指南

《Apache高级配置实战之从连接保持到日志分析的完整指南》本文带你从连接保持优化开始,一路走到访问控制和日志管理,最后用AWStats来分析网站数据,对Apache配置日志分析相关知识感兴趣的朋友... 目录Apache 高级配置实战:从连接保持到日志分析的完整指南前言 一、Apache 连接保持 - 性

MySQL 存储引擎 MyISAM详解(最新推荐)

《MySQL存储引擎MyISAM详解(最新推荐)》使用MyISAM存储引擎的表占用空间很小,但是由于使用表级锁定,所以限制了读/写操作的性能,通常用于中小型的Web应用和数据仓库配置中的只读或主要... 目录mysql 5.5 之前默认的存储引擎️‍一、MyISAM 存储引擎的特性️‍二、MyISAM 的主