相关文章推荐
发呆的黑框眼镜  ·  第三方库——JSON介绍与使用_json是什么库·  2 月前    · 
高大的春卷  ·  原生JS用AJAX以POST方式发送json ...·  1 月前    · 
爱听歌的刺猬  ·  TS项目自动识别types目录下的type. ...·  1 月前    · 
玩足球的人字拖  ·  如何在Vue组件中调用封装好的外部js文件方 ...·  1 月前    · 
想旅行的梨子  ·  javascript - js ...·  1 月前    · 
腼腆的绿豆  ·  Error in rconfigure() ...·  9 月前    · 
爱健身的鼠标垫  ·  jenkins定位GitLab推送的最新We ...·  1 年前    · 
想表白的金鱼  ·  CAD:应用程序的组件中发生了未处理的异常_ ...·  1 年前    · 
安静的甘蔗  ·  bool的存储过程_百度知道·  1 年前    · 
暴走的骆驼  ·  引导选择事件参数 - 问答 - ...·  1 年前    · 
Code  ›  js引擎v8源码解析之对象第二篇(基于v8 0.1.5)开发者社区
源码 int函数 js js代码
https://cloud.tencent.com/developer/article/1543294
怕老婆的柠檬
1 年前
theanarkh

js引擎v8源码解析之对象第二篇(基于v8 0.1.5)

腾讯云
开发者社区
文档 建议反馈 控制台
首页
学习
活动
专区
工具
TVP
最新优惠活动
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP 最新优惠活动
返回腾讯云官网
theanarkh
首页
学习
活动
专区
工具
TVP 最新优惠活动
返回腾讯云官网
社区首页 > 专栏 > js引擎v8源码解析之对象第二篇(基于v8 0.1.5)

js引擎v8源码解析之对象第二篇(基于v8 0.1.5)

作者头像
theanarkh
发布 于 2019-11-23 22:24:51
694 0
发布 于 2019-11-23 22:24:51
举报
文章被收录于专栏: 原创分享 原创分享

继续分析类。首先是HeadNumber。

1 HeadNumber

HeadNumber类的代码比较少。

// The HeapNumber class describes heap allocated numbers that cannot be
// represented in a Smi (small integer)
// 存储了数字的堆对象
class HeapNumber: public HeapObject {
 public:
  // [value]: number value.
  inline double value();
  inline void set_value(double value);
  // Casting.
  static inline HeapNumber* cast(Object* obj);
  // Dispatched behavior.
  Object* HeapNumberToBoolean();
  // Layout description.
  // kSize之前的空间存储map对象的指针
  static const int kValueOffset = HeapObject::kSize;
  // kValueOffset - kSize之间存储数字的值
  static const int kSize = kValueOffset + kDoubleSize;
 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(HeapNumber);
};

我们看看他的实现。

// 读出double类型的值
#define READ_DOUBLE_FIELD(p, offset) \
  (*reinterpret_cast<double*>(FIELD_ADDR(p, offset)))
// 写入double类型的值
#define WRITE_DOUBLE_FIELD(p, offset, value) \
  (*reinterpret_cast<double*>(FIELD_ADDR(p, offset)) = value)
// 读写属性的值
double HeapNumber::value() {
  return READ_DOUBLE_FIELD(this, kValueOffset);
// 写double值到对象
void HeapNumber::set_value(double value) {
  WRITE_DOUBLE_FIELD(this, kValueOffset, value);
Object* HeapNumber::HeapNumberToBoolean() {
  // NaN, +0, and -0 should return the false object
  switch (fpclassify(value())) {
    case FP_NAN:  // fall through
    case FP_ZERO: return Heap::false_value();
    default: return Heap::true_value();
}

还有一个函数就是cast,实现如下:

CAST_ACCESSOR(HeapNumber)
#define CAST_ACCESSOR(type)                     \
  type* type::cast(Object* object) {            \
    ASSERT(object->Is##type());                 \
    return reinterpret_cast<type*>(object);     \
CAST_ACCESSOR(HeapNumber);
HeapNumber* HeapNumber::cast(Object* object) {            \
    ASSERT(object->IsHeapNumber());                 \
    return reinterpret_cast<HeapNumber*>(object);     \

至此HeapNumber分析完了。接着看下一个类Array。

2 Array

// Abstract super class arrays. It provides length behavior.
class Array: public HeapObject {
 public:
  // [length]: length of the array.
  inline int length();
  inline void set_length(int value);
  // Convert an object to an array index.
  // Returns true if the conversion succeeded.
  static inline bool IndexFromObject(Object* object, uint32_t* index);
  // Layout descriptor.
  static const int kLengthOffset = HeapObject::kSize;
  static const int kHeaderSize = kLengthOffset + kIntSize;
 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(Array);
};

我们发现数组的对象内存布局中,只有一个属性。就是保存length大小的。首先看看读写length属性的实现。

#define INT_ACCESSORS(holder, name, offset)                             \
  int holder::name() { return READ_INT_FIELD(this, offset); }           \
  void holder::set_##name(int value) { WRITE_INT_FIELD(this, offset, value); }
// 定义数组的length和set_length函数,属性在对象的偏移的kLengthOffset,紧跟着map指针
INT_ACCESSORS(Array, length, kLengthOffset);

再继续看IndexFromObject的实现。

bool Array::IndexFromObject(Object* object, uint32_t* index) {
  if (object->IsSmi()) {
    int value = Smi::cast(object)->value();
    if (value < 0) return false;
    *index = value;
    return true;
  if (object->IsHeapNumber()) {
    double value = HeapNumber::cast(object)->value();
    uint32_t uint_value = static_cast<uint32_t>(value);
    if (value == static_cast<double>(uint_value)) {
      *index = uint_value;
      return true;
  return false;
}

该函数就是把一个对象(底层是表示数字的)转成一个数组索引。数组类也分析完了。我们继续。

3 ByteArray

// ByteArray represents fixed sized byte arrays.  Used by the outside world,
// such as PCRE, and also by the memory allocator and garbage collector to
// fill in free blocks in the heap.
class ByteArray: public Array {
 public:
  // Setter and getter.
  inline byte get(int index);
  inline void set(int index, byte value);
  // Treat contents as an int array.
  inline int get_int(int index);
    ByteArray类没有定义自己的属性,他是根据length算出对象的大小,
    然后在分配内存的时候,多分配一块存储数组元素的内存
    const int kObjectAlignmentBits = 2;
    const int kObjectAlignmentMask = (1 << kObjectAlignmentBits) - 1;
    #define OBJECT_SIZE_ALIGN(value)  ((value + kObjectAlignmentMask) & ~kObjectAlignmentMask)
    由此可知,按四个字节对齐。OBJECT_SIZE_ALIGN的作用的是不够4字节的,会多分配几个字节,使得按四字节对齐。~kObjectAlignmentMask是低两位是0,即按四字节对齐。比如value已经4字节对齐了,则(4 + 0 +3) & ~3 =4,如果value没有对齐,假设是5,则(4 + 1 +3) & ~3 = 8;如果value等于6,(4 + 2 + 3) & ~3 = 8;以此类推。
  static int SizeFor(int length) {
    return kHeaderSize + OBJECT_SIZE_ALIGN(length);
  // We use byte arrays for free blocks in the heap.  Given a desired size in
  // bytes that is a multiple of the word size and big enough to hold a byte
  // array, this function returns the number of elements a byte array should
  // have.
  static int LengthFor(int size_in_bytes) {
    ASSERT(IsAligned(size_in_bytes, kPointerSize));
    ASSERT(size_in_bytes >= kHeaderSize);
    return size_in_bytes - kHeaderSize;
  // Returns data start address.
  inline Address GetDataStartAddress();
  // Returns a pointer to the ByteArray object for a given data start address.
  static inline ByteArray* FromDataStartAddress(Address address);
  // Casting.
  static inline ByteArray* cast(Object* obj);
  // Dispatched behavior.
  int ByteArraySize() { return SizeFor(length()); }
 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(ByteArray);
};

在分析实现之前我们先看一下ByteArray的对象是怎么被分配的。

Handle<ByteArray> Factory::NewByteArray(int length) {
  ASSERT(0 <= length);
  CALL_HEAP_FUNCTION(Heap::AllocateByteArray(length), ByteArray);
Object* Heap::AllocateByteArray(int length) {
  int size = ByteArray::SizeFor(length);
  AllocationSpace space = size > MaxHeapObjectSize() ? LO_SPACE : NEW_SPACE;
  Object* result = AllocateRaw(size, space);
  if (result->IsFailure()) return result;
  reinterpret_cast<Array*>(result)->set_map(byte_array_map());
  reinterpret_cast<Array*>(result)->set_length(length);
  return result;
}

我们看到,首先通过ByteArray::SizeFor算出对象所需的内存大小size。然后分配一块大小为size的内存。然后返回这块内存的地址。这时候我们就可以使用这块内存。我们看看怎么使用的。内存布局如下。

byte ByteArray::get(int index) {
  ASSERT(index >= 0 && index < this->length());
  // 根据索引返回数组中对应元素的值,kHeaderSize是第一个元素的地址,kCharSize是1,即一个字节
  return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
void ByteArray::set(int index, byte value) {
  ASSERT(index >= 0 && index < this->length());
  WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize, value);
// 把四个元素(四个字节)的内容作为一个值。即ByteArray变成IntArray
int ByteArray::get_int(int index) {
  ASSERT(index >= 0 && (index * kIntSize) < this->length());
  return READ_INT_FIELD(this, kHeaderSize + index * kIntSize);
ByteArray* ByteArray::FromDataStartAddress(Address address) {
  ASSERT_TAG_ALIGNED(address);
  return reinterpret_cast<ByteArray*>(address - kHeaderSize + kHeapObjectTag);
// 返回数组元素的首地址,地址的低位是用作标记,要先减掉。kHeaderSize是第一个元素在对象内存空间的偏移
Address ByteArray::GetDataStartAddress() {
 
推荐文章
发呆的黑框眼镜  ·  第三方库——JSON介绍与使用_json是什么库
2 月前
高大的春卷  ·  原生JS用AJAX以POST方式发送json格式的请求 -
1 月前
爱听歌的刺猬  ·  TS项目自动识别types目录下的type.d.ts文件_vue3+ ts 项目中.d.ts 文件会自动读取吗?
1 月前
玩足球的人字拖  ·  如何在Vue组件中调用封装好的外部js文件方法-天翼云
1 月前
想旅行的梨子  ·  javascript - js 如何根据选择的时区把时间戳转换成时区的标准时间 -
1 月前
腼腆的绿豆  ·  Error in rconfigure() method java.rmi.ConnectException: Connection refused t - CSDN文库
9 月前
爱健身的鼠标垫  ·  jenkins定位GitLab推送的最新Webhook中push event来自哪一个分支 - zblade - 博客园
1 年前
想表白的金鱼  ·  CAD:应用程序的组件中发生了未处理的异常_cad应用程序的组件中发生了未经处理的异常_浮云清风的博客-CSDN博客
1 年前
安静的甘蔗  ·  bool的存储过程_百度知道
1 年前
暴走的骆驼  ·  引导选择事件参数 - 问答 - 腾讯云开发者社区-腾讯云
1 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号