欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[tamarin系列之4] 构建专用的avmshell 博客分类: tamarin AIRFlash虚拟机FlexFP 

程序员文章站 2024-03-19 18:09:40
...

    前的三章已经为我们介绍了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虚拟机来执行外部的本地代码。