MXML compiler. Part 3. Understanding the Flex Compiler

Original author: Clement Wong
  • Transfer

Hi% habra_user%!

I decided to continue a series of articles on the Flex compiler to translate a good article by the author of this creation about what processes occur inside the compiler during the assembly of the application. It dates back to 2008, but was not seen in the Russian-speaking community (and especially in others). And since in the near future it is this compiler that remains relevant for the assembly of the vast majority of Flash projects, I decided to continue the series of articles on its expansion.

As usual, everyone who is not tired of reading up to this line - I ask for a cut!

Firstly, I consider it appropriate to provide links to other articles from the cycle:
  1. Add constructor parameters to the MXML Flex compiler
  2. MXML compiler. Part 2. Non-string parameter initializers
  3. MXML compiler. Part 3. Understanding the Flex Compiler

Secondly, I had to google pretty well to find the actual (in connection with transferring Flex to Apaches) link to the branch code 4.6, and to save your time I just leave it here:
opensource.adobe.com/svn//opensource /flex/sdk/branches/4.y
Why am I using this particular version?
The answer lies in the build process, because if the version from Adobe could be assembled out of the box simply by downloading the sources and running ant, then with the Apache version you should try pretty hard to get it compiled due to dependencies. And the difference between them is still minimal (both do not support Maven for assembly :))

I (like the author of the original article) strongly recommend downloading the source for a better understanding of the article. The material in this article is relevant for both (Apache & Adobe) versions of the compiler.

Language compilers

In general, the Flex compiler supports different programming languages. They are compiled by a set of language-specific compilers. If you look at the list of project classes with the name Compiler, you can see some of them:

You cannot say that all languages ​​can be compiled in one step. For example, the MXML compiler may use dependencies written in AS3. Therefore, before compiling the MXML component into bytecode, the compiler must determine which AS3 classes it needs and verify that the AS3 code called from MXML is correct.

It is also reasonable to assume that different compilers require a different number of steps. For example, the MXML compiler requires twice as many steps as AS3.

flex2.compiler.SubCompiler

In Flex, all language compilers implement the same interface - flex2.compiler.SubCompiler :
public interface SubCompiler
{
	String getName();
	boolean isSupported(String mimeType);
	String[] getSupportedMimeTypes();
	Source preprocess(Source source);
	CompilationUnit parse1(Source source, SymbolTable symbolTable);
	void parse2(CompilationUnit unit, SymbolTable symbolTable);
	void analyze1(CompilationUnit unit, SymbolTable symbolTable);
	void analyze2(CompilationUnit unit, SymbolTable symbolTable);
	void analyze3(CompilationUnit unit, SymbolTable symbolTable);
	void analyze4(CompilationUnit unit, SymbolTable symbolTable);
	void generate(CompilationUnit unit, SymbolTable symbolTable);
	void postprocess(CompilationUnit unit, SymbolTable symbolTable);
	void initBenchmarks();
	PerformanceData[] getBenchmarks();
	PerformanceData[] getEmbeddedBenchmarks();
	void logBenchmarks(Logger logger);
}

Among the methods not related to the compilation process, we can distinguish:
String getName () - as the name implies, the method returns the name of the compiler;
isSupported and getSupportedMimeTypes - are used to determine the type of files that this compiler can reverse;
benchmarks methods related to measuring compilation performance.

Compilation steps

As you may have noticed, the compilation process consists of 9 stages. The main Flex compiler acts as a coordinator and is responsible for calling instances of compilers that expect something like this:
  1. preprocess (once)
  2. parse1 (once)
  3. parse2 (once)
  4. analyze1 (once)
  5. analyze2 (once)
  6. analyze3 (once)
  7. analyze4 (once)
  8. generate (once)
  9. postprocess (repeatedly until the instance requires a stop)

In addition to calling these methods, the main Flex compiler does a number of things:
  • Selects the appropriate compiler instance based on the type of the source file;
  • It receives from instances a list of types that are not allowed and looks for them among the project sources and libraries;
  • Passes type information to instances;
  • Decides which compiler should execute based on the state of the instances and the general state of the resources.

In order to manage everything and everything, the main compiler makes the instances cooperate. Basically, it requires you to follow a specific set of rules:
  • The syntax tree should be accessible by the end of parse2 ;
  • analyze1 must have information about the name of the superclass;
  • analyze2 needs to know about all the dependencies;
  • analyze4 should provide complete type information.

The compilation process continues until:
  • There will be no dependencies to resolve;
  • Compiler instances will throw an error.


Call Algorithms

As mentioned earlier, the compilation process consists of calling these 9 methods. But in spite of the fact that the order of calling these methods is determined quite accurately, the main compiler can still call them in different ways. In fact, there are 2 algorithms: One ( flex2.compiler.API.batch1 () ) structured, the other ( flex2.compiler.API.batch2 () ) conditionally pathogenic. Let's consider them separately:

API.batch1 () is a conservative and more structured algorithm. Its essence is that it guarantees the onset of one phase for each file before moving on to another phase. For example, analyze1 () will be called for all files before proceeding to analyze2 () .

API.batch2 ()- conditionally pathogenic algorithm, its main goal is to minimize memory consumption. Unlike API.batch1 () , source files with fewer dependencies can reach the generate step much earlier than files with more dependencies reach the analyze3 () phase. The idea is that the resources allocated for the file can be freed immediately as the file is compiled into bytecode.

Conclusion

Well, now you know much more about the internal workings of the Flex compiler! Let's summarize:
  • The main Flex compiler uses only one of two algorithms to compile: batch1 or batch2;
  • Compilation algorithms use 2 different strategies to call the 9 stages of the application assembly;
  • During compilation, instances of compilers must cooperate and provide type information to the main compiler at the end of each step;
  • The main compiler does all the dirty work (searching for source files / libraries, managing error logging, etc.), which means that language compilers do not have to worry about this.


The above is relevant for all versions of utilities (mxmlc, compc, asdoc) included in the Flex Framework.

From the translator:

Please send the found grammatical errors and inaccuracies in a personal message, so as not to increase the number of translucent comments;)
PS In general, the idea was to write an article about Flex Compiler Extension-s that allow you to expand the compiler without changing its code (connect via flex-config.xml to form jar-ok), but having thought it over I decided to make this article first, which describes the whole ins and outs.
PSS Given the pace of development of ASC2.0, I believe that the Flex Compiler will be relevant for at least another year, or even more, so do not be afraid to study and pick it, especially since this is an invaluable experience!
PSSS Yes, yes, dead. Yes, Adobe abandoned the player. Yes, they gave Apache. Blah blah blah…

Also popular now: