Configuring Flex Builder to use the HellFire compiler

Attention: The installation instruction is no longer valid. Please go to http://stopcoding.org/ to download the latest version of HFCD.

Hi, In my previous post, I talked about a RPC version of the Flex compiler API, i.e. instead of invoking the Flex compiler in the same JVM process as the caller, the RPC version makes network calls to a server dedicated to compiling Flex applications, modules and libraries. After working on the prototype a little more in the past several weeks, I finally have something for you to try – I call it the HellFire Compiler (yes, I give my work a name because ‘a RPC version of the Flex compiler’ is a mouthful).

There are three pieces in the HellFire Compiler:

A special version of flex-compiler-oem.jar. It is simply an implementation of the Flex Compiler API that makes network calls to a compiler daemon.

hfcd (HellFire Compiler Daemon). Users run hfcd as an independent, separate process (as a background job or in a Terminal window). hfcd uses the original flex-compiler-oem.jar to compile Flex applications.

An Eclipse/FB plugin. This is usually installed in FB. It retrieves from hfcd information about the compilations, e.g. compile time, link time, memory usage, etc.

Installation

So how do you go about configuring Flex Builder 3 to use the HellFire Compiler? First, we take care of hfcd…

With hfcd, the compiler and the other FB features are separated and it’s possible to give the VM for hfcd specific VM args that boost the performance of the compiler. For example, I’ve seen consistent 30% performance improvement when hfcd uses the ‘-server’ VM mode. It may be true or maybe I forgot to blink my eyes. I don’t know. Also, it’s interesting to see how aggressive the VM grows the heap in ‘-server’ VM mode.

Running hfcd on a second machine. When I was with Adobe, there was a desktop under my desk (I don’t know why I put a *desktop* computer *under* my desk) that I occasionally used for testing purposes. It was faster than my laptop too! So in theory, if you run hfcd on such a machine, it could shorten the FB build time…. I’m going to see if Eclipse can help me synchronize files and remap paths….

Suppose that there are two independent projects in your workspace, i.e. no project references. In theory, Eclipse/FB could compile the projects in parallel. If so, it would make the out-of-process solution even more compelling.

The Eclipse/FB plugin currently only retrieves compile time and link time. But there is nothing to prevent the plugin from retrieving compiler reports (e.g. dependency info, usage info), bytecode disassembler output, etc.

I couldn’t find your email, so I will write you here.
I was hired by company X to implement a runtime builder for mxml. Thats means — ability to load an mxml document in a flex app and render it on the fly.

I have been reading through your code. If you can give me any tips that can lead me off the wrong path, please do.

Basically I see now to main paths for me:
1 – port all your java and javacc stuff to actionscript, so that I will run it as *is*.

2 – write a fresh parser in actionscript by hand and only refer to your code as reference.

Also, I haven’t figured out how to treat bits of actionscript in the mxml — I don’t have runtime compiling feature (eval) in actioscript.

1st I wanna ask a favor, hellfire.compiler.client.ConfigurationStub. Can you implement a toString() like what was done on flex2.tools.oem.internal.OEMConfiguration?

Now, about results. I try, and got two exceptions, both at client side and at same time:
[ERROR] java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read(BufferedInputStream.java:237)
at hellfire.tools.IOToolkit.readInt(IOToolkit.java:387)
at hellfire.tools.ClientHandler.readInt(ClientHandler.java:299)
at hellfire.tools.ClientHandler.receive(ClientHandler.java:532)
at hellfire.compiler.client.ApplicationStub.getReport(ApplicationStub.java:540)
at flex2.tools.oem.Application.getReport(Application.java:329)
at info.rvin.mojo.flexmojo.compiler.AbstractFlexCompilerMojo.tearDown(AbstractFlexCompilerMojo.java:1316)
at info.rvin.mojo.flexmojo.compiler.ApplicationMojo.tearDown(ApplicationMojo.java:126)
at info.rvin.mojo.flexmojo.AbstractIrvinMojo.execute(AbstractIrvinMojo.java:145)

and

java.lang.NegativeArraySizeException
at hellfire.compiler.CompilerReport.setFrameCount(ReportToolkit.java:453)
at hellfire.compiler.ReportToolkit.readReport(ReportToolkit.java:105)
at hellfire.compiler.ReportToolkit.readReport(ReportToolkit.java:51)
at hellfire.compiler.client.ApplicationStub.getReport(ApplicationStub.java:541)
at flex2.tools.oem.Application.getReport(Application.java:329)
at info.rvin.mojo.flexmojo.compiler.AbstractFlexCompilerMojo.tearDown(AbstractFlexCompilerMojo.java:1316)
at info.rvin.mojo.flexmojo.compiler.ApplicationMojo.tearDown(ApplicationMojo.java:126)
at info.rvin.mojo.flexmojo.AbstractIrvinMojo.execute(AbstractIrvinMojo.java:145)

Is there any additional data that I can give to you to help to track this down?

Porting the entire compiler to AS3 is going to be extremely challenging. I would not recommend that.

Writing an MXML ‘interpreter’ in AS3 is comparatively easier than porting the Flex compiler. But…

1. If you have and binding expressions in your MXML document, you’ll need an AS3-based AS3 compiler in your app.

2. If your MXML document uses mx.controls.Button but you don’t use it in your app, your MXML document will not render due to the missing class. You could dynamically load Button (in a SWF) before rendering your MXML document. But how do you find out what Button depends on? Well, you need to load catalog.xml. The situation can get out of hand pretty easily.

I’m not suggesting that such a MXML ‘interpreter’ in AS3 is not doable. It’s doable, but it’ prudent to keep the implementation of this ‘interpreter’ simple. e.g.

This AS3-based MXML ‘interpreter’ idea is not new and I know some customers are attempting to implement it. I suggest you ping flexcoders to see if you can find them and ask them to talk about their experience on this topic.

Now that there is this hfcd thing, your last option could be an AS3-based Flex Compiler API implementation that connects to hfcd via sockets or HTTP tunneling.🙂

This is great news. I am trying out the flex-mojos integration with hellfire, which VELO has done, but am getting an exception that looks like the one VELO mentions above. But the stacktrace is different.

Here it is:

[ERROR] java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read(BufferedInputStream.java:235)
at hellfire.tools.IOToolkit.readInt(IOToolkit.java:387)
at hellfire.tools.ClientHandler.readInt(ClientHandler.java:299)
at hellfire.tools.ClientHandler.receive(ClientHandler.java:532)
at hellfire.compiler.client.ConfigurationStub.setSWFMetaData(ConfigurationStub.java:1316)
at info.rvin.mojo.flexmojo.compiler.AbstractFlexCompilerMojo.configure(AbstractFlexCompilerMojo.java:998)
at info.rvin.mojo.flexmojo.compiler.AbstractFlexCompilerMojo.setUp(AbstractFlexCompilerMojo.java:773)
at info.rvin.mojo.flexmojo.compiler.ApplicationMojo.setUp(ApplicationMojo.java:117)
at info.rvin.mojo.flexmojo.AbstractIrvinMojo.execute(AbstractIrvinMojo.java:143)
at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:447)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:539)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:480)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:459)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:311)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:278)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:143)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:333)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:126)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:282)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
at org.codehaus.classworlds.Launcher.main(Launcher.java:375)

The exception is deep down in hellfire, so even though flex-mojos is present in the stacktrace, I start here🙂 Can you help with this?

To solve my problem with the SocketTimeoutException, I tried using the flex-compiler-oem.jar that comes with the latest hellfire build# 329 in combination with the flex-mojos compiler. This just throws me another exception:

java.lang.ClassCastException: java.lang.String
at hellfire.compiler.client.ConfigurationStub.setSWFMetaData(ConfigurationStub.java:1319)
at info.rvin.mojo.flexmojo.compiler.AbstractFlexCompilerMojo.configure(AbstractFlexCompilerMojo.java:993)
at info.rvin.mojo.flexmojo.compiler.AbstractFlexCompilerMojo.setUp(AbstractFlexCompilerMojo.java:773)
at info.rvin.mojo.flexmojo.compiler.ApplicationMojo.setUp(ApplicationMojo.java:117)
at info.rvin.mojo.flexmojo.AbstractIrvinMojo.execute(AbstractIrvinMojo.java:143)
at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:447)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:539)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:480)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:459)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:311)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:278)
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:143)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:333)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:126)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:282)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
at org.codehaus.classworlds.Launcher.main(Launcher.java:375)

I am using Java5.

Is it correct, that the server ports changed to 50207 and 50208 with build 329?

I reckon the exception above could be a problem with flex-mojos, but, given that the exception is thrown at setSWFMetaData(ConfigurationStub.java:1319) inside the hellfire compiler, I thought I would go to you first🙂

Is it possible to actually run this on a separate machine (i.e. desktop under the desk) as you mentioned with this version. If so, where do you specify the location of the server. Am I dumb and missing something?

[…] flex-mojos have the ability to delegate flex compilation to an external compile server, the hellfire compiler, done by Clement Wong, a former Adobe employee it seems. This would enable fast builds for single […]

[…] this plugin has a good, thriving community, with actual ongoing development. I was trying out the hellfire compiler with flex-mojos one day and could not get it to work. I checked out the sources and found a bug in […]

I take it back – after reducing my compile time down from about 3 minutues to 15 seconds, I changed the mode from RSL code included, to the standard and am now down to between 1.6 and 2.8 seconds. Holy craptastic!