Skip to content

Upgrade to upstream WebKit 47f7250137c6 - #455

Merged
Jarred-Sumner merged 851 commits into
mainfrom
bun/upgrade-to-47f7250137c6
Aug 17, 2026
Merged

Jarred-Sumner merged 851 commits into
mainfrom
bun/upgrade-to-47f7250137c6

Conversation

@robobun

@robobun robobun commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

Merges upstream WebKit main at 47f7250137c6 (2026-08-16): 846 commits since the previous merge base 3722912ff800 (2026-08-02), 235 of them touching JavaScriptCore, WTF or bmalloc. Supersedes #404, which merged an older upstream state and predates the Yarr work that landed on both sides since.

Preview build of this PR is what the matching Bun PR pins; the Bun-side changes (HandleSet include, ScriptFetchParameters ordinals, SyntheticModuleRecord::create argument, StackBounds accessor) live there.

Yarr

The fork's Yarr (#299) and upstream's Yarr commits in this range (the lookbehind JIT, several of the same correctness fixes) implement overlapping things in different code, so yarr/ and RegExp.cpp are kept at the fork's version and the upstream commits were gone through one by one:

Other conflict resolutions worth knowing about

  • USE_BUILTIN_FRAME_ADDRESS was removed upstream (2a8926009f) together with the topCallFrame fallback paths. The fork had it switched off on Windows ARM64 since the January bring-up ("crashes in DFG operations"). The fallback code no longer exists, so Windows ARM64 now uses __builtin_frame_address(1) like every other JIT platform. Verified with this PR's bun-webkit-windows-arm64-debug build on a Windows 11 ARM64 machine: a debug Bun linked against it runs a workload that tiers up to DFG and FTL (6 compiles each) and calls JIT operations for 300k iterations without tripping the topCallFrame == callFrame assertion every operation performs in debug builds, so the January workaround is obsolete. If the Bun CI lanes disagree, the fix is restoring the ~50 lines 2a8926009f removed.
  • MAX_ARRAY_BUFFER_SIZE: upstream raised it to 1 << 34 (2c2c1af357). Kept at 1 << 32 under USE(BUN_JSC_ADDITIONS): Bun's Buffer kMaxLength is this constant and Bun has not been audited for buffers above 4 GB. Raising it is a separate decision. Consequence for JSTests: upstream's new array-buffer-slice-larger-than-4gb.js allocates 5 GB unconditionally and throws under this cap (its sibling typedarray-index-past-max-array-index.js skips on RangeError); left as imported, to be given the same try/catch if this PR needs another push, or it becomes valid as-is if the cap is lifted.
  • ScriptFetchParameters::Type gains upstream's Text (import-text, 49246d2612) ahead of the fork's HostDefined, so HostDefined is now 5. With BUN_JSC_ADDITIONS, parseType("text") still returns HostDefined because Bun implements type: "text" itself; AbstractModuleRecord::moduleType() and SourceProvider::isModuleType() know about Synthetic / BunTranspiledModule.
  • SyntheticModuleRecord: upstream threads a SourceProviderSourceType through create and the tryCreate* helpers; the fork's lazy-export overload (SyntheticModuleRecord: exports whose values are produced on first binding #408) is kept and reports SourceProviderSourceType::Module. The fork's unused public 4-argument tryCreateWithExportNamesAndValues is gone.
  • Renames applied to fork code: HeapFinalizerCallback -> GCCompletionCallback, HandleSet -> StrongSet (the fork's JSHeapFinalizerPrivate.cpp still skips the JSLock), finalizeUnconditionally -> reconcileWeakReferencesAtGCEnd (ErrorInstance, where the fork runs its Bun finalizer hook), timeZoneFromRecord now takes ISOStringTimeZoneParseRecord next to the fork's TemporalZonedDateTime::toString.
  • WebKitMacros.cmake: upstream's own CMake 4.4 fix (4bfeff8c67) replaces the fork's quoting patch. OptionsJSCOnly.cmake keeps ENABLE_BUN_SKIP_FAILING_ASSERTIONS, drops the ARM32/MIPS capstone block upstream removed.
  • BuiltinExecutables.cpp: the fork's async builtin visibility tweak reads scanned.isAsyncFunction (d7cb8d6).
  • StackBounds::currentThreadStackBounds() became private to Thread upstream (f6bc402b83); c0ccc24 adds a BUN_JSC_ADDITIONS accessor for Bun's once-per-thread use.
  • WTF::numberOfProcessorCores() started honouring NUMBER_OF_PROCESSORS upstream (5fc5182bcf, for WebKit's bots). Bun reports that value as navigator.hardwareConcurrency / os.availableParallelism() (with the old pin NUMBER_OF_PROCESSORS=3 bun -p navigator.hardwareConcurrency prints the real count, with the upstream change it prints 3), and on Linux it would take precedence over the fork's affinity/cgroup aware count, so 8fc20b1 keeps that lookup out of Bun builds. The pre-existing WTF_numberOfProcessorCores override is untouched. Drop that commit if following upstream here is preferred.
  • JSType.h, .github/workflows and the release tarball names are unchanged.

Verification

  • bun run jsc:build:debug (Linux x64, debug + ASAN): builds, jsc shell runs.
  • JSTests: the 21 regexp tests upstream added in this range (17 pass, the 4 failures are explained above) and the 318 regexp*/string-*/yarr* stress tests, each in JIT and --useRegExpJIT=false mode: no failures beyond tests whose //@ directives need the real test runner (re-run by hand: pass).
  • bun run build:local: Bun links and runs against this tree. Bun's test/js/bun/jsc, jsc-stress, node/vm, node/module, bun/resolve, node/buffer, node/worker_threads, bun/wasm and node/util suites (78 files, 2034 tests): the only failures are 5-second-timeout and RSS-threshold tests that a Bun debug build on the current WebKit pin fails the same way on this (shared, debug + ASAN) machine; the scenarios behind them complete identically with both builds when run by hand.

kiaraarose and others added 30 commits August 11, 2026 18:52
https://bugs.webkit.org/show_bug.cgi?id=321237
rdar://184284891

Reviewed by Timothy Hatcher.

Add support for scripting.ExecutionWorld, which should simply return an object containing the two
different world types.

Test: Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKWebExtensionAPIScripting.mm

* Source/WebKit/WebProcess/Extensions/API/Cocoa/WebExtensionAPIScriptingCocoa.mm:
(WebKit::WebExtensionAPIScripting::executionWorld):
* Source/WebKit/WebProcess/Extensions/API/WebExtensionAPIScripting.h:
* Source/WebKit/WebProcess/Extensions/Interfaces/WebExtensionAPIScripting.idl:
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKWebExtensionAPIScripting.mm:
(TestWebKitAPI::TEST(WKWebExtensionAPIScripting, ExecutionWorld)):

Canonical link: https://commits.webkit.org/319009@main
…content in nested cross-origin subframes

https://bugs.webkit.org/show_bug.cgi?id=321486
rdar://168703870

Reviewed by Ryosuke Niwa and Abrar Rahman Protyasha.

After the changes in 317283@main, we now include content from cross-origin frames under the top
frame when serializing attributed string data to the pasteboard. However, this logic is broken in
the case where there are same-origin frames nested underneath cross-origin frames, since our current
approach of descending into RemoteFrames and asking for their contents as attributed string doesn't
handle the case where we might need to later descend **back** into a subframe hosted in the same
process as the main frame.

To fix this, we refactor the way in which this attributed string serialization works to handle all
possible ways of nesting same- or cross-origin frames:

1.  Serialize the selected DOM content into an attributed string. Whenever we encounter a
    `RemoteFrame`, append an object replacement character to the string, marked with an internal
    attribute representing the contents of that remote frame
    (`remoteFrameIdentifierAttributeName`).

2.  Serialize the contents of those remote frames. The UI process walks the frame tree to find all
    remote frames in the selection (including nested descendants) and asks each web process for the
    ones it hosts, since only the UI process knows which process hosts which frame. The web process
    containing the selection is blocked waiting on this reply, so it cannot be asked for anything;
    it serializes the frames it hosts underneath a remote frame itself.

3.  Collate the attributed strings from [1] and [2] into a final, flattened attributed string by
    iteratively replacing each remote frame placeholder with its corresponding subframe contents.

Tests:  SiteIsolation.ReadAttributedStringFromPasteboardAfterCopyWithCrossSiteIframe
        SiteIsolation.ReadAttributedStringFromPasteboardAfterCopyWithNestedCrossSiteIframes

* Source/WebCore/editing/cocoa/EditorCocoa.mm:
(WebCore::selectionAsAttributedString):
(WebCore::attributedStringByReplacingRemoteFrameMarkers):
(WebCore::populateRichTextDataIfNeeded):
(WebCore::Editor::writeSelectionToPasteboard):
(WebCore::Editor::dataInRTFDFormat):
(WebCore::Editor::dataInRTFFormat):
* Source/WebCore/editing/cocoa/NodeHTMLConverter.h:
(WebCore::attributedString): Deleted.
* Source/WebCore/editing/cocoa/NodeHTMLConverter.mm:
(HTMLConverter::HTMLConverter):
(HTMLConverter::_addRemoteFrameMarker):
(HTMLConverter::_processElement):

Add placeholders to represent the contents of remote frames embedded in the attributed string, which
are later removed (and replaced with attributed string data taken from their respective subframes,
if we got data from them).

(WebCore::remoteFrameIdentifierAttributeName):
(WebCore::containsRemoteFrameContentMarkers):
(WebCore::attributedString):

Add an option to extract cross-origin frames as placeholders in the attributed string (see above).

* Source/WebCore/page/FrameTree.cpp:
(WebCore::FrameTree::containsRemoteFrame const):
(WebCore::FrameTree::hasRemoteFrameAncestor const):
* Source/WebCore/page/FrameTree.h:
* Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm:
(WebKit::WebPageProxy::getAttributedStringsForRemoteFrames):
* Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm:
(WebKit::WebPage::attributedStringsForRemoteFrames):
(WebKit::WebPage::getContentsAsAttributedStringForFrames):
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/SiteIsolation.mm:
(TestWebKitAPI::(SiteIsolation, ReadAttributedStringFromPasteboardAfterCopyWithCrossSiteIframe)):
(TestWebKitAPI::(SiteIsolation, ReadAttributedStringFromPasteboardAfterCopyWithNestedCrossSiteIframes)):

Canonical link: https://commits.webkit.org/319010@main
…dback collection

https://bugs.webkit.org/show_bug.cgi?id=321549
rdar://184657982

Reviewed by Yijia Huang.

CallLinkInfo::m_maxArgumentCountIncludingThisForVarargs is uint8_t so we
should not use branch32 with Address(). load8 first to zero-extend the byte,
then branch32 on registers.

* Source/JavaScriptCore/jit/JITCall.cpp:
(JSC::JIT::compileSetupFrame):

Canonical link: https://commits.webkit.org/319011@main
…g _client in ensureOnMainThread blocks

<https://bugs.webkit.org/show_bug.cgi?id=320431>
<rdar://183392744>

Reviewed by Eric Carlson.

Assert the main thread at the top of each `ensureOnMainThread()` block
in `WebAVSampleBufferListenerPrivate` that reads the `_client` instance
variable.  `_client` is annotated
`WTF_GUARDED_BY_CAPABILITY(mainThread)`, and although every reader
reaches it through `ensureOnMainThread()`, the thread-safety analyzer
cannot infer that the dispatched block body runs on the main thread.
`assertIsMainThread()` supplies the missing main-thread capability so
`-Wthread-safety-analysis` can prove the guarded access is well-formed.

No new tests since no change in behavior.

* Source/WebCore/platform/graphics/avfoundation/WebAVSampleBufferListener.mm:
(-[WebAVSampleBufferListenerPrivate observeValueForKeyPath:ofObject:change:context:]):
(-[WebAVSampleBufferListenerPrivate layerFailedToDecode:]):
(-[WebAVSampleBufferListenerPrivate layerRequiresFlushToResumeDecodingChanged:]):
(-[WebAVSampleBufferListenerPrivate layerReadyForDisplayChanged:]):
(-[WebAVSampleBufferListenerPrivate audioRendererWasAutomaticallyFlushed:]):

Canonical link: https://commits.webkit.org/319012@main
…matting

https://bugs.webkit.org/show_bug.cgi?id=320826

Reviewed by Darin Adler.

Drive-by fix for this log line that I saw in the bots.

Canonical link: https://commits.webkit.org/319013@main
…PackedPtr` array

https://bugs.webkit.org/show_bug.cgi?id=321488

Reviewed by Yusuke Suzuki.

SourceProviderCacheItem stores its used-variable names in a trailing
PackedPtr<UniquedStringImpl> array, whose element is 6 bytes on 64-bit
macOS/Linux, but create() sized the allocation with
sizeof(UniquedStringImpl*) (8 bytes) per element, so every item carried 2
unused bytes per used variable. These items are created for each function
longer than 16 characters in a parsed source and live in the VM's
SourceProviderCache until the next full GC, so the slack accumulates.

Make SourceProviderCacheItem a TrailingArray of PackedRefPtr<UniquedStringImpl>
so that the allocation size, element construction and ref/deref all derive
from the declared element type instead of being hand-written. Moving the
element count into TrailingArray::m_size also lets isBodyArrowExpression share
a word with tokenType, shrinking the fixed part from 40 to 36 bytes on
macOS/Linux. Parsing a 17.8 MB bundle (64,830 items, 3.56 used variables per
item on average) goes from 4.80 MB to 4.22 MB of malloc'd
SourceProviderCacheItem storage after size-class rounding (4.46 MB with the
element size fix alone).

* Source/JavaScriptCore/parser/Parser.h:
(JSC::Scope::restoreFromSourceProviderCache):
* Source/JavaScriptCore/parser/SourceProviderCacheItem.h:
(JSC::SourceProviderCacheItem::create):
(JSC::SourceProviderCacheItem::SourceProviderCacheItem):
(JSC::SourceProviderCacheItem::endFunctionToken const): Deleted.
(JSC::SourceProviderCacheItem::lexicallyScopedFeatures const): Deleted.
(JSC::SourceProviderCacheItem::usedVariables const): Deleted.
(JSC::SourceProviderCacheItem::~SourceProviderCacheItem): Deleted.

Canonical link: https://commits.webkit.org/319014@main
https://bugs.webkit.org/show_bug.cgi?id=321545
rdar://184655909

Reviewed by Vassili Bykov.

WasmGC Struct may have padding like what C++ struct is because of
alignment requirement of fields. But since offset of fields are not
exposed as ABI, we can fill gaps with smaller fields to compact the size
of WasmGC structs. This is effective for example if we are interleaving
i8 and i32.

    struct {
        i8;
        i32;
        i8;
        i32;
    };

This can be like,

    struct {
        i8;
        i8;
        i32;
        i32;
    };

We apply V8's heuristics[1]. Tracking one gap we found so far, and
reusing this gap when we encounter a field which can fit in this gap.

To make the layout itself testable, $vm gains wasmStructFieldOffsets and
wasmStructPayloadSize, which reflect the placement decisions of a struct
instance back to JS.

[1]: https://chromium-review.googlesource.com/c/v8/v8/+/4092494

Test: JSTests/wasm/gc/struct-field-gap-filling.js

* JSTests/wasm/gc/struct-field-gap-filling.js: Added.
* Source/JavaScriptCore/tools/JSDollarVM.cpp:
(JSC::functionWasmStructFieldOffsets):
(JSC::functionWasmStructPayloadSize):
(JSC::JSDollarVM::finishCreation):
* Source/JavaScriptCore/wasm/WasmFormat.h:
(JSC::Wasm::placeStructField):
* Source/JavaScriptCore/wasm/WasmTypeDefinition.cpp:
(JSC::Wasm::TypeInformation::typeDefinitionForStruct):
* Source/JavaScriptCore/wasm/WasmTypeDefinitionInlines.h:
(JSC::Wasm::TypeInformation::typeDefinitionForStructFromProvider):

Canonical link: https://commits.webkit.org/319015@main
https://bugs.webkit.org/show_bug.cgi?id=321532
rdar://183145568

Reviewed by Mike Wyrzykowski and Vitor Roriz.

There were a few strings in the AtomString table which were no longer used anywhere. In some cases
strings were only being used for case-insensitive comparisons which are more efficiently done with
ASCII literals. And in other cases the strings were only meant to be used off the main thread, which
AtomStrings don't support.

These are being removed to free up a small amount of space in the table and to prevent false-positive leak
repots from some memory analysis tools.

No new tests.

* Source/WebCore/platform/CommonAtomStrings.h:

Canonical link: https://commits.webkit.org/319016@main
https://bugs.webkit.org/show_bug.cgi?id=321502
rdar://184606411

Reviewed by Keith Miller.

JS accesses the handler in non-main thread. This access is sometimes the
first one, binding the CanMakeWeakPtr WeakPtrFactory to the main thread.

Avoid by not using WeakPtrs.

* Source/WTF/wtf/MemoryPressureHandler.cpp:
(WTF::MemoryPressureHandler::MemoryPressureHandler):
(WTF::MemoryPressureHandler::setShouldUsePeriodicMemoryMonitor):
* Source/WTF/wtf/MemoryPressureHandler.h:

Canonical link: https://commits.webkit.org/319017@main
https://bugs.webkit.org/show_bug.cgi?id=321571
rdar://184652023

causes webcontent being killed when using data URL greater than 2MB

Reverted change:

    Limit URL size at the IPC boundary to match Chrome/Blink
    https://bugs.webkit.org/show_bug.cgi?id=320340
    rdar://183139377
    318045@main (04e3d47)

Canonical link: https://commits.webkit.org/319018@main
…atial instead of x-webkit-projection (experimental)

https://bugs.webkit.org/show_bug.cgi?id=321541
rdar://184654127

Reviewed by Jean-Yves Avenard.

The attribute selects a projection, not whether the content is spatial; the two
are independent, which is why ImmersiveVideoMetadata reports isSpatial() and
isImmersive() separately.

* Source/WebCore/Modules/modern-media-controls/media/spatial-video-support.js:
(SpatialVideoSupport.prototype._resolveProjection):

Canonical link: https://commits.webkit.org/319019@main
https://bugs.webkit.org/show_bug.cgi?id=321522
rdar://184632964

Reviewed by Yijia Huang.

This patch tightens WasmGC allocations.

1. While allocator is not a constant in WasmGC struct allocations (it is
   coming from JSWebAssemblyInstance field), size is constant when
   compiling. We add VariableNonNullWithConstantCellSize mode, which
   means that "allocator is in GPR as a variable, but cell size is constant"
   to tighten the code generation.
2. We revisit effect model of WasmGC allocations, now it is more aligned
   to DFG's allocations (not saying write-top).
3. We also fold WasmGC array allocations with constant size too.

Tests: JSTests/wasm/gc/struct-new-does-not-clobber-loads.js
       JSTests/wasm/gc/struct-new-nested-alloc-gc.js

* JSTests/wasm/gc/array-new-constant-size.js: Added.
(get return):
(make):
(get for):
* JSTests/wasm/gc/struct-new-does-not-clobber-loads.js: Added.
* JSTests/wasm/gc/struct-new-nested-alloc-gc.js: Added.
(want):
* Source/JavaScriptCore/b3/B3AbstractHeapRepository.cpp:
(JSC::B3::AbstractHeapRepository::AbstractHeapRepository):
(JSC::B3::AbstractHeapRepository::decorateWasmStructNew):
(JSC::B3::AbstractHeapRepository::decorateWasmArrayNew):
(JSC::B3::AbstractHeapRepository::computeRangesAndDecorateInstructions):
* Source/JavaScriptCore/b3/B3AbstractHeapRepository.h:
* Source/JavaScriptCore/b3/B3LowerMacros.cpp:
* Source/JavaScriptCore/b3/B3Value.cpp:
(JSC::B3::Value::effectsSlow const):
* Source/JavaScriptCore/b3/B3WasmArrayNewValue.h:
* Source/JavaScriptCore/b3/B3WasmStructNewValue.h:
* Source/JavaScriptCore/heap/CompleteSubspace.cpp:
(JSC::CompleteSubspace::prepareAllAllocators):
* Source/JavaScriptCore/jit/AssemblyHelpers.cpp:
(JSC::AssemblyHelpers::emitAllocateWithNonNullAllocator):
(JSC::AssemblyHelpers::emitAllocate):
* Source/JavaScriptCore/jit/JITAllocator.h:
(JSC::JITAllocator::variableNonNullWithConstantCellSize):
(JSC::JITAllocator::hasConstantCellSize const):
(JSC::JITAllocator::constantCellSize const):
* Source/JavaScriptCore/wasm/WasmBBQJIT64.cpp:
(JSC::Wasm::BBQJITImpl::BBQJIT::emitAllocateGCArrayUninitialized):
(JSC::Wasm::BBQJITImpl::BBQJIT::emitAllocateGCStructUninitialized):
* Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp:
(JSC::Wasm::OMGIRGenerator::addArrayNew):
(JSC::Wasm::OMGIRGenerator::addArrayNewDefault):
(JSC::Wasm::OMGIRGenerator::addArrayNewFixed):
(JSC::Wasm::OMGIRGenerator::addStructNew):
(JSC::Wasm::OMGIRGenerator::addStructNewDefault):

Canonical link: https://commits.webkit.org/319020@main
…le` itself

https://bugs.webkit.org/show_bug.cgi?id=321497

Reviewed by Yusuke Suzuki.

210869@main moved m_parentScopeTDZVariables into UnlinkedFunctionExecutable::RareData
because it was non-empty for only ~1% of executables at the time. That no longer holds:
since 230994@main, BytecodeGenerator::getVariablesUnderTDZ() returns a non-null
TDZEnvironmentLink whenever the enclosing TDZ stack is non-empty, and in
let/const/class-heavy code most closures are created while some lexical binding of an
enclosing scope is still in its TDZ (the binding being initialized in
`const f = () => ...`, the class name for every method of a named class, any const/class
declared later in the scope). As a result the 80-byte RareData is malloc'ed for a large
fraction of the 96-byte executables just to hold this one pointer.

This patch stores m_parentScopeTDZVariables in the cell again without growing it. The 8
bytes come from m_name/m_ecmaName: FunctionMetadataNode::ecmaName() is ident() whenever
ident() is non-null, so the two Identifiers only differ for anonymous functions. Keep a
single m_ecmaName plus an m_hasName bit, which fits in the existing bit-field padding, and
make name() return vm().propertyNames->nullIdentifier (what the parser already uses as the
ident of anonymous functions) when the bit is unset. sizeof(UnlinkedFunctionExecutable)
stays at 96 bytes and RareData goes back to being rare (class constructors, private name
environments, generator/async body wrapper parameter names, source URL directives).

RareData allocations, counted at UnlinkedFunctionExecutable::ensureRareDataSlow():

                                             non-builtin      RareData
                                             executables   before   after

    typescript.js 5.9 load + transpileModule       15979     5553      49
    JetStream2 chai-wtb                            13544     4149     197
    JetStream2 prepack-wtb                         13622     4061     197
    JetStream2 uglify-js-wtb                       13434     4061     197
    JetStream2 coffeescript-wtb                    13192     3817     197
    JetStream2 acorn-wtb                           13078     3702     197
    JetStream2 WSL                                  2197     1476     136
    JetStream2 pdfjs                                 986      897      17
    JetStream2 ML                                    564      543      30
    JetStream2 Air                                   386      333      30
    JetStream2 Babylon                               397      376      28
    JetStream2 FlightPlanner                         223      191      37
    JetStream2 Basic                                 228      162      32
    JetStream2 UniPoker                              135      111      21
    JetStream2 async-fs                              138      110      27
    JetStream2 driver only (cdjs, gbemu, ...)       ~170       88      17

JetStream2 scores are neutral. Per-benchmark Score, patched/baseline over 8 alternating
runs of cli.js: acorn-wtb 1.003, babylon-wtb 1.010, chai-wtb 0.994, coffeescript-wtb
0.999, espree-wtb 1.006, jshint-wtb 1.002, lebab-wtb 0.994, prepack-wtb 1.000,
uglify-js-wtb 1.006, typescript 1.001, pdfjs 0.997, first-inspector-code-load 1.012,
multi-inspector-code-load 1.037, WSL 1.035, Air 0.991, ML 1.053, Basic 0.997,
async-fs 1.028, UniPoker 1.028; all within the run-to-run confidence intervals.

* Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp:
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
(JSC::UnlinkedFunctionExecutable::name const):
* Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h:
* Source/JavaScriptCore/runtime/CachedTypes.cpp:
(JSC::CachedFunctionExecutableRareData::encode):
(JSC::CachedFunctionExecutableRareData::decode const):
(JSC::CachedFunctionExecutable::hasName const):
(JSC::CachedFunctionExecutable::parentScopeTDZVariables const):
(JSC::CachedFunctionExecutable::encode):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
(JSC::CachedFunctionExecutable::name const): Deleted.

Canonical link: https://commits.webkit.org/319021@main
…Joiner` for any separator

https://bugs.webkit.org/show_bug.cgi?id=321228

Reviewed by Yusuke Suzuki.

295918@main taught JSOnlyStringsAndInt32sJoiner to write Int32 elements
directly into the result buffer, but fastArrayJoin's ALL_INT32_INDEXING_TYPES
case was not updated and still went through the generic JSStringJoiner,
allocating a numeric string per element. Only the empty-separator case was
fast because arrayProtoFuncJoin has its own early path, so `ids.join("")`
was ~2x faster than `ids.join(",")` / `ids.toString()`.

This patch makes the ALL_INT32 case try JSOnlyStringsAndInt32sJoiner first,
mirroring the ALL_CONTIGUOUS case, and falls back to the generic loop only
when the array has holes.

tryJoin is now templatized on the indexing shape so that the Int32Shape
instantiation only checks for holes and skips the per-element isString() checks
that the ContiguousShape one needs.

                                      baseline                  patched

array-join-int32-separator        22.1538+-0.6142     ^     10.9635+-0.7135        ^ definitely 2.0207x faster

Tests: JSTests/microbenchmarks/array-join-int32-separator.js
       JSTests/stress/array-join-int32-separator.js

* JSTests/microbenchmarks/array-join-int32-separator.js: Added.
(next):
(test):
* JSTests/stress/array-join-int32-separator.js: Added.
(shouldBe):
(test):
* Source/JavaScriptCore/runtime/ArrayPrototypeInlines.h:
(JSC::fastArrayJoin):

Canonical link: https://commits.webkit.org/319022@main
https://bugs.webkit.org/show_bug.cgi?id=321119
rdar://184152184

Reviewed by Tim Nguyen.

Adds the (unprefixed) user-select property, gated by a new feature
flag (CSSUserSelectEnabled). The property is completely inert - this
commit only adds the plumbing required for making user-select actually
affect selectability in the future. The prefixed `-webkit-user-select`
still exists independently and is the only source of truth.

No changes in behavior expected. However, some tests now pass simply
because the user-select property exists (though only in testing -
feature flag set to 'testable').

Canonical link: https://commits.webkit.org/319023@main
…ded automation pages

https://bugs.webkit.org/show_bug.cgi?id=296394
rdar://178913733

Reviewed by Qianlang Chen and Sihui Liu.

An automation session created with siteIsolationEnabled had no way to carry that
preference onto the pages it vends: the flag lived on the
_WKAutomationSessionConfiguration but was never applied to a new browsing context's
WebPreferences, so Site Isolation never engaged for automation-driven pages.

Stamp the configuration's siteIsolationEnabled onto WebAutomationSession at
session-creation time, then in createBrowsingContext() inject it into the vended
page's WebPreferences before process assignment. Only the vended automation page is affected;
sibling pool pages keep their own preferences.

Update `WebProcessPool` to override keeping frames in the same process when site isolation is enabled.
That behavior was introduced in https://commits.webkit.org/201369@main as a guard against PSON (process swap on nagivation)
to force keeping automation sessions working the same process.

Automation was built on a single-process-per-page assumption that predates both PSON and site isolation.
`WebAutomationSession` (UI process) drives one `WebAutomationSessionProxy` per `WebProcess`,
and it caches state that only means anything inside a specific WebProcess:
- injected JS atoms,
- element/node handles
- the current frame handle.

* Source/WebKit/UIProcess/API/Cocoa/_WKAutomationSession.mm:
(-[_WKAutomationSession initWithConfiguration:]):
* Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp:
(WebKit::WebAutomationSession::WebAutomationSession):
(WebKit::WebAutomationSession::createBrowsingContext):
* Source/WebKit/UIProcess/Automation/WebAutomationSession.h:
* Source/WebKit/UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::processForNavigationInternal):

Canonical link: https://commits.webkit.org/319024@main
…dded through SVGImage

https://bugs.webkit.org/show_bug.cgi?id=321333

Reviewed by Alejandro G. Castro.

An SVG document embedded through SVGImage (<img>, background-image, SVG <image>)
is resized to the container size chosen by the embedder. With no viewBox,
SVGSVGElement synthesizes one from the intrinsic size, plus a preserveAspectRatio
of "none", so the content stretches to that size.

The legacy engine gets this for free, since buildLocalToBorderBoxTransform() asks
the element for the viewBox transform without checking for a viewBox attribute
first, as LBSE did. Fix LBSE by calling viewBoxToViewTransform() unconditionally.
It returns the identity transform when there is nothing to map, which makes the
surrounding conditions redundant.

* LayoutTests/platform/mac-tahoe-wk2-lbse-text/TestExpectations:
* Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp:
(WebCore::RenderSVGViewportContainer::needsHasSVGTransformFlags const):
(WebCore::RenderSVGViewportContainer::updateLayerTransform):
(WebCore::RenderSVGViewportContainer::overflowClipRect const):
* Source/WebCore/svg/SVGSVGElement.cpp:
(WebCore::SVGSVGElement::hasSynthesizedViewBoxForSVGImage const):
(WebCore::SVGSVGElement::currentViewBoxRect const):
(WebCore::SVGSVGElement::viewBoxToViewTransform const):
* Source/WebCore/svg/SVGSVGElement.h:

Canonical link: https://commits.webkit.org/319025@main
… iframes under Site Isolation

https://bugs.webkit.org/show_bug.cgi?id=321440
rdar://184526544

Reviewed by BJ Burg.

Element Send Keys, Element Clear, Get Element Rect, and Element Click commands hang
in cross-origin iframes under Site Isolation.

`WebAutomationSessionProxy::computeElementLayout()` and `takeScreenshot()` reached to the page's
main frame to convert position coordinates, via `dynamicDowncast<LocalFrame>(mainFrame())`.

When Site Isolation is enabled, the main frame of an out-of-process iframe is a RemoteFrame,
so the downcast produces `null` and both functions early return, destroying their completion
handler without calling it. This prevents an IPC reply from ever being, so the automation command
never completes and the WebDriver client hangs until it times out.

This affects every command that computes an element's layout for an element inside a cross-origin iframe:
Element Send Keys, Element Clear, Element Click and Get Element Rect.

This patch introduces a change to convert through the frame's local root instead of the page's main frame.

This is not a new approximation: `LocalFrameView::contentsToRootView()` already stops at the local root,
so the existing conversion helpers produce local-root coordinates and pairing them with the local
root's view is consistent. Without Site Isolation the local root is the main frame, so behavior there is unchanged.

When the local root has no view, reply with an error instead of dropping the completion handler,
so that any future failure surfaces as a WebDriver error rather than as a hang.

* Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp:
(WebKit::WebAutomationSessionProxy::computeElementLayout):
(WebKit::WebAutomationSessionProxy::takeScreenshot):

Canonical link: https://commits.webkit.org/319026@main
https://bugs.webkit.org/show_bug.cgi?id=321560
rdar://184667562

Reviewed by Ryosuke Niwa.

This mainly improves code readability. Lambdas also inline better.
This also increases Clang static analysis coverage since captures are
visible to SaferCPP checkers.

* Source/WebCore/Modules/webaudio/MediaElementAudioSourceNode.cpp:
(WebCore::MediaElementAudioSourceNode::updateResamplerIfNeeded):
* Source/WebCore/Modules/webaudio/MediaStreamAudioSourceNode.cpp:
(WebCore::MediaStreamAudioSourceNode::setFormat):
* Source/WebCore/editing/MarkupAccumulator.cpp:
(WebCore::MarkupAccumulator::shouldExcludeElement):
* Source/WebCore/platform/audio/MultiChannelResampler.cpp:
(WebCore::MultiChannelResampler::MultiChannelResampler):

Canonical link: https://commits.webkit.org/319027@main
https://bugs.webkit.org/show_bug.cgi?id=321577
rdar://184689585

Reviewed by Ian Grunert.

This adapts the existing swiftc-wrapper.sh into a Python script called
swiftc-wrapper.py. The intention is that it's functionally identical.

This is a pre-requisite for enabling Swift support on Windows. This PR does
not do that - Swift is still disabled on Windows platforms - but it gets
us closer.

The launch mechanism is slightly subtle here. On POSIX platforms, we
can set CMAKE_Swift_COMPILER directly to the python script, and the
shebang will ensure it's launched correctly. On Windows, there is no
such thing as a shebang, so the most obvious option would be to launch it using
a cmd.exe invocation and perhaps a batch file. That doesn't work since our
Swift compilation commands are too long for cmd.exe's limits. For that
reason we use a CMake _ARG1 variable.

A few other minor 'if' conditions are adjusted too, so that the Windows
build most closely matches GTK and WPE and thus does not involve Cocoa-
specific Swift code.

* CMakeLists.txt:
* Source/WebCore/PAL/pal/CMakeLists.txt:
* Source/cmake/OptionsWin.cmake:
* Source/cmake/WebKitMacros.cmake:
* Tools/Scripts/swift/swiftc-wrapper.py: Added.
(filter_benign_warnings):
(expand_response_file):
(process_args):
(main):
* Tools/Scripts/swift/swiftc-wrapper.sh: Removed.

Canonical link: https://commits.webkit.org/319028@main
…ne does not move the following content to the next page

https://bugs.webkit.org/show_bug.cgi?id=321413

Reviewed by Antti Koivisto.

applyAfterBreak answers a forced break by moving the container's logical height to the top of the next page.
That is what puts the content after a block level sibling there, since the next block child starts from the
container's height. A block level box on a line is laid out through the same layoutBlockChild, so the break is
taken, but what comes after the box is a line, and a line takes its position from the line before it in
logicalTopForNextLine. Nothing reads the height the break moved, and the content stays on the first page.

The distance the break moved the height is already at hand: layoutBlockChildFromInlineLayout returns it as
containerLogicalBottom. Take it as the margin after the box, so the line after it starts at the top of the
next page.

Only a forced break may contribute here. The collapsed margin after the box is carried by the margin state a
few lines below, and counting it in both places grows the container by that margin.

* LayoutTests/printing/page-break-after-block-level-box-on-a-line.html: Added.
* LayoutTests/printing/page-break-after-block-level-box-on-a-line-expected.txt: Added.
* Source/WebCore/layout/integration/LayoutIntegrationFormattingContextLayout.cpp:
(WebCore::LayoutIntegration::layoutWithFormattingContextForBlockInInline):

Canonical link: https://commits.webkit.org/319029@main
…ner has a block level box on a line

https://bugs.webkit.org/show_bug.cgi?id=321472

Reviewed by Antti Koivisto.

RenderBlock::positionForPoint answers a point above its content with the first child the point is above,
walking the children in document order. isChildHitTestCandidate takes floats, so a float that leads the
container is what a point above it resolves to.

A container whose children are a mix of inline and block level content takes positionForPointWithInlineChildren
instead. That walks line boxes, and while PlacedFloats does record the line that placed each float, a float
never gets a display box, so the line box iterators cannot reach one. The caret goes to the first line's
leading box, which for such a container is the block level box on it.

Answer from the leading floats before taking the inline children walk, and only for a container that has a
block level box on a line, so that a container with inline content only keeps resolving the point with its
lines. The float walk stops at the first child that is not floating, so it only speaks for floats that come
before any other content.

* LayoutTests/editing/selection/caret-from-point-above-leading-float.html: Added.
* LayoutTests/editing/selection/caret-from-point-above-leading-float-expected.txt: Added.
* Source/WebCore/rendering/RenderBlock.cpp:
(WebCore::RenderBlock::positionForPoint):

Canonical link: https://commits.webkit.org/319030@main
…values from the calling context

https://bugs.webkit.org/show_bug.cgi?id=321585
rdar://184701762

Reviewed by Alan Baradlay.

BuilderState::registeredProperty returned only the function's own registrations, so a document
@Property registration was invisible inside a function body. A name the function does not
introduce arrives there by inheritance, carrying the calling element's computed value, so the
value was typed while the registration view said unregistered. var() reads the equivalent
token sequence either way and never noticed, but if(style()) compared a typed value against a
token stream and never matched.

Make the function's registrations shadow the document's rather than replace them, register the
body's local variables with the universal syntax so a local stays untyped, and resolve the
style() feature value with the same registrations as the property it is compared against.

* LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-parameter-types.tentative-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/function-parameter-types.tentative.html:
Tentative because the spec wording does not address an untyped local directly.

* LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/local-if-substitution-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/local-if-substitution.html:
* Source/WebCore/css/query/ContainerQueryFeatures.cpp:
(WebCore::CQ::Features::StyleFeatureSchema::localPropertyRegistry):
(WebCore::CQ::Features::StyleFeatureSchema::evaluateRange const):
* Source/WebCore/style/StyleBuilder.cpp:
(WebCore::Style::Builder::applyCustomPropertyFromCallingContext):
* Source/WebCore/style/StyleBuilderState.cpp:
(WebCore::Style::BuilderState::registeredProperty const):
* Source/WebCore/style/StyleBuilderState.h:
(WebCore::Style::BuilderState::localPropertyRegistry const):
* Source/WebCore/style/StyleSubstitutionResolver.cpp:
(WebCore::Style::SubstitutionResolver::substituteDashedFunction):

Canonical link: https://commits.webkit.org/319031@main
…ex or grid item

https://bugs.webkit.org/show_bug.cgi?id=321487

Reviewed by Antti Koivisto.

A ruby is a rebuild root, so appending a child to one destroys and recreates its renderer. Detaching it from a
grid merges the anonymous items on either side of it, and on re-attach the box it comes before is no longer the
merged item's first child, so findParentAndBeforeChildForNonSibling puts the block level ruby inside that item
instead of next to it. It stops being a grid item and never lays out.

That misplacement is not new, but the anonymous block path used to undo it: attach ends the inline parent with
block child case by calling removeLeftoverAnonymousBlock, which hoists everything back into the grid.
shouldBuildAnonymousBlock is what leads there, and it asks the parent for its display value. The parent here is
the anonymous item, whose display comes from the content it wraps rather than from the grid, so the answer is no
and the box stays where it was put.

Ask what an anonymous item is an item of. Inline content and a block level box may not share one item, which is
what the display values already listed there stand for.

* LayoutTests/fast/ruby/append-rt-to-ruby-grid-item.html: Added.
* LayoutTests/fast/ruby/append-rt-to-ruby-grid-item-expected.txt: Added.
* Source/WebCore/rendering/updating/RenderTreeBuilderBlock.cpp:
(WebCore::RenderTreeBuilder::Block::attach):

Canonical link: https://commits.webkit.org/319032@main
https://bugs.webkit.org/show_bug.cgi?id=321504

Reviewed by Antti Koivisto.

A legend that reaches past its fieldset's border edge is carried as an intrinsic border, which
RenderBlock::borderBefore adds to the fieldset's border. The border box height the fieldset ends up with is
measured with that border in it, so RenderBox::contentBoxHeight has nothing left and clamps at zero.

updateLayoutBoxDimensions builds the geometry for a box on a line from both of those: the content box height from
the renderer, and the border from adjustBorderForTableAndFieldset, which adds the intrinsic border again. The
margin box the line gets is then max(0, H - BP) + BP, which is BP rather than H whenever the legend overhangs, so
the fieldset takes the overhang twice and its container grows by it.

The overhang belongs to the fieldset's own content: the lines inside it start below the legend. It says nothing
about the box a line holds, whose inner layout the render tree does. So take it where the fieldset is the
formatting context root and nowhere else, which leaves logicalBorder about a table's collapsed borders. The
content box size comes from what is left of the border box, since the renderer's own answer is measured against a
border that has the overhang in it. Only the fieldset's own block axis grew, which is the container's inline axis
when the two writing modes differ in orientation.

* LayoutTests/imported/w3c/web-platform-tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-with-overhanging-legend-on-a-line.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-with-overhanging-legend-on-a-line-ref.html: Added.
* LayoutTests/imported/w3c/web-platform-tests/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-with-overhanging-legend-on-a-line-expected.html: Added.
* Source/WebCore/layout/integration/LayoutIntegrationBoxGeometryUpdater.cpp:
(WebCore::LayoutIntegration::adjustBorderForTable):
(WebCore::LayoutIntegration::intrinsicBorder):
(WebCore::LayoutIntegration::contentLogicalWidthForRenderer):
(WebCore::LayoutIntegration::contentLogicalHeightForRenderer):
(WebCore::LayoutIntegration::BoxGeometryUpdater::updateLayoutBoxDimensions):
(WebCore::LayoutIntegration::BoxGeometryUpdater::setFormattingContextRootGeometry):
(WebCore::LayoutIntegration::BoxGeometryUpdater::formattingContextConstraints):
(WebCore::LayoutIntegration::adjustBorderForTableAndFieldset): Deleted.
(WebCore::LayoutIntegration::BoxGeometryUpdater::logicalBorder):

Canonical link: https://commits.webkit.org/319033@main
…eate a cycle

https://bugs.webkit.org/show_bug.cgi?id=321592
rdar://184711017

Reviewed by Alan Baradlay.

* LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/dashed-function-cycles-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-mixins/dashed-function-cycles.html:
* Source/WebCore/style/StyleSubstitutionResolver.cpp:
(WebCore::Style::SubstitutionResolver::substituteDashedFunction):

Move cycle detection after argument substitution.

Canonical link: https://commits.webkit.org/319034@main
https://bugs.webkit.org/show_bug.cgi?id=321576
rdar://184684164

Reviewed by Chris Dumez.

Ensure that data URL greater than 2MB do not cause the web content process to be killed.

* LayoutTests/media/video-large-data-url-expected.txt: Added.
* LayoutTests/media/video-large-data-url.html: Added.

Canonical link: https://commits.webkit.org/319035@main
https://bugs.webkit.org/show_bug.cgi?id=

Reviewed by Michael Catanzaro.

OpenTypeVerticalData loads vertical glyph substitutions from a
downloaded font's GSUB table, which is attacker controlled.
LookupTable::getSubstitutions() fills the substitution map one Coverage
Format 2 range at a time. from and fromEnd were uint16_t with fromEnd
set to end + 1, so a range whose end is 0xffff wraps fromEnd to 0. The
guard indexTo + (fromEnd - from) > countTo then underflows on the
truncated value and passes, and the inner loop walks from start through
0xffff before from wraps back to 0, reading
singleSubstitution2->substitute[indexTo] far past its validated
glyphCount entries. substitute is a raw pointer into the GSUB buffer, so
this is an unchecked heap read past the table. A reversed range with
start greater than end underflows the same guard.

Widen from and fromEnd to unsigned so end + 1 stays exact, and reject
fromEnd <= from to drop reversed and empty ranges before the copy. Valid
ranges map the same glyphs as before.

* Source/WebCore/platform/graphics/opentype/OpenTypeVerticalData.cpp:
(WebCore::OpenType::LookupTable::getSubstitutions):

Canonical link: https://commits.webkit.org/319036@main
…n account profile/settings pages

https://bugs.webkit.org/show_bug.cgi?id=321566
rdar://184671350

Reviewed by Abrar Rahman Protyasha.

Make several adjustments to further streamline resulting text extractions on zoom.us; see below for
more details.

Test: fast/text-extraction/debug-text-extraction-bare-images.html

* LayoutTests/fast/text-extraction/debug-text-extraction-bare-images-expected.txt: Added.
* LayoutTests/fast/text-extraction/debug-text-extraction-bare-images.html: Added.
* LayoutTests/fast/text-extraction/debug-text-extraction-basic-expected.txt:
* LayoutTests/fast/text-extraction/debug-text-extraction-form-controls-expected.txt:
* LayoutTests/fast/text-extraction/debug-text-extraction-lightweight-discretionary-expected.txt:
* LayoutTests/fast/text-extraction/debug-text-extraction-lightweight-expected.txt:
* LayoutTests/fast/text-extraction/debug-text-extraction-offscreen-password-fields-expected.txt:
* LayoutTests/fast/text-extraction/debug-text-extraction-role-suppression-expected.txt:
* LayoutTests/fast/text-extraction/debug-text-extraction-role-suppression.html:
* Source/WebCore/page/text-extraction/TextExtraction.cpp:
(WebCore::TextExtraction::extractRecursive):

Avoid surfacing `tree` and `treeitem` as relevant accessibility roles.

* Source/WebKit/Shared/TextExtractionToStringConversion.cpp:
(WebKit::isUninformativeImage):

Exclude redundant image items with no semantically meaningful roles or attributes. For instance,

```
button uid=5234 label='Learn more'
  image uid=5235
```

...can simply become:

```
button uid=5234 label='Learn more'
```

(WebKit::isIdentityFreeContainer):

Eliminate interstitial container elements with no semantically meaningful roles or attributes.

(WebKit::addTextRepresentationRecursive):

Canonical link: https://commits.webkit.org/319037@main
…on/user-messages is timing out

https://bugs.webkit.org/show_bug.cgi?id=321565

Unreviewed test gardening.

* Tools/TestWebKitAPI/glib/TestExpectations.json:

Canonical link: https://commits.webkit.org/319038@main
dpino and others added 8 commits August 16, 2026 01:53
…olution-002.html is failing

https://bugs.webkit.org/show_bug.cgi?id=225499

Reviewed by Carlos Garcia Campos.

This test turns font feature 'dlig' (discretionary ligatures) ON and OFF
several times. The former code only turned ON this feature, but it never
turned it OFF again. As a result of that, the test was failing because it shown
some characters with ligatures enabled when it shouldn't.

Now the 'dlig' and 'hlig' features are always disabled when
'shouldDisableLigaturesForSpacing' is true. Otherwise, those feature tags
are added if each corresponding feature is enabled.

* Source/WebCore/platform/graphics/skia/FontCacheSkia.cpp:
(WebCore::FontCache::computeFeatures):
* LayoutTests/platform/glib/TestExpectations:

Canonical link: https://commits.webkit.org/319250@main
https://bugs.webkit.org/show_bug.cgi?id=138673
rdar://185001852

Reviewed by Zak Ridouh.

Clicking a link with a download attribute in Mac MiniBrowser saves nothing: the
page navigates to the file, or goes blank. Same for a response carrying
Content-Disposition: attachment, and for Download Linked File in the context menu.

Three things were missing, each one enough on its own.
decidePolicyForNavigationAction returned Allow for anything _canHandleRequest,
which is true for the http and https URLs a download attribute points at. There
was no WKDownloadDelegate, so a download that did start was never told where to
write. And MiniBrowser is sandboxed with no entitlement for the download folder.

This answers download for a download attribute, and for a response that is an
attachment or a MIME type we cannot display in the main frame. It saves under a
name that is still free, since WebKit refuses a destination that already exists.

Note the WK1 window is untouched; the download attribute is off by default there.

Test: ManualTests/download-triggers.html

* ManualTests/download-triggers.html: Added.
* Tools/MiniBrowser/MiniBrowser.entitlements:
* Tools/MiniBrowser/mac/WK2BrowserWindowController.m:
(responseIsAttachment):
(-[WK2BrowserWindowController webView:decidePolicyForNavigationAction:preferences:decisionHandler:]):
(-[WK2BrowserWindowController webView:decidePolicyForNavigationResponse:decisionHandler:]):
(-[WK2BrowserWindowController webView:navigationAction:didBecomeDownload:]):
(-[WK2BrowserWindowController webView:navigationResponse:didBecomeDownload:]):
(-[WK2BrowserWindowController _webView:contextMenuDidCreateDownload:]):
(availableDownloadURLWithFilename):
(-[WK2BrowserWindowController download:decideDestinationUsingResponse:suggestedFilename:completionHandler:]):
(-[WK2BrowserWindowController downloadDidFinish:]):
(-[WK2BrowserWindowController download:didFailWithError:resumeData:]):

Canonical link: https://commits.webkit.org/319251@main
….truncateEnd is not a function"

https://bugs.webkit.org/show_bug.cgi?id=321865
rdar://185027124

Reviewed by Devin Rousso.

WI.DOMTreeElementPathComponent builds its title from the WI.DOMNode, but the
CDATA_SECTION_NODE case calls truncateEnd() on the node instead of on the node's
value. truncateEnd() is a String.prototype extension, so selecting a CDATA
section throws a TypeError out of the constructor, which leaves
ContentBrowser._updateContentViewSelectionPathNavigationItem() half done and
takes down the frontend. XML documents are the only ones that parse CDATA
sections, so this is reachable by selecting the CSS inside <style> when
inspecting an SVG document.

WI.DOMSearchMatchObject.titleForDOMNode() has the same mistake in its
CDATA_SECTION_NODE case, where it concatenates the WI.DOMNode itself and
produces "<![CDATA[[object Object]]]>" as the search result title.

* Source/WebInspectorUI/UserInterface/Models/DOMSearchMatchObject.js:
(WI.DOMSearchMatchObject.titleForDOMNode):
* Source/WebInspectorUI/UserInterface/Views/DOMTreeElementPathComponent.js:
(WI.DOMTreeElementPathComponent):

Canonical link: https://commits.webkit.org/319252@main
…ters to allow some callers to avoid unnecessary includes

https://bugs.webkit.org/show_bug.cgi?id=317315

Reviewed by Geoffrey Garen.

Replace adhoc out-of-line Style::ComputedStyleProperties getters added in 315023@main
with generated ones.

Now, in addition to the existing getters, each property has a getter with an additional
suffix, "OutOfLine", that is implemented in StyleComputedStyleProperties.cpp forwards to
the existing inline getter.

In addition, added an accessor, Style::ComputedStyleBase::primaryFont(), which returns
`fontCascade().primaryFont()`, to simplify a few call sites.

* Source/WebCore/accessibility/AccessibilityScrollView.cpp:
* Source/WebCore/accessibility/cocoa/AccessibilityObjectCocoa.mm:
* Source/WebCore/accessibility/ios/AccessibilityObjectIOS.mm:
* Source/WebCore/css/CSSProperties.json:
* Source/WebCore/css/scripts/process-css-properties.py:
* Source/WebCore/css/scripts/test/TestCSSProperties.json:
* Source/WebCore/css/scripts/test/TestCSSPropertiesResults/StyleComputedStyleProperties.cpp:
* Source/WebCore/css/scripts/test/TestCSSPropertiesResults/StyleComputedStyleProperties.h:
* Source/WebCore/page/writing-tools/WritingToolsController.mm:
* Source/WebCore/style/computed/StyleComputedStyle.cpp:
* Source/WebCore/style/computed/StyleComputedStyle.h:
* Source/WebCore/style/computed/StyleComputedStyleBase.cpp:
* Source/WebCore/style/computed/StyleComputedStyleBase.h:
* Source/WebKitLegacy/mac/DOM/DOM.mm:
* Source/WebKitLegacy/mac/WebView/WebView.mm:

Canonical link: https://commits.webkit.org/319253@main
Merge base was 3722912 (846 upstream commits).

Yarr is kept at the fork's version (09e4777, #299) for now; the upstream
Yarr commits in this range are ported on top in follow-up commits. The
ENABLE_YARR_JIT_* flags upstream removed in 318417@main stay defined in
PlatformEnable.h because the fork's YarrJIT still uses them.

Other resolutions:
- USE_BUILTIN_FRAME_ADDRESS removed upstream (318429@main): Windows ARM64 now
  uses __builtin_frame_address(1) like every other JIT platform; the fork's
  topCallFrame fallback for it is gone with the upstream code that backed it.
- MAX_ARRAY_BUFFER_SIZE stays 1 << 32 under USE(BUN_JSC_ADDITIONS); upstream
  raised it to 1 << 34.
- ScriptFetchParameters::Type gains upstream's Text before the fork's
  HostDefined; with BUN_JSC_ADDITIONS "text" still parses as HostDefined.
- SyntheticModuleRecord: upstream's SourceProviderSourceType parameter threaded
  through; the fork's lazy-export overload reports SourceProviderSourceType::Module.
- HeapFinalizerCallback -> GCCompletionCallback, HandleSet -> StrongSet,
  finalizeUnconditionally -> reconcileWeakReferencesAtGCEnd applied to fork code.
- Both versions of regexp-lookbehind-jit.js and
  regexp-unicode-property-escape-ignore-case.js are kept; the fork's copies are
  renamed with -vs-interpreter / -matrix suffixes.
Upstream moved the builtin source scan into BuiltinSourceMetadata, so the
fork's async-visibility tweak in createExecutable() has to read it from there.
… is an inverted class

Port of upstream 318854@main (webkit.org/b/321252) onto the fork's Yarr.
appendInverted() applied the pending set operation to the characters only,
so /^[\q{ab|c|1}&&\P{L}]$/v still matched "ab". Materialize the complement
and go through append(), which applies the operation to the strings too.
Covered by JSTests/stress/regexp-v-flag-class-set-op-inverted-property.js.
Upstream 318534@main made StackBounds::currentThreadStackBounds() private to
Thread. Bun computes the bounds once per thread, including for threads that
are not WTF threads, so expose that use under USE(BUN_JSC_ADDITIONS).
…) in Bun

Upstream 319108@main made numberOfProcessorCores() honor NUMBER_OF_PROCESSORS
for WebKit's test bots. Bun reports this value as navigator.hardwareConcurrency
and os.availableParallelism(), which do not follow that variable in Node, and
on Linux it would also take precedence over the affinity and cgroup aware count
below. The older WTF_numberOfProcessorCores override is left as it was.
Comment thread JSTests/stress/array-buffer-slice-larger-than-4gb.js
@github-actions

Copy link
Copy Markdown

Preview Builds

Commit Release Date
8fc20b18 autobuild-preview-pr-455-8fc20b18 2026-08-17 00:01:13 UTC

robobun added a commit to oven-sh/bun that referenced this pull request Aug 17, 2026
Pins WEBKIT_VERSION at the preview build of oven-sh/WebKit#455 (upstream
WebKit 47f7250137c6) and adapts the embedding:

- root.h: HandleSet.h no longer exists (Strong slots moved to StrongSet).
- ScriptFetchParameters::Type gained Text ahead of the fork's HostDefined,
  so the ordinal Bun's transpiler emits for host-defined import types is 5;
  the static_asserts pin Text and HostDefined.
- SyntheticModuleRecord::create() takes the record's SourceProviderSourceType.
- scriptFetchParametersToImportAttributes() covers Type::Text.
- StackBounds::currentThreadStackBounds() is private upstream; use the fork's
  embedder accessor.
- Test pinning the JS-visible changes of this range and the fork-side
  decisions (type: "text" stays host-defined, NUMBER_OF_PROCESSORS is not
  honored).
@Jarred-Sumner
Jarred-Sumner merged commit e462c38 into main Aug 17, 2026
47 checks passed
Jarred-Sumner added a commit to oven-sh/bun that referenced this pull request Aug 18, 2026
Upgrades the WebKit fork to upstream WebKit/WebKit@47f7250137c6
(2026-08-16) via oven-sh/WebKit#455: 846 upstream commits since the
previous merge base `3722912ff800` (2026-08-02), 235 of them in
JavaScriptCore, WTF or bmalloc.

`WEBKIT_VERSION` is pinned to oven-sh/WebKit@eeab04040fa6, the fork
`main` after oven-sh/WebKit#455 merged, plus oven-sh/WebKit#463
(URLParser host scanning, WTF only); its `autobuild-eeab04040fa6...`
release has all 42 variants. (The PR initially pinned the #455 preview
build while that PR was open.)

### Bun-side changes

- `root.h`: `<JavaScriptCore/HandleSet.h>` no longer exists (`Strong<>`
slots moved to `StrongSet`, upstream `ff64aee116d4`).
- `ScriptFetchParameters::Type` gained `Text` (import-text, upstream
`49246d2612`) ahead of the fork's `HostDefined`, so the ordinal Bun's
transpiler emits for host-defined import types
(`to_script_fetch_parameters_type`) is 5 instead of 4; the
static_asserts in `BunAnalyzeTranspiledModule.cpp` pin both values. With
the fork, `with { type: "text" }` still parses as a host-defined type,
so Bun's own text loader keeps handling it on every file type.
- `NodeVMSyntheticModule.cpp`: `SyntheticModuleRecord::create()` takes
the record's `SourceProviderSourceType` (it only feeds the module kind
attached to errors).
- `NodeVM.cpp`: the import attributes switch covers `Type::Text`.
- `wtf-bindings.cpp`: `StackBounds::currentThreadStackBounds()` is
private to `Thread` upstream (`f6bc402b83`);
`Bun__StackCheck__initialize` uses the once-per-thread accessor the fork
adds.

### Visible to JavaScript after this upgrade

- `Iterator.prototype.chunks` / `windows` / `join` and `Iterator.zip` /
`zipKeyed` are enabled by default (upstream flipped the flags;
`chunks`/`windows` also follow the latest spec text and throw on
non-integral sizes).
- intl-era-monthcode (Stage 4) is unconditional:
`Intl.supportedValuesOf("calendar")` returns the proposal's 16 calendars
(`islamic` and `islamic-rgsa` are gone, Temporal rejects them as
calendar ids), era / eraYear / monthCode handling reworked across the
non-ISO calendars.
- `Array.prototype.sort()` without a comparator is stable for small
buckets of equal keys (was not) and faster on string arrays.
- Temporal: a batch of spec fixes (constructor `newTarget` order,
Duration rounding in exact arithmetic, `.with()` field resolution, time
zone string parsing follows the spec's parse records, DST gap range
checks).
- `/^[\q{ab|c|1}&&\P{L}]$/v` no longer matches `"ab"` (ported upstream
fix, the one Yarr change of this range that #299 did not already
contain).
- Deliberately unchanged in the fork, each flagged in oven-sh/WebKit#455
so it can be revisited separately: `Buffer` `kMaxLength` /
`MAX_ARRAY_BUFFER_SIZE` stays 4 GB (upstream went to 16 GB),
`NUMBER_OF_PROCESSORS` does not influence
`navigator.hardwareConcurrency` / `os.availableParallelism()`
(upstream's WTF now reads it), import-text is not exposed (`type:
"text"` stays Bun's).

### WebKit-side notes (details in oven-sh/WebKit#455)

- Yarr is kept at the fork's version (#299); upstream's Yarr commits of
this range were checked one by one and upstream's new regexp JSTests run
against the fork's engine. Not yet ported: one JIT optimization and the
default-off `\A` `\z` buffer boundaries.
- Windows ARM64 now uses `__builtin_frame_address(1)` in JIT operations
like every other platform: upstream deleted the `topCallFrame` fallback
the fork had selected there since the January bring-up ("crashes in DFG
operations" back then). Checked on a Windows 11 ARM64 machine with a
debug build of this branch against the preview WebKit: a workload that
tiers up to DFG and FTL (6 compiles each, `reportCompileTimes`) and
calls operations for 300k iterations runs clean; debug builds assert
`topCallFrame == callFrame` in every operation, so a wrong frame address
would have fired immediately. The windows-aarch64 lanes of this PR cover
the rest.
- Other resolutions: `GCCompletionCallback`, `StrongSet` and
`reconcileWeakReferencesAtGCEnd` renames applied to fork code,
upstream's own CMake 4.4 fix replaces the fork's,
`SyntheticModuleRecord` lazy exports kept on top of upstream's source
type plumbing.
- `JSType.h` did not change, so `src/jsc/JSType.rs` stays valid. ICU is
unchanged (the fork's 78.3 bump is already in the current pin). Bytecode
caches are keyed on the WebKit version and invalidate on their own.

### Binary size

The stripped binaries grow 448 KB to 800 KB per target against main
(0.6% to 0.9%; the size check's 0.5 MB threshold trips on darwin,
android and freebsd), acknowledged with `[skip size check]` in 95d581dd.
Comparing the non-LTO linux-x64 WebKit prebuilts of the old and new pin:
`libJavaScriptCore.a` object code grows a net 90 KB spread over 117
object files (StrongSet replacing HandleSet, the typed array sort
rewrite, intl-era-monthcode, memory64/table64, the new Air analyses,
builtins metadata), `libWTF.a` 2 KB, `libbmalloc.a` unchanged; the
remainder of the per-binary delta is LTO inlining of the changed engine
headers into Bun's own objects. The zipped artifacts are slightly
smaller than main's, so the added bytes are highly compressible.

### How did you verify your code works?

- `bun run jsc:build:debug` and `bun run build:local -p '42'` on Linux
x64 against the merged tree.
- oven-sh/WebKit#455 built on every platform variant as a preview before
merging; the merged release pinned here built the same way.
- The JS-visible changes listed above and the fork-side decisions
(`type: "text"` staying host-defined on both module paths,
`NUMBER_OF_PROCESSORS` being ignored, the 4 GB limit) were checked
against this build and against the previous pin with a throwaway test;
`test/js/bun/jsc/webkit-upgrade-3722912f.test.ts` still passes. No test
file is added in this PR.
- With the locally linked build: `test/js/bun/jsc`, `jsc-stress`,
`node/vm`, `node/module`, `bun/resolve`, `node/buffer`,
`node/worker_threads`, `bun/wasm`, `node/util` (78 files, 2034 tests);
the only failures are 5 s timeout / RSS threshold tests that a debug
build of current main fails identically on the same machine, and the
scenarios behind them behave the same with both builds when run
directly.
- JSTests: upstream's 21 new regexp tests plus the 318 `regexp*` /
`string-*` / `yarr*` stress tests against the fork's Yarr, JIT and
interpreter modes (see oven-sh/WebKit#455 for the four explained
failures).

<details>
<summary>JavaScriptCore / WTF / bmalloc changes in
WebKit/WebKit@3722912ff800...47f7250137c6 (235 commits; the ones that
matter to an embedder)</summary>

### Highlights
- `2c2c1af35743` ArrayBuffer / Wasm memory sizing overhaul: upstream
raises 64-bit `MAX_ARRAY_BUFFER_SIZE` from 4 GiB to 16 GiB (the Bun fork
pins it back to 4 GiB under `BUN_JSC_ADDITIONS` because
`buffer.constants.MAX_LENGTH` derives from it), fixes
`ArrayBuffer.prototype.slice` truncating byte lengths to 32 bits, fixes
growing shared memory64 past 4 GiB, and makes typed-array string keys
past `MAX_ARRAY_INDEX` reach the element.
- `ff64aee116d4` `Strong<>` root slots move from
`HandleSet`/`HandleBlock` to new `StrongSet`/`StrongBlock` (faster and
smaller for embedders that create/destroy many `JSC::Strong` handles, as
Bun does); `HandleSet.h` is gone and `Heap::handleSet()` is now
`Heap::strongSet()` (Bun's `root.h` already switched).
- `f6bc402b8344` `StackBounds::currentThreadStackBounds()` is now
private (on Linux it can re-parse `/proc/self/maps` per call); Bun's
`Bun__StackCheck__initialize` called it directly and now goes through a
`USE(BUN_JSC_ADDITIONS)`-only `currentThreadStackBoundsForEmbedder()`
shim.
- `5fc5182bcf83` `WTF::numberOfProcessorCores()` upstream now honors
`NUMBER_OF_PROCESSORS`; kept out of Bun builds in the fork (it feeds
`navigator.hardwareConcurrency` / `os.availableParallelism()` and would
override the fork's cgroup aware count), so nothing changes for Bun.
- `49246d261276` Implements the import-text proposal behind new
`useImportText` (default true); `ScriptFetchParameters::Type` and
`SourceProviderSourceType` gain `Text` (Bun's `HostDefined` tag moves
from 4 to 5), `SyntheticModuleRecord::create` / `AbstractModuleRecord`
take a `SourceProviderSourceType`; the fork keeps `"text"` as
`HostDefined` so Bun's own text loader still wins.
- `547e1555ce4d` `Iterator.prototype.chunks/windows` (and via yaml-only
flips `Iterator.prototype.join`, `Iterator.zip`/`zipKeyed`) become
enabled by default in this range and Bun does not override the flags, so
they become visible to Bun users with this upgrade.
- `99473681ff5e` intl-era-monthcode (Stage 4) is now unconditional:
`Intl.supportedValuesOf("calendar")` returns the fixed 16-calendar list,
`islamic`/`islamic-rgsa` are dropped as Temporal calendar ids, and
era/eraYear/monthCode handling is reworked across all non-ISO calendars.
- `a011564b98ab` `Array.prototype.sort()` with no comparator was not
stable for buckets of <32 equal-key entries (spec violation); now stable
(and `6380373fc6a1` makes it 1.2x-3.9x faster on string arrays).
- `f641af0b8e47` DFG-inlined single-element `Array.prototype.unshift`
was missing a write barrier, so the shifted element could be hidden from
the concurrent collector; fixes a potential GC use-after-free/crash in
optimized code.
- `7ff1104e4d0b` DFG no longer re-speculates GlobalProperty scope
accesses (e.g. `console`, `process`) after a BadCache exit, fixing
repeated OSR exits when such globals are redefined.
- `f2b02eb84f25` `MicrotaskQueue::performMicrotaskCheckpoint` skips
`drain()` on an empty queue; an empty `VM::drainMicrotasks()` halves in
cost (Bun calls this after every task).

### Runtime / builtins
- `2c2c1af35743` Overhauled ArrayBuffer / Wasm memory sizing: upstream
raises the 64-bit `MAX_ARRAY_BUFFER_SIZE` from 4 GiB to 16 GiB, caps
memory64 at 262144 pages (over-declared modules now fail
`WebAssembly.Module`), caps a single resizable/growable buffer's
`maxByteLength` reservation at 1/4 of the primitive address-space
budget, stops GCing while holding the buffer-memory lock (fixes growing
a shared memory64 buffer past 4 GiB), fixes
`ArrayBuffer.prototype.slice` truncating byte lengths to 32 bits, and
makes typed-array string keys past `MAX_ARRAY_INDEX` (e.g.
`"4294967295"`) reach the element for get/set/define/delete. (The Bun
fork pins `MAX_ARRAY_BUFFER_SIZE` back to 4 GiB under
`BUN_JSC_ADDITIONS` in `Source/JavaScriptCore/runtime/PageCount.h`
because `buffer.constants.MAX_LENGTH` in `src/jsc/bindings/JSBuffer.h`
is derived from it.)
- `40d37f36527f` Follow-up: module parsing accepts arbitrarily large
memory64 limits (rejected at instantiate/grow instead);
`PageCount::maxPageCount` becomes a `uint64_t` and `PageCount::bytes()`
saturates instead of wrapping.
- `a011564b98ab` `Array.prototype.sort()` with no comparator was not
stable for buckets of <32 equal-key entries (spec violation); now uses a
stable sort.
- `6380373fc6a1` `Array.prototype.sort()` with no comparator rewritten
as an in-place counting sort over UTF-16 (still stable); 1.2x-3.9x
faster on string arrays such as `Object.keys(o).sort()`.
- `547e1555ce4d` `Iterator.prototype.chunks/windows` aligned to the
latest spec: non-number or non-integral size now throws TypeError (was
ToNumber coercion), invalid arguments close the underlying iterator,
`undersized` only defaults when `undefined`. These methods become
enabled by default in this range via `793e36fb835e` (yaml-only, outside
these paths); Bun does not override the flag, so they appear on
`Iterator.prototype` after this upgrade.
- `7417386b7da1` `Iterator.prototype.join` aligned to spec: a separator
is still emitted for `undefined`/`null` elements; builds the result with
a RopeBuilder; OOM closes the iterator. Enabled by default in this range
via `e9a62e6b4da5` (yaml-only), so `Iterator.prototype.join` now exists
in Bun. (`Iterator.zip`/`zipKeyed` are likewise enabled by
`934bb002485a`, yaml-only.)
- `c0625bcafb6c` `ErrorInstance` is now subclassable by embedders
(exported constructor/method-table entries plus a `finishCreation(VM&,
StackTraceCapturePolicy)` that captures no stack and adds no own props),
used by WebCore to make `Error.isError(new DOMException())` true;
`CloneSerializerBase` now consults the embedder's `dumpDerivedTerminal`
before its generic ErrorInstance path. Bun's `JSDOMException`
(`src/jsc/bindings/webcore/JSDOMException.h`) is still a plain wrapper,
so no behavior change in Bun unless adopted.
- `fedbb7bdc250`
`Int8Array/Uint8Array/Uint8ClampedArray.prototype.sort()` uses a SIMD
presorted check plus counting sort (2.5x-12x faster, ~38x on presorted
input).
- `4f3ecec97431` `JSON.stringify` fast path now accepts final objects
with non-`Object.prototype` prototypes (class instances) when the chain
has no `toJSON` (~3.5x on such payloads); also fixes
`noSideEffectMayHaveNonIndexProperty()` checking static properties on
the wrong chain entry.
- `8b5e6ebb64e6` FastStringifier caches buffer pointer/length across
property-name emission (reland of `ea3fbb33caa5`, which was reverted in
`ba1d526398de` for a perf regression; value half dropped).
- `da12fb32aeb9` FastStringifier adds a 4-7 byte two-window copy tier
and removes the 8-byte loop; faster `JSON.stringify` of short Latin-1
keys.
- `01ea2a8eb955` `String.prototype.split` no longer atomizes results
when the subject is not an atom string (~3.8x faster on runtime-built
strings; results are plain substrings now).
- `81a11702ef82` The `str.replace(/^\s+/, "")` / `/\s+$/` trim fast path
was unreachable once the caller tiered up to DFG/FTL; now applies in all
tiers (4.5x-5x).
- `a4df93500a72` `Array.prototype.join` / `toString` on Int32 arrays
writes numbers directly for any separator (~2x);
`JSOnlyStringsAndInt32sJoiner::tryJoin` is now templated on indexing
shape.
- `2af38faaec70` DFG `Function.prototype.bind` strength reduction now
also fires for method structures (`this.onClick.bind(this)` on class
methods, ~4.6x).
- `deb0d2fa4be6` BigInt add/sub/mul get fixed-size fast paths, squaring
optimization and carry handling that avoids flag spills on arm64.
- `0270fd0a8d77` BigInt Crandall modular reduction made branch-free for
the first corrective subtract (faster big modular arithmetic).
- `5d6747ef60d4` (parser) see below; memory-visible: closures no longer
retain all call arguments when an inner arrow uses object shorthand.
- `a73e86f9a37f` `Set.prototype`, `WeakRef` and `FinalizationRegistry`
are no longer materialized in `JSGlobalObject::init()`;
WeakRef/FinalizationRegistry become lazy static-table globals (~6.6 KB
saved per global object; `propertyNames->WeakRef` /
`->FinalizationRegistry` removed).
- `8d33a8ff591d` `UnlinkedFunctionExecutable` stores
`parentScopeTDZVariables` inline (RareData allocations drop ~100x in
let/const-heavy code at the same 96-byte cell size); bytecode cache
encoding in `CachedTypes.cpp` changed (Bun keys its cache on the WebKit
version, so old caches are simply invalidated).
- `edd953757f9f` `StructureRareData` shrunk back from 104 to 96 bytes
(cell 112 -> 96) with a static_assert so it does not regress.
- `f2b02eb84f25` `MicrotaskQueue::performMicrotaskCheckpoint` skips
`drain()` on an empty queue; an empty `VM::drainMicrotasks()` halves in
cost (Bun calls this after every task).
- `13dc8fa6e3d5` VM startup: AtomStringTable and BuiltinNames'
private-name set reserve capacity up front (fewer rehashes during VM
construction).
- `81d660ceeb2e` Builtin executable metadata (line counts, parameter
counts, etc.) is precomputed by the builtins generator instead of at VM
launch; `BuiltinCodeIndex::NumberOfBuiltinCodes` replaced by
`numberOfBuiltinCodes`. The free `JSC::createBuiltinExecutable()` used
by Bun's generated builtins is unchanged.
- `c1b19d012809` JIT thunks split into eagerly- and lazily-created sets
(less work at VM startup; `JITThunks::ctiStub` now takes `VM&`).
- `bff3814d76f7` Linux: checkpoint OSR side-state handling used uncached
stack bounds, which glibc implements by re-reading `/proc/self/maps` on
every call; now uses the thread's cached bounds (also on the release
path).
- `c00fd8a9713c` Baseline JIT gets an inline atom-identity fast path for
`switch` on strings; new option `maximumInlineStringSwitchCaseCount`
(default 64).
- `0c51f43daa3b` Wasm OMG recognizes naive byte-copy/fill loops and
prepends `memory.copy`/`memory.fill` fast paths; new option
`useWasmByteLoopReplacement` (default true).
- `c7ed9fcf7957` 32-bit only: typed-array put with an out-of-range
canonical numeric index keeps the index as `uint64_t` until
bounds-checked.
- `a53d011599e7` Tree-wide rename, no behavior change:
`finalizeUnconditionally` -> `reconcileWeakReferencesAtGCEnd` on
ErrorInstance, Structure, StructureRareData, SymbolTable, InferredValue,
JSWeakObjectRef, JSFinalizationRegistry, FunctionExecutable, etc.;
`Heap::finalizeUnconditionalFinalizers` ->
`reconcileWeakReferencesAtGCEnd`; `finalizerSet(For)` ->
`weakReconciliationSet(For)`; `ScriptExecutable::finalizeCodeBlockEdge`
-> `jettisonCodeBlockEdgeIfDead` (Bun only references the old names in
comments).

### Parser / bytecompiler
- `5d6747ef60d4` Object-literal shorthand inside an arrow function no
longer marks the enclosing function as using `eval`, so it stops
materializing `arguments` into its scope; closures returned from such
functions no longer keep all call arguments alive (memory + faster
function entry).
- `69b336c0ac05` `SourceProviderCacheItem` (one per function >16 chars
parsed, retained until full GC) is now a proper trailing array of
`PackedRefPtr`; ~12% less malloc memory for the source-provider cache on
large bundles.
- `9f770b1bd595` `Parser::useVariable` remembers the last variable added
and skips the set insertion on repeats (parse speed).
- `8aa3307b46af` Single-line-comment scanning and the arrow-function /
destructuring paths are moved out of the lexer and
`parseAssignmentExpression` hot loops (lower register pressure; parse
speed, no logic change).
- `71c68f4b3b35` `Lexer::lexExpectIdentifier()` removed; the vectorized
`parseIdentifier()` is now faster, so this shrinks hot code (header API
removal, internal to the parser).

### Intl / Temporal
- `99473681ff5e` intl-era-monthcode (Stage 4) is implemented
unconditionally and the previously default-off `useIntlEraMonthcode`
option is removed: `Intl.supportedValuesOf("calendar")` now returns the
proposal's fixed 16-calendar list, `islamic`/`islamic-rgsa` are dropped
as Temporal calendar ids (`islamic` maps to `islamic-tbla` in
DateTimeFormat, unknown calendars fall back to the locale default),
era/eraYear/monthCode handling reworked across all non-ISO calendars
with chinese/dangi falling back to ISO fields beyond +/-10000 instead of
throwing, and DateTimeFormat's era-text override only applies when an
era field was requested.
- `9ef04dabf52d` `Intl.Locale.prototype.getCollations()` etc. now return
sorted arrays per spec.
- `171864159318` DateTimeFormat with islamic-civil/tbla/umalqura
calendars rendered pre-Hijra years as e.g. `-332 Before Hijra`; now `333
Before Hijra` (computed from the calendar, works with `year:
"2-digit"`).
- `b2ec9a4586ee` `formatToParts()` now emits the separating space that
`format()` inserts before a synthesized coptic/islamic era, so joined
parts equal `format()` again.
- `33a5272cf9ac` `String.prototype.localeCompare(x, "locale")` (string
locale, no options) caches the collator per global object; the common
sort-comparator pattern is ~50x faster.
- `7d0200e4e6ed` That cache is invalidated when the user preferred
languages change (it returned stale orderings for unavailable locales
like `"xx"`).
- `b48f01b7f1b1` All eight Temporal constructors now validate fields
before reading `newTarget.prototype` (spec order; `Reflect.construct`
with a throwing prototype getter gets the RangeError);
`ZonedDateTime.prototype.with` now range-checks epoch nanoseconds;
`tryCreateIfValid`-style helpers renamed to
`createTemporalDate`/`createTemporalZonedDateTime`/... taking a
`TemporalNewTarget`.
- `11615f86705a` Duration rounding decisions now use exact Int128
instead of doubles, fixing wrong results such as `until(...,
{smallestUnit:"month", roundingMode:"ceil"})` returning `P1M` instead of
`P29DT1H`, and the half-even branch of ApplyUnsignedRoundingMode.
- `399973c04a04` `.with()` on all Temporal types now goes through spec
`ISODateToFields`/`CalendarMergeFields` (year-only changes on lunisolar
calendars pick the right month); fixes `PlainYearMonth.add/subtract`
shifting months by -2 for buddhist/roc/japanese in ISO years ~1-1582;
`ZonedDateTime.prototype.with` restored to spec step order.
- `22a13eb9ee2f` Time-zone string parsing follows the spec's parse
records: bracket annotations are now accepted on all six string
productions (`"2024-12[Europe/Berlin]"`, `"12:00[Europe/Berlin]"`, ...),
`"T12+01"` is rejected as an unavailable named zone instead of resolving
to `+01:00`, and IANA-name syntax drops the 14-char limit (accepting
e.g. `[..]`).
- `284afdacfb77` Non-ISO field resolution at range edges:
`PlainYearMonth.toPlainDate({day: 256})` no longer wraps the day to 0
(produced a live `...-01-00` date); chinese/dangi arithmetic at extreme
years no longer throws; `dateUntil` used the wrong year kind on ICU 76.
- `6fd438a4aef2` DST-gap disambiguation re-enters the epoch range check,
so `ZonedDateTime.from("+275760-10-05T02:30[Australia/Sydney]")` throws
instead of creating an out-of-range value; also fixes which candidate is
picked in gaps.
- `4f049dc9046e` `monthCode` given a non-string now throws TypeError
again in `PlainDateTime.from`/`PlainDate.with` (regression from
consolidation); ISO `.with()` no longer regulates day/month twice;
getter order test added.
- `89c1884e15a9` `PlainDate` construction clamps out-of-range years
itself (was a debug assertion crash); fixes `PlainYearMonth.toPlainDate`
clamp direction under `overflow: "constrain"` and a UB cast in the
PlainMonthDay constructor.
- `642d9211add2` ICU failures inside the calendar/time-zone bridges now
propagate as errors instead of being folded into plausible values (e.g.
hebrew `M05L` silently becoming `M06`, a sticky UErrorCode making
`getTimeZoneTransition` return bogus transitions).
- `b2233ac17643` Fixes uninitialized members in duration nudging, an
overflowable day bound, and a debug-only assertion crash when a
zero-length nudge window lands on a day a zone skips; removes dead
duration helpers.
- `8776c95a1b0a` Temporal time-zone cache widened from 8 to 16 entries
(parity with V8 on the duration-total benchmark).
- (`e07ecf4c4a07`, `ee16ce938a8f`, `1375d28c26b3`, `e165fd1fce9a`,
`f6c491404f2d`: internal Temporal refactors declared no-behavior-change;
omitted.)

### Modules
- `49246d261276` Implements the import-text proposal: `import x from
"./a.txt" with { type: "text" }` / dynamic import are handled by JSC as
synthetic default-export modules, gated by new option `useImportText`
(default true, generated from the preferences yaml). Adds
`ScriptFetchParameters::Type::Text` and
`SourceProviderSourceType::Text`, and
`AbstractModuleRecord`/`CyclicModuleRecord`/`SyntheticModuleRecord`
constructors and `SyntheticModuleRecord::create` now take a
`SourceProviderSourceType`. The Bun fork keeps `"text"` as a
`HostDefined` type in `ScriptFetchParameters::parseType` so Bun's own
text loader still wins; Bun's `HostDefined` tag moved from 4 to 5
(static_asserts in `src/jsc/bindings/BunAnalyzeTranspiledModule.cpp` and
`to_script_fetch_parameters_type` in `src/js_printer/lib.rs` are already
updated).
- `cc673d7b23bf` import-defer updated to proposal PRs #85/#87:
`ReadyForSyncExecution` and `GatherAsynchronousTransitiveDependencies`
now use `IsModuleSCCEvaluated` (new
`CyclicModuleRecord::isSCCEvaluated()`), so touching a deferred
namespace whose dependency sits in a still-awaiting TLA cycle correctly
throws "Unable to synchronously evaluate deferred module" instead of
evaluating early (and a debug assertion no longer fires). Bun already
forces `useImportDefer` on; upstream also flipped its default on in
`85e82ceefe1b` (yaml-only).

### API
- `62692012c98a` `HeapFinalizerCallback` renamed to
`GCCompletionCallback` (header `heap/HeapFinalizerCallback.h` ->
`heap/GCCompletionCallback.h`; `Heap::add/removeHeapFinalizerCallback`
-> `add/removeGCCompletionCallback`); the C entry points
`JSContextGroupAddHeapFinalizer` / `JSContextGroupRemoveHeapFinalizer`
keep their names and behavior.

### Embedder-relevant API changes
- Removed: `heap/HeapFinalizerCallback.h` / class
`HeapFinalizerCallback`, `Heap::addHeapFinalizerCallback`,
`Heap::removeHeapFinalizerCallback` -> `GCCompletionCallback.h`,
`Heap::addGCCompletionCallback`, `Heap::removeGCCompletionCallback`
(`62692012c98a`).
- Renamed: `T::finalizeUnconditionally(VM&, CollectionScope)` ->
`T::reconcileWeakReferencesAtGCEnd` on ErrorInstance, Structure,
StructureRareData, StructureTransitionTable, SymbolTable, InferredValue,
JSWeakObjectRef, JSFinalizationRegistry, FunctionExecutable,
GlobalExecutable, UnlinkedFunctionExecutable, CodeBlock;
`Heap::finalizeUnconditionalFinalizers` ->
`reconcileWeakReferencesAtGCEnd`;
`Heap::finalizeMarkedUnconditionalFinalizers` ->
`reconcileWeakReferencesInMarkedCells`; IsoCellSet
`finalizerSet`/`finalizerSetFor` ->
`weakReconciliationSet`/`weakReconciliationSetFor`;
`ScriptExecutable::finalizeCodeBlockEdge` ->
`jettisonCodeBlockEdgeIfDead`; `JITPlan::finalizeInGC` ->
`reconcileWeakReferencesAtGCEnd` (`a53d011599e7`). Any embedder class
registered for unconditional finalization must rename its method.
- Enums: `ScriptFetchParameters::Type` gains `Text` after `JSON` (shifts
any embedder-appended values); `SourceProviderSourceType` gains `Text`
between `JSON` and `ImportMap` (shifts `ImportMap` and any
embedder-appended values; exhaustive switches need a case);
`SourceProvider::isModuleType()` now also true for `Text`
(`49246d261276`).
- Signatures: `AbstractModuleRecord(VM&, Structure*, Identifier,
SourceProviderSourceType)`, `CyclicModuleRecord(...,
SourceProviderSourceType)`,
`SyntheticModuleRecord::create(JSGlobalObject*, VM&, Structure*, const
Identifier&, SourceProviderSourceType)`; new
`SyntheticModuleRecord::createTextModule` (`49246d261276`). Bun's
`NodeVMSyntheticModule.cpp` already passes the new argument.
- `ArrayBuffer::grow(const AbstractLocker&, VM&, size_t, bool)` removed;
replaced by `tryGrow(const AbstractLocker&, size_t, bool,
BufferMemoryResult::Kind&)` (the `grow(VM&, ...)` overload remains); new
`maxGrowableBufferReservationBytes` in `BufferMemoryHandle.h`; new
`Gigacage::primitiveAddressSpaceBudget`; `isCanonicalNumericIndexString`
gains an optional `std::optional<uint64_t>*` out-parameter (source
compatible); 64-bit `MAX_ARRAY_BUFFER_SIZE` is 16 GiB upstream (fork
keeps 4 GiB) (`2c2c1af35743`).
- `PageCount::maxPageCount` is now `uint64_t` with a much larger value;
`PageCount::bytes()` saturates (`40d37f36527f`).
- `ErrorInstance`: constructor and
`getOwnPropertySlot`/`put`/`defineOwnProperty`/`deleteProperty`/`getOwnSpecialPropertyNames`
are now `JS_EXPORT_PRIVATE`; new protected `finishCreation(VM&,
StackTraceCapturePolicy)`; `CloneSerializerBase::dumpIfTerminal` calls
`dumpDerivedTerminal` before the ErrorInstance path (`c0625bcafb6c`).
- `CommonIdentifiers`: `propertyNames->WeakRef` and
`propertyNames->FinalizationRegistry` removed;
WeakRef/FinalizationRegistry structures/prototypes become lazy accessors
(`a73e86f9a37f`).
- `BuiltinCodeIndex::NumberOfBuiltinCodes` removed ->
`JSC::numberOfBuiltinCodes`; new `BuiltinSourceMetadata` /
`s_JSCBuiltinSourceMetadata`; member
`BuiltinExecutables::createBuiltinExecutable` gains a metadata parameter
(free `JSC::createBuiltinExecutable()` and public static
`BuiltinExecutables::createExecutable()` unchanged) (`81d660ceeb2e`).
- `JSOnlyStringsAndInt32sJoiner::tryJoin` is now
`template<IndexingType>` (`a4df93500a72`);
`JITThunks::ctiStub(CommonJITThunkID)` now takes `VM&` first
(`c1b19d012809`); `Lexer::lexExpectIdentifier()` removed
(`71c68f4b3b35`); Temporal `try*` creation helpers replaced by
`createTemporal*(…, TemporalNewTarget)` free functions and
`TemporalPlainDate::mergeDateFields` removed (`b48f01b7f1b1`,
`4f049dc9046e`); `IntlObject.h` calendar-ID table drops `islamic` and
`islamic-rgsa`, `Options::useIntlEraMonthcode` removed (`99473681ff5e`).
- New options: `useImportText` (true),
`maximumInlineStringSwitchCaseCount` (64), `useWasmByteLoopReplacement`
(true). Defaults flipped to true in this range but via yaml-only commits
outside these paths: `useIteratorChunking` (`793e36fb835e`),
`useIteratorJoin` (`e9a62e6b4da5`), `useJointIteration`
(`934bb002485a`), `useImportDefer` (`85e82ceefe1b`); Bun overrides none
of the first three, so `Iterator.prototype.chunks/windows/join` and
`Iterator.zip/zipKeyed` become visible to Bun users with this upgrade.

### GC / heap
- `ff64aee116d45c` `Strong<>` root slots now live in new
`StrongBlock`/`StrongSet` (libpas-style bump+freelist pages, empty
blocks returned to the OS, no write barrier on set) replacing
`HandleSet`/`HandleBlock`; faster and smaller for embedders that
create/destroy many `JSC::Strong` handles (Bun does);
`Heap::handleSet()` is now `Heap::strongSet()` and `HandleSet.h` is gone
(Bun's `root.h` already switched to `StrongSet.h` in this PR). Follow-up
`55659d048725` drops a dead `USE(JSVALUE64_32)` branch from
`StrongBlock.h`.
- `f641af0b8e47` DFG-inlined single-element `Array.prototype.unshift` on
contiguous arrays was missing a write barrier, so the shifted element
could be hidden from the concurrent collector; fixes a potential GC
use-after-free/crash in optimized code.
- `6bdb4f69e23b` VM/Heap teardown (`lastChanceToFinalize`) uses a new
`StopAllocatingMode::ForGood` that skips recomputing allocation bitmaps;
faster VM destruction (e.g. Worker exit);
`MarkedSpace::stopAllocatingForGood()` removed.
- `a53d011599e7` Rename-only: `finalizeUnconditionally()` on all cell
types/VM becomes `reconcileWeakReferencesAtGCEnd()`,
`Heap::finalizeUnconditionalFinalizers` ->
`reconcileWeakReferencesAtGCEnd`, IsoCellSet `finalizerSet` ->
`weakReconciliationSet`, `ScriptExecutable::finalizeCodeBlockEdge` ->
`jettisonCodeBlockEdgeIfDead`; no behavior change (Bun only mentions the
old name in comments in `src/jsc/bindings/ErrorStackTrace.cpp`,
`JSCTaskScheduler.cpp`, `FormatStackTraceForJS.cpp`).
- `5602ec36107b` Rename-only follow-up: `visitWeak()` on
CallLinkInfo/PropertyInlineCache/InlineCacheHandler/JITStubRoutine/PolymorphicCallStubRoutine/MicrotaskCall
-> `reconcileWeakReferencesAtGCEnd()`;
`AccessCase`/`PolymorphicAccess::visitWeak` -> `isStillLive`.
- `3d37c6da40ba` Rename-only:
`GetByStatus`/`PutByStatus`/`InByStatus`/`DeleteByStatus`/`CallLinkStatus`/private-brand
statuses and their variants `finalize()` -> `isStillLive()`.
- `62692012c98a` Rename-only: `HeapFinalizerCallback` ->
`GCCompletionCallback` (header renamed too),
`Heap::add/removeHeapFinalizerCallback` ->
`add/removeGCCompletionCallback`; C API `JSContextGroupAddHeapFinalizer`
unchanged.
- `f4da7823ee1d` Rename-only: `Heap::finalize` ->
`runCollectionEpilogue` (and `needFinalize` bits); the only observable
change is the `--logGC=1` phase label "finalize" is now "epilogue".

### LLInt / Baseline / DFG / FTL / B3
- `a02f99629f76` FTL OSR-exit compiler hit `RELEASE_ASSERT_NOT_REACHED`
(crash) when exiting with a `PhantomNewArrayWithButterfly` whose
butterfly was still live (`DataFormatStorage`); now passed through like
`DataFormatJS`.
- `91d96b29d6b2` DFG
`AbstractInterpreter::forAllValues`/`dump`/`SafeToExecute` now handle
tuple nodes; the DFG-inlined `StringIterator.prototype.next` followed by
a structure transition in the same block asserted in debug builds and
silently skipped the tuple's values in release.
- `7ff1104e4d0b` DFG no longer re-speculates
`op_get_from_scope`/`op_put_to_scope` GlobalProperty accesses (e.g.
`console`, `process`, any global-object property) after a BadCache exit;
emits a generic IC instead, fixing repeated OSR exits when such globals
are redefined.
- `7600ab4bec97` DFG stops inlining varargs calls (`f(...args)`,
`f.apply`) once a `VarargsOverflow` exit has been seen at that site,
fixing perpetual OSR exit/recompile loops.
- `fbb79b137a90` Baseline JIT read the 1-byte
`maxArgumentCountIncludingThisForVarargs` profile with a 32-bit compare
(picking up adjacent bytes), so varargs argument-count feedback fed to
the DFG was wrong; now `load8` + compare.
- `465d5ab28c60` `String.prototype.substring` is now inlined in DFG/FTL
(shares `slice` lowering: empty/one-char/whole-string/rope fast paths);
1.6-2.1x faster in microbenchmarks.
- `fb299342a580` RegExp `test`/`exec` first-character filter now also
applies when the subject is an Untyped edge (runtime string check),
widening the fast path for real-world code.
- `c00fd8a9713c` Baseline JIT gets an inline pointer-identity dispatch
for `switch` on strings when the scrutinee is an atom (previously always
called the hashing slow path); new option
`maximumInlineStringSwitchCaseCount` (default 64).
- `a4df93500a72` `Array.prototype.join`/`toString` on Int32 arrays now
uses `JSOnlyStringsAndInt32sJoiner` for any separator (was only for
`""`), ~2x faster (one-line DFGOperations change; mostly runtime/).
- `0d25934d08a8` VM-independent JIT thunks (polymorphic call thunks,
most IC handler thunks) are generated once per process and shared across
VMs; less per-VM startup work and JIT memory when creating many VMs
(Workers); `JITThunks::ctiStub` now takes `VM&`, handler generators no
longer take `VM&`.
- `c1b19d012809` Remaining VM-dependent thunks split into eager
(exception/native-call/virtual-call) and lazily generated (IC
transition/custom-accessor handlers), so short-lived VMs do not generate
thunks they never use.
- `f40dcdd0730d` LLInt function prologue zeroes the new frame 16 bytes
per iteration with a hoisted zero register (4 instructions/16 bytes on
ARM64, 5 on x64, was 12); `76f57a9311b1` extends it to ARM64E (not built
by Bun).
- `bbab514b1010` DFG/FTL `LazyJSValue::emit` leaked a `StringImpl` ref
per emitted string constant when compilation was abandoned (JIT memory
exhausted or code block invalidated before finalize); now held in a
`RefPtr`.
- `74091f918bfc` New Air `Padding` pseudo-op that emits no bytes
replaces most `Nop` padding, and `reportUsedRegisters` is skipped for
Wasm OMG; faster OMG compiles with no extra `nop`s in generated code.
- `5821b05faa72` Air `TmpWidth` and `UseCounts` are now built in a
single graph walk via new `InstAnalyzer`; faster FTL/OMG register
allocation.
- `4a10860dc35c` Faster Air liveness (`WTF::Liveness` no longer re-walks
blocks or zeroes gen/kill sets; new
`forEachLiveAtHeadNotLiveAtTail`/`...TailNotLiveAtHead`), ~17% off
greedy allocator `buildLiveRanges`.
- `ee4f0240590d` Air DCE worklist seeded in reverse program order, ~20%
faster phase; `ae85b80e5fbe` same phase avoids Vector element removal.
- `4af3bbad9cda` Air, BBQ and Baseline JIT code-generation loops skip
disassembler-only label creation and hoist loop invariants; lower
compile latency in all JIT tiers.
- `6589b2e5c18c` WasmGC `struct.new`/`array.new` codegen tightened (new
`JITAllocator::variableNonNullWithConstantCellSize`, narrower B3
effects, constant-size array allocation folding); faster WasmGC
allocation and more B3 load motion around it.
- `2ec06de15a0d` B3 CSE stops walking every predecessor block for WasmGC
`struct.get`/`struct.set` when no other access to that field exists;
faster OMG compile of WasmGC modules.
- `53517eb3a2b8` / `31f35870966c` Wasm `memory.copy` and `memory.fill`
runtime operations inline small-size copies/fills before falling back to
`memcpy`/`memset`; faster small bulk-memory ops.
- `d02c68d04f96` IPInt mis-decoded `memory.size`/`memory.grow` when the
memory-index immediate took more than one LEB byte (multi-memory, on by
default), desynchronizing the following instructions; also removes the
`parseMemoryIndexForBulkOp` spec-test workaround.
- `9226ba78d93d` `DFG::enableInt52()` removed; Int52 speculation is
unconditional now that the only 64-bit JIT backends remain (no behavior
change on x64/arm64).
- `bf1dab73b14d` / `6010a9ea6ce6` / `84f83abd45c9` 32-bit/ARMv7 JIT
leftovers removed: `ARMv7Assembler.h` deleted, 32-bit DataFormats/GPR
pairs/OSR-entry paths dropped, `branchIfNumber`/`branchIfNotNumber` lose
their scratch-register parameter, `CCallHelpers` `extraGPRArgs` removed;
no codegen change on 64-bit.
- `2a8926009f45` `USE(BUILTIN_FRAME_ADDRESS)` removed (always on for JIT
platforms); `JSWebAssemblyInstance::temporaryCallFrame()` and its field
removed. The fork had it off on Windows ARM64; that configuration no
longer exists (see above).
- `ac2afd10b8ac` Yarr JIT sub-feature flags
(`YARR_JIT_ALL_PARENS_EXPRESSIONS`, `YARR_JIT_BACKREFERENCES`,
`YARR_JIT_REGEXP_TEST_INLINE`, `YARR_JIT_UNICODE_EXPRESSIONS`) removed
as always-on for x64/arm64, with matching DFG/FTL ifdef cleanup; no
behavior change.
- `ef6d9ba26b17` / `56baf6e01b3d` Linux RT-thread removal briefly set
JIT worklist threads to `ThreadQOS::Utility`, then was reverted for
JetStream/Speedometer regressions; net zero change to JSC.

### Bytecode / CodeBlock
- `8d33a8ff591d` `m_parentScopeTDZVariables` moves back into
`UnlinkedFunctionExecutable` (name stored as `m_ecmaName` + `m_hasName`
bit), so the 80-byte RareData is no longer malloc'ed for ~30-40% of
executables in let/const/class-heavy code; also changes the
`CachedTypes` bytecode-cache layout (Bun keys its cache version on
`BUN_WEBKIT_VERSION`, so old `--bytecode` artifacts are invalidated as
with any bump).
- `b00e0c35f823` Slow-path location and per-site register fields move
from `PropertyInlineCache` into `RepatchingPropertyInlineCache`; handler
ICs shrink 128->112 bytes, baseline unlinked ICs 40->32, DFG unlinked
ICs 64->40 (~465 KB saved on Octane typescript).

### Embedder-relevant API changes
- Removed headers: `heap/HandleSet.h`, `heap/HandleBlock.h`,
`heap/HandleBlockInlines.h` (use `heap/StrongSet.h` /
`heap/StrongBlock.h`); `assembler/ARMv7Assembler.h`. Renamed header:
`heap/HeapFinalizerCallback.h` -> `heap/GCCompletionCallback.h`.
- `Heap::handleSet()` -> `Heap::strongSet()`; `HandleSet::heapFor(slot)`
-> `StrongSet::setFor(slot)`; `HandleSet` -> `StrongSet`.
- `HeapFinalizerCallback` -> `GCCompletionCallback`;
`Heap::addHeapFinalizerCallback/removeHeapFinalizerCallback` ->
`addGCCompletionCallback/removeGCCompletionCallback` (C API
`JSContextGroupAdd/RemoveHeapFinalizer` unchanged).
- `finalizeUnconditionally()` -> `reconcileWeakReferencesAtGCEnd()` on
`VM`, `ErrorInstance`, `JSFinalizationRegistry`, `JSWeakObjectRef`,
`Structure`, `StructureRareData`, `SymbolTable`, `WeakMapImpl`,
`InferredValue`, `UnlinkedFunctionExecutable`, `FunctionExecutable`,
`GlobalExecutable`, `CodeBlock`, `JSWebAssemblyInstance`, `JITPlan` (was
`finalizeInGC`);
`Heap::ScriptExecutableSpaceAndSets::finalizerSet/finalizerSetFor` ->
`weakReconciliationSet/weakReconciliationSetFor`;
`ScriptExecutable::finalizeCodeBlockEdge` ->
`jettisonCodeBlockEdgeIfDead`;
`CodeBlock::finalizeLLIntInlineCaches/finalizeJITInlineCaches` ->
`reconcileLLIntInlineCachesAtGCEnd/reconcileJITInlineCachesAtGCEnd`;
`RecordedStatuses::finalize` -> `reconcileWeakReferences`.
- `visitWeak()` -> `reconcileWeakReferencesAtGCEnd()` on `CallLinkInfo`,
`DirectCallLinkInfo`, `PropertyInlineCache`, `InlineCacheHandler`,
`JITStubRoutine` (incl. the virtual `...Impl`),
`PolymorphicCallStubRoutine`, `MicrotaskCall`;
`AccessCase::visitWeak`/`PolymorphicAccess::visitWeak` -> `isStillLive`;
`*Status::finalize()`/`*Variant::finalize()` -> `isStillLive()`.
- `Heap::finalize` -> `Heap::runCollectionEpilogue`;
`MarkedSpace::stopAllocatingForGood()` removed;
`MarkedBlock::Handle::stopAllocating` and
`LocalAllocator::stopAllocating` gain a `StopAllocatingMode` parameter.
- `JITThunks::ctiStub(CommonJITThunkID)` -> `ctiStub(VM&,
CommonJITThunkID)`; `polymorphicThunk()`,
`polymorphicThunkForClosure()`, `polymorphicTopTierThunk[ForClosure]()`,
`returnFromBaselineGenerator()` and the VM-independent IC handler
generators in `InlineCacheCompiler.h` no longer take `VM&`;
`JSC_FOR_EACH_COMMON_THUNK` is now the union of
`JSC_FOR_EACH_VM_INDEPENDENT_COMMON_THUNK` and
`JSC_FOR_EACH_VM_DEPENDENT_{EAGER,LAZY}_COMMON_THUNK`.
- `AssemblyHelpers::branchIfNumber/branchIfNotNumber(JSValueRegs, GPRReg
scratch, ...)` overloads removed (now `(JSValueRegs,
TagRegistersMode)`); `storeValue(JSValue, Address, JSValueRegs)` ->
`storeValue(JSValue, Address)`; `DataFormat.h`
`isJSFormat/isJSInt32/isJSDouble/isJSCell/isJSBoolean` removed;
`DFG::enableInt52()` removed.
- `USE(BUILTIN_FRAME_ADDRESS)` macro removed (`DECLARE_CALL_FRAME` is
unconditionally builtin-frame-address based);
`JSWebAssemblyInstance::temporaryCallFrame()/setTemporaryCallFrame()/offsetOfTemporaryCallFrame()`
removed; `ENABLE(YARR_JIT_*)` sub-flags listed above removed;
`Yarr::JITFailureReason::{DecodeSurrogatePair,BackReference,ParenthesizedSubpattern}`
removed; `WTF_CPU_ARM_VFP_V3_D32/V2` removed.
- New JSC option: `maximumInlineStringSwitchCaseCount` (default 64).
`--logGC` phase label "finalize" -> "epilogue".
- Bun impact: only the `HandleSet.h` removal required a source change
(`src/jsc/bindings/root.h`, already in this PR's diff); the other
renamed symbols are not referenced by Bun's C++ apart from stale
comments naming `finalizeUnconditionally` in
`src/jsc/bindings/ErrorStackTrace.cpp`,
`src/jsc/bindings/JSCTaskScheduler.cpp`, and
`src/jsc/bindings/FormatStackTraceForJS.cpp`.

### WebAssembly
- `2c2c1af35743` Overhauls ArrayBuffer/Wasm::Memory sizing for memory64:
`MAX_ARRAY_BUFFER_SIZE` goes from 4 GiB to 16 GiB on 64-bit (the fork
keeps 4 GiB under `BUN_JSC_ADDITIONS`, so not in Bun; Bun's
`Buffer.kMaxLength`/`MAX_LENGTH` derive from this macro in
`src/jsc/bindings/JSBuffer.h`, and `src/jsc/array_buffer.rs` `MAX_SIZE`
is a hard-coded `u32::MAX`), memory32 capped at 4 GiB and memory64 at 16
GiB, growing a shared memory64 past 4 GiB no longer crashes, and a
memory's buffer now advertises the maximum it can actually grow to; no
GC is triggered while holding the buffer-memory lock.
- `40d37f36527f` Follow-up: memory64 modules may declare arbitrarily
large page limits (parsing accepts them, as for table64); the 16 GiB cap
is enforced when the Memory is created or grown at runtime instead of
failing `WebAssembly.Module()`.
- `d6d09268899b` BBQ and OMG now always emit explicit bounds checks for
memory64 (and non-zero multi-memory) accesses via
`ModuleInformation::memoryModeForAccess()`; signaling-mode fast paths
are reserved for 32-bit memory 0 (previously a release-assert
crash/unsafe path once memory64 code tiered up).
- `72928a517633` Instances whose module declares no memory now still
reserve and zero the memory-0 cached base/size slot that every wasm
entry reads (previously it overlapped the import call-link area).
- `bfe5073f4c99` Fixes a crash when an imported memory is grown while a
multi-memory instance is only partially linked (e.g. after a LinkError
on a later import).
- `f771c5060cd7` `ref.func`, `table.get` and `array.init_elem` slow
paths now set up a FrameTracer since they can allocate wrapper functions
and GC (fixes crashes/ShadowChicken corruption).
- `0a704bb74f1e` IPInt->BBQ loop OSR entry now rejects a stack pointer
exactly at the soft stack limit (and underflow) instead of crashing
inside BBQ.
- `0c51f43daa3b` OMG recognizes naive byte-at-a-time copy/fill loops and
prepends a guarded `memory.copy`/`memory.fill` fast path; new option
`useWasmByteLoopReplacement` (default on).
- `ca730ef8b0fe` Wasm-to-JS import stubs convert an already-BigInt i64
return value inline instead of calling out to `operationConvertToI64`
(faster imports returning i64).
- `6589b2e5c18c` Tighter WasmGC struct/array allocation codegen
(constant cell size with variable allocator, DFG-like effect model so
allocations no longer clobber loads, constant-size array.new folded).
- `3eee8becf0b5` WasmGC struct layouts fill alignment gaps with smaller
fields (V8 heuristic), shrinking structs that interleave narrow and wide
fields; adds `$vm.wasmStructFieldOffsets`/`wasmStructPayloadSize`.
- `4687d7ecfefa` BBQ skips null checks for `ref.as_non_null`, `call_ref`
and `throw_ref` on non-nullable reference types, matching OMG.
- `74091f918bfc` New Air `Padding` pseudo-op that emits no code; OMG
stops running `reportUsedRegisters`, cutting OMG compile time without
the nop-related regression.
- `4af3bbad9cda` Faster JIT code emission loops in Air, BBQ and baseline
(skip disassembler-only labels, hoist loop invariants).
- `099f93fe4993` memory64/table64 JS API fixes: i64 address values are
round-tripped as BigInt in descriptors, imports and type reflection, and
a memory64's maximum bytes is clamped to what ArrayBuffer supports; adds
`addressValueFromUint64` helper.
- `b8af849be6f0` table64: `WebAssembly.Table.prototype.length` returns a
BigInt for i64 tables and `grow()` throws RangeError on an out-of-range
delta, per JS API spec.
- `b91045c99b1b` table64 maximum sizes are no longer silently truncated
to 32 bits (`Table::maximum()` is now 64-bit).
- `e942b93cdaa0` Active element segment offsets into a table64 are read
as i64 and no longer truncated to uint32.
- `02cdfb795a84` BBQ/OMG zero-extend i32 table indices when calling into
the uint64 table operations (table64 correctness).
- `aa8167a2feb9` Oversized table declarations are accepted at parse time
and rejected when the table is created/grown, so type reflection reports
the declared sizes and the failure happens at instantiation.
- `47f20d8cfd63` `call_indirect` in unreachable code now validates the
table element type and that the type index is a function type;
previously-accepted invalid modules now fail with CompileError.
- `2e8a96a8c585` memarg offsets are decoded as u64 for both memory32 and
memory64 (range-checked for memory32), and call/table immediates in
unreachable code are scanned correctly.
- `64153f963497` memory64 memarg immediates in unreachable code were
decoded differently from reachable code, producing spurious parse errors
on valid modules.
- `d319ee7c278e` A module declaring a memory64 together with any other
memory is now rejected regardless of declaration order (JSC supports
memory64 only as a single memory).
- `d02c68d04f96` `memory.size`/`memory.grow` in IPInt now record the
memidx immediate length, fixing non-minimal LEB encodings of the memory
index under multi-memory; drops the `parseMemoryIndexForBulkOp` hack.
- `102fd6db184d` OMG now passes the memory index when building
loads/stores, so accesses to non-zero memories are marked trapping
correctly under multi-memory.
- `de45b9be42db` `memory.init` overflow check uses 64-bit arithmetic
(memory64); dead `Wasm::Memory::fill/copy` removed.
- `b1b0566f244e` `table.copy` detects source/destination aliasing by
table identity rather than index, so the same table imported under two
indices copies with overlap semantics.
- `2194da86b382` Spec-aligned limits: tag/exception section limit raised
100,000 -> 1,000,000, tables may have exactly 10,000,000 entries (was
exclusive), `maxTableInitializationEntries` removed, exception-section
error message fixed.
- `9b3637884b68` `WebAssembly.Global.prototype.value` setter called with
no argument now treats it as `undefined` instead of throwing a
not-enough-arguments TypeError (WPT behavior).
- `707048fdabb7` `WebAssembly.Memory.prototype.type()` (type reflection,
behind `useWasmJSTypes`) reports the current size as `minimum`, not the
initially declared size.
- `0cc69e2993f4` / `57a1c44be6eb` BBQ pointer materialization takes a
uint64 offset (no truncation for >4 GiB memory64 addresses) and queries
address-form validity with the actual access width (folds more offsets
into addressing).
- `01a43483d35f` `WasmCalleeGroup` stops using
`ThreadSafeWeakOrStrongPtr`, which is removed from WTF
(`wtf/ThreadSafeWeakPtr.h`) as prep for making `ThreadSafeWeakPtr`
thread-safe.
- `a53d011599e7` / `5602ec36107b` Heap-wide renames reaching wasm:
`finalizeUnconditionally` -> `reconcileWeakReferencesAtGCEnd` (and
`Heap`/`IsoCellSet` accessors), `visitWeak` family ->
`reconcileWeakReferencesAtGCEnd`/`isStillLive`; no behavior change.
- `bf1dab73b14d` / `84f83abd45c9` / `6010a9ea6ce6` / `2a8926009f45`
Post-32-bit-JIT-removal cleanups touching BBQ/JSToWasm/WasmToJS: 32-bit
register pairs and scratch registers dropped, `ARMv7Assembler.h`
deleted, `USE(BUILTIN_FRAME_ADDRESS)` made unconditional; no behavior
change on x64/arm64.

### RegExp (Yarr)
- `yarr/` and `RegExp.cpp` stay at the fork's version
(oven-sh/WebKit#299 already contains the lookbehind JIT and most of the
fixes upstream landed in this range); see oven-sh/WebKit#455 for the
commit-by-commit status. Net new for Bun from this range: the `&&` /
`--` with `\P{..}` fix (`7b5e7da783f5`, ported), nothing else. Not yet
in the fork: the BMP code-unit read optimization (`bbc000ae4f3d`), the
default-off `\A` `\z` buffer boundaries (`2f66f5ed23f9`, `37f4628ab5fe`)
and the `ENABLE(YARR_JIT_*)` ifdef removal (`ac2afd10b8ac`; the fork
keeps those macros defined, so the mentions of their removal below do
not apply to this build).

### Inspector / debugger
- `1a7f711d887e` `Debugger::sourceParsed` for WebAssembly modules now
reports the module's `sourceMappingURL` custom section, so
`Debugger.scriptParsed` for wasm scripts carries a source map URL that
inspector frontends can use to map byte offsets to source.
- `49246d261276` Implements the import-text proposal (`import x from
"./f.txt" with { type: "text" }` and the dynamic-import form) behind new
`useImportText` (default on); in this area it only teaches
`InspectorDebuggerAgent` about the new `SourceProviderSourceType::Text`,
but the module-loader API changes (listed below) affect embedders with
custom loaders.
- `4ccb3f3a1c85` / `af624adbb3bc` / `de82d6282625` / `86575c4e1516` /
`87399235b55a` / `fcd024f84dbb` / `1240a421fe56` Protocol schema churn
in the WebCore-only Canvas and Recording domains plus a new generic
`Size` type in `GenericTypes.json`; these flow into
`CombinedDomains.json` (and therefore into regenerated
bun-inspector-protocol types) but change no JSC agent behavior.

### Build / scripts
- `81d660ceeb2e` wkbuiltins generator now precomputes builtin executable
metadata (`BuiltinSourceMetadata`) at build time instead of scanning
sources at VM startup; `BuiltinExecutables::createBuiltinExecutable`
gains a metadata parameter (the free `JSC::createBuiltinExecutable(VM&,
...)` that Bun uses is unchanged).
- `ff64aee116d4` `HandleSet`/`HandleBlock` replaced by
`StrongSet`/`StrongBlock` (Sources.txt/CMakeLists updated): `Strong<>`
slots are allocated from a libpas-style segregated freelist, cheaper and
smaller; `<JavaScriptCore/HandleSet.h>` no longer exists and
`Heap::handleSet()` is now `Heap::strongSet()`.
- `62692012c98a` `heap/HeapFinalizerCallback.{h,cpp}` renamed to
`GCCompletionCallback.{h,cpp}` with
`Heap::add/removeHeapFinalizerCallback` ->
`add/removeGCCompletionCallback`; the C API
`JSContextGroupAdd/RemoveHeapFinalizer` keeps its names.
- `3c64729cefbc` Fixes a clang 18 `-Wthread-safety-precise`/constexpr
build break in `WasmCalleeGroup.cpp`.
- `b9d3ef9f6a0f` Removes the dead `JettisonDueToProfiledWatchpoint`
value from the profiler's `JettisonReason` enum.

### Embedder-relevant API changes
- `MAX_ARRAY_BUFFER_SIZE` (runtime/PageCount.h) is now `1 << 34` on
64-bit (was `1 << 32`); `PageCount::maxPageCount` is public and
redefined; `Wasm::maxMemoryPages` renamed `maxMemory32Pages`,
`maxMemory64Pages` redefined, `maxTableInitializationEntries` removed;
new
`Wasm::maxDeclarablePages/maxBufferByteLength/maxAllocatableBytes(AddressType)`;
`Gigacage::primitiveAddressSpaceBudget` added in bmalloc.
- `ArrayBuffer::grow(const AbstractLocker&, VM&, ...)` replaced by
`ArrayBuffer::tryGrow(const AbstractLocker&, size_t, bool,
BufferMemoryResult::Kind&)`; `Wasm::Memory::fill()`/`copy()` removed
(use `Wasm::memoryFill/memoryCopy`); `Wasm::Table::maximum()` is now
64-bit.
- WTF: `ThreadSafeWeakOrStrongPtr` removed from
`wtf/ThreadSafeWeakPtr.h`; `USE(BUILTIN_FRAME_ADDRESS)` removed
(`DECLARE_CALL_FRAME`/`DECLARE_WASM_CALL_FRAME` always use the
frame-address form);
`ENABLE(YARR_JIT_ALL_PARENS_EXPRESSIONS|YARR_JIT_BACKREFERENCES|YARR_JIT_BACKREFERENCES_FOR_16BIT_EXPRS|YARR_JIT_UNICODE_EXPRESSIONS|YARR_JIT_REGEXP_TEST_INLINE)`
removed from PlatformEnable.h.
- Yarr:
`JITFailureReason::{DecodeSurrogatePair,BackReference,ParenthesizedSubpattern}`
removed; `Yarr::parse()` gained a defaulted trailing
`allowRegExpBufferBoundaries` parameter; new
`Options::useRegExpBufferBoundaries` (off by default).
- Module loading (from import-text): `SourceProviderSourceType::Text`
inserted before `ImportMap` (renumbers `ImportMap`; Bun's fork also
appends `BunTranspiledModule`), `ScriptFetchParameters::Type::Text`
inserted before `HostDefined` (HostDefined becomes 5, matching the
updated static_asserts in
`src/jsc/bindings/BunAnalyzeTranspiledModule.cpp`),
`SyntheticModuleRecord::create()` and the `AbstractModuleRecord`
constructor now take a `SourceProviderSourceType` (already adapted in
`src/jsc/bindings/NodeVMSyntheticModule.cpp`), new
`SyntheticModuleRecord::createTextModule()`, new
`Options::useImportText` (on by default).
- Heap renames: `T::finalizeUnconditionally()` ->
`reconcileWeakReferencesAtGCEnd()`,
`Heap::finalizeUnconditionalFinalizers()` ->
`reconcileWeakReferencesAtGCEnd()`, `Heap::...::finalizerSetFor()` ->
`weakReconciliationSetFor()`, `CallLinkInfo::visitWeak` and friends ->
`reconcileWeakReferencesAtGCEnd`; `HeapFinalizerCallback` ->
`GCCompletionCallback` (header renamed);
`HandleSet.h`/`HandleBlock.h`/`HandleBlockInlines.h` removed in favor of
`StrongSet.h`/`StrongBlock.h`, `Heap::handleSet()` -> `strongSet()`
(Bun's `src/jsc/bindings/root.h` include already switched).
- `BuiltinExecutables::createBuiltinExecutable()`/`createExecutable()`
gained `const BuiltinSourceMetadata&` overloads (member function
signature changed; free function unchanged);
`JettisonReason::JettisonDueToProfiledWatchpoint` removed;
`assembler/ARMv7Assembler.h` deleted;
`Wasm::ModuleInformation::memoryModeForAccess()` added.

### WTF

- `f6bc402b8344` `StackBounds::currentThreadStackBounds()` is now
private (only `Thread`/`StackStats` may call it; other code is meant to
read the cached `Thread::currentSingleton().stack()`) because on Linux
it can re-parse `/proc/self/maps` on every call. Bun's
`Bun__StackCheck__initialize` called it once per thread, including on
non-WTF threads, and now uses the
`currentThreadStackBoundsForEmbedder()` accessor the fork adds under
`USE(BUN_JSC_ADDITIONS)`. `36403ca62849` re-adds `WTF_EXPORT_PRIVATE` on
`currentThreadStackBoundsInternal()`.
- `5fc5182bcf83` `WTF::numberOfProcessorCores()` now honors a
`NUMBER_OF_PROCESSORS` env var (after the existing
`WTF_numberOfProcessorCores`) before asking the OS. Bun reports this
value as `navigator.hardwareConcurrency` / `os.availableParallelism()`
and it would take precedence over the fork's affinity/cgroup aware
count, so the fork keeps this lookup out of Bun builds
(oven-sh/WebKit#455, 8fc20b18b9); no change for Bun.
- `957b52180bee` `MemoryPressureHandler` no longer inherits
`CanMakeWeakPtr` (timers bind to the singleton via lambdas); fixes a
debug-build WeakPtr thread assertion when the singleton is first touched
off the main thread (JSC's `FullGCActivityCallback` does this, e.g. from
a Worker), and `s_hasCreatedMemoryPressureHandler` is now only set once
the singleton really exists.
- `4a10860dc35c` `WTF::Liveness` iterates less (no separate boundary
pass, no zeroing of the gen store) and gains
`forEachLiveAtHeadNotLiveAtTail` / `forEachLiveAtTailNotLiveAtHead`;
used by the Air greedy register allocator (~17% faster
`buildLiveRanges`), i.e. lower DFG/FTL/OMG compile latency.
- `01a43483d35f` `ThreadSafeWeakOrStrongPtr` removed from
`wtf/ThreadSafeWeakPtr.h` (its only user, `Wasm::CalleeGroup`, was
rewritten); groundwork for shrinking `ThreadSafeWeakPtr` to one pointer
and making it atomic.
- `ac2afd10b8ac` Removes the `ENABLE_YARR_JIT_*` sub-feature macros
upstream (unconditional on x64/arm64). The fork keeps them defined
because its YarrJIT still tests them; no behavior change either way.
- `6010a9ea6ce6` ARMv7 JIT removal follow-ups: drops
`CPU(ARM_VFP_V2)`/`CPU(ARM_VFP_V3_D32)`, simplifies
`ASSERT_VALID_CODE_POINTER`, `ENABLE(JUMP_ISLANDS)` is now arm64-only
and `LLINT_EMBEDDED_OPCODE_ID` drops Thumb2; no effect on x64/arm64
builds.
- `2a8926009f45` `USE(BUILTIN_FRAME_ADDRESS)` macro removed; JSC now
unconditionally uses `__builtin_frame_address` on JIT platforms. The
fork had it disabled on Windows ARM64 only; that fallback is gone with
this merge (see the Windows ARM64 note above).
- `ef6d9ba26b17` removed Linux real-time threads in favor of nice/RTKit
priorities, `44bab332e0f1` fixed its JSCOnly build, and `56baf6e01b3d`
reverted the whole thing for ~2% JetStream3/Speedometer3 regressions:
net zero change to `Threading.h`/`AutomaticThread`/`RealTimeThreads.cpp`
in this range.
- `1240a421fe56` Additive
`JSON::Array::set{Boolean,Integer,Double,String,Value,Object,Array}(index,
…)` and `JSON::ArrayOf<T>::setItem(index, …)` (in-place replacement;
`RELEASE_ASSERT`s index in range) in `wtf/JSONValues.h`, which Bun's
inspector/profiler bindings include.
- `5720766c8056` Reverts the IPC URL-size limit, removing the
`WTF::maxURLLength` constant from `wtf/URL.h`; no URL parsing behavior
change.
- `3089b5074c3d` Deletes the empty `wtf/text/WYHash.h`; any `#include`
of it now fails (Bun has none).
- `e9a62e6b4da5` `85e82ceefe1b` `793e36fb835e` `934bb002485a`
`2f66f5ed23f9` `49246d261276` `99473681ff5e` only touch
`Scripts/Preferences/UnifiedWebPreferences.yaml` on the WTF side,
mirroring JSC option changes (iterator join / import defer / iterator
chunking / joint iteration flipped to default-on, new RegExp
buffer-boundaries and import-text prefs, `IntlEraMonthcodeEnabled` pref
removed since the feature is now unconditional); the actual behavior
lives in the JavaScriptCore commits. All other yaml-only commits in this
range are WebCore/WebKit feature flags and irrelevant to Bun.

**Embedder-relevant API changes**
- `StackBounds::currentThreadStackBounds()` is private (`friend class
Thread`); replacement is `Thread::currentSingleton().stack()`
(`f6bc402b8344`).
- `WTF::ThreadSafeWeakOrStrongPtr` removed (`01a43483d35f`).
- Header `wtf/text/WYHash.h` removed (`3089b5074c3d`); header
`wtf/Nonallocatable.h` added and `RefCountedWithInlineWeakPtrBase`
removed / `RefCountedWithInlineWeakPtr<T>` made non-`new`-able
(`f880bc57ad50`).
- `using WTF::Task` removed from `wtf/CoroutineUtilities.h`
(`9f82586af24c`); `WTF::maxURLLength` removed from `wtf/URL.h`
(`5720766c8056`).
- `MemoryPressureHandler` no longer derives from `CanMakeWeakPtr` and
lost its no-op `ref()`/`deref()` (`957b52180bee`).
- Config macros removed: `USE(BUILTIN_FRAME_ADDRESS)`,
`ENABLE(YARR_JIT_ALL_PARENS_EXPRESSIONS)`,
`ENABLE(YARR_JIT_REGEXP_TEST_INLINE)`,
`ENABLE(YARR_JIT_BACKREFERENCES)`,
`ENABLE(YARR_JIT_BACKREFERENCES_FOR_16BIT_EXPRS)`,
`ENABLE(YARR_JIT_UNICODE_EXPRESSIONS)`, `CPU(ARM_VFP_V2)`,
`CPU(ARM_VFP_V3_D32)`; `ENABLE(JUMP_ISLANDS)` now arm64-only; new
`ENABLE(JIT_CAGE_RELAXATION)`.
- Additive only: `JSON::Array::set*`/`ArrayOf<T>::setItem`,
`Liveness::forEachLiveAt{Head,Tail}NotLiveAt{Tail,Head}`,
`WTF::isInBaseSystem()` (Cocoa port only, not compiled in JSCOnly/Bun),
`numberOfProcessorCores()` reading `NUMBER_OF_PROCESSORS`.

### bmalloc

- `2c2c1af35743` Adds `Gigacage::primitiveAddressSpaceBudget` (a
`constexpr uint64_t`, 64 GB on 64-bit desktop/server targets, 16 GB on
iOS/32-bit) to `Gigacage.h`, defined *outside* `#if GIGACAGE_ENABLED` so
it exists even when the Gigacage is compiled out;
`primitiveGigacageSize` is now derived from it (same value as before, so
no cage-size change). This is the bmalloc half of the ArrayBuffer/Wasm
memory64 sizing overhaul: JSC's `BufferMemoryHandle.h` uses it to cap
the virtual reservation of any one resizable `ArrayBuffer` / growable
`SharedArrayBuffer` / `WebAssembly.Memory` at budget/4 (16 GB on Bun's
platforms), which is what lets those buffers reach the new 16 GB
`MAX_ARRAY_BUFFER_SIZE` (previously 4 GB) and lets memory64 grow past 4
GB without crashing. (The fork pins `MAX_ARRAY_BUFFER_SIZE` at 4 GB, so
in Bun only the crash fix applies.)

Embedder-relevant API changes (bmalloc):
- Added: `Gigacage::primitiveAddressSpaceBudget` (`constexpr uint64_t`)
in `Source/bmalloc/bmalloc/Gigacage.h`; `primitiveGigacageSize`
unchanged in type and value. No removals or renames. Bun's own C++
(`src/jsc/bindings`) references no Gigacage symbols, so nothing on the
Bun side needs updating for this area.

</details>

<!-- robobun:evidence:begin -->

---

**[decide:webkit]** gate passed · iteration 0 · 8 files touched

<!-- robobun:evidence:end -->

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
dylan-conway added a commit that referenced this pull request Sep 13, 2026
…eature

Upstream's \A \z \Z (2f66f5e, behind --useRegExpBufferBoundaries) changed
nine files under yarr/. The sync that contained it (#455) came five days after
this fork's YARR was rewritten (#299) and kept the fork's side of every YARR
conflict, so the tests arrived and the feature did not. The four tests are
skipped, with a TODO naming what to port.
dylan-conway added a commit that referenced this pull request Sep 14, 2026
…Core tests (#645)

* CI: run the JavaScriptCore tests against the Linux asan builds

Nothing in CI ran a test. Add a `test` job that downloads the jsc shell shipped
by the bun-webkit-linux-{amd64,arm64}-asan lanes and runs
run-javascriptcore-tests (JSTests, LayoutTests/js, PerformanceTests) and testFFI
with it. The job does not gate the release and is continue-on-error until the
known failures on this fork are worked through.

* CI: fail the run when JavaScriptCore tests fail

Drop continue-on-error from the test job so a test failure turns the run red.
The release still does not wait for the tests. The preview-build comment is now
posted whenever the release was published rather than only when the whole build
workflow succeeded, so it keeps appearing while tests are failing.

* CI: generate the build lanes from one table in a plan job

The 42 lanes were spread over seven near-identical jobs plus a hand-kept list
of expected assets in the release job. They are now defined once, in
.github/scripts/plan.mjs; a `plan` job turns that table into the build, test
and expected-asset matrices. Every lane gets the same runner, release script
and settings as before.

The lanes that are tested build in their own job (same steps, via an anchor) so
that the tests start when those lanes are done instead of waiting for all 42.

Also drops the unused llvm_version input, and only triggers CI on pushes to
main rather than starting a skipped run for every branch.

* CI: one workflow instead of build.yml, build-preview.yml and build-reusable.yml

build.yml (pushes to main) and build-preview.yml (pull requests) were thin
wrappers that called build-reusable.yml with a different commit, release tag
and prerelease flag. They are now one workflow, ci.yml, with all three triggers:
the plan job works out what is being built, and the pull request comment is a
final job that only runs for pull requests.

Tags, the write-access check for pull requests, manual dispatch with pr_number
and the per-pull-request concurrency group are unchanged.

* CI: main and pull requests share everything but the release name

What differs between a build of main and a build of a pull request is now nine
lines: the commit (env.REF), the release tag, the prerelease flag, the
concurrency group and a one-line `gh pr comment` after publishing. The separate
target-resolution step and the 60-line comment job are gone.

Dropped: the explicit write-access check (a fork's token is read-only, so such a
build already fails when it creates the release) and manual dispatch by
pr_number. Manual dispatch now builds the head of the branch it is run on.

* Cross-compile bun-webkit-windows-arm64-debug on Linux like every other lane

It was the one lane that still built on a Windows runner, because /MTd needs the
static debug CRT (libcmtd.lib, libcpmtd.lib, libvcruntimed.lib) and an xwin
splat has none for ARM64. The libs exist: for x64 they are in the same Visual
Studio package as the release CRT, for ARM64 Microsoft ships them in a separate
package, CRT.ARM64.Desktop.debug.base, that xwin does not select.
Dockerfile.windows now fetches that package (pinned by sha256) and unpacks its
libs next to the others.

The lane takes the same settings as bun-webkit-windows-amd64-debug with
WIN_ARCH=arm64. With it gone, the LLVM install and PowerShell steps are gone
from the workflow: every lane is checkout, buildx, build, upload.

* CI: build each toolchain once and keep it as an image, instead of once per lane

Every one of the 42 lanes rebuilt its toolchain from scratch on every run: apt,
the LLVM and GCC debs, the xwin download, the macOS SDK, the NDK. The Dockerfiles'
`base` stages are now pure toolchain stages (no lane settings; the glibc and musl
Dockerfiles get a `lane` stage on top for those), and CI keeps them as images in
ghcr.io/oven-sh/bun-webkit-build-env, tagged with a hash of what goes into them.

A new `image` job, one leg per distinct toolchain (10), builds and pushes an
image only when its tag is missing, i.e. after a change to a `base` stage. Lanes
start from their image (--build-context base=docker-image://...). If an image
is not there a lane builds the toolchain itself, which is also what running a
release script by hand still does. The ICU and WebKit stages are unchanged.

Modelled on the bun-toolchain workflow in oven-sh/rust.

* CI: a toolchain image that cannot be built or pushed fails the run

The image job warned and carried on when a push failed, and lanes fell back to
building the toolchain themselves when their image was missing, so a broken
registry setup would only show up as every lane being slow. Now the image leg
fails, no lane starts, and a lane always builds from its image.

* One tool builds a lane; the six *-release.sh scripts are gone

release.sh, musl-release.sh, macos-cross-release.sh, windows-cross-release.sh,
freebsd-release.sh and android-release.sh were six copies of the same wrapper
around `docker buildx build`, each also deriving a few settings that were
visible nowhere else (MARCH_FLAG per architecture, WIN_TRIPLE_ARCH,
ICU_MARCH_FLAG, ENABLE_MALLOC_HEAP_BREAKDOWN=ON for macOS Debug,
FREEBSD_VERSION, ANDROID_API). What a lane was built with was spread over the
plan, a script and the Dockerfile's defaults.

.github/scripts/lanes.mjs (was plan.mjs) now holds every build argument of
every lane and is the only way one is built:

  lanes.mjs build <label> --output <dir> [--base-image <ref>]
  lanes.mjs image <name> --push

CI runs exactly that, so a lane can be reproduced by running the same command.
For all 42 lanes the docker command is the same as the one the scripts on main
produce: same Dockerfile, platform and build arguments.

* CI: a failure in one test does not keep the others from running

- A tested lane that fails to build no longer skips the tests of the ones that
  did build: `test` runs whenever `build-tested` ran, and the leg of the lane
  that did not build fails at its download.
- testFFI and run-javascriptcore-tests each run whatever the other did; either
  failing fails the job. Before, a testFFI failure skipped the JavaScriptCore
  tests, leaving no results or log.

Also says what `native` means in lanes.mjs.

* CI: check out the web-platform-tests the wasm collection reads

JSTests/wasm.yaml runs LayoutTests/imported/w3c/web-platform-tests/wasm/{core/js,jsapi}
with the harness in web-platform-tests/resources; the test job's sparse checkout
left them out and run-jsc-stress-tests died in `realpath` before running a test.

The log filter that drops "Skipping <test>" lines also dropped that error,
which was printed onto the end of one: it now only drops lines that are nothing
but a skip.

* Cross-compile the Linux arm64 lanes from x86_64, like every other target

The glibc and musl Dockerfiles built for whatever architecture the container
was, so the arm64 lanes needed arm64 runners and their own toolchain images.
They now build in the same linux/amd64 container as the x86_64 lanes, with
clang --target and a sysroot:

- glibc: an ubuntu 20.04 arm64 sysroot (the arm64 ubuntu:20.04 image, focal's
  libc6/libc6-dev unpacked over it, and the arm64 half of the gcc-13 mirror),
  plus the aarch64 sanitizer runtimes from the arm64 half of the LLVM mirror.
- musl: an alpine aarch64 sysroot populated by apk from the same repository.
- ICU is a two-stage cross build for aarch64 (the container's own ICU tools live
  in the toolchain image), as in the FreeBSD and Android Dockerfiles.

The x86_64 lanes run the same commands as before. The libc versions do not
change, and that is now checked: the image build fails unless the sysroot's
glibc is 2.31 like the container's (for musl: the same package version as the
container's), and every glibc jsc that is linked must not need a symbol
version newer than GLIBC_2.31.

Every lane now builds on linux-x64-gh; arm64 runners only run tests. 8 toolchain
images instead of 10. The musl stages no longer install packages or build zstd
per lane: that moved into the toolchain image.

* CI: no image job unless a toolchain image is actually missing

Every run queued one `image` leg per toolchain on the large runners only to find
the image already there. `plan` (a standard runner, and it already knows the
tags) now asks the registry itself and hands `image` only the missing ones;
when there are none, `image` is skipped and the lanes start right after `plan`.

The legs that do run, after a change to a Dockerfile's `base` stage, use a
standard runner too: every image is linux/amd64 and building one is mostly
downloading and unpacking. They free the usual disk space first.

The registry token is passed to `docker login` through the environment rather
than written into the script.

* Nothing is downloaded or installed while a lane builds

The toolchain images took the package installs, SDKs and sysroots out of the
lanes, but every lane still fetched a few things and redid some lane-independent
work: ICU's source tarball (all but macOS), its host tools (Windows, FreeBSD,
Android), zstd, node and `patch` (Windows), and bootstrap_cmds to build `mig`
(macOS). Those are now in each Dockerfile's `base` stage, so in the image. The
stages on top only apply the lane's settings.

On Windows the host ICU tools are therefore built from the sources before the
udata.cpp hook patch is applied rather than after; the hook is null in ICU's
own tools either way.

The macOS image now depends on all of macos-cross/, not just xmac.mjs.

* CI: old toolchain images are deleted, after a grace period

Each image leg used to delete the older versions of its own image as soon as it
pushed a new one, on main only. That missed images nothing uses any more (a
renamed toolchain, a pull request that never landed) and had no notion of age.

A build of main now runs `prune`: every version of the package that main's
lanes do not use and that was pushed more than 14 days ago is deleted, untagged
leftovers included. An image a pull request pushed recently stays, so a
toolchain change can be iterated on before it is merged; if an image a branch
still wants has gone, `plan` finds it missing on that branch's next run and
`image` rebuilds it.

* CI: no builds for fork pull requests; image tags cover their build arguments

- A pull request from a fork gets a read-only token, so it could never publish,
  but nothing stopped its 42 lanes from occupying the large runners for an hour
  before failing at the upload (the old workflow refused such runs up front).
  `plan` is now skipped for them, and everything else needs `plan`.
- A toolchain image's tag hashed its Dockerfile's `base` stage and the files it
  copies, but not the build arguments that stage takes from lanes.mjs
  (FREEBSD_VERSION, MACOS_DEPLOYMENT_TARGET, ANDROID_API, ...): bumping one left
  the tag unchanged and the lanes on the old toolchain. The ARGs a `base` stage
  declares that a lane sets are now part of the hash.
- Dockerfile.macos: a comment still named the deleted build-reusable.yml.

* CI: plan creates the draft release; fix the linux and linux-musl image builds

- Creating the draft release was a job of its own next to `plan`. It is now the
  last step of `plan`, which already names the release. Every lane needs `plan`,
  so the draft exists before any lane starts, and the loop in which each lane
  waited up to ten minutes for it to appear is gone.
- linux image: there are no *.list files in /etc/apt/sources.list.d in this
  container, so the glob handed to sed stayed literal and sed failed.
- linux-musl image: /usr/share/apk/keys/aarch64/* are symlinks to ../<key>.pub,
  and cp -r copied them as dangling links, so apk trusted no key for the
  aarch64 index and found no packages. They are dereferenced now.

* Fixes from a review of the CI rework

Builds:
- aarch64 glibc sysroot: libc6-dev's libm.so, libpthread.so, libdl.so, ... are
  absolute symlinks into /lib/aarch64-linux-gnu, which dangle when the package
  is unpacked into a sysroot, so the linker quietly took the static archives.
  They are re-pointed into the sysroot, their presence is checked, and every
  glibc jsc must list libm.so.6 as NEEDED.
- The glibc and musl version guards did nothing: under `set -e` a failing test
  that is not last in an `&&` list does not abort. They are separate statements.
- The aarch64 sanitizer runtimes must be the version of the clang installed.

Workflow:
- prune: only on the first attempt of a push to main (a re-run of an old run
  knew an old set of images), and the two newest versions of each toolchain
  main has always stay, so the image main used until a moment ago is not pulled
  from under runs still in flight.
- plan: a branch that predates lanes.mjs gets told so; a registry that cannot
  be asked is an error, not eight missing images; two images may not share a
  name; at least one lane must be tested and one not (no empty matrices).
- test takes the jsc shell from an artifact of build-tested instead of the draft
  release, which `release` deletes the moment any lane fails.
- A lane checks that there is a release to upload to before it builds, not
  after.
- The image tag no longer changes with comments, lane-only ARG defaults or
  macos-cross/README.md.
- Build and test checkouts skip about 2 GB nothing reads; dead outputs, ids and
  an API call left over from the reusable workflow are gone.

* linux image: link ICU's host tools against the ICU being built

The `base` stage's LDFLAGS carry -L/usr/lib/x86_64-linux-gnu, where the
distribution's ICU 66 lives (libxml2-dev brings libicu-dev), and that came ahead
of the freshly built libicuuc.a: makeconv failed to link with undefined
uprv_stricmp_78 and friends. The lanes' ICU step already replaces LDFLAGS for
the same reason; the host tools step does now too.

* Call the glibc toolchain image linux-glibc

`linux` sat next to `linux-musl` and `android`, which are Linux too; the job was
called "image linux" though only the ten glibc lanes use it.

* Dockerfiles: remove what is dead now that every container is linux/amd64

Dockerfile: TARGETARCH is always amd64, so the gcc-13 and LLVM bundles and their
checksums are named directly, the library-path step is unconditional, and its
`uname -m` twin (which did the same thing a second time) is gone. The LLVM
symlink step ran twice, before and after the last apt-get install; the second
run, whose result is the one that stands, stays.

Dockerfile and Dockerfile.musl: CPU was an ARG and an ENV that no lane passes
and nothing reads. musl never used LLVM_VERSION (clang-21 is spelled out).

Dockerfile.freebsd, .android, .windows: the ICU_* ARGs in build_icu were only
for the ADD that moved to `base`.

Dockerfile.macos: two comments still spoke of native macOS lanes.

No build argument, environment variable that is read, or command that affects
an artifact changes.

* Remove build.ts, mac-release.bash and windows-release.ps1

Nothing runs them. CI builds every lane, macOS and Windows included, through
lanes.mjs and the Dockerfiles; Bun builds WebKit from source with its own
scripts/build.ts. Each of the three carried its own copy of the compiler flags
and cmake options, already out of step with what ships (build.ts still looked
for ICU under vcpkg_installed/), and a stale script that looks authoritative is
how a wrong flag gets copied somewhere it matters.

build-icu.ps1 stays: Bun runs it when it builds WebKit from source on Windows.
It now says so.

* One place says which ICU is built, and clang builds it everywhere

The ICU version, tarball URL and checksum were written out in five Dockerfiles
and build-icu.ps1, in three spellings, and the major version was hard-coded in
file names (icudt78l.dat, sicudt78.lib) in every build step: an ICU bump was a
six-file edit and missing one shipped a lane on a different ICU. icu/source.json
now holds the version and sha256. lanes.mjs passes them to the Dockerfiles as
build arguments (so the toolchain images re-tag with them), build-icu.ps1 reads
the same file, and the major version is derived from it.

build-icu.ps1, which Bun runs to build WebKit from source on Windows, compiled
ICU with clang (the ClangCL toolset) on x64 only and with MSVC on ARM64. It is
clang on both now, with the same code generation floor as the lanes that ship,
and it verifies the checksum of the tarball it downloads. Its header says what
it is, why it exists next to Dockerfile.windows (ICU's configure/make does not
run on Windows, its MSBuild projects do not run on Linux), and the two ways its
output still differs from the ICU that ships.

* Linux arm64: cmake takes programs from the container, not the sysroot

With CMAKE_SYSROOT set, find_program looks in the sysroot first, and the ubuntu
arm64 rootfs the glibc sysroot is built on has /usr/bin/perl: cmake chose it,
could not run it (it is an aarch64 binary), and failed with "Could NOT find
PerlModules". CMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER, the usual setting for a
cross build, for both the glibc and the musl Dockerfile.

* Test the Linux release lanes too

The asan lanes are where every test can pass (assertions, $vm, the
disassembler); the release lanes are what ships. bun-webkit-linux-amd64 and
-arm64 are tested as well now. The tests that need $vm or the disassembler fail
there, since a release build compiles those out.

* Test the macOS arm64 and Windows x64/arm64 lanes too

Which lanes are tested, and on what, is per platform and architecture in
lanes.mjs now: Linux as before, macOS arm64 on macos-15, Windows x64 on
windows-2025 and Windows arm64 on windows-11-arm. asan and release where there
is an asan lane, release on Windows arm64. Those are GitHub's standard runners
with 3 or 4 cores, so the tests run with --quick there.

The test job is the same steps on all three systems, in bash. On Windows the
runner is driven the way upstream's Windows bots drive it: Windows' own perl,
test scripts written as ruby, the ruby runner instead of make.

A macOS asan jsc names its sanitizer runtime as
@rpath/libclang_rt.asan_osx_dynamic.dylib, with the build container's clang
resource directory as the only rpath, so it could not start on a Mac. The dylib
ships in bin/ next to it now (as the Windows asan lane already does with its
DLL), and @executable_path is an rpath of the sanitizer builds' executables.

* Failing tests do not fail the run, for now

The testFFI and run-javascriptcore-tests steps are continue-on-error: their
failures show as a warning on the run, in the job summary and in the uploaded
log and results, and the job stays green. Not getting as far as running the
tests (no checkout, no jsc shell) still fails it. The release never depended on
the tests and still does not.

* Revert "Failing tests do not fail the run, for now"

This reverts commit f2a570528a1dab3dbc1075d898ec7aff47ce18b9.

* run-javascriptcore-tests: take --jsc-only on macOS and Windows too

The script looked up the port before parsing its options only on Linux, which
is what removes --jsc-only from the arguments; elsewhere the option parser got
it and stopped with "Unrecognized option `--jsc-only'". The macOS and Windows
test jobs need the JSCOnly port: that is the one whose jsc is <root>/bin/jsc.

* Review fixes: test job token, summary on an empty result, arch assert, ICU cache

- The test job runs the branch's code with a read-only token.
- The summary step copes with a results file that has no stressTestFailures.
- The Linux lanes assert that the jsc they linked is for LINUX_ARCH, instead of
  only printing what it is for: an arm64 lane that lost its --target would
  otherwise ship an x86_64 build.
- build-icu.ps1 records which ICU version its source directory was extracted
  from and starts over when that is not the pinned one, names the tarball after
  the version, and checks the checksum of a tarball that was already there too.
- CLAUDE.md: `lanes.mjs build` without --base-image builds the toolchain too;
  pull requests from forks are not built.

* JSCOnly on macOS: one listenForTimeZoneChangeNotifications() in libWTF.a

With USE_BUN_JSC_ADDITIONS, TimeZone.cpp compiles its no-op
listenForTimeZoneChangeNotifications() on every platform (Bun bumps the time
zone ID itself through timeZoneDidChange()), and on macOS PlatformJSCOnly.cmake
also compiled cocoa/TimeZoneCocoa.cpp, which defines the same function. libWTF.a
held two strong definitions and a consumer's link took whichever member came
first.

67898ceb4669 had dropped the Cocoa file from JSCOnly for this reason; an
upstream merge brought the line back in a new shape. It is now skipped when
USE_BUN_JSC_ADDITIONS is on, keeping upstream's statement otherwise.

Found by the duplicate-definition scan of bun's link inputs.

* Test job: a log that can be read

The JavaScriptCore tests print a line per test run and everything each test
prints: 160,000 lines on Linux, which the Actions log viewer truncates. The
step now shows each FAIL as it happens, a progress line every 5000 runs and the
runner's own messages and results, about 1,600 lines. The full output is still
jsc-tests.log in the artifact, next to a new jsc-failures.log: what each failing
run printed (exception, stack, exit code, repro command) grouped under its name.

* Test job log: show what is known to be useful, not everything but the noise

The tests run in parallel into one pipe, so what they print arrives cut up
mid-line ("stress/regre    "columnNumber":283,"), and a filter that drops lines
which look like a test's output lets the pieces through. The step now prints
what the runner says before the first test, each FAIL, a progress line, and the
runner's results from where they begin, and nothing else. If the runner ends
without printing results, the last 40 lines of its output are shown, so that an
error of the runner itself is never hidden.

* Test job: write jsc-failures.log when tests fail

The step's shell is started with -e, and `set -uo pipefail` does not turn that
off, so when a test failed the script ended at the test pipeline: the exit
status line and jsc-failures.log, which is only of use then, never happened.
The step now runs without -e and passes the status on at its end.

* Test the lto lanes instead of the release lanes

Bun's release builds link the -lto tarballs wherever there is one, so those are
the builds to run the tests on: linux amd64/arm64, macOS arm64 and Windows x64
test their lto lane next to their asan lane. Windows arm64 has no lto lane and
ships its release build, which stays the one tested there.

* JSTests: expect this fork's ReferenceError text

An unresolvable reference is "ReferenceError: x is not defined" here, as in V8
and Node, where upstream says "ReferenceError: Can't find variable: x". These
14 tests compared against upstream's text and nothing else about them differs;
they now compare against ours.

* JSTests: superclass-expression-strictness expects this fork's ReferenceError text

Same difference as the previous commit, in a test that compares error.message
rather than the whole string.

* Test baselines: this fork's ReferenceError text

The ChakraCore and LayoutTests/js tests that print an error's message are
checked by diffing their output against a baseline file, and those baselines
have upstream's "Can't find variable: x". 30 of them now have "x is not
defined", which is what this fork prints. Nothing else in them changes, so a
line that still differs in CI differs for another reason.

* JSTests: module error messages of this fork; a test that tripped over itself

The module tests compared against upstream's link errors ("Importing binding
name 'B' is not found.", "Indirectly exported binding name ..."). With
USE(BUN_JSC_ADDITIONS) CyclicModuleRecord.cpp words them differently
("Export named 'B' not found in module '<url>'.", "export 'B' not found in
'./x.js'", "Cannot export 'B' multiple times in ...", "export default cannot be
used with export *", "Missing 'default' export in module ..."). The six tests
now expect those; where the message carries the module's URL the directory is
taken off before comparing.

function-toString-native-one-line.js: its walker over everything reachable from
globalThis was a top-level function declaration, so a property of globalThis
itself, and its source contains the "[native code]" it searches for: it
reported itself. It is a const now.

* jsc: $vm on global objects made by $vm.createGlobalObject() in release builds

Release builds leave $vm out of the library (#329), so JSGlobalObject::init()
does not install it, and jsc installs it on its own global object. A global
object made by $vm.createGlobalObject() got none, and
stress/temporal-now-overridden-date-now.js, which uses other.$vm, failed on the
release and lto lanes. The copy of JSDollarVM.cpp compiled into jsc installs it
on the global objects it creates.

lanes.mjs and CLAUDE.md said tests that use $vm fail on release builds. They do
not: jsc has $vm in every configuration.

* JSTests: compare the module errors' exact text

different-view.js, import-error.js and re-execute-error-module.js took the
directory off the module URL in the message before comparing. They now build
the URL from their own location (import.meta.url; callerSourceOrigin() in the
script) and compare the whole message.

* JSTests: build the expected module URLs without a regular expression

* JSTests: import-error.js without a helper function

* JSTests: the expected module URLs written inline

* JSTests: one call to build each expected module URL

* JSTests: intl-datetimeformat-default-timezone-change checks each zone in its own task

$vm.setHostTimeZone() bumps the time-zone generation; the VM drops its date and
Intl caches when it is next entered (executeEntryScopeServicesOnEntry). The
test read the zone back in the same task as the change and saw the old one. It
now checks after a setTimeout, as the other setHostTimeZone tests do.

* JSTests: the ffi tests run without the executable allocation fuzzer

The ftl-eager-no-cjit mode passes --useExecutableAllocationFuzz=true
--fireExecutableAllocationFuzzRandomly=true, which fails executable allocations
at random. bun:ffi's call thunk, IC stub and callback thunk are allocated with
JITCompilationCanFail and throw RangeError: Out of memory when that happens;
unlike a JIT tier there is nothing to fall back to, so the tests failed on the
exception. They opt out of the fuzzer the way wasm-loop-consistency.js does.

* JSTests: out-of-memory-while-creating-undefined-variable-error expects this fork's fallback text

When the ReferenceError message cannot be allocated the fork falls back to
"Variable is not defined" (ExceptionHelpers.cpp), upstream to "Can't find
variable".

* Test job: the asan lanes skip the tests marked slow!

Four wasm tests marked //@ slow! pass their 300 second hard timeout under ASan
in the wasm-collect-continuously mode. run-jsc-stress-tests has --no-slow, which
skips every test so marked; run-javascriptcore-tests gets a --no-slow option
that passes it on, and ci.yml gives it to the lanes whose label ends in -asan.
The lto lanes still run those tests.

* CLAUDE.md: the asan test lanes pass --no-slow

* Test job: --no-slow only where --quick is not passed

run-jsc-stress-tests keeps --quick and --no-slow in the same $mode and the later
one wins, so on the macOS and Windows asan legs, which are --quick, adding
--no-slow ran every mode. --quick already skips the tests marked slow!.

* CLAUDE.md: the local repro command passes --no-slow like the asan lanes

* JSTests: regress-151324.js expects this fork's ReferenceError text

* The asan lanes are built with USE_SYSTEM_MALLOC

The asan and debug-asan lanes were built with bmalloc/libpas. Under ASan
bmalloc hands every allocation to the system allocator at run time, so the only
part of libpas those lanes ran was its JIT heap, which no shipped build has:
release and lto are built with mimalloc, which leaves libpas out. With
USE_SYSTEM_MALLOC=ON allocation is unchanged (ASan's malloc), libpas is not
compiled, and the JIT pool is the allocator the shipped builds use, so the asan
test lanes exercise that one.

This also takes away the linux-arm64-asan failures in the
ftl-no-cjit-small-pool mode: with a JIT pool under 256 MB every allocation goes
to libpas's bitfit pages, and on Linux arm64, where the JIT small page is
64 KB, that page's 4128 byte header does not fit the utility heap's 1400 byte
limit.

lanes.mjs sets the argument per variant; the Dockerfiles pass it to CMake. The
toolchain images are unchanged.

* The Windows asan lane keeps bmalloc/libpas

bmalloc has an #error for USE_SYSTEM_MALLOC on Windows (aligned memory cannot
be freed via ::free), so that lane did not compile.

* Test job: --no-testlibjsctools

On Apple platforms run-javascriptcore-tests also runs testLibJSCTools, which
the lanes do not build, like the other C++ test binaries; the macOS legs
reported it as a failure.

* Test job: allow_user_segv_handler=1 in ASAN_OPTIONS

On Linux under ASan JSC disables its wasm fault signal handler unless
ASAN_OPTIONS has allow_user_segv_handler=1 or handle_segv=0 (Options.cpp), and
without the handler a module with shared memory does not parse ("shared memory
is not enabled"): about 40 wasm tests failed on the asan lanes for that.

* Test job: tell the driver the architecture on Windows

run-javascriptcore-tests takes it from perl, which on windows-11-arm reports
x86_64, and passes it on as run-jsc-stress-tests --arch; the jsc.exe tested
there is arm64.

* Test job: the tarball's bin/ is on PATH on Windows

run-jsc-stress-tests stages jsc at .vm/jsc as a symlink, and where it cannot
make one, as on Windows, copies that one file. The asan jsc.exe then started
without clang_rt.asan_dynamic-x86_64.dll beside it and every run ended with no
exit code. Windows also searches PATH for a DLL.

* jsc: open modules on Windows without the CRT's stat

fetchModuleFromLocalFileSystem() prefixes the path with \\?\ and called
_wstat() on it. The CRT's stat treats '?' as a wildcard and fails, so jsc.exe
could not load any module: "Could not open file" on every module and wasm test
of the Windows lanes. Ask GetFileAttributesW() whether it is a file.

* jsc reads the repacked ICU data: the decompression hook, in jsc.cpp

The ICU data the lanes bundle has a zstd frame per item (icu/compress-data.ts)
and their ICU calls the weak hook bun_icu_maybe_decompress on each item it
loads. Only Bun defined it. jsc.exe and the musl jsc link that data, so without
the hook they could read only the items of keep-raw.txt and most of Intl threw
("Failed to format a number", "failed to initialize DateTimeFormat": about 170
tests on the Windows lanes); the glibc jsc linked the uncompressed copy `make
install` leaves in /usr/local instead, so it tested other data than Bun runs.

jsc.cpp now defines the hook, as Bun's bun_icu_decompress.cpp does, when CMake
is given zstd's lib/ directory (BUN_ICU_ZSTD_SOURCE_DIR): shell/CMakeLists.txt
builds the decoder (common/ and decompress/) into the jsc target. The glibc,
musl and Windows `base` stages keep those sources at /zstd/lib, where they
already built the zstd CLI, and the lanes pass the path. The glibc lane's
ICU_ROOT is /output, the libraries Bun gets; the hook names the dictionary in
the repacked data, so linking any other ICU data fails.

The toolchain images of those three change.

* jsc: resolve a file:// module key on Windows; the driver takes cmake's "ARM64"

moduleLoaderResolve() cuts "file://" off a key that is a file URL and asks
isAbsolutePath() about the rest. For file:///D:/x the rest is "/D:/x", which on
Windows is not an absolute path (that is "D:\" or "D:/"), so with module files
now opening, every module and wasm test of the Windows lanes failed at "Module
specifier ... is not absolute". On Windows the key goes through
URL::fileSystemPath(), which gives D:\x.

webkitdirs.pm takes the architecture from cmake --system-information, maps
amd64 and aarch64 to the names the scripts use, and left Windows' "ARM64" as it
was: run-javascriptcore-tests then refused --architecture arm64 ("not supported
by the provided binary, which supports 'ARM64'") and the Windows arm64 leg ran
nothing.

* Tests: native functions print on one line; builtin frames have no URL

Two things this fork does that these expectations did not have:

Function.prototype.toString() of a native function is
`function f() { [native code] }` on one line (3ad19d9e49d5), where upstream
prints three. Eight ChakraCore baselines and js/basic-strict-mode (script and
expected text) had upstream's.

The lanes are built with ALLOW_LINE_AND_COLUMN_NUMBER_IN_BUILTINS, so a builtin
like Array.prototype.map keeps its code block on a stack frame and the frame's
URL is that block's, which is empty, not "[native code]": js/stack-trace's
expected text.

* Layout tests: a cyclic array converts to "" here

Upstream removed StringRecursionChecker (318399@main) and rewrote
js/array-string-recursion, js/array-tostring-and-join and js/toString-recursion
to expect the stack overflow that follows. Bun keeps the guard for arrays
(runtime/StringRecursionChecker.h): an array met again while it is being joined
gives the empty string, as in V8 and SpiderMonkey, which code written for Node
depends on.

array-string-recursion is the test as it was before that change. In the other
two only the array cases change back; an Error or RegExp that reaches itself
has no guard here either and still throws.

* Error messages from JSC's own builtins do not depend on the build

A private builtin (a builtin whose source has no URL: JSC's, not Bun's) emits
expression info only when assertions are on (73b551e25d97), which is there for
the positions. With the info present the message code also appended the
builtin's source text, so an assertion build said "undefined is not a function
(near '...item of wrapper...')" and "null is not an object (evaluating
'iterable')" where a release build, like upstream, says "undefined is not a
function" and "null is not an object". Twelve stress tests that compare those
messages failed on the asan lanes only.

appendSourceToErrorMessage() leaves the text out for a private builtin in every
build. Release builds never had the info, so nothing changes there; messages
from user code and from Bun's builtins keep their source text.

* JSTests: import attributes and cached string literals, as this fork has them

import-attributes-unsupported.js, invalid-import-assertion.js: Bun keeps every
import attribute for its loaders and takes any non-empty `type` as one the
host loads, so an unknown key is no SyntaxError and an unknown type does not
reject. The tests expect that; the malformed-syntax cases are unchanged.

jsstring-definitely-atom-bit.js: not run in the bytecode-cache mode. A literal
decoded from the cache is a plain StringImpl over the cache's bytes, so loading
a cache interns nothing, and is not flagged as an atom, which the test expects
of a literal. The invariant it protects (flagged means atom) holds.

* JSTests: skip the RegExp buffer boundaries tests until YARR has the feature

Upstream's \A \z \Z (2f66f5ed23f9, behind --useRegExpBufferBoundaries) changed
nine files under yarr/. The sync that contained it (#455) came five days after
this fork's YARR was rewritten (#299) and kept the fork's side of every YARR
conflict, so the tests arrived and the feature did not. The four tests are
skipped, with a TODO naming what to port.

* JSTests: say only what is known in the buffer boundaries TODO

* [JSC] WasmOperations: divide the frame offset as a signed value

The `access` lambdas turn a byte offset into an index with `i / sizeof(V)`. `i`
is an int and sizeof is a size_t, so a negative offset is converted to unsigned
first: WasmToJSCallableFunctionSlot (-8) becomes index 0x1FFFFFFFFFFFFFFF, and
&p[0x1FFFFFFFFFFFFFFF] is pointer arithmetic that overflows. It wraps to p - 8,
so the right slot is read, but it is undefined behaviour.

Under ASan on x86_64 the compiler folds the check it puts before that load into
a read of the constant shadow address ((uint64_t)-8 >> 3) + 0x7fff8000, which
is not mapped: operationWasmToJSExitMarshalArguments faulted in the check
itself, and every wasm test that calls into JS with the JIT off (wasm-no-jit,
lockdown) crashed on the linux-amd64-asan lane, 370 files. The division is done
in int.

* [JSC] A parse-time SyntaxError keeps the location of the syntax error

addErrorInfo() gives a SyntaxError the parser's line and the URL of the source
that failed to parse. Upstream materializes the error's stack-derived
properties first and then puts those two over them. Here (9fa6dd7006b5) the
parser's values were stored in the ErrorInstance before materializing and the
function returned without the final puts, on the assumption that materializing
would use what was stored. It does not: with frames on the stack
getLineColumnAndSource(), or the host's onComputeErrorInfo callback, overwrite
them with the top frame's position, and with no frame nothing is set at all.

So an error from load("bad.js") said the line and file of the load() call, and
a script that fails to parse at its own top level had no line or sourceURL, and
the shell printed no "at file:line" after it: 22 ChakraCore baselines. In Bun a
SyntaxError from eval or new Function reports the caller's position for the
same reason.

The parser's line and sourceURL are put after materializing again, DontEnum as
ErrorInstance makes them. What a host callback is handed is unchanged.

* [JSC] addErrorInfo: what a host's error-info callback computed stands

Bun's callback (VM::onComputeErrorInfo) reads the parser's line and sourceURL
from the ErrorInstance fields addErrorInfo() stores before materializing, maps
them through its source maps, adds an "at <parse>" frame and hands back the
line to report. The previous change put the parser's raw line and sourceURL
over that afterwards, which in Bun would replace a source-mapped line with the
line in the transpiled output.

The parser's values go on afterwards only when no host computed the error
info: no callback installed (the shell, where materializing takes them from
the top stack frame), or no frame on the stack, in which case the callback is
not asked and nothing was set at all.

* [JSC] The code cache key tells two sources apart by a 64-bit hash of their text

SourceCodeKey::operator== does not compare source text here (3186362fe1a8): for
a large source that comparison is the most expensive thing on a cache hit. That
left the 24-bit StringImpl::hash() in m_hash as the only part of the key that
depends on the text, and with equal length, flags, name and host two different
sources were one cache entry: of 20,000 `new Function("x", "return x + N;")` with
same-length bodies three ran another body's code (class-subclassing-function.js,
parse-line-comment.js).

The key still never reads the text. SourceProvider::contentHash() is a 64-bit
hash of the provider's whole text, RapidHash, of which StringImpl::hash() is the
low 24 bits. Two keys are equal when they are over the same characters in memory,
or have the same contentHash(), and the same range.

No pass over a text is added: a string nobody has hashed gets its one pass in
StringSourceProvider::hash(), which now computes all 64 bits and hands the string
its own hash from them; a string that has its hash is not read when a key is
built, and its 64 bits are computed only if a lookup meets an equal-looking entry
held in other memory. A provider that hashed its text while loading it overrides
contentHash().

The bytecode cache stores the 64 bits in CachedSourceCodeKey (format revision 6).

* Revert "[JSC] The code cache key tells two sources apart by a 64-bit hash of their text"

The key goes back to what it was; the two tests it fixed (class-subclassing-function.js, parse-line-comment.js) fail again.

* Tests: three fixes for the mode or the lane, not the engine

buffer-accessor-jit-{large,byteoffset,fractional-value}.js check
numberOfDFGCompiles(f) <= 3. Lockdown runs with --useJIT=false, where the shell
reports a huge count on purpose; they skip that mode, as upstream's tests of
this shape do.

wasm/stress/memory64-overflow.js is marked slow!: under ASan in the
wasm-collect-continuously mode it passes the 300 second hard timeout.

The Windows test leg checks out with core.autocrlf off. With \r\n in the files
Function.prototype.toString() has them too, and lazy-function-executables.js
and bytecode-optimizer-exceptions.js compare it with a template literal.

* regress-174463162.js skips the two modes that collect continuously

$vm.installPropertyInlineCacheClearingWatchpointWithDeadOwner() ends by
scribbling proto's cell header, to stand for a swept cell, while main() still
holds proto and goes on to run another statement. A collection before the
script ends finds proto on the stack (the conservative scan, Heap.cpp:3183),
marks it, and SlotVisitor::visitChildren() decodes 0xbadbeef0 as its structure
ID: ASSERTION FAILED: decontaminate(), or a segfault.

The test allocates next to nothing, so only ftl-eager-no-cjit and
no-cjit-collect-continuously, which pass --collectContinuously=true, collect in
that window: 2 to 3% of runs on a loaded machine. One fullGC() after the helper
call crashes every run in any mode.

* regress-174463162.js: the comment does not say Bun

The test and the helper are upstream's, unchanged, and upstream's bots fail it
in the same two modes (4 of about 4,850 runs since it landed, none in any other
mode).

* Tests: --asan, and wasm/regress/298930.js skips it

run-jsc-stress-tests --asan sets $asan, for //@ skip if $asan;
run-javascriptcore-tests passes it through, and the *-asan test legs pass it.

wasm/regress/298930.js is the first user. Wasm::ConstExprInterpreter keeps the
arrays it creates in a MarkedArgumentBuffer whose 16 inline slots are in a
stack local, protected by the conservative stack scan. ASan's fake stack
(detect_stack_use_after_return, on by default on Linux) puts that local in a
heap-allocated frame the scan does not visit, so the collection triggered by
the 17th array frees the first 16 and MarkedVectorBase::expandCapacity() reads
one: heap-use-after-free, every run. With detect_stack_use_after_return=0, or
without ASan, it passes. Upstream's jsc built the same way fails the same way;
upstream turns the fake stack off for its Cocoa ASan builds
(Configurations/Sanitizers.xcconfig, OptionsCocoa.cmake) and has no Linux ASan
bot. The asan lanes keep the fake stack, and the use-after-return check with
it.

* module-loader-promise-then-tampered.js is skipped, with a TODO

import() here still wraps the module loader's promise in a second promise
(USE(BUN_JSC_ADDITIONS) in globalFuncImportModule()) and resolves that with the
first through the ordinary resolve(), which calls a replaced
Promise.prototype.then. Upstream returns the loader's promise.

The wrapper came with a fast path for a loader promise that is already
fulfilled (8a5ce3999589, with an early return for evaluated modules in the old
requestImportModule builtin, 4a2db3254a95). The module loader rewrite
(4a638109b905) replaced that builtin, its requestImportModule() always returns
a pending promise, and the merge kept the wrapper: the fast path is never taken
(0 of 4 imports of one module), and every import() takes one more microtask
tick than without the wrapper (13 and 9 against 12 and 8, first load and
loaded).

* wasm core simd_f32x4_cmp.wast.js is skipped on the asan lanes

In the wasm-collect-continuously mode it hit ASSERTION FAILED: !isScheduled()
in RunLoop::TimerBase::ScheduledTask::updateReadyTime() (RunLoopGeneric.cpp).

RunLoop::runImpl() calls ScheduledTask::fired() without the loop lock. For a
one-shot timer fired() deactivates the task and then, if it is active again,
updateReadyTime()s it. TimerBase::start() takes the lock but may be called from
any thread, and the collector thread calls it on the VM's
JSRunLoopTimer::Manager timer (Heap::stopTheMutator() ->
StopIfNecessaryTimer::scheduleSoon(), GCActivityCallback::cancel()): between
the two steps it makes the task active and scheduled.

The code is upstream's; upstream's jsc built with assertions asserts the same
way (a script of zero-delay setTimeouts with --collectContinuously=true: 18 of
64 runs, 14 of 64 here). It is the run loop of the JSCOnly and PlayStation
ports and of this shell; inside Bun timers are Bun's. Without assertions the
effect is a timer's key changing while it is in the run loop's tree.

Any test that waits on the run loop can hit it in that mode; this is the one
that has.

* CI: the asan lanes are not tested

The JavaScriptCore tests took 65 and 68 minutes against the Linux asan lanes,
99 on macOS and had not finished after 275 on Windows (run 34767304513), against
11 to 16 for the lto lanes on Linux and macOS. The tested lanes are now the
ones Bun ships: linux-amd64-lto, linux-arm64-lto, macos-arm64-lto,
windows-amd64-lto and windows-arm64. The asan lanes are still built and
published.

The asan lanes were the only tested ones with assertions on.

run-javascriptcore-tests keeps --no-slow and --asan, and the tests their
//@ skip if $asan, for running against an asan build by hand (CLAUDE.md).

* CI: only the Linux lto lanes are tested

linux-amd64-lto and linux-arm64-lto, about 11 minutes each. The macOS and
Windows lanes are no longer tested.

windows-amd64-lto took 145 minutes for the same 32,000 test runs macos-arm64-lto
did in 16 (run 34767304513): --ruby-runner, the only runner that works on
Windows, writes a runscript of `system "ruby test_script_N"` lines
(TestRunnerRuby, jsc-stress-test-writer-ruby.rb), so the tests run one at a
time, each in a new ruby, on one of the runner's four cores. windows-arm64 had
not run at all: the driver refused "arm64" against cmake's "ARM64", fixed in
85372b8b7357 and not exercised since.

The test job still handles both platforms; lanes.mjs says how to list them as
tested again.

* regexp-unicode-code-unit-read-for-bmp-terms.js: two expectations follow the /u match-start rule here

With /u or /v, RegExpBuiltinExec matches over code points: inputIndex is the
index of the character obtained from element lastIndex of S, so a lastIndex
inside a surrogate pair is that pair's code point and a match never starts
between a pair's halves. RegExp::matchInlineAtCodePointBoundaries() does that
here (09e477744721); upstream starts at the code unit.

- /[a-z\u{1F600}]/uy with lastIndex 1 on "\u{1F600}x": ["\u{1F600}"], as V8,
  where upstream gives null.
- /a?\B|q/u.exec("X\u{1F600}Z"): null. Upstream and V8 give [""] at index 2,
  between the halves of the pair; \B holds at no code point boundary of that
  string.

The file's other assertions pass unchanged.

* CI: nothing is published when a test fails

`release` now needs `test` as well as the builds. It already deletes the draft
and fails when any job it needs did not succeed, so a failing test on any
tested lane (linux-amd64-lto, linux-arm64-lto) means no release, for main and
for a pull request's preview alike.

* class-subclassing-function.js and parse-line-comment.js are skipped, with a TODO

Both build thousands of same-length new Function / eval sources and check what
each returns. SourceCodeKey::operator== does not compare source text here
(3186362fe1a8, to keep a large source's text out of a code cache hit), which
leaves the 24-bit StringImpl::hash() as the only part of the key that depends
on the text: of 20,000 `new Function("x", "return x + N;")` with same-length
bodies, 3 ran another body's code.

* Review: three more collect-continuously modes, the wasm log lines, Windows' native architecture

regress-174463162.js also skips dfg-eager, dfg-eager-no-cjit-validate and
ftl-eager: in a release build those pass --collectContinuously=true too (five
of the default modes do, not two).

WasmOperations.cpp: the dataLogLnIf lines in the two `access` lambdas divide by
static_cast<int>(sizeof(...)) like the returns below them. They are compiled
out (verbose is a constexpr false), so nothing changes until someone turns it
on.

webkitdirs.pm: determineNativeArchitecture() reads PROCESSOR_ARCHITEW6432 /
PROCESSOR_ARCHITECTURE on Windows, where there is no uname, so that
run-javascriptcore-tests --architecture arm64 on Windows on ARM passes the
"cannot run tests with arm64 on this machine" check. Not exercised: the Windows
lanes are not tested at the moment.

* Review: the workflow's job graph shows test before release; --asan reaches webkitdirs too

ci.yml's header drew `test` as a leaf; `release` waits for it now.

run-javascriptcore-tests --asan: GetOptions took the flag before
webkitdirs.pm's determineASanIsEnabled() could, which is what picks the ASan
product directory on the Cocoa CMake path when there is no --root. The flag is
handed back and webkitdirs consumes it straight away, since anything left in
@ARGV is rejected as an unrecognized option.

* webkitdirs: Windows' native architecture comes from the registry

The previous change read PROCESSOR_ARCHITEW6432 and PROCESSOR_ARCHITECTURE.
Strawberry Perl is x64, and an x64 process on Windows on ARM runs emulated: it
has AMD64 in %PROCESSOR_ARCHITECTURE%, and PROCESSOR_ARCHITEW6432 is only set
for 32-bit processes, so that still said x86_64 on windows-11-arm.

HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment's
PROCESSOR_ARCHITECTURE is the machine's, whatever the process is. oven-sh/bun's
scripts/bootstrap.ps1 detects ARM64 the same way, for the same reason.

Not exercised: the Windows lanes are not tested at the moment. The query's
output format is as the pattern expects on a Windows x64 machine (AMD64).

* shadow-realm-remote-function-copy-length-and-name.js skips the eager modes that collect continuously

It segfaulted (exit 139, no output) in the ftl-eager mode on linux-arm64-lto,
once, and with publishing now dependent on the tests that held back the
release.

On x64 with the ftl-eager options it crashes in JIT code, called from
llint_op_call at the top level of the script, 13 times in 320 on a loaded
machine (ASan build; 1 in 320 without ASan). It needs eager tiering and
--collectContinuously=true together: 0 of 320 with either alone. Upstream's own
jsc at ccdcb8a026c0, built the same way, does the same, 19 of 640, so this is
not the fork's; upstream's bots show 1 failure in about 48,000 runs of these
modes. The cause is not known.

dfg-eager, dfg-eager-no-cjit-validate, ftl-eager and ftl-eager-no-cjit are the
default modes that have both ingredients.

* [JSC] A direct tail call to a host function keeps its CodeBlock on the stack

For a DirectTailCall to a known host function, DFG and FTL shuffle the frame
for the tail call and then call the host function inline, from their own code
(emitCallTarget(): prologue, null CodeBlock slot, call, exception check,
epilogue, ret). After the shuffle no frame names this CodeBlock: the frame is
the host function's, with a null CodeBlock slot. The only thing left that
points into this code is the return address, which the conservative scan does
not map to a CodeBlock. If the host function triggers a collection and nothing
else keeps the caller alive, the CodeBlock dies, its executable memory is freed
(and reused), and the host function returns into it.

stress/shadow-realm-remote-function-copy-length-and-name.js hit it: the
ShadowRealm builtins tail-call the host function createRemoteFunction, which
allocates. With eager tiering and --collectContinuously=true --useGenerationalGC=false
together (the dfg-eager and ftl-eager modes) it segfaulted in 11 to 16 of 640
runs on a loaded x86_64 machine, once on linux-arm64-lto in CI; upstream's jsc
at ccdcb8a026c0 does the same, 19 of 640. The freed DFG code, saved before it
was freed, has the inline call, and the fault is at its return address.

The inline call stays. Before it, the CodeBlock's pointer is stored in a stack
slot below the host function's frame, where the conservative scan finds it and
keeps the CodeBlock alive (and in CodeBlockSet's currently-executing set); the
epilogue that was already there drops the slot. 0 of 1,280 runs with the
minimal options and 0 of 1,280 with the ftl-eager mode's. A native tail call
from optimized code costs the same, 18.0 ns against 18.0 ns.

The test runs in every mode again.

* CI: a failing test does not hold back the release

`release` needs the builds only, as before b7bc14f7a87e. The test job still
runs on the tested lanes and goes red when a test fails; nothing waits for it.

One intermittent failure in about 120,000 test runs (an upstream JIT bug, since
fixed here) was enough to stop a preview from being published.

* The asan lanes use bmalloc/libpas again

Reverts 46650cc619cd ("The asan lanes are built with USE_SYSTEM_MALLOC") and
1bd036781327 (its Windows exception): the asan and debug-asan variants pass no
USE_SYSTEM_MALLOC, and the Dockerfiles no longer take it. They build as they do
on main. No other lane ever set the argument.

With the system allocator, every fastMalloc in WTF, JavaScriptCore and Bun's C++
is an ASan allocation. In Bun's asan test lane that made LeakSanitizer see
allocations it could not see in libpas, freed JavaScriptCore memory count as RSS
through ASan's 256 MB quarantine, and max_allocation_size_mb cap JavaScriptCore's
own allocations. One build of that lane: 81 failing test files against 0, 559
minutes of shard time against 108, 4 of 20 shards past the job's time limit.
Of those, 15 files compare RSS with exact limits that are not to be retuned.

* musl: the aarch64 sysroot has fortify-headers

Alpine's clang defines _FORTIFY_SOURCE=2 by itself and looks for the checked
libc wrappers in <sysroot>/usr/include/fortify. In the container they come
with clang (a dependency); the aarch64 sysroot has no clang and never got
them, so since the arm64 lanes became a cross build they were compiled with
the define and nothing behind it (musl has no fortify of its own), while the
x86_64 lanes kept the checks.

Against main's build of the same sources, in bun-webkit-linux-arm64-musl:
libWTF.a's code is 15% smaller (StringImpl.cpp.o 140,544 -> 60,548 bytes,
WTF::equal(StringImpl&, StringImpl&) 6,108 -> 1,612, 38 brk traps -> 0),
libJavaScriptCore.a 0.7%, ICU 1.4 to 3.5%; the bun that links the -lto lane
lost 472 KB of .text. The arm64 glibc lanes are unaffected (every object of
libWTF, libbmalloc and libicuuc has the same code size as main's).

The sysroot's fortify-headers must be the container's version, and the
toolchain check compiles a memcpy for both and requires the trap in each. This
changes `base`, so the musl toolchain image is rebuilt.

* musl: the aarch64 target reads the clang configuration the x86_64 one does

Alpine gives clang its default flags in /etc/clang21/<triple>.cfg, read for the
triple being compiled for. The clang package installs the container's
(x86_64-alpine-linux-musl.cfg: -fstack-clash-protection); Alpine's aarch64 clang
package installs the same file as aarch64-alpine-linux-musl.cfg, and in this
x86_64 container nothing did, so the cross-built arm64 lanes were compiled
without it.

With fortify-headers back, that was what was left of the difference from main's
native build of bun-webkit-linux-arm64-musl: 11 of libWTF.a's 175 objects 144
bytes smaller in all, 55 of libJavaScriptCore.a's 196. The file is copied, so
the aarch64 lanes get whatever Alpine puts there, and the toolchain check
requires clang to pass itself the same protection flags for both targets.

* JSTests: a list of where this fork's tests differ from upstream's, and why

JSTests/BUN-TEST-DIFFERENCES.md. All 120 changed test files and the three
runner scripts, grouped by reason, for whoever has a failing test after an
upstream sync and needs to know whether the test is the thing to change:

- nine behaviors the fork has on purpose (ReferenceError text, one-line native
  toString, module link error wording, import attributes, cyclic array join,
  /u matches and surrogate pairs, when a time-zone change is seen, builtin
  frames' URL, bytecode-cache strings), each with the fork code that causes it
  and the files whose expectations follow it;
- tests narrowed to the modes or builds they can pass in, with the reason;
- the seven skipped with TODO(bun), by the gap each waits on;
- the rules an edit to an upstream test follows, and the steps for sorting a
  new failure.

* CLAUDE.md points at JSTests/BUN-TEST-DIFFERENCES.md

Under Testing: what the file is, that it is read before a test's expectation is
changed or a test is skipped, and that a changed test is added to it. The CI/CD
paragraph mentions it where the failing tests' summary is described.
JSTests/CLAUDE.md and README.md are upstream's and stay as they are.
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.