The code of each method body in an ABC file is a run of AVM2 instructions. Each is a one-byte opcode followed by its operands. The AVM2 is a stack machine with local registers and a scope stack: instructions take their inputs from the operand stack and push their results.
Operands
Operands are u30 unless the table says otherwise. In the table, “mn” is a multiname index, “string” a string pool index, and “register” a local register number. In the stack column, values before the arrow are popped and after it pushed; “[ns], [name]” are the parts a run-time multiname (RTQName, MultinameL and the rest) takes from the stack.
Branch offsets are s24, counted from the end of the branch instruction, after its 3-byte operand. lookupswitch is the exception: its default and case offsets count from the start of the lookupswitch instruction itself; its operands are s24 default, u30 case_count, then case_count + 1 s24 offsets.
Instructions marked U are not described in Adobe’s May 2007 AVM2 Overview; their names and operands are from Tamarin’s opcode table and RABCDAsm. Which instructions the overview leaves out was checked from memory of it, not against the document again.
A small example
A constructor body usually begins like this:
D0 30 D0 49 00 47
getlocal_0 (this), pushscope,
getlocal_0, constructsuper 0 (the base class constructor
with no arguments), returnvoidAll instructions
| Hex | Name | Operands | Stack and meaning |
|---|---|---|---|
| 01 | bkpt U | – | Debugger breakpoint |
| 02 | nop | – | Nothing |
| 03 | throw | – | value → throws it |
| 04 | getsuper | mn | obj, [ns], [name] → the value from the base class |
| 05 | setsuper | mn | obj, [ns], [name], value → |
| 06 | dxns | string | Sets the default XML namespace |
| 07 | dxnslate | – | value → sets the default XML namespace |
| 08 | kill | register | Sets the register to undefined |
| 09 | label | – | Marks the target of a backward branch |
| 0C | ifnlt | s24 | a, b → branch unless a < b |
| 0D | ifnle | s24 | a, b → branch unless a <= b |
| 0E | ifngt | s24 | a, b → branch unless a > b |
| 0F | ifnge | s24 | a, b → branch unless a >= b |
| 10 | jump | s24 | Always branches |
| 11 | iftrue | s24 | v → branch if true |
| 12 | iffalse | s24 | v → branch if false |
| 13 | ifeq | s24 | a, b → branch if a == b |
| 14 | ifne | s24 | a, b → branch if a != b |
| 15 | iflt | s24 | a, b → branch if a < b |
| 16 | ifle | s24 | a, b → branch if a <= b |
| 17 | ifgt | s24 | a, b → branch if a > b |
| 18 | ifge | s24 | a, b → branch if a >= b |
| 19 | ifstricteq | s24 | a, b → branch if a === b |
| 1A | ifstrictne | s24 | a, b → branch if a !== b |
| 1B | lookupswitch | s24 default, u30 case_count, s24 × (case_count + 1) | index → branch to that case, or the default |
| 1C | pushwith | – | obj → onto the scope stack as a with scope |
| 1D | popscope | – | Pops the scope stack |
| 1E | nextname | – | obj, index → name (for … in) |
| 1F | hasnext | – | obj, index → the next index, or 0 |
| 20 | pushnull | – | → null |
| 21 | pushundefined | – | → undefined |
| 23 | nextvalue | – | obj, index → value (for each … in) |
| 24 | pushbyte | u8, signed | → int |
| 25 | pushshort | u30, used as a signed 16-bit number | → int |
| 26 | pushtrue | – | → true |
| 27 | pushfalse | – | → false |
| 28 | pushnan | – | → NaN |
| 29 | pop | – | v → |
| 2A | dup | – | v → v, v |
| 2B | swap | – | a, b → b, a |
| 2C | pushstring | string | → String |
| 2D | pushint | integer pool index | → int |
| 2E | pushuint | unsigned integer pool index | → uint |
| 2F | pushdouble | double pool index | → Number |
| 30 | pushscope | – | obj → onto the scope stack |
| 31 | pushnamespace | namespace index | → Namespace |
| 32 | hasnext2 | register, register | → Boolean; steps the object and index registers |
| 35 | li8 U | – | addr → int: a byte from domain memory (“Alchemy”, Flash Player 10) |
| 36 | li16 U | – | addr → int |
| 37 | li32 U | – | addr → int |
| 38 | lf32 U | – | addr → Number |
| 39 | lf64 U | – | addr → Number |
| 3A | si8 U | – | value, addr → stores a byte in domain memory |
| 3B | si16 U | – | value, addr → |
| 3C | si32 U | – | value, addr → |
| 3D | sf32 U | – | value, addr → |
| 3E | sf64 U | – | value, addr → |
| 40 | newfunction | method | → Function, a closure |
| 41 | call | arg_count | function, receiver, args → value |
| 42 | construct | arg_count | obj, args → a new object |
| 43 | callmethod | disp_id, arg_count | receiver, args → value |
| 44 | callstatic | method, arg_count | receiver, args → value |
| 45 | callsuper | mn, arg_count | receiver, [ns], [name], args → value |
| 46 | callproperty | mn, arg_count | obj, [ns], [name], args → value |
| 47 | returnvoid | – | Returns undefined |
| 48 | returnvalue | – | v → returns v |
| 49 | constructsuper | arg_count | obj, args → (runs the base class constructor) |
| 4A | constructprop | mn, arg_count | obj, [ns], [name], args → a new object |
| 4C | callproplex | mn, arg_count | As callproperty, with a null receiver |
| 4E | callsupervoid | mn, arg_count | As callsuper, the result dropped |
| 4F | callpropvoid | mn, arg_count | As callproperty, the result dropped |
| 50 | sxi1 U | – | v → int, sign-extended from 1 bit |
| 51 | sxi8 U | – | v → int, sign-extended from 8 bits |
| 52 | sxi16 U | – | v → int, sign-extended from 16 bits |
| 53 | applytype U | arg_count | factory, types → type, as in Vector.<int> (Flash Player 10) |
| 55 | newobject | arg_count | name1, value1 … → Object |
| 56 | newarray | arg_count | values → Array |
| 57 | newactivation | – | → an activation object |
| 58 | newclass | class index | base class → class; runs its cinit |
| 59 | getdescendants | mn | obj, [ns], [name] → XMLList (..) |
| 5A | newcatch | exception index | → a catch scope object |
| 5D | findpropstrict | mn | [ns], [name] → the object holding the name, or a ReferenceError |
| 5E | findproperty | mn | [ns], [name] → the object holding the name, or the global object |
| 5F | finddef U | mn | → the script object that defines the name |
| 60 | getlex | mn | → value: findpropstrict and getproperty in one |
| 61 | setproperty | mn | obj, [ns], [name], value → |
| 62 | getlocal | register | → value |
| 63 | setlocal | register | value → |
| 64 | getglobalscope | – | → the global scope object |
| 65 | getscopeobject | u8 index | → a scope object |
| 66 | getproperty | mn | obj, [ns], [name] → value |
| 67 | getouterscope U | u30 | → an outer scope object (Tamarin internal) |
| 68 | initproperty | mn | obj, [ns], [name], value → initialises a property, constants too |
| 69 | setpropertylate U | – | Tamarin internal |
| 6A | deleteproperty | mn | obj, [ns], [name] → Boolean |
| 6B | deletepropertylate U | – | Tamarin internal |
| 6C | getslot | slot | obj → value |
| 6D | setslot | slot | obj, value → |
| 6E | getglobalslot | slot | → value |
| 6F | setglobalslot | slot | value → |
| 70 | convert_s | – | v → String |
| 71 | esc_xelem | – | v → String escaped for XML element content |
| 72 | esc_xattr | – | v → String escaped for an XML attribute |
| 73 | convert_i | – | v → int |
| 74 | convert_u | – | v → uint |
| 75 | convert_d | – | v → Number |
| 76 | convert_b | – | v → Boolean |
| 77 | convert_o | – | v → v, or a TypeError if null or undefined |
| 78 | checkfilter | – | v → v, or a TypeError unless XML or XMLList |
| 80 | coerce | mn | v → v coerced to the type |
| 81 | coerce_b U | – | v → Boolean |
| 82 | coerce_a | – | v → v as * |
| 83 | coerce_i U | – | v → int |
| 84 | coerce_d U | – | v → Number |
| 85 | coerce_s | – | v → String; null stays null |
| 86 | astype | mn | v → v or null |
| 87 | astypelate | – | v, class → v or null |
| 88 | coerce_u U | – | v → uint |
| 89 | coerce_o U | – | v → Object |
| 90 | negate | – | v → −v |
| 91 | increment | – | v → v + 1 |
| 92 | inclocal | register | register += 1 |
| 93 | decrement | – | v → v − 1 |
| 94 | declocal | register | register −= 1 |
| 95 | typeof | – | v → String |
| 96 | not | – | v → !v |
| 97 | bitnot | – | v → ~v |
| A0 | add | – | a, b → a + b |
| A1 | subtract | – | a, b → a − b |
| A2 | multiply | – | a, b → a × b |
| A3 | divide | – | a, b → a ÷ b |
| A4 | modulo | – | a, b → a % b |
| A5 | lshift | – | a, b → a << b |
| A6 | rshift | – | a, b → a >> b |
| A7 | urshift | – | a, b → a >>> b |
| A8 | bitand | – | a, b → a & b |
| A9 | bitor | – | a, b → a | b |
| AA | bitxor | – | a, b → a ^ b |
| AB | equals | – | a, b → a == b |
| AC | strictequals | – | a, b → a === b |
| AD | lessthan | – | a, b → a < b |
| AE | lessequals | – | a, b → a <= b |
| AF | greaterthan | – | a, b → a > b |
| B0 | greaterequals | – | a, b → a >= b |
| B1 | instanceof | – | v, type → Boolean, by the prototype chain |
| B2 | istype | mn | v → Boolean |
| B3 | istypelate | – | v, type → Boolean |
| B4 | in | – | name, obj → Boolean |
| C0 | increment_i | – | v → int(v) + 1 |
| C1 | decrement_i | – | v → int(v) − 1 |
| C2 | inclocal_i | register | register = int(register) + 1 |
| C3 | declocal_i | register | register = int(register) − 1 |
| C4 | negate_i | – | v → −int(v) |
| C5 | add_i | – | a, b → int(a) + int(b) |
| C6 | subtract_i | – | a, b → int(a) − int(b) |
| C7 | multiply_i | – | a, b → int(a) × int(b) |
| D0 | getlocal_0 | – | → register 0, this |
| D1 | getlocal_1 | – | → register 1 |
| D2 | getlocal_2 | – | → register 2 |
| D3 | getlocal_3 | – | → register 3 |
| D4 | setlocal_0 | – | v → register 0 |
| D5 | setlocal_1 | – | v → register 1 |
| D6 | setlocal_2 | – | v → register 2 |
| D7 | setlocal_3 | – | v → register 3 |
| EF | debug | u8 debug_type, string, u8 register, u30 extra | Debugging information; type 1 names a local register |
| F0 | debugline | u30 line | The source line of what follows |
| F1 | debugfile | string | The source file of what follows |
| F2 | bkptline U | u30 line | A breakpoint at a line |
| F3 | timestamp U | – | Profiling |
Opcodes that were never used
These are named in Tamarin and RABCDAsm but no released compiler writes them, and
their operands are not known to the explorer, which stops decoding a method body at
one and says so. The _p, _m and decimal ones belong to
decimal-number support that never shipped. None occurs in the movies examined for this
site.
| Hex | Name | Hex | Name |
|---|---|---|---|
| 22 | pushuninitialized | 9C | increment_p |
| 33 | pushdecimal | 9D | inclocal_p |
| 34 | pushdnan | 9E | decrement_p |
| 4B | callsuperid | 9F | declocal_p |
| 4D | callinterface | B5 | add_p |
| 5B | deldescendants | B6 | subtract_p |
| 79 | convert_m | B7 | multiply_p |
| 7A | convert_m_p | B8 | divide_p |
| 8F | negate_p | B9 | modulo_p |
| 9A | concat | 9B | add_d |
Every other byte value is not an instruction.