Disclaimer:  This page is written by a person who is not the original author of this code, nor is a compiler expert.

 

History

(The History section was copied from this mostly out-of-date page.)

Spring 2010

Falcon began as a project at Adobe in response to the Flex community's concerns about long compilation times with the legacy compiler. The project began with several months of discussions about improving the old compiler versus starting over with Falcon. The main reasons for starting over were:

*The compiler team at Adobe wanted a compiler that could do double-duty as the code-intelligence engine for Flash Builder, rather than being something completely separate that Flash Builder called just to create a SWF or SWC. This approach would avoid duplicate data structures and duplicate algorithms, and would enable live error highlighting based on accurate semantic analysis. The team ended up taking Flash Builder's code intelligence engine, improving it, and adding semantic analysis and code generation to it. The resulting Falcon compiler doesn't have dependencies on Flash Builder though... it's the other way around.

*The legacy compiler wasn't designed for compilation on multiple threads. The team wanted a compiler that was designed with concurrency in mind from the beginning, as a primary way to get better – and scalable – performance.

*There was an awkward relationship between the legacy asc (which essentially understands only how to compile a single .as file) and the legacy mxmlc (which layers on top multi-file compilation and support for .mxml.css.properties, and .fxg), based on their historical development by two separate teams at Adobe. The team wanted a single compiler, designed by a single team, that had a unified architecture, unified data structures, and multi-file / multi-language support from the bottom up.

Fall 2011

A strategic shift at Adobe resulted a refocus on ActionScript and a defocus on Flex and MXML. Flex was donated to Apache, with a promise to finish the ActionScript side of Falcon and donate it by the end of 2012. Non-ActionScript support was left intact, at pre-alpha quality.

Summer 2012

Falcon was prepared for donation to Apache. By this point it has involved approximately 15 person-years of development effort.

Architecture

(The Architecture section was copied from this mostly out-of-date page.)

Falcon is designed from the beginning to support compiling multiple targets in multiple projects in a workspace, as exist in an IDE like Flash Builder. By contrast, the legacy asc was designed to compile a single AS file, and then the legacy mxmlc was built by another team on top of that. 

Falcon uses multiple threads to compile multiple files at the same time. It can even compile multiple method bodies in the same file in parallel. The more cores you have, the faster it goes, unlike the legacy compiler. The multiple threads are managed using Java Futures (java.util.concurrent.IFuture<V>). The maximum number of thread allowed to be used is a small multiple of the number of cores.

Critical data structures such as the symbol table (which stores information about which classes are known, what methods they have, etc.) are shared across the entire workspace, to minimize memory usage.

Critical data structures are maintained in memory to support both compilation and IDE code intelligence in an efficient and consistent way. For example: If you open an ActionScript file in Flash Builder 4.7, Falcon builds a syntax tree and symbol table for it to support intelligent editing. Compiling the file requires just one additional code generation step. By contrast, in Flash Builder 4.6, which uses the legacy compiler in the SDK, the IDE builds its own parse trees and symbol tables to support editing, and then when you compile the compiler in the SDK builds another set of parse trees and symbol tables. This is slow and a waste of memory.

Falcon was designed from the beginning for incremental compilation of a complete workspace, so it tracks dependencies between compilation units in various projects. If you edit a file, it knows which other files it should recompile.

It can compile an app against a library project without creating the SWC for that library on disk.

Falcon understands .as.mxml.fxg.css, and .properties files.

Implementation

At a highest level,  Falcon compiles MXML and ActionScript into ActionScript Byte Code (ABC), potentially combines it with ABC code from SWCs, and writes out a SWF or SWC.
At the next lower level, the source-path is searched for .mxml and .as files each of which is represented by an MXMLCompilationUnit or ASCompilationUnit.  The library-path is searched for SWCs whose contents are represented by SWCCompilationUnits.  MXMLCompilationUnits and ASCompilationUnits parse the source files into Abstract Syntax Trees (ASTs).  Then the ASTs are converted to ABC by a Reducer.  During the reduction, semantic errors may be found and reported.  Finally, if no errors are reported, all ABC from the Reducers and SWCCompilationUnits are written to a SWF or SWC by an Emitter.
At the next lower level, ActionScript files are tokenized by a Tokenizer which feeds tokens to a Parser.  The Parser is generated from an Antlr grammar.  The Parser creates the AST.  The Reducer is written using a Bottom Up Rewrite Machine (BURM) called JBurg.  The Reducer is a very difficult piece of code to debug and understand.  The Reducer makes calls to a GeneratingReducer which determines what ABC instructions to use.  MXML files are tokenized by a different Tokenizer and feed to a different Parser to create the AST.  MXMLCompilationUnits don't use a Reducer, they use a ClassDirectiveProcessor to determine which ABC instructions to use.  Note that MXMLC converts MXML to ActionScript which is then compiled to ABC.  Falcon converts MXML directly to ABC.
At the next lower level, the main() method in MXMLC or COMPC class is the entry point.  It sets up an instance of MXMLC or COMPC.  MXMLC or COMPC initializes a FlexProject to share things between CompilationUnits, and initializes a Configuration by combining command-line options and -config.xml files.   Errors found are reported and the compiler exits.  If no errors are found, a SWFTarget subclass is created which in turn starts creating CompilationUnits.
A thread is launched by the CompilationUnits to generate the AST for the CompilationUnit.  The AST is not always fully formed.  The AST nodes for method bodies are often not created until it is time to reduce the method body.  The entry point for the reducer is usually in ABCGenerator which calls the CMCEmitter class which is the Reducer.  The Reducer calls ABCGeneratingReducer.
All problems and warnings subclass CompilerProblem.  Setting a breakpoint on CompilerProblem's constructor enables you to see the call stack when the compiler decides to generate an error.  The call stack will show you which method decided to generate the error.  There are occasionally errors created that are not reported.
  • No labels