Slimmed AssemblyScript Compiler

AssemblyScript is a great target in notebooks, it can increase code performance, run in WebWorkers and remove the slow start Javascript has when first loaded. Its compiler size is ok (2.5MB) if you are building something that needs high performance and your readers are willing to wait a little for it.

import {toochain} from "@tomlarkworthy/assembly-script"
...
toolchain.asc("<program>")

Binaryen compiler was shrunk from 3.5MB to 2MB by exluding optimizations and programs AssemblyScript does not use. ActionScript frontend itself is quite small, Binaryen is the bit that does the clever performance improving bit (optimizing compiler)

edit
edit
asc 0.28.20 · slim binaryen 131 · toolchain ready in 199ms
edit
compiled in 136ms · 1091 bytes of wasm
edit
passes to full speed
2 vs 10
WebAssembly arrives at its floor; JavaScript is still being tiered up by V8
once both are warm
0.99×
2.01ms a pass against 1.98ms
the whole session
1.16×
126ms against 146ms for all 60 passes
2 4 8 1.98 ms2.01 ms ms/pass pass 1 — cold pass 60 JavaScript WebAssembly
2 independent runs of each, measured in this page just now. A pass is 24 inversions of a 48×48 matrix. Every series starts genuinely cold — a unique custom section on the wasm and a unique trailing comment on the JavaScript, so neither compilation cache can hit. The steps in the red line are V8 tiering the JavaScript up: interpreted, then baseline, then optimised. WebAssembly does the same thing once, between pass 1 and pass 2, and then stays at the dashed line. This clock resolves to 0.100ms — 5% of a pass — so the two per-pass figures above are 20% trimmed means over 40 passes, not single readings. Both implementations agree on the trace of the inverse (24.004116).
edit
the JavaScript it is measured against — the same algorithm, written the way you would write it
const N = 48, W = N * 2;
const m = new Float64Array(N * W);
const at = (i, j) => m[i * W + j];
const put = (i, j, v) => { m[i * W + j] = v; };

function fill(seed) {
  let z = seed >>> 0;
  for (let i = 0; i < N; i++) {
    for (let j = 0; j < N; j++) {
      z = (Math.imul(z, 1664525) + 1013904223) >>> 0;
      put(i, j, (z >>> 8) / 8388608.0 - 1.0);
      put(i, N + j, i === j ? 1.0 : 0.0);
    }
    put(i, i, at(i, i) + N);
  }
}

return function invert(rounds) {
  let acc = 0;
  for (let r = 0; r < rounds; r++) {
    fill(r + 1);
    for (let c = 0; c < N; c++) {
      let piv = c;
      for (let i = c + 1; i < N; i++) {
        if (Math.abs(at(i, c)) > Math.abs(at(piv, c))) piv = i;
      }
      if (piv !== c) {
        for (let j = 0; j < W; j++) {
          const t = at(c, j); put(c, j, at(piv, j)); put(piv, j, t);
        }
      }
      const d = at(c, c);
      for (let j = 0; j < W; j++) put(c, j, at(c, j) / d);
      for (let i = 0; i < N; i++) {
        if (i === c) continue;
        const f = at(i, c);
        if (f === 0.0) continue;
        for (let j = 0; j < W; j++) put(i, j, at(i, j) - f * at(c, j));
      }
    }
    for (let i = 0; i < N; i++) acc += at(i, N + i);
  }
  return acc;
};
edit
the WebAssembly text format asc emitted (438 lines)
(module
 (type $0 (func))
 (type $1 (func (param i32) (result f64)))
 (global $main/m (mut i32) (i32.const 0))
 (memory $0 1)
 (data $0 (i32.const 1036) ",")
 (data $0.1 (i32.const 1048) "\02\00\00\00\1c\00\00\00I\00n\00v\00a\00l\00i\00d\00 \00l\00e\00n\00g\00t\00h")
 (data $1 (i32.const 1084) "<")
 (data $1.1 (i32.const 1096) "\02\00\00\00&\00\00\00~\00l\00i\00b\00/\00s\00t\00a\00t\00i\00c\00a\00r\00r\00a\00y\00.\00t\00s")
 (data $2 (i32.const 1148) "<")
 (data $2.1 (i32.const 1160) "\02\00\00\00(\00\00\00A\00l\00l\00o\00c\00a\00t\00i\00o\00n\00 \00t\00o\00o\00 \00l\00a\00r\00g\00e")
 (data $3 (i32.const 1212) "<")
 (data $3.1 (i32.const 1224) "\02\00\00\00\1e\00\00\00~\00l\00i\00b\00/\00r\00t\00/\00s\00t\00u\00b\00.\00t\00s")
 (export "invert" (func $main/invert))
 (export "memory" (memory $0))
 (start $~start)
 (func $~start
  (local $0 i32)
  (local $1 i32)
  memory.size
  local.tee $0
  i32.const 16
  i32.shl
  i32.const 15
  i32.add
  i32.const -16
  i32.and
  local.tee $1
  i32.const 38172
  i32.lt_u
  if
   local.get $0
   i32.const 103707
   local.get $1
   i32.sub
   i32.const -65536
   i32.and
   i32.const 16
   i32.shr_u
   local.tee $1
   local.get $0
   local.get $1
   i32.gt_s
   select
   memory.grow
   i32.const 0
   i32.lt_s
   if
    local.get $1
    memory.grow
    i32.const 0
    i32.lt_s
    if
     unreachable
    end
   end
  end
  i32.const 1276
  i32.const 36892
  i32.store
  i32.const 1280
  i32.const 0
  i32.store
  i32.const 1284
  i32.const 0
  i32.store
  i32.const 1288
  i32.const 4
  i32.store
  i32.const 1292
  i32.const 36864
  i32.store
  i32.const 1296
  i32.const 0
  i32.const 36864
  memory.fill
  i32.const 1296
  global.set $main/m
 )
 (func $main/invert (param $0 i32) (result f64)
  (local $1 i32)
  (local $2 i32)
  (local $3 i32)
  (local $4 f64)
  (local $5 i32)
  (local $6 i32)
  (local $7 f64)
  loop $for-loop|0
   local.get $0
   local.get $6
   i32.gt_s
   if
    local.get $6
    i32.const 1
    i32.add
    local.set $5
    i32.const 0
    local.set $1
    loop $for-loop|00
     local.get $1
     i32.const 48
     i32.lt_s
     if
      i32.const 0
      local.set $2
      loop $for-loop|1
       local.get $2
       i32.const 48
       i32.lt_s
       if
        global.get $main/m
        local.get $1
        i32.const 96
        i32.mul
        local.tee $3
        local.get $2
        i32.add
        i32.const 3
        i32.shl
        i32.add
        local.get $5
        i32.const 1664525
        i32.mul
        i32.const 1013904223
        i32.add
        local.tee $5
        i32.const 8
        i32.shr_u
        f64.convert_i32_u
        f64.const 1.1920928955078125e-07
        f64.mul
        f64.const -1
        f64.add
        f64.store
        global.get $main/m
        local.get $2
        i32.const 48
        i32.add
        local.get $3
        i32.add
        i32.const 3
        i32.shl
        i32.add
        f64.const 1
        f64.const 0
        local.get $1
        local.get $2
        i32.eq
        select
        f64.store
        local.get $2
        i32.const 1
        i32.add
        local.set $2
        br $for-loop|1
       end
      end
      global.get $main/m
      local.get $1
      i32.const 96
      i32.mul
      local.get $1
      i32.add
      i32.const 3
      i32.shl
      i32.add
      local.tee $2
      local.get $2
      f64.load
      f64.const 48
      f64.add
      f64.store
      local.get $1
      i32.const 1
      i32.add
      local.set $1
      br $for-loop|00
     end
    end
    i32.const 0
    local.set $2
    loop $for-loop|11
     local.get $2
     i32.const 48
     i32.lt_s
     if
      local.get $2
      local.tee $1
      i32.const 1
      i32.add
      local.set $5
      loop $for-loop|2
       local.get $5
       i32.const 48
       i32.lt_s
       if
        local.get $5
        local.get $1
        global.get $main/m
        local.get $5
        i32.const 96
        i32.mul
        local.get $2
        i32.add
        i32.const 3
        i32.shl
        i32.add
        f64.load
        f64.abs
        global.get $main/m
        local.get $1
        i32.const 96
        i32.mul
        local.get $2
        i32.add
        i32.const 3
        i32.shl
        i32.add
        f64.load
        f64.abs
        f64.gt
        select
        local.set $1
        local.get $5
        i32.const 1
        i32.add
        local.set $5
        br $for-loop|2
       end
      end
      local.get $1
      local.get $2
      i32.ne
      if
       i32.const 0
       local.set $5
       loop $for-loop|3
        local.get $5
        i32.const 96
        i32.lt_s
        if
         global.get $main/m
         local.get $2
         i32.const 96
         i32.mul
         local.get $5
         i32.add
         i32.const 3
         i32.shl
         i32.add
         local.tee $3
         f64.load
         local.set $4
         local.get $3
         global.get $main/m
         local.get $1
         i32.const 96
         i32.mul
         local.get $5
         i32.add
         i32.const 3
         i32.shl
         i32.add
         local.tee $3
         f64.load
         f64.store
         local.get $3
         local.get $4
         f64.store
         local.get $5
         i32.const 1
         i32.add
         local.set $5
         br $for-loop|3
        end
       end
      end
      global.get $main/m
      local.get $2
      i32.const 96
      i32.mul
      local.get $2
      i32.add
      i32.const 3
      i32.shl
      i32.add
      f64.load
      local.set $4
      i32.const 0
      local.set $1
      loop $for-loop|4
       local.get $1
       i32.const 96
       i32.lt_s
       if
        global.get $main/m
        local.get $2
        i32.const 96
        i32.mul
        local.get $1
        i32.add
        i32.const 3
        i32.shl
        i32.add
        local.tee $3
        local.get $3
        f64.load
        local.get $4
        f64.div
        f64.store
        local.get $1
        i32.const 1
        i32.add
        local.set $1
        br $for-loop|4
       end
      end
      i32.const 0
      local.set $1
      loop $for-loop|5
       local.get $1
       i32.const 48
       i32.lt_s
       if
        block $for-continue|5
         local.get $1
         local.get $2
         i32.eq
         br_if $for-continue|5
         global.get $main/m
         local.get $1
         i32.const 96
         i32.mul
         local.get $2
         i32.add
         i32.const 3
         i32.shl
         i32.add
         f64.load
         local.tee $4
         f64.const 0
         f64.eq
         br_if $for-continue|5
         i32.const 0
         local.set $5
         loop $for-loop|6
          local.get $5
          i32.const 96
          i32.lt_s
          if
           global.get $main/m
           local.get $1
           i32.const 96
           i32.mul
           local.get $5
           i32.add
           i32.const 3
           i32.shl
           i32.add
           local.tee $3
           local.get $3
           f64.load
           local.get $4
           global.get $main/m
           local.get $2
           i32.const 96
           i32.mul
           local.get $5
           i32.add
           i32.const 3
           i32.shl
           i32.add
           f64.load
           f64.mul
           f64.sub
           f64.store
           local.get $5
           i32.const 1
           i32.add
           local.set $5
           br $for-loop|6
          end
         end
        end
        local.get $1
        i32.const 1
        i32.add
        local.set $1
        br $for-loop|5
       end
      end
      local.get $2
      i32.const 1
      i32.add
      local.set $2
      br $for-loop|11
     end
    end
    i32.const 0
    local.set $1
    loop $for-loop|7
     local.get $1
     i32.const 48
     i32.lt_s
     if
      local.get $7
      global.get $main/m
      local.get $1
      i32.const 48
      i32.add
      local.get $1
      i32.const 96
      i32.mul
      i32.add
      i32.const 3
      i32.shl
      i32.add
      f64.load
      f64.add
      local.set $7
      local.get $1
      i32.const 1
      i32.add
      local.set $1
      br $for-loop|7
     end
    end
    local.get $6
    i32.const 1
    i32.add
    local.set $6
    br $for-loop|0
   end
  end
  local.get $7
 )
)
edit