Skip to content

Commit 06b1579

Browse files
authored
[JS Interop] SignatureRefining: Refine results even when we can't refine params (#8055)
1 parent 0c63d8b commit 06b1579

File tree

2 files changed

+124
-73
lines changed

2 files changed

+124
-73
lines changed

src/passes/SignatureRefining.cpp

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ struct SignatureRefining : public Pass {
8787
// Normally we can optimize, but some cases prevent a particular signature
8888
// type from being changed at all, see below.
8989
bool canModify = true;
90+
91+
// If we can modify this, whether we can modify parameters specifically.
92+
// In some cases we can only refine results, namely if we are signature-
93+
// called: it is fine to refine results, as the calls still succeed (we
94+
// just happen to get something even more refined back), but we cannot
95+
// refine params (as calls might start to fail, with insufficiently-
96+
// refined inputs).
97+
bool canModifyParams = true;
9098
};
9199

92100
// This analysis also modifies the wasm as it goes, as the getResultsLUB()
@@ -154,10 +162,11 @@ struct SignatureRefining : public Pass {
154162
}
155163
}
156164

157-
// configureAll functions are signature-called, and must also not be
158-
// modified.
165+
// configureAll functions are signature-called, which means their params
166+
// must not be refined.
159167
for (auto func : Intrinsics(*module).getConfigureAllFunctions()) {
160-
allInfo[module->getFunction(func)->type.getHeapType()].canModify = false;
168+
allInfo[module->getFunction(func)->type.getHeapType()].canModifyParams =
169+
false;
161170
}
162171

163172
// Also skip modifying types used in tags, even private tags, since we don't
@@ -198,44 +207,48 @@ struct SignatureRefining : public Pass {
198207

199208
auto sig = type.getHeapType().getSignature();
200209

201-
auto numParams = sig.params.size();
202-
std::vector<LUBFinder> paramLUBs(numParams);
210+
// Change the params only if we are allowed to.
211+
auto newParams = func->getParams();
203212

204-
auto updateLUBs = [&](const ExpressionList& operands) {
205-
for (Index i = 0; i < numParams; i++) {
206-
paramLUBs[i].note(operands[i]->type);
207-
}
208-
};
213+
if (info.canModifyParams) {
214+
auto numParams = sig.params.size();
215+
std::vector<LUBFinder> paramLUBs(numParams);
209216

210-
for (auto* call : info.calls) {
211-
updateLUBs(call->operands);
212-
}
213-
for (auto* callRef : info.callRefs) {
214-
updateLUBs(callRef->operands);
215-
}
216-
for (auto* call : info.extraCalls) {
217-
// Note that these intrinsic calls have an extra function reference
218-
// param at the end, but updateLUBs looks at |numParams| only, so it
219-
// considers just the relevant parameters.
220-
updateLUBs(call->operands);
221-
}
217+
auto updateLUBs = [&](const ExpressionList& operands) {
218+
for (Index i = 0; i < numParams; i++) {
219+
paramLUBs[i].note(operands[i]->type);
220+
}
221+
};
222+
223+
for (auto* call : info.calls) {
224+
updateLUBs(call->operands);
225+
}
226+
for (auto* callRef : info.callRefs) {
227+
updateLUBs(callRef->operands);
228+
}
229+
for (auto* call : info.extraCalls) {
230+
// Note that these intrinsic calls have an extra function reference
231+
// param at the end, but updateLUBs looks at |numParams| only, so it
232+
// considers just the relevant parameters.
233+
updateLUBs(call->operands);
234+
}
222235

223-
// Find the final LUBs, and see if we found an improvement.
224-
std::vector<Type> newParamsTypes;
225-
for (auto& lub : paramLUBs) {
226-
if (!lub.noted()) {
227-
break;
236+
// Find the final LUBs, and see if we found an improvement.
237+
std::vector<Type> newParamsTypes;
238+
for (auto& lub : paramLUBs) {
239+
if (!lub.noted()) {
240+
break;
241+
}
242+
newParamsTypes.push_back(lub.getLUB());
243+
}
244+
if (newParamsTypes.size() < numParams) {
245+
// We did not have type information to calculate a LUB (no calls, or
246+
// some param is always unreachable), so there is nothing we can
247+
// improve here. Other passes might remove the type entirely.
248+
newParams = func->getParams();
249+
} else {
250+
newParams = Type(newParamsTypes);
228251
}
229-
newParamsTypes.push_back(lub.getLUB());
230-
}
231-
Type newParams;
232-
if (newParamsTypes.size() < numParams) {
233-
// We did not have type information to calculate a LUB (no calls, or
234-
// some param is always unreachable), so there is nothing we can improve
235-
// here. Other passes might remove the type entirely.
236-
newParams = func->getParams();
237-
} else {
238-
newParams = Type(newParamsTypes);
239252
}
240253

241254
auto& resultsLUB = info.resultsLUB;

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

Lines changed: 74 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,55 +7,55 @@
77
;; This is so even in closed world.
88

99
(module
10-
;; CHECK: (type $externs (array (mut externref)))
11-
;; OPEN_WORLD: (type $externs (array (mut externref)))
12-
(type $externs (array (mut externref)))
13-
14-
;; CHECK: (type $funcs (array (mut funcref)))
15-
;; OPEN_WORLD: (type $funcs (array (mut funcref)))
16-
(type $funcs (array (mut funcref)))
10+
;; CHECK: (rec
11+
;; CHECK-NEXT: (type $func-2 (func (param (ref (exact $struct))) (result (ref (exact $struct)))))
1712

18-
;; CHECK: (type $bytes (array (mut i8)))
19-
;; OPEN_WORLD: (type $bytes (array (mut i8)))
20-
(type $bytes (array (mut i8)))
13+
;; CHECK: (type $func-1 (func (param anyref) (result (ref (exact $struct)))))
2114

22-
;; CHECK: (rec
23-
;; CHECK-NEXT: (type $ret-any-2 (func (result (ref (exact $struct)))))
15+
;; CHECK: (type $2 (func (result i32)))
2416

2517
;; CHECK: (type $struct (struct))
2618

27-
;; CHECK: (type $ret-any-1 (func (result anyref)))
19+
;; CHECK: (type $4 (func))
2820

29-
;; CHECK: (type $6 (func (result i32)))
21+
;; CHECK: (type $externs (array (mut externref)))
22+
;; OPEN_WORLD: (rec
23+
;; OPEN_WORLD-NEXT: (type $func-2 (func (param (ref (exact $struct))) (result (ref (exact $struct)))))
3024

31-
;; CHECK: (type $7 (func))
25+
;; OPEN_WORLD: (type $func-1 (func (param anyref) (result (ref (exact $struct)))))
3226

33-
;; CHECK: (type $configureAll (func (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref)))
34-
;; OPEN_WORLD: (rec
35-
;; OPEN_WORLD-NEXT: (type $ret-any-2 (func (result (ref (exact $struct)))))
27+
;; OPEN_WORLD: (type $2 (func (result i32)))
3628

3729
;; OPEN_WORLD: (type $struct (struct))
3830

39-
;; OPEN_WORLD: (type $ret-any-1 (func (result anyref)))
31+
;; OPEN_WORLD: (type $4 (func))
4032

41-
;; OPEN_WORLD: (type $6 (func (result i32)))
33+
;; OPEN_WORLD: (type $externs (array (mut externref)))
34+
(type $externs (array (mut externref)))
35+
36+
;; CHECK: (type $funcs (array (mut funcref)))
37+
;; OPEN_WORLD: (type $funcs (array (mut funcref)))
38+
(type $funcs (array (mut funcref)))
4239

43-
;; OPEN_WORLD: (type $7 (func))
40+
;; CHECK: (type $bytes (array (mut i8)))
41+
;; OPEN_WORLD: (type $bytes (array (mut i8)))
42+
(type $bytes (array (mut i8)))
4443

44+
;; CHECK: (type $configureAll (func (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref)))
4545
;; OPEN_WORLD: (type $configureAll (func (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref)))
4646
(type $configureAll (func (param (ref null $externs)) (param (ref null $funcs)) (param (ref null $bytes)) (param externref)))
4747

4848
(type $struct (struct))
4949

5050
(rec
51-
(type $ret-any-1 (func (result anyref)))
51+
(type $func-1 (func (param anyref) (result anyref)))
5252

53-
;; use brands to allow $ret-any-1/2 to be optimized separately.
53+
;; use brands to allow $func-1/2 to be optimized separately.
5454
(type $brand1 (struct))
5555
)
5656

5757
(rec
58-
(type $ret-any-2 (func (result anyref)))
58+
(type $func-2 (func (param anyref) (result anyref)))
5959

6060
(type $brand2 (struct))
6161
(type $brand3 (struct))
@@ -88,7 +88,7 @@
8888
;; OPEN_WORLD: (start $start)
8989
(start $start)
9090

91-
;; CHECK: (func $start (type $7)
91+
;; CHECK: (func $start (type $4)
9292
;; CHECK-NEXT: (call $configureAll
9393
;; CHECK-NEXT: (array.new_elem $externs $externs
9494
;; CHECK-NEXT: (i32.const 0)
@@ -105,7 +105,7 @@
105105
;; CHECK-NEXT: (ref.null noextern)
106106
;; CHECK-NEXT: )
107107
;; CHECK-NEXT: )
108-
;; OPEN_WORLD: (func $start (type $7)
108+
;; OPEN_WORLD: (func $start (type $4)
109109
;; OPEN_WORLD-NEXT: (call $configureAll
110110
;; OPEN_WORLD-NEXT: (array.new_elem $externs $externs
111111
;; OPEN_WORLD-NEXT: (i32.const 0)
@@ -134,36 +134,74 @@
134134
)
135135
)
136136

137-
;; CHECK: (func $foo (type $6) (result i32)
137+
;; CHECK: (func $calls (type $4)
138+
;; CHECK-NEXT: (drop
139+
;; CHECK-NEXT: (call $bar
140+
;; CHECK-NEXT: (struct.new_default $struct)
141+
;; CHECK-NEXT: )
142+
;; CHECK-NEXT: )
143+
;; CHECK-NEXT: (drop
144+
;; CHECK-NEXT: (call $unconfigured
145+
;; CHECK-NEXT: (struct.new_default $struct)
146+
;; CHECK-NEXT: )
147+
;; CHECK-NEXT: )
148+
;; CHECK-NEXT: )
149+
;; OPEN_WORLD: (func $calls (type $4)
150+
;; OPEN_WORLD-NEXT: (drop
151+
;; OPEN_WORLD-NEXT: (call $bar
152+
;; OPEN_WORLD-NEXT: (struct.new_default $struct)
153+
;; OPEN_WORLD-NEXT: )
154+
;; OPEN_WORLD-NEXT: )
155+
;; OPEN_WORLD-NEXT: (drop
156+
;; OPEN_WORLD-NEXT: (call $unconfigured
157+
;; OPEN_WORLD-NEXT: (struct.new_default $struct)
158+
;; OPEN_WORLD-NEXT: )
159+
;; OPEN_WORLD-NEXT: )
160+
;; OPEN_WORLD-NEXT: )
161+
(func $calls
162+
(drop
163+
(call $bar
164+
(struct.new $struct)
165+
)
166+
)
167+
(drop
168+
(call $unconfigured
169+
(struct.new $struct)
170+
)
171+
)
172+
)
173+
174+
;; CHECK: (func $foo (type $2) (result i32)
138175
;; CHECK-NEXT: (i32.const 42)
139176
;; CHECK-NEXT: )
140-
;; OPEN_WORLD: (func $foo (type $6) (result i32)
177+
;; OPEN_WORLD: (func $foo (type $2) (result i32)
141178
;; OPEN_WORLD-NEXT: (i32.const 42)
142179
;; OPEN_WORLD-NEXT: )
143180
(func $foo (result i32)
144181
;; Nothing to do here anyhow, but do not error.
145182
(i32.const 42)
146183
)
147184

148-
;; CHECK: (func $bar (type $ret-any-1) (result anyref)
185+
;; CHECK: (func $bar (type $func-1) (param $x anyref) (result (ref (exact $struct)))
149186
;; CHECK-NEXT: (struct.new_default $struct)
150187
;; CHECK-NEXT: )
151-
;; OPEN_WORLD: (func $bar (type $ret-any-1) (result anyref)
188+
;; OPEN_WORLD: (func $bar (type $func-1) (param $x anyref) (result (ref (exact $struct)))
152189
;; OPEN_WORLD-NEXT: (struct.new_default $struct)
153190
;; OPEN_WORLD-NEXT: )
154-
(func $bar (type $ret-any-1) (result anyref)
155-
;; This will not be refined due to configureAll.
191+
(func $bar (type $func-1) (param $x anyref) (result anyref)
192+
;; The params will not be refined due to configureAll, but the result will.
156193
(struct.new $struct)
157194
)
158195

159-
;; CHECK: (func $unconfigured (type $ret-any-2) (result (ref (exact $struct)))
196+
;; CHECK: (func $unconfigured (type $func-2) (param $x (ref (exact $struct))) (result (ref (exact $struct)))
160197
;; CHECK-NEXT: (struct.new_default $struct)
161198
;; CHECK-NEXT: )
162-
;; OPEN_WORLD: (func $unconfigured (type $ret-any-2) (result (ref (exact $struct)))
199+
;; OPEN_WORLD: (func $unconfigured (type $func-2) (param $x (ref (exact $struct))) (result (ref (exact $struct)))
163200
;; OPEN_WORLD-NEXT: (struct.new_default $struct)
164201
;; OPEN_WORLD-NEXT: )
165-
(func $unconfigured (type $ret-any-2) (result anyref)
166-
;; This is not referred to by configureAll, and can be refined.
202+
(func $unconfigured (type $func-2) (param $x anyref) (result anyref)
203+
;; This is not referred to by configureAll, and can be refined in both
204+
;; params and result.
167205
(struct.new $struct)
168206
)
169207
)

0 commit comments

Comments
 (0)