JavaScript Compilation

Normally, when you upload code to Espruino it is executed straight from source - which means that your source code is on the device itself so you can edit it easily.

While this is fast enough for most things, occasionally you may need your code to run faster. Up until now you've had the option of writing Inline Assembler, but now you can actually compile JavaScript directly into native code.

The Compiler uses a web service provided from espruino.com to convert your code to C, compile it with GCC, and then upload it to your board. There is now the option of a JIT Compiler which runs completely on your device,

Note: The compiler is an online service that is only provided for official Espruino boards. It won't work on devices like ESP8266 or ESP32.

How do I use it?

Simply get your function working as you want it to, and then add the string "compiled"; to the very front of it:

function foo(a,b) {
  "compiled";
  return a*53 + b*2;
}

foo(2,3);

You can also include loops - for instance here we're rendering the Mandelbrot fractal:

function f() {
  "compiled";
  var Xr = 0;
  var Xi = 0;
  var i = 0;
  var Cr=(4*x/64)-2;
  var Ci=(4*y/64)-2;
  while ((i<32) & ((Xr*Xr+Xi*Xi)<4)) {
    var t=Xr*Xr - Xi*Xi + Cr;
    Xi=2*Xr*Xi+Ci;
    Xr=t;
    i=i+1;
  }
  return i;
}

var x,y;
for (y=0;y<64;y++) {
 line="";
 for (x=0;x<64;x++) line += " *"[f()&1];
 print(line);
}

or you can use compiled code to speed up your IO:

function f(pin, val) {
  "compiled";
  /* we can assign d to a local variable so
  Espruino doesn't have to look it up by name
  each time it's called.*/
  var d = digitalWrite;
  d(pin, (val>>7)&1);
  d(pin, (val>>6)&1);
  d(pin, (val>>5)&1);
  d(pin, (val>>4)&1);
  d(pin, (val>>3)&1);
  d(pin, (val>>2)&1);
  d(pin, (val>>1)&1);
  d(pin, val&1);
}

If you want extremely fast IO, you can take advantage of peek32 and poke32 to access the registers directly - however which registers you write to depends on the chip you're running Espruino on. As of Espruino 1v81 this is a lot easier, as you can query the bit-banded address of the specific pin that you need:

function toggler() {
  "compiled";
  var pB2 = 0|B2.getInfo().out_addr;
  var cnt = 1000000;
  for (var i=0;i<cnt;i++) {
    poke32(pB2, 1); // on
    poke32(pB2, 0); // off
  }
}

function go() {
  pinMode(B2, "output");
  toggler();
}

We need to cast B2.getInfo().out_addr to an integer by oring it with 0, as it allows the compiler to optimise the poke32 call.

Note: in_addr also works for the input address - see Pin.prototype.getInfo

Note 2: We're only setting the Output Data register, not the pin state register. This means you'll need a call to pinMode (or digitalWrite) beforehand in order to set the pin to be an output.

If you did want to access the pins directly, you still can. For example the following code will produce a roughly 8Mhz square wave on an STM32F4 (Espruino Pico):

function toggler() {
  "compiled";
  // BSRR registers on STM32F4
  var GPIOA = 0x40020018;
  var GPIOB = 0x40020418;

  var PIN2 = 1 << 2;
  // toggle B2 on and off 1 million times
  var cnt = 1000000;
  for (var i=0;i<cnt;i++) {
    poke32(GPIOB, PIN2); // on
    poke32(GPIOB, PIN2 << 16); // off
  }
}

For what to do on an STM32F1, take a look at the Assembler page.

Direct access can be done with other peripherals as well - check out the reference manual for the MCU on your board for more information on which addresses to write to. The correct reference manual is linked from the Pico Board and Original Espruino Board pages under the 'Information' heading.

There's a tutorial on accessing low-level STM32 peripherals here

What Happens?

Before uploading, the Web IDE scans your code for functions with the "compiled"; keyword. It then sends those functions to our server which parses them, converts them to C++ code, compiles that code with GCC, and sends the binary back so that it can be uploaded to Espruino as a native function.

When you run this native function, the ARM processor in Espruino executes the compiled code directly (with no interpreter in the way). You should see an increase in execution speed of at least 4x, and sometimes over 100x if your code can be executed using entirely integers.

For any variable with a type that is not obviously an integer, Maths is handled using Espruino's built-in variable type (which is significantly slower). This means you should try and use integers wherever possible for maximum speed.

Caveats

Performance Notes

What works and what doesn't?

Works

Doesn't Work

Can I help?

Absolutely! We're always after contributions. The actual code you need is here:

This page is auto-generated from GitHub. If you see any mistakes or have suggestions, please let us know.