v8的Handle

Handle是v8中最爲基礎的類,v8爲了保證數據訪問的正確性和垃圾回收,設計了Handle類
涉及的文件:
include/v8.h
src/handles.h
src/handles-inl.h
src/handles.cc
src/global-handles.h
src/global-handles.cc
src/api.h

  • Handle的分類
    v8對外提供的Handle類定義在v8.h中,它是一個模板類,而且有兩個派生類Local和Persistent,他們都是在v8 namespace下的,如果作爲v8的使用者應該使用這裏的Handle。Local Handle的特點是它們由HandleScope類負責管理,而HandleScope類對象一般作爲一個棧分配的本地變量使用,也就是說在棧退出的時候,該類對象會被釋放,他所管理的對象也會被釋放,也就是說Local Handle所代表的對象會被釋放,此時再使用Local Handle訪問他所代表的對象將會是不安全和未定義的。Persistent則不同,它的生命週期是由用戶維護的,在創建之後,直到我們顯式的調用Persistent的Dispose函數。
  • Handle的實現
一.internal::Handle的實現分析
1.Handle的聲明
v8在handles.h中定義了v8::internal::Handle類,這是一個v8內部使用的類,所有外部使用的Handle最終都會轉換爲它,其定義如下:
template<typename T>
class Handle {
public:
  INLINE(explicit Handle(T** location)) { location_ = location; }
  INLINE(explicit Handle(T* obj));
  INLINE(Handle(T* obj, Isolate* isolate));

  INLINE(Handle()) : location_(NULL) {}

  // Constructor for handling automatic up casting.
  // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected.
  template <class S> Handle(Handle<S> handle) {
#ifdef DEBUG
    T* a = NULL;
    S* b = NULL;
    a = b;  // Fake assignment to enforce type checks.
    USE(a);
#endif
    location_ = reinterpret_cast<T**>(handle.location_);
  }

  INLINE(T* operator ->() const) { return operator*(); }

  // Check if this handle refers to the exact same object as the other handle.
  INLINE(bool is_identical_to(const Handle<T> other) const);

  // Provides the C++ dereference operator.
  INLINE(T* operator*() const);

  // Returns the address to where the raw pointer is stored.
  INLINE(T** location() const);

  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() const { return location_ == NULL; }

  // Closes the given scope, but lets this handle escape. See
  // implementation in api.h.
  inline Handle<T> EscapeFrom(v8::HandleScope* scope);

private:
  T** location_;

  // Handles of different classes are allowed to access each other's location_.
  template<class S> friend class Handle;
};
從Handle類的定義來看,它實際上存儲了一個T** location_,這是一個二維指針,表示它所指向的是一個T*指針,從後面的分析,我們會知道這個T**指針實際上就是v8用來存儲T*的內存的地址。
從構造函數來看,Handle類有五個構造函數,
  INLINE(explicit Handle(T** location)) { location_ = location; }//內核用於生成一個internal handle
  INLINE(explicit Handle(T* obj));//T* obj是內核希望使用handle保存的對象指針
  INLINE(Handle(T* obj, Isolate* isolate));
  INLINE(Handle()) : location_(NULL) {}//返回空對象
  template <class S> static Handle<T> cast(Handle<S> that)//類似拷貝構造函數
除此之外,Handle類還重載操作符*和->,這樣,就能像操作指針那樣操作Handle了。
2.Handle的實現
Handle類的具體實現是在handles-inl.h。Handle類的構造函數中都調用了HandleScope::CreateHandle來創建Handle。
HandleScope有這樣一段註釋
// A stack-allocated class that governs a number of local handles.
// After a handle scope has been created, all local handles will be
// allocated within that handle scope until either the handle scope is
// deleted or another handle scope is created.  If there is already a
// handle scope and a new one is created, all allocations will take
// place in the new handle scope until it is deleted.  After that,
// new handles will again be allocated in the original handle scope.
//
// After the handle scope of a local handle has been deleted the
// garbage collector will no longer track the object stored in the
// handle and may deallocate it.  The behavior of accessing a handle
// for which the handle scope has been deleted is undefined.
大致意思是說,HandleScope管理着衆多的local handle。創建一個handle scope之後,所有的local handle都會在這個handle scope中分配,直到創建一個新的handle scope爲止。如果已經有一個handle scope,又創建了一個新的handle scope,那麼所有的分配行爲都會發生在這個新的handle scope之中,直到它被刪除爲止。這之後,新的handle會在原來的handle scope中分配。在handle scope中的local handle被刪除之後,垃圾回收器就不再追蹤handle中存儲的對象,而是會把它們釋放掉,任何訪問這種handle的行爲都是undefined
我們來看HandleScope::CreateHandle是如何實現的,該函數在handles-inl.h中定義
template <typename T>
T** HandleScope::CreateHandle(Isolate* isolate, T* value) {
  v8::ImplementationUtilities::HandleScopeData* current =
      isolate->handle_scope_data();

  internal::Object** cur = current->next;
  //在初始狀態和current->next增大到limit的限制的時候,會調用Extend函數,增加內存
  if (cur == current->limit) cur = Extend(isolate);
  // Update the current next field, set the value in the created
  // handle, and return the result.
  ASSERT(cur < current->limit);
  //把next指向下一個可用的位置
  current->next = cur + 1;

  //把期望存儲的value值,存儲在T**中
  T** result = reinterpret_cast<T**>(cur);
  *result = value;
  //返回T**作爲Handle
  return result;
}
current是一個如下的類對象,該類在v8.h中定義的
class V8EXPORT Data {
   public:
    internal::Object** next;
    internal::Object** limit;
    int level;
    V8_INLINE(void Initialize()) {
      next = limit = NULL;
      level = 0;
    }
  };
Extend函數實際上調用了api.h中定義的HandleScopeImplementer類來擴大內存的。

二.Local類的實現
首先,Local和Persistent都是在v8的namespace下的類,它們是從v8::Handle中繼承來的,而不是從v8::internal::Handle繼承的,這裏需要特別注意,它們是給外部用戶使用的。
1.創建
對於Local和Persistent,主要需要關注的是New函數
template <class T>
Local<T> Local<T>::New(Isolate* isolate, Handle<T> that) {
  if (that.IsEmpty()) return Local<T>();
  T* that_ptr = *that;
  internal::Object** p = reinterpret_cast<internal::Object**>(that_ptr);
  return Local<T>(reinterpret_cast<T*>(HandleScope::CreateHandle(
      reinterpret_cast<internal::Isolate*>(isolate), *p)));
}
我們看到,實際上是調用了HandleScope::CreateHandle,這裏的HandleScope是v8::HandleScope,還需要進行一次轉換變爲v8::internal::HandleScope,總之,最後會調用到上面分析到的v8::internal::HandleScope創建handle。
2.釋放
Local類中保存的對象是由HandleScope類自動維護的,HandleScope類本身並不保存數據,數據實際上是保存在isolate的成員對象中的,我們可以認爲T*是通過一個T*的指針數組來保存的,而對該數組的使用是線性增長的。HandleScope類只負責記錄上次使用的位置(prev_next指針)和當前指針數組的極限(prev_limit指針),主要用於在HandleScope析構的時候,恢復上次使用數組的位置。如果在同一個棧中有多個HandleScope對象的話,HanldeScope本身其實並不知道是誰在管理對象,這是由棧的特性來決定的,FILO,最後聲明的對象,其構造函數會記錄isolate中最新的next和limit指針,在此之後聲明的對象通過靜態函數HandleScope::CreateHandle得到的Handle都在next和limit之間,在棧推出的時候,最後聲明的對象最先析構,那麼它會使用在構造函數中聲明的prev_next和prev_limit把isolate中的位置指針恢復到聲明它之前的位置,從而實現了handle的釋放。

三.Persistent的實現
1.創建
Persistent::New就要複雜點
template <class T>
Persistent<T> Persistent<T>::New(Isolate* isolate, Handle<T> that) {
  if (that.IsEmpty()) return Persistent<T>();
  internal::Object** p = reinterpret_cast<internal::Object**>(*that);
  return Persistent<T>(reinterpret_cast<T*>(
      V8::GlobalizeReference(reinterpret_cast<internal::Isolate*>(isolate),
                             p)));
}
它調用了api.cc文件中定義的V8::GlobalizeReference函數,這個函數又調用了global-handles.cc文件中的GlobalHandles::Create函數,最終是在這裏實現了Persistent Handle的分配,這種Handle的分配用到了NodeBlock和Node類,其中NodeBlock類中有一個Node數組實例,數組單元數爲256。GlobalHandles類中的first_block_ NodeBlock指針與NodeBlock類中的next_指針,組合使用形成一個NodeBlock鏈表,通過這個鏈表可以找到所有分配過的NodeBlock。
GlobalHandles類中的NodeBlock指針first_used_block_與NodeBlock類中的next_used_和prev_used_指針配合使用,組成了一個雙向鏈表,表示所有正在使用的NodeBlock,即其中存儲有Handle的Block。
在初始狀態下,GlobalHandles的first_free_指針爲null,首次進行create handle的時候,會new一個NodeBlock,然後NodeBlock::PutNodesOnFreeList函數會在NodeBlock中的Node數組中構建一個鏈表,並使得GlobalHandles的first_free_指向第一個可以用的Node節點,後面每create一個handle,這個first_free都會找到下一個可用的Node節點,然後把value指針存儲在Node節點中,並返回存儲地址作爲Handle。
在first_block中的所有Node節點都使用過後,first_free指針會被設置爲null,在下一次調用create Handle的時候,又會重新分配一個NodeBlock,並通過first_block_把它鏈接到鏈表中,然後再次進行上述流程,這就是GlobalHandle的創建過程。
2.釋放
Persistent的Dispose函數的實現相對來說就簡單很多,首先是轉換到內部類,最終會調用GlobalHandles::Destroy函數,該函數會從Handle值找到Node節點,然後把這個節點釋放掉,重新放入NodeBlock中。

  • Handle的轉換
v8有很多的內部handle對應外部handle的情況,所以它通過宏定義了一組這樣的轉換函數,它們都是聲明在api.h中的Utils類。Utils.OpenHandle負責從外部Handle到內部Handle的轉換,Utils.ToLocal負責從內部handle到外部handle的轉換。
#define MAKE_OPEN_HANDLE(From, To)                                          \
  v8::internal::Handle<v8::internal::To> Utils::OpenHandle(                 \
    const v8::From* that, bool allow_empty_handle) {                        \
    EXTRA_CHECK(allow_empty_handle || that != NULL);                        \
    EXTRA_CHECK(that == NULL ||                                             \
        !(*reinterpret_cast<v8::internal::To**>(                            \
            const_cast<v8::From*>(that)))->IsFailure());                    \
    return v8::internal::Handle<v8::internal::To>(                          \
        reinterpret_cast<v8::internal::To**>(const_cast<v8::From*>(that))); \
  }
MAKE_OPEN_HANDLE定義了從外部的From類型,到內部的To類型的轉換
宏OPEN_HANDLE_LIST則定義了一組這樣的轉換函數

#define MAKE_TO_LOCAL(Name, From, To)                                       \
  Local<v8::To> Utils::Name(v8::internal::Handle<v8::internal::From> obj) { \
    ASSERT(obj.is_null() || !obj->IsTheHole());                             \
    return Local<To>(reinterpret_cast<To*>(obj.location()));                \
  }
MAKE_TO_LOCAL定義了從內部的To類型,到內部的From類型的轉換,當然也有一組這樣的函數,但是他們是分別定義的。
以在api.cc中定義的FunctionTemplate::New爲例,我們可以看到他們之間的轉換
Local<FunctionTemplate> FunctionTemplate::New(InvocationCallback callback,
    v8::Handle<Value> data, v8::Handle<Signature> signature, int length) {
  i::Isolate* isolate = i::Isolate::Current();
  EnsureInitializedForIsolate(isolate, "v8::FunctionTemplate::New()");
  LOG_API(isolate, "FunctionTemplate::New");
  ENTER_V8(isolate);
  i::Handle<i::Struct> struct_obj =
      isolate->factory()->NewStruct(i::FUNCTION_TEMPLATE_INFO_TYPE);
  i::Handle<i::FunctionTemplateInfo> obj =
      i::Handle<i::FunctionTemplateInfo>::cast(struct_obj);
  InitializeFunctionTemplate(obj);
  int next_serial_number = isolate->next_serial_number();
  isolate->set_next_serial_number(next_serial_number + 1);
  obj->set_serial_number(i::Smi::FromInt(next_serial_number));
  if (callback != 0) {
    if (data.IsEmpty()) data = v8::Undefined();
    Utils::ToLocal(obj)->SetCallHandler(callback, data);
  }
  obj->set_length(length);
  obj->set_undetectable(false);
  obj->set_needs_access_check(false);

  if (!signature.IsEmpty())
    obj->set_signature(*Utils::OpenHandle(*signature));
  return Utils::ToLocal(obj);
}
局部變量obj是一個內部handle,通過Utils::ToLocal函數轉換爲一個Local<v8::FunctionTemplate>類型的handle,然後去調用SetCallHandler。
signature是一個外部handle,*操作後得到Handle的內容,通過Utils::OpenHandle函數,得到內部handle i::Handle<i::SignatureInfo>,然後被set給obj。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章