#6390·pyodide

Status of synchronous WASM compilation limitation in main thread (2026/07)

Author: ryanking13Created Jul 28, 2026Updated Aug 4, 2026

@hoodmane told me in EuroPython that the synchronous WASM compilation limit in Chrome was removed or at least relaxed a lot, so I tested it. Here is the result and related links.


Test script

It tests syncronously compiling WASM modules of size 8MiB, 8MiB +1, 16 MiB, and 64 MiB in the main thread.

javascript
function uleb(n) {
  const out = [];
  do {
    let b = n & 0x7f;
    n = Math.floor(n / 128);
    if (n) b |= 0x80;
    out.push(b);
  } while (n);
  return out;
}

function paddedModule(size) {
  const bytes = new Uint8Array(size);
  bytes.set([0, 97, 115, 109, 1, 0, 0, 0]); // wasm header
  bytes[8] = 0; // custom section

  let payload = size - 10;
  while (9 + uleb(payload).length + payload !== size) {
    payload += size - (9 + uleb(payload).length + payload);
  }

  const length = uleb(payload);
  bytes.set(length, 9);
  bytes[9 + length.length] = 0; // empty custom-section name
  return bytes;
}

for (const size of [
  8 * 1024 * 1024,
  8 * 1024 * 1024 + 1,
  16 * 1024 * 1024,
  64 * 1024 * 1024,
]) {
  try {
    const module = new WebAssembly.Module(paddedModule(size));
    new WebAssembly.Instance(module);
    console.log(size, "OK");
  } catch (error) {
    console.log(size, error.toString());
  }
}

Test result

Browser Result
Chrome (Windows, v150) 8MiB passes, 8MiB+ fails
Chrome (MacOS, v150) 8MiB passes, 8MiB+ fails
Chrome (Android [Pixel 9]) 8MiB passes, 8MiB+ fails
Chrome (iOS [iPhone 15]) Pass
Chrome (iPadOS [iPad 9]) Pass
Firefox (Windows, v153) Pass
Safari (MacOS, v26.5 ) Pass
Edge (Windows, v150) 8MiB passes, 8MiB+ fails
Node.js (v24) Pass
Deno (2.9.4) Pass
Bun (v1.3.14) Pass

So obviously chromium-based browsers has 8MiB limitation (which is increased from 4KiB before), while all other JS runtimes does not have it. Note that Chrome on iPhone and iPad does not have this limitation since they are based on WebKit.

Related changes

Chrome has updated the limitation in Chrome v115 which was landed Jul 2023 (3 years ago).

There is a --enable-features=WebAssemblyUnlimitedSyncCompilation flag which removes this limitation but it is disabled by default.

How large are shared libraries in Pyodide packages?

I scanned all packages in latest pyodide-recipes release and only the following packages have shared libraries with 8MiB or more.

Image

Note that all libraries in the numpy and scipy are under 8MiB

Sharedlib size in numpy and scipy

NumPy 2.4.3
2,154,517  numpy/_core/_multiarray_umath.so
1,056,155  numpy/linalg/_umath_linalg.so
  490,960  numpy/random/_generator.so
  389,101  numpy/random/mtrand.so
  260,256  numpy/fft/_pocketfft_umath.so
  207,529  numpy/linalg/lapack_lite.so
  138,648  numpy/random/_bounded_integers.so
  134,521  numpy/random/_common.so
  114,584  numpy/random/bit_generator.so
   58,123  numpy/random/_pcg64.so
   56,655  numpy/random/_mt19937.so
   53,558  numpy/random/_philox.so
   38,026  numpy/random/_sfc64.so
SciPy 1.18.0
6,456,081  scipy.libs/libopenblas.so
2,758,624  scipy/sparse/_sparsetools.so
2,377,843  scipy/optimize/_highspy/_core.so
1,419,071  scipy/special/_ufuncs_cxx.so
1,386,725  scipy/linalg/_flapack.so
  947,359  scipy/special/cython_special.so
  913,909  scipy/special/_special_ufuncs.so
  805,670  scipy/fft/_duccfft/pyduccfft.so
  705,946  scipy/io/_fast_matrix_market/_fmm_core.so
  561,884  scipy/spatial/_qhull.so
  545,850  scipy/special/_ufuncs.so
  480,765  scipy/special/_gufuncs.so
  405,566  scipy/linalg/_fblas.so
  367,781  scipy/linalg/_decomp_interpolative.so
  365,615  scipy/stats/_unuran/unuran_wrapper.so
  260,121  scipy/spatial/_ckdtree.so
  242,687  scipy/spatial/transform/_rotation_cy.so
  231,406  scipy/stats/_stats.so
  223,296  scipy/sparse/_csparsetools.so
  216,584  scipy/spatial/_distance_pybind.so
  203,624  scipy/sparse/csgraph/_shortest_path.so
  186,861  scipy/sparse/linalg/_dsolve/_superlu.so
  173,155  scipy/sparse/csgraph/_traversal.so
  162,387  scipy/optimize/_highspy/_highs_options.so
  150,585  scipy/linalg/cython_lapack.so
  147,497  scipy/linalg/_batched_linalg.so
  147,226  scipy/linalg/_decomp_update.so
  131,947  scipy/odr/__odrpack.so
  123,622  scipy/spatial/transform/_rigid_transform_cy.so
  122,553  scipy/sparse/linalg/_eigen/arpack/_arpacklib.so
  121,661  scipy/cluster/hierarchy/_hierarchy.so
  119,757  scipy/interpolate/_interpnd.so
  111,485  scipy/interpolate/_fitpack.so
  110,042  scipy/io/matlab/_mio5_utils.so
  103,251  scipy/linalg/_cythonized_array_utils.so
   99,335  scipy/special/_specfun.so
   97,671  scipy/interpolate/_ppoly.so
   96,634  scipy/interpolate/_rbfinterp_pythran.so
   95,854  scipy/sparse/csgraph/_tools.so
   94,811  scipy/optimize/_trlib/_trlib.so
   93,021  scipy/optimize/_bglu_dense.so
   93,010  scipy/signal/_upfirdn_apply.so
   86,301  scipy/sparse/csgraph/_matching.so
   85,685  scipy/stats/_sobol.so
   85,072  scipy/stats/_biasedurn.so
   83,937  scipy/optimize/_pava_pybind.so
   80,920  scipy/ndimage/_nd_image.so
   80,426  scipy/sparse/csgraph/_flow.so
   79,516  scipy/ndimage/_ni_label.so
   78,631  scipy/_cyutility.so
   75,398  scipy/sparse/csgraph/_reordering.so
   74,278  scipy/integrate/_quadpack.so
   71,940  scipy/cluster/hierarchy/_optimal_leaf_ordering.so
   59,781  scipy/linalg/cython_blas.so
   57,701  scipy/signal/_peak_finding_utils.so
   56,861  scipy/optimize/_moduleTNC.so
   56,589  scipy/linalg/_internal_matfuncs.so
   56,564  scipy/io/matlab/_streams.so
   56,213  scipy/sparse/linalg/_propack.so
   53,251  scipy/linalg/_solve_toeplitz.so
   52,259  scipy/integrate/_vode.so
   52,070  scipy/cluster/vq/_vq.so
   51,853  scipy/fftpack/convolve.so
   50,983  scipy/interpolate/_rgi_cython.so
   49,628  scipy/signal/_sosfilt.so
   49,497  scipy/signal/_sigtools.so
   48,249  scipy/stats/_qmc_cy.so
   47,473  scipy/stats/_stats_pythran.so
   47,398  scipy/stats/_qmvnt_cy.so
   45,816  scipy/special/_ellip_harm_2.so
   45,577  scipy/interpolate/_dierckx.so
   45,347  scipy/stats/_ansari_swilk_statistics.so
   43,951  scipy/sparse/csgraph/_min_spanning_tree.so
   43,212  scipy/linalg/_matfuncs_sqrtm_triu.so
   42,146  scipy/_lib/_ccallback_c.so
   41,866  scipy/stats/_rcont/rcont.so
   40,553  scipy/optimize/cython_optimize/_zeros.so
   38,586  scipy/spatial/_hausdorff.so
   38,261  scipy/optimize/_minpack.so
   38,193  scipy/linalg/_linalg_pythran.so
   38,089  scipy/_lib/_uarray/_uarray.so
   36,467  scipy/spatial/_voronoi.so
   36,225  scipy/ndimage/_cytest.so
   36,090  scipy/special/_test_internal.so
   33,211  scipy/_lib/messagestream.so
   32,833  scipy/integrate/_odepack.so
   29,327  scipy/io/matlab/_mio_utils.so
   25,605  scipy/optimize/_lsq/givens_elimination.so
   24,959  scipy/stats/_levy_stable/levyst.so
   23,984  scipy/optimize/_slsqplib.so
   23,868  scipy/spatial/_distance_wrap.so
   23,092  scipy/optimize/_group_columns.so
   22,725  scipy/special/_comb.so
   21,574  scipy/optimize/_lbfgsb.so
   19,533  scipy/signal/_spline.so
   17,656  scipy/optimize/_direct.so
   16,934  scipy/_lib/_test_deprecation_call.so
   15,644  scipy/integrate/_dop.so
   14,658  scipy/optimize/_lsap.so
   13,781  scipy/signal/_max_len_seq_inner.so
   10,171  scipy/ndimage/_rank_filter_1d.so
    8,500  scipy/_lib/_test_deprecation_def.so
    7,539  scipy/optimize/_zeros.so
    4,461  scipy/_lib/_test_ccallback.so
    1,972  scipy/ndimage/_ctest.so
    1,222  scipy/integrate/_test_multivariate.so
      747  scipy/_lib/_fpumode.so

I didn't check blis or semicolon-lapack so it would be great if @agriyakhetarpal can check them too.

Conclusion

I think we can start experimenting with synchronously loading WASM modules with 8MiB or lower, probably making a optional parameter in loadPyodide to disable / enable that feature. Since Chrome v115 is pretty old, I think we can enable it by default it things work well.