- 浏览: 3009368 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (430)
- Programming Languages (23)
- Compiler (20)
- Virtual Machine (57)
- Garbage Collection (4)
- HotSpot VM (26)
- Mono (2)
- SSCLI Rotor (1)
- Harmony (0)
- DLR (19)
- Ruby (28)
- C# (38)
- F# (3)
- Haskell (0)
- Scheme (1)
- Regular Expression (5)
- Python (4)
- ECMAScript (2)
- JavaScript (18)
- ActionScript (7)
- Squirrel (2)
- C (6)
- C++ (10)
- D (2)
- .NET (13)
- Java (86)
- Scala (1)
- Groovy (3)
- Optimization (6)
- Data Structure and Algorithm (3)
- Books (4)
- WPF (1)
- Game Engines (7)
- 吉里吉里 (12)
- UML (1)
- Reverse Engineering (11)
- NSIS (4)
- Utilities (3)
- Design Patterns (1)
- Visual Studio (9)
- Windows 7 (3)
- x86 Assembler (1)
- Android (2)
- School Assignment / Test (6)
- Anti-virus (1)
- REST (1)
- Profiling (1)
- misc (39)
- NetOA (12)
- rant (6)
- anime (5)
- Links (12)
- CLR (7)
- GC (1)
- OpenJDK (2)
- JVM (4)
- KVM (0)
- Rhino (1)
- LINQ (2)
- JScript (0)
- Nashorn (0)
- Dalvik (1)
- DTrace (0)
- LLVM (0)
- MSIL (0)
最新评论
-
mldxs:
虽然很多还是看不懂,写的很好!
虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 -
HanyuKing:
Java的多维数组 -
funnyone:
Java 8的default method与method resolution -
ljs_nogard:
Xamarin workbook - .Net Core 中不 ...
LINQ的恶搞…… -
txm119161336:
allocatestlye1 顺序为 // Fields o ...
最近做的两次Java/JVM分享的概要
(那个……我没读过中文版的ActionScript 3文档,不知道标准文档里翻译用了哪些词。凑合吧)
使用过ActionScript 3(AS3)的人应该会注意到其中的可选类型标注。在声明变量或常量时,可以有选择的在变量名之后加上冒号和类型名,像这样:
在编译的时候,可以选择使用标准模式(standard mode)和严格模式(strict mode)来编译,默认为标准模式。
ECMAScript 4(ES4)接受了AS3的这个设计,也提出相同的类型标注和两种编译模式。
在ES4的文档wiki,Strict and Standard compilation modes中特别提到,严格模式并不改变程序的语义,而只是对变量进行静态的类型检查,以杜绝一些常见的类型相关错误,例如对未声明的变量赋值,或者调用函数是给的参数的个数不正确等。
换句话说,AS3/ES4中的类型标注并不意味着更高的执行效率;在纯动态的解释器实现中,严格模式可能反而更慢(因为要做更多的动态检查来保证类型的正确性)。
Adobe在许多产品里都附带有AS3的编译器。我使用的是与Flex 3 SDK一起发布的,asc.jar,在Flex3SDK/lib目录下能找到。
直接用asc.jar来编译*.as源文件时,默认得到的是*.abc(Adobe ByteCode)文件,也就是对应AVM2(Adobe Virtual Machine 2,Flash 9/Flex 2/Flex 3/AIR所使用的虚拟机)的字节码。
在AVM2的指令集中,算术运算相关的指令都有专门针对整型的版本。例如add指令有相应的add_i版本。不过单是add指令本身的语义就很复杂了:
而add_i指令的语义相对简单些:
注意到,add_i指令并没有要求其操作数(栈顶的两个对象)是int型,而特别提到该指令的语义是用ToInt32算法将这两个对象转换到int。虽然如此,在将两个int型变量相加时,add_i执行的效率也应该比add指令好一些吧。
但实际上Adobe提供的AS3编译器会为我们编译出怎样的代码呢?让我们来看看下面的AS3代码,以严格模式编译会怎样:
(在命令行用java -jar asc.jar -import builtin.abc -import toplevel.abc -m -strict test.as编译)
test.as:
这里,我定义了几个方法,内容本质上都一样,都是使用+运算符把两个操作数“加”起来。但是其中foo()有完整的类型标注,包括参数和返回类型都标注上了;goo()完全没有类型标注;hoo()只有第二个参数做了类型标注;ioo()没有标注返回类型,局部变量也没有标注类型;joo()在ioo()的基础上标注了局部变量的类型。
编译时使用了-m参数,得到编译结果的文字表示test.il。其内容太长,就不完整贴出来了。下面的中间代码都出自test.il。
于是让我们把这几个方法分析一下。
首先是foo()。编译器为其生成的方法信息是:
稍微解释一下。根据ABC(Adobe ByteCode)文件的格式定义,用于描述方法的signature的method_info数据结构如下:
其中return_type与param_type里都是对multiname数组的索引。如果为0则意味着类型是“*”,也就是AS3的严格模式中的任意类型。
也就是说,编译器正确的识别出了foo()的两个参数类型都是int,返回类型也是int。
foo()的方法体部分编译结果如下:
可以看到,编译器在知道两个参数都是int型的前提下,仍然为运算符“+”选择了add而不是add_i指令。
另外几个方法编译出来的到的method_info分别为:
goo():
hoo():
ioo():
joo():
可以看到,编译器生成的method_info中关于类型的描述完全取决于代码中的标注;没有被标注的方法和变量一律被认为是“*”也就是任意类型;即便编译器有足够的信息区推导出其中的一些类型。
特别看一下ioo()中的状况:
它与foo()最大的不同是,在两个参数被add之后,还对结果做了一次隐式类型转换到Object类型(coerce_o)。虽然编译器可以通过类型标注合理的推断出局部变量i也应该是int类型的,但却并没有这么做,而是继续将i看作“*”类型。
总的说来,AS3的可选类型标注的意义仅仅在于:
1、为编辑器提供更好的支持,使其容易实现高质量的智能感应(打个点能出现成员列表之类);
2、为编译器提供静态的类型检查的依据,尽量早的将类型错误报告给用户;有标注的就检查,没标注的就不检查;不能对未声明的变量赋值(而不像ES3或之前的版本,可以直接对未声明的变量赋值,赋值时自动创建出新的变量)。
至于运行效率,严格模式与标准模式编译出来的东西似乎没多少区别……并没有生成出更快的代码,不过至少也没有变得比标准模式更慢。
我的结论是否与现实状况有出入,这个有待进一步探究。Flex 3的asc.jar没有进行类型推导这点应该是没错的。
===================================================================================
但是值得一提的是,新版本的AVM2(Tamarin)正在试验所谓的Tracing-JIT,可以有效的减少动态类型检查带来的额外开销。无论是以标准模式还是以严格模式编译的AS3代码都能从中获益。或许的Adobe的策略就是:“反正后面有Tracing-JIT,即便编译器前端不做类型推导也没关系”,吧?
使用过ActionScript 3(AS3)的人应该会注意到其中的可选类型标注。在声明变量或常量时,可以有选择的在变量名之后加上冒号和类型名,像这样:
var myvar : Number;
在编译的时候,可以选择使用标准模式(standard mode)和严格模式(strict mode)来编译,默认为标准模式。
ECMAScript 4(ES4)接受了AS3的这个设计,也提出相同的类型标注和两种编译模式。
在ES4的文档wiki,Strict and Standard compilation modes中特别提到,严格模式并不改变程序的语义,而只是对变量进行静态的类型检查,以杜绝一些常见的类型相关错误,例如对未声明的变量赋值,或者调用函数是给的参数的个数不正确等。
引用
In order to specify the two modes’ runtime behavior consistently, we specify the dynamic semantics of ECMAScript in a single, unified, dynamically typed language. In other words, the choice of strict or standard mode does not affect the meaning of a legal program; it only affects the definition of “legality”.
...
...Strict mode is only meant as a way for programmers to indicate their desire for more extensive and conservative error analysis. All programs, regardless of mode, must execute as though they were performing all dynamic checks.
...
...Strict mode is only meant as a way for programmers to indicate their desire for more extensive and conservative error analysis. All programs, regardless of mode, must execute as though they were performing all dynamic checks.
换句话说,AS3/ES4中的类型标注并不意味着更高的执行效率;在纯动态的解释器实现中,严格模式可能反而更慢(因为要做更多的动态检查来保证类型的正确性)。
Adobe在许多产品里都附带有AS3的编译器。我使用的是与Flex 3 SDK一起发布的,asc.jar,在Flex3SDK/lib目录下能找到。
直接用asc.jar来编译*.as源文件时,默认得到的是*.abc(Adobe ByteCode)文件,也就是对应AVM2(Adobe Virtual Machine 2,Flash 9/Flex 2/Flex 3/AIR所使用的虚拟机)的字节码。
在AVM2的指令集中,算术运算相关的指令都有专门针对整型的版本。例如add指令有相应的add_i版本。不过单是add指令本身的语义就很复杂了:
ActionScript Virtual Machine 2 (AVM2) Overview 写道
add
Operation
Add two values.
Format
add
Forms
add = 160 (0xa0)
Stack
…, value1, value2 => …, value3
Description
Pop value1 and value2 off of the stack and add them together as specified in ECMA-262 section 11.6 and as extended in ECMA-357 section 11.4. The algorithm is briefly described below.
1. If value1 and value2 are both Numbers, then set value3 to the result of adding the two number values. See ECMA-262 section 11.6.3 for a description of adding number values.
2. If value1 or value2 is a String or a Date, convert both values to String using the ToString algorithm described in ECMA-262 section 9.8. Concatenate the string value of value2 to the string value of value1 and set value3 to the new concatenated String.
3. If value1 and value2 are both of type XML or XMLList, construct a new XMLList object, then call [[Append]](value1), and then [[Append]](value2). Set value3 to the new XMLList.
See ECMA-357 section 9.2.1.6 for a description of the [[Append]] method.
4. If none of the above apply, convert value1 and value2 to primitives. This is done by calling ToPrimitive with no hint. This results in value1_primitive and value2_primitive. If value1_primitive or value2_primitive is a String then convert both to Strings using the ToString algorithm (ECMA-262 section 9.8), concatenate the results, and set value3 to the concatenated String. Otherwise convert both to Numbers using the ToNumber algorithm (ECMA-262 section 9.3), add the results, and set value3 to the result of the addition.
Push value3 onto the stack.
Notes
For more information, see ECMA-262 section 11.6 (“Additive Operators”) and ECMA-357 section 11.4.
Operation
Add two values.
Format
add
Forms
add = 160 (0xa0)
Stack
…, value1, value2 => …, value3
Description
Pop value1 and value2 off of the stack and add them together as specified in ECMA-262 section 11.6 and as extended in ECMA-357 section 11.4. The algorithm is briefly described below.
1. If value1 and value2 are both Numbers, then set value3 to the result of adding the two number values. See ECMA-262 section 11.6.3 for a description of adding number values.
2. If value1 or value2 is a String or a Date, convert both values to String using the ToString algorithm described in ECMA-262 section 9.8. Concatenate the string value of value2 to the string value of value1 and set value3 to the new concatenated String.
3. If value1 and value2 are both of type XML or XMLList, construct a new XMLList object, then call [[Append]](value1), and then [[Append]](value2). Set value3 to the new XMLList.
See ECMA-357 section 9.2.1.6 for a description of the [[Append]] method.
4. If none of the above apply, convert value1 and value2 to primitives. This is done by calling ToPrimitive with no hint. This results in value1_primitive and value2_primitive. If value1_primitive or value2_primitive is a String then convert both to Strings using the ToString algorithm (ECMA-262 section 9.8), concatenate the results, and set value3 to the concatenated String. Otherwise convert both to Numbers using the ToNumber algorithm (ECMA-262 section 9.3), add the results, and set value3 to the result of the addition.
Push value3 onto the stack.
Notes
For more information, see ECMA-262 section 11.6 (“Additive Operators”) and ECMA-357 section 11.4.
而add_i指令的语义相对简单些:
ActionScript Virtual Machine 2 (AVM2) Overview 写道
add_i
Operation
Add two integer values.
Format
add_i
Forms
add_i = 197 (0xc5)
Stack
…, value1, value2 => …, value3
Description
Pop value1 and value2 off of the stack and convert them to int values using the ToInt32 algorithm (ECMA-262 section 9.5). Add the two int values and push the result onto the stack.
Operation
Add two integer values.
Format
add_i
Forms
add_i = 197 (0xc5)
Stack
…, value1, value2 => …, value3
Description
Pop value1 and value2 off of the stack and convert them to int values using the ToInt32 algorithm (ECMA-262 section 9.5). Add the two int values and push the result onto the stack.
注意到,add_i指令并没有要求其操作数(栈顶的两个对象)是int型,而特别提到该指令的语义是用ToInt32算法将这两个对象转换到int。虽然如此,在将两个int型变量相加时,add_i执行的效率也应该比add指令好一些吧。
但实际上Adobe提供的AS3编译器会为我们编译出怎样的代码呢?让我们来看看下面的AS3代码,以严格模式编译会怎样:
(在命令行用java -jar asc.jar -import builtin.abc -import toplevel.abc -m -strict test.as编译)
test.as:
package { class TestClass { function foo(x : int, y : int) : int { return x + y; } function goo(x, y) { return foo(x, y); } function hoo(x, y : String) { return x + y; } function ioo(x : int, y : int) { var i = x + y; return i; } function joo(x : int, y : int) { var i : int = x + y; return i; } } var c = new TestClass(); var i = c.goo(1, "2"); print(i); // prints: 3 }
这里,我定义了几个方法,内容本质上都一样,都是使用+运算符把两个操作数“加”起来。但是其中foo()有完整的类型标注,包括参数和返回类型都标注上了;goo()完全没有类型标注;hoo()只有第二个参数做了类型标注;ioo()没有标注返回类型,局部变量也没有标注类型;joo()在ioo()的基础上标注了局部变量的类型。
编译时使用了-m参数,得到编译结果的文字表示test.il。其内容太长,就不完整贴出来了。下面的中间代码都出自test.il。
于是让我们把这几个方法分析一下。
首先是foo()。编译器为其生成的方法信息是:
MethodInfo param_count=2 return_type=1 param_types={ 1 1 } debug_name_index=2 needs_arguments=false need_rest=false needs_activation=false has_optional=false ignore_rest=false native=false has_param_names =false -> 1
稍微解释一下。根据ABC(Adobe ByteCode)文件的格式定义,用于描述方法的signature的method_info数据结构如下:
method_info { u30 param_count u30 return_type u30 param_type[param_count] u30 name u8 flags option_info options param_info param_names }
其中return_type与param_type里都是对multiname数组的索引。如果为0则意味着类型是“*”,也就是AS3的严格模式中的任意类型。
也就是说,编译器正确的识别出了foo()的两个参数类型都是int,返回类型也是int。
foo()的方法体部分编译结果如下:
MethodBody max_stack=2 max_locals=3 scope_depth=4 max_scope=5 code_length=6 traits_count=0 -> 1
// ++StartMethod foo$0 LoadThis 0:Getlocal0 [1] PushScope 1:Pushscope [0] LoadRegister 1, int 2:Getlocal1 [1] LoadRegister 2, int 3:Getlocal2 [2] InvokeBinary BinaryPlusOp 4:Add [1] Return 5:Returnvalue [0] // --FinishMethod foo$0 TestClass/foo
可以看到,编译器在知道两个参数都是int型的前提下,仍然为运算符“+”选择了add而不是add_i指令。
另外几个方法编译出来的到的method_info分别为:
goo():
MethodInfo param_count=2 return_type=0 param_types={ 0 0 } debug_name_index=2 needs_arguments=false need_rest=false needs_activation=false has_optional=false ignore_rest=false native=false has_param_names =false -> 2
hoo():
MethodInfo param_count=2 return_type=0 param_types={ 0 3 } debug_name_index=2 needs_arguments=false need_rest=false needs_activation=false has_optional=false ignore_rest=false native=false has_param_names =false -> 3
ioo():
MethodInfo param_count=2 return_type=0 param_types={ 1 1 } debug_name_index=2 needs_arguments=false need_rest=false needs_activation=false has_optional=false ignore_rest=false native=false has_param_names =false -> 4
joo():
MethodInfo param_count=2 return_type=0 param_types={ 1 1 } debug_name_index=2 needs_arguments=false need_rest=false needs_activation=false has_optional=false ignore_rest=false native=false has_param_names =false -> 5
可以看到,编译器生成的method_info中关于类型的描述完全取决于代码中的标注;没有被标注的方法和变量一律被认为是“*”也就是任意类型;即便编译器有足够的信息区推导出其中的一些类型。
特别看一下ioo()中的状况:
// ++StartMethod ioo$0 LoadThis 0:Getlocal0 [1] PushScope 1:Pushscope [0] LoadRegister 1, int 2:Getlocal1 [1] LoadRegister 2, int 3:Getlocal2 [2] InvokeBinary BinaryPlusOp 4:Add [1] CheckType * 5:Coerce.o [1] StoreRegister 3, * 6:Setlocal3 [0] LoadRegister 3, * 7:Getlocal3 [1] Return 8:Returnvalue [0] // --FinishMethod ioo$0 TestClass/ioo
它与foo()最大的不同是,在两个参数被add之后,还对结果做了一次隐式类型转换到Object类型(coerce_o)。虽然编译器可以通过类型标注合理的推断出局部变量i也应该是int类型的,但却并没有这么做,而是继续将i看作“*”类型。
总的说来,AS3的可选类型标注的意义仅仅在于:
1、为编辑器提供更好的支持,使其容易实现高质量的智能感应(打个点能出现成员列表之类);
2、为编译器提供静态的类型检查的依据,尽量早的将类型错误报告给用户;有标注的就检查,没标注的就不检查;不能对未声明的变量赋值(而不像ES3或之前的版本,可以直接对未声明的变量赋值,赋值时自动创建出新的变量)。
至于运行效率,严格模式与标准模式编译出来的东西似乎没多少区别……并没有生成出更快的代码,不过至少也没有变得比标准模式更慢。
我的结论是否与现实状况有出入,这个有待进一步探究。Flex 3的asc.jar没有进行类型推导这点应该是没错的。
===================================================================================
但是值得一提的是,新版本的AVM2(Tamarin)正在试验所谓的Tracing-JIT,可以有效的减少动态类型检查带来的额外开销。无论是以标准模式还是以严格模式编译的AS3代码都能从中获益。或许的Adobe的策略就是:“反正后面有Tracing-JIT,即便编译器前端不做类型推导也没关系”,吧?
- avmplus_test.zip (925.6 KB)
- 描述: 文章中所做的测试所需要的东西,包括Tamarin、asc.jar、builtin.abc、toplevel.abc等
- 下载次数: 37
发表评论
-
ActionScript 3茶几
2009-11-05 16:26 0Vector - Adobe® Flex™ 3.4 Langu ... -
Flex 3 mxmlc保留AS3
2009-11-03 22:16 0mxmlc --keep-generated-actionsc ... -
Flex 4/AS3里的双向数据绑定
2009-11-03 21:49 0http://www.hufkens.net/2009/06/ ... -
AS3, optional type annotation, and strict mode
2008-05-24 17:32 2954Boy, this is my first English p ... -
Flex 3正式发布了 (2008-02-25)
2008-02-29 09:55 1798Great, Flex 3 SDK和Flex Builder ... -
ActionScript 3中的E4X实现的小实验
2007-11-14 20:13 2337ActionScript 3或许是现在最接近ECMAScrip ... -
杜增强关于Flash与Flex的整合的idea
2007-11-10 04:05 3283Integrating a Flash Interface i ... -
Fisix,一个AS3物理引擎
2007-11-07 12:44 2638www.fisixengine.com 引用The Engin ... -
Flash中使用BitmapData来Double Buffering (转载链接)
2007-10-31 09:40 4213原文在此 Kieth的blog。相当有趣。看来可以在这个blo ...
相关推荐
actionscript3.0编译器错误中文说明
ActionScript 3.0编译器编译错误大全
ActionScript 3 For Adobe Flash CS4 Professional About this guide This guide provides a quick introduction to migrating to ActionScript 3 from ActionScript 2. It is targeted at designers and ...
仅供网友学习参考使用,本资料是市面上难得可见的ActionScript 学习经典图书,内容详实,且所有文字均可以复制。
Adobe Flex4.0 ActionScript3 中文API 语言参考.part1.rar的下载地址: http://download.csdn.net/source/3245173 Adobe Flex4.0 ActionScript3 中文API 语言参考.part2.rar的下载地址: ...
ActionScript 3.0 语言和组件参考概述Adobe Flex 2 语言参考ActionScript 3.0 语言和组件参考是适用于 Flash® Player 应用程序编程接口 (API) 的参考手册。 Adobe Flex 2 语言参考ActionScript 3.0 语言和组件...
《用于 Adobe® Flash® Platform 的 ActionScript® 3.0 参考》包含 ActionScript 语言元素、核心库、组件包以及适用于 Flash Platform 中的工具、运行时、服务和服务器的类。 使用预设过滤器按产品进行过滤 此...
ActionScript3类型与java数据类型对应表
更全面更新的帮助文档,以前下的chm老是不能用,终于找到解决方法了,下载后单击chm属性,选择解除锁定,OK。
Adobe Flash 中的 ActionScript 2
Adobe® Flex™ SDK 和 Flex™ Data Services 中提供的编译器。字节码嵌入 SWF 文件中, SWF 文件由运行时环境 Flash Player 执行。 ActionScript 3.0 提供了可靠的编程模型,具备面向对象编程的基本知识的开发人员...
包含内容: ...Adobe Flex4.0 ActionScript3 中文API 语言参考.part1.rar的下载地址: http://download.csdn.net/source/3245173 Adobe Flex4.0 ActionScript3 中文API 语言参考.part2.rar的下载地址: ...
本书在讲解过程中对于ActionScript 3中相对于ActionScript 2 的改动进行了一一指出,并从理论上解释了为何改变及相关的实现。使ActionScript 2 程序员能够快速上手ActionScript 3 ,并对ActionScript 2代码移植有...
ActionScript3中文手册
ActionScript® 3是适用于Adobe® Flash® Player和Adobe® AIR™ 运行时环境的编程语言。 你可以使用ActionScript 3实现从简单动画到复杂、富含数据和互动应用程序的任何任务。 所有级别的编程人员 - 初级、中级和...
ActionScript脚本几种数据类型的相互转换