1.Handle结构
(1)API Handle(v8::handle):含有一个T*对象指针,(实际上是相应内部对象指针的指针)
(2)内部Handle(v8::internal::handle):T**内部对象指针的指针
2.相互转换:
(1)API Handle->内部Handle
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))
);
}
将API Handle中的API对象指针强制转化为内部对象指针的指针,创建内部Handle并返回
v8::internal::Handle<v8::internal::Object2> Utils::OpenHandle(* v8::Handle<v8::Object1>);
(2)内部Handle->API Handle
Local<v8::To> Utils::ToLocal(v8::internal::Handle<v8::internal::From> obj)
{
ASSERT(obj.is_null() || !obj->IsTheHole());
return Local<To>(reinterpret_cast<To*>(obj.location()));
}
将内部Handle中的内部对象指针的指针强制转化为API Handle中API对象指针,创建API Handle并返回
Local<v8::Object1> Utils::ToLocal(v8::internal::Handle<v8::internal::Object2>);
3.API Handle
(1)Local Handle(局部句柄)
(2)Persistent Handle(持久句柄)
Local Handle对应的内部对象指针会被放入HandleScope类中的Static HandleScopeData中,在HandleScope销毁的时候会恢复覆盖(清空)HandleScopeData,使得内部对象成为垃圾,被回收。而Persistent Handle对应的内部对象指针不放入Static HandleScopeData,内部对象指针的指针直接保存在Persistent Handle中,由用户自己销毁内部对象、释放内存。
4.API Handle的使用
函数调用:
(1)重载API Handle的->操作符,返回 API对象指针(内部对象指针的指针)
inline T* operator->() const { return val_; }
(2)OpenHandle转换为内部句柄
(3)重载内部Handle的->或者*操作符,返回内部对象指针
(4)开始调用
v8 HandleScope机制
1.概述
HandleScope其实就是一个HandleScopeData的备份。
HandleScopeData:内部对象指针的数组
2.HandleScope结构
(1)内部HandleScope
static v8::ImplementationUtilities::HandleScopeData current_;当前HandleScopeData
const v8::ImplementationUtilities::HandleScopeData previous_;备份
(2)API HandleScope
HandleScopeData previous_;备份
API HandleScope和内部HandleScope共用static HandleScopeData;
3.运行过程
创建API HandleScope时,备份当前static HandleScopeData到API HandleScope中的previous_。 之后创建的对象的指针放入static HandleScopeData中,当销毁(析构)API HandleScope时,恢复static HandleScopeData为之前的备份。清空了期间创建的对象的指针,由垃圾回收器回收对象。
内部HandleScope同理.
Context(上下文)运行时环境
1.概述
上下文(Context):即运行时环境Runtime(内建(自定义)的对象(函数))
每个v8::Context含有一个global(全局)ObjectTemplate对象
Context::Scope:表示进入Context
创建(1)保存顶层i::Context到i::HandleScopeImplementer
(2)设置顶层为当前Context
销毁:退出Context:恢复顶层i::Context
2.运行时环境的建立(v8.cc)
(1)Logger::Setup()
(2)CpuProfiler::Setup()
(3)HeapProfiler::Setup()
(4)OS::Setup()
(5)Heap::Setup()
MemoryAllocator内存分配器
static NewSpace new_space_;
static OldSpace* old_pointer_space_;
static OldSpace* old_data_space_;
static OldSpace* code_space_;
static MapSpace* map_space_;
static CellSpace* cell_space_;
static LargeObjectSpace* lo_space_;
static HeapState gc_state;
static Object* roots_[kRootListLength];//内建对象(指针)数组---全部内建对象
(6)Bootstrapper::Initialize()
(7)Builtins::Setup() :内建函数 (跳转到内建Code对象的机器指令)
(8)Top::Initialize()
(9)StubCache::Initialize()
(10)CPU::Setup()
(11)OProfileAgent::Initialize()
3.CodeStub对象(用于访问内建的Code对象)
(1)固定(Fixed)CodeStub
CEntryStub
| CEntry Code:同时存放在roots_[kCEntryCodeRootIndex]和
| roots_[kCodeStubsRootIndex]的NumberDictionary对象
JSEntryStub
| JSEntry Code:同时存放在roots_[kJsEntryCodeRootIndex]和
| roots_[kCodeStubsRootIndex]的NumberDictionary对象
JSConstructEntryStub
JSConstructEntry Code:同时存放在roots_[kJsConstructEntryCodeRootIndex]和 roots_[kCodeStubsRootIndex]的NumberDictionary对象
(2)其他Stub
4.Builtins类
static Object* builtins_[];//内建函数的Code对象数组
3类内建函数:(1)C++实现
(2)汇编实现
(3)汇编实现,用于debug
v8对象机制
1.概述
v8中每一个API对象都对应一个内部实现对象(堆对象)
2.对象创建过程
(1)v8::internal::Factory类:创建各种内部对象(v8::internal::)
(2)创建内部对象的内部Handle(v8::internal::Handle<T>),调用
i::Handle<T>::Handle(T* obj)->HandleScope::CreateHandle(obj);
把(T*内部对象指针)放入static HandleScopeData;
(3)把内部句柄转化为API Handle(v8::internal::T**->v8::T*),返回API Handle
---------------------------------------------------------------------------------------------------------------------------------
V8内部类继承层次
Object
| Smi (immediate small integer)
| Failure (immediate for marking failed operation)
| HeapObject (superclass for everything allocated in the heap)
| | JSObject
| | | JSArray
| | | JSRegExp
| | | JSFunction
| | | GlobalObject
| | | | JSGlobalObject
| | | | JSBuiltinsObject
| | | JSGlobalProxy
| | | JSValue
| | ByteArray
| | PixelArray
| | ExternalArray
| | | ExternalByteArray
| | | ExternalUnsignedByteArray
| | | ExternalShortArray
| | | ExternalUnsignedShortArray
| | | ExternalIntArray
| | | ExternalUnsignedIntArray
| | | ExternalFloatArray
| | FixedArray
| | | DescriptorArray
| | | HashTable
| | | | Dictionary
| | | | | StringDictionary
| | | | | NumberDictionary
| | | | SymbolTable
| | | | CompilationCacheTable
| | | | CodeCacheHashTable
| | | | MapCache
| | | Context
| | | JSFunctionResultCache
| | | SerializedScopeInfo
| | String
| | | SeqString
| | | | SeqAsciiString
| | | | SeqTwoByteString
| | | ConsString
| | | ExternalString
| | | | ExternalAsciiString
| | | | ExternalTwoByteString
| | HeapNumber
| | Code
| | Map
| | Oddball
| | Proxy
| | SharedFunctionInfo
| | Struct
| | | AccessorInfo
| | | AccessCheckInfo
| | | InterceptorInfo
| | | CallHandlerInfo
| | | TemplateInfo
| | | | FunctionTemplateInfo
| | | | ObjectTemplateInfo
| | | Script
| | | SignatureInfo
| | | TypeSwitchInfo
| | | DebugInfo
| | | BreakPointInfo
| | | CodeCache
v8编译过程(parser.cc文件)
1.创建编译环境MakeAST()
解析器AstBuildingParser parser->扫描器Scanner scanner_
扫描器结构: (1)TokenDesc current_
(2)TokenDesc next_
(3)缓冲 source_
2.语法分析(包含词法分析),创建抽象语法树(AST)FunctionLiteral-----(语句,声明,)
MakeAST()->ParseProgram()->ParseSourceElements():
进入while循环,每次解析一个JS语句
While(peek()!=end_token)
{
Statement* stat = ParseStatement(NULL, CHECK_OK);//解析一个语句
if (stat == NULL || stat->IsEmpty()) continue;//函数声明语句不放入FunctionLiteral
……
processor->Add(stat);//放入最外层FunctionLiteral的ZoneList
}
ParseStatement():解析一个语句
(1)根据下一个Token判断语句类型,并进入相应的语句解析函数
switch (peek()) //取下一个Token
{
case Token::LBRACE:
return ParseBlock(labels, ok); //{}Block语句
case Token::CONST:
case Token::VAR:
stmt = ParseVariableStatement(ok); //变量声明语句
break;
case Token::SEMICOLON:
Next();
return factory()->EmptyStatement(); //空语句
case Token::IF:
stmt = ParseIfStatement(labels, ok); //If语句
break;
case Token::DO:
stmt = ParseDoWhileStatement(labels, ok); //Do循环语句
break;
case Token::WHILE:
stmt = ParseWhileStatement(labels, ok); //While循环语句
break;
case Token::FOR:
stmt = ParseForStatement(labels, ok); //For循环语句
break;
case Token::CONTINUE:
stmt = ParseContinueStatement(ok); //Continue语句
break;
case Token::BREAK:
stmt = ParseBreakStatement(labels, ok); //Break语句
break;
case Token::RETURN:
stmt = ParseReturnStatement(ok); //返回语句
break;
case Token::WITH:
stmt = ParseWithStatement(labels, ok); //With语句??
break;
case Token::SWITCH:
stmt = ParseSwitchStatement(labels, ok); //Switch语句
break;
case Token::THROW:
stmt = ParseThrowStatement(ok); //Throw语句
break;
case Token::TRY:
{……} //Try语句
case Token::FUNCTION:
return ParseFunctionDeclaration(ok); //函数声明语句
case Token::NATIVE:
return ParseNativeDeclaration(ok);
case Token::DEBUGGER:
stmt = ParseDebuggerStatement(ok); //Debugger语句
break;
default: stmt = ParseExpressionOrLabelledStatement(labels, ok);//其他语句(表达式/标号)
}
(2)解析语句
首先,调用扫描器Scanner(对JS源码进行词法分析):每次扫描Scan()得到当前Token和下一个Token,把Token描述信息分别放入TokenDesc current_和 TokenDesc next_中,把Token的值放入缓冲source_中.
其次,根据JS的语法语义进行相应(编译时)处理
最后,
-1-一般(非声明)语句:创建Statement对象,放入FunctionLiteral对象中ZoneList<Statement*>.
-2-变量声明语句:创建Declaration对象放入当前抽象语法树FunctionLiteral的Scope的decls_,
再由CallRuntime语句创建ExpressionStatement对象,放入body_ (JS语句 数组)
-3-函数声明语句:根据函数体创建新的抽象语法树FunctionLiteral,放入新创建的
Declaration对象,再放入当前抽象语法树FunctionLiteral的Scope的 decls_.
解析完所有语句后,得到抽象语法树FunctionLiteral。
附:
抽象语法树4种结点:Statement(语句),Expression(表达式),Declaration(声明)和TargetCollector
---------------------------------------------------------------------------------------------------------------------------------
抽象语法树FunctionLiteral结构
1.ZoneList<Statement*> body_ JS语句数组
2.Scope* scope_
(1)ZoneList<Declaration*> decls_ 变量、函数声明数组(Declaration对象数组)
(2)……….
3.……
---------------------------------------------------------------------------------------------------------------------------------
抽象语法树FunctionLiteral结点的继承层次
ZoneObject
| AstNode
| | Statement
| | | BreakableStatement
| | | | Block
| | | | IterationStatement
| | | | | DoWhileStatement
| | | | | WhileStatement
| | | | | ForStatement
| | | | | ForInstatement
| | | | SwitchStatement
| | | ExpressionStatement
| | | ContinueStatement
| | | BreakStatement
| | | ReturnStatement
| | | WithEnterStatement
| | | WithExitStatement
| | | IfStatement
| | | TryStatement
| | | | TryCatchStatement
| | | | TryFinallyStatement
| | | DebuggerStatement
| | | EmptyStatement
| | Expression (会被转化为ExpressionStatement)
| | | ValidLeftHandSideSentinel
| | | Literal
| | | MaterializedLiteral
| | | | ObjectLiteral
| | | | RegExpLiteral
| | | | ArrayLiteral
| | | CatchExtensionObject
| | | VariableProxy
| | | | VariableProxySentinel
| | | Slot
| | | Property
| | | Call
| | | CallNew
| | | CallRuntime
| | | UnaryOperation
| | | BinaryOperation
| | | CountOperation
| | | CompareOperation
| | | Conditional
| | | Assignment
| | | Throw
| | | FunctionLiteral
| | | ShareFunctionInfoLiteral
| | | ThisFunction
| | Declaration
| | TargetCollector
| CaseClause
v8汇编过程
根据抽象语法树FunctionLiteral创建Code对象(内含机器指令),返回JSFunction对象.
MakeCode():
1.增加返回语句: Rewriter::Process(FunctionLiteral) 向抽象语法树的语句数 组Body_添加ReturnStatement(返回语句)
2.优化AST: Rewriter::Optimize(FunctionLiteral)优化抽象语法树
3.产生机器码(机器指令)
1.创建代码产生器FullCodeGenerator(AstVisitor的子类 ):
内含汇编器MacroAssembler(根据硬件架构宏来选择相应的汇编器对象).
v8目前支持4个硬件架构: V8_TARGET_ARCH_IA32
V8_TARGET_ARCH_X84
V8_TARGET_ARCH_ARM
V8_TARGET_ARCH_MIPS
2.调用FullCodeGenerator::Generate(CompilationInfo*,Mode)开始汇编
(1)代码产生器访问AST ,根据语义调用汇编器(MacroAssembler)产生相应的机器指令并放入汇编器的缓冲区.
共有5个步骤:
---- 若Mode为PRIMARY,则 Allocate locals
Allocate local context
Allocate arguments object
----Declarations:汇编抽象语法树的Scope中变量和函数声明对象(ZoneList<Declaration*>)
---- Stack check:汇编栈检验语句
---- Body:汇编非声明语句(语句数组的所有语句)
---- return:汇编返回语句
(2)创建一个CodeDesc对象描述产生的机器指令,再创建Code对象Factory::NewCode(….)
struct CodeDesc { byte* buffer; //缓冲地址
int buffer_size; //缓冲大小
int instr_size; //指令总长度
int reloc_size; //重定位信息长度
Assembler* origin; //汇编器
};
|<--------------- buffer_size ---------------->|
|<-- instr_size -->| |<-- reloc_size -->|
+==================+========+==================+
机器指令缓冲 | instructions | free | reloc info |
+==================+========+==================+
4.结尾操作
根据 抽象语法树FunctionLiteral+Code+CompilationInfo创建SharedFunctionInfo ,
再创建JSFunction对象,Handle<JSFunction>转化为API Handle<Script>,返回
v8执行过程
JS源码经过v8编译后得到Handle<Script>,调用API Script的Run()运行。
(1)由API进入v8内部,取到JSFunction对象: API Handle<Script>转换为Handle<JSFunction>,得到JSFunction对象
(2)通过(动态)内建JSEntry Code对象的入口函数调用目标机器指令:
通过JSEntryStub获得内建的JSEntry Code对象(含有内建入口函数的机器指令),再得到其JS入口函数地址(第一条机器指令的地址) , 调用入口函数 , 同时将(JS源码编译后生成的)JSFunction中的Code对象的入口函数地址作为参数.
JSEntryFunction entry = FUNCTION_CAST<JSEntryFunction>(code->entry());//内建入口函数地址
// Call the function through the right JS entry stub.
byte* entry_address = func->code()->entry();
JSFunction* function = *func;
Object* receiver_pointer = *receiver;
//跳到运行时动态产生的JS入口函数机器指令处执行,随后跳到动态产生的目标机器指令处
entry(entry_address, function,receiver_pointer, argc, args);
v8 中JS与C++互调
**************************v8中JS调C++:注册回调函数*****************************
JS调C++数据:访问器(Accessor) (直接访问)
(1)定义C++回调函数Getter/Setter
(2)Context全局对象模板(ObjectTemplate)注册Getter/Setter
JS调C++函数:(Context)全局对象模板ObjectTemplate注册回调函数(通过v8::Arguments传递参数)
Template::Set(Handle<String> name, Handle<Data> value,PropertyAttribute attributes = None);
JS调C++对象:(通过CPPObj.XXX访问)
1.C++对象映射成(v8_API)JS对象,加入JS运行时环境(Context): C++类映射成ObjectTemplate对象
(1)创建JS对象模板ObjectTemplate:
Handle<ObjectTemplate> JSObjTempl = ObjectTemplate::New();
(2)设置对象模板内部域:
JSObjTempl->SetInternalFieldCount(1);
(3)创建JS对象:
Local<Object> JSObj=JSObjTempl->NewInstance();
(3)C++对象包装成(External)外部对象,放入JS对象内部域:
ClassA* p=new ClassA(3,7);
Local<External> Ext=External::New(p);
JSObj->SetInternalField(0,Ext);
(4)JS对象放入运行时环境(全局对象)
context->Global()->Set(String::New("ClassA"),JSObj);
2.调C++对象的成员数据:JS对象模板注册Getter/Setter回调函数
JSObjTempl->SetAccessor(String::New("x"),GetCPPObj_X,SetCPPObj_X);
JSObjTempl->SetAccessor(String::New("y"),GetCPPObj_Y,SetCPPObj_Y);
3.调C++对象的成员函数:JS对象模板注册回调函数,通过回调函数调用成员函数
JSObjTempl->Set(String::New("method_a"), FunctionTemplate::New(Callback_A));
JSObjTempl->Set(String::New("method_b"), FunctionTemplate::New(Callback_B));
回调函数:(1)(当前调用)JS对象:
Local<Object> self = AccessorInfo.Holder()/Arguments.Holder();
(2)(包装后)外部对象:
Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
(3)C++对象
CPPObj* p = static_cast<CPPObj*>(wrap->Value())
**********************************C++调JS**************************************
C++调JS函数:运行时环境查找JS函数,并调用