Heavy constructor JIT optimisation in ActionScript

I was running FlexPMD the other day over some code and it brought up this warning: "HeavyConstructor. Constructor must be as lightweight as possible. No control statement allowed, whereas a cyclomatic complexity of 2 has been detected. The Just-In-Time compiler does not compile constructors. Make them as lightweight as possible, or move the complexity of the code to a method called by the constructor. Then the complexity will be compiled by the JIT."

Huh? That's news to me, actionscript constructors are not compiled if they have a conditional statement in them?

The FlashPlayer is a Just In Time (JIT) compiler just like Java. What this means is that is that it will convert the code in a swf into native machine code and run that. That's the main reason the flash player is so fast!

A Flex application, when it is compiled the code gets converted from MXML to ActionScript to ActionScript Byte Code (ABC) which is then packaged up into a swf. When that swf is run in the Flash Player it gets compiled again by the JIT compiler from ABC code to native machine code.

If you want to know more about the flash virtual machine take a look at the ActionScript Virtual Machine 2 (AVM2) Overview.

While it doesn't say much about JIT compilation it does contain this footnote:

"In practice, the AVM2 may transform the code at run-time by means of a JIT, but this does not affect the semantics of execution, only its performance."

Notice the word "may" there so you code may or may not be converted to machine code.

Why would this be the case? JIT compilation is sometimes a trade off and it can be faster to not JIT a piece of code but just interpret the code. It takes time to convert the byte code to native machine code. If the code is only going to run once it may run faster if it is not converted.

It turns out that the JIT compiler doesn't compile ActionScript class constructors.

The solution is to make your constructors as light as possible, if you need a constructor to do a lot of work it's a good idea to move all of the code into a private init method and call that from the constructor as the init method will be compiled and optimized by the JIT.

So if you have code like this:

view plain print about
1public function SomeClass()
2{
3    if (condition) {
4        .... code here ....
5    }
6    ... more code here ...
7}

Change it to be like this:

view plain print about
1public function SomeClass()
2{
3    init();
4}
5        
6private function init():void {
7    if (condition) {
8        .... code here ....
9    }
10    ... more code here ...
11}

For some classes with a single simple condition in the constructor the extra overhead of calling another method may be slower. So if you're not sure run some timing tests.

For more information take a look at ActionScript 3.0 and AVM2: Performance Tuning which goes into a lot more detail and what the Flash Player does under the hood.

TweetBacks
Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
The statement that constructors are not jitted is suspect to me. This is based on performance tests that I have done and also on documentation within the Performace tuning PDF clearly mentions that algorithm for jit or no-jit is

Initialization functions ($init, $cinit) are interpreted
Everything else is JITted

A user defined object's constructor is different from $init and $cinit. I downloaded open source sdk, unassembled a few pure action script and mxml programs using SwfxPrinter, and clearly saw that $init, $cinit and the class's constructor were three different entities that did not seem to call each other at all. Further black tests proved to indicate no difference.

If someone has code that clearly depicts performance degradation with large constructors, please post them. I even tried statics with constructors and saw the compiler cleverly move this code into $init leaving the constructor with other stuff that seemed jittable... This mystery has been bothering me alot :)
# Posted By manu | 11/10/10 9:47 AM
I did some basic testing and didn't notice any any difference with very simple constructors but with more complex one it did seem to make a difference. I'll see if I can come up with some real numbers.

The JIT here we are talking about is conversion of ABC bytecode to native machine code so disassembling SWFs is probably not going to be much help as you wouldn't know which bits are JITed and which bit are not. It's all internal to the Flash player I would assume.

I've seen reference to the issue in other place and generally the word constructor is used. eg Section 4.1 in http://je2050.joa-ebert.com/files/misc/as3opt.pdf
# Posted By Justin Mclean | 11/10/10 10:47 AM
Once again - Although there is no clear documentation of what is jitted and what is not, the closest description of the algorithm is in the Performance Tuning pdf you have a pointer to. There may be someone else who has other information culled from Tamarin to add on here on what is jitted and what is not.

Unassembling code shows you the $cinit and $init functions - these are "interpreted" - and I am assuming everything else is jitted (assuming that PDF is the bible). Since none of the constructors code gets moved over to $init, once can assume that the constructor is not interpreted.

Now if you have static variables defined, you can see that it gets moved into $init and therefore you know for sure that it is interpreted. Thats how the disassembly helps in pointing to some hints - i.e if code moved into $init or $cinit it is interpreted.

I'm not the authority on this, so this message is just to stimulate a discussion ...
# Posted By manu | 11/10/10 1:33 PM
With no clear documentation as you say it hard to know what it does for sure. Testing this is certainly quite hard as you would never be sure if any bit of code got JITed or not and only assume so from the time it takes to run.

I had assumed that $init was for statics and $cinit for the constructor - which may or may not be the case. We assume these 2 blocks of code are not JITed but again it's hard to know for sure.

And of course new versions of the Flash Player (10 and 10.1) may do things totally differently.

I'll do some further investigation and see what I can come up some information.
# Posted By Justin Mclean | 11/10/10 8:51 PM
I've just run a few simple tests and I'm seeing differences. As far as I can tell a constructor calling an init method is faster than just a constructor alone by about 10-20% even for simple constructors. I have no way of confirming that the constructor is not JITed but it's a reasonable assumption to make as the class with the init method should be slower with no JIT.

You need to make a release version of the swf and run it in the non debug version of the Flash Player. Running it in the debug player shows that the init method is usually slower.
# Posted By Justin Mclean | 11/10/10 11:07 PM
Two things I did not do - use the release version of the swf and use the non-debug version of the flash virtual machine - i mean non debug flash player/browser plugin ha ha!

Just curious - how did you collect your timing? I have trace statements that do not show up in release versions. Did you display the timing inside a textbox or something?
# Posted By manu | 11/14/10 8:10 AM
Any time you do any performance testing it really must be a release swf in the non debug flash player - you often get order of magnitude differences in timing.

Rather than using trace statements I just set the text property of some labels to show the results like so:

private function onCreationComplete():void {
   result1.text = testA().toString();
   ...
}

private function testA():int {
   var noRuns:int = 500000;
   var start:int = getTimer();
   for (var i:int = 0; i < noRuns; i++) {
      var a:ClassA = new ClassA();
   }
   var end:int = getTimer();
   return end-start;
}

...
<s:Label id="result1" />
...

Hope that helps.
# Posted By Justin Mclean | 11/14/10 8:56 AM
# Posted By manu | 11/24/10 12:12 PM
Hi Manu I see from your test results you didn't get much difference with using an init method. Did you run the tests in the release version of the Flash Player? I typically see 10-20% improvement in speed but as they say your milage may vary.
# Posted By Justin Mclean | 11/24/10 12:44 PM
Here are the results from some simple tests:

In debug player.
Non empty constructor: 639
Constructor calling non empty init: 840
Empty constructor and calling non empty init: 837

In release player:
Non empty constructor: 120
Constructor calling non empty init: 115
Empty constructor and calling non empty init: 106

(smaller numbers are faster)

There's not a lot of difference here but the results are always consistent in that calling a constructor always takes more than having it call init.
# Posted By Justin Mclean | 11/24/10 1:32 PM