The only think I am not sure about is whether asm.js allows objects as local variables. My take on the specification (
) is that it does, in fact, not support this - the asm.js type system is fairly restrictive. However, heap pointers are obviously supported and so is access to the heap or stack at a certain pointer plus offset. Basically, one had to apply the same rule with which a local struct variable is currently mapped. I strongly suspect it becomes a heap or stack pointer.
static void foo(int a, float b) {
struct {
int a;
float b;
} bar;
bar.a = a;
bar.b = b;
printf("%i %f\n", bar.a, bar.b);
}
It becomes this asm.js Javascript function:
function _foo($a,$b) {
$a = $a|0;
$b = +$b;
var $0 = 0, $1 = 0.0, $2 = 0, $3 = 0.0, $4 = 0, $5 = 0, $6 = 0, $7 = 0.0, $8 = 0.0, $bar = 0, $vararg_buffer = 0, $vararg_ptr1 = 0, label = 0, sp = 0;
sp = STACKTOP;
STACKTOP = STACKTOP + 32|0;
$vararg_buffer = sp;
$bar = sp + 16|0;
$0 = $a;
$1 = $b;
$2 = $0;
HEAP32[$bar>>2] = $2;
$3 = $1;
$4 = (($bar) + 4|0);
HEAPF32[$4>>2] = $3;
$5 = HEAP32[$bar>>2]|0;
$6 = (($bar) + 4|0);
$7 = +HEAPF32[$6>>2];
$8 = $7;
HEAP32[$vararg_buffer>>2] = $5;
$vararg_ptr1 = (($vararg_buffer) + 4|0);
HEAPF64[tempDoublePtr>>3]=$8;HEAP32[$vararg_ptr1>>2]=HEAP32[tempDoublePtr>>2];HEAP32[$vararg_ptr1+4>>2]=HEAP32[tempDoublePtr+4>>2];
(_printf((8|0),($vararg_buffer|0))|0);
STACKTOP = sp;return;
}
I have highlighted the interesting lines where the “bar" struct is essentially copied to a location in memory, pointed to by STACKTOP+16 and the function parameters $a and $b are assigned to the struct members (residing at the memory locations pointed to be $bar and $bar+4, respectively). Interestingly, emscripten uses the artificial stack (HEAP32 array at STACKTOP offset) for certain variables (such as structs and the vararg parameters for the printf call), whereas any variable that can be directly represented as a local variable (such as $a and $b) stays a local variable of the Javascript function.
Coming back to the problem of efficiently saving and restoring local variables, my understanding is that you would need to save 16 local variables ($a, $b, $0 … $8, $bar, $vararg_buffer, $vararg_ptr1, label, sp). Some of these would probably be eliminated by better optimisation settings (like $2, $3, $4), but you may still end up with a whole lot of local variables to be taken care of. If you elevated all of the local variables to struct members like proposed before, you would in principle have fewer work to do for saving and restoring them. However, each access would turn into a HEAP32[(funcScopePtr + variableOffset|0)>>2] operation. I would *guess* that the performance implications are next to nothing (at the least in an AOT asm.js runtime).