本篇内容介绍了“js引擎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() {
/*
typedef uint8_t byte;
typedef byte* Address;
*/
return reinterpret_cast<Address>(this) - kHeapObjectTag + kHeaderSize;
}“js引擎HeadNumber类是怎么实现的”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
原创文章,作者:bd101bd101,如若转载,请注明出处:https://blog.ytso.com/223322.html