Upgrade to upstream WebKit 47f7250137c6 - #455
Merged
Merged
Conversation
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
…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.
Preview Builds
|
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
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>
This was referenced Aug 18, 2026
This was referenced Aug 28, 2026
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merges upstream WebKit main at
47f7250137c6(2026-08-16): 846 commits since the previous merge base3722912ff800(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/andRegExp.cppare kept at the fork's version and the upstream commits were gone through one by one:f4f06bc115+ddf3655422(lookbehind JIT, 6 test files),b7fac90284(\p{}under/iu/iv),dc35ebdb9b,6a1ef9a1ef,540f0965c6,29d016fbd9,64243d698a(the fork'scollectBoyerMooreInfoFromTermalready passes through parenthetical assertions).7b5e7da783as f787159. The fork'sappendInverted()applied a pending&&/--to characters only, so/^[\q{ab|c|1}&&\P{L}]$/vmatched"ab"; upstream's test now passes.ac2afd10b8(removal of theENABLE_YARR_JIT_*ifdefs; this fork's YarrJIT still uses them, so the flags upstream deleted fromPlatformEnable.hare kept defined there),bbc000ae4f(raw code unit reads for BMP-only classes in unicode mode, an optimization inside the JIT paths Yarr: JIT lookbehinds, first-code-point alternation dispatch, Boyer-Moore and /u·/v spec alignment, RegExp correctness fixes #299 rewrote),2f66f5ed23+37f4628ab5(\A\zbuffer boundaries; the generateduseRegExpBufferBoundariesoption exists but is default-off upstream as well and does nothing here).regexp-unicode-code-unit-read-for-bmp-terms.jsfails on two assertions about match attempts that start inside a surrogate pair; both are the match-start behaviour Yarr: JIT lookbehinds, first-code-point alternation dispatch, Boyer-Moore and /u·/v spec alignment, RegExp correctness fixes #299 changed on purpose (documented there), not regressions.regexp-lookbehind-jit.jsandregexp-unicode-property-escape-ignore-case.jsexisted on both sides with different content; upstream's files keep the names, the fork's are renamed-vs-interpreter/-matrix.Other conflict resolutions worth knowing about
USE_BUILTIN_FRAME_ADDRESSwas removed upstream (2a8926009f) together with thetopCallFramefallback 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'sbun-webkit-windows-arm64-debugbuild 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 thetopCallFrame == callFrameassertion every operation performs in debug builds, so the January workaround is obsolete. If the Bun CI lanes disagree, the fix is restoring the ~50 lines2a8926009fremoved.MAX_ARRAY_BUFFER_SIZE: upstream raised it to1 << 34(2c2c1af357). Kept at1 << 32underUSE(BUN_JSC_ADDITIONS): Bun'sBufferkMaxLengthis this constant and Bun has not been audited for buffers above 4 GB. Raising it is a separate decision. Consequence for JSTests: upstream's newarray-buffer-slice-larger-than-4gb.jsallocates 5 GB unconditionally and throws under this cap (its siblingtypedarray-index-past-max-array-index.jsskips 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::Typegains upstream'sText(import-text,49246d2612) ahead of the fork'sHostDefined, soHostDefinedis now 5. WithBUN_JSC_ADDITIONS,parseType("text")still returnsHostDefinedbecause Bun implementstype: "text"itself;AbstractModuleRecord::moduleType()andSourceProvider::isModuleType()know aboutSynthetic/BunTranspiledModule.SyntheticModuleRecord: upstream threads aSourceProviderSourceTypethroughcreateand thetryCreate*helpers; the fork's lazy-export overload (SyntheticModuleRecord: exports whose values are produced on first binding #408) is kept and reportsSourceProviderSourceType::Module. The fork's unused public 4-argumenttryCreateWithExportNamesAndValuesis gone.HeapFinalizerCallback->GCCompletionCallback,HandleSet->StrongSet(the fork'sJSHeapFinalizerPrivate.cppstill skips the JSLock),finalizeUnconditionally->reconcileWeakReferencesAtGCEnd(ErrorInstance, where the fork runs its Bun finalizer hook),timeZoneFromRecordnow takesISOStringTimeZoneParseRecordnext to the fork'sTemporalZonedDateTime::toString.WebKitMacros.cmake: upstream's own CMake 4.4 fix (4bfeff8c67) replaces the fork's quoting patch.OptionsJSCOnly.cmakekeepsENABLE_BUN_SKIP_FAILING_ASSERTIONS, drops the ARM32/MIPS capstone block upstream removed.BuiltinExecutables.cpp: the fork's async builtin visibility tweak readsscanned.isAsyncFunction(d7cb8d6).StackBounds::currentThreadStackBounds()became private toThreadupstream (f6bc402b83); c0ccc24 adds aBUN_JSC_ADDITIONSaccessor for Bun's once-per-thread use.WTF::numberOfProcessorCores()started honouringNUMBER_OF_PROCESSORSupstream (5fc5182bcf, for WebKit's bots). Bun reports that value asnavigator.hardwareConcurrency/os.availableParallelism()(with the old pinNUMBER_OF_PROCESSORS=3 bun -p navigator.hardwareConcurrencyprints 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-existingWTF_numberOfProcessorCoresoverride is untouched. Drop that commit if following upstream here is preferred.JSType.h,.github/workflowsand the release tarball names are unchanged.Verification
bun run jsc:build:debug(Linux x64, debug + ASAN): builds,jscshell runs.regexp*/string-*/yarr*stress tests, each in JIT and--useRegExpJIT=falsemode: 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'stest/js/bun/jsc,jsc-stress,node/vm,node/module,bun/resolve,node/buffer,node/worker_threads,bun/wasmandnode/utilsuites (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.