Skip to content

Commit cb18db5

Browse files
authored
[Custom Descriptors] Use exact imports in wasm-split (#8043)
When custom descriptors are enabled, import primary functions into secondary modules using exact imports. This allows references to those functions in the secondary module to remain exact, just like they are before splitting. Remove the exact casts we previously inserted to fix this problem. Do not use exact imports when custom descriptors are not enabled. In principle this could cause validation errors because we allow e.g. exact locals even when custom descriptors are not enabled. This could be worked around in the future either by running a pass to remove exactness before splitting or by always using and allowing exact imports, but then emitting them as inexact imports when custom descriptors are disabled.
1 parent 253aab4 commit cb18db5

File tree

9 files changed

+58
-115
lines changed

9 files changed

+58
-115
lines changed

src/ir/module-splitting.cpp

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,13 @@
6767
// 2. It assumes that either all table segment offsets are constants or there
6868
// is exactly one segment that may have a non-constant offset. It also
6969
// assumes that all segments are active segments.
70-
70+
//
71+
// 3. It assumes that if exact function references are required for validity
72+
// (because they are stored in a local with an exact function type, for
73+
// example), then custom descriptors are allowed so primary functions can
74+
// be imported exactly. This could be worked around by removing exactness
75+
// from the IR before splitting.
76+
//
7177
#include "ir/module-splitting.h"
7278
#include "asmjs/shared-constants.h"
7379
#include "ir/export-utils.h"
@@ -341,7 +347,6 @@ struct ModuleSplitter {
341347
void setupTablePatching();
342348
void shareImportableItems();
343349
void removeUnusedSecondaryElements();
344-
void updateIR();
345350

346351
ModuleSplitter(Module& primary, const Config& config)
347352
: config(config), primary(primary), tableManager(primary),
@@ -358,7 +363,6 @@ struct ModuleSplitter {
358363
setupTablePatching();
359364
shareImportableItems();
360365
removeUnusedSecondaryElements();
361-
updateIR();
362366
}
363367
};
364368

@@ -520,7 +524,7 @@ void ModuleSplitter::exportImportFunction(Name funcName,
520524
func->hasExplicitName = primaryFunc->hasExplicitName;
521525
func->module = config.importNamespace;
522526
func->base = exportName;
523-
func->type = func->type.with(Inexact);
527+
func->type = func->type.withInexactIfNoCustomDescs(secondary->features);
524528
secondary->addFunction(std::move(func));
525529
}
526530
}
@@ -981,31 +985,6 @@ void ModuleSplitter::removeUnusedSecondaryElements() {
981985
}
982986
}
983987

984-
void ModuleSplitter::updateIR() {
985-
// Imported functions may need type updates.
986-
struct Fixer : public PostWalker<Fixer> {
987-
void visitRefFunc(RefFunc* curr) {
988-
auto& wasm = *getModule();
989-
auto* func = wasm.getFunction(curr->func);
990-
if (func->type != curr->type) {
991-
// This became an import, and lost exactness.
992-
assert(!func->type.isExact());
993-
assert(curr->type.isExact());
994-
if (wasm.features.hasCustomDescriptors()) {
995-
// Add a cast, as the parent may depend on the exactness to validate.
996-
// TODO: The cast may be needed even without CD enabled
997-
replaceCurrent(Builder(wasm).makeRefCast(curr, curr->type));
998-
}
999-
curr->type = curr->type.with(Inexact);
1000-
}
1001-
}
1002-
} fixer;
1003-
fixer.walkModule(&primary);
1004-
for (auto& secondaryPtr : secondaries) {
1005-
fixer.walkModule(secondaryPtr.get());
1006-
}
1007-
}
1008-
1009988
} // anonymous namespace
1010989

1011990
Results splitFunctions(Module& primary, const Config& config) {

src/ir/module-splitting.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,18 @@
2626
// functions. The secondary module imports all of its dependencies from the
2727
// primary module.
2828
//
29-
// This code currently makes a couple assumptions about the modules that will be
29+
// This code currently makes a few assumptions about the modules that will be
3030
// split and will fail assertions if those assumptions are not true.
3131
//
3232
// 1) It assumes that mutable-globals are allowed.
3333
//
3434
// 2) It assumes that either all segment offsets are constants or there is
3535
// exactly one segment that may have a non-constant offset.
3636
//
37+
// 3) It assumes that exact function references are only required for validity
38+
// if custom descriptors (and its exact function import feature) are
39+
// allowed.
40+
//
3741
// These requirements will be relaxed as necessary in the future, but for now
3842
// this code should be considered experimental and used with care.
3943

test/example/module-splitting.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ Secondary:
745745
(module
746746
(type $0 (func))
747747
(import "primary" "%table" (table $0 1 funcref))
748-
(import "primary" "%foo_1" (func $foo (type $0)))
748+
(import "primary" "%foo_1" (func $foo (exact (type $0))))
749749
(elem $0 (i32.const 0) $bar)
750750
(func $bar (type $0)
751751
(call $foo)
@@ -1055,7 +1055,7 @@ Secondary:
10551055
(module
10561056
(type $0 (func))
10571057
(import "primary" "%table_2" (table $0 1 funcref))
1058-
(import "primary" "%foo" (func $foo (type $0)))
1058+
(import "primary" "%foo" (func $foo (exact (type $0))))
10591059
(elem $0 (i32.const 0) $bar)
10601060
(func $bar (type $0)
10611061
(call $foo)
@@ -1102,7 +1102,7 @@ Secondary:
11021102
(module
11031103
(type $0 (func (param i32) (result i32)))
11041104
(import "primary" "%table_2" (table $0 1 funcref))
1105-
(import "primary" "%foo" (func $foo (type $0) (param i32) (result i32)))
1105+
(import "primary" "%foo" (func $foo (exact (type $0) (param i32) (result i32))))
11061106
(elem $0 (i32.const 0) $bar)
11071107
(func $bar (type $0) (param $0 i32) (result i32)
11081108
(call $foo

test/lit/wasm-split/exact.wast

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373

7474
;; SECONDARY: (import "primary" "table" (table $timport$0 1 funcref))
7575

76-
;; SECONDARY: (import "primary" "foo" (func $foo (type $0)))
76+
;; SECONDARY: (import "primary" "foo" (func $foo (exact (type $0))))
7777

7878
;; SECONDARY: (elem $0 (i32.const 0) $bar)
7979

@@ -82,9 +82,7 @@
8282
;; SECONDARY: (func $bar (type $0)
8383
;; SECONDARY-NEXT: (local $exact (ref (exact $0)))
8484
;; SECONDARY-NEXT: (local.set $exact
85-
;; SECONDARY-NEXT: (ref.cast (ref (exact $0))
86-
;; SECONDARY-NEXT: (ref.func $foo)
87-
;; SECONDARY-NEXT: )
85+
;; SECONDARY-NEXT: (ref.func $foo)
8886
;; SECONDARY-NEXT: )
8987
;; SECONDARY-NEXT: (local.set $exact
9088
;; SECONDARY-NEXT: (ref.func $bar)

test/lit/wasm-split/multi-split-escape-names.wast

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424

2525
;; MOD1: (import "primary" "table" (table $timport$0 3 funcref))
2626

27-
;; MOD1: (import "primary" "trampoline_std::operator<<\\28std::__2::basic_ostream<char\\2c\\20std::__2::char_traits<char>>&\\2c\\20wasm::Module&\\29" (func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29 (result f32)))
27+
;; MOD1: (import "primary" "trampoline_std::operator<<\\28std::__2::basic_ostream<char\\2c\\20std::__2::char_traits<char>>&\\2c\\20wasm::Module&\\29" (func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29 (exact (result f32))))
2828

29-
;; MOD1: (import "primary" "trampoline_wasm::Literal::Literal\\28std::__2::array<wasm::Literal\\2c\\204ul>\\20const&\\29" (func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29 (result i64)))
29+
;; MOD1: (import "primary" "trampoline_wasm::Literal::Literal\\28std::__2::array<wasm::Literal\\2c\\204ul>\\20const&\\29" (func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29 (exact (result i64))))
3030

3131
;; MOD1: (elem $0 (i32.const 2) $wasm::Type::getFeatures\28\29\20const)
3232

@@ -38,16 +38,12 @@
3838
;; MOD1-NEXT: )
3939
;; MOD1-NEXT: (drop
4040
;; MOD1-NEXT: (call_ref $1
41-
;; MOD1-NEXT: (ref.cast (ref (exact $1))
42-
;; MOD1-NEXT: (ref.func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29)
43-
;; MOD1-NEXT: )
41+
;; MOD1-NEXT: (ref.func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29)
4442
;; MOD1-NEXT: )
4543
;; MOD1-NEXT: )
4644
;; MOD1-NEXT: (drop
4745
;; MOD1-NEXT: (call_ref $0
48-
;; MOD1-NEXT: (ref.cast (ref (exact $0))
49-
;; MOD1-NEXT: (ref.func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29)
50-
;; MOD1-NEXT: )
46+
;; MOD1-NEXT: (ref.func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29)
5147
;; MOD1-NEXT: )
5248
;; MOD1-NEXT: )
5349
;; MOD1-NEXT: (i32.const 0)
@@ -79,18 +75,16 @@
7975

8076
;; MOD2: (import "primary" "table" (table $timport$0 3 funcref))
8177

82-
;; MOD2: (import "primary" "trampoline_std::operator<<\\28std::__2::basic_ostream<char\\2c\\20std::__2::char_traits<char>>&\\2c\\20wasm::Module&\\29" (func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29 (result f32)))
78+
;; MOD2: (import "primary" "trampoline_std::operator<<\\28std::__2::basic_ostream<char\\2c\\20std::__2::char_traits<char>>&\\2c\\20wasm::Module&\\29" (func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29 (exact (result f32))))
8379

84-
;; MOD2: (import "primary" "trampoline_wasm::Type::getFeatures\\28\\29\\20const" (func $trampoline_wasm::Type::getFeatures\28\29\20const (result i32)))
80+
;; MOD2: (import "primary" "trampoline_wasm::Type::getFeatures\\28\\29\\20const" (func $trampoline_wasm::Type::getFeatures\28\29\20const (exact (result i32))))
8581

8682
;; MOD2: (elem $0 (i32.const 0) $wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29)
8783

8884
;; MOD2: (func $wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29 (result i64)
8985
;; MOD2-NEXT: (drop
9086
;; MOD2-NEXT: (call_ref $1
91-
;; MOD2-NEXT: (ref.cast (ref (exact $1))
92-
;; MOD2-NEXT: (ref.func $trampoline_wasm::Type::getFeatures\28\29\20const)
93-
;; MOD2-NEXT: )
87+
;; MOD2-NEXT: (ref.func $trampoline_wasm::Type::getFeatures\28\29\20const)
9488
;; MOD2-NEXT: )
9589
;; MOD2-NEXT: )
9690
;; MOD2-NEXT: (drop
@@ -100,9 +94,7 @@
10094
;; MOD2-NEXT: )
10195
;; MOD2-NEXT: (drop
10296
;; MOD2-NEXT: (call_ref $0
103-
;; MOD2-NEXT: (ref.cast (ref (exact $0))
104-
;; MOD2-NEXT: (ref.func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29)
105-
;; MOD2-NEXT: )
97+
;; MOD2-NEXT: (ref.func $trampoline_std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29)
10698
;; MOD2-NEXT: )
10799
;; MOD2-NEXT: )
108100
;; MOD2-NEXT: (i64.const 0)
@@ -134,25 +126,21 @@
134126

135127
;; MOD3: (import "primary" "table" (table $timport$0 3 funcref))
136128

137-
;; MOD3: (import "primary" "trampoline_wasm::Literal::Literal\\28std::__2::array<wasm::Literal\\2c\\204ul>\\20const&\\29" (func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29 (result i64)))
129+
;; MOD3: (import "primary" "trampoline_wasm::Literal::Literal\\28std::__2::array<wasm::Literal\\2c\\204ul>\\20const&\\29" (func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29 (exact (result i64))))
138130

139-
;; MOD3: (import "primary" "trampoline_wasm::Type::getFeatures\\28\\29\\20const" (func $trampoline_wasm::Type::getFeatures\28\29\20const (result i32)))
131+
;; MOD3: (import "primary" "trampoline_wasm::Type::getFeatures\\28\\29\\20const" (func $trampoline_wasm::Type::getFeatures\28\29\20const (exact (result i32))))
140132

141133
;; MOD3: (elem $0 (i32.const 1) $std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29)
142134

143135
;; MOD3: (func $std::operator<<\28std::__2::basic_ostream<char\2c\20std::__2::char_traits<char>>&\2c\20wasm::Module&\29 (result f32)
144136
;; MOD3-NEXT: (drop
145137
;; MOD3-NEXT: (call_ref $1
146-
;; MOD3-NEXT: (ref.cast (ref (exact $1))
147-
;; MOD3-NEXT: (ref.func $trampoline_wasm::Type::getFeatures\28\29\20const)
148-
;; MOD3-NEXT: )
138+
;; MOD3-NEXT: (ref.func $trampoline_wasm::Type::getFeatures\28\29\20const)
149139
;; MOD3-NEXT: )
150140
;; MOD3-NEXT: )
151141
;; MOD3-NEXT: (drop
152142
;; MOD3-NEXT: (call_ref $0
153-
;; MOD3-NEXT: (ref.cast (ref (exact $0))
154-
;; MOD3-NEXT: (ref.func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29)
155-
;; MOD3-NEXT: )
143+
;; MOD3-NEXT: (ref.func $trampoline_wasm::Literal::Literal\28std::__2::array<wasm::Literal\2c\204ul>\20const&\29)
156144
;; MOD3-NEXT: )
157145
;; MOD3-NEXT: )
158146
;; MOD3-NEXT: (drop

0 commit comments

Comments
 (0)