移植前的准备:
准备工作最起码要做三件事情:
1、完全理解微软的脚本引擎规范;
2、完全满足Jscript的现有功能特性;
3、完全掌握V8的架构和使用过程。
理解微软的脚本引擎规范
众所周知,微软产品的每个角落都充斥着COM,脚本引擎也不例外。一个合格的脚本引擎必须首先是一个COM组件,并实现下表中列出的标准接口:
IActiveScript – 这个接口是必须的,所有脚本引擎都应该实现这个接口,它负责维护脚本引擎的状态机,以及报告脚本执行状态。
IActiveScriptParse – 这个接口也是必须的,脚本代码执行之前的解析过程必须由它来完成。
IActiveScriptParseProcedure2 – 这个接口可选,但如果脚本引擎被IE浏览器使用的话,则是必须的。嵌入到HTML标签中的事件处理脚本代码片段的解析需要这个接口,CSS中的脚本表达式也需要它。
IActiveScriptProperty – 这个接口可选。用来让客户端设置或者检索某些属性。
IActiveScriptStats – 这个接口可选。对于异步控制脚本代码执行是有用的,如果某个脚本代码执行时间很长,使用这个接口能向客户端报告当前脚本的执行进度,IE通常使用它来提示用户后台执行周期过长,并接受用户选择以终止脚本执行。在我的脚步引擎实现中并未实现这个接口。
IObjectSafety – 这个接口可选,但如果脚本引擎被IE浏览器使用的话,则是必须的,IE利用它来设置或检索某些安全属性。
还有很多可选的接口,例如用于脚本的调试和单步执行、查看调用栈、查看当前变量值、报告异常等等功能,有些功能我没有实现,有些功能由于V8本身的限制暂时无法实现,但不影响引擎的使用。
除了要实现的接口,实现规范的脚本引擎还必须关注一些额外的事情。
状态机和状态的迁移。
熟悉COM的人都知道,COM组件跟线程关系密切,对线程异常敏感,在COM术语中叫做线程套间。通常实现一个COM组件就意味着这个组件已经限定了自己的套间类型,或者是STA,或者是MTA。但脚本引擎组件是一个非常非常特殊的组件类型。
由于状态机的存在,不同状态下脚本引擎组件必须使用不同的套间类型,而且不同状态下引擎能做的事情也是不同的。这点理解起来有点困难,后面会稍做解释。
在现阶段的脚本引擎规范中只定义了6种状态,对于一个刚刚创建的引擎组件,它的状态是“未初始化”,在这种状态下,引擎唯一能做的事情就是绑定到客户端,同时它是一个自由线程组件(MTA),能被任意线程使用。
一旦客户端绑定到引擎组件上,它的状态就变成了“已初始化”。在这种状态下,引擎可以开始解析脚本代码了,而且组件变成了STA和MTA之间的一种特殊的套间状态。这种特殊套间的含义就是:某些组件方法开始对线程敏感,只能用于STA,某些组件方法仍然对线程不敏感,可以被MTA中的其它线程直接调用。
当状态机迁移到“已启动”状态时,所有已解析的脚本代码开始执行,而且后续注入的脚本代码将在解析之后立即执行,不再内部排队。从进入这个状态开始,整个脚本引擎组件已经是一个完完全全的STA组件,所有方法都对线程敏感。
在状态机进入“已启动”状态之后,可以随时命令引擎进入“已关闭”状态。在这种状态下,引擎组件永久失效,不能再执行任何脚本代码,也不能恢复到“已启动”或者“已连接”状态,唯一能做的就是释放引擎组件。
在“已启动”状态之上还有两个状态,“已连接”和“未连接”,通常情况下这两种状态可以不使用,因为连接代表引擎将自动连接到命名项的连接点,来接收任何对象事件。