Skip to content

Commit

Permalink
Initial support for exception handling
Browse files Browse the repository at this point in the history
  • Loading branch information
GerardSmit committed Aug 27, 2024
1 parent df3a7cf commit c1c3f34
Show file tree
Hide file tree
Showing 38 changed files with 1,452 additions and 74 deletions.
20 changes: 18 additions & 2 deletions WebAssembly.Tests/AssemblyBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace WebAssembly;
/// </summary>
static class AssemblyBuilder
{
public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType? @return, params Instruction[] code)
public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType? @return, Instruction[] code, Action<Module>? configure)
where TExport : class
{
Assert.IsNotNull(name);
Expand Down Expand Up @@ -37,6 +37,8 @@ public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType?
Code = code
});

configure?.Invoke(module);

var compiled = module.ToInstance<TExport>();

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

public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType? @return, IList<WebAssemblyValueType> parameters, params Instruction[] code)
public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType? @return, params Instruction[] code)
where TExport : class
{
return CreateInstance<TExport>(name, @return, code, null);
}

public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType? @return, IList<WebAssemblyValueType> parameters, Instruction[] code, Action<Module>? configure)
where TExport : class
{
Assert.IsNotNull(name);
Expand Down Expand Up @@ -75,6 +83,8 @@ public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType?
Code = code
});

configure?.Invoke(module);

var compiled = module.ToInstance<TExport>();

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

public static TExport CreateInstance<TExport>(string name, WebAssemblyValueType? @return, IList<WebAssemblyValueType> parameters, params Instruction[] code)
where TExport : class
{
return CreateInstance<TExport>(name, @return, parameters, code, null);
}

private static readonly Dictionary<System.Type, WebAssemblyValueType> map = new(4)
{
{ typeof(int), WebAssemblyValueType.Int32 },
Expand Down
50 changes: 50 additions & 0 deletions WebAssembly.Tests/Instructions/CatchAllTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace WebAssembly.Instructions;

/// <summary>
/// Tests the <see cref="Try"/> instruction.
/// </summary>
[TestClass]
public class CatchAllTests
{
/// <summary>
/// Tests compilation and execution of the <see cref="CatchAll"/> instruction when there are no exceptions.
/// </summary>
[TestMethod]
public void CatchAll_NoException()
{
Assert.AreEqual<int>(0, AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
new Try(),
new Int32Constant(0),
new Return(),
new CatchAll(),
new Int32Constant(1),
new Return(),
new End(),

new Int32Constant(2),
new End()
).Test());
}

/// <summary>
/// Tests compilation and execution of the <see cref="CatchAll"/> instruction when there is an exception.
/// </summary>
[TestMethod]
public void CatchAll_Catch()
{
Assert.AreEqual<int>(0, AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
new Try(),
new Int32Constant(0),
new Return(),
new CatchAll(),
new Int32Constant(1),
new Return(),
new End(),

new Int32Constant(2),
new End()
).Test());
}
}
181 changes: 181 additions & 0 deletions WebAssembly.Tests/Instructions/CatchTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace WebAssembly.Instructions;

/// <summary>
/// Tests the <see cref="Catch"/> instruction.
/// </summary>
[TestClass]
public class CatchTests
{
/// <summary>
/// Tests compilation and execution of the <see cref="Catch"/> instruction when there are no exceptions.
/// </summary>
[TestMethod]
public void Catch_NoException()
{
Assert.AreEqual<int>(0, AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
new Instruction[]
{
new Try(),
new Int32Constant(0),
new Return(),
new Catch(0),
new Int32Constant(1),
new Return(),
new End(),

new Int32Constant(2),
new End()
},
module =>
{
module.Types.Add(new WebAssemblyType
{
Parameters = new[]
{
WebAssemblyValueType.Int32
},
});

module.Tags.Add(new WebAssemblyTag
{
TypeIndex = 1
});
}
).Test());
}

/// <summary>
/// Tests compilation and execution of the <see cref="Catch"/> instruction when there is an exception.
/// </summary>
[TestMethod]
public void Catch_Exception()
{
Assert.AreEqual<int>(1, AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
new Instruction[]
{
new Try(),
new Int32Constant(0),
new Throw(0),
new Catch(0),
new Int32Constant(1),
new Return(),
new End(),

new Int32Constant(2),
new End()
},
module =>
{
module.Types.Add(new WebAssemblyType
{
Parameters = new[]
{
WebAssemblyValueType.Int32
},
});

module.Tags.Add(new WebAssemblyTag
{
TypeIndex = 1
});
}
).Test());
}

/// <summary>
/// Tests compilation and execution of the <see cref="Catch"/> instruction when there is an exception of the wrong type.
/// </summary>
[TestMethod]
public void Catch_MultipleExceptionTags()
{
Assert.AreEqual<int>(2, AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
new Instruction[]
{
new Try(),
new Int32Constant(0),
new Throw(1),
new Catch(0),
new Int32Constant(1),
new Return(),
new Catch(1),
new Int32Constant(2),
new Return(),
new End(),

new Int32Constant(3),
new End()
},
module =>
{
module.Types.Add(new WebAssemblyType
{
Parameters = new[]
{
WebAssemblyValueType.Int32
},
});

module.Tags.Add(new WebAssemblyTag
{
TypeIndex = 1
});

module.Tags.Add(new WebAssemblyTag
{
TypeIndex = 1
});
}
).Test());
}


/// <summary>
/// Tests compilation and execution of the <see cref="Rethrow"/> instruction.
/// </summary>
[TestMethod]
public void Catch_TryInCatch()
{
Assert.AreEqual(1, AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
new Instruction[]
{
new Try(),

new Throw(0),

new Catch(0),

new Try(),
new Throw(1),
new Catch(1),
new Int32Constant(1),
new Return(),
new End(),

new End(),

new Int32Constant(0),
new End()
},
module =>
{
module.Types.Add(new WebAssemblyType
{
Parameters = Array.Empty<WebAssemblyValueType>()
});

module.Tags.Add(new WebAssemblyTag
{
TypeIndex = 1
});

module.Tags.Add(new WebAssemblyTag
{
TypeIndex = 1
});
}
).Test());
}
}
48 changes: 48 additions & 0 deletions WebAssembly.Tests/Instructions/RethrowTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WebAssembly.Runtime;

namespace WebAssembly.Instructions;

/// <summary>
/// Tests the <see cref="Rethrow"/> instruction.
/// </summary>
[TestClass]
public class RethrowTests
{
/// <summary>
/// Tests compilation and execution of the <see cref="Rethrow"/> instruction.
/// </summary>
[TestMethod]
public void Rethrow_Exception()
{
Assert.ThrowsException<WebAssemblyException>(() =>
{
AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
new Instruction[]
{
new Try(),
new Throw(0),
new Catch(0),
new Rethrow(0),
new End(),

new Int32Constant(0),
new End()
},
module =>
{
module.Types.Add(new WebAssemblyType
{
Parameters = Array.Empty<WebAssemblyValueType>()
});

module.Tags.Add(new WebAssemblyTag
{
TypeIndex = 1
});
}
).Test();
});
}
}
43 changes: 43 additions & 0 deletions WebAssembly.Tests/Instructions/ThrowTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WebAssembly.Runtime;

namespace WebAssembly.Instructions;

/// <summary>
/// Tests the <see cref="Throw"/> instruction.
/// </summary>
[TestClass]
public class ThrowTests
{
/// <summary>
/// Tests compilation and execution of the <see cref="Throw"/> instruction.
/// </summary>
[TestMethod]
public void Throw_Exception()
{
Assert.ThrowsException<WebAssemblyException>(() =>
{
AssemblyBuilder.CreateInstance<dynamic>("Test", WebAssemblyValueType.Int32,
new Instruction[]
{
new Throw(0),

new End()
},
module =>
{
module.Types.Add(new WebAssemblyType
{
Parameters = Array.Empty<WebAssemblyValueType>()
});

module.Tags.Add(new WebAssemblyTag
{
TypeIndex = 1
});
}
).Test();
});
}
}
Loading

0 comments on commit c1c3f34

Please sign in to comment.