Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/ir/module-splitting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,10 +353,10 @@ struct ModuleSplitter {
classifyFunctions();
moveSecondaryFunctions();
thunkExportedSecondaryFunctions();
shareImportableItems();
indirectReferencesToSecondaryFunctions();
indirectCallsToSecondaryFunctions();
exportImportCalledPrimaryFunctions();
shareImportableItems();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why the order change?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is what I meant by this:

The first commit runs into a crash where the table is not present yet. I fixed that in the last commit by reordering operations: shareImportableItems needs the other code to run first so it can see which tables etc. need to be used.

That is the table needs to be created at the right time. I think...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't see why that would be related to this change 🤔

Copy link
Copy Markdown
Member

@aheejin aheejin May 15, 2026

Choose a reason for hiding this comment

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

I don't either... Can you give an example?
That order change was the gist of #8688, so without breaking a lot of new assumptions, it is not easy to flip...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

For an example, run the multi-split test in this PR. (That is, take all of this PR but the part in question. The test crashes because it doesn't find the table. Reordering makes the table exist - but I have no high-level understanding of the flow here 😄 so maybe it is the wrong fix)

setupTablePatching();
}
};
Expand Down Expand Up @@ -432,11 +432,11 @@ void ModuleSplitter::classifyFunctions() {
configSecondaryFuncs.insert(funcs.begin(), funcs.end());
}
for (auto& func : primary.functions) {
// The start function must always be kept in the primary module.
if (func->imported() || !configSecondaryFuncs.contains(func->name) ||
segmentReferrers.contains(func->name)) {
segmentReferrers.contains(func->name) || func->name == primary.start) {
Comment on lines +435 to +437
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we just do something like

if (primary.start)
  primaryFuncs.insert(primary.start)

at the start of the function, rather than in this loop?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We also need the if's else not to happen, though. That is, we need to add it in the primary and not in the secondary. If the loop body is not modified, it will add it to the second.

primaryFuncs.insert(func->name);
} else {
assert(func->name != primary.start && "The start function must be kept");
allSecondaryFuncs.insert(func->name);
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/tools/wasm-split/wasm-split.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,13 @@ void splitModule(const WasmSplitOptions& options) {
}
continue;
}
if (function->name == wasm.start) {
if (!options.quiet) {
std::cerr << "warning: cannot split out start function " << func
<< "\n";
}
continue;
}
Comment on lines +299 to +305
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can't you do the same thing in multiSplitModule after this line?

assert(currFuncs);

Then we don't need to do anything in module-splitting.cpp.

Also while you're at it you can add this there too, to be consistent with splitModule:

if (!function) {
if (!options.quiet) {
std::cerr << "warning: function " << func << " does not exist\n";
}
continue;
}
if (function->imported()) {
if (!options.quiet) {
std::cerr << "warning: cannot split out imported function " << func
<< "\n";
}
continue;
}

if (!options.quiet && options.keepFuncs.contains(func)) {
std::cerr << "warning: function " << func
<< " was to be both kept and split. It will be split.\n";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
(func $keep
(call $split)
)
;; SECONDARY: (import "primary" "table" (table $table 1 funcref))
;; SECONDARY: (import "primary" "table" (table $table 2 funcref))

;; SECONDARY: (import "primary" "global" (global $base i32))

Expand Down
86 changes: 86 additions & 0 deletions test/lit/wasm-split/multi-split-start.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.

;; RUN: wasm-split -all -g --multi-split %s --manifest %s.manifest --out-prefix=%t -o %t.wasm
;; RUN: wasm-dis %t.wasm | filecheck %s --check-prefix=PRIMARY
;; RUN: wasm-dis %t1.wasm | filecheck %s --check-prefix=MOD1
;; RUN: wasm-dis %t2.wasm | filecheck %s --check-prefix=MOD2
;; RUN: wasm-dis %t3.wasm | filecheck %s --check-prefix=MOD3

;; The start function, $C, cannot be split it, and will remain in the primary.

(module
;; PRIMARY: (type $0 (func))

;; PRIMARY: (import "placeholder.2" "0" (func $placeholder_0))

;; PRIMARY: (table $0 1 funcref)

;; PRIMARY: (elem $0 (i32.const 0) $placeholder_0)

;; PRIMARY: (export "C" (func $C))

;; PRIMARY: (export "table" (table $0))

;; PRIMARY: (start $C)
(start $C)

;; MOD1: (type $0 (func))

;; MOD1: (import "primary" "table" (table $timport$0 1 funcref))

;; MOD1: (import "primary" "C" (func $C (exact)))

;; MOD1: (func $A
;; MOD1-NEXT: (call $A)
;; MOD1-NEXT: (call_indirect (type $0)
;; MOD1-NEXT: (i32.const 0)
;; MOD1-NEXT: )
;; MOD1-NEXT: (call $C)
;; MOD1-NEXT: )
(func $A
(call $A)
(call $B)
(call $C)
)

;; MOD2: (type $0 (func))

;; MOD2: (import "primary" "table" (table $timport$0 1 funcref))

;; MOD2: (elem $0 (i32.const 0) $B)

;; MOD2: (func $B
;; MOD2-NEXT: (drop
;; MOD2-NEXT: (i32.const 42)
;; MOD2-NEXT: )
;; MOD2-NEXT: )
(func $B
(drop
(i32.const 42)
)
)

;; PRIMARY: (func $C
;; PRIMARY-NEXT: (drop
;; PRIMARY-NEXT: (i32.const 1337)
;; PRIMARY-NEXT: )
;; PRIMARY-NEXT: )
(func $C
(drop
(i32.const 1337)
)
)

;; MOD3: (type $0 (func))

;; MOD3: (func $D
;; MOD3-NEXT: (drop
;; MOD3-NEXT: (i32.const 999999)
;; MOD3-NEXT: )
;; MOD3-NEXT: )
(func $D
(drop
(i32.const 999999)
)
)
)
9 changes: 9 additions & 0 deletions test/lit/wasm-split/multi-split-start.wast.manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
1:
A

2:
B

3:
C
D
4 changes: 2 additions & 2 deletions test/lit/wasm-split/split-module-items.wast
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@
;; PRIMARY: (tag $keep-tag (type $1) (param i32))
;; PRIMARY-NEXT: (tag $shared-tag (type $1) (param i32))

;; PRIMARY: (export "memory" (memory $shared-memory))
;; PRIMARY: (export "keep" (func $keep))
;; PRIMARY-NEXT: (export "memory" (memory $shared-memory))
;; PRIMARY-NEXT: (export "table" (table $shared-table))
;; PRIMARY-NEXT: (export "global" (global $shared-global))
;; PRIMARY-NEXT: (export "tag" (tag $shared-tag))
;; PRIMARY-NEXT: (export "keep" (func $keep))
;; PRIMARY-NEXT: (export "table_5" (table $2))

;; SECONDARY: (import "primary" "memory" (memory $shared-memory 1 1))
Expand Down
28 changes: 28 additions & 0 deletions test/lit/wasm-split/start.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.

;; RUN: wasm-split %s --split-funcs=start_func,other -o1 %t.1.wasm -o2 %t.2.wasm -g 2>&1
;; RUN: wasm-dis -all %t.1.wasm | filecheck %s --check-prefix PRIMARY
;; RUN: wasm-dis -all %t.2.wasm | filecheck %s --check-prefix SECONDARY

;; Do not error on trying to split out the start function. It cannot be
;; split out, keep it in the primary module.

(module
;; PRIMARY: (type $0 (func))

;; PRIMARY: (start $start_func)

;; PRIMARY: (func $start_func (type $0)
;; PRIMARY-NEXT: )
(func $start_func)

(start $start_func)

;; SECONDARY: (type $0 (func))

;; SECONDARY: (func $other (type $0)
;; SECONDARY-NEXT: )
(func $other)
)


Loading