Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >js引擎v8源码解析之对象第二篇(基于v8 0.1.5)

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

作者头像
theanarkh
发布于 2019-11-23 14:24:51
发布于 2019-11-23 14:24:51
77700
代码可运行
举报
文章被收录于专栏:原创分享原创分享
运行总次数:0
代码可运行

继续分析类。首先是HeadNumber。

1 HeadNumber

HeadNumber类的代码比较少。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 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);
};

我们看看他的实现。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 读出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,实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 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属性的实现。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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的实现。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 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的对象是怎么被分配的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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的内存。然后返回这块内存的地址。这时候我们就可以使用这块内存。我们看看怎么使用的。内存布局如下。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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() {
  /*
    typedef uint8_t byte;
    typedef byte* Address;
  */
  return reinterpret_cast<Address>(this) - kHeapObjectTag + kHeaderSize;
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-17,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
js引擎v8源码分析之HeapObject(基于v8 0.1.5)
HeapObject是Object的子类。是所有基于堆分配的对象的基类。 class HeapObject: public Object { public: // 每个堆对象都有一个map对象,记录对象的类型,大小等信息 inline Map* map(); inline void set_map(Map* value); // 对象的地址+对象标记 static inline HeapObject* FromAddress(Address address); // 对象的真正
theanarkh
2020/02/25
9840
js引擎v8源码分析之HeapObject(基于v8 0.1.5)
js引擎v8源码解析之对象第一篇(基于v8 0.1.5)
我们看到类中有一个静态属性kSize,这个属性是标记该类的对象,属性需要占据的内存字节大小。下面我们看第一个继承于Object的类Smi。Smi是表示小整形。我们看他的定义。
theanarkh
2019/11/23
9460
js引擎v8源码解析之map对象上篇(基于v8 0.1.5)
从上面的代码中我们知道,只是对某些属性或标记进行读写。根据对象的内存布局对号入座就行,至于每个属性和标记的意义,后续再慢慢探讨。map还有很多函数,但是会涉及很多其他的类,等后面分析完了,再继续分析。
theanarkh
2019/11/23
1.6K0
v8源码解析之数组系列1(v8 0.1.5)
v8中很多数据结构都具备数组的特性,今天我们先介绍Array和FixedArray。他们是V8中很多数据结构的基类。
theanarkh
2020/11/02
9040
v8源码解析之数组系列1(v8 0.1.5)
v8源码解析之ByteArray(v8 0.1.5)
ByteArray是字节数组的实现,顾名思义,该数组的元素大小的一个字节,不过类似js的Uint16Array,Uint32Array数组一样,我们可以把多个元素看做一个,把多个字节合并成一个元素看待。下面我们看一下实现。
theanarkh
2020/11/02
7660
v8源码解析之ByteArray(v8 0.1.5)
js引擎v8源码解析之对象第四篇(基于v8 0.1.5)
SemiSpace他自己不申请内存。他是负责管理某块内存的,内存申请在其他地方处理。
theanarkh
2019/11/24
5800
js引擎v8源码分析之Object(基于v8 0.1.5)
1 c++对象的类型 1 v8的对象是4字节对齐的,用地址的低两位出来标记对象的类型。 2 堆对象(HeapObject)是Object的子类。Object里面的很多方法都是用于堆对象。堆对象有自己的一套对象类型判断方式。每个堆对象有一个map属性,他记录了堆对象的类型type,大小size。 1 type主要是用于记录c++对象的类型。 2 有一些单例的map对象,也是用于判断c++对象的类型的。 3 map的type属性的低八位是用来区分是不是字符串类型的。高位8位是1说明不是字符串,是0说明是字符串类型。低7位记录字符串的子类型。 下面是定义。
theanarkh
2020/02/25
1.5K0
js引擎v8源码分析之Object(基于v8 0.1.5)
js引擎v8源码解析之对象第三篇(基于v8 0.1.5)
我们从代码可以知道,这几个类没有太多的逻辑,都有一系列的属性和对应的读写函数。对号入座就行。
theanarkh
2019/11/24
6840
js引擎v8源码解析之allocation(基于0.1.5)
#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 }
theanarkh
2019/07/30
8220
js引擎v8源码解析之allocation(基于0.1.5)
js引擎v8源码分析之HeapNumber(基于v8 0.1.5)
HeapNumber是保存大整形的对象。v8里有smi保存整形,但是他只有31位,超过31位的就需要用HeapNumber。
theanarkh
2020/02/25
8500
js引擎v8源码分析之NewSpace(基于v8 0.1.5)
NewSpace是v8内存管理中,负责管理新生代区的类。分为from和to两个区,每个区由SemiSpace对象管理。和SemiSpace一样,NewSpace也不负责内存的分配和释放,他只负责内存的使用和管理。下面是类的定义。
theanarkh
2020/02/17
7850
CVE-2018-17463详细分析及复现
(https://bbs.pediy.com/thread-274865.htm)
h1J4cker
2022/12/01
5050
js引擎v8源码分析之SemiSpace(基于v8 0.1.5)
SemiSpace的管理新生代内存的类,即我们常听到的from区和to区。from区和to区都由一个SemiSpace对象管理。SemiSpace只管理地址,不负责分配和释放管理的内存。下面是Semispace类的定义。
theanarkh
2020/02/17
1K0
js引擎v8源码解析之zone(基于0.1.5)
zone也是用于内存管理的,不过他是增量分配,一次销毁的。下面是结构图。 zone.h #ifndef V8_ZONE_H_ #define V8_ZONE_H_ namespace v8 { namespace internal { // The Zone supports very fast allocation of small chunks of // memory. The chunks cannot be deallocated individually, but instead // t
theanarkh
2019/07/30
1.1K0
js引擎v8源码解析之zone(基于0.1.5)
js引擎v8源码解析之平台相关(上篇)(基于v8 0.1.5)
PlatformData 是管理线程中,不同系统中的数据。这里只看linux系统。只保存了线程id。
theanarkh
2019/11/23
6750
V8 新生代垃圾回收的实现
前言:因为最近在做一些 gc track 的事情,所以打算了解一下 V8 GC 的实现。介绍 V8 GC 的文章网上已经有很多,就不打算再重复介绍。本文主要介绍一下新生代 GC 的实现,代码参考 V8 10.2,因为 GC 的实现非常复杂,只能介绍一些大致的实现,读者需要对 V8 GC 有一定的了解,比如新生代是分为 from 和 to 两个 space,然后在 GC 时是如何处理的。
theanarkh
2022/05/16
7500
V8 GC 的实现
前言:GC 是一个古老、复杂并且很 Cool 的技术,本文大概介绍一下早期 V8 中关于 GC 实现的部分,代码版本 0.1.5,早期版本利于快速理解整体的逻辑,因为现代版本已经非常复杂。
theanarkh
2022/12/06
3450
V8 GC 的实现
V8 CPU Profiler 的实现
前言:CPU Profiler 是应用性能诊断和优化的利器,本文介绍 V8 中关于这部分的实现,细节比较多也比较复杂,大致分析一下原理,代码来自 V8 10.2。
theanarkh
2022/05/16
8490
V8 CPU Profiler 的实现
js引擎v8源码解析之token(基于0.1.5)
#ifndef V8_TOKEN_H_ #define V8_TOKEN_H_ namespace v8 { namespace internal { // TOKEN_LIST takes a list of 3 macros M, all of which satisfy the // same signature M(name, string, precedence), where name is the // symbolic token name, string is the corres
theanarkh
2019/07/30
3.2K0
js引擎v8源码解析之list(基于0.1.5)
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef V8_LIST_H_ #define V8_LIST_H_ namespace v8 { namespace internal { // ---------------------------------------------------------------------------- // The list is a template for v
theanarkh
2019/07/30
6980
相关推荐
js引擎v8源码分析之HeapObject(基于v8 0.1.5)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档