Skip to content

Commit d7c468b

Browse files
committed
Add support for enabling the Memory64 proposal, which was added to the Wasmtime C API with bytecodealliance/wasmtime#3182.
Additionally, add tests to verify the new APIs added with bytecodealliance#166 are able to access a memory beyond the 4 GiB area.
1 parent 3b26938 commit d7c468b

6 files changed

Lines changed: 145 additions & 19 deletions

File tree

src/Config.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,17 @@ public Config WithMultiMemory(bool enable)
189189
return this;
190190
}
191191

192+
/// <summary>
193+
/// Sets whether or not enable WebAssembly memory64 support.
194+
/// </summary>
195+
/// <param name="enable">True to enable WebAssembly memory64 support or false to disable.</param>
196+
/// <returns>Returns the current config.</returns>
197+
public Config WithMemory64(bool enable)
198+
{
199+
Native.wasmtime_config_wasm_memory64_set(handle, enable);
200+
return this;
201+
}
202+
192203
/// <summary>
193204
/// Sets the compiler strategy to use.
194205
/// </summary>
@@ -391,6 +402,9 @@ private static class Native
391402
[DllImport(Engine.LibraryName)]
392403
public static extern void wasmtime_config_wasm_multi_memory_set(Handle config, bool enable);
393404

405+
[DllImport(Engine.LibraryName)]
406+
public static extern void wasmtime_config_wasm_memory64_set(Handle config, bool enable);
407+
394408
[DllImport(Engine.LibraryName)]
395409
public static extern void wasmtime_config_strategy_set(Handle config, byte strategy);
396410

tests/Memory64AccessTests.cs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System;
2+
using System.Linq;
3+
using FluentAssertions;
4+
using Xunit;
5+
6+
namespace Wasmtime.Tests
7+
{
8+
public class Memory64AccessFixture : ModuleFixture
9+
{
10+
protected override string ModuleFileName => "Memory64Access.wat";
11+
}
12+
13+
public class Memory64AccessTests : IClassFixture<Memory64AccessFixture>, IDisposable
14+
{
15+
private Memory64AccessFixture Fixture { get; set; }
16+
17+
private Store Store { get; set; }
18+
19+
private Linker Linker { get; set; }
20+
21+
public Memory64AccessTests(Memory64AccessFixture fixture)
22+
{
23+
Fixture = fixture;
24+
Store = new Store(Fixture.Engine);
25+
Linker = new Linker(Fixture.Engine);
26+
}
27+
28+
[Fact]
29+
public unsafe void ItCanAccessMemoryWith65537Pages()
30+
{
31+
var instance = Linker.Instantiate(Store, Fixture.Module);
32+
var memory = instance.GetMemory("mem");
33+
34+
memory.GetLength().Should().Be(0x100010000);
35+
36+
memory.ReadInt32(0).Should().Be(0);
37+
38+
memory.WriteInt64(100, 1234);
39+
memory.ReadInt64(100).Should().Be(1234);
40+
41+
memory.ReadByte(0x10000FFFF).Should().Be(0x63);
42+
memory.ReadInt16(0x10000FFFE).Should().Be(0x6364);
43+
memory.ReadInt32(0x10000FFFC).Should().Be(0x63646500);
44+
45+
memory.ReadSingle(0x10000FFFC).Should().Be(4.2131355E+21F);
46+
47+
var span = memory.GetSpan(0x10000FFFE, 2);
48+
span.SequenceEqual(new byte[] { 0x64, 0x63 }).Should().BeTrue();
49+
50+
var int16Span = memory.GetSpan<short>(0x10000, int.MaxValue);
51+
int16Span[0x7FFFFFFE].Should().Be(0x6500);
52+
53+
int16Span = memory.GetSpan<short>(0x10002);
54+
int16Span[0x7FFFFFFE].Should().Be(0x6364);
55+
56+
byte* ptr = (byte*)memory.GetPointer();
57+
ptr += 0x10000FFFF;
58+
(*ptr).Should().Be(0x63);
59+
60+
string str1 = "Hello World";
61+
memory.WriteString(0x10000FFFF - str1.Length, str1);
62+
memory.ReadString(0x10000FFFF - str1.Length, str1.Length).Should().Be(str1);
63+
}
64+
65+
[Fact]
66+
public void ItThrowsForOutOfBoundsAccess()
67+
{
68+
var instance = Linker.Instantiate(Store, Fixture.Module);
69+
var memory = instance.GetMemory("mem");
70+
71+
#pragma warning disable CS0618 // Type or member is obsolete
72+
Action action = () => memory.GetSpan();
73+
#pragma warning restore CS0618 // Type or member is obsolete
74+
action.Should().Throw<OverflowException>();
75+
76+
action = () => memory.GetSpan<short>(0x10000);
77+
action.Should().Throw<OverflowException>();
78+
79+
action = () => memory.GetSpan(-1L, 0);
80+
action.Should().Throw<ArgumentOutOfRangeException>();
81+
82+
action = () => memory.GetSpan(0L, -1);
83+
action.Should().Throw<ArgumentOutOfRangeException>();
84+
85+
action = () => memory.ReadInt16(0x10000FFFF);
86+
action.Should().Throw<ArgumentException>();
87+
88+
action = () => memory.GetSpan<short>(0x10000FFFF, 1);
89+
action.Should().Throw<ArgumentException>();
90+
}
91+
92+
public void Dispose()
93+
{
94+
Store.Dispose();
95+
Linker.Dispose();
96+
}
97+
}
98+
}

tests/MemoryAccessTests.cs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,36 +31,35 @@ public unsafe void ItCanAccessMemoryWith65536Pages()
3131
var instance = Linker.Instantiate(Store, Fixture.Module);
3232
var memory = instance.GetMemory("mem");
3333

34-
memory.GetLength().Should().Be(uint.MaxValue + 1L);
34+
memory.GetLength().Should().Be(0x100000000);
3535

3636
memory.ReadInt32(0).Should().Be(0);
37-
memory.ReadInt32(0L).Should().Be(0);
3837

3938
memory.WriteInt64(100, 1234);
40-
memory.ReadInt64(100L).Should().Be(1234);
39+
memory.ReadInt64(100).Should().Be(1234);
4140

42-
memory.ReadByte(uint.MaxValue).Should().Be(0x63);
43-
memory.ReadInt16(uint.MaxValue - 1).Should().Be(0x6364);
44-
memory.ReadInt32(uint.MaxValue - 3).Should().Be(0x63646500);
41+
memory.ReadByte(0xFFFFFFFF).Should().Be(0x63);
42+
memory.ReadInt16(0xFFFFFFFE).Should().Be(0x6364);
43+
memory.ReadInt32(0xFFFFFFFC).Should().Be(0x63646500);
4544

46-
memory.ReadSingle(uint.MaxValue - 3).Should().Be(4.2131355E+21F);
45+
memory.ReadSingle(0xFFFFFFFC).Should().Be(4.2131355E+21F);
4746

48-
var span = memory.GetSpan(uint.MaxValue - 1, 2);
47+
var span = memory.GetSpan(0xFFFFFFFE, 2);
4948
span.SequenceEqual(new byte[] { 0x64, 0x63 }).Should().BeTrue();
5049

5150
var int16Span = memory.GetSpan<short>(0, int.MaxValue);
52-
int16Span[int.MaxValue - 1].Should().Be(0x6500);
51+
int16Span[0x7FFFFFFE].Should().Be(0x6500);
5352

5453
int16Span = memory.GetSpan<short>(2);
55-
int16Span[int.MaxValue - 1].Should().Be(0x6364);
54+
int16Span[0x7FFFFFFE].Should().Be(0x6364);
5655

5756
byte* ptr = (byte*)memory.GetPointer();
58-
ptr += uint.MaxValue;
57+
ptr += 0xFFFFFFFF;
5958
(*ptr).Should().Be(0x63);
6059

6160
string str1 = "Hello World";
62-
memory.WriteString(uint.MaxValue - str1.Length, str1);
63-
memory.ReadString(uint.MaxValue - str1.Length, str1.Length).Should().Be(str1);
61+
memory.WriteString(0xFFFFFFFF - str1.Length, str1);
62+
memory.ReadString(0xFFFFFFFF - str1.Length, str1.Length).Should().Be(str1);
6463
}
6564

6665
[Fact]
@@ -83,10 +82,10 @@ public void ItThrowsForOutOfBoundsAccess()
8382
action = () => memory.GetSpan(0L, -1);
8483
action.Should().Throw<ArgumentOutOfRangeException>();
8584

86-
action = () => memory.ReadInt16(uint.MaxValue);
85+
action = () => memory.ReadInt16(0xFFFFFFFF);
8786
action.Should().Throw<ArgumentException>();
8887

89-
action = () => memory.GetSpan<short>(uint.MaxValue, 1);
88+
action = () => memory.GetSpan<short>(0xFFFFFFFF, 1);
9089
action.Should().Throw<ArgumentException>();
9190
}
9291

tests/ModuleFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public ModuleFixture()
1616
public virtual Config GetEngineConfig()
1717
{
1818
return new Config()
19-
.WithReferenceTypes(true);
19+
.WithMemory64(true);
2020
}
2121

2222
public void Dispose()

tests/Modules/Memory64Access.wat

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
(module
2+
(memory (export "mem") i64 65537)
3+
(func $start
4+
i64.const 0x10000FFFF
5+
i32.const 99
6+
i32.store8
7+
i64.const 0x10000FFFE
8+
i32.const 100
9+
i32.store8
10+
i64.const 0x10000FFFD
11+
i32.const 101
12+
i32.store8
13+
)
14+
(start $start)
15+
)

tests/Modules/MemoryAccess.wat

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
(module
22
(memory (export "mem") 65536)
33
(func $start
4-
i32.const 4294967295
4+
i32.const 0xFFFFFFFF
55
i32.const 99
66
i32.store8
7-
i32.const 4294967294
7+
i32.const 0xFFFFFFFE
88
i32.const 100
99
i32.store8
10-
i32.const 4294967293
10+
i32.const 0xFFFFFFFD
1111
i32.const 101
1212
i32.store8
1313
)

0 commit comments

Comments
 (0)