Skip to content

Commit d5eb3ec

Browse files
committed
Bug 1728897 - Update Wasm try-delegate semantics to match spec r=rhunt
The semantics of the try-delegate Wasm exception handling instruction was recently changed in this spec discussion: WebAssembly/exception-handling#176 This patch adjusts compilation and validation to match the new semantics, which allows delegate to target any block. Differential Revision: https://phabricator.services.mozilla.com/D124424
1 parent e9afada commit d5eb3ec

File tree

7 files changed

+119
-33
lines changed

7 files changed

+119
-33
lines changed

js/src/jit-test/tests/wasm/exceptions/instructions.js

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1136,7 +1136,7 @@ assertEq(
11361136
1
11371137
);
11381138

1139-
// Test delegation to function body.
1139+
// Test delegation to function body and blocks.
11401140
assertEq(
11411141
wasmEvalText(
11421142
`(module
@@ -1149,6 +1149,46 @@ assertEq(
11491149
1
11501150
);
11511151

1152+
assertEq(
1153+
wasmEvalText(
1154+
`(module
1155+
(tag $exn (param i32))
1156+
(func (export "f") (result i32)
1157+
try (result i32)
1158+
block
1159+
try
1160+
i32.const 1
1161+
throw $exn
1162+
delegate 0
1163+
end
1164+
i32.const 0
1165+
catch $exn
1166+
end))`
1167+
).exports.f(),
1168+
1
1169+
);
1170+
1171+
assertEq(
1172+
wasmEvalText(
1173+
`(module
1174+
(tag $exn (param))
1175+
(func (export "f") (result i32)
1176+
try (result i32)
1177+
try
1178+
throw $exn
1179+
catch $exn
1180+
try
1181+
throw $exn
1182+
delegate 0
1183+
end
1184+
i32.const 0
1185+
catch_all
1186+
i32.const 1
1187+
end))`
1188+
).exports.f(),
1189+
1
1190+
);
1191+
11521192
assertEq(
11531193
wasmEvalText(
11541194
`(module

js/src/jit-test/tests/wasm/exceptions/throw-to-js.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,46 @@ assertWasmThrowsExn(() =>
7272
).exports.f()
7373
);
7474

75+
assertWasmThrowsExn(() =>
76+
wasmEvalText(
77+
`(module
78+
(tag $exn (param))
79+
(func (export "f")
80+
block
81+
try
82+
throw $exn
83+
delegate 0
84+
end))`
85+
).exports.f()
86+
);
87+
88+
assertWasmThrowsExn(() =>
89+
wasmEvalText(
90+
`(module
91+
(tag $exn (param))
92+
(func (export "f")
93+
loop
94+
try
95+
throw $exn
96+
delegate 0
97+
end))`
98+
).exports.f()
99+
);
100+
101+
assertWasmThrowsExn(() =>
102+
wasmEvalText(
103+
`(module
104+
(tag $exn (param))
105+
(func (export "f")
106+
(i32.const 1)
107+
if
108+
try
109+
throw $exn
110+
delegate 0
111+
end))`
112+
).exports.f()
113+
);
114+
75115
// Test throwing simple empty exceptions to JS.
76116
assertWasmThrowsExn(() =>
77117
wasmEvalText(

js/src/jit-test/tests/wasm/exceptions/validation.js

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,29 @@ function testValidateDelegate() {
576576
end))`
577577
);
578578

579+
wasmValidateText(
580+
`(module
581+
(tag $exn (param))
582+
(func
583+
block
584+
try
585+
throw $exn
586+
delegate 0
587+
end))`
588+
);
589+
590+
wasmValidateText(
591+
`(module
592+
(tag $exn (param))
593+
(func
594+
try
595+
catch $exn
596+
try
597+
throw $exn
598+
delegate 0
599+
end))`
600+
);
601+
579602
wasmFailValidateText(
580603
`(module
581604
(tag $exn (param))
@@ -611,31 +634,6 @@ function testValidateDelegate() {
611634
/delegate depth exceeds current nesting level/
612635
);
613636

614-
wasmFailValidateText(
615-
`(module
616-
(tag $exn (param))
617-
(func
618-
block
619-
try
620-
throw $exn
621-
delegate 0
622-
end))`,
623-
/delegate target was not a try or function body/
624-
);
625-
626-
wasmFailValidateText(
627-
`(module
628-
(tag $exn (param))
629-
(func
630-
try
631-
catch $exn
632-
try
633-
throw $exn
634-
delegate 0
635-
end))`,
636-
/delegate target was not a try or function body/
637-
);
638-
639637
wasmFailValidateText(
640638
`(module (func delegate 0))`,
641639
/delegate can only be used within a try/

js/src/wasm/WasmBCClass.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,7 @@ struct BaseCompiler final {
867867
inline Control& controlItem();
868868
inline Control& controlItem(uint32_t relativeDepth);
869869
inline Control& controlOutermost();
870+
inline LabelKind controlKind(uint32_t relativeDepth);
870871

871872
////////////////////////////////////////////////////////////
872873
//

js/src/wasm/WasmBCRegMgmt-inl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,10 @@ Control& BaseCompiler::controlItem(uint32_t relativeDepth) {
443443

444444
Control& BaseCompiler::controlOutermost() { return iter_.controlOutermost(); }
445445

446+
LabelKind BaseCompiler::controlKind(uint32_t relativeDepth) {
447+
return iter_.controlKind(relativeDepth);
448+
}
449+
446450
} // namespace wasm
447451
} // namespace js
448452

js/src/wasm/WasmBaselineCompile.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3744,7 +3744,6 @@ bool BaseCompiler::emitDelegate() {
37443744
}
37453745

37463746
Control& tryDelegate = controlItem();
3747-
Control& target = controlItem(relativeDepth);
37483747

37493748
// End the try branch like a plain catch block without exception ref handling.
37503749
if (deadCode_) {
@@ -3778,6 +3777,15 @@ bool BaseCompiler::emitDelegate() {
37783777
tryNote.entryPoint = tryNote.end;
37793778
tryNote.framePushed = masm.framePushed();
37803779

3780+
// If the target block is a non-try block, skip over it and find the next
3781+
// try block or the very last block (to re-throw out of the function).
3782+
Control& lastBlock = controlOutermost();
3783+
while (controlKind(relativeDepth) != LabelKind::Try &&
3784+
&controlItem(relativeDepth) != &lastBlock) {
3785+
relativeDepth++;
3786+
}
3787+
Control& target = controlItem(relativeDepth);
3788+
37813789
popBlockResults(ResultType::Empty(), target.stackHeight,
37823790
ContinuationKind::Jump);
37833791
masm.jump(&target.otherLabel);
@@ -3799,7 +3807,7 @@ bool BaseCompiler::endTryCatch(ResultType type) {
37993807
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
38003808

38013809
Control& tryCatch = controlItem();
3802-
LabelKind tryKind = iter_.controlKind(0);
3810+
LabelKind tryKind = controlKind(0);
38033811

38043812
if (deadCode_) {
38053813
fr.resetStackHeight(tryCatch.stackHeight, type);

js/src/wasm/WasmOpIter.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1626,11 +1626,6 @@ inline bool OpIter<Policy>::readDelegate(uint32_t* relativeDepth,
16261626
return fail("delegate depth exceeds current nesting level");
16271627
}
16281628

1629-
LabelKind kind = controlKind(*relativeDepth);
1630-
if (kind != LabelKind::Try && kind != LabelKind::Body) {
1631-
return fail("delegate target was not a try or function body");
1632-
}
1633-
16341629
// Because `delegate` acts like `end` and ends the block, we will check
16351630
// the stack here.
16361631
return checkStackAtEndOfBlock(resultType, tryResults);

0 commit comments

Comments
 (0)