Reference Guide

This reference guide contains detailed information about all aspects of the Crossbridge toolchain. The sections are laid out roughly in the order in which it makes most sense to learn about, but it is probably a good idea to have one or two of the samples open while reading this through so you can see how things work in practice as well.

Compiling With GCC

Crossbridge uses a version of LLVM-GCC 4.2 with a custom LLVM backend that generates ActionScript bytecode capable of running within the Flash Runtime. More specifically, the bytecode runs in the ActionScript virtual machine (AVM). This lets you compile arbitrary C/C++ code into a managed bytecode format capable of high performance execution within the Flash Runtime on Mac, Windows, or Linux in any supported browser.

Tip: Think of Crossbridge as you would any cross compiler toolchain that targets an architecture that isn't your native system architecture. All of the concepts are the same.

When using GCC to compile a single source file into an object file, you usually only have one choice of object file format: the native format supported by the target architecture. But with LLVM-GCC you have two formats: the native format, and LLVM bitcode.

The native format is used when you want to perform short incremental compiles without any cross-object optimization. Use LLVM bitcode when you want to perform an expensive Link Time Optimized (LTO) build where the majority of the optimization occurs during the final link step.

With Crossbridge, the "native" object format is ActionScript bytecode (ABC). Object files generated as ABC or LLVM bitcode are interchangeable and won't affect your build process, but typically you will either want to perform a quick un-optimized build with all object files compiled to ABC or a final fully-optimized build with everything compiled as LLVM bitcode.

By default the Crossbridge version of GCC will produce ABC:

# test.o will be ABC
gcc test.c -c -o test.o

To generate LLVM bitcode, specify either -emit-llvm or -O4 when invoking GCC:

The whole Crossbridge toolchain understands these object file formats so the standard nm, ar and ranlib tools for inspecting and archiving object files will work on them just as they would work on native object files in a native toolchain.

When performing the final link step you must also specify -emit-llvm or -O4 if you want an LTO build, otherwise the ABC versions of the system libraries (libc, libstdc++, etc) will be used instead of the LLVM bitcode versions.

Executable Formats

With a native toolchain the final output of GCC, when linking your object files together, is typically an executable program suitable for running on the target architecture. With Crossbridge there are two different output formats:

Projectors

SWFs

For example, compile a simple hello world example using the following command:

~/crossbridge/sdk/usr/bin/gcc hello.c -o hello

If you inspect the resulting executable, or attempt to run it, you might be surprised to see it execute; Wasn't Crossbridge supposed to be producing something that doesn't execute natively? By default Crossbridge compiles the program into ABC format and embeds it within a copy of the AVM runtime so that it can run as a native command-line program.

Crossbridge works this way because build systems often try to compile and execute small programs as part of the configure step of their build process to determine certain facts about the environment they are running in. By producing native Projector executables by default, Crossbridge is able to seamlessly work with almost any build system, just include the sdk/usr/bin directory in your shell's PATH variable.

To generate a SWF, the executable format suitable for use in the Flash Runtime, you pass the -emit-swf argument to GCC:

gcc -emit-swf hello.c -o hello.swf

The resulting SWF can run inside your web browser or within the standalone version of the Flash Runtime, and will be significantly smaller than the projector version as it does not include the AVM.

Using Crossbridge With Existing Codebases

To use Crossbridge to compile a codebase that uses a command-line build system like AutoConf, CMake or Make, all you have to do is ensure that the Crossbridge SDK's bin directory appears first in your PATH environment variable when invoking the build command.

The real world examples in the samples directory show this being done for a variety of build systems including CMake (Bullet Physics example) and Make (Lua example). The usual way to invoke a Make file to target Crossbridge is as follows:

PATH="~/crossbridge/sdk/usr/bin":$PATH make

Crossbridge's tools will be chosen in preference to any native tools on your path, but only for the invocation of make, after that your PATH will return to normal.

Building SWCs

A SWC is the Flash Runtime equivalent of a shared library. You can link a SWC into a pure ActionScript project either with an IDE (Flash Builder, for example), or via the command-line ActionScript compiler (named mxmlc). A SWC contains the compiled ActionScript bytecode, along with an API catalog so that Flash Builder can perform code hinting while a developer writes ActionScript that uses the API exposed by a SWC.

When you generate a SWC you must specify an AS3 package name to contain the generated code, and the internal Crossbridge boilerplate code. This lets you link multiple Crossbridge-generated SWCs into one SWF without any function or class collisions. Anywhere you would have previously seen a name starting with com.adobe.flascc this namespace will be replaced with the string passed in the gcc/g++ -emit-swc=... argument.

Crossbridge-Specific GCC Command Line Options

The version of gcc that comes with Crossbridge has several custom options for controlling the generated code. You can see a list of them by running gcc --target-help. The table below gives an explanation of what each option does, and how it can be used.

Option

Explanation

-disable-telemetry

By default Crossbridge generates SWFs that support Adobe Scout's advanced metrics. This means that stack trace information will be visible to anybody profiling the SWF.

-emit-swc=

Emits a SWC that can be linked into a Flash Builder project or distributed for others to link into their own projects. You must specify the namespace that you want to use to replace the default com.adobe.flascc namespace, this lets you link multiple Crossbridge-generated SWCs into a single project.

-emit-swf

Emit a SWF that can be executed by the Flash Runtime.

-enable-debugger

Generate SWF debug information and include it within the SWF. It isn't necessary to specify this option if you already compile your code with -g.

-fllvm-llc-opt=

Pass an argument through to the final invocation of llc (LLVM-IR->ABC codegen). For more information on what options llc accepts read the LLVM documentation.

-fllvm-opt-opt=

Pass an argument through to the final invocation of opt (LLVM-IR->LLVM-IR optimization). For more information on what options opt accepts read the LLVM documentation.

-flto-api=

Specifies a file containing the public API LLVM should preserve (implies that the optimizer is free to strip any symbols not mentioned in this file that aren't referenced by the symbols mentioned in this file)

-no-swf-preloader

By default Crossbridge injects a simple preloader into your SWF, which displays a loading bar until the SWF has downloaded. Use this option to disable the preloader.

-swf-ns=

Performs the same namespace re-writing as the -emit-swc= option when generating a SWF, by default no namespace rewriting takes place when generating a SWF.

-swf-preloader=

Lets you use a custom SWF as the preloader. All of the SWF tags within the specified SWF will be included at the beginning of the generated SWF. To see a sample preloader, review sdk/usr/share/DefaultPreloader.as.

-swf-size=WxH

Specifies the initial width and height of the generated SWF.

-swf-version=

Specifies the SWF version of the generated SWF. Remember that certain APIs will only be available to your code if your SWF version is high enough. By default the SWF version is 18.

-symbol-abc=

If you have compiled a custom Console.as you must point to the location of the ABC so that it can be used as the root sprite within the generated SWF.

-symbol-class=

If you have changed the namespace or name of the class within your Console.as implementation you must specify it here in the form ":0:com.adobe.flascc::Console" where "com.adobe.flascc" is the package name and "Console" is the class name.

Crossbridge-Specific Preprocessor Macros

Crossbridge exposes some non-standard preprocessor macros that you can use to conditionally compile code:

Macro

Value

__AVM2, __AVM2__

1

__FLASHPLAYER, __FLASHPLAYER__

1

__SWF_VER, __SWF_VER__

default: 18, or whatever was passed to GCC via -swf-version=

Optimizing SWFs and SWCs

By default gcc/g++ compiles individual source files into ABC files. All the
tools in the toolchain understand ABC as a native object file format. When
it comes to link time the linker understands how to link multiple ABCs together
to produce a SWF/SWC. This is equivalent to most typical native gcc/g++ workflows,
and supports a fast turn around time.

Although this workflow is great for iterative development it omits
optimizations that require cross-compilation-unit knowledge. To produce more
optimal code we must perform Whole Program Optimization by compiling to LLVM
bitcode instead of ABC and then optimizing the code during the link step when
all the code is available to the optimizer.

Setting the gcc/g++ optimization level to -O4 causes it to produce LLVM
bitcode instead of ABC. This is also a fully supported object file format in the Crossbridge
toolchain. When multiple LLVM bitcode files are given to the linker they are
merged and optimized together, producing more optimal code.

To allow LLVM to optimize your code as much as possible, you must provide a
list of C/C++ symbols that you want to preserve. By doing this, LLVM can choose
to remove unused functions or even rewrite function prototypes in cases where
it thinks that would result in more optimal code. By providing a minimal list
of symbols that must remain with their current name and prototype intact, LLVM
knows how far it can take these kinds of optimizations without breaking your
code.

The Quake1 example uses this kind of optimization to get the best possible
performance. To enable this level of optimization create
a text file with the names of the symbols you want to preserve and pass it to
gcc/g++ using the -flto-api= argument. Any symbol within the Crossbridge generated
code that is referenced from ActionScript must be listed in this file or it might be removed or renamed by LLVM.

Any symbols referenced by your ActionScript must also be listed here. For more examples of exports.txt being used refer to sample 9, sample 11, sample 12, and also the Bullet Physics and Quake 1 examples.

Behind The Scenes: LLVM Bitcode

Using the -O4 option to get whole program optimization should satisfy most use
cases. However if you want to get your hands dirty and explore the possibilities of
some of the more exotic bitcode optimizations and transformations you can
try out some of the llvm tools included in the SDK. Crossbridge is currently based on
LLVM 2.9.

To perform a manual whole program optimized build with special optimizations,
first compile individual source files with -O4 to produce bitcode.
After you have bitcode object files you can merge them into one bitcode file
using llvm-link, optimize the resulting binary with opt and then pass it to
gcc for the final link step.

Crossbridge isn't limited to C and C++; you can use any front end capable of generating LLVM
bitcode. As long as the bitcode doesn't have native dependencies,
simply pass it to the Crossbridge gcc to perform the final codegen and link step.
If you do experiment with other frontends the Crossbridge team would love to hear about your
experience.

Obfuscation

Crossbridge is not designed to be an obfuscator for either ActionScript or C/C++ code. Although the generated ActionScript bytecode should be no easier to reverse engineer than natively compiled machine code the Crossbridge engineering team makes no strong claims about this, nor do they test whether this is true.

By default the mangled C++ name of every source function will be trivially visible in both the decompiled output and also in ActionScript debugger and profilers. To hide the names of any generated C/C++ functions you can pass -fllvm-opt-opt=-strip to gcc so that any function names not listed in your exports.txt file will be renamed to a symbol of the form __unnamed_N. Functions that need to be called from ActionScript, which you must protect by listing in exports.txt, will not be renamed.

For true obfuscation you will need to find a third party solution that either obfuscates the LLVM bitcode or the ActionScript bytecode in the final SWF. A search on the web should yield plenty of results for SWF obfuscators, but the Crossbridge engineering team has not investigated which ones are reliable.

To understand the problem from the other side you might want to play around with various SWF decompilers and ActionScript bytecode disassemblers to get a better understanding of what exactly is in a SWF and how easy/hard it is to extract the various components from it.

Other Tools

Many build systems use a tool called pkg-config as part of their configure step to determine what libraries have been installed on a system, so that dependencies can be validated and compiler options can be setup. Crossbridge ships with a version of pkg-config so that build systems will find the Crossbridge versions of the included libraries rather than the native system libs. The directory for pkg-config files is sdk/usr/lib/pkgconfig/ and you use the variable flascc_sdk_root to make pkg-config paths aware of the actual location of the Crossbridge SDK without having to hardcode the path.

Crossbridge ships with several small python utilities in the sdk/usr/bin directory, which you can use for debugging and inspecting SWFs:

Utility

Description

swf-info.py

Dumps information about the structure of a SWF file including the various tags, SWF version, SWF size, etc.

swfdink.py

Lets you change the SWF version and make the SWF compressed or uncompressed.

projector-dis.py

Breaks apart a shell projector executable into its components.

Interop between C/C++ and ActionScript

The interop between AS3 and C/C++ in Crossbridge is based around the concept of inline assembly. In a native C/C++ workflow you would use inline assembly statements to allow you to pass arbitrary strings containing platform specific instructions to the assembler to be included in your final executable. With Crossbridge the underlying system is the Flash Runtime, and the language it supports natively is AS3, so these inline assembly statements let you talk to the native Flash API set in the language it was designed with.

The GCC syntax for inline assembly allows for a simple form of pattern matching substitution so that C variables can be used by the AS3 code. This mechanism is powerful enough to express all of the interop you would want to do, but it is tedious to write and not type-safe. Here is an example of how you can pass a C variable into ActionScript and return a value back to C using the inline_as3 macro:

#include <AS3/AS3.h>
// Use AS3 to sqrt a double!
double somenumber = 45.0;
double result = 0.0;
inline_as3(
"%0 = Math.sqrt(%1);\n"
: "=r"(result) : "r"(somenumber)
);
// Back in C we can take the result and print it out:
printf("sqrt of %f is %f\n", somenumber, result);

To better understand how to use inline assembly with Crossbridge you will need to have a basic understanding of how the code generation strategy works. Lets take a look at the ActionScript generated for some C and C++ code (simplified for clarity):

The two important things to note about this code generation strategy are that Crossbridge doesn't attempt to synthesize ActionScript classes from C++ classes and there are two different namespaces used during code generation: C_Run (the public package) and a much longer one that contains a globally unique identifier (the private package).

These public and private packages are used to differentiate between functions that should only be visible to other functions within the same compilation unit and functions that should be visible to the rest of the codebase. Because the private package name is unique no other compilation unit will import it and so anything defined within it will be invisible to the rest of the codebase.

When using inline assembly to inject additional ActionScript into the generated code you have a choice between the inline_as3 and package_as3 macros. The former injects code into the body of a generated function and so it can only be used for injecting additional statements and expressions whereas package_as3 can be used to inject global package-level variables, classes, interfaces, etc.

The package_as3 macro will inject its contents into the private package by default, but this can be changed using the "#package" directive within the inline asm:

Although you can define almost anything at package-level scope such as additional ActionScript classes and interfaces you will probably find it best to use it just for things local to the current compilation unit.

Flash++

To make life easier for C++ developers Crossbridge includes the AS3 wrapper interface generator (as3wig.jar), which can generate C++ bindings for any AS3 classes.

The Crossbridge team has applied this tool on the internal AS3 classes in the Flash Runtime to generate a C++ library called Flash++, which exposes all of the Flash APIs as strongly typed C++ classes.

Here is a snippet of C++ code using the Flash++ classes to construct a new sprite and draw a circle into it. If you are familiar with AS3 this should look just like what you would write in AS3 only with C++ syntax. The mySprite and graphics object in this example are both reference-counted wrappers around the actual AS3 objects; they can be stored on the stack or in the heap without fear of their underlying AS3 object being garbage collected.

In order to use the Flash++ library you will need to #include <Flash++.h> and pass the -lFlash++ -lAS3++ compiler arguments to g++. To see a fully working example of the Flash++ interop layer in action look at the c++interop.cpp file in sample 2, the pthreads.cpp file in sample 9 and the Flash++ examples page.

The as3wig tool is included with the Crossbridge SDK so that you can generate bindings for your own ActionScript code. Sample 12 uses as3wig to generate bindings for the AGALAssembler ActionScript codebase and then uses those bindings from C++ at runtime to compile AGAL assembly into AGAL bytecode for use with Stage3D. Take a look at the Makefile for sample 12 to see how to invoke as3wig and how to compile the resulting wrapper code.

Implementing a Console

When running a SWF with the debugger version of the Flash Runtime debug output generated by the ActionScript trace() function can be sent to a file known as the flash log file (flashlog.txt). Information on how to enable this, and where to find the flash log file can be found here.

The Console class is the first class that is created and executed when your SWF loads. It controls when and how the Crossbridge compiled code is initialized. It is also used by the underlying Crossbridge virtual kernel implementation as the object that handles read and write requests to the various standard input, output and error terminal streams. It also handles all fcntl and ioctl calls. If you aren't familiar with all of these system calls then don't worry, the default implementation is setup to redirect console output to the flash log file and also to a console on screen.

The source code for the default Console implementation can be found in sdk/usr/share/Console.as. If you include a modified version of this in your project you will need to compile it into an ABC and also use the gcc option -symbol-abc=foo.abc in your final link step to instruct gcc to use your version instead of the default. If you also modify the name of the class in this file you will also need to give gcc this information -symbol-class=:0:com.adobe.flascc::Console where "com.adobe.flascc" is the package name and "Console" is the class name.

Take a look at the default implementation of the console, the most important things to notice are as follows:

How much more code you add to the Console beyond handling console output and starting the Crossbridge code is up to you. As you will see in the section on interop, it is possible to interact with all of the Flash APIs using the C++ wrappers included in Flash++.h, but you might prefer to write it in pure AS3 in your Console implementation.

When your SWF uses a preloader it actually won't be the first class created. To handle this case the Console class constructor takes an argument to specify a DisplayObjectContainer that you can add the Console to in order to put the Console on the Flash Runtime Stage. You will see the code to handle this case in the default preloader's constructor.

The call to CModule.serviceUIRequests is explained more in the multi-threading section, but essentially if your code is running in a background worker and needs to perform an operation that requires access to APIs that only the foreground thread (on which the Console is running) has access to, it must block and delegate the code to the foreground thread. Calling this method services any pending requests from background threads.

Within the AS3 functions that Crossbridge generates for your code, certain AS3 variable names are considered reserved and are used by the code generator to maintain internal Crossbridge state within a function. However, C/C++ local variables will not conflict with these variables as they are renamed by the code generator when the final AS3 is generated. But you must ensure that any AS3 variables you declare using the AS3_DeclareVar macro from AS3.h don't conflict with these names. The reserved AS3 variables are esp,ESP,ebp,eax,edx,st0,ram,sjid,tsjid,tcbp,_as3ReturnValue and also iNfN where N can be any integer

Implementing a Preloader

Your Crossbridge compiled code starts executing when the whole SWF file has been loaded in the browser, but it's a best practice to show some kind of loading screen before then, so the user knows that something is happening. SWF files are designed to be streamed and make it easy to embed a small animation at the start that can play while the rest of the file is loading.

The default preloader in action

By default Crossbridge injects a simple preloader into every SWF it produces. This default preloader shows a black screen with a white loading bar that progresses across the screen as the SWF loads. If an HTTP VFS is being used, it can easily be hooked up to the progress bar to show the progress of the VFS as it is downloaded in parallel with the main SWF. You can see an example of this preloader in action in this Neverball demo.

If you don't want a preloader in your SWF (for example if it is loaded via a different SWF and doesn't need to show a UI while loading), you can disable it via the gcc option -no-swf-preloader.

The source code for the default preloader ships with the SDK and can be found in sdk/usr/share/DefaultPreloader.as. This should give you a good template to start with as you develop your own preloader. Once you have compiled your modified version to a SWF you can tell gcc to use this instead of the default preloader by passing it the option -swf-preloader=foo.swf.

The contents of the preloader SWF are injected into the Crossbridge SWF at the very beginning, followed by a ShowFrame tag, which causes the preloader to execute even before the rest of the file has loaded. Once the preloader receives the event indicating that the SWF has loaded, it calls gotoAndStop to initialize the rest of the SWF, and it then calls the constructor for the Console class, which then takes control of the screen.

The preloader SWF can be created in a graphical tool such as Flash Pro if you want to make something more attractive, possibly with embedded images, sounds and fonts. As long as the SWF contains some ActionScript code that achieves the same effect as the default preloader with regards to handling the Event.COMPLETE event.

More information about the SWF file format can be found in the SWF specification, but it isn't necessary to understand things at this low level to be able to understand how preloaders work.

Implementing a Virtual File System

Any time your C/C++ code performs file IO, no matter what framework is being used, at some point it will use the low level libc API for opening, reading and writing files. Crossbridge implements these low level APIs, but also exposes a high-level ActionScript interface that makes it easy to populate the virtual filesystem with files and directories.

By default the filesystem has one root directory "/" and contains no files or directories. An object implementing IBackingStore is responsible for handling file listing, reading and writing for the files and directories within a sub tree of the global filesystem.

Using multiple BackingStores at the same time is supported. For example, you could provide some fixed data in an embedded VFS mounted at "/data" and implement a read-write BackingStore for user data in "/user" that perhaps saves updated files back to a web-server.

Several built-in VFS types are supported but the interfaces can be implemented to provide completely custom types. Here are the supported builtin types of VFS, which can also be seen by running genfs --help:

Embedded

Embedded + Zipped

HTTP

Local Shared Object

Embedded / Zipped VFS

The simplest way to provide a filesystem for your SWF is to embed it within the SWF itself. Crossbridge provides a tool called genfs, which converts a directory structure on your real filesystem into a set of ActionScript classes that can be compiled into your SWF and instantiated at runtime.

To create an embedded VFS called "myvfs" from the contents of the folder called "sourcedirectory" you would use the following command:

The output consists of multiple ActionScript files prefixed with "vfsprefix" and a file called vfsprefix.rules, which contains a makefile rule file that could be included in your makefile to compile the files (this is optional).

To compile all of the VFS files into one ABC file suitable for linking into your final SWF you can use ASC2:

This creates a file called myvfs.abc in the current directory, which you pass to gcc in the final link step of your project. To instantiate the VFS at runtime you can construct it like this:

import com.adobe.flascc.vfs.myvfs;
myvfs();

If you didn't specify a class name with the "--name" argument the default class name is "RootFSBackingStore".

Switching to an embedded and compressed VFS is as simple as changing the value of the "--type" switch to "compressed". This will produce only one ActionScript source file that contains your VFS as an embedded zip file. All of the previous commands should work just the same for this type of VFS.

HTTP VFS

genfs supports another type of VFS that can load a predetermined set of files via relative URLs. As with the embedded example, the first step is to run genfs on the local directory you want to make available as a VFS:

This time genfs generates files named vfsprefix_fileNchunkM where N and M are integers. Most files will fit into one file but files over 10 megabytes will be split into smaller chunks so that browsers are more likely to cache the files.

A manifest file will also be generated that lists all of the chunks and is designed to be included by the HTTP VFS ActionScript implementation. To compile this, you must copy the file sdk/usr/share/HTTPBackingStore.as to the current directory and run the following command:

Using the resulting class is slightly more complex than the embedded VFS because it isn't usable until the files have downloaded. The resulting class dispatches several events so that you can handle progress, failure and completion. The events are the same as those dispatched by the URLLoader.

If you look in the default preloader implementation you will see that it has code that handles the web VFS for you. To make use of this you must compile your web VFS into the preloader. A working example of this can be found in the Neverball sample.

LSO VFS

Flash has a feature known as Local Shared Objects. LSOs provide domain-specific structured data storage outside the browser cache. A working implementation of the VFS API that supports loading and saving to an LSO can be found in sdk/usr/share/LSOBackingStore.as.

By default every domain is allowed 100Kb of LSO storage space, but more can be requested by using the SharedObject API to request permission from the user.

The VFS API

All of these VFS implementations are implemented on top of the VFS ActionScript API. To implement a minimal filesystem you only need to implement the IBackingStore interface.

The IKernel Interface

The libc implementation provided with Crossbridge is compiled from the source code for the FreeBSD 8.1 libc implementation. libc is usually the lowest dependency in any software stack before you reach the operating system kernel and therefore makes assumptions about the environment in which it is running. In the FreeBSD implementation of libc these assumptions manifest as function calls whose implementations are defined within the FreeBSD kernel itself. To satisfy these "syscalls" Crossbridge provides an ActionScript interface and a default implementation that implements each of these syscalls.

For most users, the default implementation will be sufficient, but advanced users might want to customize the behavior or provide implementations of some of the more exotic syscalls that Crossbridge has left undefined.

Once you have implemented this interface you can instruct Crossbridge to use your implementation by setting CModule.kernel in your Console implementation, as shown below:

CModule.kernel = new YourIKernelImpl()

Concurrency in Flash Player 11.5

Before diving into multi-threading it is important to understand how this is implemented in the Flash Player, as it will affect the way you think about writing your AS3 interop code.

From an ActionScript developers point of view Flash player 11.4 introduces a simple Worker based model of shared-nothing multi threading where each Worker (sometimes called an Isolate) is fully separated from the others and cannot share references to any ActionScript objects. Communication between Workers is done by an API called the MessageChannel that allows copies of objects to be sent between threads. This allows for high-level concurrent programming in AS3 without having to worry about low level issues around locking and synchronization.

To enable developers to also program with a more powerful low-level shared-memory multi-threading model Flash Player 11.5 allows ByteArray objects to be shared between workers. Various concurrency primitives (Mutex/CAS/Fence/Condition) are also available to help synchronize access to ByteArrays that are being operated on by multiple Workers. Crossbridge implements all of the necessary low level thread synchronization primitives needed to enable us to support the industry standard pthreads library. When calling pthread_create to create a new C thread a new Flash Worker is setup that shares the Crossbridge domainMemoryByteArray. Using this shared access to the Crossbridge ByteArray and the low level primitives to ensure correct synchronization Crossbridge is able to faithfully implement pthreads in the Flash player. This makes it possible to compile and run existing C/C++ based multi-threaded code within the Flash Player without needing to modify the code.

The first SWF that the Flash player runs is known as the primordial Worker; Because it runs on the UI thread in the runtime it has access to the full set of APIs that Flash exposes. Subsequently created workers are all considered children of this primordial worker and have access to most, but not all, of the APIs the primordial worker can use. Because of this it might be necessary for background Workers to communicate with the primordial Worker to get it to perform actions on the child worker's behalf.

What this means for Pthreads is that it is occasionally desirable for a C thread to be run on the main Flash Worker instead of the Worker that was created to run that thread. Crossbridge includes functionality that allows you to very easily block a background thread until the main worker is in a position to service it by running a C function on the main thread whilst maintaining any thread-local state from the background thread. These requests are serviced when CModule.serviceUIRequests is invoked from the main worker. The default Console callsCModule.serviceUIRequests every ENTER_FRAME event. To ensure things work as expected the primordial Worker can only impersonate another C thread when that thread has been put to sleep using the avm2_self_msleep function. To wake up a thread that was being impersonated the impersonator must end with a call to avm2_wake. This is demonstrated in sample 9.

APIs unsupported in background Workers

The following APIs will not be available from within a background worker. Any attempt to construct an instance of any of these will throw an IllegalOperationError with the message "This feature is not available within this context," the errorID 3731 will be the same in all instances, allowing developers to key off of this value.

flash.system.IME isSupported returns false; get conversionMode returns null; set conversionMode is a no op; get enabled returns false; set enabled is a no op; doConversion() is a no op; setCompositionString() is a no op.

flash.ui.Mouse all methods are no-ops; setting 'cursor' property is a no-op

APIs with behavioral changes in background Workers

The following APIs have modified behavior when running from within a background worker. Some calls on methods are no-ops, while others will throw an IllegalOperationError or equivalent as is consistent with the documented API. Return values should be consistent with the documentation to the extent possible. For example, if a method returns an Array with elements in it under normal conditions, when executing from within a background worker, it will return an empty Array. Some of the drawing APIs spawn multiple threads based on the number of CPUs on the host system. Filters, blitting, and rasterizing will create threads to perform these operations. When running in a background worker these threaded operations are turned off.

Creating SWCs with SWIG

The Simplified Wrapper and Interface Generator (SWIG) is a tool that parses C/C++ header files and automatically generates the interop glue code required to expose that C/C++ library to a different target language. Crossbridge extends SWIG with a backend that targets the Crossbridge environment so that SWIG can automatically generate wrappers using the interop functionality introduced earlier on this page. This is ideal when you have a large codebase that you want to expose to ActionScript without writing lots of interop code by hand.

SWIG is not perfect. It is able to interpret enough C/C++ to be extremely useful, but occasionally you will run into code that its parser cannot understand. In these situations you must provide workarounds, typically hiding the misinterpreted code from SWIG and exposing the functionality to ActionScript via a custom wrapper.

There are also situations where the source language (C/C++) supports constructs that the target language (AS3 for Crossbridge) does not support. Some relevant examples include overloaded functions and operator overloading, neither of which are supported in ActionScript. To work around these limitations SWIG has support for detecting and renaming functions, but some manual work is required to tell SWIG which functions to rename and what they should be called.

The SWIG website has documentation and examples of how to use SWIG. The majority of this is applicable, regardless of the target language, so it is a valuable resource even when using SWIG to target ActionScript.

The SWIG Workflow

To use SWIG, perform the following steps:

Write a SWIG interface file

Process the interface file with SWIG to produce the ActionScript and C/C++ wrapper implementations

Compile the ActionScript wrapper implementation into an ABC file.

Compile the C/C++ wrapper implementation into an LLVM bitcode or ABC object file.

Perform your final link including both of the compiled wrapper implementations.

Creating a SWIG Interface File

The SWIG interface file contains all of the directives used to control SWIG's behavior. Use it to specify which header files from your codebase SWIG should parse and any custom rules needed to alter how SWIG wraps the C/C++ types that it finds in those headers.

From this interface file, SWIG generates the resulting interop API in two parts.

ActionScript interface - Defines the packages, functions, and classes that an ActionScript developer using the final SWC will be expected to use.

C/C++ layer - Contains code that helps to bridge the gap between the ActionScript interface and the actual codebase. Typically this includes functions that perform the actual type conversion between C++ and ActionScript objects. This code is not part of the public API and is used internally by the glue code SWIG generates.

Within your interface file you can add custom code to either half of the resulting interface. This allows you to generate simple helper C++ functions and expose them via ActionScript without having to modify your actual codebase. You might want to add custom code when you find that a common idiom in your C++ code is better exposed to ActionScript via a simpler high-level API.

Here is an example of a simple interface file which we'll assume is called MyAPI.i:

The argument -includeall instructs SWIG to follow all #include statements and the -ignoremissing argument instructs SWIG that it should not stop when it is unable to locate an include file. Neither is required and you should consult the SWIG documentation for more information about other available options.

This produces two output files MyAPI.as and MyAPI_wrapper.c that represent the two halves of the SWIG interface.

To add code into the generated C/C++ half of the wrapper you can do so like this in your interface file:

To hide certain types from appearing in the final API you can use the ignore directive, to rename a type you can use the rename directive. For an example of the ignore directive in use look at samples/Example_Bullet/bullet.i.

C++ Operator Overloading

AS3 does not support operator overloading so to be able to handle classes that use overloaded operators you need to use SWIG's rename directives to expose the operators as normal AS3 methods. In the following example the plus operator will be renamed to a method called add:

C++ Function/Method Overloading

AS3 does not support function or method overloading so if you do need to expose overloaded functions or methods in your AS3 interface you will need to use the SWIG rename directive to map them to uniquely named methods in AS3. In the following example the overloaded add method is renamed to avoid conflicts:

C++ Constructors and Destructors

The rules around C++ copy constructors, default constructors and implicit destructors are complex. SWIG will attempt to create wrappers for these methods wherever possible, but there are cases where it might not generate the wrapper you want, or conversely might generate wrappers you don't want.

The SWIG documentation has a whole section on the various directives that can be used to control the behavior of wrapper generation for constructors and destructors that can be found here.

Typemaps

SWIG uses a concept called typemaps where each language backend is able to specify how to map C/C++ types into the target language. The Crossbridge version of SWIG ships with a set of default typemaps for ActionScript that map the basic C/C++ types into equivalent ActionScript types:

All of the default SWIG typemaps for ActionScript can be found in sdk/usr/share/swig/2.0.4/as3. By re-declaring typemaps in your SWIG interface file you can override the defaults without having to modify the typemaps in the SDK.

AS3 SWIG Directives

A few custom AS3 specific SWIG directives have been exposed to control some aspects of the wrapper generation. When a derived C++ class implements a virtual function as public that was declared protected/private in the base class you will need to suppress the usual use of the "override" keyword as you can see in this example:

When using typemaps that require custom ActionScript types to be used in the generated AS3 wrappers you may need to import classes from custom packages. This can be achieved with the as3import directive that allows you to inject as3import annotations into the method declarations in the generated C/C++ wrapper code.

LTO and SWIG

As mentioned in the section on compiling code with GCC, the most optimal way to compile code is with -O4 -flto-api=.... When using SWIG the exports.txt file that you use to preserve symbol names must include all of the wrapper functions generated by SWIG.

To preserve the wrappers generated by SWIG, use the nm tool to generate a list of all of the defined symbols within the C++ half of the SWIG wrapper. To convert the output of the list into a format suitable for inclusion in the exports file, you can use the common unix utilities sed and awk to process the resulting list:

# First we generate the C and AS3 wrappers
swig -as3 -module MyLib swig.i -o MyAPI_wrapper.c
# Second we compile the C wrappers to bitcode
g++ -O4 -c MyLib_wrapper.c
# The final command consists of several steps:
# 1) Run nm on the bitcode to generate a list of symbols
# 2) Filter the symbol list using grep to only show defined ("T") symbols
# 3) Use awk to select just the symbol name
# 4) replace the "__" prefix with a single underscore
# 5) append the output to an existing exports.txt file
nm MyLib_wrapper.o | grep " T " | awk '{print $3}' | sed 's/__/_/' >> exports.txt

The Bullet Physics example uses this technique when compiling Bullet into a SWC for optimal performance. Take a look in the makefile to see it being used in practice samples/Example_BulletPhysicsLibrary/Makefile.

Debugging With GDB

Like most GCC-based toolchains Crossbridge uses GDB as its debugger. Crossbridge provides a modified version of GDB that can debug your Crossbridge compiled C/C++ code while it is running within the Flash Runtime. GDB can be used from the command line or from within IDEs that provide support for GDB like Eclipse CDT. Crossbridge does not currently offer official support for debugging within an IDE.

Setting Up GDB

In order to use GDB on your system you will need to set a couple of variables:

Set the FLASCC_GDB_RUNTIME environment variable
This is a path to the program that will launch the SWF that is being debugged. This path can either point to the standalone Flash Player Debugger or a web browser which has the Flash Player Debugger plugin installed.

This is an example of setting the path to a standalone Flash Player Debugger:

Set the ScriptStuckTimeout variable in mms.cfg
The Flash Player stops running programs if they take too long. This feature can interfere with the debugger. To ensure reliable operation of the debugger edit your mms.cfg file to include the ScriptStuckTimeout parameter.

This produces un-optimized code with full debug info so that GDB is able to fully inspect your data structures and understand where it is within the code while you step through it.

Running a SWF

Now that your environment is set up, you can run GDB by passing it the path to the file
that you want to debug. If your using the standalone Flash Player Debugger then this would be the path to the SWF file. If you are using a browser then the path could be either directly to the SWF file or to the HTML file that embeds the SWF.

GNU gdb (GDB) 7.3
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-apple-darwin10 --target=avm2-elf".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
(gdb)

Set a breakpoint by issuing the break main command and answering y when asked to make breakpoint pending on future shared library load. This warning is harmless and simply means that because the SWF has not started running GDB doesn't yet know where to set the breakpoint; once the SWF has started executing GDB will get the information it needs and place the breakpoint appropriately.

To start the content issue the run command. GDB will launch the content and attach
to the Flash Runtime. You should see the following output in the GDB console:

Evaluating Expressions And Calling C/C++ Functions

GDB has a basic C/C++ expression parser that can be used to evaluate the value of simple expressions while debugging without having to recompile any code. This expression parser also handles function calls as the following example based on the code in samples/08_GDB/debuggingexample.c demonstrates:

ActionScript Specific Commands

As far as GDB knows, it is remotely debugging a real native C/C++ application, so
when it prints out information about the current call stack or local variables, it
prints out the current C/C++ call stack or the current C/C++ local variables.
To see further up the callstack into ActionScript code, or to inspect the values of ActionScript local variables, Crossbridge implements several AS3-specific versions of the regular GDB commands, prefixed with as3.

AS3 Specific command

Description

as3bt

Shows the backtrace of the entire ActionScript stack. This displays mangled names for all of the currently executing C/C++ code along with the names of any ActionScript functions above them on the callstack.

as3locals

Displays the values of ActionScript local variables. Within the stack frame for a C/C++ function you will see internal mangled variable names along with any AS3 variables defined using the AS3_DeclareVar macro.

as3args

Displays the ActionScript arguments to the function. For a normal C/C++ function this displays nothing, but if you are within a function that was annotated using the AS3 interop function annotation syntax, it lists the arguments specified in the ActionScript signature for the function.

set as3namespace

When debugging a SWC (or a SWF compiled with -swf-ns) you must inform GDB what namespace you wish to debug, the default is com.adobe.flascc. This must be done before the run command is used.

show as3namespace

Shows the namespace GDB is using to debug, the default is com.adobe.flascc.

as3sync

Causes GDB to re-read all information about the state of the program without stepping.

as3up

Switches to a higher ActionScript stack frame, which lets you inspect stack frames that might not be part of the compiled C/C++ code; for example the code within Console.as.

as3down

Switches to a lower stack frame, this lets you inspect stack frames that might not be part of the compiled C/C++ code; for example the code within Console.as

as3finish

Runs until the current ActionScript function exits.

as3step

Steps over the currently executing instruction, but follows function calls. This might correspond to one C/C++ step or within an AS3 stack frame it might correspond to one ActionScript expression.

as3next

Steps over the currently executing instruction without following function calls. This might correspond to one C/C++ step or within an AS3 stack frame it might correspond with one ActionScript expression.

Debugging SWFs Built From Crossbridge SWCs

When you compile code into a SWC using the -emit-swc option, all of your code will be placed within the namespace you specify rather than the default com.adobe.flascc namespace. Because your SWF could contain classes within any number of namespaces GDB needs to be told which namespace you want to use.

To see what namespace GDB is currently working with use the show as3namespace command:

(gdb) show as3namespace
The AS3 namespace of the inferior is "com.adobe.flascc".

To select the namespace use the command set as3namespace before running the SWF:

(gdb) set as3namespace com.your.lib
(gdb)

You must also use this command if you have implemented the optional namespace re-writing argument for SWFs using the -swf-ns option.

Debugging Multi-threaded Applications with GDB

Multi-threaded C/C++ applications that use the pthread library can be compiled with Crossbridge to run in Flash Player 11.5 (or newer). This page describes how to get started using GDB with multi-threaded applications.

Profiling with Adobe Scout

Profiling the code from sample 4 using Adobe Scout.

SWFs generated with Crossbridge can be profiled using Adobe Scout, a tool for performance profiling Flash content. Scout gives you a sampling code profiler and exposes information that lets you diagnose problems with your usage of the Stage3D APIs.

Scout understands the mangling scheme used by Crossbridge and GCC and will show your C/C++ functions in the ActionScript sampler window as they appear in your C/C++ codebase. This makes it easy to identify performance bottlenecks in your C/C++ code when running as a SWF.

Profiling multi-threaded SWFs is currently an experimental feature in Scout that is disabled by default. To enable it select "preferences" from the main menu then click on the "Beta Features" tab. In this tab ensure that the "Start sessions for ActionScript Workers" checkbox is ticked. When using this experimental feature each worker will show up as though it were a separate SWF being profiled within Scout's UI.

Included Libraries

To help you get started, Crossbridge includes several commonly used open-source libraries already compiled and ready for use within your own projects.

Linking in any of these libraries will require you to satisfy the terms of their licenses. Read their licenses carefully!

Simple DirectMedia Layer. This library exposes a cross-platform API for handling input, sound and video. It was compiled with experimental support for the included Flash-based version of libvgl. http://www.libsdl.org/