Skip to content

Commit c1c3f34

Browse files
committed
Initial support for exception handling
1 parent df3a7cf commit c1c3f34

38 files changed

+1452
-74
lines changed

WebAssembly.Tests/AssemblyBuilder.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace WebAssembly;
99
/// </summary>
1010
static class AssemblyBuilder
1111
{
12-
public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType? @return, params Instruction[] code)
12+
public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType? @return, Instruction[] code, Action<Module>? configure)
1313
where TExport : class
1414
{
1515
Assert.IsNotNull(name);
@@ -37,6 +37,8 @@ public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType?
3737
Code = code
3838
});
3939

40+
configure?.Invoke(module);
41+
4042
var compiled = module.ToInstance<TExport>();
4143

4244
Assert.IsNotNull(compiled);
@@ -45,7 +47,13 @@ public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType?
4547
return compiled.Exports;
4648
}
4749

48-
public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType? @return, IList<WebAssemblyValueType> parameters, params Instruction[] code)
50+
public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType? @return, params Instruction[] code)
51+
where TExport : class
52+
{
53+
return CreateInstance<TExport>(name, @return, code, null);
54+
}
55+
56+
public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType? @return, IList<WebAssemblyValueType> parameters, Instruction[] code, Action<Module>? configure)
4957
where TExport : class
5058
{
5159
Assert.IsNotNull(name);
@@ -75,6 +83,8 @@ public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType?
7583
Code = code
7684
});
7785

86+
configure?.Invoke(module);
87+
7888
var compiled = module.ToInstance<TExport>();
7989

8090
Assert.IsNotNull(compiled);
@@ -83,6 +93,12 @@ public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType?
8393
return compiled.Exports;
8494
}
8595

96+
public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType? @return, IList<WebAssemblyValueType> parameters, params Instruction[] code)
97+
where TExport : class
98+
{
99+
return CreateInstance<TExport>(name, @return, parameters, code, null);
100+
}
101+
86102
private static readonly Dictionary<System.Type, WebAssemblyValueType> map = new(4)
87103
{
88104
{ typeof(int), WebAssemblyValueType.Int32 },
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
3+
namespace WebAssembly.Instructions;
4+
5+
/// <summary>
6+
/// Tests the <see cref="Try"/> instruction.
7+
/// </summary>
8+
[TestClass]
9+
public class CatchAllTests
10+
{
11+
/// <summary>
12+
/// Tests compilation and execution of the <see cref="CatchAll"/> instruction when there are no exceptions.
13+
/// </summary>
14+
[TestMethod]
15+
public void CatchAll_NoException()
16+
{
17+
Assert.AreEqual<int>(0, AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
18+
new Try(),
19+
new Int32Constant(0),
20+
new Return(),
21+
new CatchAll(),
22+
new Int32Constant(1),
23+
new Return(),
24+
new End(),
25+
26+
new Int32Constant(2),
27+
new End()
28+
).Test());
29+
}
30+
31+
/// <summary>
32+
/// Tests compilation and execution of the <see cref="CatchAll"/> instruction when there is an exception.
33+
/// </summary>
34+
[TestMethod]
35+
public void CatchAll_Catch()
36+
{
37+
Assert.AreEqual<int>(0, AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
38+
new Try(),
39+
new Int32Constant(0),
40+
new Return(),
41+
new CatchAll(),
42+
new Int32Constant(1),
43+
new Return(),
44+
new End(),
45+
46+
new Int32Constant(2),
47+
new End()
48+
).Test());
49+
}
50+
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
using System;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
4+
namespace WebAssembly.Instructions;
5+
6+
/// <summary>
7+
/// Tests the <see cref="Catch"/> instruction.
8+
/// </summary>
9+
[TestClass]
10+
public class CatchTests
11+
{
12+
/// <summary>
13+
/// Tests compilation and execution of the <see cref="Catch"/> instruction when there are no exceptions.
14+
/// </summary>
15+
[TestMethod]
16+
public void Catch_NoException()
17+
{
18+
Assert.AreEqual<int>(0, AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
19+
new Instruction[]
20+
{
21+
new Try(),
22+
new Int32Constant(0),
23+
new Return(),
24+
new Catch(0),
25+
new Int32Constant(1),
26+
new Return(),
27+
new End(),
28+
29+
new Int32Constant(2),
30+
new End()
31+
},
32+
module =>
33+
{
34+
module.Types.Add(new WebAssemblyType
35+
{
36+
Parameters = new[]
37+
{
38+
WebAssemblyValueType.Int32
39+
},
40+
});
41+
42+
module.Tags.Add(new WebAssemblyTag
43+
{
44+
TypeIndex = 1
45+
});
46+
}
47+
).Test());
48+
}
49+
50+
/// <summary>
51+
/// Tests compilation and execution of the <see cref="Catch"/> instruction when there is an exception.
52+
/// </summary>
53+
[TestMethod]
54+
public void Catch_Exception()
55+
{
56+
Assert.AreEqual<int>(1, AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
57+
new Instruction[]
58+
{
59+
new Try(),
60+
new Int32Constant(0),
61+
new Throw(0),
62+
new Catch(0),
63+
new Int32Constant(1),
64+
new Return(),
65+
new End(),
66+
67+
new Int32Constant(2),
68+
new End()
69+
},
70+
module =>
71+
{
72+
module.Types.Add(new WebAssemblyType
73+
{
74+
Parameters = new[]
75+
{
76+
WebAssemblyValueType.Int32
77+
},
78+
});
79+
80+
module.Tags.Add(new WebAssemblyTag
81+
{
82+
TypeIndex = 1
83+
});
84+
}
85+
).Test());
86+
}
87+
88+
/// <summary>
89+
/// Tests compilation and execution of the <see cref="Catch"/> instruction when there is an exception of the wrong type.
90+
/// </summary>
91+
[TestMethod]
92+
public void Catch_MultipleExceptionTags()
93+
{
94+
Assert.AreEqual<int>(2, AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
95+
new Instruction[]
96+
{
97+
new Try(),
98+
new Int32Constant(0),
99+
new Throw(1),
100+
new Catch(0),
101+
new Int32Constant(1),
102+
new Return(),
103+
new Catch(1),
104+
new Int32Constant(2),
105+
new Return(),
106+
new End(),
107+
108+
new Int32Constant(3),
109+
new End()
110+
},
111+
module =>
112+
{
113+
module.Types.Add(new WebAssemblyType
114+
{
115+
Parameters = new[]
116+
{
117+
WebAssemblyValueType.Int32
118+
},
119+
});
120+
121+
module.Tags.Add(new WebAssemblyTag
122+
{
123+
TypeIndex = 1
124+
});
125+
126+
module.Tags.Add(new WebAssemblyTag
127+
{
128+
TypeIndex = 1
129+
});
130+
}
131+
).Test());
132+
}
133+
134+
135+
/// <summary>
136+
/// Tests compilation and execution of the <see cref="Rethrow"/> instruction.
137+
/// </summary>
138+
[TestMethod]
139+
public void Catch_TryInCatch()
140+
{
141+
Assert.AreEqual(1, AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
142+
new Instruction[]
143+
{
144+
new Try(),
145+
146+
new Throw(0),
147+
148+
new Catch(0),
149+
150+
new Try(),
151+
new Throw(1),
152+
new Catch(1),
153+
new Int32Constant(1),
154+
new Return(),
155+
new End(),
156+
157+
new End(),
158+
159+
new Int32Constant(0),
160+
new End()
161+
},
162+
module =>
163+
{
164+
module.Types.Add(new WebAssemblyType
165+
{
166+
Parameters = Array.Empty<WebAssemblyValueType>()
167+
});
168+
169+
module.Tags.Add(new WebAssemblyTag
170+
{
171+
TypeIndex = 1
172+
});
173+
174+
module.Tags.Add(new WebAssemblyTag
175+
{
176+
TypeIndex = 1
177+
});
178+
}
179+
).Test());
180+
}
181+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
using WebAssembly.Runtime;
4+
5+
namespace WebAssembly.Instructions;
6+
7+
/// <summary>
8+
/// Tests the <see cref="Rethrow"/> instruction.
9+
/// </summary>
10+
[TestClass]
11+
public class RethrowTests
12+
{
13+
/// <summary>
14+
/// Tests compilation and execution of the <see cref="Rethrow"/> instruction.
15+
/// </summary>
16+
[TestMethod]
17+
public void Rethrow_Exception()
18+
{
19+
Assert.ThrowsException<WebAssemblyException>(() =>
20+
{
21+
AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
22+
new Instruction[]
23+
{
24+
new Try(),
25+
new Throw(0),
26+
new Catch(0),
27+
new Rethrow(0),
28+
new End(),
29+
30+
new Int32Constant(0),
31+
new End()
32+
},
33+
module =>
34+
{
35+
module.Types.Add(new WebAssemblyType
36+
{
37+
Parameters = Array.Empty<WebAssemblyValueType>()
38+
});
39+
40+
module.Tags.Add(new WebAssemblyTag
41+
{
42+
TypeIndex = 1
43+
});
44+
}
45+
).Test();
46+
});
47+
}
48+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
using WebAssembly.Runtime;
4+
5+
namespace WebAssembly.Instructions;
6+
7+
/// <summary>
8+
/// Tests the <see cref="Throw"/> instruction.
9+
/// </summary>
10+
[TestClass]
11+
public class ThrowTests
12+
{
13+
/// <summary>
14+
/// Tests compilation and execution of the <see cref="Throw"/> instruction.
15+
/// </summary>
16+
[TestMethod]
17+
public void Throw_Exception()
18+
{
19+
Assert.ThrowsException<WebAssemblyException>(() =>
20+
{
21+
AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
22+
new Instruction[]
23+
{
24+
new Throw(0),
25+
26+
new End()
27+
},
28+
module =>
29+
{
30+
module.Types.Add(new WebAssemblyType
31+
{
32+
Parameters = Array.Empty<WebAssemblyValueType>()
33+
});
34+
35+
module.Tags.Add(new WebAssemblyTag
36+
{
37+
TypeIndex = 1
38+
});
39+
}
40+
).Test();
41+
});
42+
}
43+
}

0 commit comments

Comments
 (0)