Skip to content

Commit 5190098

Browse files
authored
[JS Interop] Optimize configureAll (#8054)
Remove the marking of all configureAll-referred functions as having public heap types. It turns out that only 2 passes then need to be fixed, as the others that care about public types either don't look at functions, or do not care about signature-called functions (e.g. making the type final is not a problem there).
1 parent 6d5fed3 commit 5190098

File tree

9 files changed

+176
-38
lines changed

9 files changed

+176
-38
lines changed

src/ir/intrinsics.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
#include "ir/intrinsics.h"
18+
#include "ir/find_all.h"
1819
#include "wasm-builder.h"
1920

2021
namespace wasm {
@@ -100,4 +101,29 @@ std::vector<Name> Intrinsics::getConfigureAllFunctions(Call* call) {
100101
return ret;
101102
}
102103

104+
std::vector<Name> Intrinsics::getConfigureAllFunctions() {
105+
// ConfigureAll in a start function makes its functions callable.
106+
if (module.start) {
107+
auto* start = module.getFunction(module.start);
108+
if (!start->imported()) {
109+
FindAll<Call> calls(start->body);
110+
// Look for the (single) configureAll.
111+
Call* configureAll = nullptr;
112+
for (auto* call : calls.list) {
113+
if (isConfigureAll(call)) {
114+
if (configureAll) {
115+
Fatal() << "Multiple configureAlls";
116+
} else {
117+
configureAll = call;
118+
}
119+
}
120+
}
121+
if (configureAll) {
122+
return getConfigureAllFunctions(configureAll);
123+
}
124+
}
125+
}
126+
return {};
127+
}
128+
103129
} // namespace wasm

src/ir/intrinsics.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ class Intrinsics {
109109
//
110110
// where the segment $seg is of size N.
111111
std::vector<Name> getConfigureAllFunctions(Call* call);
112+
// As above, but looks through the module to find the configureAll.
113+
std::vector<Name> getConfigureAllFunctions();
112114
};
113115

114116
} // namespace wasm

src/ir/module-utils.cpp

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616

1717
#include "module-utils.h"
18-
#include "ir/find_all.h"
1918
#include "ir/intrinsics.h"
2019
#include "ir/manipulation.h"
2120
#include "ir/metadata.h"
@@ -693,26 +692,6 @@ std::vector<HeapType> getPublicHeapTypes(Module& wasm) {
693692
WASM_UNREACHABLE("unexpected export kind");
694693
}
695694

696-
// ConfigureAll in a start function makes its functions callable. They are
697-
// only signature-called, so the heap type does not need to be public - nor
698-
// types referred to - but for now we mark them as public to avoid breakage in
699-
// several passes.
700-
// TODO Specific fixes in those passes could replace this, and allow better
701-
// optimization.
702-
if (wasm.start) {
703-
auto* start = wasm.getFunction(wasm.start);
704-
if (!start->imported()) {
705-
Intrinsics intrinsics(wasm);
706-
for (auto* call : FindAll<Call>(start->body).list) {
707-
if (intrinsics.isConfigureAll(call)) {
708-
for (auto func : intrinsics.getConfigureAllFunctions(call)) {
709-
notePublic(wasm.getFunction(func)->type.getHeapType());
710-
}
711-
}
712-
}
713-
}
714-
}
715-
716695
// Ignorable public types are public.
717696
for (auto type : getIgnorablePublicTypes()) {
718697
notePublic(type);

src/passes/AbstractTypeRefining.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,8 @@ struct AbstractTypeRefining : public Pass {
243243

244244
for (auto type : subTypes.types) {
245245
if (!type.isStruct()) {
246-
// TODO: support arrays and funcs
246+
// TODO: Support arrays and functions (for functions we will need to
247+
// handle configureAll).
247248
continue;
248249
}
249250

src/passes/SignaturePruning.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,13 @@ struct SignaturePruning : public Pass {
176176
allInfo[tag->type].optimizable = false;
177177
}
178178

179+
// configureAll functions are signature-called, and must also not be
180+
// modified.
181+
for (auto func : Intrinsics(*module).getConfigureAllFunctions()) {
182+
allInfo[module->getFunction(func)->type.getHeapType()].optimizable =
183+
false;
184+
}
185+
179186
// A type must have the same number of parameters and results as its
180187
// supertypes and subtypes, so we only attempt to modify types without
181188
// supertypes or subtypes.

src/passes/SignatureRefining.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ struct SignatureRefining : public Pass {
154154
}
155155
}
156156

157+
// configureAll functions are signature-called, and must also not be
158+
// modified.
159+
for (auto func : Intrinsics(*module).getConfigureAllFunctions()) {
160+
allInfo[module->getFunction(func)->type.getHeapType()].canModify = false;
161+
}
162+
157163
// Also skip modifying types used in tags, even private tags, since we don't
158164
// analyze exception handling or stack switching instructions. TODO: Analyze
159165
// and optimize exception handling and stack switching instructions.

src/passes/TypeFinalizing.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ struct TypeFinalizing : public Pass {
5050
subTypes = SubTypes(*module);
5151
}
5252

53+
// Note we don't need to worry about signature-called functions here
54+
// (configureAll) because such calls don't care about finality.
5355
auto privateTypes = ModuleUtils::getPrivateHeapTypes(*module);
5456
for (auto type : privateTypes) {
5557
// If we are finalizing types then we can only do that to leaf types. If
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
2+
3+
;; RUN: foreach %s %t wasm-opt --signature-pruning --closed-world -all -S -o - | filecheck %s
4+
5+
;; Test that configureAll is respected: referred functions are not pruned.
6+
7+
(module
8+
;; CHECK: (type $externs (array (mut externref)))
9+
(type $externs (array (mut externref)))
10+
11+
;; CHECK: (type $funcs (array (mut funcref)))
12+
(type $funcs (array (mut funcref)))
13+
14+
;; CHECK: (type $bytes (array (mut i8)))
15+
(type $bytes (array (mut i8)))
16+
17+
18+
;; CHECK: (type $configureAll (func (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref)))
19+
(type $configureAll (func (param (ref null $externs)) (param (ref null $funcs)) (param (ref null $bytes)) (param externref)))
20+
21+
(type $struct (struct))
22+
23+
(rec
24+
;; CHECK: (rec
25+
;; CHECK-NEXT: (type $any-2 (func))
26+
27+
;; CHECK: (type $any-1 (func (param anyref)))
28+
(type $any-1 (func (param anyref)))
29+
30+
;; use brands to allow $any-1/2 to be optimized separately.
31+
(type $brand1 (struct))
32+
)
33+
34+
(rec
35+
(type $any-2 (func (param anyref)))
36+
37+
(type $brand2 (struct))
38+
(type $brand3 (struct))
39+
)
40+
41+
;; CHECK: (type $6 (func (result i32)))
42+
43+
;; CHECK: (type $7 (func))
44+
45+
;; CHECK: (import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll) (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref)))
46+
(import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll)))
47+
48+
49+
;; CHECK: (data $bytes "12345678")
50+
51+
;; CHECK: (elem $externs externref (item (ref.null noextern)))
52+
(elem $externs externref
53+
(ref.null extern)
54+
)
55+
56+
;; CHECK: (elem $funcs func $foo $bar)
57+
(elem $funcs funcref
58+
(ref.func $foo)
59+
(ref.func $bar)
60+
)
61+
62+
(data $bytes "12345678")
63+
64+
;; CHECK: (start $start)
65+
(start $start)
66+
67+
;; CHECK: (func $start (type $7)
68+
;; CHECK-NEXT: (call $configureAll
69+
;; CHECK-NEXT: (array.new_elem $externs $externs
70+
;; CHECK-NEXT: (i32.const 0)
71+
;; CHECK-NEXT: (i32.const 1)
72+
;; CHECK-NEXT: )
73+
;; CHECK-NEXT: (array.new_elem $funcs $funcs
74+
;; CHECK-NEXT: (i32.const 0)
75+
;; CHECK-NEXT: (i32.const 2)
76+
;; CHECK-NEXT: )
77+
;; CHECK-NEXT: (array.new_data $bytes $bytes
78+
;; CHECK-NEXT: (i32.const 0)
79+
;; CHECK-NEXT: (i32.const 8)
80+
;; CHECK-NEXT: )
81+
;; CHECK-NEXT: (ref.null noextern)
82+
;; CHECK-NEXT: )
83+
;; CHECK-NEXT: )
84+
(func $start
85+
(call $configureAll
86+
(array.new_elem $externs $externs
87+
(i32.const 0) (i32.const 1))
88+
(array.new_elem $funcs $funcs
89+
(i32.const 0) (i32.const 2))
90+
(array.new_data $bytes $bytes
91+
(i32.const 0) (i32.const 8))
92+
(ref.null extern)
93+
)
94+
)
95+
96+
;; CHECK: (func $foo (type $6) (result i32)
97+
;; CHECK-NEXT: (i32.const 42)
98+
;; CHECK-NEXT: )
99+
(func $foo (result i32)
100+
;; Nothing to do here anyhow, but do not error.
101+
(i32.const 42)
102+
)
103+
104+
;; CHECK: (func $bar (type $any-1) (param $x anyref)
105+
;; CHECK-NEXT: )
106+
(func $bar (type $any-1) (param $x anyref)
107+
;; The param is unused, but will not be pruned (turned into a local) due to
108+
;; configureAll.
109+
)
110+
111+
;; CHECK: (func $unconfigured (type $any-2)
112+
;; CHECK-NEXT: (local $0 anyref)
113+
;; CHECK-NEXT: )
114+
(func $unconfigured (type $any-2) (param $x anyref)
115+
;; This is not referred to by configureAll, and can be pruned.
116+
)
117+
)

test/lit/passes/signature-refining-configureAll.wast

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,35 +24,33 @@
2424

2525
;; CHECK: (type $struct (struct))
2626

27-
;; CHECK: (type $5 (func))
27+
;; CHECK: (type $ret-any-1 (func (result anyref)))
28+
29+
;; CHECK: (type $6 (func (result i32)))
30+
31+
;; CHECK: (type $7 (func))
2832

2933
;; CHECK: (type $configureAll (func (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref)))
3034
;; OPEN_WORLD: (rec
3135
;; OPEN_WORLD-NEXT: (type $ret-any-2 (func (result (ref (exact $struct)))))
3236

3337
;; OPEN_WORLD: (type $struct (struct))
3438

35-
;; OPEN_WORLD: (type $5 (func))
39+
;; OPEN_WORLD: (type $ret-any-1 (func (result anyref)))
40+
41+
;; OPEN_WORLD: (type $6 (func (result i32)))
42+
43+
;; OPEN_WORLD: (type $7 (func))
3644

3745
;; OPEN_WORLD: (type $configureAll (func (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref)))
3846
(type $configureAll (func (param (ref null $externs)) (param (ref null $funcs)) (param (ref null $bytes)) (param externref)))
3947

4048
(type $struct (struct))
4149

4250
(rec
43-
;; CHECK: (type $7 (func (result i32)))
44-
45-
;; CHECK: (rec
46-
;; CHECK-NEXT: (type $ret-any-1 (func (result anyref)))
47-
;; OPEN_WORLD: (type $7 (func (result i32)))
48-
49-
;; OPEN_WORLD: (rec
50-
;; OPEN_WORLD-NEXT: (type $ret-any-1 (func (result anyref)))
5151
(type $ret-any-1 (func (result anyref)))
5252

5353
;; use brands to allow $ret-any-1/2 to be optimized separately.
54-
;; CHECK: (type $brand1 (struct))
55-
;; OPEN_WORLD: (type $brand1 (struct))
5654
(type $brand1 (struct))
5755
)
5856

@@ -90,7 +88,7 @@
9088
;; OPEN_WORLD: (start $start)
9189
(start $start)
9290

93-
;; CHECK: (func $start (type $5)
91+
;; CHECK: (func $start (type $7)
9492
;; CHECK-NEXT: (call $configureAll
9593
;; CHECK-NEXT: (array.new_elem $externs $externs
9694
;; CHECK-NEXT: (i32.const 0)
@@ -107,7 +105,7 @@
107105
;; CHECK-NEXT: (ref.null noextern)
108106
;; CHECK-NEXT: )
109107
;; CHECK-NEXT: )
110-
;; OPEN_WORLD: (func $start (type $5)
108+
;; OPEN_WORLD: (func $start (type $7)
111109
;; OPEN_WORLD-NEXT: (call $configureAll
112110
;; OPEN_WORLD-NEXT: (array.new_elem $externs $externs
113111
;; OPEN_WORLD-NEXT: (i32.const 0)
@@ -136,10 +134,10 @@
136134
)
137135
)
138136

139-
;; CHECK: (func $foo (type $7) (result i32)
137+
;; CHECK: (func $foo (type $6) (result i32)
140138
;; CHECK-NEXT: (i32.const 42)
141139
;; CHECK-NEXT: )
142-
;; OPEN_WORLD: (func $foo (type $7) (result i32)
140+
;; OPEN_WORLD: (func $foo (type $6) (result i32)
143141
;; OPEN_WORLD-NEXT: (i32.const 42)
144142
;; OPEN_WORLD-NEXT: )
145143
(func $foo (result i32)

0 commit comments

Comments
 (0)