打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
v8 知识点

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函数,并调用



本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
脚本引擎小PK: SpiderMonkey vs V8(二)
【项目实践】一文带你搞定Session和JWT的登录认证方式
谈谈协程和C语言的协程
基础类的DSP/BIOS API调用下
Windows核心编程(第五版)笔记 第三章 内核对象(Kernel Objects)
callback回调函数理解
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服