google_javascript_engine_v8_阅读笔记
Utils::OpenHandle:
#define MAKE_OPEN_HANDLE(From, To) \ v8::internal::Handle<v8::internal::To> Utils::OpenHandle(\ const v8::From* that) { \ return v8::internal::Handle<v8::internal::To>( \ reinterpret_cast<v8::internal::To**>(const_cast<v8::From*>(that))); \ } MAKE_OPEN_HANDLE(Template, TemplateInfo) MAKE_OPEN_HANDLE(FunctionTemplate, FunctionTemplateInfo) MAKE_OPEN_HANDLE(ObjectTemplate, ObjectTemplateInfo) MAKE_OPEN_HANDLE(Signature, SignatureInfo) MAKE_OPEN_HANDLE(TypeSwitch, TypeSwitchInfo) MAKE_OPEN_HANDLE(Data, Object) MAKE_OPEN_HANDLE(RegExp, JSRegExp) MAKE_OPEN_HANDLE(Object, JSObject) MAKE_OPEN_HANDLE(Array, JSArray) MAKE_OPEN_HANDLE(String, String) MAKE_OPEN_HANDLE(Script, Object) MAKE_OPEN_HANDLE(Function, JSFunction) MAKE_OPEN_HANDLE(Message, JSObject) MAKE_OPEN_HANDLE(Context, Context) MAKE_OPEN_HANDLE(External, Foreign) MAKE_OPEN_HANDLE(StackTrace, JSArray) MAKE_OPEN_HANDLE(StackFrame, JSObject) #undef MAKE_OPEN_HANDLE
Utils::ToLocal:
#define MAKE_TO_LOCAL(Name, From, To) \ Local<v8::To> Utils::Name(v8::internal::Handle<v8::internal::From> obj) { \ ASSERT(obj.is_null() || !obj->IsTheHole()); \ return Local<To>(reinterpret_cast<To*>(obj.location())); \ } MAKE_TO_LOCAL(ToLocal, Context, Context) MAKE_TO_LOCAL(ToLocal, Object, Value) MAKE_TO_LOCAL(ToLocal, JSFunction, Function) MAKE_TO_LOCAL(ToLocal, String, String) MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp) MAKE_TO_LOCAL(ToLocal, JSObject, Object) MAKE_TO_LOCAL(ToLocal, JSArray, Array) MAKE_TO_LOCAL(ToLocal, Foreign, External) MAKE_TO_LOCAL(ToLocal, FunctionTemplateInfo, FunctionTemplate) MAKE_TO_LOCAL(ToLocal, ObjectTemplateInfo, ObjectTemplate) MAKE_TO_LOCAL(ToLocal, SignatureInfo, Signature) MAKE_TO_LOCAL(ToLocal, TypeSwitchInfo, TypeSwitch) MAKE_TO_LOCAL(MessageToLocal, Object, Message) MAKE_TO_LOCAL(StackTraceToLocal, JSArray, StackTrace) MAKE_TO_LOCAL(StackFrameToLocal, JSObject, StackFrame) MAKE_TO_LOCAL(NumberToLocal, Object, Number) MAKE_TO_LOCAL(IntegerToLocal, Object, Integer) MAKE_TO_LOCAL(Uint32ToLocal, Object, Uint32) #undef MAKE_TO_LOCAL
对于v8::String 和v8::internal::String来说宏展开后就是
OpenHandle:
v8::internal::Handle<v8::internal::String> Utils::OpenHandle(const v8::String* that) { return v8::internal::Handle<v8::internal::String>( reinterpret_cast<v8::internal::String**>(const_cast<v8::String*>(that))); }
ToLocal:
Local<v8::String> Utils::ToLocal(v8::internal::Handle<v8::internal::String> obj) { ASSERT(obj.is_null() || !obj->IsTheHole()); return Local<String>(reinterpret_cast<String*>(obj.location())); }
String的构建过程(samples/Shell.cc):
OS: Win7_IA32
v8的例子程序Shell.cc中可以用load来读取一个utf8编码的js文件,返回v8::String类型。
Js文件内容为:
//encoding: utf8 //filename: a.js var a="abc你好"; var b="gogogo"; function f() { print(a+b); } function fun() { print("just a test"); }
文件路径为d:\\a.js,在编译好的shell.exe中输入
load("d:\\a.js");
调用Load方法。
从utf8编码文件构造v8::String的过程:
1、v8::String::New()有2个重载函数,这里调用第一个
Local<String> v8::String::New(const char* data, int length);//char Local<String> v8::String::New(const uint16_t* data, int length);//wchar_t
2、v8::internal::Factory中有三种构建v8::internal::String的方法,char类型的v8::String::New()调用第二个
i::Handle<i::String> i::Factory::NewStringFromAscii(Vector<const char> string, PretenureFlag pretenure);//Ascii String i::Handle<i::String> i::Factory::NewStringFromUtf8(Vector<const char> string, PretenureFlag pretenure);//Utf8 String i::Handle<i::String> i::Factory::NewStringFromTwoByte(Vector<const uc16> string,PretenureFlag pretenure); //Wide String
3、i::Factory::NewStringFromUtf8()负责调用i::Heap::NewStringFromUtf8(),并将返回的i::MaybeObject*类型转换为i::Handle<i::String>类型
4、在i::Heap::NewStringFromUtf8()中先判断该字符串是否全部为ascii(c<128),全为ascii调用i::Heap::AllocateRawAsciiString(),否则调用i::Heap::AllocateStringFromUtf8Slow()。
5、全为ascii时i::Heap::AllocateStringFromAscii()调用i::Heap::AllocateRawAsciiString(),i::Heap::AllocateRawAsciiString()负责计算申请空间的长度,并调用i::Heap::AllocateRaw()申请空间,设置相应位后返回申请的指针;i::Heap::AllocateStringFromAscii()再调用i::SeqAsciiString::SeqAsciiStringSet()将ascii字符串复制到申请的空间里,每个字符占用1byte空间。
6、含有非ascii字符时i::Heap::AllocateStringFromUtf8Slow()调用i::Heap::AllocateRawTwoByteString(),i::Heap::AllocateRawTwoByteString()负责计算申请空间的长度,并调用i::Heap::AllocateRaw()申请空间,设置相应位后返回申请的指针;i::Heap::AllocateStringFromUtf8Slow()再调用i::String::Set()将字符串复制到申请的内存空间,所有字符均占用2byte空间。
PS. 1、申请内存大小的计算
//全Ascii字符串:调用i::SeqAsciiString::SizeFor()计算
//namespace v8::internal;
const int kPointerSizeLog2 = 2;//32-bit const int kObjectAlignmentBits = kPointerSizeLog2; const intptr_t kObjectAlignment = 1 << kObjectAlignmentBits; const intptr_t kObjectAlignmentMask = kObjectAlignment - 1; #define OBJECT_POINTER_ALIGN(value) (((value) + kObjectAlignmentMask) & ~kObjectAlignmentMask) const int kPointerSize = sizeof(void*); static const int Object::kHeaderSize = 0; static const int kMapOffset = Object::kHeaderSize; static const int HeapObject::kHeaderSize = kMapOffset + kPointerSize; static const int kLengthOffset = HeapObject::kHeaderSize; static const int kHashFieldOffset = kLengthOffset + kPointerSize; static const int String::kSize = kHashFieldOffset + kPointerSize; static const int kHeaderSize = String::kSize; const int kCharSize = sizeof(char);//=1, win32, ia32, vc //计算长度, OBJECT_POINTER_ALIGN宏使申请内存的长度按4对齐 static int SizeFor(int length) {//length ascii字符串长度 return OBJECT_POINTER_ALIGN(kHeaderSize + length * kCharSize); }
//还有非ascii时:调用i::SeqTwoByteString::SizeFor()计算 //内存对齐和计算kHeaderSize和上面相同,不同的是每个字符要占用2bytes const int kShortSize = sizeof(short);//=2, win32, ia32, vc static int SizeFor(int length) { return OBJECT_POINTER_ALIGN(kHeaderSize + length * kShortSize); }
2、对上面申请内存填充,对上面申请内存的相应部位进行填充
分别填充map,length(Smi),hashfield.
//ascii string,非全ascii string填充方法类似
MaybeObject* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) { ................................................. // Partially initialize the object. HeapObject::cast(result)->set_map_no_write_barrier(ascii_string_map()); String::cast(result)->set_length(length); String::cast(result)->set_hash_field(String::kEmptyHashField); ASSERT_EQ(size, HeapObject::cast(result)->Size()); return result; } const int kHeapObjectTag = 1; #define FIELD_ADDR(p, offset) (reinterpret_cast<byte*>(p) + offset - kHeapObjectTag) //?为什么要减1 #define WRITE_FIELD(p, offset, value) (*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value) static const int Object::kHeaderSize = 0; static const int kMapOffset = Object::kHeaderSize; void HeapObject::set_map_word(MapWord map_word) { WRITE_FIELD(this, kMapOffset, reinterpret_cast<Object*>(map_word.value_)); } void HeapObject::set_map_no_write_barrier(Map* value) { set_map_word(MapWord::FromMap(value)); } //其他填充过程类似