How the ActionScript Virtual Machine Works

If you are involved with AS3 development you might have heard of a virtual machine that lives inside the Flash Player or of the so-called bytecode that your code gets transformed into. But what are they exactly?

A significant part of the Flash Player is the AVM – the ActionScript Virtual Machine. When you compile your AS3 code it gets transformed into a binary instruction set, called bytecode, which is embedded into the produced SWF. As a user loads the SWF into the Flash Player, the AVM parses the bytecode and executes it step by step.

Let’s examine the process in a little bit more detail: Have a look at the following statement and imagine we want to execute it (compute the result and assign it to “foo”):

foo = 2 + 3 * 4;

From a human’s point of view this line means “Multiply 3 by 4, add 2 to the result and assign that to a variable named foo”.

On the other hand if a computer reads this line it would store it as “character f, followed by character o, followed by character o, followed by character space, followed by character equals, followed by….” And so on. At this state this information is pretty useless and additional steps need to be taken in order to turn the statement into something that a machine can execute. Basically what we need to do is to compile the source code.

The Compiler

As I noted before, the statement above is raw source code, a collection of characters that mean nothing to a computer. In order to obtain useful information we have to run the code through a few procedures. First, we should turn the stream of characters into words and second, turn the words into sentences.

The first step of turning the characters into words is done by a tokenizer which basically performs lexical analysis of the source code. It runs over the characters and groups them into series of “tokens” (and it also determines their type – identifiers, operators, constants…). After the tokenizer (it’s also called a lexer BTW) finishes its job, we get an array which can be illustrated like this:

[Identifier foo][Operator equals][Integer 2][Operator plus][Integer 3][Operator multiply][Integer 4]

This is a higher level structure that contains “words” instead of the raw characters.

The resulting tokens are fed into a parser. It performs semantic analysis of the tokens and assembles them into machine instructions. In simpler words, it constructs sentences out of the words (tokens) and makes sense out of them (i.e. compiles instructions out of them). For instance if the parser is given a statement 2 + 3; i++; as tokens the parser must first separate the tokens into “sentences” (2 + 3 and i++) and then actually understand them (the first is add operation and second is an increment). After we understand the instruction we can actually compile instructions to the machine out of the input.

After the parsing the tokens of our string we get the following instructions:

push 2
push 3
push 4
multiply
assign "foo"

These are instructions that a computer can execute. Compress it to a binary format and you’ve got bytecode. Bytecode is a list of instructions that a machine is very good at processing and when processed in order yield the desired results.

The Interpreter

After we compiled the source code to bytecode we can execute it with a virtual machine. The VM is software that executes the bytecode one instruction at a time, so let’s just walk through the interpretation of our statement:

1. push 2 — The command is to push the number 2 into the stack. The VM maintains a stack during execution which the commands can operate on, that is to push into and pop off values (http://en.wikipedia.org/wiki/Stack_(data_structure)). Currently the stack looks like this : [2]
2. push 3 — push another integer into the stack. Now it looks like [2, 3];
3. push 4 — push yet another integer into the stack. Now it looks like [2, 3, 4];
4. multiply — this command pops 2 values off the stack, multiplies them and pushes the result back to the stack. It pops the values 3 and 4 (which are currently on the top of the stack), multiplies them and pushes the resulting 12 to the stack. It affects the stack to look like [2, 12];
5. add — you’ve probably guessed it: The command pop 12 and 2 off the stack, adds them and pushes the resulting 14 into the stack. Now only 14 remains inside the stack.
6. assign "foo" — This command pops a value off the stack and assign it to a variable named foo. So now the variable foo contains value of 14 and the stack is empty.

That’s it! This is an example of an extremely simple statement executed of an extremely simple virtual machine. Let’s examine a slightly more complicated example:

bar = 12 / (4 + 2) - (6 - 9) * 3

This may compile to (I say “may” because there are different ways to compile the statement):

push 12
push 4
push 2
divide
push 6
push 9
subtract
push 3
multiply
subtract
assign "bar"

This will be interpreted like:

1. The first 3 pushes will be added to the stack: [12, 4, 2]
2. add — will sum the 2 values at the top of the stack: [12, 6]
3. divide — will pop 6, then pop 12, divide 12 by 6 and push the result to the stack: [2]
4. The next 2 commands will push integers into the stack: [2, 6, 9]
5. subtract — will subtract the 2 numbers at the top of the stack. Will pop 9, then 6, then subtract 6 from 9 and push the result to the stack: [2, -3]
6. Another integer will be pushed to the stack: [2, -3, 3]
7. multiply — will pop and multiply the 2 numbers at the top of the stack. -9, which is 3 times -3, will be pushed back to the stack: [2, -9]
8. subtract — will subtract -9 from 2 and push the result to the stack: [11]
9. assign — will pop 11 and assign it to a variable named “bar”. Stack is now empty.

The result is now stored inside a variable named “bar” and it is 11. Yay!

Conclusion

That’s the most basic information about a VM, it might come in handy when you start learning some low-level Flash Player stuff. The VM inside the Flash Player is of course much more complex but the base is the same as in the example presented above.

If you want to learn more about the ActionScript Virtual Machine you can take a look at this PDF document by Adobe. Thanks for reading!

• K Manny

Very Fundamental aspect of how the Adobe Flash Player functions.

trace(“AVM2 is awesome”)

• Chrysto Panayotov

Understanding how AVM works can help you improve your code – Now I always try do less calculations to run faster, in if(){}else{} if I got only two conditions I use if ? do : else do …. Also remember that multiplying is always faster tha devision – use “* 0.5″ instead of “/2″ .

• http://www.thedevelopertuts.com Bratu Sebastian

Great info, I always loved assembler structures ( Even if its AVM ) :)
So … var a = 2 ^ 6 ( power ) would be:

push 2
push 2
multiply
push 2
multiply
push 2
multiply
push 2
multiply
push 2
multiply
assign “a”

Thats it, I’m making my own spoken code language :))

• .

push 2
push 2
push 2
push 2
push 2
push 2
multiply
multiply
multiply
multiply
multiply
assign “a”

• Jackal