Thread overview
Another WebAssembly example: Meta tic-tac-toe
Aug 22, 2018
Dennis
Aug 22, 2018
Allen Garvey
Aug 22, 2018
Dennis
Aug 22, 2018
kinke
Aug 22, 2018
Trass3r
Aug 22, 2018
Trass3r
Aug 24, 2018
Mike Franklin
Aug 30, 2018
Johan Engelen
August 22, 2018
Try it: https://dkorpel.github.io/tictac/
Source: https://github.com/dkorpel/tictac

I planned to port an assembly Meta tic-tac-toe game to D for a while now, and with the recent addition of WebAssembly to LDC I saw the opportunity to do some client-side web-development in D. I first made the command line version (with -betterC in mind), and then added a Javascript back-end to it. Thanks to the image dithering example, I already was aware of most issues and limitations so it went smoothly. Here are the findings that I had:

1. I saw that my application was expecting 'env.memcpy' and 'env.memset' to be present, I presume this is because the compiler emits these calls for struct/array copying/initialization. I solved it by providing simple implementations in the D code, hopefully that didn't have too much impact on performance.

2. The image dithering example had a JavaScript implementation to compare it to. I haven't made a JavaScript implementation, but I did compare how long the A.I. took to find a move with the command line version. Around 2 million moves were considered, here are the results:

| Version       | Time    | Factor |
|---------------|---------|--------|
| Ldc (release) |  357 ms | 1.0    |
| Dmd (release) |  671 ms | 1.9    |
| Wasm (-O3)    |  967 ms | 2.7    |
| Dmd (debug)   | 1651 ms | 4.6    |
| Ldc (debug)   | 2159 ms | 6.0    |
| Wasm (-O0)    | 2807 ms | 7.9    |

The WebAssembly version was tested in FireFox, in Chrome it seems to be ~1.5x slower for some reason.

3. Loading WebAssembly in a way that allows for both local testing and Github Pages deployment was annoying. The sample code from the wiki works on FireFox both locally and online, but Chrome complains you're loading a .wasm larger than 4Kb (16 Kb in my case) synchronously. I tried using fetch and instantiateStreaming, as suggested by:
https://developers.google.com/web/updates/2018/04/loading-wasm
But then when testing with live-server, it would complain about the request having an unknown MIME type. So I settled with an asynchronous XMLHttpRequest approach that works both offline and online, only for Chrome you still need live-server because for security it won't load requests using 'File://'.

4. I ran into some betterC issues:
- Final switch can't be used in debug mode since it throws an error in the default case. Solution: only compile in -release mode. See: https://issues.dlang.org/show_bug.cgi?id=19087
- Indexing `enum string[] messageStrings` with a runtime value gives a TypeInfo error. Solution: make it a __gshared immutable string[].
Related: https://issues.dlang.org/show_bug.cgi?id=19169, https://issues.dlang.org/show_bug.cgi?id=18949
- And, of course, the inability to use some language/library features. For this simple game it's okay, but for bigger projects I'd like to have some malloc/sprintf/math solutions.

5. Dub doesn't support WebAssembly targets. I solved this by making a build script that allows you to execute `rdmd build wasm` and then a simple refresh in the browser would show the results.

Overall it was very pleasant, kudos to the LDC team!
August 22, 2018
Cool project, and nice job on the readme as well.

On Wednesday, 22 August 2018 at 12:22:34 UTC, Dennis wrote:
> The WebAssembly version was tested in FireFox, in Chrome it seems to be ~1.5x slower for some reason.

Were you using Chrome for Mac by any chance? In my testing with the dithering example Chrome specifically on Mac had by far the slowest WebAssembly implementation.


> 3. Loading WebAssembly in a way that allows for both local testing and Github Pages deployment was annoying. The sample code from the wiki works on FireFox both locally and online, but Chrome complains you're loading a .wasm larger than 4Kb (16 Kb in my case) synchronously. I tried using fetch and instantiateStreaming, as suggested by:
> https://developers.google.com/web/updates/2018/04/loading-wasm
> But then when testing with live-server, it would complain about the request having an unknown MIME type. So I settled with an asynchronous XMLHttpRequest approach that works both offline and online, only for Chrome you still need live-server because for security it won't load requests using 'File://'.


While instantiateStreaming is definitely the future, be aware that this is not supported on Safari or Edge yet. I believe it is technically in the spec that WebAssembly has to be served with application/wasm mime type for instantiateStreaming, but in my testing Chrome doesn't care while Firefox does. The problem is that most web servers now don't currently serve the correct mime type out of the box (such as npm httpserver or Python simplehttpserver) so I had to use a custom node server (https://github.com/allen-garvey/wasm-dither-example/commit/5cd5baf84b681074de4ee7af4c224103e17a3827 https://gist.github.com/aolde/8104861) so I could set the mime type manually before I switched to instantiate since it has wider browser support.


August 22, 2018
On Wednesday, 22 August 2018 at 12:22:34 UTC, Dennis wrote:
> [...]

Interesting read, thx! [I've added it as further example to the Wiki page.]
August 22, 2018
On Wednesday, 22 August 2018 at 12:22:34 UTC, Dennis wrote:
> 1. I saw that my application was expecting 'env.memcpy' and 'env.memset' to be present, I presume this is because the compiler emits these calls for struct/array copying/initialization. I solved it by providing simple implementations in the D code, hopefully that didn't have too much impact on performance.

It does get vectorized, but it is a lot of code:
https://d.godbolt.org/z/zRgHuR
August 22, 2018
I guess @noalias and @nonnull LLVM parameter attributes would be useful here as memcpy does not allow overlapping arrays and passing null is undefined behavior.
August 22, 2018
On Wednesday, 22 August 2018 at 15:09:36 UTC, Allen Garvey wrote:
> Were you using Chrome for Mac by any chance? In my testing with the dithering example Chrome specifically on Mac had by far the slowest WebAssembly implementation.

I'm using Chrome 68 and FireFox 61 on Windows 10, on Debian I have FireFox ESR 52 which doesn't have WebAssembly support. I just tried Microsoft Edge 42 and it seems to be the same as FireFox.

On Wednesday, 22 August 2018 at 15:09:36 UTC, Allen Garvey wrote:
> The problem is that most web servers now don't currently serve the correct mime type out of the box (such as npm httpserver or Python simplehttpserver) so I had to use a custom node server (https://github.com/allen-garvey/wasm-dither-example/commit/5cd5baf84b681074de4ee7af4c224103e17a3827 https://gist.github.com/aolde/8104861) so I could set the mime type manually before I switched to instantiate since it has wider browser support.

Thanks for the info.
August 24, 2018
On Wednesday, 22 August 2018 at 12:22:34 UTC, Dennis wrote:
> Try it: https://dkorpel.github.io/tictac/
> Source: https://github.com/dkorpel/tictac

> Overall it was very pleasant, kudos to the LDC team!

And kudos to you!  Very nice work, I hope to see more.

Mike
August 29, 2018
On Wednesday, 22 August 2018 at 12:22:34 UTC, Dennis wrote:
> Try it: https://dkorpel.github.io/tictac/
> Source: https://github.com/dkorpel/tictac
>

Didn't knew about Meta Tic Tac Toe. This is wonderful and then to see it written in D and Webassembly. Thank you and LDC team!
August 29, 2018
On Wednesday, 22 August 2018 at 12:22:34 UTC, Dennis wrote:
> Try it: https://dkorpel.github.io/tictac/
> Source: https://github.com/dkorpel/tictac
>
> [...]

This could make a nice article for D blog.
August 30, 2018
On Wednesday, 29 August 2018 at 19:35:46 UTC, Arun Chandrasekaran wrote:
> On Wednesday, 22 August 2018 at 12:22:34 UTC, Dennis wrote:
>> Try it: https://dkorpel.github.io/tictac/
>> Source: https://github.com/dkorpel/tictac
>>
>> [...]
>
> This could make a nice article for D blog.

Really cool indeed! Definitely nice for a blog post.

Cheers,
  Johan