Skip to content

Upgrade to upstream WebKit 6b58d86abe - #651

Closed
robobun wants to merge 226 commits into
mainfrom
bun/upgrade-to-6b58d86abe
Closed

robobun wants to merge 226 commits into
mainfrom
bun/upgrade-to-6b58d86abe

Conversation

@robobun

@robobun robobun commented Sep 14, 2026 •

Copy link
Copy Markdown
Collaborator

Merges upstream WebKit main at 6b58d86abe (2026-09-13) into the fork: 216 commits since the previous merge base ccdcb8a026 (2026-09-09), 47 of them in JavaScriptCore, WTF, bmalloc, cmake or JSTests. The branch starts from the fork's main at 28f58fb055 (#634). The merge commit 89e6d367e7 has 6b58d86abe as its second parent.

The branch also contains the fork's main as of 299c532387 (2026-09-23), so GitHub can merge this PR as it is. The fork's main was merged in seven times so far, each time Bun's main moved its pin. The sections "Second merge", "Third merge" and "Later merges" below describe them. The fork's main moved to 35e8970dfd on 2026-09-24 (#718, the bytecode cache order file). Bun's main does not pin it yet, so the branch does not contain it yet. I checked that merge ahead of time on a local copy: no conflict, bun run jsc:build:debug builds with no error, and 6 JSTests pass, one of them bytecode-cache-persistent-payloads-are-released.js. #718 adds code to runtime/CachedBytecode.h and CachedBytecode.cpp next to the reconcileWeakReferencesAtGCEnd() edit of the second merge, and does not touch that function. So GitHub can still merge this PR as it is.

This PR contains every upstream commit of #623 (ccdcb8a026..50320fd3b3) plus 123 newer ones. If this PR merges, #623 is not needed.

Conflicts and how they were resolved

7 files conflicted.

  • heap/FastMallocAlignedMemoryAllocator.cpp (b8d7e24add, the one that needs a decision). Upstream moves the MarkedBlock warm-up supply from JSC (WarmUpBlockProvider) into libpas (bmalloc_prefault_supply) and calls it only under USE(LIBPAS). The fork's release builds set USE_MIMALLOC=ON, so with upstream's file they get no prefaulted blocks at all. [JSC] WarmUpBlockProvider: start the helper thread after 64 block requests, not the first #553 measured that the helper makes an allocation-heavy script 19% faster on such a build. Resolution:
    • USE(LIBPAS) builds (the fork's debug and ASAN builds) use upstream's libpas supply.
    • Builds without libpas (mimalloc or system malloc) keep the JSC-side WarmUpBlockProvider as it is on the fork's main today. It sits under #else // !USE(LIBPAS). Its Phase enum moves into the class, because upstream removed it from the header.
    • The start threshold from [JSC] WarmUpBlockProvider: start the helper thread after 64 block requests, not the first #553 (warmUpMarkedBlockStartAfterBlocks, default 64) is now the free function isPastWarmUpStartThreshold(). Both paths test it before they touch the supply.
    • The new $vm functions work on both paths. Without libpas, warmUpMarkedBlocksAreEnabledForTesting() reports the option state and warmUpMarkedBlockCountForTesting() reads the provider's block count. JSTests/stress/warm-up-marked-blocks-state-machine.js is upstream's file, not changed. Its comment says that a build without libpas reports the supply as disabled. That is not true for the fork.
    • If you prefer upstream's behaviour (no supply on mimalloc builds), delete the #else block. Nothing else depends on it.
  • runtime/JSBigInt.cpp (9e61914f4c). Upstream adds bounds hints to karatsubaStart() and divideSchoolbook(). The fork has the InterruptCheck plumbing in the same lines. Took upstream's RELEASE_ASSERTs, the window subspan and the overflow accumulator, and kept every interrupt check. The fork lets q omit its top digit when that digit is zero, so q = q.first(m + 1) became q.first(std::min(m + 1, q.size())), and the loop keeps the fork's RELEASE_ASSERT(!qhat) for the omitted digit.
  • bytecode/CodeBlock.cpp (7189f73167). CodeBlock::inferredName() now returns UTF8CString. Kept the fork's inferredNameForTools() call and the USE(BUN_JSC_ADDITIONS) module name block, with upstream's _s literals. FunctionExecutable::inferredNameForTools() now returns UTF8CString too.
  • runtime/WeakGCMap.h, runtime/WeakGCMapInlines.h (8ae0649a80). Include lines only. Kept the fork's quoted include style and dropped Weak.h and WeakInlines.h like upstream.
  • wtf/URLParser.cpp (7bd7b6dfad) and wtf/UUID.cpp (74b519d7f9). Same one-line resolutions as in Upgrade to upstream WebKit 50320fd3b3 #623: upstream's legacyCStringPointer() log line with the fork's ASSERT (Make WTF::URLParser faster than Ada #452), and the fork's commented-out OS(DARWIN) branch of bootSessionUUIDString().

Second merge: the fork's main at c775a5dc52 (44 commits since 28f58fb055)

2 files conflicted.

  • runtime/RegExp.cpp. Upstream e19f57a779 and the fork's d242f6dd4b make the same fix: RegExp::deleteCode() keeps m_atom and m_specificPattern. Kept the fork's comment. The code is the same on both sides.
  • Source/cmake/WebKitCompilerFlags.cmake. Both sides add lines after list(APPEND ENABLED_COMPILER_SANITIZERS "-fsanitize=address"). Kept both: upstream's webkit_add_compile_definitions(__SANITIZE_ADDRESS__) and the fork's -fsanitize-address-use-after-return=never block (aa140ee23f).

2 pieces of new fork code use an API that upstream changed in this range. Git merges them without a conflict, and the tree does not compile until they change. Both edits are in the merge commit 6b1d0dff80.

  • PersistentBytecodePayloads (runtime/CachedBytecode.h, from c6826dcbb1) is a WeakGCHashTable. Upstream 8ae0649a80 replaces the virtual pruneStaleEntries() with reconcileWeakReferencesAtGCEnd(VM&, CollectionScope). The override has the new name and the same body. It still runs only after a full collection, after reapWeakHandles(): Heap::reconcileWeakGCHashTables() visits every registered table in a full collection and only dirty tables in an eden collection, and this table never marks itself dirty. Its values stay Weak<UnlinkedFunctionExecutable>, which upstream did not change.
  • The value profile briefDescription() in bytecode/MetadataTable.h (from 3aec93c668) returns UTF8CString and calls toUTF8CString(), like ValueProfile::briefDescription() after upstream 7189f73167.

Checked by reading, no edit needed: the new LLInt and common slow paths of the fork (slow_path_ensure_call_link_info, iterator_next_index_in_frame_*, slow_path_iterator_close_check, slow_path_new_reg_exp_shared) go through callSlowPath and the LLINT_* / CHECK_EXCEPTION macros. So they follow upstream's new exception convention from b9c0ed5b8c (LLInt::exceptionSignal() in the second result register). slow_path_ensure_call_link_info returns a CallLinkInfo* there, which is never all ones.

Third merge: the fork's main at c28156899e (5 commits since c775a5dc52)

1 file conflicted.

No other code of these 5 commits uses an API that upstream changed in this range.

Later merges of the fork's main

None of these merges had a conflict. For each one I scanned the added lines of the fork commits for an API that upstream changed in this range (utf8(), toCString(), CString, WeakGCMap, dataLog() with a CString, String(std::span<const char>)), and found none. For each file with edits from both sides I read both sides. In every case the edits are in different functions or blocks.

Merge commit Fork's main Fork commits Files with edits from both sides
a3b5a5cba9 000c489972 #684, #662, #346, #685, #688, #689 heap/Heap.cpp, heap/Heap.h, runtime/AbstractModuleRecord.cpp, runtime/VM.cpp, tools/JSDollarVM.cpp
6eafb22fb2 ebd5a6145b #696 Source/cmake/WebKitCompilerFlags.cmake
65672fa42f 63a807e88c #693, #677, #707 bytecode/CodeBlock.cpp, bytecode/CodeBlock.h, heap/Heap.cpp, runtime/JSModuleRecord.cpp, runtime/VM.cpp
90df1859d2 564ac2a6ca #708, #676 heap/MarkedBlock.cpp
2ed8525752 299c532387 #712 runtime/FunctionExecutable.cpp

In runtime/FunctionExecutable.cpp, #712 adds visitSourceFetcher() to visitChildrenImpl(), and this branch changes the return type of the fork's inferredNameForTools() to UTF8CString. In runtime/JSModuleRecord.cpp, the executables.set(key, executable) line of the third merge is not touched by any later commit.

Fork-only code that needed an edit after the merge

  • runtime/JSModuleRecord.cpp: moduleProgramExecutables() is a WeakGCMap. set() takes a raw pointer now (8ae0649a80), so the Weak<ModuleProgramExecutable>(...) wrapper is gone.
  • builtins/BuiltinExecutables.cpp, ffi/FFIICStub.cpp, ffi/FFIInvokeThunk.cpp, runtime/AbstractModuleRecord.cpp: utf8().data() passed to a %s is now utf8().legacyCStringPointer(). data() returns const char8_t* since 00130dc2f3, which only caused -Wformat warnings here.

Checked and unchanged: runtime/JSType.h, .github/workflows, the release tarball names. Source/WebCore/bindings/scripts/CodeGeneratorJS.pm changes one line (RELEASE_ASSERT to RELEASE_ASSERT_WITH_UNQUALIFIED_FUNCTION_NAME in the generated verifyVTable), which does not affect Bun's bindings.

Verification

  • bun run jsc:build:debug (Linux x64, Debug + ASAN, clang 21): builds, jsc runs. This configuration uses libpas, so it compiles the libpas path of FastMallocAlignedMemoryAllocator.cpp. The path without libpas was checked with -fsyntax-only on the same translation unit with USE_MIMALLOC=1. The preview build of this PR compiles it for real.
  • JSTests/stress/warm-up-marked-blocks-state-machine.js passes 8 of 8 runs on that jsc, with the default start threshold and with --warmUpMarkedBlockStartAfterBlocks=1. The supply fills, drains when idle, fills again, survives the allocation failure and recovers.
  • The JSTests files that upstream added or changed in the range pass: stress/weak-gc-map-keeps-live-values.js, stress/arraybuffer-grow-resize-huge-length.js, stress/multiply-negated-operand.js, stress/regexp-cached-result-one-character-atom-delete-all-code.js, wasm/gc/bulk-array-element-types.js.
  • BigInt: 82 of 83 JSTests/stress files named bigint-*, big-int-division*, big-int-mul*, big-int-mod* pass, including the Karatsuba, Toom, Burnikel-Ziegler, Barrett and the 6 bigint-terminate-* files. The one failure is bigint-toLocaleString.js. It fails because my local jsc links the compressed ICU data without Bun's decompress hook, so every toLocaleString call fails in this setup.
  • JSTests/modules: 107 of 115 pass, including the 5 module-loaders*.js files from [JSC] Additional module loaders per global object, sharing linked module code between them #522. The 8 failures fail with the same output on the jsc from the autobuild-cf1b36ec8703 debug-asan tarball. They compare error message text that the fork changes.
  • A sample of 1075 JSTests/stress files (every file whose name matches weak, symbol, structure, dictionary, flatten, arraybuffer, resiz, json, mul, negat, finalization or gc, plus 500 random files): 1048 pass, 6 carry a //@ skip, 21 fail. Of the 21, 13 call toLocaleString or Intl (the ICU setup above), 5 fail the same way on the autobuild-cf1b36ec8703 jsc, and 3 run longer than 15 minutes on both.
  • bun run build:local: Bun builds and links against this tree with the source edits in Upgrade WebKit to 6b58d86abe bun#42666 (67 lines in 25 files, nearly all utf8().data() to utf8().legacyCStringPointer()). bun-debug -p 42 prints 42. The Bun tests that touch the edited code pass on that build. Upgrade WebKit to 6b58d86abe bun#42666 lists them.
  • The preview build of this PR (autobuild-preview-pr-651-3bec033f) built all 42 tarballs. bun bd against its debug-asan tarball builds, and the upgrade tests pass.

After the second merge (6b1d0dff80):

After the third merge (269ab60de4):

  • bun run jsc:build:debug with clang 23.1.1 (the fork and Bun moved to LLVM 23): builds with no error and no new warning.
  • The 33 JSTests files that the 5 fork commits add or change (modules/import-slots-*.js, stress/module-loaders-share-released-code.js, stress/ftl-osr-exit-materialize-phantom-array-with-live-butterfly.js, wasm/modules/js-wasm-cycle-loaders.js), the 6 modules/module-loaders*.js files and the upstream files listed above: 41 of 41 pass on the local debug + ASAN jsc.
  • bun run build:local: Bun's main at c6b7fcb5bb plus the edits of Upgrade WebKit to 6b58d86abe bun#42666 builds and links against this tree, and the test files listed in Upgrade WebKit to 6b58d86abe bun#42666 pass.
  • CI of this PR at 269ab60de4: all 42 tarballs built (autobuild-preview-pr-651-269ab60d, same names as autobuild-c28156899e). All 48 jobs finished with no failure. Both Test jobs passed (bun-webkit-linux-amd64-lto and bun-webkit-linux-arm64-lto).

After each later merge (a3b5a5cba9, 6eafb22fb2, 65672fa42f, 90df1859d2, 2ed8525752) I ran the same checks, and all of them passed every time:

The latest run is at 2ed8525752: preview autobuild-preview-pr-651-2ed85257, Bun's main at 6d504dd983.

Upstream changes

Range: ccdcb8a026..6b58d86abe (216 upstream commits, 2026-09-09 to 2026-09-13, 47 touch JavaScriptCore, WTF, bmalloc, cmake or JSTests).

Not changed anywhere in the range: runtime/JSType.h, runtime/OptionsList.h, runtime/JSGlobalObject.h (so GlobalObjectMethodTable), runtime/VM.h, runtime/JSModuleLoader.*, builtins/, and every header in Source/JavaScriptCore/API. No JSC option is added, removed or given a new default. bytecode/BytecodeList.rb, generator/, runtime/CachedTypes.cpp and bytecode/UnlinkedCodeBlock.h are untouched, so the opcode layout and the bytecode cache format stay the same. The only inspector protocol edit is in Network.json (c4a7ebcc29). Each commit appears once, under the most specific heading that applies.

Needs an embedder-side change

Each entry says what a caller must change. Some entries need a check only, and say so.

  • 74b519d7f9 WTF::String(std::span<const char>) is now private, next to String(const char*), because char carries no encoding. Callers name the encoding: String::fromLatin1(std::span<const char>) (new overload), String(std::span<const Latin1Character>), String::fromUTF8(...) or String(ASCIILiteral). In the same commit WTF::enumName() and WTF::enumTypeName() (wtf/EnumTraits.h) return ASCIILiteral. They returned std::span<const char> before, so callers now test isEmpty() and not empty(). https://bugs.webkit.org/show_bug.cgi?id=323650
  • 7bd7b6dfad CString gains legacyCStringPointer(), which returns the same const char* as data(). Every upstream utf8().data() call site moves to it. CStringWithEncoding::characters() (the const char* accessor of UTF8CString and ASCIICString from 5f14e32e57) is renamed to legacyCStringPointer(). No type changes in this commit. It is the mechanical half of the retype of String::utf8(). The retype itself is 00130dc2f3, the next entry. https://bugs.webkit.org/show_bug.cgi?id=323722
  • 00130dc2f3 String::utf8(), StringImpl::utf8(), StringView::utf8() and Identifier::utf8() now return UTF8CString. They returned CString before. UTF8CString is the alias CStringWithEncoding<char8_t> (alias in wtf/Forward.h, class in wtf/text/CString.h). The siblings are Latin1CString (Latin1Character) and ASCIICString (char). CStringWithEncoding is a final class that derives publicly from CString and adds no data member. It hides the CString accessors so that the character type carries the encoding. data() still exists, but for a UTF8CString it returns const char8_t*. span() and spanIncludingNullTerminator() return std::span<const char8_t>, and mutableSpan() returns std::span<char8_t>. legacyCStringPointer() returns the same address as const char*. It is the accessor for %s arguments and C functions, and Latin1CString does not have it. length(), isNull(), isEmpty(), hash() and toStdString() come from CString and do not change. A call such as s.utf8().data() that feeds a const char* parameter must become s.utf8().legacyCStringPointer(). The same applies to s.utf8().span().data(). For a std::span<const char>, write byteCast<char>(utf8.span()). A const void* parameter (fwrite, write) still accepts data(). The SAFE_PRINTF and SAFE_FPRINTF macros accept the UTF8CString itself. PrintStream has no overload for const char8_t*, so dataLog() must get the UTF8CString itself or the String. A UTF8CString converts implicitly to CString (derived to base). So CString c = s.utf8() still compiles and c.data() is const char*, but the encoding is lost. String gains an implicit constructor from const CStringWithEncoding<CharacterType>& that decodes by character type. CStringWithEncoding gains explicit constructors from const std::string& and from a null-terminated const CharacterType*. wtf/text/StringCommon.h gains unsafeSpan(const char8_t*). https://bugs.webkit.org/show_bug.cgi?id=323846
  • 9b09294076 Upstream removes about 850 legacyCStringPointer() call sites where the destination already accepts a String. LOG with %s becomes LOG_WITH_STREAM, EXPECT_STREQ becomes EXPECT_EQ in tests, and dataLog() gets the String. Almost all edits are in WebCore, WebKit and TestWebKitAPI. In JSC and WTF the commit edits two lines. Options::dumpAllOptions() and the truncation path of printInternal(PrintStream&, const CString&) now print a String directly. No WTF or JSC function changes a parameter type or a return type. No caller edit is needed. https://bugs.webkit.org/show_bug.cgi?id=323859
  • 7189f73167 StringPrintStream::toCString() is renamed to toUTF8CString() and returns UTF8CString. The function template WTF::toCString(...) is renamed to WTF::toUTF8CString(...) in the same way. The old names have no alias. printInternal(PrintStream&, const CString&) is now = delete, and the non-const CString& overload is removed. So out.print(cstring), dataLog(cstring) and dataLogLn(cstring) do not compile for an untyped CString. New overloads print const UTF8CString&, const ASCIICString& and const Latin1CString&. UTF-8 and ASCII bytes go through unchanged, and Latin-1 is transcoded to UTF-8. To replace out.print(someCString), keep the typed value (auto s = string.utf8(), toUTF8CString(...), string.ascii()) and print that. Or print the String or StringView itself, or pass cstring.data() as const char*. These bytecode helpers now return UTF8CString: CodeBlock::inferredName(), CodeBlock::sourceCodeForTools(), CodeBlock::sourceCodeOnOneLine(), InlineCallFrame::inferredName(), UnlinkedSourceCode::toUTF8(), reduceWhitespace(), ArrayProfile::briefDescription(), ValueProfile::briefDescription(), BytecodeDumper::registerName() and constantName(). These JIT and runtime helpers do the same: MacroAssemblerCodeRef::disassembly(), Compilation::disassembly(), ExceptionScope::unexpectedExceptionMessage(), Air::Special::name(), JITPlan::signpostMessage(), Wasm::Plan::signpostMessage(), DFG::nodeListDump(), nodeMapDump() and nodeValuePairListDump(). In WTF, sortedListDump(), sortedMapDump(), BackwardsGraph::dump(), SingleRootGraph::dump() and StringHashDumpContext::brief() return UTF8CString. Identifier::ascii() and StringHashDumpContext::getID() return ASCIICString, and Structure::dumpBrief() takes const ASCIICString&. PerfLog::log(), GdbJIT::log(), Profiler::Database::logEvent() and Profiler::Compilation::addDescription() take const UTF8CString&, and DFG::validate() takes a UTF8CString. As a side effect CodeBlock::inferredNameWithHash(), SamplingProfiler::reportTopBytecodes() and DebuggerCallFrame::functionName() no longer decode UTF-8 function names as Latin-1. https://bugs.webkit.org/show_bug.cgi?id=323960
  • 25f7ce345a FileSystem::fileSystemRepresentation(const String&) returns UTF8CString. It returned CString before. A caller that passed .data() to open(), stat() or a similar C function must call .legacyCStringPointer(). On Windows the function now converts with CP_UTF8. It converted with CP_ACP (the active ANSI code page) before. The GLib functions currentExecutablePath(), currentExecutableName() and webkitTopLevelDirectory() also return UTF8CString, and Cocoa gains currentExecutableName(). createTemporaryFileInDirectory() (Cocoa only) returns std::pair<FileHandle, String>. wtf/StdLibExtras.h gains safeNSStringPrintfType() and the SAFE_WTFLOGALWAYS macro. CStringWithEncoding gains createNSString() for Objective-C++ code. The JSC callers (dumpJITMemory(), API/JSScript.mm) move to legacyCStringPointer(). https://bugs.webkit.org/show_bug.cgi?id=324034
  • 8ae0649a80 WeakGCMap<Key, Value> now stores a raw Value* per entry. It stored a Weak<Value> before, which is a pointer to a separate WeakImpl that the heap reaps in each collection. ValueType is ValueArg*. So set(key, value) takes a raw pointer, and the ensureValue() functor returns a raw pointer. find()->value is a raw pointer with no .get(). isEmpty() is removed. pruneStaleEntries() is replaced by reconcileWeakReferencesAtGCEnd(VM&, CollectionScope). WeakGCMap.h no longer includes Weak.h, and WeakGCMapInlines.h no longer includes WeakInlines.h. A caller that wrote map.set(key, Weak<T>(cell)) must write map.set(key, cell). A file that got JSC::Weak through WeakGCMap.h must include <JavaScriptCore/Weak.h> itself. Old design: WeakBlock::reap cleared each Weak<> in every collection, and pruneStaleEntries() removed the cleared entries in full collections only. New design: Heap::runEndPhase() calls Heap::reconcileWeakGCHashTables(), and each table tests its values with Heap::isMarked(). A full collection visits every registered table and removes each entry whose value is null or not marked. An eden collection visits only the tables on the new list Heap::m_dirtyWeakGCHashTables. set() and ensureValue() put the map on that list through WeakGCHashTable::markDirty(VM&). In an eden collection the map only sets a dead value to null and does not rehash. get(), find(), contains() and ensureValue() treat the null entry as absent, and the next full collection removes it. A table that gained no entry since the last collection is skipped. All its values are old, and an eden collection cannot free them. WeakGCHashTable (runtime/WeakGCHashTable.h) now derives from BasicRawSentinelNode<WeakGCHashTable>. A subclass must override reconcileWeakReferencesAtGCEnd(VM&, CollectionScope) in place of pruneStaleEntries(). It must call markDirty(vm) when it adds an entry, if eden collections must visit it. Heap::unregisterWeakGCHashTable() also takes the table off the dirty list. WeakGCSet keeps Weak<> entries and removes them in full collections only, as before. https://bugs.webkit.org/show_bug.cgi?id=323958
  • b8d7e24add The MarkedBlock warm-up (prefault) supply moves from JSC into libpas. The old code was WarmUpBlockProvider in heap/FastMallocAlignedMemoryAllocator.cpp. It ran a JSCWarmUp AutomaticThread that allocated blocks with tryFastCompactAlignedMalloc() and wrote one byte per page. It worked with every fastMalloc backend. The new code is bmalloc_prefault_supply.c and bmalloc_prefault_supply.h in libpas, and JSC calls it only under #if USE(LIBPAS). So upstream, a build whose fastMalloc is mimalloc or the system allocator gets no prefaulted blocks. In that build tryAllocateAlignedMemory() calls tryFastCompactAlignedMalloc() directly. With libpas, tryAllocateAlignedMemory() returns bmalloc_prefault_supply_try_allocate() for block-sized requests. The supply is a fixed array of at most 64 slots (BMALLOC_PREFAULT_SUPPLY_MAX_BLOCKS). Takers and the filler exchange slots with atomic operations and no lock. A mutex and a condition variable only wake or start the filler. The filler is a detached pthread. It allocates with bmalloc_try_allocate_with_alignment_inline() and touches pages with the new pas_page_malloc_populate(). After one idle interval with no demand it frees all blocks and exits, and a later take starts a new thread. The options useWarmUpMarkedBlocks (true), warmUpMarkedBlockCount (32) and warmUpMarkedBlockIdleTimeout (10 seconds) keep their names and defaults. JSC copies them once into bmalloc_prefault_supply_target and bmalloc_prefault_supply_idle_timeout_in_milliseconds. $vm.warmUpMarkedBlockState() is removed. $vm.warmUpMarkedBlocksAreEnabled() and $vm.warmUpMarkedBlockCount() replace it, and $vm.setWarmUpMarkedBlockAllocationShouldFail() stays. In C++, warmUpMarkedBlockStateForTesting(), WarmUpMarkedBlockPhase and WarmUpMarkedBlockState are removed. warmUpMarkedBlocksAreEnabledForTesting() and warmUpMarkedBlockCountForTesting() are added, and without libpas they return false and 0. pas_thread.h (the Windows pthread shim) gains include guards, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, extern "C" and PAS_API exports. The new source file is listed in Source/bmalloc/CMakeLists.txt and Source/bmalloc/libpas/CMakeLists.txt. https://bugs.webkit.org/show_bug.cgi?id=323480
  • 2aedf51ba6 WTF::UUID::emptyValue and UUID::deletedValue become private. The constructor UUID(HashTableEmptyValueType) becomes private too. Only HashTraits<UUID> and MarkableTraits<UUID> (now friends) can build the empty value. UUID(HashTableDeletedValueType) stays public. UUID(UInt128) now release-asserts that the value is not 0 (empty) and not 1 (deleted), so UUID { 0 } crashes. UUID(uint64_t high, uint64_t low) now rejects the empty value as well as the deleted value. Code that needs "no UUID" must use Markable<WTF::UUID> or std::optional<WTF::UUID>. createVersion4(), createVersion4Weak(), createVersion5(), parse(), parseVersion4() and toString() do not change. https://bugs.webkit.org/show_bug.cgi?id=323944
  • a371ed3141 A caller can no longer construct a WTF::UUID from raw bits. UUID(std::span<const uint8_t, 16>) and UUID(UInt128) become private. UUID(std::span<const uint8_t>) and UUID(uint64_t, uint64_t) are removed. New factories replace them. static std::optional<UUID> tryCreate(std::span<const uint8_t>) returns std::nullopt if the size is not 16 or the value is reserved (0 or 1). static std::optional<UUID> tryCreate(uint64_t high, uint64_t low) does the same for two halves. static consteval UUID createConstant(uint64_t high, uint64_t low) is for hardcoded constants, and a reserved value is a compile error. The static UUID::isValid(uint64_t, uint64_t) is removed, and the member isValid() stays. The only raw constructor call in JSC (jscJITNamespace in jit/ExecutableAllocator.cpp, under HAVE(KDEBUG_H)) moves to createConstant(). The random, parse and string functions do not change. A caller that only uses createVersion4(), createVersion4UUIDString(), parse() or toString() needs no edit. https://bugs.webkit.org/show_bug.cgi?id=324032
  • 2d4a4717af wtf/UUID.h gains the struct UUIDCanonicalForm (two uint64_t fields, high and low) and StringTypeAdapter<UUIDCanonicalForm>. The adapter holds the 8-4-4-4-12 lowercase hex layout. StringTypeAdapter<UUID> now derives from it and passes uuid.high() and uuid.low(). The output of makeString(uuid) does not change. The only new user is the FIDO AAGUID logging in WebKit. No caller edit is needed. https://bugs.webkit.org/show_bug.cgi?id=324075
  • 6103d1b95a makeStringByJoining(std::span<const String>, const String& separator) is now makeString(interleave(strings, separator)). The old loop used StringBuilder::isEmpty() to detect the first element. So it dropped each separator that came before the first non-empty string. { "", "a" } joined with "\n" gave "a", and it now gives "\na". Null strings count as empty strings. Input with no empty or null element at the start gives the same result as before. An empty span still gives an empty string that is not null. A caller that relied on the dropped separators sees different output. https://bugs.webkit.org/show_bug.cgi?id=323919
  • 4a94df6096 wtf/Assertions.h gains RELEASE_ASSERT_WITH_UNQUALIFIED_FUNCTION_NAME(assertion, ...) and CRASH_WITH_UNQUALIFIED_FUNCTION_NAME_AND_INFO(...). They work like RELEASE_ASSERT and CRASH_WITH_INFO, but they pass __func__ to WTFCrashWithInfo() and not WTF_PRETTY_FUNCTION. In a template, __PRETTY_FUNCTION__ holds the full instantiation, and those strings took much space in the C string table. Upstream measured a 43% smaller C string table in JavaScriptCore (macOS, release, no LTO). With ASSERT_ENABLED the new macro is a plain ASSERT. HashTable::validateKey(), the downcast<>() overloads in TypeCasts.h, Ref.h and RefPtr.h, and the vtable check that CodeGeneratorJS.pm emits now use it. Only the function name in the crash record changes. The new crash macro has its own #ifndef guard, like CRASH_WITH_INFO. No caller edit is needed. https://bugs.webkit.org/show_bug.cgi?id=322851
  • 50c3a2fbf3 ASCIILiteral::isEmpty() is now constexpr. No caller edit is needed. https://bugs.webkit.org/show_bug.cgi?id=323911

Runtime and builtins

  • 223bd0faee ArrayBuffer.prototype.resize and SharedArrayBuffer.prototype.grow now convert the new length with toIndex. The old code used ToIntegerOrInfinity and a cast to size_t, which was undefined for a value such as 1e20. A negative length or a length above 2^53 - 1 now throws RangeError before the detached check. So detached.resize(-1) throws RangeError where it threw TypeError before. https://bugs.webkit.org/show_bug.cgi?id=323440 https://bugs.webkit.org/show_bug.cgi?id=323441
  • c194b75cde speculationFromString() (bytecode/SpeculatedType.h, used by the @idWithProfile bytecode intrinsic) now takes a StringView and looks the name up in a SortedArrayMap. The old code took a const char* and ran a chain of strncmp prefix tests. An unknown name still hits a RELEASE_ASSERT. The rest of the commit is review follow-up for 7bd7b6dfad in the Wasm debugger tests. https://bugs.webkit.org/show_bug.cgi?id=323841
  • 9e61914f4c runtime/JSBigInt.cpp moves bounds checks out of inner loops, so that the hardened std::span checks do not emit a trap inside the loop. karatsubaStart(), divideSchoolbook(), spanCopy(), leftShift(), rightShift(), cachedModMakeInverse(), toStringGeneric() and truncateToNBits() get one RELEASE_ASSERT or one subspan up front. divideSchoolbook() now works on a window of n + 1 digits per quotient digit. JSBigInt::createFrom(JSGlobalObject*, double) turns two exponent ASSERTs into one RELEASE_ASSERT. Results do not change. The change is for speed only and follows 320745@main. https://bugs.webkit.org/show_bug.cgi?id=323899

Garbage collector and heap

  • f6b9f5b24d Structure::flattenDictionaryStructure() could deadlock against the collector. When it flattens an uncacheable dictionary and the out-of-line capacity shrinks, it holds the cell lock of the object (JSCellLock). It then took m_lock with a GCSafeConcurrentJSLocker, which contains a DeferGC. That locker is destroyed before the cell lock is released. So a deferred collection could start while the mutator still held the cell lock. The collector takes the same cell lock to scan an ArrayStorage butterfly, and never gets it. The fix puts one DeferGC before the cell locker, so the collection runs after both locks are released. m_lock is now taken with a plain ConcurrentJSLocker, and JSObject::shiftButterflyAfterFlattening() takes const ConcurrentJSLocker&. A program can hit this when it flattens such an object while a collection is due. Upstream calls it extremely rare. https://bugs.webkit.org/show_bug.cgi?id=323913

RegExp (Yarr)

  • e19f57a779 RegExp::deleteCode() no longer clears m_atom and m_specificPattern. They depend only on the pattern, like m_numSubpatterns. RegExpCachedResult::lastResult() reads RegExp::atom() to reify the position of a cached one-character global match. After VM::deleteAllCode() cleared the atom, it searched for U+0000. So RegExp.leftContext, RegExp.rightContext and RegExp.lastMatch could be wrong, and a debug build asserted. Bun calls deleteAllCode on hot reload and when a debugger attaches. https://bugs.webkit.org/show_bug.cgi?id=323838

JIT (B3, Air, DFG, FTL, LLInt)

  • 41ec81351b B3 LowerToAir matches Mul(Neg(n), m) and Mul(n, Neg(m)) and emits one MultiplyNeg (ARM64 MNEG / FNMUL) when the Neg has no other user. This is the shape -n * m parses to. The floating point form emitted fneg plus fmul before. Upstream measured about 1.5x on the mul-negated-operand-chain microbenchmark. x86_64 has no such instruction form and sees no change. https://bugs.webkit.org/show_bug.cgi?id=323150
  • 5e03b0c541 Air::allocateStackByGraphColoring no longer walks every instruction in each liveness pass. One forward pass collects the stack slot mentions, the dead store candidates and the coalescable moves into a flat array per block (StackSlotActions). The liveness fixpoint and the interference build then step over these actions only. Upstream measured that about 7% of the instructions in a large sqlite3 Wasm function touch a spill slot. The phase now takes about half the time. The allocation result is the same. The WTF::Liveness adapter contract (wtf/Liveness.h) gains ActionGroup, forEachActionGroupDescending(), forEachUseInGroup(), forEachDefInGroup() and forEachUseAtTail(). Liveness gains the public Workset, makeWorkset() and copyLiveAtTailInto(). Air::StackSlotLivenessAdapter and the Air::StackSlotLiveness typedef leave AirLivenessAdapter.h and AirLiveness.h and become private to the phase. This is compile time only, for the B3 clients (FTL and Wasm OMG). https://bugs.webkit.org/show_bug.cgi?id=323526
  • b9c0ed5b8c LLInt slow paths change how they report a pending exception to the 64-bit interpreter. A slow path that throws still sets pc to the returnToThrow() sentinel. It now also returns the new LLInt::exceptionSignal() (all ones) in the second result register. It returned nullptr (LLIntSlowPaths.cpp) or the call frame (CommonSlowPaths.cpp) there before. restoreStateAfterCCall() in LowLevelInterpreter64.asm tests r1 for -1 and jumps to _llint_throw_from_slow_path_trampoline. The old code always rebuilt PC as r0 - PB and dispatched to the sentinel instruction. The sentinel lives in a different allocation from the instructions of the CodeBlock, so the two pointers have different MTE tags. On architectures with CPA2 support, the PC rebuild from these two pointers fails. LLINT_THROW, LLINT_CHECK_EXCEPTION, THROW and CHECK_EXCEPTION use the new convention. slow_path_handle_exception keeps the old return value, because the throw trampoline calls it. The prologue stack check tests r1 before it rebuilds PC. The two checkpoint OSR exit trampolines and the array sort comparator trampoline call branchIfException first. They then use the new macro restoreStateAfterCCallWithoutExceptionCheck(). The new path is active on every 64-bit LLInt build, not only on MTE hardware. Opcodes and bytecode layout do not change. https://bugs.webkit.org/show_bug.cgi?id=323984

WebAssembly

  • 0d81375a0f JSWebAssemblyArray::fill of reference elements stores through the new gcSafeMemfill() (heap/GCMemoryOperations.h, next to gcSafeZeroMemory) and then runs one write barrier, like array.copy. The old loop of plain stores could be lowered to sub-8-byte writes, and the concurrent marker could read a torn value. https://bugs.webkit.org/show_bug.cgi?id=323628
  • 0a09c02240 operationWasmArrayFillRefs (called from BBQ and OMG code) also uses gcSafeMemfill(). It used a loop of volatile uint64_t stores before, which was already safe against the concurrent marker. On x86_64 and ARM64, gcSafeMemfill() uses vector stores for the bulk and 8-byte stores for the tail. The JSWebAssemblyArray constructor keeps std::ranges::fill, because the cell is not visible to the marker before finishCreation. https://bugs.webkit.org/show_bug.cgi?id=323865
  • 92a274ec73 The Wasm debugger BreakpointManager stores Ref<Breakpoint> in its map and returns RefPtr<Breakpoint>, so a breakpoint pointer no longer goes stale when the map rehashes. Breakpoint becomes ThreadSafeRefCounted. Debugger only. https://bugs.webkit.org/show_bug.cgi?id=323910
  • e00002d2d8 Wasm debugger in IPInt. A breakpoint replaces the first byte of an instruction with unreachable. On resume the interpreter read the byte at PC again. So a resume with the patch still in place trapped at the same PC without end. handle_debugger_trap_if_needed now returns the displaced opcode (Wasm::OpType), and the new asm macro dispatchIPIntOpcode() dispatches it. It returned a boolean shouldThrow before. A return value of 0 (Unreachable) throws the trap, which is also the result when the debugger is off. BreakpointManager now keys breakpoints by physical PC and counts references to the patch. A z0 packet for an address with no site replies OK and no longer hits a RELEASE_ASSERT. Debugger only (ENABLE(WEBASSEMBLY_DEBUGGER) and Options::enableWasmDebugger()). https://bugs.webkit.org/show_bug.cgi?id=323845
  • c3a249e707 The Wasm debugger now puts the instance ID, and not the module ID, in both halves of its 64-bit virtual address (wasm/debugger/WasmVirtualAddress.h). Each live instance gets its own library entry (<name>@<id>), module image and linear memory region in LLDB. IDs are never reused, and encode() release-asserts instanceId <= MAX_ID (30 bits). A breakpoint site belongs to one instance. A sibling instance that reaches the same patched byte resumes through it and reports no stop. Wasm::Module no longer registers itself with DebugServer. trackModule(), untrackModule(), Module::debugId() and Module::setDebugId() are removed. Debugger only. https://bugs.webkit.org/show_bug.cgi?id=323479

Inspector and debugger

  • c4a7ebcc29 Network.setEmulatedConditions changes its parameters. The optional integer bytesPerSecondLimit is renamed to bandwidth (bytes per second). A new optional integer latency adds a round-trip delay in milliseconds to each request. No command, event or type is added. The command stays behind ENABLE_INSPECTOR_NETWORK_THROTTLING, and wtf/PlatformEnableCocoa.h now sets that flag to 1 (it was 0). Only that Cocoa header defines the flag, so other ports do not generate the command. The implementation is a throttle in the WebKit network process, outside JSC. A backend that implements Network.setEmulatedConditions itself must read the new parameter names. https://bugs.webkit.org/show_bug.cgi?id=287737

WTF and bmalloc

  • 86f52ba2f2 libpas: pas_runtime_config::enabled (MTE enablement, a bool where 0 meant either "not initialized" or "off") becomes the tri-state mte_state. pas_mte_is_mte_enabled() is now an inlineable relaxed load. It falls back to the renamed pas_mte_is_mte_enabled_slow() only when the state is not initialized. By default MTE is compiled in only with the Apple internal SDK on arm64e. https://bugs.webkit.org/show_bug.cgi?id=323820
  • 50320fd3b3 wtf/MathExtras.h gains absoluteValueAsUnsigned(), an abs that is defined for the most negative value of a signed type. The only adopter is WebCore. https://bugs.webkit.org/show_bug.cgi?id=257369
  • 00991b6cdc wtf/text/CString.h includes <objc/objc.h> and <wtf/RetainPtr.h> under __OBJC__. 25f7ce345a added CStringWithEncoding::createNSString() without them. This affects Objective-C++ translation units only. https://bugs.webkit.org/show_bug.cgi?id=324080

Build system and platform

  • b1865b2d63 Swift compiler flags for CMake move from OptionsCocoa.cmake and WebKitMacros.cmake into a new Source/cmake/WebKitSwiftFlags.cmake and are aligned with the Xcode build. Swift targets only. https://bugs.webkit.org/show_bug.cgi?id=322750
  • bc5bc3c2d6 WebKitMacros.cmake normalizes MSVC-style /D definitions to -D when it forwards them to the Swift clang importer on Windows. Swift targets only. https://bugs.webkit.org/show_bug.cgi?id=323791
  • 9bf932afff 62f9b5cd08 67f2974594 The first commit makes the CMake Cocoa ports build a WebKit that can be installed on a device. It adds dylibs for libwebrtc and ANGLE, XPC service bundles, entitlements and daemons. The second commit reverts it because it broke the CMake macOS build. The third commit lands it again. In Source/cmake it adds WEBKIT_SDK_IS_IOS and WEBKIT_SDK_IS_XROS to WebKitXcodeSDK.cmake. In OptionsCocoa.cmake it keeps ENABLE_AV1 on for iOS and visionOS. Cocoa ports only, no effect on PORT=JSCOnly. https://bugs.webkit.org/show_bug.cgi?id=323218 https://bugs.webkit.org/show_bug.cgi?id=323942
  • c991f535a7 With USE_APPLE_INTERNAL_SDK, the Swift clang importer gets -I${WebKitAdditions_FRAMEWORK_HEADERS_DIR} and depends on WebKitAdditions_CopyHeaders (WebKitMacros.cmake, WebKitSwiftFlags.cmake). Swift targets only. https://bugs.webkit.org/show_bug.cgi?id=323959
  • bd3aa163c8 OptionsGTK.cmake turns the WebDriver keyboard, mouse and wheel interaction options on by default, also when ENABLE_WEBDRIVER is off. GTK port only. https://bugs.webkit.org/show_bug.cgi?id=318171
  • a761c97f80 The top-level CMakeLists.txt queries swiftc -print-target-info once through the new WEBKIT_QUERY_SWIFT_TARGET_INFO() (WebKitMacros.cmake). On Windows it writes the Swift runtime directory to swift-runtime-bin-directory.txt in the build directory. All of this is inside if (SWIFT_REQUIRED). One line runs without Swift: on WIN32, configure removes that file from the build directory with file(REMOVE). https://bugs.webkit.org/show_bug.cgi?id=323228
  • ed458bb584 OptionsGTK.cmake and OptionsWPE.cmake require libpng 1.5.0 (find_package(PNG 1.5.0 REQUIRED)). GTK and WPE ports only. https://bugs.webkit.org/show_bug.cgi?id=323961
  • 060527786c OptionsCocoa.cmake drops the block from 67f2974594 that turned ENABLE_AV1 off for tvOS and watchOS. It broke the link of the iOS simulator build. Cocoa ports only. https://bugs.webkit.org/show_bug.cgi?id=324000
  • f45cdb1e65 The CMake option DEVELOPER_MODE_FATAL_WARNINGS is removed. WebKitCompilerFlags.cmake now sets the standard variable CMAKE_COMPILE_WARNING_AS_ERROR to ON when DEVELOPER_MODE is on and the variable is not defined. The old code prepended -Werror or /WX to the global compiler flags. Since 320261@main that flag was not applied in the GTK and WPE builds. The new variable applies to targets and not to compiler feature probes. A build that passed -DDEVELOPER_MODE_FATAL_WARNINGS=OFF must now pass -DCMAKE_COMPILE_WARNING_AS_ERROR=OFF. A build without DEVELOPER_MODE sees no change. The commit also wraps pas_mte_is_mte_enabled_unchecked() (pas_mte_config.c, added by 86f52ba2f2) in #if PAS_ENABLE_MTE || PAS_OS(DARWIN). That removes an unused function warning from libpas builds on other systems. The Swift warning groups NoUsage and NoUseUnstructuredThrowingTask are now fatal only with Swift 6.4 or later. https://bugs.webkit.org/show_bug.cgi?id=323574

WebCore-only or no effect on JSC embedders

The other 169 commits in the range touch WebCore, WebKit, WebGPU, LayoutTests or tooling only.

cdumez and others added 30 commits September 9, 2026 21:28
…() call site

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

Reviewed by Darin Adler.

320652@main introduced CStringWithEncoding (UTF8CString / Latin1CString / ASCIICString) so
that a CString can remember its encoding, and migrated String::ascii(), String::latin1() and
the tryGetUTF8() family. It left utf8() itself returning a plain CString, with a FIXME. The
blocker is not the return type but the accessor: retyping utf8() makes data() return
const char8_t*, which breaks the 2516 call sites that hand utf8().data() to a %s or to a
C API.

This is the mechanical half of that migration, split out so that the patch which actually
retypes utf8() is small enough to read. No type changes and no behavior change here.

CString gains legacyCStringPointer(), which returns data() as a const char*. It is the
accessor that keeps returning const char* once utf8() starts returning UTF8CString, so every
utf8().data() call site is moved to utf8().legacyCStringPointer() now, while the two
spellings are still equivalent and the rename is a no-op.

The name is deliberately not characters(). Half of these call sites are printf-style format
strings and half are external C entry points, and for UTF-8 a char is a byte of a multi-byte
sequence rather than a character, so characters() would be both vague and wrong at exactly
the sites adopting it. Naming the destination instead of the contents also explains why the
return type is const char* and not the char8_t that would otherwise be correct for UTF-8:
const char* is what C string interfaces take. It reads as intended at a %s or a
WKURLCreateWithUTF8CString() argument and as misuse anywhere the result is stored, compared
or iterated. The accessor CStringWithEncoding already had is renamed to match, since the two
have to share a name for the Latin-1 exclusion below to keep working.

Latin1CString still does not offer legacyCStringPointer(), and that is worth stating
explicitly now that the base class has one: CStringWithEncoding declares its own, constrained
to exclude Latin1Character, and that declaration exists in the instantiated class whether or
not its constraint is satisfied, so it hides CString::legacyCStringPointer() and lookup never
reaches the base. New static_asserts pin this down, since it has become a property of two
classes rather than one. Getting bytes out of a Latin1CString still means slicing to CString
or byteCast<char>(span()), exactly as before.

Canonical link: https://commits.webkit.org/320795@main
https://bugs.webkit.org/show_bug.cgi?id=322750
rdar://185773011

Reviewed by Elliott Williams.

Create a new `WebKitSwiftFlags.cmake` file to centralize all the flags as much as possible,
similar to Xcode's CommonBase.xcconfig. Also add some missing flags to be more consistent with Xcode.

* Source/WebCore/PAL/pal/CMakeLists.txt:
* Source/WebGPU/WebGPU/CMakeLists.txt:
* Source/WebKit/CMakeLists.txt:
* Source/WebKit/PlatformCocoa.cmake:
* Source/cmake/OptionsCocoa.cmake:
* Source/cmake/WebKitCommon.cmake:
* Source/cmake/WebKitMacros.cmake:
* Source/cmake/WebKitSwiftFlags.cmake: Added.
* Tools/TestWebKitAPI/PlatformCocoa.cmake:

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

Reviewed by Simon Fraser.

ASSERTION FAILED: stdDeviation.width() >= 0 && stdDeviation.height() >= 0
Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp(114)

A negative stdDeviation turns a filter primitive off, but outsets() did not
check for it and passed the value on to calculateOutsets(), which asserts.

While this was discovered during LBSE testing, it is reproducible with
plain CSS reference filters too - so add a new reftest to cover this.

* LayoutTests/css3/filters/effect-reference-negative-deviation-expected.html: Added.
* LayoutTests/css3/filters/effect-reference-negative-deviation.html: Added.
* Source/WebCore/svg/SVGFEDropShadowElement.cpp:
(WebCore::SVGFEDropShadowElement::outsets const):
* Source/WebCore/svg/SVGFEGaussianBlurElement.cpp:
(WebCore::SVGFEGaussianBlurElement::outsets const):

Canonical link: https://commits.webkit.org/320797@main
https://bugs.webkit.org/show_bug.cgi?id=323790
rdar://186773323

Reviewed by Yijia Huang.

"collectOnAlternateThread" is a debugging helper function exposed in
DumpRenderTree / WebKitTestRunner. But its implementation and feature is
broken: we cannot run GC from random alternate thread, and this never
happens. This patch removes this helper function and also removes broken
test, which is already skipped.

* LayoutTests/TestExpectations:
* LayoutTests/fast/dom/gc-8-expected.txt: Removed.
* LayoutTests/fast/dom/gc-8.html: Removed.
* Source/WebCore/bindings/js/GarbageCollectionController.cpp:
(WebCore::GarbageCollectionController::gcTimerFired):
(WebCore::collect): Deleted.
(WebCore::GarbageCollectionController::garbageCollectOnAlternateThreadForDebugging): Deleted.
* Source/WebCore/bindings/js/GarbageCollectionController.h:
* Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundle.cpp:
(WKBundleGarbageCollectJavaScriptObjectsOnAlternateThreadForDebugging): Deleted.
* Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePrivate.h:
* Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.cpp:
(WebKit::InjectedBundle::garbageCollectJavaScriptObjectsOnAlternateThreadForDebugging): Deleted.
* Source/WebKit/WebProcess/InjectedBundle/InjectedBundle.h:
* Source/WebKitLegacy/mac/Misc/WebCoreStatistics.h:
* Source/WebKitLegacy/mac/Misc/WebCoreStatistics.mm:
(+[WebCoreStatistics garbageCollectJavaScriptObjectsOnAlternateThreadForDebugging:]): Deleted.
* Tools/DumpRenderTree/GCController.cpp:
(GCController::createJSClass):
(collectOnAlternateThreadCallback): Deleted.
* Tools/DumpRenderTree/GCController.h:
* Tools/DumpRenderTree/mac/GCControllerMac.mm:
(GCController::collectOnAlternateThread const): Deleted.
* Tools/WebKitTestRunner/InjectedBundle/Bindings/GCController.idl:
* Tools/WebKitTestRunner/InjectedBundle/GCController.cpp:
(WTR::GCController::collectOnAlternateThread): Deleted.
* Tools/WebKitTestRunner/InjectedBundle/GCController.h:

Canonical link: https://commits.webkit.org/320798@main
…io:completionHandler:]

https://bugs.webkit.org/show_bug.cgi?id=323772
rdar://187034277

Reviewed by Elliott Williams and Jer Noble.

Removed staging code for -setDisconnectedFromSystemAudio:completionHandler: now that the method is
in the Public iOS 27-family SDKs. Also removed the call to
-setParticipatesInAudioSession:completionHandler:, which was an old name for the method that
ultimately became Public API. Moved the definition of HAVE_AVPLAYER_DISCONNECTEDFROMSYSTEMAUDIO to
PlatformHave.h.

* Source/WTF/wtf/PlatformHave.h:
* Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
* Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
(WebCore::MediaPlayerPrivateAVFoundationObjC::createAVPlayer):
(WebCore::MediaPlayerPrivateAVFoundationObjC::updateIsAudible):
(WebCore::MediaPlayerPrivateAVFoundationObjC::setParticipatesInAudioSession): Deleted.

Canonical link: https://commits.webkit.org/320799@main
…ings

https://bugs.webkit.org/show_bug.cgi?id=323842
rdar://187081643

Unreviewed re-land of 320700@main.

Test: Tools/TestWebKitAPI/Tests/WebKit/WebPage/WebPageTests.swift

* Source/WebKit/UIProcess/API/Cocoa/_WKTextExtractionInternal.h:
* Source/WebKit/UIProcess/WebBackForwardList.swift:
(Direction.pageClosed):
(Direction.currentItem):
(Direction.backItem):
(Direction.forwardItem):
(Direction.itemAtDeltaFromCurrentIndex(_:allowSkipping:)):
(Direction.itemAtIndexWithoutSkipping(_:index:)):
(Direction.rawBackListEntryCount):
(Direction.rawForwardListEntryCount):
(Direction.backListCountForAPI):
(Direction.forwardListCountForAPI):
(Direction.backListAsAPIArrayWithLimit(_:)):
(Direction.forwardListAsAPIArrayWithLimit(_:)):
(Direction.backListWithLimitInternal(_:makeAPIArray:array:)):
(Direction.forwardListWithLimitInternal(_:makeAPIArray:array:)):
(Direction.backForwardListState(_:)):
(Direction.goBackItemSkippingItemsWithoutUserGesture):
(Direction.goForwardItemSkippingItemsWithoutUserGesture):
(Direction.backForwardUpdateItem(_:frameState:)):
(MakeAPIArray.backListCountForAPI): Deleted.
(MakeAPIArray.forwardListCountForAPI): Deleted.
(MakeAPIArray.rawCounts): Deleted.
(MakeAPIArray.backListAsAPIArrayWithLimit(_:)): Deleted.
(MakeAPIArray.forwardListAsAPIArrayWithLimit(_:)): Deleted.
(MakeAPIArray.backListWithLimitInternal(_:makeAPIArray:array:)): Deleted.
(MakeAPIArray.forwardListWithLimitInternal(_:makeAPIArray:array:)): Deleted.
(MakeAPIArray.removeAllItems): Deleted.
(MakeAPIArray.clear): Deleted.
(MakeAPIArray.backForwardListState(_:)): Deleted.
(MakeAPIArray.restoreFromState(_:)): Deleted.
(MakeAPIArray.setItemsAsRestoredFromSession): Deleted.
(MakeAPIArray.setItemsAsRestoredFromSessionIf(_:)): Deleted.
(MakeAPIArray.didRemoveItem(_:)): Deleted.
(MakeAPIArray.goBackItemSkippingItemsWithoutUserGesture): Deleted.
(MakeAPIArray.goForwardItemSkippingItemsWithoutUserGesture): Deleted.
(MakeAPIArray.loggingString): Deleted.
(MakeAPIArray.addChildItem(_:frameState:)): Deleted.
(MakeAPIArray.setBackForwardItemIdentifier(_:itemID:)): Deleted.
(MakeAPIArray.completeFrameStateForNavigation(_:)): Deleted.
(MakeAPIArray.messageCheckItemURLs(_:process:)): Deleted.
(MakeAPIArray.setHandlingProvisionalMessage(_:)): Deleted.
(MakeAPIArray.backForwardAddItem(_:navigatedFrameState:)): Deleted.
(MakeAPIArray.backForwardClearChildren(_:frameItemID:)): Deleted.
(MakeAPIArray.backForwardUpdateItem(_:frameState:)): Deleted.
(MakeAPIArray.updateFrameIdentifier(_:newFrameID:)): Deleted.
(MakeAPIArray.backForwardGoToItem(_:)): Deleted.
(MakeAPIArray.backForwardGoToItemShared(_:)): Deleted.
(MakeAPIArray.frameStates): Deleted.
* Source/WebKit/UIProcess/mac/WKTextSelectionController.h:
* Tools/TestWebKitAPI/Helpers/cocoa/TestPDFDocument.h:
* Tools/TestWebKitAPI/Tests/WebKit/WebPage/WebPageTests.swift:
(WebPageTests.qualifiedServerTrust):

Canonical link: https://commits.webkit.org/320800@main
https://bugs.webkit.org/show_bug.cgi?id=323713
rdar://186968646

Reviewed by Michael Catanzaro and Kimmo Kinnunen

Contains upstream commits:
9d57491334bd Vulkan: Check sdk version for Xclipse devices
375920dad65a Fix export_targets.py assertion for explicit context header
1623db027d51 D3D11: Support RGB10A2 uploads to RGB565 fallback
3a07a85bfc96 Presubmit: Ignore guarded Linux window system include
4cd68cf087a3 GL: Avoid glGetBoolean[i_]v for state queries
4b61de64bab8 Roll vulkan-deps from ab1905c50690 to c0a49d78df1b (16 revisions)
b4e56ad58508 Roll Chromium from 1a43f66e2237 to f9235f771bfe (822 revisions)
80760643c85e Trace/Replay: Fix CSV shift after vk_api_wall_time
ce15aa87fc1e Skip flaky test on CI
7db9cb197c57 Roll Chromium from 0aec806e5634 to 1a43f66e2237 (529 revisions)
8983f40bc8ef GL: Recreate texture on glTexImage3D with increased depth
897bad1f41b2 Roll vulkan-deps from e875a3c61231 to ab1905c50690 (12 revisions)
6f066af1045b Add //third_party/protobuf/* to include_blocklist
c477cf31f7a9 D3D: Reject out-of-storage mip levels in completeness check
705ec1dcafff Roll chromium_revision cc17ba5f60..0aec806e56
580b6200fa52 Trace/Replay: Ignore side-context swaps
7869600a6dad Roll vulkan-deps from 39a28466f653 to e875a3c61231 (3 revisions)
204fa645c41b Add profileable android:shell="true" in ANGLE Test APK
b0a8d52989e9 Traces: Upgrade cut_the_rope
37ebded9db31 Traces: Upgrade pubg_mobile_battle_royale
33d8f1915df0 Traces: Upgrade pubg_mobile_skydive
702bda8cd924 Traces: Upgrade pokemon_go
6cac303f1a8f EGL: disable robust buffer access on Xclipse GPUs.
fd41483fbbfe Skip the timeout test on CI
2334d1b43be3 Revert "Put paletted texture formats at end of list."
a26ea0324a4c Translator: Fix sampler-rewrite making fields struct specifier
6540ea90ae98 Translator: Hard code user symbol prefixes again
87f5655006e4 GL: Apply reattachTextureToFboAfterLayerIncrease to TexStorage3D
78f42c860864 Roll vulkan-deps from 1d696389f66f to 39a28466f653 (4 revisions)
35c006a36fe9 Metal: Further signed int emulation implementation
f3b3ab6b3a40 Roll Chromium from ee6be91f251b to cc17ba5f6011 (847 revisions)
c5d7b1561c88 SPIR-V: Count non-opaque default uniforms directly
27b11fa0fa76 A handful of tricky nameless struct tests
4d8cb8a1a37c Roll Chromium from 9bf510cf5d65 to ee6be91f251b (649 revisions)
94af7869e6cd Add EGLDisplayTest.TerminateMultipleTimesInDifferentThreads
7e5d4a2f9d95 [tracing] Clean up legacy Perfetto tracing macros in angle
dbf4a195af9b Register ANGLE's track event categories with Perfetto
7f603b35e9e5 OpenCL: treat extern mem handle as integral
3aaf5212db09 Traces: Upgrade trace pack 2 for merged attribs
865d6604cf33 Vulkan: Unregister Wayland resize callback on teardown
7ae3dcf83710 Remove CPython from CIPD DEPS entry
90d3b16ba057 Fix interleaved analysis script bugs
046e6dfc215e GL: Fix querying polygon mode states
406c9799848b [DEPS] Add CPython CIPD package for hermetic Python toolchain
b10b5403b57b Roll vulkan-deps from 7947c99db1dc to 1d696389f66f (4 revisions)
a871bdb05932 D3D11: Fix use-after-free when redefining 2D array mip levels
0bee6bcfd4bd Vulkan: Avoid redundant read render target updates
3b227cfe0665 Skip flaky tests: R4G4B4A4_CubeTexImageRedefinedFace*
5ff3c3731a05 VK: End the active render pass if a draw attachment is cleared
b5e087aaabc6 Traces: Fix merging client array ranges of size 0
03562bc68c9f Improve UpdateUniformLocation() for upgrades
5be98c8a815c OpenCL: introduce RefPointer::Create
48739e490fbc CL/Vulkan: Arrange the device caps into categories
b27a30a81375 OpenCL: Move spv reflection-parse/stripping to clspv_utils
c9ec7a65ccde Manual roll Chromium from ab310674f018 to 9bf510cf5d65 (971 revisions)
c93844c75789 OpenCL: ValidateSetContextDestructorCallback handle invalid vals
f78f99f32f93 Roll vulkan-deps from 3956868af9e3 to 7947c99db1dc (19 revisions)
9ddc6e36c1fa GL: Use correct local dirty bit for blend equations
60ccf9a219bd Skip AdvancedBlendTest.NonZeroDrawBufferDisallowed on NVIDIA/GL
aa192212af54 IR: Validate matrix packing decorations
651089f2f55b D3D11: Fix crash and garbage readbacks on incomplete levels
fa5faa59766d Reenable treat_warnings_as_errors on MSVC builds
e0bfd7935f82 Roll chromium_revision aa9b74792a..ab310674f0
926e78c4192a OpenCL: Disable #pragma messages in angle_trace_fixture_cl
e4499e6b2835 Roll vulkan-deps from ed1e17f393a0 to 3956868af9e3 (10 revisions)
fff51488e419 Traces: Upgrade trace pack 1 for merged attribs
fcf0b69e5fb9 Vulkan: Fix MSVC C4002 warning in perf counter macros
cf00aa7716b5 Replace chromium perfetto dependencies with Android perfetto
a97b01bf5c78 OpenCL: Fix pragma message disable for Loader
3456dd90b777 Revert "Update Thread current context after Context::makeCurrent"
0fd366d3e5ee Vulkan external image import uses actual formatID
6579aef92ac9 Roll vulkan-deps from 34c46f7241a1 to ed1e17f393a0 (23 revisions)
7e8009eb2c42 OpenCL: Augment Device::IsValidType to handle invalid value
2f30d621a413 CL/VK: Fix test_kernel_image_methods failures for 1Dbuffer
5677218f9761 Unify X11/Wayland backend selection on Ozone/Linux
ae89e236c811 Add nullptr check for samplerParameter
346836afa5ce GN: Move angle_perfetto_cpp_dir to overrides
1a9482d28e0d Revert "Vulkan: Never emulate uint8 indices"
e0ca05c106e4 GL: Fix binding offset query on ES3.
8a3236460e4a OpenCL: Disable #pragma messages
25c2b6e85402 CL/VK: Enable Enqueue Calls for 1D Image From Buffer
a6e223f244f7 CL: Add additional checks on image flags to ValidateSetKernelArg
9997cb1dcf63 OpenCL: header cleanups sweep
1472b329259f D3D: Use common struct sampler rewriting for HLSL
4d87f08db6a9 CL/Vulkan: Report max alloc size with in spec bounds
1aaed28f5183 Translator: Don't apply row-major where not applicable
5295eb22f568 Vulkan: Preserve staged updates during format fallback
a705032c268a GL: Update VAO index buffer binding in StateManagerGL.
36e7fe4cfe62 Allow MSVC builders to use e4 instances
254d4e24ab9b Lose context on backend error if hardened
c7e5a77b65ae Automatically mark webgl contexts as hardened
7d95ab937fc3 Make sure WebGL1-specific extensions are not exposed in WebGL2
00f3b2b1732e Roll vulkan-deps from 37e841bbd2f9 to 34c46f7241a1 (16 revisions)
f465d6d80df5 Roll SwiftShader from 26e6a4b84daf to 6b8d31709ad1 (1 revision)

Canonical link: https://commits.webkit.org/320801@main
rdar://186306780
https://bugs.webkit.org/show_bug.cgi?id=323122

Reviewed by Elliott Williams.

tvOS doesn't ship libxslt or a few private frameworks (FontParser, IOKit)
that WebKit needs, so building against the public tvOS 27 SDK fails.
This adds the additions SDK that symlinks the missing headers in from
macOS and provides stub libraries for the missing frameworks, same
pattern already used for tvOS 26 and iOS 27.

FontParser and IOKit are extracted from the real internal tvOS 27 SDK.
They're the full, unstripped TBDs rather than a minimal symbol subset,
since generating those properly needs a successful WebKit build against
the internal SDK, which I couldn't get working on this machine. Should
be revisited with extract-tbds-from-internal-sdk once that's sorted out.

Verified with a full local build against the public tvOS 27 SDK,
combined with the tvOS-27-Build-EWS UAT fixes: no errors.

* WebKitLibraries/SDKs/appletvos27.0-additions.sdk/SDKSettings.plist: Added.
* WebKitLibraries/SDKs/appletvos27.0-additions.sdk/SymlinkedHeaders.xcfilelist: Added.
* WebKitLibraries/SDKs/appletvos27.0-additions.sdk/SymlinkedHeaders-output.xcfilelist: Added.
* WebKitLibraries/SDKs/appletvos27.0-additions.sdk/System/: Added.

Canonical link: https://commits.webkit.org/320802@main
…rror-prone

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

Reviewed by Yusuke Suzuki.

Make the String(std::span<const char>) constructor private as it is error-prone.
Instead, force callers to be explicit about the encoding of the characters they
are passing in.

* Source/JavaScriptCore/jsc.cpp:
(JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp:
(JSC::Profiler::OSRExit::toJSON const):
* Source/JavaScriptCore/runtime/IntlCollator.cpp:
(JSC::IntlCollator::sortLocaleData):
* Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp:
(JSC::IntlDateTimeFormat::localeData):
* Source/JavaScriptCore/runtime/IntlDisplayNames.cpp:
(JSC::IntlDisplayNames::of const):
* Source/JavaScriptCore/runtime/IntlLocale.cpp:
(JSC::IntlLocale::language):
(JSC::IntlLocale::script):
(JSC::IntlLocale::region):
(JSC::IntlLocale::calendars):
(JSC::IntlLocale::collations):
(JSC::IntlLocale::timeZones):
* Source/JavaScriptCore/runtime/IntlObject.cpp:
(JSC::languageTagForLocaleID):
(JSC::defaultCalendarForLocale):
(JSC::availableCollations):
(JSC::availableCurrencies):
(JSC::availableNumberingSystems):
* Source/JavaScriptCore/runtime/IntlPluralRules.cpp:
(JSC::IntlPluralRules::resolvedOptions const):
* Source/JavaScriptCore/runtime/JSONObject.cpp:
(JSC::gap):
* Source/JavaScriptCore/runtime/NumberPrototype.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/tools/FunctionAllowlist.cpp:
(JSC::FunctionAllowlist::FunctionAllowlist):
* Source/JavaScriptCore/tools/FunctionOverrides.cpp:
(JSC::parseClause):
* Source/WTF/wtf/UUID.cpp:
(WTF::bootSessionUUIDString):
* Source/WTF/wtf/text/WTFString.cpp:
* Source/WTF/wtf/text/WTFString.h:
* Source/WebCore/page/Quirks.cpp:
* Source/WebCore/platform/graphics/cocoa/FontPlatformDataCocoa.mm:
(WebCore::FontPlatformData::variationAxes const):
* Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.cpp:
(WebCore::WebMParser::OnTrackEntry):
* Source/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp:
(WebCore::FontPlatformData::variationAxes const):
* Source/WebCore/platform/graphics/skia/FontPlatformDataSkia.cpp:
(WebCore::FontPlatformData::variationAxes const):
* Source/WebCore/platform/libwpe/PlatformPasteboardLibWPE.cpp:
(WebCore::PlatformPasteboard::getTypes const):
(WebCore::PlatformPasteboard::readString const):
* Source/WebCore/platform/network/HTTPHeaderMap.cpp:
(WebCore::HTTPHeaderMap::set):
* Source/WebKit/NetworkProcess/webrtc/NetworkRTCMonitor.cpp:
(WebKit::NetworkRTCMonitor::gatherNetworkMap):
* Source/WebKit/NetworkProcess/webtransport/cocoa/NetworkTransportSessionCocoa.mm:
(WebKit::NetworkTransportSession::initialize):
* Source/WebKit/Platform/IPC/MessageReceiverMap.cpp:
(IPC::MessageReceiverMap::invalidate):
* Source/WebKit/Shared/RTCNetwork.cpp:
(WebKit::WebRTCNetwork::SocketAddress::SocketAddress):
* Source/WebKit/UIProcess/Launcher/glib/FlatpakLauncher.cpp:
(WebKit::flatpakSpawn):
* Source/WebKit/UIProcess/mac/WebViewImpl.mm:
(WebKit::commandNameForSelector):
* Source/WebKit/WebProcess/Network/webrtc/LibWebRTCResolver.cpp:
(WebKit::LibWebRTCResolver::start):
* Source/WebKitLegacy/mac/WebView/WebHTMLView.mm:
(commandNameForSelector):
* Tools/TestWebKitAPI/Helpers/cocoa/HTTPServer.mm:
(TestWebKitAPI::parseHeaderValue):
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/EventAttribution.mm:
(TestWebKitAPI::signUnlinkableTokenAndSendSecretToken):
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/ServiceWorkerBasic.mm:
((ServiceWorker, ExtensionServiceWorkerDisableCORS)):
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKWebViewConfiguration.mm:
(TEST(WebKit, OverrideReferrer)):

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

Reviewed by Adrian Taylor.

The Swift Clang importer must use the same preprocessor definitions as C++
translation units. The helper that collects definitions from CMake compiler
flags recognizes GCC-style -D options, but Windows CMake flags use MSVC-style
/D options. This drops NDEBUG from Windows Release Swift imports and gives
Swift and C++ incompatible views of assertion-dependent types.

Recognize both attached and separated /D options and normalize them to -D
before forwarding them to the importer.

* Source/cmake/WebKitMacros.cmake:
(_webkit_cxx_preprocessor_definitions):

Canonical link: https://commits.webkit.org/320804@main
https://bugs.webkit.org/show_bug.cgi?id=322709
rdar://185974109

Reviewed by Mike Wyrzykowski.

FontCascade would use ScopedTextMatrix get and restore the TextMatrix
CGContext property.
This state is not part of CGContext GState and is generally
modified by CT*Draw commands. As such it cannot be expected to be
saved by the CGContext using functions.

Instead always explicitly set the transform when using CT. Leave the
transform dirty.

Works towards making FontCascadeCoreText platform context property
modifications more consistent. This is needed to make GraphicsContextCG
state application lazy.

* Source/WebCore/platform/graphics/FontCascade.h:
* Source/WebCore/platform/graphics/FontPlatformData.h:
(WebCore::ScopedTextMatrix::savedMatrix const): Deleted.
* Source/WebCore/platform/graphics/cocoa/GraphicsContextCocoa.mm:
(WebCore::GraphicsContext::drawMultiRepresentationHEIC):
* Source/WebCore/platform/graphics/coretext/DrawGlyphsRecorder.cpp:
(WebCore::DrawGlyphsRecorder::prepareInternalContext):
(WebCore::DrawGlyphsRecorder::drawNativeText):
* Source/WebCore/platform/graphics/coretext/FontCascadeCoreText.cpp:
(WebCore::computeTextMatrix):
(WebCore::fillVectorWithHorizontalGlyphPositions):
(WebCore::fillVectorWithVerticalGlyphPositions):
(WebCore::FontCascade::drawGlyphs):
(WebCore::computeOverallTextMatrix): Deleted.
(WebCore::computeVerticalTextMatrix): Deleted.
(WebCore::showGlyphsWithAdvances): Deleted.

Canonical link: https://commits.webkit.org/320805@main
…s not load any PDF content

https://bugs.webkit.org/show_bug.cgi?id=323801
rdar://187047306

Reviewed by Aditya Keerthi and Wenson Hsieh.

This is a follow-up to 320534@main, where we introduced the test. Thes
test initialized a NSURLRequest pointing to the copying-disabled.pdf
resource, but it did not actually _load_ this request, and so the test
was being performed on a blank web view and was passing for the wrong
reasons.

To fix this, we add the missing `-synchronouslyLoadRequest:` call.

* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKWebViewEditActions.mm:
(TestWebKitAPI::TEST(WKWebViewEditActions, CopyMenuItemDisabledInCopyDisallowedPDF)):

Canonical link: https://commits.webkit.org/320806@main
https://bugs.webkit.org/show_bug.cgi?id=323835
rdar://187070154

Reviewed by Abrar Rahman Protyasha.

Expose some existing C++ helpers in Swift.

* Tools/TestWebKitAPI/Helpers/cocoa/CocoaTypes.swift: Added.
* Tools/TestWebKitAPI/Helpers/cocoa/TestPDFDocument.swift:

Expose CocoaColor and CocoaImage type aliases.

* Tools/TestWebKitAPI/Helpers/cocoa/TestCocoa.h:

Ignore this file in Swift because it causes conflicts and is useless too.

* Tools/TestWebKitAPI/Helpers/cocoa/TestCocoaImageAndCocoaColor.mm:
(TestWebKitAPI::Util::pixelColor):
(TestWebKitAPI::Util::compareColors):
* Tools/TestWebKitAPI/Helpers/cocoa/TestCocoaImageUtilities.h: Added.
* Tools/TestWebKitAPI/Helpers/cocoa/TestCocoaImageUtilities.swift: Added.
(Appearance.withAppearance(_:_:)):
(Appearance.makePNGData(_:color:)):
(Appearance.pixelColor(of:at:)):
(Appearance.compareColors(_:_:tolerance:)):
(CocoaImage.isSymbol):
(TestCocoaImageUtilities.pngData(_:color:)):
(TestCocoaImageUtilities.pixelColor(of:at:)):
(TestCocoaImageUtilities.compareColors(_:_:tolerance:)):

Re-implement and expose these functions in Swift.

* Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:

Canonical link: https://commits.webkit.org/320807@main
…the lock the decoding work queue reads them under

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

Reviewed by Jean-Yves Avenard.

createFrameImageAtIndex() runs on AsyncImageDecoder's org.webkit.ImageDecoder work queue and
takes m_sampleGeneratorLock to read m_sampleData, to read and advance m_cursor, and to read and
replace the samples' decoded CGImages. readTrackMetadata() and setTrack() take the same lock to
mutate that state from the main thread. Two other main-thread mutators did not.

readSamples() called m_sampleData.addSample() unlocked, while the work queue searches and
iterates the same SampleMap, which is backed by StdMap; inserting into a red-black tree while
another thread walks it can follow pointers through a rebalance. This was already
self-inconsistent, since setTrack() clears the very same container under the lock twenty lines
earlier.

clearFrameBufferCache() called setImage(nullptr) on each sample unlocked. Since
ImageDecoderAVFObjCSample::image() hands out a raw CGImageRef, createFrameImageAtIndex()'s
"RetainPtr image = sampleData->image()" loads the pointer and retains it in two steps, and this
released it in between, so the work queue could retain and return freed memory. That window is
reachable rather than theoretical: BitmapImageSource::destroyDecodedData() routes to
clearFrameBufferCache() precisely in the branch where the work queue is not known to be idle.

Take m_sampleGeneratorLock in both. readSamples() collects the samples into a Vector first and
inserts them under the lock, so that reading from the AVAssetReader does not block the work
queue, and still fires the encoded-data-status callback outside the lock, since that callback
re-enters BitmapImageSource.

Then annotate the state so this cannot regress. m_sampleData, m_cursor and
m_imageRotationSession are now WTF_GUARDED_BY_LOCK(m_sampleGeneratorLock), and the main thread's
unlocked reads use the assertIsOwnerThread() helpers added in 320637@main. storeSampleBuffer()
and advanceCursor() are only ever called from inside createFrameImageAtIndex()'s critical
section, so they declare WTF_REQUIRES_LOCK rather than locking again. sampleAtIndex() is reached
both from the work queue holding the lock and from the frame-metadata accessors on the main
thread without it, so it requires the lock shared, which both callers satisfy. Both unlocked
writes fixed here are writes to guarded state while holding only shared access, which is exactly
what this reports.

m_size is deliberately left unguarded: it is only ever read on the main thread.
createFrameImageAtIndex() does not touch it, and the other reader, size() by way of
frameSizeAtIndex(), is reached from BitmapImageSource::fetchFrameMetaDataAtIndex() on the main
thread. The comment in readTrackMetadata() claiming otherwise is corrected; only
m_imageRotationSession is read off the main thread there, by storeSampleBuffer().

Note that in the default Cocoa configuration the decoder runs in the GPU process, driven purely
by IPC on one thread, with no AsyncImageDecoder and so no work queue. The racing arrangement is
WebContent with UseGPUProcessForMediaEnabled off, where the factory constructs
ImageDecoderAVFObjC directly and AsyncImageDecoder decodes on its work queue.

* Source/WebCore/platform/graphics/avfoundation/objc/ImageDecoderAVFObjC.h:
* Source/WebCore/platform/graphics/avfoundation/objc/ImageDecoderAVFObjC.mm:
(WebCore::ImageDecoderAVFObjC::readSamples):
(WebCore::ImageDecoderAVFObjC::readTrackMetadata):
(WebCore::ImageDecoderAVFObjC::encodedDataStatus const):
(WebCore::ImageDecoderAVFObjC::frameCount const):
(WebCore::ImageDecoderAVFObjC::frameIsCompleteAtIndex const):
(WebCore::ImageDecoderAVFObjC::frameDurationAtIndex const):
(WebCore::ImageDecoderAVFObjC::frameHasAlphaAtIndex const):
(WebCore::ImageDecoderAVFObjC::frameInfos const):
(WebCore::ImageDecoderAVFObjC::clearFrameBufferCache):

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

Reviewed by Xabier Rodriguez-Calvar.

The webkitMediaStreamSrcCleanup function has to run from the main thread and it was the case
everywhere excepted when the element is replaced (thus disposed) from a non-main thread by playbin3,
when we send a new collection event from the element pad probe.

* LayoutTests/platform/wpe/TestExpectations:
* Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp:
(webkitMediaStreamSrcDispose):

Canonical link: https://commits.webkit.org/320809@main
…efore signaling `m_uploadCondition`

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

Reviewed by Nikolas Zimmermann.

The type of `writeScope` is MemoryMappedGPUBuffer::AccessScope. The dtor
~AccessScope() actually syncs the buffer. We should do that before signaling
the condition variable.

* Source/WebCore/platform/graphics/skia/SkiaGPUAtlas.cpp:
(WebCore::SkiaGPUAtlas::uploadImages):

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

Reviewed by Nikolas Zimmermann.

The combination of i915 driver and Intel Arc caused white noise for atlas image
uploading. Using xe driver work fine for the video card.

Using CPUMappingStrategy::GBMBoMap and unmapping in ~AccessScope() can work
around the issue for i915.

* Source/WebCore/platform/graphics/gbm/MemoryMappedGPUBuffer.cpp:
(WebCore::runCapabilityProbe):
(WebCore::MemoryMappedGPUBuffer::AccessScope::~AccessScope):

Canonical link: https://commits.webkit.org/320811@main
…e-mediaelementaudiosourcenode-interface/no-cors.https.html is a flaky crashing

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

Reviewed by Xabier Rodriguez-Calvar.

Flaky crashes were happening because playbin was reporting a successful change to playing state
while the audio sink was performing an asynchronous transition and hadn't reached the playing state
yet. In such situation we now make a blocking get_state() call until the asynchronous transition was
completed.

* LayoutTests/platform/glib/TestExpectations:
* Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::areAllSinksPlayingForBin):

Canonical link: https://commits.webkit.org/320812@main
…oop and its caller's thread without synchronization

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

Reviewed by Jean-Yves Avenard.

Frames are generated on m_runLoop, a dedicated run loop, while the source is controlled from
the caller's thread; generateFrame() and generatePhoto() assert !isMainThread() to say so. The
class already guards m_imageBuffer and m_drawingState with a lock, makes m_isTakingPhoto and
m_captureWasInterrupted atomic, and marshals timer start and stop onto m_runLoop. Five members
were left out of all of that, and the run loop reaches four of them indirectly, through helper
calls, which is what kept them hidden:

- m_startTime and m_elapsedTime are written by startProducingData() and stopProducingData(),
  and read by elapsedTime(), which drawText() and MockRealtimeVideoSourceMac::updateSampleBuffer()
  both call while generating a frame.
- m_preset is written by applyFrameRateAndZoomWithPreset() and read by captureSize(), which the
  whole draw path calls.
- m_deviceOrientation is written by orientationChanged() and
  rotationAngleForHorizonLevelDisplayChanged(), and read by videoFrameRotation() from
  updateSampleBuffer().
- m_delayUntil is written by delaySamples() and both read and cleared by generateFrame().

Each is fixed by whichever mechanism matches how it is reached rather than by one blanket
approach. m_startTime, m_elapsedTime and m_preset become WTF_GUARDED_BY_LOCK: every reader on
the run loop already held the lock, so only the writers needed changing, and elapsedTime() and
captureSize() get assertIsHeld() to match how the surrounding code already declares this.
m_deviceOrientation becomes atomic instead, because the lock does not fit it: videoFrameRotation()
is virtual on RealtimeMediaSource and so may be called from anywhere, and settings() reads the
member on the caller's thread. m_delayUntil moves entirely onto m_runLoop by dispatching from
delaySamples(), the same way startCaptureTimer() and stopCaptureTimer() already work; the
deadline is still computed at call time so it does not shift with dispatch latency.

Annotating m_preset immediately turned up a third accessor that reading the code had not:
settings() reads it on the caller's thread, which now takes the lock for that one read.
applyFrameRateAndZoomWithPreset() is restructured so setIntrinsicSize(), which notifies
observers, is not called while holding the lock.

The lock is renamed from m_imageBufferLock to m_frameGenerationLock. It already guarded
m_drawingState and now covers three further members that are not image buffers.

None of this is reachable by web content: MockRealtimeVideoSource is only created by
MockRealtimeMediaSourceCenter, that is, when mock capture devices are enabled for testing. Nor
was any of it a memory-safety problem, since everything read across the thread boundary is
plain data, a MonotonicTime, a Seconds, an enum, or the IntSize inside m_preset. The visible
symptom would have been a wrong timestamp, rotation or frame size in a generated mock frame.

* Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp:
(WebCore::MockRealtimeVideoSource::takePhotoInternal):
(WebCore::MockRealtimeVideoSource::settings):
(WebCore::MockRealtimeVideoSource::applyFrameRateAndZoomWithPreset):
(WebCore::MockRealtimeVideoSource::captureSize const):
(WebCore::MockRealtimeVideoSource::invalidateDrawingState):
(WebCore::MockRealtimeVideoSource::drawingState):
(WebCore::MockRealtimeVideoSource::settingsDidChange):
(WebCore::MockRealtimeVideoSource::startProducingData):
(WebCore::MockRealtimeVideoSource::stopProducingData):
(WebCore::MockRealtimeVideoSource::elapsedTime):
(WebCore::MockRealtimeVideoSource::drawText):
(WebCore::MockRealtimeVideoSource::delaySamples):
(WebCore::MockRealtimeVideoSource::generatePhoto):
(WebCore::MockRealtimeVideoSource::generateFrameInternal):
(WebCore::MockRealtimeVideoSource::generateFrame):
(WebCore::MockRealtimeVideoSource::imageBuffer):
(WebCore::MockRealtimeVideoSource::imageBufferInternal):
(WebCore::MockRealtimeVideoSource::orientationChanged):
* Source/WebCore/platform/mock/MockRealtimeVideoSource.h:
(WebCore::MockRealtimeVideoSource::WTF_GUARDED_BY_LOCK):

Canonical link: https://commits.webkit.org/320813@main
https://bugs.webkit.org/show_bug.cgi?id=323860
rdar://187098845

Reviewed by Alexey Proskuryakov.

* LayoutTests/fast/harness/test-duration-treemap.html:

Canonical link: https://commits.webkit.org/320814@main
…ang the run

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

Reviewed by Carlos Alberto Lopez Perez.

pytest-timeout raises from its SIGALRM handler wherever the alarm lands. When
that is inside asyncio's scheduler, for instance while Future.set_result() is
queueing the wake-up of the task awaiting it, the future is marked done but the
wake-up is never scheduled. asyncio swallows the exception as "Exception in
callback", the test task is parked for good, and the loop keeps servicing the
websockets keepalive until someone kills the bot. Every run of the BiDi tests
expected to time out goes through this path.

Wrap the handler pytest-timeout installs so that, while an event loop is
running, the alarm is only delivered from the selector the idle loop is blocked
in, where the exception propagates cleanly out of run_until_complete(). Anywhere
else inside the loop it is re-armed a few milliseconds later instead.

Also match the timeout message pytest-timeout 2.4.0 produces, which has been
making unexpected timeouts show up as failures since the bump.

* Tools/Scripts/webkitpy/webdriver_tests/pytest_runner.py:
(SubtestResultRecorder._was_timeout):
(TimeoutSignalHandler):
(TimeoutSignalHandler.pytest_timeout_set_timer):
(TimeoutSignalHandler._should_defer_timeout):
(run):

Canonical link: https://commits.webkit.org/320815@main
…leCopyFromMemory times out on regions of 4 GB and above

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

Reviewed by Carlos Alberto Lopez Perez.

320449@main added SharedMemoryTests.cpp to the CMake build, so it runs on the
GTK and WPE ports for the first time. The test tolerates the 4 GB + 1 and
20 GB regions failing to allocate and skips them in that case. On Linux the
allocation never fails because of overcommit, and CreateHandleCopyFromMemory,
the only one of these tests that does any work outside Cocoa, then copies the
whole region into a freshly created memfd. That commits up to 42 GB and takes
around 30 seconds even when run alone, at the timeout of run-api-tests, so
every GTK and WPE bot times out on these cases.

Outside Cocoa these sizes only exercise a memcpy into shared memory, which the
smaller regions already cover, so leave them to Cocoa, matching how the memory
sources are already selected per platform.

* Tools/TestWebKitAPI/Tests/WebCore/SharedMemoryTests.cpp:

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

Reviewed by Yusuke Suzuki.

m_atom and m_specificPattern depend only on the pattern, like
m_numSubpatterns and m_rareData which deleteCode() already keeps, so stop
clearing them.

Test: JSTests/stress/regexp-cached-result-one-character-atom-delete-all-code.js

* JSTests/stress/regexp-cached-result-one-character-atom-delete-all-code.js: Added.
(shouldBe):
(step):
* Source/JavaScriptCore/runtime/RegExp.cpp:
(JSC::RegExp::deleteCode):

Canonical link: https://commits.webkit.org/320817@main
…loop callbacks

<rdar://181438985>

Reviewed by Jonathan Bedard.

The WebQueuedVideoOutputDelegate callbacks and the AVFoundation time
observer blocks hop their work to the main run loop capturing only a
WeakPtr to the QueuedVideoOutput, then dereference it as a raw pointer
after a plain null check.  The null check does not keep the object
alive: addVideoFrameEntries() fires the current-image-changed
observers, which can synchronously tear down the media player and
release the last strong reference to the QueuedVideoOutput while the
callback is still on the stack, so the trailing member access reads
freed memory.

Promote the captured WeakPtr to a RefPtr inside each block before use
so the object is kept alive for the duration of the call.  The sole
strong owner only ever runs on the main thread, so the non-atomic
RefPtr is sufficient and no ThreadSafeRefCounted change is needed.

No new tests since this change is not directly testable.

* Source/WebCore/platform/graphics/avfoundation/objc/QueuedVideoOutput.mm:
(-[WebQueuedVideoOutputDelegate outputMediaDataWillChange:]):
(-[WebQueuedVideoOutputDelegate outputSequenceWasFlushed:]):
(-[WebQueuedVideoOutputDelegate observeValueForKeyPath:ofObject:change:context:]):
(WebCore::QueuedVideoOutput::QueuedVideoOutput):
(WebCore::QueuedVideoOutput::configureNextImageTimeObserver):

Originally-landed-as: 305413.1094@safari-7624.5-branch (f53714d). rdar://184745139
Canonical link: https://commits.webkit.org/320818@main
https://bugs.webkit.org/show_bug.cgi?id=323628

Reviewed by Yusuke Suzuki.

JSWebAssemblyArray::fill of ref elements stored encoded JSValues one
at a time. Concurrent GC needs whole 8-byte writes. Add gcSafeMemfill
next to gcSafeZeroMemory and use it for that path, then one write
barrier, matching array.copy.

* Source/JavaScriptCore/heap/GCMemoryOperations.h:
* Source/JavaScriptCore/wasm/js/JSWebAssemblyArray.cpp:
* JSTests/wasm/gc/bulk-array-element-types.js:

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

Reviewed by Carlos Garcia Campos.

Macros from libmanette: LIBMANETTE_CHECK_VERSION(deprecated) and
MANETTE_CHECK_VERSION evaluate to TRUE in case of greater than or
equal to. This caused that in case of version 0.2.13 wrong values
were passed to manette_device_rumble (normalized floating-point
rumble magnitudes) and it was rounded to 0 (guint16).

The normalized floating-point rumble magnitudes are demanded in
case of libmanette version >= 1.0.0.

Also deprecated macro is replaced with the new one.

No new tests.
* Source/WebCore/platform/gamepad/manette/ManetteGamepad.cpp:
(WebCore::ManetteGamepad::startRumble):
* Source/WebKit/WPEPlatform/wpe/WPEGamepadManette.cpp:
(wpeGamepadManetteRumble):

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

Reviewed by Yusuke Suzuki.

grow and resize used ToIntegerOrInfinity and then cast to size_t after
only checking finite and non-negative. A value such as 1e20 is in range
for double but not for size_t.

Use toIndex so the result is uint64_t and a negative length throws
RangeError before the detached check.

* JSTests/stress/arraybuffer-grow-resize-huge-length.js: Added.
* Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp:
(arrayBufferProtoFuncResize):
(sharedArrayBufferProtoFuncGrow):

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

Reviewed by Darin Adler.

* Source/JavaScriptCore/bytecode/SpeculatedType.cpp:
(JSC::speculationFromString):
* Source/JavaScriptCore/bytecode/SpeculatedType.h:
* Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp:
(JSC::BytecodeIntrinsicNode::emit_intrinsic_idWithProfile):
* Source/JavaScriptCore/wasm/debugger/tests/BinaryTests.cpp:
(WasmDebugInfoTest::testAllBinaryOps):
* Source/JavaScriptCore/wasm/debugger/testwasmdebugger.cpp:
(testWASMVirtualAddressEncoding):

Canonical link: https://commits.webkit.org/320822@main
https://bugs.webkit.org/show_bug.cgi?id=323862
rdar://187104927

Reviewed by Zak Ridouh.

The parameter is named three different things: itemIndex in .messages.in, index
in WebBackForwardList.h, and delta in both WebBackForwardList.cpp and the Swift
implementation. It is a delta - it is passed to itemAtDeltaFromCurrentIndex,
and Int32::min is rejected because it cannot be negated - so settle on that.

No behaviour change. The .messages.in name is only used as a descriptive string
in the generated MessageArgumentDescriptions for the IPC testing API.

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

Reviewed by Carlos Garcia Campos.

Add a check for the underlying `sk_sp<SkImageFilter>` before using it.

* Source/WebCore/platform/graphics/skia/SkiaCompositingLayer.cpp:
(WebCore::SkiaCompositingLayer::paintWithFilterAndMask):

* LayoutTests/compositing/filters/repeated-filter-transitions.html: Added.
* LayoutTests/compositing/filters/repeated-filter-transitions-expected.txt: Added.

Canonical link: https://commits.webkit.org/320824@main
@github-actions

github-actions Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Preview build of 2ed8525: autobuild-preview-pr-651-2ed85257

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code review found no issues

No high-confidence issues detected in this change.

…6abe

# Conflicts:
#	Source/JavaScriptCore/runtime/RegExp.cpp
#	Source/cmake/WebKitCompilerFlags.cmake

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code review found no issues

No high-confidence issues detected in this change.

robobun added a commit to oven-sh/bun that referenced this pull request Sep 15, 2026
… c775a5dc52

The preview build of oven-sh/WebKit#651 now contains the fork's main, which
changed the bytecode cache format after 65513e295c73. The values are the ones
in #42383, which pins c775a5dc52 itself. The upstream range does not move them.
…6abe

# Conflicts:
#	Source/JavaScriptCore/runtime/JSModuleRecord.cpp

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code review found no issues

No high-confidence issues detected in this change.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code review found no issues

No high-confidence issues detected in this change.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code review found no issues

No high-confidence issues detected in this change.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code review found no issues

No high-confidence issues detected in this change.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code review found no issues

No high-confidence issues detected in this change.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Findings marked 🟡 are optional suggestions and need no follow-up push.

Comment on lines +189 to +206
while (!m_data.isEmpty() && (!m_bandwidthBytesPerSecond || m_budget >= 1)) {
auto first = m_data.first();
size_t firstRemaining = first->size() - m_dataFirstOffset;
size_t bytesToDeliver = firstRemaining;
if (m_bandwidthBytesPerSecond && m_budget < bytesToDeliver)
bytesToDeliver = static_cast<size_t>(m_budget);

Ref chunk = SharedBuffer::create(first->span().subspan(m_dataFirstOffset, bytesToDeliver));
if (m_bandwidthBytesPerSecond)
m_budget -= bytesToDeliver;

m_dataFirstOffset += bytesToDeliver;
if (m_dataFirstOffset >= first->size()) {
m_data.removeFirst();
m_dataFirstOffset = 0;
}

client->didReceiveBuffer(chunk);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 The network process can use freed memory when a throttled response is cancelled from inside a data callback, which the base branch never does. ConditionEmulator::timerFired delivers queued chunks in a loop and calls client->didReceiveBuffer(chunk) at NetworkLoad.cpp:206; if the client cancels or drops the NetworkLoad synchronously, NetworkLoad::cancel() (NetworkLoad.cpp:318) deletes the emulator while its timerFired is still on the stack, and the loop then reads m_data on freed memory. Fix: make timerFired survive deletion of the emulator during didReceiveBuffer on every path (cancel() and NetworkLoad destruction), e.g. detect it after the call with a WeakPtr/CheckedPtr to self and return, or deliver from a local copy of the queue.

Why this was flagged

Web Inspector sets a bandwidth limit (Network.setEmulatedConditions), so NetworkLoad::didReceiveData queues bytes in ConditionEmulator::m_data and delivery happens from ConditionEmulator::timerFired (NetworkLoad.cpp:171-214). Inside the while loop at NetworkLoad.cpp:189 the emulator calls client->didReceiveBuffer(chunk) at line 206. Two NetworkLoadClients cancel the load synchronously from that callback: QualifiedServerTrustFetch::didReceiveBuffer (QualifiedServerTrustFetch.cpp:104-108) calls cancel(), which runs m_networkLoad->cancel() (QualifiedServerTrustFetch.cpp:143-146) once more than 10 MB has been buffered; on Cocoa NetworkResourceLoader::didReceiveBuffer (NetworkResourceLoader.cpp:1350-1354) calls failDueToExcessiveDeferredMessages(), which runs networkLoad->cancel() (NetworkResourceLoader.cpp:1973-1974) and then didFailLoading -> cleanup(), which drops m_networkLoad (NetworkResourceLoader.cpp:652) and so destroys the NetworkLoad and its unique_ptr. NetworkLoad::cancel() sets m_conditionEmulator = nullptr (NetworkLoad.cpp:318), deleting the emulator whose…

Verification: normal — triggers when Web Inspector has set a session-wide bandwidth limit (NetworkSession::setEmulatedConditions, NetworkSession.h:290 is per-session so every NetworkLoad in the session gets an emulator) and a NetworkLoadClient cancels the load synchronously from didReceiveBuffer. Mechanism verified in /home/claude/webkit/Source/WebKit/NetworkProcess/NetworkLoad.cpp (new in this PR; base has…

Comment on lines +554 to +559
void NetworkLoad::emulatedConditionsDidChange()
{
if (CheckedPtr conditionEmulator = m_conditionEmulator.get())
conditionEmulator->conditionsDidChange();
else
m_conditionEmulator = ConditionEmulator::tryCreate(*this);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 Changing emulated latency while loads are in flight now resumes tasks that are already running or still queued in the scheduler, which the base branch never did. NetworkLoad::emulatedConditionsDidChange creates a fresh emulator via tryCreate at NetworkLoad.cpp:559 with no knowledge of whether the task was already resumed; with latency > 0 it enters WaitingForLatency and timerFired calls task->resume() again. NetworkDataTaskSoup::resume and NetworkDataTaskCurl::resume assert m_state != State::Running, and a load still pending in NetworkLoadScheduler is started before the scheduler releases it and then resumed a second time from start(). … [also at: Source/WebKit/NetworkProcess/NetworkLoad.cpp:560 - Turning on latency emulation in Web Inspector while a blob: URL load is streaming makes the network process resume that load a second time, which restarts the blob read and sends a second response mid-body.]

Why this was flagged

…Fix: only arm the latency phase for a task that has not been resumed yet (track it in NetworkLoad and create the emulator in State::None otherwise), so both already-started and scheduler-queued loads are covered.

Network.setEmulatedConditions with a positive latency reaches NetworkSession::setEmulatedConditions (NetworkSession.cpp:816-824), which calls task.notifyEmulatedConditionsChanged() for every task in m_dataTaskSet; NetworkDataTask registers itself there in its constructor (NetworkDataTask.cpp:106), before NetworkLoad::start() or the scheduler ever ran. NetworkDataTask::notifyEmulatedConditionsChanged (NetworkDataTask.cpp:120-124) calls NetworkLoad::emulatedConditionsDidChange (NetworkLoad.cpp:554-560). A load that had no conditions when it started has no emulator, so the else branch calls ConditionEmulator::tryCreate (NetworkLoad.cpp:64-77), which sets State::WaitingForLatency and starts the timer; timerFired (NetworkLoad.cpp:176-181) then calls task->resume()…

Verification: normal — triggers when Web Inspector's Network.setEmulatedConditions with latency > 0 arrives while a NetworkLoad exists whose task has not yet been (or has already been) resumed by NetworkLoad::start(). Mechanism verified: NetworkSession::setEmulatedConditions (Source/WebKit/NetworkProcess/NetworkSession.cpp:816-824) calls notifyEmulatedConditionsChanged() on every task in m_dataTaskSet (tasks…

Comment on lines +1570 to +1574
// COMPATIBILITY (macOS X.Y, iOS X.Y): Network.setEmulatedConditions did not exist.
if (!target.hasCommand("Network.setEmulatedConditions"))
return;

target.NetworkAgent.setEmulatedConditions(this._emulatedCondition.bytesPerSecondLimit);
target.NetworkAgent.setEmulatedConditions(this._emulatedCondition.bandwidth, this._emulatedCondition.latency);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 Web Inspector users inspecting an iOS 16.4-17.4 or macOS 13.3-14.4 backend can no longer apply or clear network throttling; the command is rejected client-side with a Protocol Error. NetworkManager.js:1574 always passes two positional arguments, but those legacy backends register Network.setEmulatedConditions with the single parameter bytesPerSecondLimit, so InspectorBackend treats the latency value as a bad callback argument and never sends the command. Fix: gate on target.hasCommand("Network.setEmulatedConditions", "latency") and fall back to a one-argument call for older backends, and fill in the real versions in the COMPATIBILITY comment at NetworkManager.js:1570 instead of the "macOS X.Y, iOS X.Y" placeholder.

Why this was flagged

Trigger: the experimentalEnableNetworkEmulatedCondition setting is on and the frontend connects to a backend whose legacy command table is Protocol/Legacy/iOS/16.4, 17.0, 17.2 or 17.4 or Protocol/Legacy/macOS/13.3, 14.0, 14.2 or 14.4; each registers Network.setEmulatedConditions with only [{"name": "bytesPerSecondLimit", "type": "number", "optional": true}] (e.g. Legacy/iOS/17.4/InspectorBackendCommands.js:401). _applyEmulatedCondition checks only that the command exists (NetworkManager.js:1571) and calls setEmulatedConditions(bandwidth, latency) (NetworkManager.js:1574). InspectorBackend._invokeWithArguments consumes one argument for the single signature entry and then, with one number left over, returns deliverFailure("Protocol Error: Optional callback argument for command ... must be a function but its type is 'number'") (InspectorBackend.js:509-524); this also happens for the None preset because latency is 0, not undefined. The base branch sent setEmulatedConditions(bytesPerSecondLimit) with one argument, which matched those backends. Backends from 18.0 on omit the…

Verification: normal — when the experimental network-throttling setting is enabled and the frontend is loaded with one of the shipped legacy command tables (Protocol/Legacy/iOS/16.4, 17.0, 17.2, 17.4 or macOS/13.3, 14.0, 14.2, 14.4). Mechanism verified: /home/claude/webkit/Source/WebInspectorUI/UserInterface/Controllers/NetworkManager.js:1571-1574 only checks… | normal — triggers when the experimental "Allow…

Comment on lines +96 to +110
bool didReceiveData(const SharedBuffer& buffer)
{
if (!m_bandwidthBytesPerSecond && m_data.isEmpty())
return false;
if (!buffer.size())
return true;

m_data.append(protect(buffer));
if (m_state != State::Throttling) {
m_budgetUpdateTime = MonotonicTime::now();
m_state = State::Throttling;
m_timer.startOneShot(bandwidthDeliveryInterval);
}
return true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 With bandwidth throttling on, a multipart/x-mixed-replace stream (e.g. an MJPEG camera page) gets the tail of one part attributed to the next part, because responses bypass the throttling queue. Body chunks are held in m_data at NetworkLoad.cpp:103 and released later by timerFired, but NetworkLoad::didReceiveResponse at NetworkLoad.cpp:476-512 hands each new part's response to the client immediately. Fix: preserve delivery order under emulation by queueing didReceiveResponse (and its completion handler) behind pending data in the emulator, or flushing queued data before a subsequent response is delivered.

Why this was flagged

Trigger: NetworkSession emulated bandwidth set and a response that NSURLSession delivers as several didReceiveResponse callbacks, i.e. multipart/x-mixed-replace. Data for part N is appended to m_data in ConditionEmulator::didReceiveData (NetworkLoad.cpp:103) and delivered at most bandwidth * 50 ms per tick (NetworkLoad.cpp:57, 189-206). When part N+1 headers arrive, NetworkDataTaskCocoa::didReceiveResponse (NetworkDataTaskCocoa.mm:451-465) -> NetworkLoad::didReceiveResponse -> notifyDidReceiveResponse calls client->didReceiveResponse right away (NetworkLoad.cpp:512), with no emulator hook. NetworkResourceLoader::didReceiveResponse then resets m_bufferedData for multipart (NetworkResourceLoader.cpp:1154-1155) and on Cocoa sets m_isProcessingResponse (NetworkResourceLoader.cpp:1095) so the leftover part-N bytes later released by timerFired are deferred and sent after part N+1's response, i.e. prepended to part N+1's body. On the base branch throttling was done inside CFNetwork via _bytesPerSecondLimit so callbacks stayed in order.

Verification: nit — triggered when Web Inspector bandwidth throttling is on (NetworkSession::setEmulatedConditions, Source/WebKit/NetworkProcess/NetworkSession.cpp:816-823) and the load is a multipart/x-mixed-replace response, for which NSURLSession invokes URLSession:dataTask:didReceiveResponse: once per part (Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm:864-905; WebKit itself documents this at…

Comment on lines +776 to +799
static bool isEquivalentToClassSelector(const CSSSelector& selector, CSSParserMode mode)
{
// Only HTMLStandardMode. Quirks mode ASCII-lowercases the class list while [class~=] stays
// case-sensitive, and UA sheets are parsed once and shared with quirks mode documents.
if (mode != HTMLStandardMode)
return false;

if (selector.match() != CSSSelector::Match::List)
return false;

// A prefixed or uppercase attribute name is a different attribute, except for HTML elements
// where the name is matched ASCII-case-insensitively. Requiring an exact match keeps
// [CLASS~=foo] and [html|class~=foo] on the general attribute path.
if (selector.attribute() != HTMLNames::classAttr)
return false;

if (selector.attributeMatchType() == CSSSelector::AttributeMatchType::CaseInsensitive)
return false;

// Neither [class~=""] nor a value with whitespace can match anything, which is not what a
// class selector would do.
auto& value = selector.value();
return !value.isEmpty() && value.find(isASCIIWhitespace<char16_t>) == notFound;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 nit (optional): Authors animating an SVG element's class with SMIL now see [class~="x"] rules toggle with the animated class list, which the base branch never did. isEquivalentToClassSelector() marks the selector so SelectorChecker.cpp:817 and SelectorCompiler.cpp:1637 test element->hasClassName() instead of the class attribute. For SVG, SVGElement.cpp:1094-1095 refills classNames() from the animated className() while the attribute keeps the base value, so the two are not equivalent there. Fix: keep the attribute path (or skip the flag) when the element is an SVGElement, or when the sheet can apply to SVG content, so attribute selectors keep matching the base attribute value like every other [attr~=] selector.

Why this was flagged

Trigger: a standards-mode document containing <svg><rect class="a"><animate attributeName="class" to="b" dur="1s" fill="freeze"/></rect></svg> and a rule rect[class~="b"] { fill: red }. CSSSelectorParser.cpp:840 marks that selector with setIsEquivalentToClassSelector() because it is a Match::List on HTMLNames::classAttr in HTMLStandardMode (CSSSelectorParser.cpp:776-799). During the animation SVGElement::svgAttributeChanged calls classAttributeChanged(className(), ...) at SVGElement.cpp:1094-1095, so ElementData::classNames() holds the animated list {b} while the DOM class attribute still holds the base value "a" (SVG synchronizes base values only). SelectorChecker::checkOne at SelectorChecker.cpp:817-820 (and the JIT fragment at SelectorCompiler.cpp:1637-1641, RuleSet bucket at RuleSet.cpp:220) now answers element->hasClassName("b") == true, so the rule applies and the rect turns red; RuleFeature.cpp:350 also routes the rule through class-change invalidation so the change is rendered. On the base branch Match::List compared the attribute value "a" and the rule…

Verification: nit — triggers when an SVG element's class attribute is animated by SMIL (<animate>/<set attributeName="class">) in a standards-mode document and a stylesheet or querySelector uses [class~="x"]. Mechanism verified: Source/WebCore/css/parser/CSSSelectorParser.cpp:776-799 (isEquivalentToClassSelector) marks any Match::List selector on HTMLNames::classAttr in HTMLStandardMode,…

Comment on lines 3184 to 3185
if (!r.empty())
rResult = rightShift(r, uSpan, shift);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟣 pre-existing, not blocking: Pre-existing: terminating a VM (worker.terminate) during a large BigInt % crashes the process on a RELEASE_ASSERT instead of unwinding with the TerminationException. When InterruptCheck breaks the row loop in divideSchoolbook (JSBigInt.cpp:3127), uSpan still holds unreduced digits, and rightShift(r, uSpan, shift) at JSBigInt.cpp:3185 fails z.size() >= x.size() at JSBigInt.cpp:3027 because r has only b.size() digits. Fix: return (or skip the remainder shift) when interrupted, so every caller passing r, including remainderImpl at JSBigInt.cpp:4918 and divideBasecase at JSBigInt.cpp:3306, sees the pending exception rather than a crash.
A small fix can ride a push you are already making; otherwise a short reply is enough.

Why this was flagged

Input: x % y with y of 2..56 digits and x long enough that the schoolbook loop accumulates 5,000,000 work units (about 90,000 rows of a 56-digit divisor, i.e. an x of roughly 6 million bits), reached through JSBigInt::remainderImpl, which passes r sized ySpan.size() at JSBigInt.cpp:4912 and 4918 into divideDigitsInto and then divideSchoolbook with &interrupt. While the loop runs, another thread requests termination (Bun worker.terminate). InterruptCheck::addWork at JSBigInt.cpp:1264 reaches workThreshold, checkSlow at 1283 sees hasExceptionsAfterHandlingTraps and sets m_interrupted, and the loop breaks at JSBigInt.cpp:3127. At that point uSpan (a.size()+1 digits, JSBigInt.cpp:3089) still holds the remainder of the previous row in uSpan[j+1..j+n] plus the unprocessed low digits, so normalize(uSpan) inside rightShift (JSBigInt.cpp:3020) is longer than n. divideSchoolbook then calls rightShift(r, uSpan, shift) at JSBigInt.cpp:3185; with shift > 0 the RELEASE_ASSERT(z.size() >= x.size()) at JSBigInt.cpp:3027 fires, with shift == 0 spanCopy's RELEASE_ASSERT at JSBigInt.cpp:2984 fires. The…

Verification: pre-existing (the base at 299c532 has the identical break on interrupt and the identical RELEASE_ASSERT(z.size() >= x.size()) in rightShift; this diff rewrites both functions but keeps the defect). Trigger: a termination request (VMTraps NeedTermination, e.g. worker.terminate) arrives while divideSchoolbook is running with an InterruptCheck bound to a VM and enough accumulated work to reach…

@robobun

robobun commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator Author

This PR is replaced by #725. That PR merges upstream 7b485a76e9, which includes this range, with the conflict resolutions of this PR. The branch stays, so this PR can be reopened. On the Bun side, oven-sh/bun#42666 is replaced by oven-sh/bun#43882.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.