日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
通過(guò)Handle理解V8的代碼設(shè)計(jì)(基于V0.1.5)

本文轉(zhuǎn)載自微信公眾號(hào)「編程雜技」,作者theanarkh。轉(zhuǎn)載本文請(qǐng)聯(lián)系編程雜技公眾號(hào)。

目前創(chuàng)新互聯(lián)建站已為上千的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)頁(yè)空間、網(wǎng)站托管、服務(wù)器租用、企業(yè)網(wǎng)站設(shè)計(jì)、舒城網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶(hù)導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶(hù)和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。

前言:Handle在V8里是一個(gè)非常重要的概念,本文從早期的源碼分析Handle的原理,在分析的過(guò)程中我們還可以看到V8在代碼設(shè)計(jì)上的一些細(xì)節(jié)。

假設(shè)我們有以下代碼

 
 
 
 
  1. HandleScope scope; 
  2. Local hello = String::New(參數(shù)); 

這個(gè)看起來(lái)很簡(jiǎn)單的過(guò)程,其實(shí)在V8的內(nèi)部實(shí)現(xiàn)起來(lái)比較復(fù)雜。

HandleScope

我們從創(chuàng)建一個(gè)HandleScope對(duì)象開(kāi)始分析。HandleScope是負(fù)責(zé)管理多個(gè)Handle的對(duì)象,主要是為了方便管理Handle的分配和釋放。

 
 
 
 
  1. class HandleScope { 
  2.  public: 
  3.   HandleScope() : previous_(current_), is_closed_(false) { 
  4.     current_.extensions = 0; 
  5.   } 
  6.  
  7.   static void** CreateHandle(void* value); 
  8.  
  9.  private: 
  10.  
  11.   class Data { 
  12.    public: 
  13.     // 分配了一塊內(nèi)存后,又額外分配的塊數(shù) 
  14.     int extensions; 
  15.     // 下一個(gè)可用的位置 
  16.     void** next; 
  17.     // 達(dá)到limit執(zhí)行的地址后說(shuō)明當(dāng)前內(nèi)存塊用完了 
  18.     void** limit; 
  19.     inline void Initialize() { 
  20.       extensions = -1; 
  21.       next = limit = NULL; 
  22.     } 
  23.   }; 
  24.   // 當(dāng)前的HandleScope 
  25.   static Data current_; 
  26.   // 上一個(gè)HandleScope 
  27.   const Data previous_; 
  28. }; 
  29.  
  30. HandleScope::Data HandleScope::current_ = { -1, NULL, NULL }; 

通過(guò)HandleScope的構(gòu)造函數(shù)我們知道每次定義一個(gè)HandleScope對(duì)象的時(shí)候,previous就會(huì)指向前一個(gè)HandleScope的數(shù)據(jù)(但是current_除了第一次創(chuàng)建HandleScope的時(shí)候更新了(見(jiàn)CreateHandle),后續(xù)似乎沒(méi)有更新?后續(xù)詳細(xì)看一下),從HandleScope的定義中我們知道他的布局如下。

接著我們看HandleScope的CreateHandle方法。

 
 
 
 
  1. void** v8::HandleScope::CreateHandle(void* value) { 
  2.   // 獲取下一個(gè)可用的地址 
  3.   void** result = current_.next; 
  4.   // 到達(dá)limit的地址了或者為空(初始化的時(shí)候)則獲取新的內(nèi)存 
  5.   if (result == current_.limit) { 
  6.     // Block是二維數(shù)組,每個(gè)元素指向一個(gè)可以存儲(chǔ)數(shù)據(jù)的數(shù)組。非空說(shuō)明可能有可用的內(nèi)存空間 
  7.     if (!thread_local.Blocks()->is_empty()) { 
  8.       // 拿到list中最后一個(gè)元素,得到一個(gè)數(shù)組首地址,然后再獲取他的limit地址,即末地址 
  9.       void** limit = &thread_local.Blocks()->last()[i::kHandleBlockSize]; 
  10.       if (current_.limit != limit) { 
  11.         current_.limit = limit; 
  12.         // v8里少了這一句,看起來(lái)是需要修改result的值的 
  13.         // result = limit - i::kHandleBlockSize;  
  14.       } 
  15.     } 
  16.   } 
  17.   // 下一個(gè)可用的地址 
  18.   current_.next = result + 1; 
  19.   *result = value; 
  20.   return result; 

我們看到CreateHandle會(huì)首先獲取一片內(nèi)存,然后把入?yún)alue的值保存到該內(nèi)存中。

String::New

了解了HandleScope后,我們繼續(xù)分析String::New。

 
 
 
 
  1. Local v8::String::New(const char* data, int length) { 
  2.   i::Handle result = 
  3.       i::Factory::NewStringFromUtf8(i::Vector(data, length)); 
  4.   return Utils::ToLocal(result); 

我們接著看NewStringFromUtf8。

 
 
 
 
  1. Handle Factory::NewStringFromUtf8(Vector string,PretenureFlag pretenure) { 
  2.   CALL_HEAP_FUNCTION(Heap::AllocateStringFromUtf8(string,  
  3.                     pretenure),  
  4.                     String); 

我們先看一下AllocateStringFromUtf8的實(shí)現(xiàn),然后再看CALL_HEAP_FUNCTION。

 
 
 
 
  1. Object* Heap::AllocateStringFromUtf8(Vector string,PretenureFlag pretenure) { 
  2.   return AllocateStringFromAscii(string, pretenure); 
  3.  
  4. Object* Heap::AllocateStringFromAscii(Vector string,PretenureFlag pretenure) { 
  5.   // 從堆中分配一塊內(nèi)存 
  6.   Object* result = AllocateRawAsciiString(string.length(), pretenure); 
  7.   // 設(shè)置堆對(duì)象的內(nèi)容 
  8.   AsciiString* string_result = AsciiString::cast(result); 
  9.   for (int i = 0; i < string.length(); i++) { 
  10.     string_result->AsciiStringSet(i, string[i]); 
  11.   } 
  12.   return result; 

我們看到AllocateStringFromUtf8最后返回了一個(gè)堆內(nèi)存地址。接著我們看下CALL_HEAP_FUNCTION這個(gè)宏。

 
 
 
 
  1. #define CALL_HEAP_FUNCTION(FUNCTION_CALL, TYPE)         
  2.   do {                  
  3.     Object* __object__ = FUNCTION_CALL;                                       
  4.     return Handle(TYPE::cast(__object__));    
  5.   } while (false) 

CALL_HEAP_FUNCTION的作用是把函數(shù)FUNCTION_CALL執(zhí)行的結(jié)果轉(zhuǎn)成Handle對(duì)象。我們知道FUNCTION_CALL函數(shù)返回的結(jié)果是一個(gè)堆內(nèi)存指針。接下來(lái)我們看看是如何轉(zhuǎn)成Handle的。這個(gè)Handle不是我們?cè)诖a里使用的Handle。而是V8內(nèi)部使用的Handle(代碼在handles.h),我們看看實(shí)現(xiàn)。

 
 
 
 
  1. template 
  2. class Handle { 
  3.  public: 
  4.   explicit Handle(T* obj); 
  5.  private: 
  6.   T** location_; 
  7. }; 
  8.  
  9. template 
  10. Handle::Handle(T* obj) { 
  11.   location_ = reinterpret_cast(HandleScope::CreateHandle(obj)); 

我們看到Handle內(nèi)部使用的是T**二級(jí)指針,而我們剛才拿到堆內(nèi)存地址是一級(jí)指針,自然不能直接賦值,而是通過(guò)CreateHandle又處理了一下。HandleScope::CreateHandle我們剛才已經(jīng)分析過(guò)了。執(zhí)行CreateHandle后布局如下。

所以NewStringFromUtf8最后返回了一個(gè)Handle對(duì)象(里面維護(hù)了一個(gè)二級(jí)指針location_),接著V8調(diào)用Utils::ToLocal把他轉(zhuǎn)成外部使用的Handle。接著賦值給Handle hello。這里的Handle是外部使用的Handle。

 
 
 
 
  1. Local Utils::ToLocal(v8::internal::Handle obj) {  
  2.     return Local(reinterpret_cast(obj.location()));  

首先通過(guò)obj.location()拿到一個(gè)二級(jí)指針。然后轉(zhuǎn)成一個(gè)String *指針。接著構(gòu)造一個(gè)Local對(duì)象。ToLocal是V8代碼的分水嶺,我們看看Local的定義。

 
 
 
 
  1. template  class Local : public Handle { 
  2.  public: 
  3.   template  inline Local(S* that) : Handle(that) { } 
  4. }; 

直接調(diào)用Handle類(lèi)的函數(shù)

 
 
 
 
  1. template  class Handle { 
  2.   explicit Handle(T* val) : val_(val) { } 
  3.   private: 
  4.     T* val_; 

這時(shí)候的結(jié)構(gòu)圖如下

 
 
 
 
  1. template  class Handle { 
  2.   explicit Handle(T* val) : val_(val) { } 
  3.   private: 
  4.     T* val_; 

所以最后通過(guò)ToLocal返回一個(gè)外部Handle對(duì)象給用戶(hù)。當(dāng)執(zhí)行

 
 
 
 
  1. Local  xxx = Local對(duì)象 

時(shí)就會(huì)調(diào)用Local的拷貝函數(shù)。

 
 
 
 
  1. template   
  2.       inline Local(Local that) 
  3.       // *that即取得他底層對(duì)象的地址 
  4.       : Handle(reinterpret_cast(*that)) {} 

我們首先看一下that。Handle類(lèi)重載了運(yùn)算符。

 
 
 
 
  1. template  
  2. T* Handle::operator*() { 
  3.   return val_; 

所以reinterpret_cast(that)拿到了Handle底層指針的值并轉(zhuǎn)成String 類(lèi)型。接著執(zhí)行

 
 
 
 
  1. explicit Handle(T* val) : val_(val) { } 

整個(gè)過(guò)程下來(lái),其實(shí)就是把被復(fù)制對(duì)象的底層指針復(fù)制過(guò)來(lái)。=

通過(guò)Handle訪(fǎng)問(wèn)一個(gè)函數(shù)

當(dāng)我們使用Handle hello這個(gè)對(duì)象的方法時(shí)是怎樣的,比如hello->Length()。Handle重載了->運(yùn)算符。

 
 
 
 
  1. template  
  2. T* Handle::operator->() { 
  3.   return val_; 

我們看到執(zhí)行hello->Length()的時(shí)候首先會(huì)拿到一個(gè)String *。然后調(diào)用Length方法。其實(shí)就是調(diào)用String對(duì)象(在v8.h中定義)的Length方法。我們看看Length方法的實(shí)現(xiàn)。

 
 
 
 
  1. int String::Length() { 
  2.   return Utils::OpenHandle(this)->length(); 

首先通過(guò)傳入this調(diào)用OpenHandle拿到內(nèi)部Handle。從前面的架構(gòu)圖中我們知道this(即val_和location_指向的值)本質(zhì)上是一個(gè)String **,即二級(jí)指針。

 
 
 
 
  1. v8: :internal: :Handle < v8: :internal: :String >  
  2. Utils: :OpenHandle(v8: :String * that) { 
  3.     return v8: :internal: :Handle < v8: :internal: :String > (reinterpret_cast < v8: :internal: :String * *>(that)); 

OpenHandle就是首先把外部的表示轉(zhuǎn)成一個(gè)二級(jí)指針。然后再構(gòu)造一個(gè)內(nèi)部Handle。在內(nèi)部Handle里保存了這個(gè)二級(jí)指針。接著訪(fǎng)問(wèn)這個(gè)Handle對(duì)象的length方法。而Handle重載了->運(yùn)算符。

 
 
 
 
  1. INLINE(T* operator ->() const)  { return operator*(); } 
  2.  
  3. template inline T* Handle::operator*() const { 
  4.   return *location_; 

我們看到->的操作最終會(huì)被解引用一次變成String *,然后訪(fǎng)問(wèn)函數(shù)length,也就是訪(fǎng)問(wèn)String對(duì)象的length函數(shù)。

后記:從上面的分析中我們不僅看到了Handle的實(shí)現(xiàn)原理,也看到了V8代碼的一些設(shè)計(jì)細(xì)節(jié),V8在內(nèi)部實(shí)現(xiàn)了一類(lèi)對(duì)象,然后把內(nèi)部對(duì)象轉(zhuǎn)成外部使用的類(lèi)型后返回給用戶(hù),當(dāng)用戶(hù)使用該返回的對(duì)象時(shí),V8又會(huì)轉(zhuǎn)成內(nèi)部的對(duì)象再操作這個(gè)對(duì)象。核心的數(shù)據(jù)結(jié)構(gòu)是兩個(gè)Handle族的類(lèi)。因?yàn)樗麄兪蔷S護(hù)了真實(shí)對(duì)象的句柄。其他的一些類(lèi),比如String,同樣分為外部和內(nèi)部類(lèi),內(nèi)部類(lèi)是實(shí)現(xiàn)了String的細(xì)節(jié),而外部類(lèi)只是一個(gè)殼子,他負(fù)責(zé)給用戶(hù)暴露API,而不負(fù)責(zé)實(shí)現(xiàn)細(xì)節(jié),但用戶(hù)操作這些類(lèi)時(shí),V8會(huì)會(huì)轉(zhuǎn)成內(nèi)部類(lèi)再進(jìn)行操作。外部類(lèi)的定義在v8.h中,這是我們使用V8時(shí)需要了解的最好文檔。內(nèi)部類(lèi)的實(shí)現(xiàn)根據(jù)版本不同而不同,比如早期版本都是在object.h里實(shí)現(xiàn)的,而實(shí)現(xiàn)內(nèi)外部對(duì)象轉(zhuǎn)換的方法在api.c中定義。


文章標(biāo)題:通過(guò)Handle理解V8的代碼設(shè)計(jì)(基于V0.1.5)
網(wǎng)頁(yè)鏈接:http://www.5511xx.com/article/ccscpsh.html