`
RednaxelaFX
  • 浏览: 3038843 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

Adobe的ActionScript 3编译器对strict mode中的类型标注的诠释

阅读更多
(那个……我没读过中文版的ActionScript 3文档,不知道标准文档里翻译用了哪些词。凑合吧)

使用过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.

换句话说,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.

而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.

注意到,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.0编译器编译错误大全

    在深入探讨《ActionScript 3.0编译器编译错误大全》这一主题之前,我们首先需要理解ActionScript 3.0(AS3)的基本概念及其在Flash开发中的重要性。ActionScript是一种强大的面向对象编程语言,用于创建交互式内容、...

    ActionScript 3 For Adobe Flash CS4 Professional

    ActionScript 3是Adobe Flash平台的一种面向对象的脚本语言,主要用于开发Flash和Flex应用程序。随着Flash CS4 Professional的推出,许多设计师和开发者需要从ActionScript 2迁移到ActionScript 3。本指南为设计师和...

    Adobe+Flash+cs5+ActionScript3参考文档

    这份"Adobe Flash CS5 ActionScript 3参考文档"包含了关于如何使用Flash CS5和ActionScript 3.0进行开发的详细信息。 ActionScript 3.0是面向对象的编程语言,与早期版本相比,它具有更强的类型检查和错误处理机制...

    ActionScript 3 类型转换

    在深入探讨ActionScript 3类型转换的精妙之前,我们先来回顾一下ActionScript脚本语言,这是一种广泛应用于Adobe Flash平台的编程语言,主要用于创建动态交互式内容、游戏以及动画等。随着版本的演进,ActionScript...

    Adobe ActionScript 编程圣经

    仅供网友学习参考使用,本资料是市面上难得可见的ActionScript 学习经典图书,内容详实,且所有文字均可以复制。

    Adobe Flex4.0 ActionScript3 中文API 语言参考.part1.rar

    Adobe Flex4.0 ActionScript3 中文API 语言参考.part1.rar的下载地址: http://download.csdn.net/source/3245173 Adobe Flex4.0 ActionScript3 中文API 语言参考.part2.rar的下载地址: ...

    ActionScript3类型与java数据类型对应表.rar

    尽管ActionScript3主要应用于Adobe Flash平台,而Java则适用于多种跨平台应用开发,但这两者都基于类C语言语法,因此在数据类型的处理上有很多相似之处。下面我们将详细探讨ActionScript3和Java的数据类型对应关系。...

    flex中文帮助 ActionScript3.0中文帮助

    ActionScript 3.0 语言和组件参考概述Adobe Flex 2 语言参考ActionScript 3.0 语言和组件参考是适用于 Flash® Player 应用程序编程接口 (API) 的参考手册。 Adobe Flex 2 语言参考ActionScript 3.0 语言和组件...

    ActionScript3中文手册

    ActionScript3是Adobe Flash平台的核心编程语言,用于创建交互式内容、富互联网应用程序(RIA)以及游戏。这个“ActionScript3中文手册”是为开发者提供的一份详细文档,旨在帮助他们理解和掌握ActionScript3的基本...

    Adobe Flash 中的 ActionScript 2

    ActionScript 2.0 是 Adobe Flash 平台中用于创建交互式内容的主要脚本语言。在 Flash 中,ActionScript 允许开发者编写控制动画、处理用户输入、与服务器通信等功能的代码。下面是关于 ActionScript 2.0 中变量、...

    用于 Adobe® Flash® Platform 的 ActionScript® 3.0 参考

    《用于 Adobe® Flash® Platform 的 ActionScript® 3.0 参考》包含 ActionScript 语言元素、核心库、组件包以及适用于 Flash Platform 中的工具、运行时、服务和服务器的类。 使用预设过滤器按产品进行过滤 此...

    ActionScript3中文教程

    ActionScript3(简称AS3)是Adobe Flash Platform的主要编程语言,用于创建互动式富媒体内容、游戏以及应用程序。本教程是面向中文用户的专业ActionScript3教程,旨在帮助开发者利用Adobe Flash CS3专业软件进行高效...

    adobe actionscript学习资料

    ### Adobe ActionScript 学习资料知识点总结 #### 一、ActionScript 概述 - **定义**:ActionScript 是一种面向对象的编程语言,最初由 Macromedia(后来被 Adobe 收购)开发,用于 Flash 平台。它主要用于创建交互...

    一个通过XML技术实现 ASP.NET 与ActionScript 3.0紧密集成的程序代码

    而ActionScript 3.0则是Adobe Flash平台的主要编程语言,主要用于创建富互联网应用(RIA),尤其是在Flash Player和Adobe AIR环境中。 集成ASP.NET和ActionScript 3.0的核心在于XML作为数据传输的桥梁。XML文档可以...

    《ActionScript 3.0 语言和组件参考》中文官方版本,无错

    Adobe® Flex™ SDK 和 Flex™ Data Services 中提供的编译器。字节码嵌入 SWF 文件中, SWF 文件由运行时环境 Flash Player 执行。 ActionScript 3.0 提供了可靠的编程模型,具备面向对象编程的基本知识的开发人员...

Global site tag (gtag.js) - Google Analytics