April 2021
Mo Tu We Th Fr Sa Su
<< >>


Adobe Alchemy

Posted on Nov 19 2008

It was already demoed before, but Adobe Alchemy has just been released on Adobe Labs.

Alchemy is a AVM2 backend for LLVM. It means that you can compile C/C++ code to be run on the Flash Player 10.

Let's detail a bit the way this is working :

LLVM is a compiler framework. It has several frontends and several backends. A frontend is typically a C/C++ compiler that will take C/C++ sources files and compile it LLVM intermediate bytecode. A LLVM backend is typically a code generator that will compile the LLVM intermediate bytecode to x86 native code and that will create an executable.

What some guy from Adobe did was to reuse the C/C++ LLVM frontend, then write a small and smart code generator that instead of compiling the LLVM bytecode to x86 or ARM or other native bytecode, compiles it instead for AVM2 bytecode.

AVM2 is the Virtual Machine that is part of the Flash Player. The AVM2 is able to interpret a virtual bytecode which is more highlevel than x86 bytecode (and then can be more easily checked and trusted, which is necessary).

Check this document (PDF) for a list of the documented AVM2 bytecode operations.

What about Speed ?

As a reminder, the Alchemy pipeline is the following :

.c file -> LLVM intermediate bytecode -> AVM2 bytecode

However, in general, doing so reduces a lot the performances. Especially since the abstraction level of the AVM2 bytecode is a lot higher than the one of the LLVM bytecode, it means that all arbitrary operations such as pointer and memory manipulation which are done in C must be wrapped by using the memory-safe mechanisms which are available in AVM2, such as a flash.utils.ByteArray to represent the memory data.

Doing that would be very slow, and actually it would be a lot slower than doing it in AS3 or Haxe since you can always better fine-tune your Flash code, while you don't know exactly how things get translated from C/C++ to AVM2...

That's why the following sentence on the Alchemy website raised my attention :

....performance can be considerably faster than ActionScript 3.0...

Knowing that both AS3 and Alchemy output runs on the same AVM2, it would then mean that Alchemy use parts of the AVM2 that are not accessible from AS3...

And indeed, here they are : after a quick check, I could fine 12 undocumented AVM2 opcodes, that seems to be only used by Alchemy : they use codes 0x35 to 0x3E and 0x51 to 0x52. It should be quite quick to find out what they're doing and how they are used by Alchemy, and measure their performance.

This is actually quite good news for Haxe ! Since it already has full Flash10 support, it means that the compiler will be able to use these new opcodes to produce even faster SWF files !

Might be helpful for several projects I've been recently working on, and in which getting the best speed is always interesting.

With this and upcoming Pixel Blender assembler support in Haxe , that's a great time for performances addicts !

EDIT : the opcodes are now available in Haxe, see : Virtual Memory API

  • Nov 19, 2008 at 23:28

    Really interesting stuff. Keep up the good work :)

  • Nov 20, 2008 at 03:57

    This is fascinating news. Why do you suppose those opcodes are not used by AS3? (Quick -- find out what they do!)

  • Nov 20, 2008 at 08:39

    Hi Nicolas,

    I had the pleasure to be in the Alchemy (it was called Cassava internally) prerelease.
    What I can tell you is that:

    - The new OpCodes (at least the ones that have been added for Cassava - I don't know if they made some additions with the new release) are used for fast ByteArray manipulation.
    - Alchemy implements its own register based virtual machine, that uses a ByteArray as RAM. This ByteArray is then accessed using the new OpCodes that make reading and writing faster.
    - You can assing a ByteArray to ApplicationDomain.domainMemory and then write/read quickly using the new OpCodes.
    - I did a lot of tests, and the speed is not always good. The bottlenecks that flash has exist also in Alchemy (which is obvious because they didn't add nothing SO special to the Flash VM).
    - I guess that the biggest speed improvements that you can achieve are because of the use of static compilation, LLVM optimization and a typed register based VM. Compared to the ASVM2 for instance, function calls are faster because they don't require pushing/popping stack frames. And you teorically may implement tail recursion for instance to get rid of some ASVM limitations.

    After a few months of playing with Alchemy, I can say I've been negatively surprised. They made some changes with the new release that might have speed up the generated code, but as fas as I know a well written AS (or Haxe :P) code is better. You cannot improve BitmapData access, you cannot improve drawing primitives or basic numerical calculations ....

    So I don't know if this might be useful for Haxe directly but I know you will find a way to take out something good form this too.

    Looking forward for your 3D engine, which seems to be quite interesting ;)

  • Nov 20, 2008 at 10:18

    Hi Gabriele,

    Thank you for the report, that will be helpful to understand better how the AVM2 has been modified. Once the new opcodes are understood and documented, as you state, it's possible that they will not be very useful to speedup Haxe or AS3.

    But you never know how some feature that has been designed in some specific way might be used in another - more creative - way ;)

    In particular, if this is a faster way to read/write memory (compared to a Vector for instance which is the best way so far) this might indeed be useful for a whole range of applications.

  • Nov 20, 2008 at 16:03

    Hello Nicolas !

    All undocumented opcodes are explained in Scott Petersen presentation:
    Flash C Compiler: Compiling C code to the Adobe Flash Virtual Machine.

    //Store opcodes
    [stack: (coerced to int or Number) value, (coerced to int) address -> ]
    0x35 si8 – store an 8 bit integer to global memory
    0x36 si16 – store a 16 bit integer to global memory
    0x37 si32 – store a 32 bit integer to global memory
    0x38 sf32 – store a 32 bit (IEEE 754) float to global memory (truncating the input double/Number to 32 bit IEEE 754)

    Load opcodes
    [stack: (coerced to int) address -> value (int or Number)]
    0x3a li8 – load an 8 bit unsigned integer from global memory
    0x3b li16 – load a 16 bit unsigned integer from global memory
    0x3c li32 – load a 32 bit integer from global memory
    0x3d lf32 – load a 32 bit (IEEE 754) float from global memory and promote to 64 bit (IEEE 754) double/Number
    0x3e lf64 – load a 64 bit (IEEE 754) float from global memory

    Sign extension opcodes
    [stack: (coerced to int) value -> value (int)]
    0x50 sxi1 – sign extend from 1 bit to 32
    0x51 sxi8 – sign extend from 8 bits to 32
    0x52 sxi16 – sign extend from 16 bits to 32

    AS3 API
    static ApplicationDomain. MIN_DOMAIN_MEMORY_LENGTH:uint

    On x86, JITs to direct memory accesses to hard-coded addresses
    On x86, range checking JITs to compares against immediates
    Hard-coded addresses and immediate range check nums modified on-the-fly in live machine code//

    You can get Scott Petersen slides here:

    Videos are here:

    Hope that helps !
    Keep up the good hacks ! ;)

  • Nov 20, 2008 at 21:39

    I can't wait to see the HaXe Vorbis decoder go head to head with the Alchemy Vorbis decoder. ;-)

  • Fernando
    Dec 16, 2008 at 12:38

    Humm ... a Theora/Dirac decode sounds good too ;)

Name : Email : Website : Message :