Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 33ca66ce3ffefd121b93cc2dd8db81d16eb791aa
      
https://github.com/WebKit/WebKit/commit/33ca66ce3ffefd121b93cc2dd8db81d16eb791aa
  Author: Yusuke Suzuki <[email protected]>
  Date:   2026-09-27 (Sun, 27 Sep 2026)

  Changed paths:
    A JSTests/wasm/stress/array-distinct-bases-and-indices.js
    A JSTests/wasm/stress/array-fill-clobbers-cached-element.js
    A JSTests/wasm/stress/struct-field-clobbered-by-call.js
    A JSTests/wasm/stress/struct-fields-sharing-one-epoch.js
    A JSTests/wasm/stress/struct-get-forwarded-from-dominator.js
    A JSTests/wasm/stress/struct-immutable-fields-share-a-counter.js
    A JSTests/wasm/stress/struct-set-after-cast-clobbers-cached-field.js
    M JSTests/wasm/stress/wasm-array-omg-cse.js
    M Source/JavaScriptCore/b3/B3CanonicalizePrePostIncrements.cpp
    M Source/JavaScriptCore/b3/B3EliminateCommonSubexpressions.cpp
    M Source/JavaScriptCore/b3/B3EliminateWasmGCAllocations.cpp
    M Source/JavaScriptCore/b3/B3Procedure.h
    M Source/JavaScriptCore/b3/B3ReduceStrength.cpp
    M Source/JavaScriptCore/b3/B3ReduceStrength.h
    M Source/JavaScriptCore/b3/B3WasmArraySetValue.cpp
    M Source/JavaScriptCore/b3/B3WasmArraySetValue.h
    M Source/JavaScriptCore/b3/B3WasmStructSetValue.cpp
    M Source/JavaScriptCore/b3/B3WasmStructSetValue.h
    M Source/JavaScriptCore/runtime/OptionsList.h
    M Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp
    M Source/WTF/WTF.xcodeproj/project.pbxproj
    M Source/WTF/wtf/CMakeLists.txt
    A Source/WTF/wtf/LayeredHashMap.h
    M Tools/TestWebKitAPI/CMakeLists.txt
    M Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
    A Tools/TestWebKitAPI/Tests/WTF/LayeredHashMap.cpp

  Log Message:
  -----------
  [JSC] ValueNumbering-based WasmGC optimization in B3::ReduceStrength
https://bugs.webkit.org/show_bug.cgi?id=324906
rdar://188134232

Reviewed by Dan Hecht and Keith Miller.

B3 CSE phase takes very long time to optimize WasmGC operations. This is
because it is traversing back all reachable blocks to find potential
common subexpression, and making compile time significantly longer.
We should have a better tradeoff between aggressiveness of optimization
and compile time here.

This patch implements value-numbering based WasmGC optimization in B3
ReduceStrength phase. We enable it only when it is "First" run of
B3 ReduceStrength (it runs twice in the pipeline). This implements two
value-numbering optimizations.

1. We now replace PureCSE with much traditional value-numbering. We traverse
   blocks in dominance ordering. This ensures that when a block is visited,
   dominators are already visited as well. We also add LayeredHashMap
   so value-numbering HashMap can be easily layered with the level of
   dominator tree depth. This avoids checking owner of B3::Value to
   ensure it is actually dominated since LayeredHashMap's entries are
   only coming from dominators.
2. Then we extend it for WasmGC access. This is similar to Memory SSA.
   We first collect all written WasmGC abstract fields (from TBAA) and
   manages the epoch of each field. And we use LayeredHashMap with the
   key { base, index, heap (field), slot-epoch, all-heap-epoch }, and
   this map can quickly answer the previous load in the dominators.
   Whenever we write a value to the field, we bump the epoch
   corresponding to the abstract field, so the registered values in the
   map is correctly invalidated. In the initial scan, we also collect
   set of written fields inside the loop so loop do not pessimize the
   epoch significantly (we only bump the fields which is actually
   written inside the loop).

Performance neutral while significantly reducing the compile time for
WasmGC code. But note that we will further extend / having different
analysis on several weakened items.

1. A read is now forwarded only out of an access that dominates it, so the Phi
   synthesis for reads reachable from several different definitions is gone.
2. Forward store elimination is gone for the same reason, having fired 3, 9 and 
55
   times across the three WasmGC subtests.

Tests: JSTests/wasm/stress/array-fill-clobbers-cached-element.js
       JSTests/wasm/stress/struct-fields-sharing-one-epoch.js
       JSTests/wasm/stress/struct-get-forwarded-from-dominator.js
       JSTests/wasm/stress/struct-set-after-cast-clobbers-cached-field.js
       Source/JavaScriptCore/b3/testb3_1.cpp

* JSTests/wasm/stress/array-distinct-bases-and-indices.js: Added.
(from.string_appeared_here.import.as.assert.from.string_appeared_here.const.wat.module.type.A.array.mut.i32.func.export.string_appeared_here.param.count.i32.result.i32.local.p.ref.null.A.local.q.ref.null.A.local.i.i32.local.sum.i32.local.p.array.new_default.A.i32.const.4.local.q.array.new_default.A.i32.const.4.loop.loop.array.A.local.p.i32.const.0.local.i.array.A.local.q.i32.const.0.i32.add.local.i.i32.const.100.local.sum.i32.add.local.sum.i32.sub.array.A.local.q.i32.const.0.array.A.local.p.i32.const.0.local.i.i32.add.local.i.i32.const.1.br_if.loop.i32.lt_s.local.i.local.count.local.sum.func.export.string_appeared_here.param.count.i32.result.i32.local.a.ref.null.A.local.i.i32.local.sum.i32.local.a.array.new_default.A.i32.const.4.loop.loop.array.A.local.a.i32.const.0.local.i.array.A.local.a.i32.const.1.i32.add.local.i.i32.const.100.local.sum.i32.add.local.sum.i32.sub.array.A.local.a.i32.const.1.array.A.local.a.i32.const.0.local.i.i32.add.local.i.i32.const.1.br_if.loop.i32.lt_s.local.i.local.count.local.sum.async
 test):
* JSTests/wasm/stress/array-fill-clobbers-cached-element.js: Added.
(from.string_appeared_here.import.as.assert.from.string_appeared_here.const.wat.module.type.arr.array.mut.i8.func.export.string_appeared_here.param.count.i32.result.i32.local.a.ref.null.arr.local.i.i32.local.sum.i32.local.a.array.new_default.arr.i32.const.8.loop.loop.array.arr.local.a.i32.const.0.i32.const.7.array.fill.arr.local.a.i32.const.0.i32.const.0.i32.const.8.local.sum.i32.add.local.sum.array.get_u.arr.local.a.i32.const.0.local.i.i32.add.local.i.i32.const.1.br_if.loop.i32.lt_s.local.i.local.count.local.sum.async
 test):
* JSTests/wasm/stress/struct-field-clobbered-by-call.js: Added.
(from.string_appeared_here.import.as.assert.from.string_appeared_here.const.wat.module.type.S.struct.field.x.mut.i32.field.y.mut.i32.func.writeY.param.s.ref.null.S.param.v.i32.struct.S.y.local.s.local.v.func.export.string_appeared_here.param.count.i32.result.i32.local.s.ref.null.S.local.i.i32.local.sum.i32.local.s.struct.new.S.i32.const.0.i32.const.0.loop.loop.struct.S.x.local.s.local.i.local.sum.i32.add.local.sum.struct.S.y.local.s.call.writeY.local.s.local.i.local.sum.i32.add.local.sum.struct.S.y.local.s.local.i.i32.add.local.i.i32.const.1.br_if.loop.i32.lt_s.local.i.local.count.local.sum.async
 test):
* JSTests/wasm/stress/struct-fields-sharing-one-epoch.js: Added.
(from.string_appeared_here.import.as.assert.from.string_appeared_here.const.wat.module.type.S.struct.field.x.mut.i32.field.y.mut.i32.func.export.string_appeared_here.param.count.i32.result.i32.local.s.ref.null.S.local.i.i32.local.sum.i32.local.s.struct.new.S.i32.const.0.i32.const.0.loop.loop.struct.S.x.local.s.local.i.struct.S.y.local.s.i32.add.local.i.i32.const.1.local.sum.i32.add.local.sum.i32.sub.struct.S.y.local.s.struct.S.x.local.s.local.i.i32.add.local.i.i32.const.1.br_if.loop.i32.lt_s.local.i.local.count.local.sum.async
 test):
* JSTests/wasm/stress/struct-get-forwarded-from-dominator.js: Added.
(from.string_appeared_here.import.as.assert.from.string_appeared_here.const.wat.module.type.S.struct.field.b.mut.i8.field.w.mut.i32.func.export.string_appeared_here.param.flag.i32.result.i32.local.s.ref.null.S.local.s.struct.new.S.i32.const.0.i32.const.0.struct.S.b.local.s.i32.const.0x1ff.local.flag.then.struct.S.w.local.s.i32.const.1.struct.get_u.S.b.local.s.func.export.string_appeared_here.param.count.i32.result.i32.local.s.ref.null.S.local.i.i32.local.sum.i32.local.s.struct.new.S.i32.const.0.i32.const.0.struct.S.w.local.s.i32.const.7.loop.loop.local.sum.i32.add.local.sum.struct.S.w.local.s.struct.S.w.local.s.i32.add.local.i.i32.const.100.local.i.i32.add.local.i.i32.const.1.br_if.loop.i32.lt_s.local.i.local.count.local.sum.func.export.string_appeared_here.param.flag.i32.result.i32.local.s.ref.null.S.local.s.struct.new.S.i32.const.0.i32.const.0.local.flag.then.struct.S.w.local.s.i32.const.11.else.struct.S.w.local.s.i32.const.22.struct.S.w.local.s.async
 test):
* JSTests/wasm/stress/struct-immutable-fields-share-a-counter.js: Added.
(from.string_appeared_here.import.as.assert.from.string_appeared_here.const.wat.module.type.S.struct.field.a.i32.field.b.i32.field.m.mut.i32.func.clobber.param.s.ref.null.S.param.v.i32.struct.S.m.local.s.local.v.func.export.string_appeared_here.param.count.i32.result.i32.local.s.ref.null.S.local.i.i32.local.sum.i32.local.s.struct.new.S.i32.const.3.i32.const.5.i32.const.0.loop.loop.struct.S.m.local.s.local.i.call.clobber.local.s.local.i.local.sum.i32.add.local.sum.i32.sub.struct.S.b.local.s.struct.S.a.local.s.local.i.i32.add.local.i.i32.const.1.br_if.loop.i32.lt_s.local.i.local.count.local.sum.async
 test):
* JSTests/wasm/stress/struct-set-after-cast-clobbers-cached-field.js: Added.
(from.string_appeared_here.import.as.assert.from.string_appeared_here.const.wat.module.type.Base.sub.struct.field.mut.i32.type.Derived.sub.Base.struct.field.mut.i32.field.mut.i32.func.export.string_appeared_here.param.count.i32.result.i32.local.o.ref.null.Derived.local.p.ref.null.Base.local.any.anyref.local.i.i32.local.before.i32.local.sum.i32.local.o.struct.new.Derived.i32.const.0.i32.const.0.local.p.local.o.local.any.local.o.loop.loop.struct.Base.0.local.p.i32.const.1.local.before.struct.Base.0.local.p.struct.Derived.0.ref.cast.ref.null.Derived.local.any.i32.const.42.local.sum.i32.add.local.sum.i32.sub.struct.Base.0.local.p.local.before.local.i.i32.add.local.i.i32.const.1.br_if.loop.i32.lt_s.local.i.local.count.local.sum.async
 test):
* JSTests/wasm/stress/wasm-array-omg-cse.js:
* Source/JavaScriptCore/b3/B3CanonicalizePrePostIncrements.cpp:
(JSC::B3::canonicalizePrePostIncrements):
* Source/JavaScriptCore/b3/B3EliminateCommonSubexpressions.cpp:
* Source/JavaScriptCore/b3/B3EliminateWasmGCAllocations.cpp:
(JSC::B3::eliminateWasmGCAllocations):
* Source/JavaScriptCore/b3/B3Procedure.h:
(JSC::B3::Procedure::setUsesWasmGCAccesses):
(JSC::B3::Procedure::usesWasmGCAccesses const):
* Source/JavaScriptCore/b3/B3ReduceStrength.cpp:
* Source/JavaScriptCore/b3/B3ReduceStrength.h:
* Source/JavaScriptCore/b3/B3WasmArraySetValue.cpp:
(JSC::B3::WasmArraySetValue::WasmArraySetValue):
* Source/JavaScriptCore/b3/B3WasmArraySetValue.h:
* Source/JavaScriptCore/b3/B3WasmStructSetValue.cpp:
(JSC::B3::WasmStructSetValue::WasmStructSetValue):
* Source/JavaScriptCore/b3/B3WasmStructSetValue.h:
* Source/JavaScriptCore/runtime/OptionsList.h:
* Source/JavaScriptCore/wasm/WasmOMGIRGenerator.cpp:
(JSC::Wasm::OMGIRGenerator::emitStructSet):
(JSC::Wasm::OMGIRGenerator::addArrayGet):
(JSC::Wasm::OMGIRGenerator::emitArraySetUncheckedWithoutWriteBarrier):
(JSC::Wasm::OMGIRGenerator::addStructGet):
* Source/WTF/WTF.xcodeproj/project.pbxproj:
* Source/WTF/wtf/CMakeLists.txt:
* Source/WTF/wtf/LayeredHashMap.h: Added.
(WTF::LayeredHashMap::LayeredHashMap):
(WTF::LayeredHashMap::startLayer):
(WTF::LayeredHashMap::dropLastLayer):
(WTF::LayeredHashMap::layerCount const):
(WTF::LayeredHashMap::clearEntries):
(WTF::LayeredHashMap::clear):
(WTF::LayeredHashMap::find):
(WTF::LayeredHashMap::findOrAdd):
(WTF::LayeredHashMap::add):
(WTF::LayeredHashMap::isEmptyKey):
(WTF::LayeredHashMap::Entry::isEmpty const):
(WTF::LayeredHashMap::allocateTable):
(WTF::LayeredHashMap::findSlot):
(WTF::LayeredHashMap::rehashIfNeeded):
* Tools/TestWebKitAPI/CMakeLists.txt:
* Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* Tools/TestWebKitAPI/Tests/WTF/LayeredHashMap.cpp: Added.
(TestWebKitAPI::TEST(WTF_LayeredHashMap, NestedLayers)):
(TestWebKitAPI::TEST(WTF_LayeredHashMap, AddDoesNotUpdate)):
(TestWebKitAPI::TEST(WTF_LayeredHashMap, FindOrAdd)):
(TestWebKitAPI::TEST(WTF_LayeredHashMap, SiblingLayers)):
(TestWebKitAPI::TEST(WTF_LayeredHashMap, ClearEntriesKeepsLayers)):
(TestWebKitAPI::TEST(WTF_LayeredHashMap, RandomizedAgainstModel)):
(TestWebKitAPI::TEST(WTF_LayeredHashMap, DefaultTraits)):
(TestWebKitAPI::TEST(WTF_LayeredHashMap, Clear)):
(TestWebKitAPI::TEST(WTF_LayeredHashMap, WellDistributedHash)):

Canonical link: https://commits.webkit.org/322019@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to