From 37d19e2a4292ea58976f938abdebca4ace2e2ddf Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Fri, 9 Oct 2026 13:25:54 -0700 Subject: [PATCH] Compile ELF worker runtime units with the initial-exec TLS model Worker runtime variants link only into executables, whose own TLS block holds every runtime thread-local, but they were compiled with the default general-dynamic model. The linker relaxes each __tls_get_addr call to a %fs-relative address, yet the compiler had already treated it as a call: hot runtime leaves saved and restored extra registers around every thread-local access (scr_mg_visit pushed five registers instead of one). With -ftls-model=initial-exec each access is one %fs-relative operand. Darwin, Windows and wasm variants are unchanged. tsc-ts self-check, Linux sandbox, Worker build vs non-worker build: 1.04x -> 1.03x (9 interleaved runs). --- packages/runtime-pack-common/scripts/build.mjs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/runtime-pack-common/scripts/build.mjs b/packages/runtime-pack-common/scripts/build.mjs index f14ea943c..01d7a4db5 100644 --- a/packages/runtime-pack-common/scripts/build.mjs +++ b/packages/runtime-pack-common/scripts/build.mjs @@ -229,11 +229,22 @@ async function build() { ? ["-I", zlib] : []), ]; + // Worker variants link only into executables, whose own TLS block + // holds every runtime thread-local: on ELF the initial-exec model + // makes each access one %fs-relative load, where the default + // general-dynamic model compiles to a __tls_get_addr call (the + // linker relaxes the call away, but the callers already spilled + // their registers around it). + const tlsFlags = + variant.defines.includes("SCR_WORKERS") && matrix.target.object_format === "elf" + ? ["-ftls-model=initial-exec"] + : []; const unitFlags = [ ...commonFlags, flavorSpec.optimization, ...debugFlags, ...variant.defines.map((define) => `-D${define}`), + ...tlsFlags, ...includeFlags, ]; let bitcode;