www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How can I use class and wasm?

reply Jack <jckj33 gmail.com> writes:
can I make it work? the code (see below) result in link error:

lld: error: wasm.o: undefined symbol: _D4wasm1C7__ClassZ
lld: error: wasm.o: undefined symbol: _d_allocclass
Error: linking with LLD failed
command line:
ldc2 --d-debug -mtriple=wasm32-unknown-unknown-wasm -betterC 
wasm.d
ldc version:
 1.24.0-beta1 (DMD v2.094.0, LLVM 11.0.0)
code:
extern(C): // disable D mangling
// seems to be the required entry point
void _start() {}

extern(C)
int g()
{
    auto c = new C();
    return c.f();
}

extern(C++)
{
    class C
    {
        int f() { return 42; }
    }
}
Oct 15 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 15 October 2020 at 22:02:11 UTC, Jack wrote:
 can I make it work? the code (see below) result in link error:

lld: error: wasm.o: undefined symbol: _D4wasm1C7__ClassZ
lld: error: wasm.o: undefined symbol: _d_allocclass
Error: linking with LLD failed
command line:
ldc2 --d-debug -mtriple=wasm32-unknown-unknown-wasm -betterC 
wasm.d
ldc version:
 1.24.0-beta1 (DMD v2.094.0, LLVM 11.0.0)
code:
extern(C): // disable D mangling
// seems to be the required entry point
void _start() {}

extern(C)
int g()
{
    auto c = new C();
You can't use `new` in betterC.
Oct 15 2020
parent reply Jack <jckj33 gmail.com> writes:
On Friday, 16 October 2020 at 02:43:19 UTC, Paul Backus wrote:
 On Thursday, 15 October 2020 at 22:02:11 UTC, Jack wrote:
 can I make it work? the code (see below) result in link error:

lld: error: wasm.o: undefined symbol: _D4wasm1C7__ClassZ
lld: error: wasm.o: undefined symbol: _d_allocclass
Error: linking with LLD failed
command line:
ldc2 --d-debug -mtriple=wasm32-unknown-unknown-wasm -betterC 
wasm.d
ldc version:
 1.24.0-beta1 (DMD v2.094.0, LLVM 11.0.0)
code:
extern(C): // disable D mangling
// seems to be the required entry point
void _start() {}

extern(C)
int g()
{
    auto c = new C();
You can't use `new` in betterC.
that's right, my bad but even a custom allocator, using malloc()/free() wouldn't work either. How can I allocate memory for this class?
Oct 15 2020
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 16 October 2020 at 03:04:25 UTC, Jack wrote:
 How can I allocate memory for this class?
It is possible but not easy without druntime. If you are using -betterC, you can use extern(C++) classes with extern(D) members. The compiler will let you declare that. But then you need to allocate it. `__traits(classInstanceSize, Whatever)` will tell you the size to malloc, but you also need to copy an initializer over before you call the constructor. I have a technique here that works on dmd... http://dpldocs.info/this-week-in-d/Blog.Posted_2020_07_27.html#zero-runtime-classes but ldc is more strict about the type definition and I don't know the magic it expects there... like it should be doable but idk how so this might not be of much use. Personally, I prefer to just not use betterC and make my own mini runtime: http://dpldocs.info/this-week-in-d/Blog.Posted_2020_08_10.html in particular https://github.com/adamdruppe/webassembly/blob/master/arsd-webassembly/object.d#L74 But that's also not easy, lots of unfinished cases in my thing, but I did manage to make it work... for my specific case.
Oct 15 2020
parent reply Jack <jckj33 gmail.com> writes:
On Friday, 16 October 2020 at 03:42:22 UTC, Adam D. Ruppe wrote:
 On Friday, 16 October 2020 at 03:04:25 UTC, Jack wrote:
 How can I allocate memory for this class?
It is possible but not easy without druntime. If you are using -betterC, you can use extern(C++) classes with extern(D) members. The compiler will let you declare that. But then you need to allocate it. `__traits(classInstanceSize, Whatever)` will tell you the size to malloc, but you also need to copy an initializer over before you call the constructor. I have a technique here that works on dmd... http://dpldocs.info/this-week-in-d/Blog.Posted_2020_07_27.html#zero-runtime-classes
I did consider do something like this but the class would only live in the function's lifetime, right? that wouldn't work if I need to pass the class around
 but ldc is more strict about the type definition and I don't 
 know the magic it expects there... like it should be doable but 
 idk how so this might not be of much use.
Which type definition are you refering to? you mean the class members/memory layout of a class?
 Personally, I prefer to just not use betterC and make my own 
 mini runtime:
I was thinking the same, this seems the way to go.
 http://dpldocs.info/this-week-in-d/Blog.Posted_2020_08_10.html

 in particular
This is great! I'll try write a small druntime too for my case. Do you have links/resources where things like __heap_base, __data_end are defined? assuming there's such documentation somewhere, if you did into the compiler to get those, let me know where you can it too. I didn't understand the interation of webassembly-core.js with D. for example, you have this: // placeholder to be filled in by the loader var memory; How did you put the compiler/linker to set memory's location properly so you can do things like: memorySize: function() { return memory.buffer.byteLength; }, ? in the same way that ldc defines __headp_base and __data_end, doesn't it define some variables where the implementation of memorySize() and growMemory() could be done in D? also, where can I find this Sebastiaan's project that you mentioned in the article? it's a druntime like yours?
 https://github.com/adamdruppe/webassembly/blob/master/arsd-webassembly/object.d#L74
this is great, good enough to put me in the direction on how to do that. Also, I found C++ has this EMSCRIPTEN_BINDINGS() from emscripten/bind.h header, see[1] for example. I haven't tried yet. But maybe marking the class as extern(C) that would work with D's class too, right? I don't know about the C++'s or compiler's dependences that would prevent it from working with D. In fact, that seems quite a hacky. Do you think we are better off write our own small druntime? if I got an working nice one, I'll put on github for those who would like to use this. [1]: https://stackoverflow.com/questions/15865923/interaction-with-c-classes-in-emscripten Thanks for your answer, that was really helpful.
 But that's also not easy, lots of unfinished cases in my thing, 
 but I did manage to make it work... for my specific case.
Oct 26 2020
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 26 October 2020 at 21:38:39 UTC, Jack wrote:
 I did consider do something like this but the class would only 
 live in the function's lifetime, right? that wouldn't work if I 
 need to pass the class around
Right, you'd have to manage the memory somehow. One possibility is to malloc it too, but still manually done unless you use some kind of GC (and I think I do want to make a minimal gc for my little wasm thing but it will be a bit till I get around to it)
 Which type definition are you refering to? you mean the class 
 members/memory layout of a class?
The definition of the __init symbol. ldc needs it to be... something... whereas dmd doesn't care if it is just a void*.
 This is great! I'll try write a small druntime too for my case. 
 Do you have links/resources where things like __heap_base, 
 __data_end are defined?
Yeah, that's a llvm thing. I saw it here: https://dassur.ma/things/c-to-webassembly/ like idk if there's something more authoritative but that blog set me started and it works for me so worth something. A lot of this stuff is actually llvm meaning you can search for C / clang info and apply it to D as well.
 know where you can it too. I didn't understand the interation 
 of webassembly-core.js with D. for example, you have this:

 // placeholder to be filled in by the loader
 var memory;

 How did you put the compiler/linker to set memory's location 
 properly so you can do things like:
That's actually set in my own javascript just I put that in the html file instead of the js file (I gotta refactor this a bit more). See here: https://github.com/adamdruppe/webassembly/blob/master/server/webassembly-skeleton.html#L24 The "obj.instance.exports.memory" is a web api thing (I think, tbh I found much of the docs to be unclear or incomplete). Mentioned here: https://developer.mozilla.org/en-US/docs/WebAssembly/Loading_and_running and again it worked for me so I ran with it. But I preassigned it to the global after instantiating just so it is available in more places more easily.
 doesn't it define some variables where the implementation of 
 memorySize() and growMemory() could be done in D?
It might, I don't know, I just barely got this hack to work.
 also, where can I find this Sebastiaan's project that you 
 mentioned in the article? it's a druntime like yours?
His is a port of the real thing. see: https://gist.github.com/skoppe/7617ceba6afd67b2e20c6be4f922725d and: https://github.com/skoppe/druntime/tree/wasm He got like 80% done then has just been busy irl so not finished yet.
 EMSCRIPTEN_BINDINGS()
I don't know anything about emscripten. I looked at it years ago and figured it was too bloated to even seriously consider.
 emscripten/bind.h header, see[1] for example. I haven't tried 
 yet. But maybe marking the class as extern(C) that would work 
 with D's class too, right?
That won't work, extern(C) makes no sense on classes since C doesn't have classes. extern(C++) of course sometimes does make sense - you can make them with in D's -betterC too. But exporting a D class to javascript is going to be ... basically a no go given webasm's limitations. I guess you could make it work but it would be messy.
Oct 28 2020