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,即true
if (a == 0) return b == 0;
// a不等于0,如果b==0,则返回false
if (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_是null
if (that.IsEmpty()) return Handle<T>();
// *that得到指向handle管理的对象的指针,转成T类型的对象,转成底层对象是类型T的handle
return 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());
// 头指针指向新增的node
set_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的一些知识。