How JITB converts ActionScript to Java

One of the biggest challenges when writing a program like JITB is to convert ActionScript to Java. There are major differences between ActionScript 3.0 and Java 1.6 which JITB currently targets.

ActionScript 3.0 is a dynamically typed language with function closures. Furthermore it has native XML support, scope-changes, implicit getters and setters etc. The main issue however is to convert the set of bytecodes ahead of time to statically typed Java code. JITB does not know anything about what is going on since it compiles all the code ahead of time.

JITB and TAAS

JITB makes use of TAAS. A three address code intermediate language. TAAS has its own set of rules and typesystem that I defined for myself. Method overloading is supported for instance. And there is no concept of array access. Code like x = a[0] is converted to x = a.getIndex(0). In TAAS terms the name of a method is also not worth a penny since it is always using a reference based lookup.

What I love about TAAS is that it has a really small instruction set. Array access is just a method call like any other method call. No extra instructions added. This makes optimizations really slick and easy to develop. Since the code is statically typed you also always know which method is being called and you could construct a call graph and do whole program optimizations which is a huge bonus. Escape analysis is something that is now finally possible for me.

JITB uses a frontend that parses ActionScript bytecode and creates an AST which is then transformed and passed to a backend that creates Java bytecode. The class and package structure is stored in a tree form. Method bodies are always stored in a graph representation. The interesting problem is to convert ActionScript into TAAS since it is no direct mapping and some statements are not supported in the same way you get them form the ActionScript bytecode. Then the next interesting problem is to convert this code into Java bytecode which is also not a direct mapping.

An example for such a problem are implicit getters and setters. TAAS does not have a concept of getters and setters but understands methods. So whenever the ActionScript bytecode has a GetProperty instruction I try to figure out if this is a field or not. If it is a field I generate a TLoad instruction, if it is an implicit getter it will be converted to a TCall instruction. However if it cannot be determined since the class might be dynamic a TCall instruction will be generated which uses the special TGetProperty method and this will be resolved at runtime.
When converting to Java a TLoad can be easily translated to a GETFIELD operation. When it is a TCall I first lookup whether or not it is a special native function. If it is a special function like TGetProperty I insert Java code like object.JITB$getProperty(name). If it is a normal function I simply insert an invoke operation.

Closures for Java

Java 1.6 does not support closures. This means Java does not understand the concept of a reference to a function. Code like addEventListener(Event.ENTER_FRAME, onEnterFrame) is not possible with Java since onEnterFrame is a reference to the onEnterFrame function which is defined somewhere else in your code.

I took the idea from Scala and how they support closures in the JVM. Basically when code like addEventListener(Event.ENTER_FRAME, onEnterFrame) occurrs it will be translated to the TAAS instruction TCall(TReg(0), TaasMethod(addEventListener, ...), List(TString("enterFrame"), TClosure(TaasMethod(onEnterFrame, ...))), None). This basically means that the method addEventListener is called on the object in register zero with two arguments of which one a closure and it has no result which is indicated by None.

This instruction is expanded to the following Java code. Please remember that it is always Java bytecode. I think it is just easier to understand if I write the corresponding Java code here.

this.addEventListener("enterFrame", new Function1() {
  override Object call(Event arg) { callVoid(arg); return null; }
  override void callVoid(Event arg) { onEnterFrame(arg); }
});

Function1 represents a function of arity one. The AVM can call any method as either void or with an expected result. If the method has a result and you call it via CallPropVoid the resulting object is ignored. If however you have a method that does not have a result and you call it via CallProperty the null object will be pushed on the stack.

The Java code in EventDispatcher which would call closures basically now only looks like this:

void dispatchEvent(Event event) {
  for(Function1 listener : listenersFor(event.type)) 
    listener.call(event)
}

Dynamic code in Java

Since I want to target Java 1.6 I do not make use of the Java 1.7 opcodes like invokedynamic. Because TAAS is already statically typed we have only in very rare cases the need to make a dynamic lookup. This is done by some helper classes or methods. Every ActionScript based class extends from jitb.lang.Object. The jitb.lang package represents the ActionScript’s toplevel. The Object class has certain helper methods like JITB$getProperty and JITB$setProperty. Those methods throw an error by default if an object is not dynamic but they can implement the behaviour to store values in a HashMap for dynamic classes.
However currently dynamic method lookup is not supported. Code like a['method'+Math.random()]() fails since it is impossible to know upfront which method is called. But this can be supported as well. It is just very cumbersome and annoying.

Emulating the AVM in the JVM

What kind of error do you expect for this kind of code: var x: String = null; trace(x.toString());? This creates a TypeError in ActionScript but a NullPointerException in Java. Same for things like var x: A = new A(); var y: B = B(x); which would result in a Java ClassCastException if A is not assignable to B.
JITB offers an option which is by default turned on the get the exact same exceptions like the AVM would throw them. This means that a Java cast is converted to a call like AVM.cast(x, B.class) with the option turned on or the simple Java CHECKCAST bytecode when the option is turned off. Basically expecting something to be null in a try-catch block is very silly in my honest opinion. So to get rid of this overhead you can disable this extra step of correctness.

Another interesting issue is the fact thatthe AVM can throw any object. Java however expects that a throwable object extends from the Throwable class. Of course the basic jitb.lang.Object class could simply extend Throwable. However I do not want that overhead and at any time. Also I do not want to break how classes extend each other. If you do something like throw "string" it is converted to throw new Throw("string"). Throw does extend Throwable and whenever it is catched the value is simply extracted.

To box or not to box?

ActionScript allows you do use int as an object with a lot of special behaviours. Same happens for values like Boolean or Number. var x: int; trace(x); outputs 0 but not null. But it is also possible to call 0.toString() which indicates that the integer value 0 is treated like an object that has methods like toString().
In Java however you have a real int primitive and the Integer object. 0.toString() does not compile but you would rather do Integer.toString(0).

Of course Java is much faster when using primitive data types when appropriate. JITB does this since it handles primitive types like real primtives for Java. This means a method like function add(x: int, y: int): int { return x + y} is converted to int add(int x, int y) { return x + y }. However when you have a method that expects an Object type a primitive will be boxed into a compatible type.

Last but not least what happens for code like 0.toString() or other methods? A possibility would be to emit code like new jitb.lang.Number(0).toString() but that does not make sense in most of the cases. Instead those calls are treated specially with a call like jitb.lang.Number.JITB$toString(0) and we get rid of an extra allocation.

Conclusion

I hope you understand a little bit better now how JITB works internally and what the main gotchas are in such an implementaiton. The journey is not over since I have to add support for anonymous methods and although I talked about things like throw I still have to add support for try-catch. Also a lot of other basic features are still missing but I doubt that they would cause any problems.

The other side of the story is the Flash Player API inside of JITB which is maybe worth a blog post like this as well since it reveals a lot of other funny and interesting gotchas.

4 Comments

  1. Posted Oct 2, 2010 at 7:48 pm | Permalink

    What a fascinating look at the conversion process! I’d love to read an article (or five!) about your implementation of the Flash Player API in JITB.

  2. stephan
    Posted Jan 3, 2012 at 1:44 pm | Permalink

    Hi there

    I recently stumbled upon this post
    http://www.experts-exchange.com/Softwar … cript.html
    which explains how to optimize as3 code via very simple rules.

    Aparat offers bytecode optimization. But I can´t find any information about what that really means.

    I am working on a quite big project right now and currently I am searching for further possible tweaks to it.

    So are these tips even relevant if I let Aparat do it´s bytecode magic anyway?

    Thanks in advance

    Stephan

  3. stephan
    Posted Jan 3, 2012 at 1:45 pm | Permalink

    sorry here´s the link again

    http://www.experts-exchange.com/Software/Photos_Graphics/Web_Graphics/Macromedia_Flash/ActionScript/A_2107-20-Tips-to-Optimize-your-ActionScript.html

  4. Posted Oct 1, 2013 at 12:10 pm | Permalink

    Your technical information related with java programming is very useful and interesting. Also share updated details about java in your website. Thanks for sharing this article.

8 Trackbacks

  1. […] This post was mentioned on Twitter by Peter Elst, Joa Ebert, Kevin Suttle, Nisse Bryngfors, Andrea Trento and others. Andrea Trento said: RT @peterelst: RT @joa: How JITB converts ActionScript to Java http://goo.gl/7SXK […]

  2. […] Follow this link: How JITB converts ActionScript to Java « blog.joa-ebert.com – Blog … […]

  3. […] How JITB converts ActionScript to Java « blog.joa-ebert.com – Blog … […]

  4. […] How JITB converts ActionScript to Java « blog.joa-ebert.com – Blog … […]

  5. […] How JITB converts ActionScript to Java « blog.joa-ebert.com – Blog … […]

  6. […] How JITB converts ActionScript to Java JITB egy olyan program aminek célja hogy AS3-as kódot Java byte kóddá alakítson, így kihasználva a Flash flexibilitását és Java erejét. A projekt még kezdeti stádiumban van de ez a leírás betekintést nyújt pár érdekes részletbe. […]

  7. […] How JITB converts ActionScript to Java « blog.joa-ebert.com – Blog … […]

  8. […] How JITB converts ActionScript to Java « blog.joa-ebert.com – Blog … […]