v8javascriptengine的使用方法研究.docx
V8JAVASCRIPTENGINE的使用方法研究第一节一、写在前面的话随着GOOGLEIO大会上对ANDROID22系统展示,一个经过高度优化的ANDROID系统(从DALVIK虚拟机,到浏览器)呈现在大家面前。开发者们会非常自然地将目光落在DALVIK虚拟机方面的改进(包括NDK工具对JNI联机单步调试的支持),很多应用接口的调整以及以此为基础的新的应用程序(偶是属于那种喜新不厌旧,找抽性质的人)。对于ANDROID22在浏览器方面的优化和改进,在GOOGLEIO大会上只提到了已经全面支持V8JAVASCRIPT引擎,这种引擎会将浏览器的运行速度提升2-3倍(尽管FIREFOX已经官方发表声明说他们在未来的FIREFOX中会使用一个叫做TRACEMONKEY的JAVASCRIPT引擎,它要比V8更快,但目前来看V8引擎是所有现存JAVASCRIPT引擎中最快的)。HOHO,好东西嘛,自然少不了偶了,下面偶就把自己对V8引擎的一些使用方面的心得体会简单地写一下,希望能够对游戏开发者或者应用程序引擎开发者有一些用处。(稍微表达一下对GOOGLE的意见,虽然ANDROID22已经正式发布了,但SOURCECODE还没有发布出来,偶等得花儿都谢了。)二、V8引擎特性简介V8引擎的最根本的特性就是运行效率非常高,这得益于V8与众不同的设计。从技术角度来看,V8的设计主要有三个比较特别的地方(1)快速对象属性存取机制JAVASCRIPT这语言很邪门,很不规范,但是动态特性很高,甚至可以在运行时增加或减少对象的属性,传统的JAVASCRIPT引擎对于对象属性存取机制的实现方法是为运行中的对象建立一个属性字典,然后每次在脚本中存取对象属性的时候,就去查这个字典,查到了就直接存取,查不到就新建一个属性。如此设计虽然很方便,但是很多时间都浪费到这个“查字典”的工作上了。而V8则采取另外一种方式HIDDENCLASS(隐藏类偶怕翻译得不贴切因此直接把原文写上来了)链的方式,在脚本中每次为对象添加一个新的属性的时候,就以上一个HIDDENCLASS为父类,创建一个具有新属性的HIDDENCLASS的子类,如此往复递归进行,而且上述操作只在该对象第一次创建的时候进行一次,以后再遇到相同对象的时候,直接把最终版本的HIDDENCLASS子类拿来用就是了,不用维护一个属性字典,也不用重复创建。这样的设计体现了GOOGLE里面天才工程师们的才华(当然第一次运行的时候肯定要慢一些,所以GOOGLE那边强调,V8引擎在多重循环,以及重复操作一些对象的时候速度改善尤为明显,大概这种设计也是其中的一个原因吧,当然最主要的原因还在动态机器码生成机制)(2)动态机器码生成机制这一点可以类比一下JAVA虚拟机里面的JIT(JUSTINTIME)机制,地球人都知道,JAVA的运行效率很低,尤其在使用多重循环(也就是,FOR循环里面还有个FOR循环里面还有FOR循环//创建OBJECTTEMPLATE对象,这个对象可以用来注册C的全局函数供给JAVASCRIPT调用//在此演示中先可以忽略HANDLEGLOBAL_TEMPLOBJECTTEMPLATENEW//创建运行环境HANDLEC_CONTEXT//创建JAVASCRIPT脚本的存储对象,该对象存放从文件中读取的脚本字符串HANDLEJS_SOURCE//创建用于存放编译后的脚本代码的对想HANDLEJS_COMPILED//从文件中把JAVASCRIPT脚本读入JS_SOURCE对象JS_SOURCELOAD_JSJS_FNAME//把C编写的函数注册到全局的OBJECTTEMPLATE对象中,//例如,在偶的代码中,有一个叫做SET_DRAW_COLOR的函数,那么这个函数在JAVASCRIPT脚本//中如果希望调用,应该叫什么名字呢这一句STRINGNEW“SET_DRAW_COLOR“就用来指定//在脚本中的函数名称,FUNCTIONTEMPLATE用来表示在C中的函数,利用指向函数的指针把该函数//封装成函数对象。以下的几个SET都是相同的功能,就是用来把C函数注册到脚本的运行环境中。GLOBAL_TEMPLSETSTRINGNEW“SET_DRAW_COLOR“,FUNCTIONTEMPLATENEWSET_DRAW_COLORGLOBAL_TEMPLSETSTRINGNEW“DRAW_LINE“,FUNCTIONTEMPLATENEWDRAW_LINEGLOBAL_TEMPLSETSTRINGNEW“COMMIT“,FUNCTIONTEMPLATENEWCOMMITGLOBAL_TEMPLSETSTRINGNEW“CLEAR“,FUNCTIONTEMPLATENEWCLEARGLOBAL_TEMPLSETSTRINGNEW“DRAW_BMP“,FUNCTIONTEMPLATENEWDRAW_BMP//新建执行对象,把刚刚注册了C函数的GLOBAL_TEMPL关联到脚本的运行环境中去C_CONTEXTCONTEXTNEWNULL,GLOBAL_TEMPL//创建运行环境的作用域,当然,言外之意,V8可以支持多个配置不同的运行环境CONTEXTSCOPECONTEXT_SCOPEC_CONTEXT//注意,这里就是编译JAVASCRIPT脚本的源代码了JS_COMPILEDSCRIPTCOMPILEJS_SOURCEIFJS_COMPILEDISEMPTY{LOG“RUN_JS,JS_COMPILEDISEMPTY“RETURN}//最后这一句就是运行,执行刚刚从文件中载入以及编译的JAVASCRIPT脚本了JS_COMPILEDRUN(4)由JAVASCRIPT调用的C模块的编写方法以刚刚的SET_DRAW_COLOR这个函数为例,在JAVASCRIPT中的调用方法假定为SET_DRAW_COLORR,G,B例如//设置为红色SET_DRAW_COLOR255,0,0虽然调用此函数看上去非常简单,但在C中该如何编写这个函数呢该如何从JAVASCRIPT中得到相应的行参呢参见如下代码STATICHANDLESET_DRAW_COLORCONSTARGUMENTSIFARGSLENGTH3{RARGS0INT32VALUEGARGS1INT32VALUEBARGS2INT32VALUEG_CANV_PTRSETDRAWCOLORR,G,B}RETURNUNDEFINED}这里的CONSTARGUMENTSCOMMIT}先不论具体的实现细节,先看这个函数的参数,X和Y,那么偶该如何从C代码中把鼠标点按的X和Y坐标传给ONCLICK函数呢毕竟这个函数是在JAVASCRIPT中定义的。具体的方法其实很简单,前半部分与定义和调用JAVASCRIPT的步骤一致,只不过从JS_COMPILEDRUN,这一句以后,还没有完,还要继续做下面的事情HANDLEJS_FUNC_NAMEHANDLEJS_FUNC_VALHANDLEJS_FUNCHANDLEARGVARGCHANDLEINT_XHANDLEINT_Y//这一句是创建函数名对象JS_FUNC_NAMESTR