Skip to content

Port closure optimizations#1313

Merged
saghul merged 3 commits intomasterfrom
refactor-closures
Jan 12, 2026
Merged

Port closure optimizations#1313
saghul merged 3 commits intomasterfrom
refactor-closures

Conversation

@saghul
Copy link
Copy Markdown
Contributor

@saghul saghul commented Jan 8, 2026

@saghul saghul marked this pull request as ready for review January 8, 2026 12:44
@saghul saghul force-pushed the refactor-closures branch from c008353 to 4929037 Compare January 8, 2026 12:58
@saghul saghul requested a review from bnoordhuis January 8, 2026 17:36
Copy link
Copy Markdown
Contributor

@bnoordhuis bnoordhuis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work.

uint16_t var_count;
uint16_t defined_arg_count; /* for length function property */
uint16_t stack_size; /* maximum stack size */
uint16_t var_ref_count; /* number of local variable references */
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This field creates a 6 byte padding hole on 64 bits architectures because of the alignment requirement of the next field. Can maybe be eliminated with some reshuffling.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take a look!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some AI assisted suffling of fields :-) Can you PTAL?

@saghul saghul merged commit 97d23e5 into master Jan 12, 2026
122 checks passed
@saghul saghul deleted the refactor-closures branch January 12, 2026 09:00
@saghul
Copy link
Copy Markdown
Contributor Author

saghul commented Jan 12, 2026

FWIW, got this from struct_layout.py:

struct ::JSFunctionBytecode [136 Bytes]
     : [JSGCObjectHeader : 24] header
    0:   [int : 4] ref_count                              -- {cache-line 0}
   --- 1 Bytes padding ---
    5:   [unsigned char : 1] dummy1                       -- {cache-line 0}
    6:   [unsigned short : 2] dummy2                      -- {cache-line 0}
     :   [list_head : 16] link
    8:     [list_head* : 8] prev                          -- {cache-line 0}
   16:     [list_head* : 8] next                          -- {cache-line 0}
   --- 8 Bytes padding ---
   32: [unsigned char* : 8] byte_code_buf                 -- {cache-line 0}
   40: [int : 4] byte_code_len                            -- {cache-line 0}
   44: [unsigned int : 4] func_name                       -- {cache-line 0}
   48: [JSVarDef* : 8] vardefs                            -- {cache-line 0}
   56: [JSClosureVar* : 8] closure_var                    -- {cache-line 0}
   64: [unsigned short : 2] arg_count                     -- {cache-line 1}
   66: [unsigned short : 2] var_count                     -- {cache-line 1}
   68: [unsigned short : 2] defined_arg_count             -- {cache-line 1}
   70: [unsigned short : 2] stack_size                    -- {cache-line 1}
   72: [unsigned short : 2] var_ref_count                 -- {cache-line 1}
   74: [unsigned short : 2] closure_var_count             -- {cache-line 1}
   76: [int : 4] cpool_count                              -- {cache-line 1}
   80: [JSContext* : 8] realm                             -- {cache-line 1}
   88: [JSValue* : 8] cpool                               -- {cache-line 1}
   96: [unsigned int : 4] filename                        -- {cache-line 1}
  100: [int : 4] line_num                                 -- {cache-line 1}
  104: [int : 4] col_num                                  -- {cache-line 1}
  108: [int : 4] source_len                               -- {cache-line 1}
  112: [int : 4] pc2line_len                              -- {cache-line 1}
   --- 4 Bytes padding ---
  120: [unsigned char* : 8] pc2line_buf                   -- {cache-line 1}
  128: [char* : 8] source                                 -- {cache-line 2}

Maybe it can be further improved to avoid the 8 byte hole?

@bnoordhuis
Copy link
Copy Markdown
Contributor

Is that on macos? JSGCObjectHeader size and alignment on my x86_64 Linux system are both 24, not 24 and 32 as seems to be the case on your system. Maybe __attribute__((packed)) helps but that's not entirely without peril.

@saghul
Copy link
Copy Markdown
Contributor Author

saghul commented Jan 12, 2026

Yep, that is macOS, aarch64.

@MulverineX MulverineX mentioned this pull request Jan 15, 2026
@gengjiawen
Copy link
Copy Markdown

seems score very near

Benchmark (Higher scores are better) QuickJS-ng (local build) QuickJS Bellard (local build) V8 --jitless
Richards 840 832 1157
DeltaBlue 823 832 1085
Crypto 746 715 1302
RayTrace 958 1231 4423
EarleyBoyer 1670 1726 6115
RegExp 213 340 4209
Splay 2505 2501 8345
NavierStokes 1157 1264 1995
Score 919 1015 2731
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants