Wasm implementation
This is just @yowl work from his repo.
I would like to ask him to create proper PR with just code changes and instruction, then I can improve tooling, so whole thing can be built using dotnet publish workflow.
This PR is just for discussion whole idea, and give additional visibility for WASM work https://github.com/yowl/SeeSharpSnake/tree/wasm4
I did hack it about a bit due to wasm4. The framebuffer is provided, there's no main, sprites not characters, no PAL layer. Think those were the main things. What would be best, put all those things behind #if defs?
I'm probably not going to get to this as I have to hack the compiler to make it work and I don't understand why, so not worth pursuing unless that problem can be resolved, sorry. Basically the static field address calculation is screwed up when compiling or linking for w4 and goes off into random memory.
I'm probably not going to get to this as I have to hack the compiler to make it work and I don't understand why.
I think that's also reasonable. I only trying to consolidate knowledge points if possible. I then probable would go to your fork and try to make dotnet publish work there. Already send cleanup PR.
I think we just need to redo the sprites to be static ReadOnlySpan<byte> Xyz => new byte[] { 1,2,3}; to avoid the problem described in https://github.com/dotnet/runtimelab/pull/1822#issuecomment-1013812372.
This obviously requires bringing as much of ReadOnlySpan as needed.
I think I tried that but got stuck in ref struct requirements. I'll have another look
Scott
From: Michal Strehovský @.> Sent: Sunday, January 16, 2022 2:10:47 AM To: MichalStrehovsky/SeeSharpSnake @.> Cc: Scott Waye @.>; Mention @.> Subject: Re: [MichalStrehovsky/SeeSharpSnake] Wasm implementation (PR #21)
I think we just need to redo the sprites to be static ReadOnlySpan
This obviously requires bringing as much of ReadOnlySpan as needed.
— Reply to this email directly, view it on GitHubhttps://github.com/MichalStrehovsky/SeeSharpSnake/pull/21#issuecomment-1013823764, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAUYCKPVVBK3HCFZL5IER23UWJVPPANCNFSM5MA2TTEQ. Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.Message ID: @.***>
Basically
unsafe ref struct Game
{
static Game _game;
is not allowed . ref structs are on the stack, so they cant be used for static fields I guess. Problem then is how do I structure this given that there is no main? I need some static methods that can be called from W4
Would I be able to create the Game struct in the start call (called once per W4 lifetime), then clobber that over some static byte[] arrary. Then in at the start of update Unsafe.As that back into the ref struct? Too hacky?
Why do you need to make the Game a ref struct?
My suggestion above is basically this: https://sharplab.io/#v2:C4LghgzgtgPgAgJgIwFgBQ6LAE4FcDGwABAOJhQCm6A3ukfUXEgGxEBKFYAJgPIB2AGwCeAZQAOYPgB4ARkOAUAfEQAaQgF5EAvMr4UA7kTkKA2gF0i1IkgA0RBHYDMRAL4BudC6A===
It doesn't require making Game a ref struct and compiles to two movs (that are also quite inlineable).
Ah, because I thought it was = not => .
And if you take that sharplab link and switch to the IL it has a newobj. Maybe RyuJit removes that, I'll check.
Thanks
Scott
From: Michal Strehovský @.> Sent: Sunday, January 16, 2022 8:40:14 PM To: MichalStrehovsky/SeeSharpSnake @.> Cc: Scott Waye @.>; Mention @.> Subject: Re: [MichalStrehovsky/SeeSharpSnake] Wasm implementation (PR #21)
Why do you need to make the Game a ref struct?
My suggestion above is basically this: https://sharplab.io/#v2:C4LghgzgtgPgAgJgIwFgBQ6LAE4FcDGwABAOJhQCm6A3ukfUXEgGxEBKFYAJgPIB2AGwCeAZQAOYPgB4ARkOAUAfEQAaQgF5EAvMr4UA7kTkKA2gF0i1IkgA0RBHYDMRAL4BudC6A===
It doesn't require making Game a ref struct and compiles to two movs (that are also quite inlineable).
— Reply to this email directly, view it on GitHubhttps://github.com/MichalStrehovsky/SeeSharpSnake/pull/21#issuecomment-1014060522, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAUYCKKZTNAQCDAF4VLEIALUWNXP5ANCNFSM5MA2TTEQ. Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.Message ID: @.***>
The newobj is for ReadOnlySpan, which is a valuetype. It won't be a heap allocation even with optimizations disabled.
It won't be a heap allocation
How does that happen, when I look at the IR, I see the helper call for RhpNewArray
------------ BB02 [000..01C) (return), preds={BB01} succs={}
[000028] ------------ IL_OFFSET void IL offset: 0x0
N003 ( 1, 4) [000002] H----------- t2 = CNS_INT(h) int 0x420040 class
N004 ( 1, 1) [000001] ------------ t1 = CNS_INT int 2
/--* t2 int arg0 in rcx
+--* t1 int arg1 in rdx
N005 ( 16, 9) [000003] --CXG------- t3 = * CALL help ref HELPER.CORINFO_HELP_NEWARR_1_VC
The il in sharplab is:
IL_0000: ldsflda valuetype '<PrivateImplementationDetails>'/'__StaticArrayInitTypeSize=3' '<PrivateImplementationDetails>'::'039058C6F2C0CB492C533B0A4D14EF77CC0F78ABCCCED5287D84A1A2011CFB81'
IL_0005: ldc.i4.3
IL_0006: newobj instance void valuetype [System.Private.CoreLib]System.ReadOnlySpan`1
The field is RVA static (ie the data is in the rdata section of the executable). If you see newarr, Roslyn doesn't think it's the ReadOnlySpan in your corelib.
Aha! Right, better download Roslyn to see how it decides. Thanks! I guess [System.Private.CoreLib] is my problem
In the Roslyn tree there should be ReadOnlySpans they use for testing that the compiler should understand as ReadOnlySpan.
This one might be it:
https://github.com/dotnet/roslyn/blob/19d315955b91f40c374f94a8f2674b8956d912f4/src/Compilers/Test/Utilities/CSharp/TestSources.cs#L85-L156
Once you have something Roslyn recognizes, you might try to make it smaller (e.g. the enumerator might not actually be needed, but who knows).
Thanks, that saved me some debugging. Looks like this ctor is important
unsafe public ReadOnlySpan(void* pointer, int length)
{
_pointer = new ByReference<T>(ref Unsafe.As<byte, T>(ref *(byte*)pointer));
_length = length;
}
The enumerator and Span stuff I dropped and looks ok

Hmm, I guess that's obvious looking at the IL, oh well.