www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Some questions with D and webassembly

reply TheZipCreator <thezipcreator protonmail.com> writes:
In webassembly, there's a type called `externref`, which opaquely 
represents a javascript object. So, you could do this for 
example, with this javascript:
```js
class Foo {
	constructor(x) {
		this.x = x;
	}
}

const imports = {
	env: {
		fooNew: (x) => new Foo(x),
		fooX: (foo) => foo.x,
		fooSetX: (foo, x) => { foo.x = x; }
	}
}

WebAssembly.instantiateStreaming(fetch("./foo.wasm"), 
imports).then(module => {
	let foo = module.instance.exports.f();
	console.log(foo.x); // 5
	module.instance.exports.g(foo);
	console.log(foo.x); // 8
});
```
and this webassembly:
```wat
(module
	(import "env" "fooNew" (func $fooNew (param i32) (result 
externref)))
	(import "env" "fooX" (func $fooX (result i32)))
	(import "env" "fooSetX" (func $fooSetX (param externref) (param 
i32)))
	(func (export "f") (result externref)
		i32.const 5
		call $fooNew)
	(func (export "g") (param $foo externref)
		local.get $foo
		i32.const 8
		call $fooSetX))
```
5 and 8 get logged. Equivalent D to the webassembly part would be:
```d
extern(C):

// how to get this externref type?
externref fooNew(int);
externref fooX(externref);
void fooSetX(externref, int);

externref f() {
	return fooNew();
}

void g(externref foo) {
	fooSetX(foo, 8);
}
```
problem being, there exists no `externref` type. So how would you 
achieve it with ldc2?

B) In the javascript WebAssembly API, you can pass in memory like 
so:
```js
const imports = {
	"mem": new WebAssembly.Memory({ initial: 1 })
}

WebAssembly.instantiateStreaming(fetch("bar.wasm"), imports, 
module => { ... });
```
then in WebAssembly
```wat
(import "mem" (memory 1))
```
so how could I do that in D? That is, I want the memory that D 
uses to be accessible to javascript (this way I can pass pointers 
between JS and D)
Mar 02 2023
parent reply ryuukk_ <ryuukk.dev gmail.com> writes:
On Friday, 3 March 2023 at 03:32:37 UTC, TheZipCreator wrote:
 In webassembly, there's a type called `externref`, which 
 opaquely represents a javascript object. So, you could do this 
 for example, with this javascript:
 ```js
 class Foo {
 	constructor(x) {
 		this.x = x;
 	}
 }

 const imports = {
 	env: {
 		fooNew: (x) => new Foo(x),
 		fooX: (foo) => foo.x,
 		fooSetX: (foo, x) => { foo.x = x; }
 	}
 }

 WebAssembly.instantiateStreaming(fetch("./foo.wasm"), 
 imports).then(module => {
 	let foo = module.instance.exports.f();
 	console.log(foo.x); // 5
 	module.instance.exports.g(foo);
 	console.log(foo.x); // 8
 });
 ```
 and this webassembly:
 ```wat
 (module
 	(import "env" "fooNew" (func $fooNew (param i32) (result 
 externref)))
 	(import "env" "fooX" (func $fooX (result i32)))
 	(import "env" "fooSetX" (func $fooSetX (param externref) 
 (param i32)))
 	(func (export "f") (result externref)
 		i32.const 5
 		call $fooNew)
 	(func (export "g") (param $foo externref)
 		local.get $foo
 		i32.const 8
 		call $fooSetX))
 ```
 5 and 8 get logged. Equivalent D to the webassembly part would 
 be:
 ```d
 extern(C):

 // how to get this externref type?
 externref fooNew(int);
 externref fooX(externref);
 void fooSetX(externref, int);

 externref f() {
 	return fooNew();
 }

 void g(externref foo) {
 	fooSetX(foo, 8);
 }
 ```
 problem being, there exists no `externref` type. So how would 
 you achieve it with ldc2?

 B) In the javascript WebAssembly API, you can pass in memory 
 like so:
 ```js
 const imports = {
 	"mem": new WebAssembly.Memory({ initial: 1 })
 }

 WebAssembly.instantiateStreaming(fetch("bar.wasm"), imports, 
 module => { ... });
 ```
 then in WebAssembly
 ```wat
 (import "mem" (memory 1))
 ```
 so how could I do that in D? That is, I want the memory that D 
 uses to be accessible to javascript (this way I can pass 
 pointers between JS and D)
https://discourse.llvm.org/t/rfc-webassembly-reference-types-in-clang/66939 it says it is an opaque type, maybe just need to be ``void*``? Also there are new intrinsics, maybe you can define them like this: ```D alias externref_t = void*; pragma(LDC_intrinsic, "llvm.wasm.table.set.externref.i32") extern(C) void llvm_wasm_table_set_externref(void*, int, externref_t); pragma(LDC_intrinsic, "llvm.wasm.table.get.externref.i32") extern(C) externref_t llvm_wasm_table_get_externref(void*, int); ```
Mar 03 2023
parent reply TheZipCreator <thezipcreator protonmail.com> writes:
On Friday, 3 March 2023 at 13:42:55 UTC, ryuukk_ wrote:
 On Friday, 3 March 2023 at 03:32:37 UTC, TheZipCreator wrote:
 [...]
https://discourse.llvm.org/t/rfc-webassembly-reference-types-in-clang/66939 it says it is an opaque type, maybe just need to be ``void*``? Also there are new intrinsics, maybe you can define them like this: ```D alias externref_t = void*; pragma(LDC_intrinsic, "llvm.wasm.table.set.externref.i32") extern(C) void llvm_wasm_table_set_externref(void*, int, externref_t); pragma(LDC_intrinsic, "llvm.wasm.table.get.externref.i32") extern(C) externref_t llvm_wasm_table_get_externref(void*, int); ```
Using `void*` doesn't appear to work (and looking at the generated wasm it seems to reduce it to `i32`, which is not the right type unfortunately). I guess what I could do is have a global array in js which stores all objects I'll need to access, then just access them via the index into that array but that feels like a hack especially when `externref` is a thing that exists.
Mar 03 2023
parent Johan <j j.nl> writes:
On Friday, 3 March 2023 at 18:34:24 UTC, TheZipCreator wrote:
 On Friday, 3 March 2023 at 13:42:55 UTC, ryuukk_ wrote:
 On Friday, 3 March 2023 at 03:32:37 UTC, TheZipCreator wrote:
 [...]
https://discourse.llvm.org/t/rfc-webassembly-reference-types-in-clang/66939
It looks like this needs some more compiler support. Please submit the feature request (including the link to this LLVM page) on LDC's github page. cheers, Johan
Mar 03 2023