New topics: Your Pet, IOU, Baby IQ, The Poisons, Birther II, Games, Future Power

Welcome to the Tech Space!

Microsoft Related

Skip to end of metadata
Go to start of metadata

Flash virtual machine

Stack
Constant pool
Global registers
Local registers

Every ActionScript statement is compiled by Flash into a couple of simple bytecode actions. For example, a=b*b; is transformed into

constants 'a', 'b'
push 'a', 'b'
getVariable
push 'b'
getVariable
multiply
setVariable

The bytecodes are stored in SWF in binary form. They are interpreted by the virtual machine of the Flash Player. The code above is the visual representation of the bytecodes, created by Flasm.

I'll call actions inside of a frame or event action blocks. Flash executes action blocks one after another, so the execution flow inside of a block is never interrupted, neither by event nor by gotoAndPlay() or similar actions. Real parallel execution would be nicer? I'm sure it would dramatically affect player stability, which is great now, considering all things going on in a complex movie.

Stack

Flash virtual machine is stack based, you can not refer to the particular memory location. The stack is a place in memory where data can be stored so that the last entered (pushed) value will be extracted (popped) first from the stack. Every command reads (and pops) operands from stack and pushes the result (if any) onto the stack.

The stack may contain elements of arbitrary type --- integers, strings, floats and some others. If needed, type conversion happens during execution --- like in ActionScript. Often there's no difference between the string '10', integer 10 or double 10.0.

Further stack explanation by Robert Penner:
If you're familiar with Array.push and Array.pop, those commands are similar to stack manipulations. The stack is like an array of values, except you can only access the value on top, push another value onto the top, or swap the top two values.
For instance, to add two numbers, you have to push both of them onto the stack, then call add. The add command will pop the top two values off the stack, add them together, and push the value onto the stack.
The pop action leads to no errors if the stack is empty. The special UNDEF value is popped then, that corresponds to the ActionScript's undefined.

These two actions give you additional functionality for stack handling: dup and swap. dup duplicates the value on top of the stack, swap swaps the two topmost values. Currently Flash doesn't use dup and swap very often as you'll see in disassembly, but they are of great importance for optimization.

Every ActionScript statement, regardless of its complexity, leaves the stack empty after execution. In Flash IDE you don't see the bytecodes and don't have to worry about it. Making changes to bytecodes with Flasm, however, you should always count what's on stack. Improper stack manipulation often doesn't lead to any errors in Flash player. You will not see the 10.000 dead stack entries your loop produced, but the execution will slow down and the SWF probably runs out of memory at some point.

The stack was global in Flash 5. If the value was pushed in frame 1, frame 5 could trace it successfully. It was accessible in movie clips too. With Flash MX the situation changed: Flash Players 6 and 7 flush stack contents after every action block.

Constant pool

At the beginning of every action block where variables, methods or strings are used more than once, Flash creates so called constant pool. In fact, if at least one variable is used twice, the pool is created for all strings in the block. Here is an example:

constants 'bottom', 'paused', 'aliensleft', 'fire'

Constant pool can hold up to 65535 strings (in theory). These can be addressed later in your actions with 1 byte (first 256 strings in the pool) or 2 byte (the rest of the pool) reference. Commonly no more than 256 strings are stored, so you rarely meet 2 byte references in SWF. Practically the number of strings is limited by overall size of constants action, which can't exceed 65535 bytes like any other action.

Flasm disassembler abstracts constant references away by default. They are showed as strings. To see actual references in disassembly, set literalconstants option in flasm.ini to 0. The difference between strings and constant pool members will be obvious then.

Writing push c:1 after the above constants definition means push second constant from the pool (counting from 0). Writing push 'paused' will in turn have the same effect, because Flasm finds the constant in the pool automatically and substitutes string with reference during assembly.

If no previous constant pool declaration is found in the same action block, however, the string 'paused' will be pushed as is. The difference is in code size only, not in execution speed --- naturally, the string 'paused' takes five bytes more than one-byte reference. Don't forget to add your strings to the constant pool.

In update mode (flasm -u foo.swf) Flasm rebuilds all constants, removing empty strings and those referenced only once.

The constant pool defined at the start of the frame is valid for every function in this frame. I've never seen constants defined in functions in disassembly. Every event has its own constant pool though.

Although Flash itself never redefines constant pool in the middle of the action block, theoretically you're allowed to do this. Flasm disassembler versions < 1.52 couldn't really deal with multiple constant pools. Flasm 1.52 will show constant references in c:xx form. To always show strings (resembles Flasm < 1.52 behavior, may be inaccurate) set literalconstants to 2.

Global registers

Flash virtual machine has 4 global registers that are addressed r:0, r:1, r:2, r:3. Accessing variables is much slower than accessing registers, so you should store your most used variables there. Flash versions before MX 2004 only used r:0, so there was enough room for optimization. Flash MX 2004's compiler, however, may substitute local variables with other registers --- a very good reason to use local variables in ActionScript.

To store something in a register, you should first put this something onto the stack and then execute setRegister command:

push 'paused'
getVariable
setRegister r:1

Now the value of variable paused is stored in r:1. Instead of asking for paused next time, use push r:1.
Note: Unlike most other commands, setRegister does not pop the top value from stack! If you don't need the value stored in register to be on stack, you should manually pop it.

The value of global register, defined in a particular frame on _root, is available to all functions in this frame. If some function is defined or movie clip happens here, it can access or overwrite the register too. It looks like after the showFrame tag occurs in SWF, registers disappear. Generally you don't know what happens to the global register. Of course, calling function A from the middle of function B should leave registers untouched. Flash MX 2004's compiler takes care of it --- at the start of the function registers are saved on stack, at the end original values are restored. You should pay some attention here, too.

Local registers

Inside of function2 (Flash Player 6.0.65 and above), and only there, up to 255 local registers exist --- from r:0 to r:254. Why not 256? In the function2 header, the number of local registers used in this function is stored in a byte. At the start of function2 the place for local registers is allocated somewhere in memory. The highest possible value for a byte is 255.

Generally, you don't have to care about the number of allocated registers --- Flasm calculates this number automatically, and it's not shown in disassembly. Please take consequent registers numbers --- using r:1 and r:254 only forces Flasm and Flash Player to allocate 255 registers, which may have impact on memory.

Since local registers are addressed by the same bytecodes as global registers --- setRegister and push r:something, function2 has no access to the global registers. Even more confusing is the scope --- imagine you have frame A, function2 B inside of A, and function C inside of B. Now function2 B nicely has its own set of registers, and is totally unaware of global registers. That's OK. But function C will share four global registers with frame A!

Besides of all that, local registers function just like global ones. There's no speed difference, too. To summarize: in SWF7 there are still four global registers everywhere outside function2, but any function2 may allocate a set of 255 local registers.

References

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.