JavaScript code size

Posted on
  • I got a bit fed up with people randomly linking to the performance page from Twitter and sniggering about whitespace changing execution speed.

    I came up with this - thought you might like it:

    Why not compile to native/bytecode?

    Memory is scarce on microcontrollers, and we want the source code on the device itself so we can edit and debug it without external tools.

    There isn't enough room on the microcontroller for source code and compiled code, but luckily source code is surprisingly memory-efficient.

    For instance take this code that draws a Mandelbrot fractal:

    var x,y,line;
    for (y=0;y<32;y++) {
     line="";
     for (x=0;x<32;x++) {
      var Xr = 0;
      var Xi = 0;
      var i = 0;
      var Cr=(4*x/32)-2;
      var Ci=(4*y/32)-2;
      while ((i<8) & ((Xr*Xr+Xi*Xi)<4)) {
        var t=Xr*Xr - Xi*Xi + Cr;
        Xi=2*Xr*Xi+Ci;
        Xr=t;
        i=i+1;
      }
      line += " *"[i&1];
     }
     print(line);
    }
    

    It's 301 bytes long.

    When compiled with SpiderMonkey, the following bytecode is created (obtained by running a debug build and dbg(function() { .... }):

    loc     op
    -----   --
    main:
    00000:  getlocal 0
    00003:  pop
    00004:  getlocal 1
    00007:  pop
    00008:  getlocal 2
    00011:  pop
    00012:  zero
      ...
    00256:  loopentry 1
    00258:  getlocal 1
    00261:  int8 32
    00263:  lt
    00264:  ifne 22 (-242)
    00269:  stop
    

    It's 270 bytes long. So you've saved 31 bytes over the original code, but now your code is totally uneditable and unreadable.

    If you compiled this into native code with the Espruino Compiler, the size of the binary would be 1136 bytes.

    But what if you rewrote it in C and compiled it in GCC with size optimisation turned on. That'll be efficient, right?

    void main() {
     int x,y;
     char line[33];
     line[32] = 0;
     for (y=0;y<32;y++) {
      for (x=0;x<32;x++) {
       double Xr = 0;
       double Xi = 0;
       int i = 0;
       double Cr=(4*x/32.0)-2;
       double Ci=(4*y/32.0)-2;
       while ((i<8) & ((Xr*Xr+Xi*Xi)<4)) {
         double t=Xr*Xr - Xi*Xi + Cr;
         Xi=2*Xr*Xi+Ci;
         Xr=t;
         i=i+1;
       }
       line[x] = (char)((i&1)?'*':' ');
      }
      puts(line);
     }
    }
    
    $arm-none-eabi-gcc mandel.c -mthumb -Os -c -o mandel.o
    $arm-none-eabi-objdump -S mandel.o
    
    00000000 <main>:
       0:	b5f0      	push	{r4, r5, r6, r7, lr}
       2:	2400      	movs	r4, #0
       4:	b097      	sub	sp, #92	; 0x5c
       6:	ab0c      	add	r3, sp, #48	; 0x30
       ...
     116:	bc01      	pop	{r0}
     118:	4700      	bx	r0
     11a:	46c0      	nop			; (mov r8, r8)
     11c:	3fa00000 	.word	0x3fa00000
     120:	40100000 	.word	0x40100000
    

    Nope. 290 bytes.

    However, if you minified your code with the closure compiler you'd get:

    var a,b,c;for(b=0;32>b;b++){c="";for(a=0;32>a;a++){for(var 
    d=0,e=0,f=0,g=4*a/32-2,h=4*b/32-2;8>f&4>d*d+e*e;)var k=d*d
    -e*e+g,e=2*d*e+h,d=k,f=f+1;c+=" *"[f&1]}print(c)};
    

    It's editable, just about readable, and it's only 167 bytes - so it is smaller than bytecode and even highly optimised native code!

    Type Size (bytes)
    Original JS Code 301
    Spidermonkey bytecode 270
    Espruino Compiled JS 1136
    GCC Compiled C code (-Os) 290
    Minified JS 167

    So by executing from source, we use around the same amount of memory as we would if we compiled or used bytecode, while still having everything we need to edit and debug the code on-chip.

    However, if you need to make things smaller, you can minify the JavaScript functions you don't need to edit, which will use less RAM than even size-optimised C code!

  • Hi, @Gordon!
    You are right!!!!
    I think most persons do not have a correct understanding of what is going under the curtain!
    I mean, doing really real time I/O in such a high level language as Espruino / JavaScript are, as simply as it is now, is quite a challenge very few of them would have tried, say using Arduino C++ approach!
    Furthermore we all try to do this on very small platforms, happily forgetting any realistic constraints of memory sizes or computation time/responsiveness.
    Espruino definitely allows to make it, reducing the source code to a minimal size.
    I think, just as every one else, I hit the available ram size wall.
    So, to make it concrete, I would state that any ram saving technique is good to use but, expecting a massive ram requirement reduction, is just an illusion. You have to choose an appropriate platform to your application!
    So, you are right when you consider that Espruino is targeted at small, very energy saving, platforms...
    Now it is clear that tomorrow will be brighter than yesterday... Maybe...
    It's a time/effort/cost alternative consideration.
    Should this community finds a clearly simple, universal, solution let's do it.
    I doubt...
    Go on!
    You know what you are doing as a software / hardware designer or architect. It's more than obvious looking at the Espruino's projects.

  • Some things just have to be left alone. May be stating this information in a different way is more helpful: the IDE allows from 0 to maximum compression/minification, and the first one is taking spaces out. Any code reaching minimal maturity level and any code that has to perform is put to runtim taking any available advantage of runtime enahncement options.

    Why would I leave spaces in the uploaded code when not having to, but could if I wanted for what so ever reason? - Nobody prevents me to drive off with half pulled emergency breakes... any decent enging will get over it... but not my wallet after a while... enjoy hotrod mag borrowed attachment.


    1 Attachment

    • hotrodmagphoto.png
  • Wow, impressive! Never seen someone manage to do that before!

    The latest builds (so 1v82) have a few more space-saving tweaks which should help you squeeze a bit more out of it (~20%). There's still a little room for improvement, but yes - the level of memory available is such that it's entirely possible to write enough code that you'll run out of memory :(

    It was actually a bit of a surprise just how much more compact minified code was - however the code used is quite maths-heavy and I'm sure you could find cases where minified code wasn't as good... but it does make you wonder what something like Web Assembly would really add.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

JavaScript code size

Posted by Avatar for Gordon @Gordon

Actions