[tamarin系列之4] 构建专用的avmshell

    前的三章已经为我们介绍了tamarin和开源的flex-sdk的一些基本操作,本章我们将要更加深入地了解avmshell和asc编译器。 1、深入tamarin项目

     到目前为止,我们仔细看看我们的tamarin-tracing的目录结构,可能我们从来都没深入了解也注意到他里面的文件:

 |-- build               //  make后的编译版本 

     |-- Makefile |

     |-- core |

     |-- extensions |

     |-- nanojit |

     |-- pcre |

     |-- platform |

     |-- shell            // 前三章,我们一直在这里用./avmshell和java -jar asc.jar进行示例

     |-- space

 

 |-- tamarin-tracing    // tamarin源码工程

     |-- axscript

     |-- build

     |-- configure

     |-- configure.py

     |-- core            // 核心文件夹

     |-- esc            // esc的编译器,相对于asc

     |-- extensions

     |-- localization

     |-- manifest.mk

     |-- nanojit

     |-- pcre

     |-- platform        // 平台文件夹,win的项目文件在这里可以找到

     |-- shell            // shell文件夹

     |-- space        // mmgc项目文件夹

     |-- test

     |-- utils            // 工具文件夹

     `-- zlib

 

   结构大体如上,其中   tamarin-tracing/core是程序的核心项目部分,主要构建builtin.abc部分,也有资料写作global.abc

   tamarin-tracing/shell是shell项目部分,主要构建shell.abc,也有资料写作toplevel.abc

     关于global.abc和toplevel.abc的构建请参考redtamarin项目(http://code.google.com/p/redtamarin/)

   这是另一个不同于官方的tamarin实现。

 

     2、定制我们自己的tamarin

 

     大家是不是有一些头晕,tamarin就tamarin吧,怎么还有个redtamerin? 这是另一套完全不同的项目吗?

     其实,关于tamarin项目的结果,只是最终生成了avmshell这个可以运行虚拟机的shell。而shell究竟内容如何,主要靠core和shell这两大块。

   而core是核心,里面基本是雷打不动的代码,比较偏重虚拟机内的方法,如AS3的内建方法,而shell则是偏重于本地代码的实现,即不同平台上的shell的实现,类似AIR。

    两部分合在一起,构成了tamarin的avmshell。

    那么,我们完全可以自己制作一个属于自己的shell,或自己的Integrated Runtime环境,就像之前说的Yahoo!Widgets。

    Goole Code上实现的叫redtamarin,我们大可以自己作一个bluetamarin。或者My Integrated Runtime 或叫 MIR,以区别AIR。这是完全可行的。

     redtamarin在global.as中选用了

include "core\/builtin.as"

 include "core\/Math.as"

 include "core\/ErrorConstants.as"

 include "core\/Error.as"

 include "core\/RegExp.as"

 include "core\/Date.as"

include "core\/XML.as"

 

 编译成global.abc来代替官方的 tamarin-tracing/core下的builtin_full.abc 在toplevel.as中,用 include "shell\\toplevel.as" include "shell\\Domain.as" include "shell\\StringBuilder.as" include "shell\\ByteArray.as" include "shell\\IntArray.as" include "shell\\UIntArray.as" include "shell\\DoubleArray.as" include "shell\\FloatArray.as" include "shell\\ShortArray.as" include "shell\\UShortArray.as" include "shell\\Dictionary.as" include "shell\\Endian.as" include "shell\\Java.as" //RedTamarin include "shell\\standard.Errors.as" include "shell\\standard.Operations.as" include "shell\\standard.as"

编译成toplevel.abc代替了官方 tamarin-tracing/shell下的shell_full.abc,如此而已。

 

 3、创建自己的build版本,定制avmshell 如果真要按照redtamarin这样定制下来,你会发现,需要编译的地方很多,出错的地方更多。可能大家会觉得没有足够的知识和耐心是不能作到的。

 

   实际上呢,redtamarin已经是个趋向与成品的东西了,就是说它中间经历过的编译过程和产生的文件,事实上都被删掉了,只留下了最终的结果,所以你按照redtamarin编译是没法成功的。

   其实我们没有必要从头来定制,core和shell的大部分代码我们都是很需要的,我们只需要在上面加上我们需要的就可以了,而tamarin-tracing也提供了编译和定制的工具。 我们看 tamarin-tracing/core下面有一个builtin.py,这个文件可以编译一些头文件和abc文件或声明内容。

 

 1)它调用了forth语言编译器fc(在 tamarin-tracing/utils下),生成fpu和soft fp部分,关于forth语言,这里就不再赘述。

 2)它使用asc.jar下的macromedia.asc.embedding.ScriptCompiler而不是macromedia.asc.embedding.Main(java -jar asc.jar默认的是执行Main)。

     这个ScriptCompiler既可以编译abc又可以生成cpp和h文件,从而在make时进一步编译生成avmshell。

 

     同理在tamarin-tracing/shell下也有shell.py,这个文件编译shell相关的abc和头文件或声明内容。 (注意,在运行这两个python脚本后生成的builtin_full.h和shell_full.h有BUG,稍后我们会详细说明这个问题)

 

    我们通过修改源文件,并使用builtin.py和shell.py来快速地进行cpp和h文件的生成,然后新建空文件夹configure,再通过make就可以构建我们自己的avmshell了。

 

 4、初步实践 首先,我们在build/shell的目录下(还是我们经常测试的那个目录)制作testShell.as:

 import avmplus.*;

 System.alert("test alert");

 

编译java-jar asc.jar testShell.as testShell.abc, 100 bytes written

 

运行./avmshell testShell.abc 结果输出

 

 TypeError: Error #1006: alert is not a function.

         at global$init() avmshell运行提示并没有定义这个alert方法。

 

 事实上,shell里也没有这个alert方法。我们可以定义一个。在tamarin-tracing/shell/shell.as中

 package avmplus {

         public class System         {

                 public native static function exit(status:int):void

                 public native static function getAvmplusVersion():String

                 public native static function debugger():void

                 public native static function isDebugger():Boolean

                 public native static function getTimer():uint

                 public native static function readLine():String

         // 加入这个方法

         public static function alert(text:String):void                 {

                         // 方法体,自己定义

                        write(text);  

         }

 

然后编译这个shell的头文件 tamarin-tracing/shell/shell.py

输出 Building Full AS3 shell: 80361 Files: 18 Time: 2614ms

 

 BEFORE 80361

 AFTER  46010

SAVED  34351 43%

 

Building Min AS3 shell: 6504 Files: 6 Time: 836ms

BEFORE 6504

 AFTER  3281

 SAVED  3223 50%

 

然后新建一个build2目录去configure & make,

 mkdir build2 cd build2 ../tamarin-tracing/configure --enable-shell --enable-debugger make 你会发现,编译错误,这是个BUG。

 

解决方法是,修改shell_full.h,把所有以AVMPLUS_NATIVE_METHOD_DECL(Atom开头的宏命令都替换成AVMPLUS_NATIVE_METHOD_DECL(BoxReturnType

 

 比如AVMPLUS_NATIVE_METHOD_DECL(Atom, avmplus_Domain_private__load)替换为AVMPLUS_NATIVE_METHOD_DECL(BoxReturnType, avmplus_Domain_private__load)

 

好了,再make,就可以编译了然后,我们就在build2/shell下,得到了一个新的avmshell 我们有两个不同avmshell了,两个不同的shell环境,想不想搞几个不同的avmshell发行版呢,或者自己作一个特色的AIR出来?

 

 这时候,我们可以针对两个build环境分别测试:在build/shell下用./avmshell  testShell.abc 结果输出 TypeError: Error #1006: alert is not a function.

         at global$init()

 

    在build2/shell下用./avmshell testShell.abc

 

 结果输出 test alert 有些环境下的tamarin-tracing可能输出不出来结果,不过没关系用

./avmshell -Dastrace 1 testShell.abc

 结果输出

 87 AVMINF: MTHD global$init ()

88 AVMINF: MTHD Object$$cinit ()

88 AVMINF: MTHD Class$$cinit ()

90 AVMINF: MTHD Function$$cinit ()

90 AVMINF: MTHD Object$/private::_hideproto ()

160 AVMINF: MTHD Object$/private::init ()

161 AVMINF: MTHD Object$/private::_hideproto ()

 161 AVMINF: MTHD private::MethodClosure$$cinit ()

 164 AVMINF: MTHD Namespace$$cinit ()

164 AVMINF: MTHD Object$/private::_hideproto ()

165 AVMINF: MTHD QName$$cinit ()

165 AVMINF: MTHD Object$/private::_hideproto ()

 166 AVMINF: MTHD Boolean$$cinit ()

166 AVMINF: MTHD Object$/private::_hideproto ()

171 AVMINF: MTHD Number$$cinit ()

181 AVMINF: MTHD Object$/private::_hideproto ()

 183 AVMINF: MTHD int$$cinit ()

184 AVMINF: MTHD Object$/private::_hideproto ()

186 AVMINF: MTHD uint$$cinit ()

 206 AVMINF: MTHD Object$/private::_hideproto ()

218 AVMINF: MTHD String$$cinit ()

219 AVMINF: MTHD Object$/private::_hideproto ()

 232 AVMINF: MTHD Array$$cinit ()

233 AVMINF: MTHD Object$/private::_hideproto ()

236 AVMINF: MTHD private::FieldName$$cinit ()

236 AVMINF: MTHD private::StackFrame$$cinit ()

237 AVMINF: MTHD private::ArraySort$$cinit ()

286 AVMINF: MTHD global$init ()

286 AVMINF: MTHD global$init ()

286 AVMINF: MTHD avmplus::Domain$$cinit ()

 286 AVMINF: MTHD global/private::getfiles ()

286 AVMINF: MTHD global$init ()

 287 AVMINF: MTHD avmplus::System$$cinit ()

 287 AVMINF: MTHD avmplus::System$/private::getArgv ()

287 AVMINF: MTHD avmplus::File$$cinit ()

 287 AVMINF: MTHD flash.system::Capabilities$$cinit ()

 287 AVMINF: MTHD Array/get length ()

287 AVMINF: MTHD Array/http://adobe.com/AS3/2006/builtin::shift ()

 287 AVMINF: MTHD Array$/private::_shift ()

287 AVMINF: MTHD Array/get length ()

287 AVMINF: MTHD Array/set length ()

287 AVMINF: MTHD Array/private::_set_length ()

287 AVMINF: MTHD Array/http://adobe.com/AS3/2006/builtin::push ()

287 AVMINF: MTHD Array$/private::_push ()

287 AVMINF: MTHD Array/get length ()

 287 AVMINF: MTHD Array/get length ()

287 AVMINF: MTHD Array/set length ()

287 AVMINF: MTHD Array/private::_set_length ()

288 AVMINF: MTHD Array/get length ()

288 AVMINF: MTHD Array/get length ()

288 AVMINF: MTHD Array/get length ()

288 AVMINF: MTHD avmplus::Domain/load ()

288 AVMINF: MTHD avmplus::Domain/private::_readAndLoad ()

288 AVMINF: MTHD global$init ()

288 AVMINF: MTHD flash.utils::ByteArray$$cinit ()

288 AVMINF: MTHD flash.utils::ByteArray$/readFile ()

 288 AVMINF: MTHD global/_checkNull ()

 288 AVMINF: MTHD flash.utils::ByteArray$iinit ()

288 AVMINF: MTHD Object$iinit ()

289 AVMINF: MTHD global$init ()
289 AVMINF: MTHD avmplus::System$/alert ()

289 AVMINF: MTHD avmplus::System$/write ()

289 AVMINF: MTHD global/_checkNull () testShell

289 AVMINF: MTHD Array/get length ()

 

看这一行289 AVMINF: MTHD avmplus::System$/alert (),说明alert已经执行,并调用了

 

289 AVMINF: MTHD avmplus::System$/write ()

 

好了,今天的内容到此结束。 今天主要稍微简单地深入了一下tamarin的各部分构成,以及如何定制自己的avmshell。 接下来,我们要深入了解native这个本地代码关键字以及如何让AVM2虚拟机来执行外部的本地代码。

你可能感兴趣的:(虚拟机,Flex,Flash,AIR,FP)