The GWT "Hello World" challenge. Make the smallest cross-compiled Hello World.

Last week, when optimizing +Joel Webber 's Bench2D benchmark for GWT, we were able to beat most the non-C-language competitors in speed, and came out #1 in size (smallest) by a large margin.

But one of the often used, phony benchmarks, is to take a tiny program, Hello World, and run it through a compiler to see what you get. It's a phony benchmark because most systems have some kind of fixed runtime they must drag into the output, and so for tiny programs, it looks like a lot of bloat, but for large programs, it is insignificant.

In any case, I wondered, how far can I shrink the runtime included? I started out by identifying what is being included, but not really used.

1) java.lang.Throwable and subtypes. This is pulled in because the $entry function and friends try to put a global try/catch around everything, and throw Java exceptions for any caught JS exceptions.

2) Object.toString() pulls in String.HashCode (inner class), but getHashCode function. Object.toString() also pulls in java.lang.Class

3) Scheduler is pulled in because of ScheduleEntry/ScheduleFinally

4) Linker adds a lot of bloat because of permutations and lightweight stats

5) UserAgentAsserter/DocumentModeAsserted. Unneeded.

I eliminated most of this, in the following way.

1) Go rid of Object.toString alias, that assigns Object.prototype.toString to point to Java.lang.Object.toString. it's only useful for debugging really.

2) Put a flag on SchedulerImpl called 'anyScheduled', which is set to true if the scheduler functions are ever invoked. I then put a guard around the enter/exit functions in Impl.entry so they that the scheduler isn't flushed if nothing is ever scheduled

3) Modified Impl.entry to make sure that if nothing is ever scheduled, and no uncaught exception handler is ever registered, the compiler optimizes it to "jsFunction.apply(this, arguments)"

4) Wrote my own linker called "DumbLinker", like SingleScriptLinker, but just assumes no code splitting, no nocache.js, just invokes gwtOnload

5) Turned off DocumentModeAsserter, and used Elemental, not GWT User land code.

6) Cranked up the Java optimized level, and ClosureCompiler settings far more aggressively.

Here is the Hello World source:
public class Hello implements EntryPoint {

  public void onModuleLoad() {
    Window window = JsBrowser.getWindow();

Here is the resulting JS (710 bytes, 409 bytes compressed): 
var d,f={};function g(){}function k(b){function a(){}a.prototype=b||{};return new a}function l(b,a,e){var c=f[b],h=c instanceof Array?c[0]:null;c&&!h?d=c:(d=f[b]=a?k(f[a]):{},d["__gwt_try_"+b]=1,d.d=e,d.constructor=d,!a&&(d.e=g));for(c=3;c<arguments.length;++c)arguments[c].prototype=d;h&&(d.c=h)}l(1,null,{});var m=0;function n(){window.alert("Hello")}function p(){}function q(b){var a;a=new p;b||a.b||(a.b=++m);if(b){a.a=b;var e=f[a.a];e?e.c=a:f[b]=[a]}}l(17,1,{},p);d.a=0;q(1);q(0);q(29);q(48);q(17);q(2);function r(){return function(){return n.apply(this,arguments)}}var j="undefined"===typeof j?null:j;(function(){var b=j;j=function(a,e,c,h){b&&b(a,e,c,h);if(a)try{r()()}catch(s){a(e)}else r()()}})();j();

Most of the surrounding code that has not been pruned is related to java.lang.Class. Because the Class Literal for 6 classes is still alive, the createForClass and defineClass functions are still emitted. If we could rid ourselves of those, we'd kill off another 50% of the size.

The starting size before I began was 2205 bytes, so this is a 300% reduction. 

It's doubtful it'll ever land in GWT because it won't help any non-trivial program.  But it does feel good to shave off every last byte you can.
Shared publiclyView activity