Skip to content

Commit c0e8f90

Browse files
osa1Commit Queue
authored andcommitted
[wasm_builder] Add new exception handling instructions
These instructions are not used yet as they're not enabled by default in Chrome yet. This CL is mainly tested by the child CL, which uses instructions added in this CL for exception handling. Change-Id: I04d767599f47cdb6abc9cca02974647d9e5421fb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/411581 Commit-Queue: Ömer Ağacan <[email protected]> Reviewed-by: Martin Kustermann <[email protected]>
1 parent 889c670 commit c0e8f90

File tree

8 files changed

+303
-19
lines changed

8 files changed

+303
-19
lines changed

pkg/dart2wasm/lib/async.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,13 +275,13 @@ class AsyncStateMachineCodeGenerator extends StateMachineCodeGenerator {
275275
}
276276

277277
// Handle Dart exceptions.
278-
b.catch_(translator.getExceptionTag(b.module));
278+
b.catch_legacy(translator.getExceptionTag(b.module));
279279
b.local_set(stackTraceLocal);
280280
b.local_set(exceptionLocal);
281281
callCompleteError();
282282

283283
// Handle JS exceptions.
284-
b.catch_all();
284+
b.catch_all_legacy();
285285

286286
// Create a generic JavaScript error.
287287
call(translator.javaScriptErrorFactory.reference);

pkg/dart2wasm/lib/code_generator.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ abstract class AstCodeGenerator
978978

979979
// Insert a catch instruction which will catch any thrown Dart
980980
// exceptions.
981-
b.catch_(translator.getExceptionTag(b.module));
981+
b.catch_legacy(translator.getExceptionTag(b.module));
982982

983983
b.local_set(thrownStackTrace);
984984
b.local_set(thrownException);
@@ -1007,7 +1007,7 @@ abstract class AstCodeGenerator
10071007
.any((c) => guardCanMatchJSException(translator, c.guard))) {
10081008
// This catches any objects that aren't dart exceptions, such as
10091009
// JavaScript exceptions or objects.
1010-
b.catch_all();
1010+
b.catch_all_legacy();
10111011

10121012
// We can't inspect the thrown object in a catch_all and get a stack
10131013
// trace, so we just attach the current stack trace.
@@ -1122,12 +1122,12 @@ abstract class AstCodeGenerator
11221122
}
11231123

11241124
// Handle Dart exceptions.
1125-
b.catch_(translator.getExceptionTag(b.module));
1125+
b.catch_legacy(translator.getExceptionTag(b.module));
11261126
translateStatement(node.finalizer);
11271127
b.rethrow_(tryBlock);
11281128

11291129
// Handle JS exceptions.
1130-
b.catch_all();
1130+
b.catch_all_legacy();
11311131
translateStatement(node.finalizer);
11321132
b.rethrow_(tryBlock);
11331133

pkg/dart2wasm/lib/state_machine.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ class ExceptionHandlerStack {
358358
codeGen._jumpToTarget(_handlers[nextHandlerIdx].target);
359359
}
360360

361-
b.catch_(codeGen.translator.getExceptionTag(b.module));
361+
b.catch_legacy(codeGen.translator.getExceptionTag(b.module));
362362
b.local_set(stackTraceLocal);
363363
b.local_set(exceptionLocal);
364364

@@ -375,7 +375,7 @@ class ExceptionHandlerStack {
375375
}
376376

377377
if (canHandleJSExceptions) {
378-
b.catch_all();
378+
b.catch_all_legacy();
379379

380380
// We can't inspect the thrown object in a `catch_all` and get a stack
381381
// trace, so we just attach the current stack trace.

pkg/wasm_builder/lib/src/builder/builder.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,16 @@ export 'tables.dart' show TablesBuilder;
1717
export 'table.dart' show TableBuilder;
1818
export 'tags.dart' show TagsBuilder;
1919
export 'types.dart' show TypesBuilder;
20-
export 'instructions.dart' show InstructionsBuilder, Label, ValidationError;
20+
export 'instructions.dart'
21+
show
22+
InstructionsBuilder,
23+
Label,
24+
ValidationError,
25+
TryTableCatch,
26+
Catch,
27+
CatchAll,
28+
CatchRef,
29+
CatchAllRef;
2130

2231
mixin Builder<T> {
2332
T? _built;

pkg/wasm_builder/lib/src/builder/instructions.dart

Lines changed: 97 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,72 @@ class Try extends Label {
9191
List<ir.ValueType> get targetTypes => outputs;
9292
}
9393

94+
class TryTable extends Label {
95+
final List<TryTableCatch> catches;
96+
97+
TryTable(super.inputs, super.outputs, this.catches) : super._();
98+
99+
@override
100+
List<ir.ValueType> get targetTypes => outputs;
101+
}
102+
103+
abstract class TryTableCatch {
104+
final Label label;
105+
106+
TryTableCatch(this.label);
107+
108+
ir.TryTableCatch toIr(int labelIndex);
109+
110+
/// Values that the catch block catches, i.e. pushes as outputs.
111+
List<ir.ValueType> caughtValues();
112+
}
113+
114+
class Catch extends TryTableCatch {
115+
final ir.Tag tag;
116+
117+
Catch(this.tag, super.label);
118+
119+
@override
120+
ir.TryTableCatch toIr(int labelIndex) => ir.Catch(tag, labelIndex);
121+
122+
@override
123+
List<ir.ValueType> caughtValues() => tag.type.inputs;
124+
}
125+
126+
class CatchRef extends TryTableCatch {
127+
final ir.Tag tag;
128+
129+
CatchRef(this.tag, super.label);
130+
131+
@override
132+
ir.TryTableCatch toIr(int labelIndex) => ir.CatchRef(tag, labelIndex);
133+
134+
@override
135+
List<ir.ValueType> caughtValues() =>
136+
<ir.ValueType>[...tag.type.inputs, ir.RefType.exn(nullable: false)];
137+
}
138+
139+
class CatchAll extends TryTableCatch {
140+
CatchAll(super.label);
141+
142+
@override
143+
ir.TryTableCatch toIr(int labelIndex) => ir.CatchAll(labelIndex);
144+
145+
@override
146+
List<ir.ValueType> caughtValues() => <ir.ValueType>[];
147+
}
148+
149+
class CatchAllRef extends TryTableCatch {
150+
CatchAllRef(super.label);
151+
152+
@override
153+
ir.TryTableCatch toIr(int labelIndex) => ir.CatchAllRef(labelIndex);
154+
155+
@override
156+
List<ir.ValueType> caughtValues() =>
157+
<ir.ValueType>[ir.RefType.exn(nullable: false)];
158+
}
159+
94160
/// A sequence of Wasm instructions.
95161
///
96162
/// Instructions can be added to the sequence by calling the corresponding
@@ -545,8 +611,8 @@ class InstructionsBuilder with Builder<ir.Instructions> {
545611
ir.BeginOneOutputTry.new,
546612
ir.BeginFunctionTry.new);
547613

548-
/// Emit a `catch` instruction.
549-
void catch_(ir.Tag tag) {
614+
/// Emit a legacy `catch` instruction.
615+
void catch_legacy(ir.Tag tag) {
550616
assert(_topOfLabelStack is Try ||
551617
_reportError("Unexpected 'catch' (not in 'try' block)"));
552618
final Try try_ = _topOfLabelStack as Try;
@@ -555,18 +621,18 @@ class InstructionsBuilder with Builder<ir.Instructions> {
555621
assert(tag.enclosingModule == module);
556622
try_.hasCatch = true;
557623
_reachable = try_.reachable;
558-
_add(ir.Catch(tag));
624+
_add(ir.CatchLegacy(tag));
559625
}
560626

561-
void catch_all() {
627+
void catch_all_legacy() {
562628
assert(_topOfLabelStack is Try ||
563629
_reportError("Unexpected 'catch_all' (not in 'try' block)"));
564630
final Try try_ = _topOfLabelStack as Try;
565631
assert(_verifyEndOfBlock([],
566632
trace: ['catch_all'], reachableAfter: try_.reachable, reindent: true));
567633
try_.hasCatch = true;
568634
_reachable = try_.reachable;
569-
_add(const ir.CatchAll());
635+
_add(const ir.CatchAllLegacy());
570636
}
571637

572638
/// Emit a `throw` instruction.
@@ -585,6 +651,12 @@ class InstructionsBuilder with Builder<ir.Instructions> {
585651
_reachable = false;
586652
}
587653

654+
/// Emit a `throw_ref` instruction.
655+
void throw_ref() {
656+
_add(ir.ThrowRef());
657+
_reachable = false;
658+
}
659+
588660
/// Emit an `end` instruction.
589661
void end() {
590662
assert(_verifyEndOfBlock(_topOfLabelStack.outputs,
@@ -632,6 +704,26 @@ class InstructionsBuilder with Builder<ir.Instructions> {
632704
_reachable = false;
633705
}
634706

707+
/// Emit a `try_table` instruction.
708+
Label try_table(List<TryTableCatch> catches,
709+
[List<ir.ValueType> inputs = const [],
710+
List<ir.ValueType> outputs = const []]) {
711+
// Validation: blocks in the table should have the outputs based on the
712+
// types of exceptions they catch.
713+
for (TryTableCatch catch_ in catches) {
714+
assert(_verifyBranchTypes(catch_.label, 0, catch_.caughtValues()));
715+
}
716+
final List<ir.TryTableCatch> irCatches =
717+
catches.map((c) => c.toIr(_labelIndex(c.label))).toList();
718+
final label = _pushLabel(TryTable(inputs, outputs, catches),
719+
trace: const ['try_table']);
720+
return _beginBlock(
721+
label,
722+
() => ir.BeginNoEffectTryTable(irCatches),
723+
(ty) => ir.BeginOneOutputTryTable(ty, irCatches),
724+
(ty) => ir.BeginFunctionTryTable(ty, irCatches));
725+
}
726+
635727
/// Emit a `return` instruction.
636728
void return_() {
637729
assert(_verifyTypes(_labelStack[0].outputs, const [],

pkg/wasm_builder/lib/src/ir/instruction.dart

Lines changed: 123 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,10 @@ class BeginFunctionTry extends Instruction {
199199
}
200200
}
201201

202-
class Catch extends Instruction {
202+
class CatchLegacy extends Instruction {
203203
final Tag tag;
204204

205-
Catch(this.tag);
205+
CatchLegacy(this.tag);
206206

207207
@override
208208
void serialize(Serializer s) {
@@ -211,8 +211,8 @@ class Catch extends Instruction {
211211
}
212212
}
213213

214-
class CatchAll extends SingleByteInstruction {
215-
const CatchAll() : super(0x19);
214+
class CatchAllLegacy extends SingleByteInstruction {
215+
const CatchAllLegacy() : super(0x19);
216216
}
217217

218218
class Throw extends Instruction {
@@ -227,6 +227,15 @@ class Throw extends Instruction {
227227
}
228228
}
229229

230+
class ThrowRef extends Instruction {
231+
const ThrowRef();
232+
233+
@override
234+
void serialize(Serializer s) {
235+
s.writeByte(0x0a);
236+
}
237+
}
238+
230239
class Rethrow extends Instruction {
231240
final int labelIndex;
232241

@@ -1757,3 +1766,113 @@ class I64TruncSatF64U extends Instruction {
17571766
s.writeByte(0x07);
17581767
}
17591768
}
1769+
1770+
class BeginNoEffectTryTable extends Instruction {
1771+
final List<TryTableCatch> catches;
1772+
1773+
BeginNoEffectTryTable(this.catches);
1774+
1775+
@override
1776+
void serialize(Serializer s) {
1777+
s.writeByte(0x1F);
1778+
s.writeByte(0x40);
1779+
s.writeUnsigned(catches.length);
1780+
for (final catch_ in catches) {
1781+
catch_.serialize(s);
1782+
}
1783+
}
1784+
}
1785+
1786+
class BeginOneOutputTryTable extends Instruction {
1787+
final ValueType type;
1788+
final List<TryTableCatch> catches;
1789+
1790+
BeginOneOutputTryTable(this.type, this.catches);
1791+
1792+
@override
1793+
List<ValueType> get usedValueTypes => [type];
1794+
1795+
@override
1796+
void serialize(Serializer s) {
1797+
s.writeByte(0x1F);
1798+
s.write(type);
1799+
s.writeUnsigned(catches.length);
1800+
for (final catch_ in catches) {
1801+
catch_.serialize(s);
1802+
}
1803+
}
1804+
}
1805+
1806+
class BeginFunctionTryTable extends Instruction {
1807+
final FunctionType type;
1808+
final List<TryTableCatch> catches;
1809+
1810+
BeginFunctionTryTable(this.type, this.catches);
1811+
1812+
@override
1813+
List<DefType> get usedDefTypes => [type];
1814+
1815+
@override
1816+
void serialize(Serializer s) {
1817+
s.writeByte(0x1F);
1818+
s.write(type);
1819+
s.writeUnsigned(catches.length);
1820+
for (final catch_ in catches) {
1821+
catch_.serialize(s);
1822+
}
1823+
}
1824+
}
1825+
1826+
abstract class TryTableCatch {
1827+
final int labelIndex;
1828+
1829+
TryTableCatch(this.labelIndex);
1830+
1831+
void serialize(Serializer s);
1832+
}
1833+
1834+
class Catch extends TryTableCatch {
1835+
final Tag tag;
1836+
1837+
Catch(this.tag, super.labelIndex);
1838+
1839+
@override
1840+
void serialize(Serializer s) {
1841+
s.writeByte(0x00);
1842+
s.writeUnsigned(tag.index);
1843+
s.writeUnsigned(labelIndex);
1844+
}
1845+
}
1846+
1847+
class CatchRef extends TryTableCatch {
1848+
final Tag tag;
1849+
1850+
CatchRef(this.tag, super.labelIndex);
1851+
1852+
@override
1853+
void serialize(Serializer s) {
1854+
s.writeByte(0x01);
1855+
s.writeUnsigned(tag.index);
1856+
s.writeUnsigned(labelIndex);
1857+
}
1858+
}
1859+
1860+
class CatchAll extends TryTableCatch {
1861+
CatchAll(super.labelIndex);
1862+
1863+
@override
1864+
void serialize(Serializer s) {
1865+
s.writeByte(0x02);
1866+
s.writeUnsigned(labelIndex);
1867+
}
1868+
}
1869+
1870+
class CatchAllRef extends TryTableCatch {
1871+
CatchAllRef(super.labelIndex);
1872+
1873+
@override
1874+
void serialize(Serializer s) {
1875+
s.writeByte(0x03);
1876+
s.writeUnsigned(labelIndex);
1877+
}
1878+
}

0 commit comments

Comments
 (0)