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

AS3, optional type annotation, and strict mode

阅读更多
Boy, this is my first English post on this blog. I wish I had the time to write more English and Japanses posts. Anyway here we go.

Those who have been using ActionScript 3 would have noticed its optional type annotations. So what do we get from being explicit about types? It's obvious that, by stating the programs' invariants through type annotation, type errors can be reported earlier (at compile time) than they would have been otherwise (at runtime). But what else? Does explicit typing yield better runtime performance too?

On the current implementation of Adobe's ActionScript 3 compiler, the answer to that may just be a _no_. Even though Flex SDK and Tamarin are both open source, which means that we can get full sources to the whole compiler+vm suite to get AS3 running, it's still hard to figure things out just by browsing through the code without detailed documentations. So I'm just gonna do some superficial tests to see what's going on in the AS3 compiler.

=======================================================================================================

When compiling AS3 source code, there are two compilation modes: the standard mode and the strict mode. In standard mode, everything's supposed to be compatible to the good old ECMA-262 version 3 spec, so we should be able to safely assume that the type annotations in standard mode doesn't do much. In strict mode, however, some type checks can be done at compile time, so that: we can't assign to a variable not yet declared, neither can we call a function with parameters of imcompatible types.

According to the ES4 wiki, Strict and Standard compilation modes, strict mode is "only meant as a way for programmers to indicate their desire for more extensive and conservative error analysis", and does not imply optimizations, although implementation can take advantage of the type information to produce better code.

So let's take a look at this sample code snippet, to see how type annotations affect type checking and instruction selection in Adobe's AS3 compiler:
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); // 3
    i = c.hoo(1, "2");
    print(i); // 12
    i = c.ioo(1, "2");
    print(i); // 3
}

(compiled with asc.jar from Flex 3 SDK, with the command:
java -jar asc.jar -import builtin.abc -import toplevel.abc -m -strict test.as
builtin.abc and toplevel.abc are from Tamarin, 2007/10/31)

The methods in the code snippet are pretty much the same: they *add up* the two parameters. Foo() is fully type annotated, goo() is totally unannotated, where as the other methods are partially annotated.
Note that there are two AVM2 instructions that does the operation of "add": one is the general "add", the other is "add_i", which adds up two integers.
As stated in ActionScript Virtual Machine 2 Overview, the semantics of add and add_i are:
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.

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.

Both instructions aren't really low-level enough. Whatever parameters passed in, both instructions include the semantics to do a type check/implicit type convertion first, then add the two operands, and finally pushing the result back onto the evaluation stack. Anyway, if it is known that both the operands are ints, I reckon it should be better to choose add_i than add. But that's not the case here, Adobe's AS3 compiler always generated code using add.

Take a closer look at the code generated for foo().
The method's generated signature is:
   1. 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

The return type and parameter types are all int, correct.
The method's body:
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

So even when fully type annotated as in foo(), the compiler chooses add instead of add_i. Actually the compiler seem to generate the same code for foo()'s method body whatever the compilation mode.

For goo(), we can see that calling goo() with (1, "2") yields a number 3. The string "2" is implicitly converted into int upon calling foo() in goo(), even if that wasn't the programmer's intention.
The compiler doesn't reject methods calls where formal parameters' types and actual parameters' types aren't exactly the same. The types are considered "compatible" if there's a way to implicitly convert from the source type to the target type. So unless we do something like this:
class A { }
class B { }
function test(a : A) {
    print("A");
}
test(new B()); // compile time error
// [Compiler] Error #1067: Implicit coercion of a value of type B to an unrelated type A.

the compiler's gonna be "forgiving" enough not to warn you that implicit conversions have been done. Not to mention, code like this will also compile, whatever the compilation mode:
c.ioo(1);

No errors, no warnings. Not until you run the code will you see the argument error:
引用
ArgumentError: Error #1063


I thought strict mode was supposed to be less forgiving than this...well, I'm wrong.

It's easy to see that the compiler doesn't do type inference at all. In ioo(), where I didn't annotate the local variable's type, the compiler adds a coerce instruction after the add:
// ++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] // coerce here

StoreRegister 3, *
      6:Setlocal3 [0]

LoadRegister 3, *
      7:Getlocal3 [1]

Return
      8:Returnvalue [0]

// --FinishMethod ioo$0 TestClass/ioo

Again, the code generated for ioo()'s method body is the same whatever the compilation mode. Overall, there's only little difference between code generated in strict mode or standard mode.

Haven't run any benchmarks for differently annotated code, I'd just guess from the code generated that strict mode with annotated types in AS3 doesn't imply better runtime performance. I'm asking Francis Cheng on this, and see if he can give us more detail on optional type annotations and strict mode.

I thought we can take advantage of the declared types and at least reduce some of these redundant type checks/coerces. Adobe's AS3 compiler doesn't do that currently. And there should be a reason behind it, which I don't know. Maybe digging into the source code will give me a better picture...

=======================================================================================================

The only reason I can come up with is, the optimization on reducing dynamic type checking is not done at compile time, and is instead done at runtime, through a tracing-JIT. Tamarin-tracing is the one that
引用
traces code executing during hotspots and compiles it so when those hotspots are entered again the compiled code is run instead. It traces each statement executed, including within other function calls, and this entire execution path is compiled.

Maybe the JITter knows how to reduce all those redundant type checks on frequently used types, so no matter what compilation mode you're using, you always benefit from the runtime.

=======================================================================================================

The Impact of Optional Type Information on JIt Compilation of Dynammically Typed Languages
分享到:
评论

相关推荐

    3D Annotation

    如果选择后者,记得取消选中feature linked,并在Create Annotation Feature Class对话框中指定目标数据库,如图1-2和图1-3所示。 然后,进入ArcGlobe来设置和展示3D Annotation图层。首先,打开3DD文件并添加图层...

    前端项目-d3-annotation.zip

    3. **Arrow Annotation**:创建箭头形状,指示特定的方向或关联。 4. **Box Annotation**:绘制矩形框,可用于突出显示或标记图表区域。 5. **Circle Annotation**:绘制圆形,可以用来标记数据点或其他关键位置。 ...

    Hibernate distribution and annotation

    标题“Hibernate distribution and annotation”涉及到的是Hibernate ORM框架的一个特定版本及其相关的注解功能。Hibernate是一个流行的Java对象关系映射(ORM)工具,它允许开发者使用面向对象的编程模型来操作...

    自定义的Annotation

    guard let annotation = annotation as? CustomAnnotation else { return nil } let identifier = "CustomAnnotationIdentifier" var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: ...

    Annotation手册

    3. **Annotation类型**:Annotation类型是一种接口,定义了Annotation的结构和默认值。在Java中,通过`@interface`关键字声明Annotation类型,其中的成员变量是固定的,没有方法参数。当我们通过反射API访问...

    struts2 hibernate3 spring2.5 annotation 整合

    这里主要讨论的是如何将这三者结合,并利用注解(Annotation)进行配置,以简化开发过程。 Struts2是MVC(模型-视图-控制器)框架,主要负责处理HTTP请求和控制应用的流程。它通过Action类处理业务逻辑,使用拦截器...

    Annotation详细介绍(大全)

    `ElementType`枚举定义了这些元素,如`ANNOTATION_TYPE`表示可以应用于其他Annotation。 9. **处理Annotation**: 处理Annotation通常发生在编译时(通过编译器插件)或运行时(通过反射API)。例如,`@Retention...

    annotation

    import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @...

    jakarta.annotation-api-1.3.5-API文档-中文版.zip

    赠送jar包:jakarta.annotation-api-1.3.5.jar; 赠送原API文档:jakarta.annotation-api-1.3.5-javadoc.jar; 赠送源代码:jakarta.annotation-api-1.3.5-sources.jar; 赠送Maven依赖信息文件:jakarta.annotation...

    hibernate annotation hibernate3

    《Hibernate注解与Hibernate3深度解析》 在Java开发领域,Hibernate作为一种强大的对象关系映射(ORM)框架,极大地简化了数据库操作。本篇将深入探讨Hibernate 3版本中的注解使用,帮助开发者理解如何利用注解进行...

    hibernate 中文文档 and _annotation.chm

    3. 注解(Annotation)在Hibernate中的应用: - @Entity:标记一个Java类为数据库中的一个表,表示该类是实体类。 - @Table:指定实体类对应的数据库表名。 - @Id:标识类中的主键字段,可以配合@GeneratedValue...

    javax.annotation-api-1.2-API文档-中文版.zip

    赠送jar包:javax.annotation-api-1.2.jar; 赠送原API文档:javax.annotation-api-1.2-javadoc.jar; 赠送源代码:javax.annotation-api-1.2-sources.jar; 赠送Maven依赖信息文件:javax.annotation-api-1.2.pom;...

    annotation的jar包

    javax.annotation-3.0.jar javax.annotation-3.0.jar javax.annotation-3.0.jar

    annotation-1.1.0.jar

    @androidx.annotation.NonNull 缺失的兼容、androidx.annotation兼容包

    用Annotation简化Java程序的开发(PDF)

    3. **访问Annotation** ##### 1. 定义Annotation 定义Annotation的基本语法如下: ```java public @interface MyAnnotation { String value() default ""; } ``` 这里定义了一个名为`MyAnnotation`的Annotation...

    Annotation技术

    3. **自定义Annotation** 自定义Annotation通过使用`@interface`关键字来创建。 Annotation类型可以包含成员,这些成员通常是没有参数的方法,其返回类型限制为基本类型、字符串、Class、枚举、Annotation或它们的...

    jakarta.annotation-api-1.3.5-API文档-中英对照版.zip

    赠送jar包:jakarta.annotation-api-1.3.5.jar; 赠送原API文档:jakarta.annotation-api-1.3.5-javadoc.jar; 赠送源代码:jakarta.annotation-api-1.3.5-sources.jar; 赠送Maven依赖信息文件:jakarta.annotation...

    hibernate 注解 annotation 教程

    hibernate 注解 annotation 教程

Global site tag (gtag.js) - Google Analytics