前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >js引擎v8源码解析之allocation(基于0.1.5)

js引擎v8源码解析之allocation(基于0.1.5)

作者头像
theanarkh
发布2019-07-30 18:31:37
7810
发布2019-07-30 18:31:37
举报
文章被收录于专栏:原创分享原创分享
代码语言:javascript
复制
#ifndef V8_ALLOCATION_H_
#define V8_ALLOCATION_H_

namespace v8 { namespace internal {


// A class that controls whether allocation is allowed.  This is for
// the C++ heap only!
class NativeAllocationChecker {
 public:
  typedef enum { ALLOW, DISALLOW } NativeAllocationAllowed;
  explicit inline NativeAllocationChecker(NativeAllocationAllowed allowed)
      : allowed_(allowed) {
#ifdef DEBUG
    if (allowed == DISALLOW) {
      allocation_disallowed_++;
    }
#endif
  }
  ~NativeAllocationChecker() {
#ifdef DEBUG
    if (allowed_ == DISALLOW) {
      allocation_disallowed_--;
    }
#endif
    ASSERT(allocation_disallowed_ >= 0);
  }
  static inline bool allocation_allowed() {
    return allocation_disallowed_ == 0;
  }
 private:
  // This static counter ensures that NativeAllocationCheckers can be nested.
  static int allocation_disallowed_;
  // This flag applies to this particular instance.
  NativeAllocationAllowed allowed_;
};


// Superclass for classes managed with new & delete.
// 管理内存的类,对c函数进行了封装
class Malloced {
 public:
  void* operator new(size_t size) { return New(size); }
  void  operator delete(void* p) { Delete(p); }

  static void FatalProcessOutOfMemory();
  static void* New(size_t size);
  static void Delete(void* p);
};


// A macro is used for defining the base class used for embedded instances.
// The reason is some compilers allocate a minimum of one word for the
// superclass. The macro prevents the use of new & delete in debug mode.
// In release mode we are not willing to pay this overhead.

#ifdef DEBUG
// Superclass for classes with instances allocated inside stack
// activations or inside other objects.
class Embedded {
 public:
  void* operator new(size_t size);
  void  operator delete(void* p);
};
#define BASE_EMBEDDED : public Embedded
#else
#define BASE_EMBEDDED
#endif


// Superclass for classes only using statics.
// 类里只有静态成员
class AllStatic {
#ifdef DEBUG
 public:
  void* operator new(size_t size);
  void operator delete(void* p);
#endif
};

// 新建一个T类型的数组
template <typename T>
static T* NewArray(int size) {
  ASSERT(NativeAllocationChecker::allocation_allowed());
  T* result = new T[size];
  if (result == NULL) Malloced::FatalProcessOutOfMemory();
  return result;
}


template <typename T>
static void DeleteArray(T* array) {
  delete[] array;
}


// The normal strdup function uses malloc.  This version of StrDup
// uses new and calls the FatalProcessOutOfMemory handler if
// allocation fails.
// 复制字符串
char* StrDup(const char* str);


// Allocation policy for allocating in the C free store using malloc
// and free. Used as the default policy for lists.
class FreeStoreAllocationPolicy {
 public:
  INLINE(static void* New(size_t size)) { return Malloced::New(size); }
  INLINE(static void Delete(void* p)) { Malloced::Delete(p); }
};


// Allocation policy for allocating in preallocated space.
// Used as an allocation policy for ScopeInfo when generating
// stack traces.
// 内存管理 
class PreallocatedStorage : public AllStatic {
 public:
  // 管理内存的大小
  explicit PreallocatedStorage(size_t size);
  size_t size() { return size_; }
  static void* New(size_t size);
  static void Delete(void* p);

  // Preallocate a set number of bytes.
  static void Init(size_t size);

 private:
  size_t size_;
  // 链表
  PreallocatedStorage* previous_;
  PreallocatedStorage* next_;
  static bool preallocated_;
  // 已分配出去的内存链表
  static PreallocatedStorage in_use_list_;
  // 空闲链表
  static PreallocatedStorage free_list_;
  // 链表操作函数
  void LinkTo(PreallocatedStorage* other);
  void Unlink();
  DISALLOW_IMPLICIT_CONSTRUCTORS(PreallocatedStorage);
};


} }  // namespace v8::internal

#endif  // V8_ALLOCATION_H_

allocation.cc

代码语言:javascript
复制
#include <stdlib.h>

#include "v8.h"

namespace v8 { namespace internal {

// 对c函数的封装
void* Malloced::New(size_t size) {
  ASSERT(NativeAllocationChecker::allocation_allowed());
  void* result = malloc(size);
  if (result == NULL) V8::FatalProcessOutOfMemory("Malloced operator new");
  return result;
}


void Malloced::Delete(void* p) {
  free(p);
}


void Malloced::FatalProcessOutOfMemory() {
  V8::FatalProcessOutOfMemory("Out of memory");
}


#ifdef DEBUG

static void* invalid = static_cast<void*>(NULL);

void* Embedded::operator new(size_t size) {
  UNREACHABLE();
  return invalid;
}


void Embedded::operator delete(void* p) {
  UNREACHABLE();
}


void* AllStatic::operator new(size_t size) {
  UNREACHABLE();
  return invalid;
}


void AllStatic::operator delete(void* p) {
  UNREACHABLE();
}

#endif

// 复制字符串
char* StrDup(const char* str) {
  int length = strlen(str);
  // 申请一个字符数组
  char* result = NewArray<char>(length + 1);
  // 复制过去
  memcpy(result, str, length * kCharSize);
  result[length] = '\0';
  return result;
}


int NativeAllocationChecker::allocation_disallowed_ = 0;

// 初始化属性
PreallocatedStorage PreallocatedStorage::in_use_list_(0);
PreallocatedStorage PreallocatedStorage::free_list_(0);
bool PreallocatedStorage::preallocated_ = false;

// 申请一块内存对其进行管理
void PreallocatedStorage::Init(size_t size) {
  ASSERT(free_list_.next_ == &free_list_);
  ASSERT(free_list_.previous_ == &free_list_);
  // 申请size个字节,前n个字节是一个PreallocatedStorage对象
  PreallocatedStorage* free_chunk =
      reinterpret_cast<PreallocatedStorage*>(new char[size]);
  // 初始化链表,双向循环链表
  free_list_.next_ = free_list_.previous_ = free_chunk;
  free_chunk->next_ = free_chunk->previous_ = &free_list_;
  // 大小是申请的大小减去一个PreallocatedStorage对象
  free_chunk->size_ = size - sizeof(PreallocatedStorage);
  // 已经分配了内存
  preallocated_ = true;
}

// 从预分配的内存里分配一块内存
void* PreallocatedStorage::New(size_t size) {
  // 没有使用预分配内存,则直接到底层申请一块新的内存,否则从预分配的内存里分配
  if (!preallocated_) {
    return FreeStoreAllocationPolicy::New(size);
  }
  ASSERT(free_list_.next_ != &free_list_);
  ASSERT(free_list_.previous_ != &free_list_);
  /*
    ~(kPointerSize - 1)是使高n位取反,n取决于kPointerSize的大小,即1的位置。 
    size + (kPointerSize - 1)是如果没有按kPointerSize对齐则向上取整。 
  */
  size = (size + kPointerSize - 1) & ~(kPointerSize - 1);
  // Search for exact fit.
  // 从预分配的内存里找到等于size的块
  for (PreallocatedStorage* storage = free_list_.next_;
       storage != &free_list_;
       storage = storage->next_) {
    if (storage->size_ == size) {
      // 找到后,把该块从链表中删除,并插入到已分配链表中
      storage->Unlink();
      storage->LinkTo(&in_use_list_);
      // 返回存储数据的首地址,前面存储了一个PreallocatedStorage对象
      return reinterpret_cast<void*>(storage + 1);
    }
  }
  // Search for first fit.
  // 没有大小等于size的块,则找比size大的块
  for (PreallocatedStorage* storage = free_list_.next_;
       storage != &free_list_;
       storage = storage->next_) {
    // 多出来的那一块还需要一个PreallocatedStorage对象进行管理
    if (storage->size_ >= size + sizeof(PreallocatedStorage)) {
      storage->Unlink();
      storage->LinkTo(&in_use_list_);
      // 分配一部分出去,storage + 1即可用于存储数据的首地址,加上size得到还剩下的空闲内存首地址
      PreallocatedStorage* left_over =
          reinterpret_cast<PreallocatedStorage*>(
              reinterpret_cast<char*>(storage + 1) + size);
      // 剩下的大小等于本来的大小减去size-一个PreallocatedStorage对象
      left_over->size_ = storage->size_ - size - sizeof(PreallocatedStorage);
      ASSERT(size + left_over->size_ + sizeof(PreallocatedStorage) ==
             storage->size_);
      // 更新原来的storage的大小,为请求的size,stroage被切分了
      storage->size_ = size;
      // 剩下的插入空闲链表
      left_over->LinkTo(&free_list_);
      // 返回可用于存储数据的首地址
      return reinterpret_cast<void*>(storage + 1);
    }
  }
  // Allocation failure.
  ASSERT(false);
  return NULL;
}


// We don't attempt to coalesce.
// 释放内存,不作合并处理,p是存储数据的首地址
void PreallocatedStorage::Delete(void* p) {
  if (p == NULL) {
    return;
  }
  // 参考New
  if (!preallocated_) {
    FreeStoreAllocationPolicy::Delete(p);
    return;
  }
  // 转成PreallocatedStorage指针,减一则指向管理这块内存的PreallocatedStorage对象
  PreallocatedStorage* storage = reinterpret_cast<PreallocatedStorage*>(p) - 1;
  ASSERT(storage->next_->previous_ == storage);
  ASSERT(storage->previous_->next_ == storage);
  // 脱离原来的链表,插入空闲链表
  storage->Unlink();
  storage->LinkTo(&free_list_);
}

// 插入双向循环链表
void PreallocatedStorage::LinkTo(PreallocatedStorage* other) {
  next_ = other->next_;
  other->next_->previous_ = this;
  previous_ = other;
  other->next_ = this;
}


void PreallocatedStorage::Unlink() {
  next_->previous_ = previous_;
  previous_->next_ = next_;
}


PreallocatedStorage::PreallocatedStorage(size_t size)
  : size_(size) {
  previous_ = next_ = this;
}

} }  // namespace v8::internal
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程杂技 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档