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

GlobalHandles是实现v8中持久句柄功能的类。GlobalHandles主要是维护一个链表,每个节点维护堆对象的状态。我们先看看节点的定义。

class GlobalHandles::Node : public Malloced {
 public:

  void Initialize(Object* object) {
    // 指向堆对象地址
    object_ = object;
    state_  = NORMAL;
    parameter_or_next_free_.parameter = NULL;
    callback_ = NULL;
  }

  explicit Node(Object* object) {
    Initialize(object);
    next_ = NULL;
  }

  ~Node() {
    if (state_ != DESTROYED) Destroy();
  }

  void Destroy() {
    if (state_ == WEAK || IsNearDeath()) {
      GlobalHandles::number_of_weak_handles_--;
      if (object_->IsJSGlobalObject()) {
        GlobalHandles::number_of_global_object_weak_handles_--;
      }
    }
    state_ = DESTROYED;
  }

  Node* next() { return next_; }
  void set_next(Node* value) { next_ = value; }
  // 指针的地址
  Node** next_addr() { return &next_; }

  // 用于销毁状态的时候,在空闲链表的操作
  Node* next_free() {
    ASSERT(state_ == DESTROYED);
    return parameter_or_next_free_.next_free;
  }
  void set_next_free(Node* value) {
    ASSERT(state_ == DESTROYED);
    parameter_or_next_free_.next_free = value;
  }

  // location指向Node对象的object_属性的地址
  static Node* FromLocation(Object** location) {
    // object_属性在Node对象的首地址
    ASSERT(OFFSET_OF(Node, object_) == 0);
    // 直接转成Node指针,因为object_就是Node对象的首地址
    return reinterpret_cast<Node*>(location);
  }

  // 返回object_属性的地址,即对象的首地址
  Handle<Object> handle() { return Handle<Object>(&object_); }

  // Make this handle weak.
  void MakeWeak(void* parameter, WeakReferenceCallback callback) {
    // 更新统计数据
    if (state_ != WEAK && !IsNearDeath()) {
      GlobalHandles::number_of_weak_handles_++;
      if (object_->IsJSGlobalObject()) {
        GlobalHandles::number_of_global_object_weak_handles_++;
      }
    }
    // 修改状态和待销毁时执行的回调和参数
    state_ = WEAK;
    set_parameter(parameter);
    callback_ = callback;
    }
    
  // 和上面的函数相反
  void ClearWeakness() {
    if (state_ == WEAK || IsNearDeath()) {
      GlobalHandles::number_of_weak_handles_--;
      if (object_->IsJSGlobalObject()) {
        GlobalHandles::number_of_global_object_weak_handles_--;
      }
    }
    state_ = NORMAL;
    set_parameter(NULL);
  }

  bool IsNearDeath() {
    return state_ == PENDING || state_ == NEAR_DEATH;
  }

  bool IsWeak() {
    return state_ == WEAK;
  }

  // 参数的存取
  void set_parameter(void* parameter) {
    ASSERT(state_ != DESTROYED);
    parameter_or_next_free_.parameter = parameter;
  }
  void* parameter() {
    ASSERT(state_ != DESTROYED);
    return parameter_or_next_free_.parameter;
  }

  WeakReferenceCallback callback() { return callback_; }
  // gc相关
  void PostGarbageCollectionProcessing() {
    if (state_ != Node::PENDING) return;
    void* par = parameter();
    state_ = NEAR_DEATH;
    set_parameter(NULL);
    WeakReferenceCallback func = callback();
    if (func != NULL) {
      func(v8::Persistent<v8::Object>(ToApi<v8::Object>(handle())), par);
    }
  }

  Object* object_;  // Storage for object pointer.

  // Transition diagram:
  // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED }
  enum State {
    NORMAL,      // Normal global handle.
    WEAK,        // Flagged as weak but not yet finalized.
    PENDING,     // Has been recognized as only reachable by weak handles.
    NEAR_DEATH,  // Callback has informed the handle is near death.
    DESTROYED
  };
  State state_;

 private:
  // 待销毁时执行的回调
  WeakReferenceCallback callback_;
  // next_free是用于销毁状态的node,这时候parameter已经不需要了,不是销毁状态的时候,next_free也不会用到 
  union {
    void* parameter;
    Node* next_free;
  } parameter_or_next_free_;

  Node* next_;

 public:
  TRACK_MEMORY("GlobalHandles::Node")
};

Node类对象保存了堆对象的地址、销毁前执行的回调和参数。管理堆对象的状态。下面看一下GlobalHandles的定义,我们是通过GlobalHandles使用Node类的。下面的注释解释的比较好,所以保留。

// Structure for tracking global handles.
// A single list keeps all the allocated global handles.
// Destroyed handles stay in the list but is added to the free list.
// At GC the destroyed global handles are removed from the free list
// and deallocated.

// Callback function on handling weak global handles.
// typedef bool (*WeakSlotCallback)(Object** pointer);

// An object group is indexed by an id. An object group is treated like
// a single JS object: if one of object in the group is alive,
// all objects in the same group are considered alive.
// An object group is used to simulate object relationship in a DOM tree.
class ObjectGroup : public Malloced {
 public:
  explicit ObjectGroup(void* id) : id_(id), objects_(4) {}

  void* id_;
  List<Object**> objects_;
};

class GlobalHandles : public AllStatic {
 public:
  // Creates a new global handle that is alive until Destroy is called.
  static Handle<Object> Create(Object* value);

  // Destroy a global handle.
  static void Destroy(Object** location);

  // Make the global handle weak and set the callback parameter for the
  // handle.  When the garbage collector recognizes that only weak global
  // handles point to an object the handles are cleared and the callback
  // function is invoked (for each handle) with the handle and corresponding
  // parameter as arguments.  Note: cleared means set to Smi::FromInt(0). The
  // reason is that Smi::FromInt(0) does not change during garage collection.
  static void MakeWeak(Object** location,void* parameter,WeakReferenceCallback callback);

  // Returns the current number of weak handles.
  static int NumberOfWeakHandles() { return number_of_weak_handles_; }

  // Returns the current number of weak handles to global objects.
  // These handles are also included in NumberOfWeakHandles().
  static int NumberOfGlobalObjectWeakHandles() {
    return number_of_global_object_weak_handles_;
  }

  // Clear the weakness of a global handle.
  static void ClearWeakness(Object** location);

  // Tells whether global handle is near death.
  static bool IsNearDeath(Object** location);

  // Tells whether global handle is weak.
  static bool IsWeak(Object** location);

  // Process pending weak handles.
  static void PostGarbageCollectionProcessing();

  // Iterates over all handles.
  static void IterateRoots(ObjectVisitor* v);

  // Iterates over all weak roots in heap.
  static void IterateWeakRoots(ObjectVisitor* v);

  // Mark the weak pointers based on the callback.
  static void MarkWeakRoots(WeakSlotCallback f);

  // Add an object to a group indexed by an id.
  // Should only used in GC callback function before a collection.
  // All groups are destroyed after a mark-compact collection.
  static void AddToGroup(void* id, Object** location);

  // Returns the object groups.
  static List<ObjectGroup*>& ObjectGroups() {
    return object_groups_;
  }

  // Remove bags, this should only happen after GC.
  static void RemoveObjectGroups();

  // Tear down the global handle structure.
  static void TearDown();

 private:
  // Internal node structure, one for each global handle.
  class Node;

  // Field always containing the number of weak and near-death handles.
  static int number_of_weak_handles_;

  // Field always containing the number of weak and near-death handles
  // to global objects.  These objects are also included in
  // number_of_weak_handles_.
  static int number_of_global_object_weak_handles_;

  // Global handles are kept in a single linked list pointed to by head_.
  static Node* head_;
  static Node* head() { return head_; }
  static void set_head(Node* value) { head_ = value; }

  // Free list for DESTROYED global handles not yet deallocated.
  static Node* first_free_;
  static Node* first_free() { return first_free_; }
  static void set_first_free(Node* value) { first_free_ = value; }

  // A list of object groups.
  static List<ObjectGroup*> object_groups_;
};


int GlobalHandles::number_of_weak_handles_ = 0;
int GlobalHandles::number_of_global_object_weak_handles_ = 0;

// 初始化这两个头指针
GlobalHandles::Node* GlobalHandles::head_ = NULL;
GlobalHandles::Node* GlobalHandles::first_free_ = NULL;
List<ObjectGroup*> GlobalHandles::object_groups_(4);

内存结构图。
在这里插入图片描述
GlobalHandles的方法看起来比较多,很多都是对Node类的封装。我们继续看一下GlobalHandles的实现。

1 创建一个持久句柄。

持久句柄里保存了Node对象的地址。Node对象的地址由Create函数返回。

// 一个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) {
    // 没有可重用的节点则分配一个新的
    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();
}

2 销毁一个节点

修改节点的状态,把节点插入到空闲链表等待复用。

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);
}

3 节点状态相关

// 更新node的状态
void GlobalHandles::MakeWeak(Object** location, void* parameter,
                             WeakReferenceCallback callback) {
  Node::FromLocation(location)->MakeWeak(parameter, callback);
}

// 恢复node的状态
void GlobalHandles::ClearWeakness(Object** location) {
  Node::FromLocation(location)->ClearWeakness();
}

bool GlobalHandles::IsNearDeath(Object** location) {
  return Node::FromLocation(location)->IsNearDeath();
}

bool GlobalHandles::IsWeak(Object** location) {
  return Node::FromLocation(location)->IsWeak();
}

4 遍历

// gc相关,在分析gc的时候讲
void GlobalHandles::MarkWeakRoots(WeakSlotCallback f) {
  for (Node* current = head_; current != NULL; current = current->next()) {
    if (current->state_ == Node::WEAK) {
      if (f(&current->object_)) {
        current->state_ = Node::PENDING;
      }
    }
  }
}

// 遍历链表,ObjectVisitor是基类,传进来的是具体的子类(多态)
void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
  // Traversal of GC roots in the global handle list that are marked as
  // WEAK or PENDING.
  for (Node* current = head_; current != NULL; current = current->next()) {
    if (current->state_ == Node::WEAK
      || current->state_ == Node::PENDING
      || current->state_ == Node::NEAR_DEATH) {
      v->VisitPointer(&current->object_);
    }
  }
}
// 遍历链表
void GlobalHandles::IterateRoots(ObjectVisitor* v) {
  // Traversal of global handles marked as NORMAL or NEAR_DEATH.
  for (Node* current = head_; current != NULL; current = current->next()) {
    if (current->state_ == Node::NORMAL) {
      v->VisitPointer(&current->object_);
    }
  }
}

5 销毁链表

// 销毁所有节点,重置头指针
void GlobalHandles::TearDown() {
  // Delete all the nodes in the linked list.
  Node* current = head_;
  while (current != NULL) {
    Node* n = current;
    current = current->next();
    delete n;
  }
  // Reset the head and free_list.
  set_head(NULL);
  set_first_free(NULL);
}

6 组相关

参考上面的结构体

void GlobalHandles::AddToGroup(void* id, Object** handle) {
  for (int i = 0; i < object_groups_.length(); i++) {
    ObjectGroup* entry = object_groups_[i];
    if (entry->id_ == id) {
      entry->objects_.Add(handle);
      return;
    }
  }

  // not found
  ObjectGroup* new_entry = new ObjectGroup(id);
  new_entry->objects_.Add(handle);
  object_groups_.Add(new_entry);
}


void GlobalHandles::RemoveObjectGroups() {
  for (int i = 0; i< object_groups_.length(); i++) {
    delete object_groups_[i];
  }
  object_groups_.Clear();
}

7 gc相关

// 垃圾回收的时候处理已经销毁的handle
void GlobalHandles::PostGarbageCollectionProcessing() {
  // 垃圾回收完之后
  ASSERT(Heap::gc_state() == Heap::NOT_IN_GC);
  Node** p = &head_;
  while (*p != NULL) {
    // 调用Node的函数,可能会更新node的状态
    (*p)->PostGarbageCollectionProcessing();
    // 销毁的节点会放到free链表
    if ((*p)->state_ == Node::DESTROYED) {
      // Delete the link.
      Node* node = *p;
      // 指向下一个节点,即从链表中删除该节点
      *p = node->next();  // Update the link.
      // 释放node的内存
      delete node;
    } else {
      // 因为p是二级指针,说明指向node的next域的地址。*p取得node的下一个节点地址
      p = (*p)->next_addr();
    }
  }
  // 重置free队列的头指针,因为链表的节点都被释放了
  set_first_free(NULL);
}

总结,主要介绍了v8中实现持久句柄的基本原理(可结合分析handle那一篇一起看)。有一部分是gc相关的,等后分析gc的时候再分析。

### 回答1: 要下载elasticsearchhead0.1.5谷歌插件,您可以按照以下步骤进行操作: 1. 首先,打开您的Chrome浏览器,并在地址栏中输入"Chrome网上应用店"。 2. 在搜索栏中,输入"elasticsearchhead0.1.5"并点击搜索按钮。 3. 在搜索结果中,应该能找到相关的插件。请确保选择的插件是"elasticsearchhead0.1.5"。 4. 点击插件的名称或图标,进入插件的详情页面。 5. 在详情页面,您将看到一个"添加至Chrome"的按钮。点击该按钮以安装插件。 6. 安装完成后,您将收到一个确认消息,并且插件的图标将出现在Chrome浏览器的工具栏或扩展程序区域。 7. 现在,您已成功下载并安装了elasticsearchhead0.1.5谷歌插件。 请注意,插件的下载和安装过程可能因不同的Chrome浏览器版本而有所不同。如果您遇到任何问题,请参考官方文档或在相关论坛寻求帮助。 ### 回答2: Elasticsearch Head是一个用于查看和管理Elasticsearch集群的插件。虽然插件名称中包含谷歌,但实际上Elasticsearch Head插件不是谷歌官方出品的插件,它是开源社区开发的一个插件。要下载Elasticsearch Head插件,可以按照以下步骤进行操作: 1. 打开谷歌浏览器,进入插件商店。 2. 在插件商店搜索框中输入“Elasticsearch Head”并回车。 3. 在搜索结果中选择合适的插件,通常是由mobz开发的插件。 4. 点击插件卡片上的“添加至Chrome”按钮,开始下载和安装插件。 5. 下载完成后,浏览器右上角会出现一个新的插件图标。 6. 点击插件图标,弹出一个新的页面,输入Elasticsearch集群的地址和端口号。 7. 输入正确的地址和端口号后,点击连接按钮,即可访问和管理Elasticsearch集群。 需要注意的是,Elasticsearch Head插件只适用于谷歌浏览器,其他浏览器可能无法使用该插件。此外,插件下载和使用需要一定的网络条件和相关知识,对于不熟悉的用户,可以参考相关教程或向社区寻求帮助。 ### 回答3: 要下载elasticsearch-head 0.1.5插件,可以按照以下步骤进行操作: 1. 打开谷歌浏览器,并在地址栏中输入“elasticsearch-head 0.1.5谷歌插件下载”。 2. 在搜索结果页面,可以找到elasticsearch-head插件的官方下载页面或第三方站点提供的下载链接。 3. 点击相关链接,进入插件下载页面。 4. 在插件下载页面,可以选择合适的插件版本,确认选择0.1.5版本。 5. 阅读下载页面上的相关信息,了解插件的功能和适用版本。 6. 确认无误后,点击下载按钮开始下载插件。 7. 下载完成后,根据提示,将下载的插件文件保存到本地计算机的特定文件夹中。 8. 在谷歌浏览器中,点击浏览器右上方三个点的菜单按钮,选择“更多工具”->“扩展程序”。 9. 在打开的扩展程序页面上,找到“elasticsearch-head”插件,并启用它。 10. 完成上述操作后,elasticsearch-head插件将被成功安装,并在浏览器的工具栏上显示图标,点击图标即可使用该插件进行Elasticsearch相关操作。 请注意,在下载和安装插件的过程中,要确保从官方或可信赖的第三方网站下载插件,以避免安全隐患。另外,确认插件的兼容性和适用版本,以确保它能够正常运行在您的谷歌浏览器上。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值