Azriel Fasten
November 25, 2008
The following is my understanding of what the Alchemy does ( mostly inside Alchemy's gcc script ). This is for creating an executable swf, not a library. There may be some minor differences. Using these tools, one can compile C/C++ programs to Actionscript, to be used in the Actionscript Virtual Machine found in Adobe Flash Player.
LLVM-GCC
llvm-gcc/llvm-g++ is a C/C++ compiler which targets LLVM Intermediate Representation ( IR ). The bytecode format of the IR is normally stored in *.bc ( bytecode ) files. These bytecode files can then be operated upon by the rest of LLVM's tools such as opt ( for optimization ). For a full list of LLVM tools see: http://llvm.org/docs/CommandGuide/index.html.
Example:
llvm-g++ -emit-llvm -c -nostdinc -nostdinc++ -I"../avm2-libc/include/" -I"../avm2-libc/include/c++/3.4/" --include "../avm2-libc/avm2/AVM2Env.h"
Note:
The C and C++ standard library header files are provided by Alchemy. Also, AVM2Env.h must be included to set up the environment correctly. Arguments:
-o specifies output file.
-nostdinc tells llvm-g++ not to use the standard C headers ( since Alchemy uses its own )
-nostdinc++ tells llvm-g++ not to use the standard C++ headers ( since Alchemy uses its own )
-I sets include folders.
--include forces a file to be included.
-O3 sets optimization level to 3.
-emit-llvm .Make[s] the output be LLVM bitcode (with -c).1.
-c is used together with -emit-llvm, ( without .-emit-llvm -c. llvm-g++ will create a native executable by driving llc and gcc's ld to compile and assemble ).
llvm-gcc is run in a similar manner.
OPT
opt is LLVM's optimizer. It takes bytecode files as input, and outputs bytecode files.
Example:
opt -f "main.bc" -lowerallocs -o "main.opted.bc"
Note:
Alchemy's gcc script uses -lowerallocs, if it isn't used, then asc.jar will be unable to compile the Actionscript file. Arguments:
-o specifies output file.
-f forces overwrite.
LLVM-LD
llvm-ld can be used to combine bytecode files, which can then be further optimized with opt ( inter-procedural optimizations ). For Alchemy, the C and C++ standard libraries are pre-compiled into LLVM bytecode files. They should be combined with the project ( and optionally re-optimized ) before using llc.
Example:
llvm-ld "main.bc" "avm2-libc/lib/avm2-libc.l.bc" "avm2-libc/lib/avm2-libstdc++.l.bc" -O3 -o "main.bc" -internalize-public-api-list="$(internsyms)"
Notes:
Alchemy provides the standard libraries in bytecode format. They are linked in with llvm-ld, together with your bytecode file ( main.bc ). Arguments:
-O3 specifies optimization level of 3.
-o specifies output file.
-internalize-public-api-list is .A list of symbol names to preserve.2. The list is a comma separated list ( no spaces ) of functions. This list is found in the gcc script and is as follows ( remove the spaces ):
_start, malloc, free, __adddi3, __anddi3, __ashldi3, __ashrdi3, __cmpdi2, __divdi3, __fixdfdi, __fixsfdi, __fixunsdfdi, __fixunssfdi, __floatdidf, __floatdisf, __floatunsdidf, __iordi3, __lshldi3, __lshrdi3, __moddi3, __muldi3, __negdi2, __one_cmpldi2, __qdivrem, __adddi3, __anddi3, __ashldi3, __ashrdi3, __cmpdi2, __divdi3, __qdivrem, __fixdfdi, __fixsfdi, __fixunsdfdi, __fixunssfdi, __floatdidf, __floatdisf, __floatunsdidf, __iordi3, __lshldi3, __lshrdi3, __moddi3, __muldi3, __negdi2, __one_cmpldi2, __subdi3, __ucmpdi2, __udivdi3, __umoddi3, __xordi3, __subdi3, __ucmpdi2, __udivdi3, __umoddi3, __xordi3, __error
LLC
llc is used to convert bytecode files to a target back-end. LLVM has many back-ends. Adobe ( Peterson ) has made their own custom back-end called avm2, which targets the Actionscript Virtual Machine version 2. llc, using this back-end, will produce *.as files ( Actionscript ). These are not ordinary *.as files as they use special extensions not supported by the Actionscript compiler. Thus, alchemy provides a custom Actionscript compiler asc.jar.
Example:
llc -f -march=avm2 -o "main.as" "main.bc. -avm2-package-name=cmodule
Notes:
Arguments:
-o specifies output file.
-f forces overwrite.
-march=avm2 specifies that llc should target avm2.
-avm2-package-name=cmodule .Specify[s] the package name for this module.3
ASC.JAR
asc.jar is the custom Actionscript compiler. It converts the *.as files to *.swc, *.swf, *.abc files. The compiler must link in the flash libraries provided by Alchemy ( presumably to provide the runtime ). It is a Java application and thus requires Java.
Example:
java -Xms16M -Xmx1024M -jar "bin/asc.jar" -AS3 -strict -import "flashlibs/global.abc" -import "flashlibs/playerglobal.abc" -config "Alchemy::Shell=false" -config "Alchemy::NoShell=true" -config "Alchemy::LogLevel=2" -config "Alchemy::Vector=true" -config "Alchemy::NoVector=false" -config "Alchemy::SetjmpAbuse=true" -swf "cmodule.ConSprite,800,600,60"
Notes:
The following is an explanation of the arguments used. The quoted text is from running from running .java -jar asc.jar --help..
.bin/asc.jar. is the location of the modified Actionscript compiler ( in Alchemy's .bin. directory ).
-Xms16M, -Xmx1024M set the minimum and maximum heapsize.
-AS3 tells the compiler to .use the AS3 class based object model for greater performance and better error reporting..
-strict treats .undeclared variable and method access as errors..
-optimize .produce[s] an optimized abc file., I do not know if it has any effect.
-swf is defined as .-swf classname,width,height[,fps] = emit a SWF file.. I copied this out of the gcc script. This will change for a library.
-import is defined as .-import <filename> = make the packages in the specified file available for import.. I presume that these are the runtime libraries, the glue between the standard libraries and the VM.
-config obviously sets configuration options for the custom Actionscript compiler. What these options are exactly, I do not know, I just copied them out of the gcc script.
My environment:
WinXP SP3
Intel P4 3GHz
1 GB RAM
cygwin installed on drive F
alchemy_sdk_cygwin_p1_111708
Problems I've encountered using Alchemy:
When running the swf file in a browser, on the web, it takes ~21 seconds for the program to begin, but when running the same swf from a local file, happens it runs instantaneously. I can't figure out what I'm doing wrong. I tested this with the simplest of programs.
When compiling the following program, the program fails to output text as it should. std::strings do work though, just std::cout and other streams such as std::stringstream seem to cause problems. Under certain conditions ( for ex. SetjmpAbuse=false ) it gives an error: .terminate called after throwing an instance of 'St8bad_cast'\nterminate called recursively.
#include <iostream>
int main(){
std::cout << "testing\n";
return 0;
}
asc.jar doesn't allow me to specify output file names.
llvm-ld appends ..bc. to output file?
"shebang" doesn't really work. It runs adl and just hangs. Is it an adl problem? This is what it runs:
/cygdrive/f/super/dump/alchemy/flex_sdk_3/bin/adl.exe c:\\cygwin/tmp/t974.0/app.xml 2> /tmp/adl.trace & echo $!
I have absolutely zero experience with Flex or adl. So this could be a demonstration of my ignorance.
Is there a way to make the gcc script emit a swf without the "shebang"?
When trying to compress a swf, ShrSWF.pl gives error of:
Undefined subroutine &main::sys called at /cygdrive/f/super/dump/alchemy/alchemy_sdk_cygwin_p1_111708/alchemy-cygwin-v0.4a/bin/ShrSWF.pl line 56.
The docs state4:
ShrSWF.pl: This will take a source SWF and compress it.
Example: ShrSWF.pl src.swf dst.swf
2From running .llvm-ld --help.
3From running Alchemy's .llc --help.
4http://labs.adobe.com/wiki/index.php/Alchemy:Documentation:Developing_with_Alchemy:Tools#Tools_in_.24ALCHEMY_HOME.2Fbin