This changelog covers updates to JavaScriptCore in Bun's WebKit fork, from 9a2cc42ae1bf to 7bc2f97e2835.
Regular expressions got a major performance boost with a new SIMD-accelerated prefix search, inspired by V8's approach. When a regex has alternatives with known leading characters (e.g., /aaaa|bbbb/), JSC now uses SIMD instructions to scan 16 bytes at a time, rapidly rejecting non-matching positions before falling back to scalar matching. This is implemented for both ARM64 (using TBL2) and x86_64 (using PTEST), so all platforms benefit.
The x86_64 codegen also gained new constant materialization primitives (move128ToVector, move64ToDouble, move32ToFloat) using broadcast and shuffle instructions, which are necessary for the SIMD regex paths and future SIMD optimizations.
579b96614b75— SIMD fast prefix search for RegExp (ARM64)b7ed3dae4a6a— SIMD fast prefix search for RegExp (x86_64)aa596dded063— x86_64 constant materialization for SIMD masks
Non-capturing parenthesized subpatterns with fixed-count quantifiers like (?:abc){3} previously fell back to the slower Yarr interpreter. They are now JIT-compiled using a counter-based loop, yielding a ~3.9x speedup on affected patterns. A follow-up patch also added JIT support for fixed-count subpatterns with capture groups (e.g., /(a+){2}b/), correctly saving and restoring capture state across iterations.
ac63cc259d74— JIT support for non-capturing fixed-count parentheses (~3.9x faster)c8b66aa0832b— JIT support for fixed-count subpatterns with captures
String.prototype.startsWith is now an intrinsic in the DFG and FTL JIT tiers, with constant folding support when both the string and search term are known at compile time.
| Benchmark | Speedup |
|---|---|
string-prototype-startswith |
1.42x faster |
string-prototype-startswith-constant-folding |
5.76x faster |
string-prototype-startswith-with-index |
1.22x faster |
The .size getter on Set and Map is now handled as an intrinsic in the DFG/FTL tiers and inline caches, eliminating the overhead of a generic getter call.
| Benchmark | Speedup |
|---|---|
set-size |
2.24x faster |
map-size |
2.74x faster |
String.prototype.trim, trimStart, and trimEnd now use direct pointer access via span8()/span16() instead of indirect str[i] character access, avoiding repeated bounds checking.
| Benchmark | Speedup |
|---|---|
string-trim |
1.17x faster |
string-trim-end |
1.42x faster |
string-trim-start |
1.10x faster |
Object.defineProperty is now recognized as an intrinsic in the DFG and FTL JIT tiers. While this patch alone doesn't change benchmark numbers, it lays the groundwork for future optimizations that can specialize based on descriptor shape.
When using "string".replace("search", "replacement") with string arguments, JSC now constructs a rope (lazy concatenation) instead of eagerly copying the entire result. This avoids unnecessary allocations for the common case where the result is only used briefly. This aligns with V8's behavior.
The B3 backend's Switch lowering was reworked to produce simpler CFG. Instead of an explicit bounds check + conditional branch before the jump table, the index is now clamped with a min and the fallthrough target is placed at the end of the jump table. This eliminates a branch and makes the resulting code easier for later optimization passes to analyze, particularly for large switch statements.
ref.castfor final types: When the target type of aref.castis a final type, JSC now uses a direct RTT pointer comparison instead of walking the RTT chain, which is faster. (17d713c71a50)- OMG VM access consolidation: The OMG compiler now caches the
VM*pointer in a single B3 value, avoiding redundant loads from the instance for write barriers and mutator fences. (6c59818feb76)
The op_end opcode was removed and replaced with op_ret everywhere. op_end was semantically identical to op_ret but had worse codegen in the Baseline JIT. This simplifies the bytecode set.
The SequesteredArenaMalloc allocator, which provides per-thread arenas for JIT compiler allocations to improve isolation and reduce contention, is now enabled on macOS. A follow-up patch also removed the hard limit on the number of compiler thread handles, allowing an arbitrary number of compiler threads.
9defcdb215ac— Enable on macOSaf95d936795d— Support arbitrary compiler threads
Comparisons where both operands are the same value (e.g., x <= x where x is a Symbol) could cause the DFG to incorrectly treat the result as unreachable, generating a brk instruction that crashes at runtime. This is now fixed.
The string representation of native functions was changed from a multi-line format to a single-line format matching V8/Node.js:
// Before:
"function Function() {\n [native code]\n}"
// After:
"function Function() { [native code] }"This fixes compatibility with packages that parse the output of .toString() on native functions.
8ab210be7028— Fixes bun#26698
Fixed a spec compliance issue where TypedArray.prototype.set would return early during value conversion if the underlying ArrayBuffer was shrunk and then grown. The conversion loop now runs to completion per ECMA-262, correctly handling resizable ArrayBuffers.
When Error.captureStackTrace was called on an ErrorInstance before the error's properties were lazily materialized, the materialization would overwrite the .stack property set by captureStackTrace. A tracking bit now prevents this.
A regression from the fixed-count parentheses optimization where nested capture groups were not being reset to undefined at the start of each iteration, as required by the ECMAScript spec. For example, /(a)?b\1/{2} now correctly resets capture group 1 between iterations.
Several missing exception checks were added:
String.prototype.replacewith regex and empty replacement string could miss an exception check. (ffbeef167f9a)- The JS-to-Wasm entry wrapper could miss an exception when building the return frame. (
9546f07aeb91) - Wasm GC IPInt slow paths could trigger GC, which reads
topCallFramefor ShadowChicken — but IPInt'stopCallFramecan be stale, causing crashes. Now nulled out in such slow paths. (d106624a1491) - Missing exception checks in
AbstractModuleRecordandJSModuleNamespaceObject. (3712974e056a)
Math.sumPrecise has reached Stage 4 in TC39, so its feature flag has been removed. It is now always available. Math.sumPrecise computes the sum of an iterable of numbers with higher precision than naive sequential addition, avoiding catastrophic cancellation.
A new WebAssembly debugger allows LLDB to debug Wasm code running in JSC. Key changes in this release:
-
A dedicated
ENABLE_WEBASSEMBLY_DEBUGGERmacro was introduced (currently macOS ARM64 only). -
A preference/option was added to enable the debugger.
-
A race condition in the debug server's accept thread was fixed, which previously caused LLDB connection timeouts.
-
Idle VMs can now be interrupted for Stop-The-World debugging by dispatching to their RunLoop.
-
Wasm binary hashes are now attached to internal function names for easier identification in debugger output.
-
Added test coverage for Swift Wasm exception handling (
do-catch-throw). -
f2e39ae2e148,4d96269236ae,69f3eff63c32,6582b6b3fb43,b5980d315589,91c756f67029,a9e86615c78f
The LOL (Lowered-Overhead Lightweight) JIT, a new JIT tier being developed between the interpreter and Baseline JIT, gained support for:
-
All jump bytecodes (
jtrue,jfalse,jless,jgreater,jbelow, etc.) -
Type-checking bytecodes (
is_undefined,is_boolean,is_number,is_big_int,is_string,is_object,is_callable, etc.)
The LLVM toolchain used for building was upgraded from 19.1.7 to 21.1.8.
- Fixed bmalloc MTE (Memory Tagging Extension) builds for open-source configurations. (
590c4d847d46) - Fixed
libpassystem-heap reporting forLibpasMallocReportConfig=1. (7de508db0171) [[nodiscard]]added toWTF::Vectoraccessor functions. (4b535ee9b46f)AvailableMemorymoved from bmalloc to WTF. (c021912ad55c)