Object是所有js对象在c++层的基类。
class Object BASE_EMBEDDED {
public:
inline bool IsSmi();
inline bool IsHeapObject();
inline bool IsHeapNumber();
inline bool IsString();
inline bool IsSeqString();
inline bool IsAsciiString();
inline bool IsTwoByteString();
inline bool IsConsString();
inline bool IsSlicedString();
inline bool IsExternalString();
inline bool IsExternalAsciiString();
inline bool IsExternalTwoByteString();
inline bool IsShortString();
inline bool IsMediumString();
inline bool IsLongString();
inline bool IsSymbol();
inline bool IsNumber();
inline bool IsByteArray();
inline bool IsFailure();
inline bool IsRetryAfterGC();
inline bool IsException();
inline bool IsJSObject();
inline bool IsMap();
inline bool IsFixedArray();
inline bool IsDescriptorArray();
inline bool IsContext();
inline bool IsGlobalContext();
inline bool IsJSFunction();
inline bool IsCode();
inline bool IsOddball();
inline bool IsSharedFunctionInfo();
inline bool IsJSValue();
inline bool IsProxy();
inline bool IsBoolean();
inline bool IsJSArray();
inline bool IsHashTable();
inline bool IsDictionary();
inline bool IsSymbolTable();
inline bool IsPrimitive();
inline bool IsGlobalObject();
inline bool IsJSGlobalObject();
inline bool IsJSBuiltinsObject();
inline bool IsUndetectableObject();
inline bool IsAccessCheckNeeded();
// Returns true if this object is an instance of the specified
// function template.
bool IsInstanceOf(FunctionTemplateInfo* type);
inline bool IsStruct();
inline bool IsAccessorInfo();
inline bool IsAccessCheckInfo();
inline bool IsInterceptorInfo();
inline bool IsCallHandlerInfo();
inline bool IsFunctionTemplateInfo();
inline bool IsObjectTemplateInfo();
inline bool IsSignatureInfo();
inline bool IsTypeSwitchInfo();
inline bool IsDebugInfo();
inline bool IsBreakPointInfo();
inline bool IsScript();
// Oddball testing.
INLINE(bool IsUndefined());
INLINE(bool IsTheHole());
INLINE(bool IsNull());
INLINE(bool IsTrue());
INLINE(bool IsFalse());
// Extract the number.
inline double Number();
Object* ToObject(); // ECMA-262 9.9.
Object* ToBoolean(); // ECMA-262 9.2.
Object* ToObject(Context* global_context);
inline Object* ToSmi();
void Lookup(String* name, LookupResult* result);
// Property access.
inline Object* GetProperty(String* key);
inline Object* GetProperty(String* key, PropertyAttributes* attributes);
Object* GetPropertyWithReceiver(Object* receiver,String* key,PropertyAttributes* attributes);
Object* GetProperty(Object* receiver,LookupResult* result,String* key,PropertyAttributes* attributes);
Object* GetPropertyWithCallback(Object* receiver,Object* structure,String* name,Object* holder);
inline Object* GetElement(uint32_t index);
Object* GetElementWithReceiver(Object* receiver, uint32_t index);
Object* GetPrototype();
inline bool IsStringObjectWithCharacterAt(uint32_t index);
static Object* cast(Object* value) { return value; }
// 对象在内存的布局,基类没有属性,内存是0
static const int kSize = 0; // Object does not take up any space.
private:
// 禁止直接创建对象,复制函数,赋值函数
DISALLOW_IMPLICIT_CONSTRUCTORS(Object);
};
基类主要是提供一些公共的方式,比如判断类型,属性存取。类型转化。
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位记录字符串的子类型。
下面是定义。
// 第7位(从0开始算)如果是1说明对象不是字符串类型,否则是
const uint32_t kIsNotStringMask = 0x80;
const uint32_t kStringTag = 0x0;
const uint32_t kNotStringTag = 0x80;
// If bit 7 is clear, bits 5 and 6 are the string's size (short, medium, or
// long).
// 对于字符串类型,5,6两位标记字符串的类型,短,中等,长三种类型
const uint32_t kStringSizeMask = 0x60;
const uint32_t kShortStringTag = 0x0;
const uint32_t kMediumStringTag = 0x20;
const uint32_t kLongStringTag = 0x40;
// If bit 7 is clear, bit 4 indicates that the string is a symbol (if set) or
// not (if cleared).
// 第四位标记字符串是不是symbol类型,1则表示是
const uint32_t kIsSymbolMask = 0x10;
const uint32_t kNotSymbolTag = 0x0;
const uint32_t kSymbolTag = 0x10;
// If bit 7 is clear, and the string representation is a sequential string,
// then bit 3 indicates whether the string consists of two-byte characters or
// one-byte characters.
// 第三位表示字符串是单字节字符还是双字节字符组成的
const uint32_t kStringEncodingMask = 0x8;
const uint32_t kTwoByteStringTag = 0x0;
const uint32_t kAsciiStringTag = 0x8;
// If bit 7 is clear, the low-order 3 bits indicate the representation
// of the string.
// 第0,1,2位表示字符串类型,四种
const uint32_t kStringRepresentationMask = 0x07;
enum StringRepresentationTag {
kSeqStringTag = 0x0,
kConsStringTag = 0x1,
kSlicedStringTag = 0x2,
kExternalStringTag = 0x3
};
enum InstanceType {
// 下面都是字符串类型,根据上面的定义,下面的tag标记在8比特上各有自己的位置范围,所以相与的结果不会一样
SHORT_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kSeqStringTag,
MEDIUM_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kSeqStringTag,
LONG_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kSeqStringTag,
SHORT_ASCII_SYMBOL_TYPE = kShortStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
MEDIUM_ASCII_SYMBOL_TYPE = kMediumStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
LONG_ASCII_SYMBOL_TYPE = kLongStringTag | kAsciiStringTag | kSymbolTag | kSeqStringTag,
SHORT_CONS_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kConsStringTag,
MEDIUM_CONS_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kConsStringTag,
LONG_CONS_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kConsStringTag,
SHORT_CONS_ASCII_SYMBOL_TYPE = kShortStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
MEDIUM_CONS_ASCII_SYMBOL_TYPE = kMediumStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
LONG_CONS_ASCII_SYMBOL_TYPE = kLongStringTag | kAsciiStringTag | kSymbolTag | kConsStringTag,
SHORT_SLICED_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kSlicedStringTag,
MEDIUM_SLICED_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kSlicedStringTag,
LONG_SLICED_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kSlicedStringTag,
SHORT_SLICED_ASCII_SYMBOL_TYPE = kShortStringTag | kAsciiStringTag | kSymbolTag | kSlicedStringTag,
MEDIUM_SLICED_ASCII_SYMBOL_TYPE = kMediumStringTag | kAsciiStringTag | kSymbolTag | kSlicedStringTag,
LONG_SLICED_ASCII_SYMBOL_TYPE = kLongStringTag | kAsciiStringTag | kSymbolTag | kSlicedStringTag,
SHORT_EXTERNAL_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kExternalStringTag,
MEDIUM_EXTERNAL_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kExternalStringTag,
LONG_EXTERNAL_SYMBOL_TYPE = kLongStringTag | kSymbolTag | kExternalStringTag,
SHORT_EXTERNAL_ASCII_SYMBOL_TYPE = kShortStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
MEDIUM_EXTERNAL_ASCII_SYMBOL_TYPE = kMediumStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
LONG_EXTERNAL_ASCII_SYMBOL_TYPE = kLongStringTag | kAsciiStringTag | kSymbolTag | kExternalStringTag,
SHORT_STRING_TYPE = kShortStringTag | kSeqStringTag,
MEDIUM_STRING_TYPE = kMediumStringTag | kSeqStringTag,
LONG_STRING_TYPE = kLongStringTag | kSeqStringTag,
SHORT_ASCII_STRING_TYPE = kShortStringTag | kAsciiStringTag | kSeqStringTag,
MEDIUM_ASCII_STRING_TYPE = kMediumStringTag | kAsciiStringTag | kSeqStringTag,
LONG_ASCII_STRING_TYPE = kLongStringTag | kAsciiStringTag | kSeqStringTag,
SHORT_CONS_STRING_TYPE = kShortStringTag | kConsStringTag,
MEDIUM_CONS_STRING_TYPE = kMediumStringTag | kConsStringTag,
LONG_CONS_STRING_TYPE = kLongStringTag | kConsStringTag,
SHORT_CONS_ASCII_STRING_TYPE = kShortStringTag | kAsciiStringTag | kConsStringTag,
MEDIUM_CONS_ASCII_STRING_TYPE = kMediumStringTag | kAsciiStringTag | kConsStringTag,
LONG_CONS_ASCII_STRING_TYPE = kLongStringTag | kAsciiStringTag | kConsStringTag,
SHORT_SLICED_STRING_TYPE = kShortStringTag | kSlicedStringTag,
MEDIUM_SLICED_STRING_TYPE = kMediumStringTag | kSlicedStringTag,
LONG_SLICED_STRING_TYPE = kLongStringTag | kSlicedStringTag,
SHORT_SLICED_ASCII_STRING_TYPE = kShortStringTag | kAsciiStringTag | kSlicedStringTag,
MEDIUM_SLICED_ASCII_STRING_TYPE = kMediumStringTag | kAsciiStringTag | kSlicedStringTag,
LONG_SLICED_ASCII_STRING_TYPE = kLongStringTag | kAsciiStringTag | kSlicedStringTag,
SHORT_EXTERNAL_STRING_TYPE = kShortStringTag | kExternalStringTag,
MEDIUM_EXTERNAL_STRING_TYPE = kMediumStringTag | kExternalStringTag,
LONG_EXTERNAL_STRING_TYPE = kLongStringTag | kExternalStringTag,
SHORT_EXTERNAL_ASCII_STRING_TYPE = kShortStringTag | kAsciiStringTag | kExternalStringTag,
MEDIUM_EXTERNAL_ASCII_STRING_TYPE = kMediumStringTag | kAsciiStringTag | kExternalStringTag,
LONG_EXTERNAL_ASCII_STRING_TYPE = kLongStringTag | kAsciiStringTag | kExternalStringTag,
LONG_PRIVATE_EXTERNAL_ASCII_STRING_TYPE = LONG_EXTERNAL_ASCII_STRING_TYPE,
/*
下面是所有类型都不属于字符串类型,kNotStringTag是128,即10000000,
因为最高一位是0表示是字符串类型,所以10000000保证了大于所有字符串类型的值
*/
MAP_TYPE = kNotStringTag,
HEAP_NUMBER_TYPE,
FIXED_ARRAY_TYPE,
CODE_TYPE,
ODDBALL_TYPE,
PROXY_TYPE,
BYTE_ARRAY_TYPE,
FILLER_TYPE,
SMI_TYPE,
ACCESSOR_INFO_TYPE,
ACCESS_CHECK_INFO_TYPE,
INTERCEPTOR_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
CALL_HANDLER_INFO_TYPE,
FUNCTION_TEMPLATE_INFO_TYPE,
OBJECT_TEMPLATE_INFO_TYPE,
SIGNATURE_INFO_TYPE,
TYPE_SWITCH_INFO_TYPE,
DEBUG_INFO_TYPE,
BREAK_POINT_INFO_TYPE,
SCRIPT_TYPE,
JS_OBJECT_TYPE,
JS_GLOBAL_OBJECT_TYPE,
JS_BUILTINS_OBJECT_TYPE,
JS_VALUE_TYPE,
JS_ARRAY_TYPE,
JS_FUNCTION_TYPE,
// Pseudo-types
FIRST_NONSTRING_TYPE = MAP_TYPE,
FIRST_TYPE = 0x0,
LAST_TYPE = JS_FUNCTION_TYPE,
FIRST_JS_OBJECT_TYPE = JS_OBJECT_TYPE,
LAST_JS_OBJECT_TYPE = JS_ARRAY_TYPE
}
示例图如下
我们对c++对象的类型大概有了一个印象,下面看一下Object类的定义。下面是几个宏,用来判断c++对象的类型的。
#define HAS_SMI_TAG(value) ((reinterpret_cast<int>(value) & kSmiTagMask) == kSmiTag)
#define HAS_FAILURE_TAG(value) ((reinterpret_cast<int>(value) & kFailureTagMask) == kFailureTag)
#define HAS_HEAP_OBJECT_TAG(value) ((reinterpret_cast<int>(value) & kHeapObjectTagMask) == kHeapObjectTag
下面是一些有代表性的isType函数的定义。
// 地址的低位是否是0
bool Object::IObject::isSmi() {
return HAS_SMI_TAG(this);
}
// 低两位是01
bool Object::IsHeapObject() {
return HAS_HEAP_OBJECT_TAG(this);
}
// 类型判断,在map里标记
bool Object::IsHeapNumber() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == HEAP_NUMBER_TYPE;
}
bool Object::IsString() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() < FIRST_NONSTRING_TYPE;
}
bool Object::IsSeqString() {
return IsString()
&& (String::cast(this)->representation_tag() == kSeqStringTag);
}
bool Object::IsByteArray() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == BYTE_ARRAY_TYPE;
}
bool Object::IsJSObject() {
return IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() >= JS_OBJECT_TYPE;
}
// 根据单例map对象判断类型
bool Object::IsContext() {
return Object::IsHeapObject()
&& (HeapObject::cast(this)->map() == Heap::context_map() ||
HeapObject::cast(this)->map() == Heap::global_context_map());
}
bool Object::IsUndefined() {
return this == Heap::undefined_value();
}
bool Object::IsTheHole() {
return this == Heap::the_hole_value();
}
下面继续看其他函数的定义。
1 解包对象里的数字。smi是小整形,在v8中表示整形。长度是31位。
double Object::Number() {
return IsSmi()
? static_cast<double>(reinterpret_cast<Smi*>(this)->value())
: reinterpret_cast<HeapNumber*>(this)->value();
}
2 转成smi对象
Object* Object::ToSmi() {
// 已经是,直接返回
if (IsSmi()) return this;
// 是堆对象
if (IsHeapNumber()) {
double value = HeapNumber::cast(this)->value();
// double to int类型
int int_value = FastD2I(value);
if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
return Smi::FromInt(int_value);
}
}
return Failure::Exception();
}
3 判断index是不是字符串的有效长度
bool Object::IsStringObjectWithCharacterAt(uint32_t index) {
if (!this->IsJSValue()) return false;
JSValue* js_value = JSValue::cast(this);
if (!js_value->value()->IsString()) return false;
String* str = String::cast(js_value->value());
if (index >= (uint32_t)str->length()) return false;
return true;
}
4 参考js的IsInstanceOf。很多类型后面的时候分析。
bool Object::IsInstanceOf(FunctionTemplateInfo* expected) {
// js对象的基类
if (!this->IsJSObject()) return false;
Object* cons_obj = JSObject::cast(this)->map()->constructor();
if (!cons_obj->IsJSFunction()) return false;
JSFunction* fun = JSFunction::cast(cons_obj);
for (Object* type = fun->shared()->function_data();type->IsFunctionTemplateInfo(); type = FunctionTemplateInfo::cast(type)->parent_template()) {
if (type == expected) return true;
}
// Didn't find the required type in the inheritance chain.
return false;
}
5 ToObject,其他类型转成对象类型。js的原生类型需要转成对象的时候。具体的在分析子类时再详细分析。
static Object* CreateJSValue(JSFunction* constructor, Object* value) {
// 分类一个以constructor为构造函数的对象
Object* result = Heap::AllocateJSObject(constructor);
if (result->IsFailure()) return result;
JSValue::cast(result)->set_value(value);
return result;
}
Object* Object::ToObject(Context* global_context) {
if (IsNumber()) {
return CreateJSValue(global_context->number_function(), this);
} else if (IsBoolean()) {
return CreateJSValue(global_context->boolean_function(), this);
} else if (IsString()) {
return CreateJSValue(global_context->string_function(), this);
}
ASSERT(IsJSObject());
return this;
}
Object* Object::ToObject() {
Context* global_context = Top::context()->global_context();
if (IsJSObject()) {
return this;
} else if (IsNumber()) {
return CreateJSValue(global_context->number_function(), this);
} else if (IsBoolean()) {
return CreateJSValue(global_context->boolean_function(), this);
} else if (IsString()) {
return CreateJSValue(global_context->string_function(), this);
}
// Throw a type error.
return Failure::InternalError();
}
6 ToBoolean,判断js变量是true或false的时候使用。
Object* Object::ToBoolean() {
if (IsTrue()) return Heap::true_value();
if (IsFalse()) return Heap::false_value();
// 数字0是false
if (IsSmi()) {
return Heap::ToBoolean(Smi::cast(this)->value() != 0);
}
// null或undefined是false
if (IsUndefined() || IsNull()) return Heap::false_value();
// Undetectable object is false
if (IsUndetectableObject()) {
return Heap::false_value();
}
// 空字符串是false
if (IsString()) {
return Heap::ToBoolean(String::cast(this)->length() != 0);
}
//
if (IsHeapNumber()) {
return HeapNumber::cast(this)->HeapNumberToBoolean();
}
return Heap::true_value();
}
7 属性查找,使用具体类型的查找函数
void Object::Lookup(String* name, LookupResult* result) {
if (IsJSObject()) return JSObject::cast(this)->Lookup(name, result);
Object* holder = NULL;
Context* global_context = Top::context()->global_context();
if (IsString()) {
holder = global_context->string_function()->instance_prototype();
} else if (IsNumber()) {
holder = global_context->number_function()->instance_prototype();
} else if (IsBoolean()) {
holder = global_context->boolean_function()->instance_prototype();
}
ASSERT(holder != NULL); // cannot handle null or undefined.
JSObject::cast(holder)->Lookup(name, result);
}
8 查找原型对象
Object* Object::GetPrototype() {
// 对象的原型对象存在map对象里
if (IsJSObject()) return JSObject::cast(this)->map()->prototype();
Context* context = Top::context()->global_context();
if (IsNumber()) return context->number_function()->instance_prototype();
if (IsString()) return context->string_function()->instance_prototype();
if (IsBoolean()) {
return context->boolean_function()->instance_prototype();
} else {
return Heap::null_value();
}
}
还有几个属性查找的函数,依赖一些子类,分析完子类再分析。