ActionScript 3.0 is compiled to ABC, ActionScript Byte Code, for the AVM2. An ABC file holds a constant pool, the signatures of every method, the classes, the scripts and the method bodies with their AVM2 instructions. In a SWF, from SWF 9, it sits in a DoABC tag. The layout is from Adobe’s ActionScript Virtual Machine 2 (AVM2) Overview of May 2007, checked against Tamarin and RABCDAsm. Every ABC file in the movies examined for this site is version 46.16.
DoABC (82, SWF 9)
| Type | Name | Meaning |
|---|---|---|
| UI32 | Flags | Bit 0, kDoAbcLazyInitializeFlag: parse the ABC lazily. The flags are 0 or 1 |
| STRING | Name | A name for the ABC; may be empty |
| bytes | ABCData | The ABC file, to the end of the tag |
Flex 3 applications write flags 1 and names such as frame1, one ABC a
frame; a Flex debug build writes one DoABC a class, named by its path, such as
mx/core/IChildList; other tools write flags 0 and an empty name. The code
runs only when FileAttributes
sets the ActionScript3 flag. SymbolClass
links characters to the classes, character 0 being the document class.
Tag 72 (DoABCDefine, not in the specification)
The ABC file with no flags and no name: the whole body is the ABC. The specification documents only tag 82. That tag 72 came from Flash Player 9’s pre-release tools is an inference from its absence there; JPEXS calls 72 DoABC and 82 DoABC2. No movie examined for this site has one.
Numbers in ABC
| Type | Encoding |
|---|---|
| u8, u16 | Plain little-endian |
| u30, u32 | One to five bytes, seven bits each, lowest group first; the top bit (0x80) is set while another byte follows. The fifth byte adds its low four bits as bits 28 to 31. A u30 must be below 230 |
| s32 | The same bytes, taken as a 32-bit two’s-complement number. Tamarin and RABCDAsm do not sign-extend shorter forms, so a one-byte 0x7F is +127 and negative numbers are written in five bytes |
| s24 | Three bytes, little-endian, two’s complement: branch offsets |
| d64 | An IEEE 754 double, little-endian |
FF 81 FC 07 as an s32: 0x7F + 0x01 × 27 + 0x7C ×
214 + 0x07 × 221 = 16,711,935, which is 0xFF00FF.
abcFile
| Type | Name | Meaning |
|---|---|---|
| u16 | minor_version | 16 in files from the Flash and Flex compilers |
| u16 | major_version | 46 |
| cpool_info | constant_pool | Numbers, strings, namespaces and names |
| u30 | method_count | |
| method_info × method_count | method | Every method, function, initialiser and closure |
| u30 | metadata_count | |
| metadata_info × metadata_count | metadata | |
| u30 | class_count | |
| instance_info × class_count | instance | All the instance halves first … |
| class_info × class_count | class | … then all the class halves, with no second count |
| u30 | script_count | |
| script_info × script_count | script | The last script is the entry point |
| u30 | method_body_count | |
| method_body_info × method_body_count | method_body |
A major version of 47 with minors 12 to 14 is reported for a float extension that never shipped in released players; that is not confirmed.
Constant pool
Seven pools, in this order, each a u30 count and then the entries. Every count is the number of entries plus one: entry 0 is implied and not stored, and a count of 0 or 1 means the pool is empty.
| Pool | Entry | Entry 0 means |
|---|---|---|
| int_count, integer | s32 | 0 |
| uint_count, uinteger | u32 | 0 |
| double_count, double | d64 | NaN |
| string_count, string | string_info | The empty name, or no string |
| namespace_count, namespace | namespace_info | Any namespace (*) |
| ns_set_count, ns_set | ns_set_info | – |
| multiname_count, multiname | multiname_info | Any name (*) |
Integers
Signed 32-bit integers, each an s32, for pushint and for the default
values of int slots.
Unsigned integers
Unsigned 32-bit integers, each a u32, for pushuint and
uint defaults.
Doubles
Eight-byte IEEE doubles, little-endian, for pushdouble and
Number defaults.
Strings
Each string_info is a u30 size in bytes, then that many bytes of UTF-8, with no terminating zero. Every name in the file, of classes, methods, properties and packages, is an index into this pool.
Namespaces
Each namespace_info is a u8 kind and a u30 name, a string index.
| Kind | Name | In ActionScript 3 |
|---|---|---|
| 0x08 | Namespace | A user namespace, namespace foo = "uri", and interface method namespaces |
| 0x16 | PackageNamespace | Public in a package; the name is the package, empty for the top level |
| 0x17 | PackageInternalNs | internal |
| 0x18 | ProtectedNamespace | protected |
| 0x19 | ExplicitNamespace | An explicit namespace |
| 0x1A | StaticProtectedNs | static protected |
| 0x05 | PrivateNs | private; each private namespace is distinct, even with the same name |
Namespace sets
Each ns_set_info is a u30 count and that many u30 namespace indexes, never 0. A
multiname with a set is looked up in each of its namespaces, as a name is found
through the open imports.
Multinames
Each multiname_info is a u8 kind and data by kind. The kinds ending in A name XML
attributes, @x.
| Kind | Name | Data |
|---|---|---|
| 0x07 | QName | u30 ns, u30 name |
| 0x0D | QNameA | u30 ns, u30 name |
| 0x0F | RTQName | u30 name; the namespace is taken from the stack at run time |
| 0x10 | RTQNameA | u30 name |
| 0x11 | RTQNameL | None; namespace and name from the stack |
| 0x12 | RTQNameLA | None |
| 0x09 | Multiname | u30 name, u30 ns_set |
| 0x0E | MultinameA | u30 name, u30 ns_set |
| 0x1B | MultinameL | u30 ns_set; the name from the stack |
| 0x1C | MultinameLA | u30 ns_set |
| 0x1D | TypeName | u30 qname (a multiname index), u30 param_count, u30 params[param_count]: Vector.<T>, Flash Player 10. Not in the 2007 overview; the layout is from Tamarin and RABCDAsm |
method_info
| Type | Name | Meaning |
|---|---|---|
| u30 | param_count | The formal parameters |
| u30 | return_type | A multiname index; 0 is any type (*) |
| u30 × param_count | param_type | Multiname indexes; 0 is any type |
| u30 | name | A string index, for debugging only, such as mx.core:UIComponent/get width; not the name the method is called by |
| u8 | flags | Below |
| option_info | options | If HAS_OPTIONAL: u30 option_count, then option_count × (u30 val, u8 kind), the defaults of the last option_count parameters |
| u30 × param_count | param_names | If HAS_PARAM_NAMES: string indexes |
| Flag | Name | Meaning |
|---|---|---|
| 0x01 | NEED_ARGUMENTS | Make an arguments object |
| 0x02 | NEED_ACTIVATION | Make an activation object: the method has closures or with |
| 0x04 | NEED_REST | ...rest: extra arguments as an Array |
| 0x08 | HAS_OPTIONAL | Options follow |
| 0x10 | IGNORE_REST | Rarely used; its meaning in practice is not confirmed |
| 0x20 | NATIVE | Implemented by the player; no body |
| 0x40 | SET_DXNS | The method sets the default XML namespace |
| 0x80 | HAS_PARAM_NAMES | Parameter names follow |
An option’s kind, and a slot’s vkind, says which pool its value index is in:
| Kind | Name | Index into |
|---|---|---|
| 0x03 | Int | The integer pool |
| 0x04 | UInt | The unsigned integer pool |
| 0x06 | Double | The double pool |
| 0x01 | Utf8 | The string pool |
| 0x0B | True | None; the index is ignored |
| 0x0A | False | None |
| 0x0C | Null | None |
| 0x00 | Undefined | None |
| 0x08, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x05 | The namespace kinds | The namespace pool |
metadata_info
| Type | Name | Meaning |
|---|---|---|
| u30 | name | A string index: the tag’s name, such as Embed, Event or Bindable |
| u30 | item_count | |
| u30 × item_count | keys | String indexes; 0 for a value with no key |
| u30 × item_count | values | String indexes |
The overview draws the items as key and value pairs; the compilers, Tamarin and
RABCDAsm write all the keys and then all the values, and the explorer reads them that
way. The size is the same either way. Only metadata the compiler is told to keep is
written: Flex keeps Bindable, Event and a few others.
instance_info
| Type | Name | Meaning |
|---|---|---|
| u30 | name | A multiname index, a QName: the class |
| u30 | super_name | A multiname index: the base class; 0 for none (Object itself, interfaces) |
| u8 | flags | ClassSealed 0x01 (not dynamic), ClassFinal 0x02, ClassInterface 0x04, ClassProtectedNs 0x08 |
| u30 | protectedNs | If ClassProtectedNs: a namespace index |
| u30 | intrf_count | |
| u30 × intrf_count | interface | Multiname indexes of the interfaces it implements |
| u30 | iinit | A method index: the constructor |
| u30 | trait_count | |
| traits_info × trait_count | trait | The instance members |
class_info
| Type | Name | Meaning |
|---|---|---|
| u30 | cinit | A method index: the static initialiser, run by newclass |
| u30 | trait_count | |
| traits_info × trait_count | traits | The static members |
Class i’s class_info goes with instance_info i.
script_info
| Type | Name | Meaning |
|---|---|---|
| u30 | init | A method index: the script initialiser |
| u30 | trait_count | |
| traits_info × trait_count | traits | What the script defines in the global scope: classes, functions, variables |
A script’s initialiser runs when a name it defines is first needed; the last script in the file runs at once.
method_body_info
| Type | Name | Meaning |
|---|---|---|
| u30 | method | The method_info this is the body of |
| u30 | max_stack | The deepest operand stack |
| u30 | local_count | Registers: 0 is this, then the parameters, then locals |
| u30 | init_scope_depth | The scope stack depth on entry |
| u30 | max_scope_depth | The deepest scope stack |
| u30 | code_length | |
| u8 × code_length | code | The instructions |
| u30 | exception_count | |
| exception_info × exception_count | exception | |
| u30 | trait_count | |
| traits_info × trait_count | trait | The activation object’s slots: locals captured by closures |
Native methods and interface methods have no body.
exception_info
| Type | Name | Meaning |
|---|---|---|
| u30 | from | Start of the try block, a code offset |
| u30 | to | Its end |
| u30 | target | The handler |
| u30 | exc_type | A multiname: the type caught; 0 for any |
| u30 | var_name | A multiname: the catch variable; 0 for a finally block |
traits_info
| Type | Name | Meaning |
|---|---|---|
| u30 | name | A multiname index, a QName |
| u8 | kind | The low four bits are the kind, the high four the attributes |
| by kind | data | Below |
| u30, u30 × count | metadata_count, metadata | Only with the Metadata attribute: indexes into the metadata array |
| Kind | Name | Data |
|---|---|---|
| 0 | Slot | u30 slot_id, u30 type_name (multiname), u30 vindex, u8 vkind if vindex is not 0 |
| 1 | Method | u30 disp_id, u30 method |
| 2 | Getter | u30 disp_id, u30 method |
| 3 | Setter | u30 disp_id, u30 method |
| 4 | Class | u30 slot_id, u30 classi (an index into the instance and class arrays) |
| 5 | Function | u30 slot_id, u30 function (a method index) |
| 6 | Const | As Slot |
The attributes are Final 0x1, Override 0x2 and Metadata 0x4. A slot_id or disp_id of 0 lets the AVM2 choose one. A slot’s vkind is one of the constant kinds.
A worked example
An uncompressed SWF 14 movie, a Flex 4.6 debug build. Its first tags are
FileAttributes (44 11 19 00 00 00: HasMetadata, ActionScript3 and
UseNetwork), Metadata, EnableDebugger2, DebugID, ScriptLimits, SetBackgroundColor,
ProductInfo and FrameLabel. The first DoABC follows at 0x265:
00000265 BF 14 E3 07 00 00 01 00 00 00 6D 78 2F 63 6F 72
00000275 65 2F 49 46 6C 65 78 4D 6F 64 75 6C 65 46 61 63
00000285 74 6F 72 79 00 10 00 2E 00 00 00 00 47 00 4A 45
00000295 3A 5C 64 65 76 5C …
BF 14 is code 82 in the long form, 0x07E3 = 2,019 bytes;
flags 1, lazy; the name mx/core/IFlexModuleFactory, one ABC a class as
Flex debug builds write; then the ABC from 0x28A| Bytes | Field | Value |
|---|---|---|
10 00 | minor_version | 16 |
2E 00 | major_version | 46 |
00 | int_count | 0: no integers |
00 | uint_count | 0: none |
00 | double_count | 0: none |
47 | string_count | 71: 70 strings follow |
00 | string[1] | “”, length 0 |
4A 45 3A 5C … | string[2] | 74 bytes: E:\dev\4.y\frameworks\projects\framework\src;mx\core;IFlexModuleFactory.as, a source file path of the kind debug builds record for debugfile |
4F 6D 78 2E … | string[3] | 79 bytes, beginning mx.core:IFlexModuleFactory/mx.core:IFlexModuleFactory:allowDoma: a method’s debugging name |
What an ActionScript 3 class becomes
package com.example {
import flash.display.Sprite;
public class Main extends Sprite {
public static var count:int = 0;
private var b:int;
public function Main() { super(); }
public function go(x:int):void { b = x; }
}
}
The Flex compiler and Flash CS3 and later both write:
- Multinames
QName(package com.example, "Main")andQName(package flash.display, "Sprite"), and QNames forcount(PackageNamespace “”),b(PrivateNs) andgo. - An instance_info: name Main, super_name Sprite, flags ClassSealed and
ClassProtectedNs with a ProtectedNamespace “com.example:Main”, iinit the
constructor, and the traits
Slot b:intandMethod go. - A class_info at the same index: cinit, the static initialiser, and the trait
Slot count:int, with its default as vindex and vkind, or set in cinit’s code instead. - A method_info for the constructor, cinit,
go(param_count 1, param_type int, return_type void) and the script initialiser, and a method_body_info for each. A constructor body usually startsgetlocal_0; pushscope; getlocal_0; constructsuper 0. - A script_info whose traits hold
Class Main, and whose init method builds the class: it pushes the scope of each base class in turn (getscopeobject 0,getlex Object,pushscope,getlex flash.events.EventDispatcher,pushscope…), thengetlex Sprite,newclass, thepopscopes andinitproperty Main.
A movie compiled by Flash CS3 or later with timeline code also has a class for each
timeline, such as MainTimeline, with each frame’s code as a method
frame1, frame2 … registered with addFrameScript
in the constructor. See also ActionScript 3.0
compiled bytecode.