Skip to content

LibJS: Add hand-written assembly bytecode interpreter - #8299

Merged
awesomekling merged 5 commits into
LadybirdBrowser:masterfrom
awesomekling:asmint
Mar 7, 2026
Merged

awesomekling merged 5 commits into
LadybirdBrowser:masterfrom
awesomekling:asmint

Conversation

@awesomekling

Copy link
Copy Markdown
Member

This PR adds a new bytecode interpreter for LibJS that executes via generated assembly instead of the C++ indirect-threaded computed goto interpreter. The bytecode PC and register file pointer live in machine registers, opcodes dispatch through a jump table, and hot paths (arithmetic, comparisons, property access on simple objects) stay entirely in assembly. Cold and complex operations call into C++ helpers.

The assembly is written in a custom DSL (asmint.asm) that a Rust tool (AsmIntGen) compiles into native x86_64 or aarch64 assembly. Instruction layouts come from Bytecode.def and struct field offsets from a small build-time C++ tool, so the assembly stays in sync with C++ struct layouts automatically.

Supported on Linux and macOS, both x86_64 and aarch64. Enabled by default where supported. Set LIBJS_USE_CPP_INTERPRETER=1 to fall back.

Benchmarks look great. There's more work to do on squeezing the generated code for performance ofc :)

macOS (M3 MacBook Pro):

Suite       Test                                      Speedup  Old (Mean ± Range)                 New (Mean ± Range)
----------  --------------------------------------  ---------  ---------------------------------  ---------------------------------
SunSpider   3d-cube.js                                  1.145  0.017 ± 0.017 … 0.017              0.015 ± 0.015 … 0.015
SunSpider   3d-morph.js                                 1.182  0.022 ± 0.022 … 0.022              0.019 ± 0.018 … 0.019
SunSpider   3d-raytrace.js                              1.106  0.020 ± 0.020 … 0.020              0.018 ± 0.018 … 0.018
SunSpider   access-binary-trees.js                      0.932  0.014 ± 0.014 … 0.014              0.015 ± 0.015 … 0.015
SunSpider   access-fannkuch.js                          1.497  0.031 ± 0.031 … 0.031              0.021 ± 0.020 … 0.021
SunSpider   access-nbody.js                             1.497  0.021 ± 0.021 … 0.021              0.014 ± 0.014 … 0.014
SunSpider   access-nsieve.js                            1.165  0.013 ± 0.013 … 0.013              0.011 ± 0.011 … 0.011
SunSpider   bitops-3bit-bits-in-byte.js                 1.063  0.011 ± 0.011 … 0.012              0.011 ± 0.011 … 0.011
SunSpider   bitops-bits-in-byte.js                      1.135  0.016 ± 0.016 … 0.016              0.014 ± 0.014 … 0.014
SunSpider   bitops-bitwise-and.js                       1.598  0.022 ± 0.022 … 0.023              0.014 ± 0.014 … 0.014
SunSpider   bitops-nsieve-bits.js                       1.432  0.018 ± 0.017 … 0.018              0.012 ± 0.012 … 0.012
SunSpider   controlflow-recursive.js                    1.019  0.011 ± 0.011 … 0.011              0.011 ± 0.011 … 0.011
SunSpider   crypto-aes.js                               1.09   0.018 ± 0.018 … 0.018              0.017 ± 0.016 … 0.017
SunSpider   crypto-md5.js                               1.034  0.012 ± 0.012 … 0.012              0.011 ± 0.011 … 0.011
SunSpider   crypto-sha1.js                              1.065  0.011 ± 0.011 … 0.012              0.011 ± 0.011 … 0.011
SunSpider   date-format-tofte.js                        0.968  0.039 ± 0.039 … 0.039              0.041 ± 0.040 … 0.041
SunSpider   date-format-xparb.js                        0.928  0.026 ± 0.025 … 0.026              0.028 ± 0.028 … 0.028
SunSpider   math-cordic.js                              1.168  0.020 ± 0.020 … 0.020              0.017 ± 0.017 … 0.017
SunSpider   math-partial-sums.js                        1.193  0.015 ± 0.015 … 0.015              0.012 ± 0.012 … 0.012
SunSpider   math-spectral-norm.js                       0.973  0.013 ± 0.012 … 0.013              0.013 ± 0.013 … 0.013
SunSpider   regexp-dna.js                               0.96   0.335 ± 0.335 … 0.336              0.349 ± 0.348 … 0.351
SunSpider   string-base64.js                            0.957  0.015 ± 0.014 … 0.015              0.015 ± 0.015 … 0.016
SunSpider   string-fasta.js                             0.985  0.054 ± 0.054 … 0.054              0.055 ± 0.054 … 0.056
SunSpider   string-tagcloud.js                          0.949  0.069 ± 0.069 … 0.070              0.073 ± 0.072 … 0.074
SunSpider   string-unpack-code.js                       0.941  0.064 ± 0.064 … 0.064              0.068 ± 0.068 … 0.068
SunSpider   string-validate-input.js                    0.886  0.018 ± 0.018 … 0.019              0.021 ± 0.021 … 0.021
Kraken      ai-astar.js                                 1.713  1.018 ± 1.011 … 1.026              0.595 ± 0.594 … 0.596
Kraken      audio-beat-detection.js                     1.662  0.806 ± 0.806 … 0.807              0.485 ± 0.485 … 0.486
Kraken      audio-dft.js                                1.582  0.547 ± 0.541 … 0.552              0.345 ± 0.342 … 0.349
Kraken      audio-fft.js                                1.671  0.697 ± 0.696 … 0.698              0.417 ± 0.417 … 0.417
Kraken      audio-oscillator.js                         1.586  0.648 ± 0.647 … 0.649              0.408 ± 0.406 … 0.410
Kraken      imaging-darkroom.js                         1.466  0.937 ± 0.935 … 0.939              0.639 ± 0.639 … 0.639
Kraken      imaging-desaturate.js                       2.076  1.269 ± 1.266 … 1.273              0.611 ± 0.608 … 0.615
Kraken      imaging-gaussian-blur.js                    1.784  5.108 ± 5.106 … 5.111              2.863 ± 2.854 … 2.873
Kraken      json-parse-financial.js                     0.982  0.056 ± 0.055 … 0.057              0.057 ± 0.057 … 0.058
Kraken      json-stringify-tinderbox.js                 1.012  0.058 ± 0.056 … 0.060              0.057 ± 0.057 … 0.058
Kraken      stanford-crypto-aes.js                      1.268  0.282 ± 0.282 … 0.283              0.222 ± 0.222 … 0.223
Kraken      stanford-crypto-ccm.js                      1.162  0.260 ± 0.256 … 0.264              0.224 ± 0.223 … 0.225
Kraken      stanford-crypto-pbkdf2.js                   1.164  0.494 ± 0.485 … 0.504              0.425 ± 0.422 … 0.427
Kraken      stanford-crypto-sha256-iterative.js         1.109  0.185 ± 0.184 … 0.185              0.166 ± 0.166 … 0.167
Octane      box2d.js                                    1.435  5488.000 ± 5478.000 … 5498.000     7873.500 ± 7858.000 … 7889.000
Octane      code-load.js                                0.957  16342.500 ± 16335.000 … 16350.000  15638.500 ± 15601.000 … 15676.000
Octane      crypto.js                                   1.476  1916.500 ± 1916.000 … 1917.000     2829.000 ± 2826.000 … 2832.000
Octane      deltablue.js                                1.156  1418.000 ± 1417.000 … 1419.000     1639.000 ± 1615.000 … 1663.000
Octane      earley-boyer.js                             1.115  3638.500 ± 3622.000 … 3655.000     4055.500 ± 3995.000 … 4116.000
Octane      gbemu.js                                    1.491  10831.500 ± 10809.000 … 10854.000  16151.500 ± 15960.000 … 16343.000
Octane      mandreel.js                                 1.574  9072.500 ± 9048.000 … 9097.000     14284.000 ± 14243.000 … 14325.000
Octane      navier-stokes.js                            1.79   2350.000 ± 2349.000 … 2351.000     4207.000 ± 4199.000 … 4215.000
Octane      pdfjs.js                                    1.073  6003.000 ± 6003.000 … 6003.000     6440.500 ± 6426.000 … 6455.000
Octane      raytrace.js                                 1.054  2447.000 ± 2437.000 … 2457.000     2579.500 ± 2572.000 … 2587.000
Octane      regexp.js                                   0.974  193.000 ± 193.000 … 193.000        188.000 ± 187.000 … 189.000
Octane      richards.js                                 1.372  1429.000 ± 1414.000 … 1444.000     1961.000 ± 1959.000 … 1963.000
Octane      splay.js                                    0.923  5968.000 ± 5964.000 … 5972.000     5507.500 ± 5492.000 … 5523.000
Octane      typescript.js                               1.111  15813.000 ± 15765.000 … 15861.000  17566.500 ± 17534.000 … 17599.000
Octane      zlib.js                                     1.639  3223.500 ± 3219.000 … 3228.000     5282.000 ± 4803.000 … 5761.000
JetStream   bigfib.cpp.js                               1.631  8.212 ± 8.191 … 8.232              5.036 ± 5.005 … 5.066
JetStream   cdjs.js                                     1.071  2.825 ± 2.819 … 2.832              2.639 ± 2.533 … 2.744
JetStream   container.cpp.js                            1.428  31.058 ± 30.971 … 31.145           21.750 ± 21.636 … 21.864
JetStream   dry.c.js                                    2.163  22.745 ± 22.743 … 22.747           10.514 ± 10.507 … 10.521
JetStream   float-mm.c.js                               1.253  21.640 ± 21.606 … 21.674           17.269 ± 17.232 … 17.305
JetStream   gcc-loops.cpp.js                            1.787  127.827 ± 126.781 … 128.874        71.549 ± 71.492 … 71.606
JetStream   hash-map.js                                 1.218  1.283 ± 1.276 … 1.291              1.054 ± 1.050 … 1.058
JetStream   n-body.c.js                                 1.838  34.406 ± 34.379 … 34.434           18.715 ± 18.390 … 19.039
JetStream   quicksort.c.js                              1.492  4.584 ± 4.571 … 4.596              3.072 ± 3.026 … 3.118
JetStream   towers.c.js                                 1.811  6.121 ± 6.118 … 6.124              3.379 ± 3.363 … 3.395
JetStream3  js-tokens.js                                1.013  0.705 ± 0.692 … 0.717              0.695 ± 0.695 … 0.696
JetStream3  lazy-collections.js                         1.064  1.035 ± 1.030 … 1.040              0.973 ± 0.971 … 0.975
JetStream3  raytrace-private-class-fields.js            1.101  4.047 ± 4.019 … 4.074              3.675 ± 3.640 … 3.710
JetStream3  raytrace-public-class-fields.js             1.123  3.069 ± 3.060 … 3.078              2.732 ± 2.721 … 2.742
JetStream3  sync-file-system.js                         1.21   2.007 ± 2.004 … 2.010              1.659 ± 1.635 … 1.682
GarBench    array-of-objects.js                         1.027  0.675 ± 0.673 … 0.677              0.657 ± 0.651 … 0.663
GarBench    closures.js                                 0.956  0.858 ± 0.856 … 0.859              0.897 ± 0.895 … 0.900
GarBench    cyclic-graph.js                             1.028  2.365 ± 2.361 … 2.370              2.302 ± 2.299 … 2.305
GarBench    deep-linked-list.js                         1.156  0.616 ± 0.613 … 0.619              0.533 ± 0.528 … 0.538
GarBench    finalization.js                             1.008  0.993 ± 0.992 … 0.993              0.985 ± 0.974 … 0.996
GarBench    many-properties.js                          0.96   2.163 ± 2.161 … 2.166              2.254 ± 2.252 … 2.255
GarBench    marking-stress.js                           1.193  2.440 ± 2.435 … 2.446              2.045 ± 1.695 … 2.395
GarBench    mixed-sizes.js                              0.979  0.940 ± 0.927 … 0.953              0.960 ± 0.949 … 0.972
GarBench    sparse-arrays.js                            1.085  1.747 ± 1.733 … 1.762              1.611 ± 1.607 … 1.615
GarBench    string-heavy.js                             1.031  1.327 ± 1.325 … 1.329              1.286 ± 1.280 … 1.293
GarBench    wide-tree.js                                0.998  1.159 ± 1.135 … 1.183              1.162 ± 1.155 … 1.168
MicroBench  array-destructuring-assignment-rest.js      0.975  0.401 ± 0.401 … 0.401              0.411 ± 0.407 … 0.415
MicroBench  array-destructuring-assignment.js           0.948  2.079 ± 2.067 … 2.091              2.193 ± 2.186 … 2.201
MicroBench  array-prototype-map.js                      0.971  1.056 ± 1.054 … 1.057              1.088 ± 1.060 … 1.115
MicroBench  array-prototype-shift.js                    1.042  0.012 ± 0.011 … 0.013              0.011 ± 0.011 … 0.011
MicroBench  base64-from.js                              0.971  0.184 ± 0.183 … 0.185              0.189 ± 0.189 … 0.189
MicroBench  base64-to.js                                0.9    0.213 ± 0.209 … 0.216              0.236 ± 0.231 … 0.242
MicroBench  bound-call-00-args.js                       1.103  1.452 ± 1.451 … 1.454              1.316 ± 1.316 … 1.317
MicroBench  bound-call-04-args.js                       1.136  1.692 ± 1.687 … 1.697              1.489 ± 1.489 … 1.490
MicroBench  bound-call-16-args.js                       1.095  1.804 ± 1.793 … 1.816              1.648 ± 1.646 … 1.650
MicroBench  call-00-args.js                             1.213  1.001 ± 0.999 … 1.003              0.825 ± 0.822 … 0.828
MicroBench  call-01-args.js                             1.202  1.000 ± 0.999 … 1.002              0.833 ± 0.830 … 0.835
MicroBench  call-02-args.js                             1.176  0.997 ± 0.997 … 0.998              0.848 ± 0.844 … 0.852
MicroBench  call-03-args.js                             1.204  1.036 ± 1.035 … 1.038              0.861 ± 0.857 … 0.864
MicroBench  call-04-args.js                             1.216  1.061 ± 1.060 … 1.062              0.873 ± 0.872 … 0.873
MicroBench  call-16-args.js                             1.157  1.243 ± 1.241 … 1.246              1.074 ± 1.072 … 1.076
MicroBench  call-32-args.js                             1.081  1.464 ± 1.461 … 1.468              1.355 ± 1.354 … 1.355
MicroBench  call-native.js                              0.92   0.652 ± 0.645 … 0.659              0.708 ± 0.707 … 0.708
MicroBench  construct-00-args.js                        1.016  0.846 ± 0.830 … 0.863              0.833 ± 0.826 … 0.840
MicroBench  construct-04-args.js                        0.988  0.857 ± 0.852 … 0.861              0.867 ± 0.867 … 0.868
MicroBench  deep-call-stack.js                          1.156  0.374 ± 0.373 … 0.375              0.324 ± 0.322 … 0.326
MicroBench  env-binding-oneshot-eval.js                 1.115  0.590 ± 0.587 … 0.592              0.529 ± 0.529 … 0.529
MicroBench  for-in-indexed-properties.js                1.008  0.812 ± 0.812 … 0.813              0.806 ± 0.801 … 0.811
MicroBench  for-in-named-properties.js                  0.983  1.181 ± 1.169 … 1.193              1.202 ± 1.197 … 1.206
MicroBench  for-of.js                                   1.103  0.454 ± 0.453 … 0.454              0.411 ± 0.406 … 0.417
MicroBench  json-parse-edge-cases.js                    0.963  0.007 ± 0.006 … 0.007              0.007 ± 0.007 … 0.008
MicroBench  json-parse-massive.js                       0.995  0.905 ± 0.892 … 0.918              0.910 ± 0.902 … 0.917
MicroBench  json-stringify-edge-cases.js                0.984  0.007 ± 0.006 … 0.008              0.007 ± 0.007 … 0.007
MicroBench  json-stringify-massive.js                   0.998  0.970 ± 0.963 … 0.977              0.971 ± 0.969 … 0.974
MicroBench  lots-alloc.js                               1.015  2.635 ± 2.623 … 2.646              2.596 ± 2.579 … 2.614
MicroBench  object-keys.js                              1.007  1.626 ± 1.603 … 1.649              1.615 ± 1.604 … 1.626
MicroBench  object-literal.js                           0.862  1.149 ± 1.146 … 1.151              1.332 ± 1.325 … 1.339
MicroBench  object-set-with-rope-strings.js             1.004  0.574 ± 0.574 … 0.575              0.572 ± 0.569 … 0.576
MicroBench  pic-add-own.js                              1.094  0.800 ± 0.797 … 0.803              0.731 ± 0.729 … 0.733
MicroBench  pic-get-own.js                              1.167  0.890 ± 0.878 … 0.902              0.763 ± 0.760 … 0.766
MicroBench  pic-get-pchain.js                           1.186  0.910 ± 0.874 … 0.947              0.767 ± 0.747 … 0.788
MicroBench  pic-put-own.js                              1.302  1.103 ± 1.092 … 1.113              0.847 ± 0.846 … 0.847
MicroBench  pic-put-pchain.js                           0.932  1.824 ± 1.823 … 1.826              1.957 ± 1.940 … 1.974
MicroBench  setter-in-prototype-chain.js                0.966  1.830 ± 1.818 … 1.842              1.894 ± 1.876 … 1.912
MicroBench  strictly-equals-object.js                   1.956  2.034 ± 1.982 … 2.086              1.040 ± 1.038 … 1.042
SunSpider   Total                                       1.023  0.927                              0.906
Kraken      Total                                       1.645  12.366                             7.516
Octane      Total                                       1.233  86134.000                          106203.000
JetStream   Total                                       1.682  260.702                            154.975
JetStream3  Total                                       1.116  10.862                             9.734
GarBench    Total                                       1.04   15.282                             14.692
MicroBench  Total                                       1.075  39.726                             36.941
All Suites  Total                                       1.451  437.710                            301.685

Linux (AMD Ryzen 7 PRO 8700GE)

Suite       Test                                      Speedup  Old (Mean ± Range)                 New (Mean ± Range)
----------  --------------------------------------  ---------  ---------------------------------  ---------------------------------
SunSpider   3d-cube.js                                  1.146  0.016 ± 0.016 … 0.017              0.014 ± 0.014 … 0.015
SunSpider   3d-morph.js                                 1.152  0.020 ± 0.020 … 0.020              0.017 ± 0.017 … 0.018
SunSpider   3d-raytrace.js                              1.018  0.017 ± 0.017 … 0.017              0.017 ± 0.017 … 0.017
SunSpider   access-binary-trees.js                      0.936  0.013 ± 0.013 … 0.013              0.014 ± 0.014 … 0.014
SunSpider   access-fannkuch.js                          1.294  0.024 ± 0.024 … 0.024              0.019 ± 0.018 … 0.019
SunSpider   access-nbody.js                             1.4    0.016 ± 0.015 … 0.016              0.011 ± 0.011 … 0.012
SunSpider   access-nsieve.js                            1.12   0.011 ± 0.011 … 0.012              0.010 ± 0.010 … 0.011
SunSpider   bitops-3bit-bits-in-byte.js                 1.051  0.010 ± 0.010 … 0.010              0.009 ± 0.009 … 0.010
SunSpider   bitops-bits-in-byte.js                      1.114  0.011 ± 0.010 … 0.011              0.010 ± 0.009 … 0.010
SunSpider   bitops-bitwise-and.js                       1.381  0.015 ± 0.014 … 0.015              0.011 ± 0.010 … 0.011
SunSpider   bitops-nsieve-bits.js                       1.334  0.014 ± 0.013 … 0.014              0.010 ± 0.010 … 0.010
SunSpider   controlflow-recursive.js                    1.088  0.010 ± 0.010 … 0.011              0.010 ± 0.010 … 0.010
SunSpider   crypto-aes.js                               1.046  0.018 ± 0.018 … 0.019              0.018 ± 0.018 … 0.018
SunSpider   crypto-md5.js                               1.132  0.011 ± 0.010 … 0.011              0.010 ± 0.009 … 0.010
SunSpider   crypto-sha1.js                              0.95   0.009 ± 0.009 … 0.010              0.010 ± 0.010 … 0.010
SunSpider   date-format-tofte.js                        0.979  0.041 ± 0.041 … 0.041              0.042 ± 0.041 … 0.042
SunSpider   date-format-xparb.js                        0.948  0.029 ± 0.029 … 0.030              0.031 ± 0.030 … 0.032
SunSpider   math-cordic.js                              1.059  0.017 ± 0.016 … 0.017              0.016 ± 0.015 … 0.016
SunSpider   math-partial-sums.js                        1.135  0.011 ± 0.011 … 0.011              0.010 ± 0.009 … 0.010
SunSpider   math-spectral-norm.js                       1.11   0.011 ± 0.010 … 0.011              0.010 ± 0.009 … 0.010
SunSpider   regexp-dna.js                               0.993  0.446 ± 0.443 … 0.450              0.450 ± 0.441 … 0.458
SunSpider   string-base64.js                            0.942  0.016 ± 0.016 … 0.017              0.017 ± 0.017 … 0.018
SunSpider   string-fasta.js                             0.988  0.058 ± 0.057 … 0.058              0.058 ± 0.058 … 0.059
SunSpider   string-tagcloud.js                          0.988  0.081 ± 0.081 … 0.082              0.082 ± 0.081 … 0.084
SunSpider   string-unpack-code.js                       1.037  0.073 ± 0.072 … 0.074              0.070 ± 0.070 … 0.071
SunSpider   string-validate-input.js                    0.854  0.020 ± 0.020 … 0.021              0.024 ± 0.023 … 0.024
Kraken      ai-astar.js                                 1.742  1.023 ± 1.019 … 1.027              0.587 ± 0.583 … 0.591
Kraken      audio-beat-detection.js                     1.373  0.732 ± 0.715 … 0.749              0.533 ± 0.532 … 0.535
Kraken      audio-dft.js                                1.441  0.491 ± 0.491 … 0.492              0.341 ± 0.339 … 0.343
Kraken      audio-fft.js                                1.464  0.658 ± 0.647 … 0.670              0.449 ± 0.447 … 0.452
Kraken      audio-oscillator.js                         1.127  0.554 ± 0.554 … 0.555              0.492 ± 0.458 … 0.526
Kraken      imaging-darkroom.js                         1.296  0.818 ± 0.815 … 0.822              0.632 ± 0.625 … 0.638
Kraken      imaging-desaturate.js                       1.848  1.138 ± 1.136 … 1.140              0.616 ± 0.604 … 0.628
Kraken      imaging-gaussian-blur.js                    1.382  4.000 ± 3.997 … 4.004              2.895 ± 2.731 … 3.059
Kraken      json-parse-financial.js                     1.008  0.057 ± 0.057 … 0.058              0.057 ± 0.056 … 0.058
Kraken      json-stringify-tinderbox.js                 1.018  0.056 ± 0.055 … 0.057              0.055 ± 0.055 … 0.056
Kraken      stanford-crypto-aes.js                      1.035  0.245 ± 0.245 … 0.246              0.237 ± 0.235 … 0.239
Kraken      stanford-crypto-ccm.js                      1.025  0.289 ± 0.288 … 0.291              0.282 ± 0.282 … 0.283
Kraken      stanford-crypto-pbkdf2.js                   1.107  0.492 ± 0.489 … 0.496              0.445 ± 0.437 … 0.452
Kraken      stanford-crypto-sha256-iterative.js         1.026  0.188 ± 0.188 … 0.188              0.183 ± 0.183 … 0.184
Octane      box2d.js                                    1.266  5678.000 ± 5675.000 … 5681.000     7189.000 ± 7182.000 … 7196.000
Octane      code-load.js                                0.996  10297.000 ± 10277.000 … 10317.000  10259.000 ± 10221.000 … 10297.000
Octane      crypto.js                                   1.089  2294.000 ± 2244.000 … 2344.000     2498.500 ± 2157.000 … 2840.000
Octane      deltablue.js                                1.055  1178.000 ± 1175.000 … 1181.000     1242.500 ± 1177.000 … 1308.000
Octane      earley-boyer.js                             1.044  3027.000 ± 2999.000 … 3055.000     3160.000 ± 3159.000 … 3161.000
Octane      gbemu.js                                    1.216  11480.000 ± 11440.000 … 11520.000  13965.000 ± 13934.000 … 13996.000
Octane      mandreel.js                                 1.242  8632.500 ± 8625.000 … 8640.000     10721.000 ± 10698.000 … 10744.000
Octane      navier-stokes.js                            1.525  3630.500 ± 3627.000 … 3634.000     5536.500 ± 5404.000 … 5669.000
Octane      pdfjs.js                                    1.072  4635.000 ± 4331.000 … 4939.000     4968.000 ± 4958.000 … 4978.000
Octane      raytrace.js                                 1.036  2208.000 ± 2207.000 … 2209.000     2288.500 ± 2278.000 … 2299.000
Octane      regexp.js                                   1.006  176.000 ± 175.000 … 177.000        177.000 ± 176.000 … 178.000
Octane      richards.js                                 1.192  1316.000 ± 1312.000 … 1320.000     1568.500 ± 1559.000 … 1578.000
Octane      splay.js                                    0.976  2255.500 ± 2254.000 … 2257.000     2201.500 ± 2193.000 … 2210.000
Octane      typescript.js                               1.05   13618.000 ± 13596.000 … 13640.000  14299.000 ± 14242.000 … 14356.000
Octane      zlib.js                                     1.193  4176.000 ± 4134.000 … 4218.000     4983.500 ± 4979.000 … 4988.000
JetStream   bigfib.cpp.js                               1.197  6.587 ± 6.499 … 6.675              5.505 ± 5.421 … 5.589
JetStream   cdjs.js                                     0.998  3.122 ± 3.121 … 3.123              3.129 ± 2.971 … 3.286
JetStream   container.cpp.js                            1.097  26.199 ± 25.831 … 26.567           23.885 ± 23.284 … 24.486
JetStream   dry.c.js                                    1.208  16.234 ± 15.860 … 16.609           13.436 ± 13.306 … 13.566
JetStream   float-mm.c.js                               1.002  16.631 ± 16.016 … 17.246           16.596 ± 16.531 … 16.661
JetStream   gcc-loops.cpp.js                            1.173  99.732 ± 98.010 … 101.454          85.045 ± 84.856 … 85.235
JetStream   hash-map.js                                 1.097  1.391 ± 1.381 … 1.401              1.268 ± 1.263 … 1.274
JetStream   n-body.c.js                                 1.448  26.353 ± 25.356 … 27.350           18.199 ± 18.117 … 18.280
JetStream   quicksort.c.js                              1.061  3.607 ± 3.480 … 3.733              3.400 ± 3.310 … 3.490
JetStream   towers.c.js                                 1.259  5.509 ± 5.003 … 6.014              4.374 ± 4.351 … 4.398
JetStream3  js-tokens.js                                0.996  0.780 ± 0.778 … 0.781              0.783 ± 0.778 … 0.788
JetStream3  lazy-collections.js                         1.025  1.192 ± 1.184 … 1.199              1.162 ± 1.155 … 1.169
JetStream3  raytrace-private-class-fields.js            1.06   4.277 ± 4.235 … 4.318              4.034 ± 4.027 … 4.041
JetStream3  raytrace-public-class-fields.js             1.071  3.273 ± 3.254 … 3.292              3.056 ± 3.048 … 3.063
JetStream3  sync-file-system.js                         0.878  1.857 ± 1.836 … 1.879              2.115 ± 2.059 … 2.171
GarBench    array-of-objects.js                         0.928  0.984 ± 0.975 … 0.993              1.060 ± 1.054 … 1.066
GarBench    closures.js                                 0.955  1.594 ± 1.590 … 1.599              1.669 ± 1.662 … 1.675
GarBench    cyclic-graph.js                             0.988  2.014 ± 1.993 … 2.035              2.038 ± 1.984 … 2.092
GarBench    deep-linked-list.js                         0.977  0.950 ± 0.948 … 0.952              0.972 ± 0.967 … 0.977
GarBench    finalization.js                             1.032  1.950 ± 1.879 … 2.021              1.889 ± 1.843 … 1.935
GarBench    many-properties.js                          0.931  3.262 ± 3.255 … 3.269              3.503 ± 3.497 … 3.508
GarBench    marking-stress.js                           0.964  2.177 ± 2.005 … 2.348              2.258 ± 2.007 … 2.509
GarBench    mixed-sizes.js                              1.051  1.409 ± 1.404 … 1.414              1.340 ± 1.339 … 1.342
GarBench    sparse-arrays.js                            0.968  2.243 ± 2.171 … 2.315              2.317 ± 2.315 … 2.320
GarBench    string-heavy.js                             0.951  1.953 ± 1.948 … 1.958              2.054 ± 2.048 … 2.060
GarBench    wide-tree.js                                0.988  2.089 ± 2.070 … 2.108              2.114 ± 2.101 … 2.128
MicroBench  array-destructuring-assignment-rest.js      1.003  0.403 ± 0.402 … 0.404              0.401 ± 0.394 … 0.409
MicroBench  array-destructuring-assignment.js           0.963  3.746 ± 3.725 … 3.768              3.890 ± 3.812 … 3.969
MicroBench  array-prototype-map.js                      0.937  1.296 ± 1.296 … 1.297              1.384 ± 1.299 … 1.468
MicroBench  array-prototype-shift.js                    1.022  0.007 ± 0.007 … 0.008              0.007 ± 0.007 … 0.007
MicroBench  bound-call-00-args.js                       0.987  1.597 ± 1.586 … 1.608              1.619 ± 1.612 … 1.625
MicroBench  bound-call-04-args.js                       1.014  1.752 ± 1.665 … 1.840              1.728 ± 1.698 … 1.759
MicroBench  bound-call-16-args.js                       0.993  1.883 ± 1.880 … 1.886              1.896 ± 1.886 … 1.905
MicroBench  call-00-args.js                             1.32   1.088 ± 1.084 … 1.091              0.824 ± 0.820 … 0.828
MicroBench  call-01-args.js                             1.337  1.128 ± 1.089 … 1.167              0.843 ± 0.843 … 0.844
MicroBench  call-02-args.js                             1.244  1.100 ± 1.088 … 1.113              0.885 ± 0.883 … 0.886
MicroBench  call-03-args.js                             1.21   1.067 ± 1.058 … 1.077              0.882 ± 0.881 … 0.884
MicroBench  call-04-args.js                             1.154  1.037 ± 1.028 … 1.047              0.899 ± 0.889 … 0.909
MicroBench  call-16-args.js                             1.095  1.173 ± 1.173 … 1.173              1.071 ± 1.053 … 1.090
MicroBench  call-32-args.js                             1.032  1.344 ± 1.336 … 1.353              1.303 ± 1.271 … 1.334
MicroBench  deep-call-stack.js                          1.119  0.358 ± 0.351 … 0.364              0.320 ± 0.318 … 0.321
MicroBench  for-in-indexed-properties.js                0.945  0.918 ± 0.914 … 0.922              0.971 ± 0.964 … 0.977
MicroBench  for-in-named-properties.js                  0.881  1.155 ± 1.153 … 1.157              1.311 ± 1.302 … 1.320
MicroBench  for-of.js                                   0.847  0.439 ± 0.438 … 0.441              0.518 ± 0.496 … 0.540
MicroBench  object-keys.js                              0.988  1.381 ± 1.378 … 1.385              1.398 ± 1.391 … 1.405
MicroBench  object-set-with-rope-strings.js             0.972  0.658 ± 0.654 … 0.661              0.676 ± 0.675 … 0.677
MicroBench  pic-add-own.js                              1.027  0.850 ± 0.847 … 0.853              0.827 ± 0.824 … 0.830
MicroBench  pic-get-own.js                              1.186  1.049 ± 1.048 … 1.050              0.884 ± 0.883 … 0.886
MicroBench  pic-get-pchain.js                           1.186  1.096 ± 1.060 … 1.132              0.924 ± 0.876 … 0.971
MicroBench  pic-put-own.js                              1.328  1.297 ± 1.291 … 1.302              0.976 ± 0.967 … 0.986
MicroBench  pic-put-pchain.js                           1.035  2.480 ± 2.429 … 2.532              2.397 ± 2.388 … 2.405
MicroBench  setter-in-prototype-chain.js                0.755  1.893 ± 1.891 … 1.895              2.507 ± 2.186 … 2.827
MicroBench  strictly-equals-object.js                   1.035  1.113 ± 1.106 … 1.121              1.076 ± 1.070 … 1.081
SunSpider   Total                                       1.021  1.019                              0.998
Kraken      Total                                       1.377  10.744                             7.805
Octane      Total                                       1.14   74601.500                          85057.500
JetStream   Total                                       1.175  205.364                            174.838
JetStream3  Total                                       1.02   11.378                             11.150
GarBench    Total                                       0.972  20.624                             21.214
MicroBench  Total                                       1.028  33.309                             32.417
All Suites  Total                                       1.127  371.971                            329.930

@awesomekling
awesomekling force-pushed the asmint branch 3 times, most recently from e23a205 to 91380a2 Compare March 7, 2026 00:37
Replace individual bool bitfields in Object (m_is_extensible,
m_has_parameter_map, m_has_magical_length_property, etc.) with a
single u8 m_flags field and Flag:: constants.

This consolidates 8 scattered bitfields into one byte with explicit
bit positions, making them easy to access from generated assembly
code at a known offset. It also converts the virtual is_function()
and is_ecmascript_function_object() methods to flag-based checks,
avoiding virtual dispatch for these hot queries.

ProxyObject now explicitly clears the IsFunction flag in its
constructor when wrapping a non-callable target, instead of relying
on a virtual is_function() override.
Move Interpreter::get() and set() from the .cpp file into the header
as inline methods. Make handle_exception(), perform_call(),
perform_call_impl(), and the HandleExceptionResponse enum public so
they can be called by the upcoming assembly interpreter's C++ glue
code. Also add set_running_execution_context() for the same reason.
Move the Bytecode.def parser, field type info, and layout computation
out of Rust/build.rs into a standalone BytecodeDef crate. This allows
both the Rust bytecode codegen (build.rs) and the upcoming AsmIntGen
tool to share a single source of truth for instruction field offsets
and sizes.

The AsmIntGen directory is excluded from the workspace since it has
its own Cargo.toml and is built separately by CMake.
@awesomekling
awesomekling force-pushed the asmint branch 2 times, most recently from 878a051 to 2e24666 Compare March 7, 2026 10:51
AsmIntGen is a Rust tool that compiles a custom assembly DSL into
native x86_64 or aarch64 assembly (.S files). It reads struct field
offsets from a generated constants file and instruction layouts from
Bytecode.def (via the BytecodeDef crate) to emit platform-specific
code for each bytecode handler.

The DSL provides a portable instruction set with register aliases,
field access syntax, labels, conditionals, and calls. Each backend
(codegen_x86_64.rs, codegen_aarch64.rs) translates this into the
appropriate platform assembly with correct calling conventions
(SysV AMD64, AAPCS64).
Add a new interpreter that executes bytecode via generated assembly,
written in a custom DSL (asmint.asm) that AsmIntGen compiles to
native x86_64 or aarch64 code.

The interpreter keeps the bytecode program counter and register file
pointer in machine registers for fast access, dispatching opcodes
through a jump table. Hot paths (arithmetic, comparisons, property
access on simple objects) are handled entirely in assembly, with
cold/complex operations calling into C++ helper functions defined
in AsmInterpreter.cpp.

A small build-time tool (gen_asm_offsets) uses offsetof() to emit
struct field offsets as constants consumed by the DSL, ensuring the
assembly stays in sync with C++ struct layouts.

The interpreter is enabled by default on platforms that support it.
The C++ interpreter can be selected via LIBJS_USE_CPP_INTERPRETER=1.

Currently supported platforms:
- Linux/x86_64
- Linux/aarch64
- macOS/x86_64
- macOS/aarch64
@awesomekling
awesomekling merged commit 200103b into LadybirdBrowser:master Mar 7, 2026
19 of 20 checks passed
@awesomekling
awesomekling deleted the asmint branch March 7, 2026 12:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant