May 28, 2019
On Tuesday, 28 May 2019 at 11:19:47 UTC, Sebastiaan Koppe wrote:
> I also have bindings to many web apis. All generated from WebIDL files.

Indeed, and then, as I understand it, you generate javascript for the extern(C) things actually referenced after the linker does its thing, with one extern(C) function corresponding to one Javascript method, right? I see int handles into a node array, just like I was thinking... but do you have a solution to memory management?

What I wanna do here is see if I can manage storing things fairly effectively with a minimal amount of code. I think a refcounting scheme, similar to how objective-c does it for the native handles would work and is reasonably easy to use.


May 28, 2019
On Tuesday, 28 May 2019 at 13:22:57 UTC, Adam D. Ruppe wrote:
> On Tuesday, 28 May 2019 at 11:19:47 UTC, Sebastiaan Koppe wrote:
>> I also have bindings to many web apis. All generated from WebIDL files.
>
> Indeed, and then, as I understand it, you generate javascript for the extern(C) things actually referenced after the linker does its thing, with one extern(C) function corresponding to one Javascript method, right?

Yep. There is a bindgen utility that generates only the js glue code you need.

Last time I looked Go takes a similar approach to yours, i.e. dynamically resolving calls based on strings. It does result in less js glue code, at the cost of having to decode strings. Both approaches are valid, but I wanted to focus on calling js function with little overhead.

> I see int handles into a node array, just like I was thinking...
> but do you have a solution to memory management?

I tried doing Unique+move, but failed with optional and sumtypes (don't like @disable this(this))

So it will probably be refcounts (but on the D side).

> What I wanna do here is see if I can manage storing things fairly effectively with a minimal amount of code. I think a refcounting scheme, similar to how objective-c does it for the native handles would work and is reasonably easy to use.

Nice. Good to see more people working on this.

btw. for the strings you can have a look at https://github.com/skoppe/spasm/blob/master/examples/fetch/spasm/modules/spasm.js#L42
May 28, 2019
On Tuesday, 28 May 2019 at 14:30:00 UTC, Sebastiaan Koppe wrote:
> I wanted to focus on calling js function with little overhead.

Yeah, and I like how you have a pretty good amount of type safety.

One of the things I like about strings though is working with existing code. Like if I can just, on the D side, do `window.my_own_object` I think that will be pretty cool.

> btw. for the strings you can have a look at

Indeed, that is next on my list. Actually, I kinda think I could pass D slices in general pretty directly as an i64, something like ptr << 32 | length... and a reinterpret cast on the D side could just work to do that. But that might be too clever for my own good.

(actually it briefly crossed my mind to define a communication bytecode thing to build calls but lolol, defining some kind of stack-based bytecode in javascript so our stack-based bytecode from javascript can communicated to javascript. absurd.)


May 28, 2019
On Tuesday, 28 May 2019 at 14:49:48 UTC, Adam D. Ruppe wrote:
> Yeah, and I like how you have a pretty good amount of type safety.

As well as auto-completion. One serious downside is that there is so much binding code that a full recompile of the library is painstakingly slow. It could be because of the many uses of Sumtype and Optional, or that I am public importing everything through a package.d, idk.

> One of the things I like about strings though is working with existing code. Like if I can just, on the D side, do `window.my_own_object` I think that will be pretty cool.

Yeah, whichever way you go you cant go wrong. D has so much better tools to write bindings than Rust or Go.

```go
func main() {
    document := js.Global().Get("document")
    p := document.Call("createElement", "p")
    p.Set("innerHTML", "Hello WASM from Go!")
    document.Get("body").Call("appendChild", p)
}
```

```rust
#[wasm_bindgen(start)]
pub fn run() -> Result<(), JsValue> {
    let window = web_sys::window().expect("no global `window` exists");
    let document = window.document().expect("should have a document on window");
    let body = document.body().expect("document should have a body");
    let val = document.create_element("p")?;
    val.set_inner_html("Hello from Rust!");
    body.append_child(&val)?;
    Ok(())
}
```

> Indeed, that is next on my list. Actually, I kinda think I could pass D slices in general pretty directly as an i64, something like ptr << 32 | length... and a reinterpret cast on the D side could just work to do that. But that might be too clever for my own good.

You can just put string/array types in the extern(C) definition. Somehow LLVM expands array arguments into two u32's. Dunno why. And for return types it adds an u32 as first argument (on the js side) that points to the return value on the stack. Pretty rad.

See:
https://github.com/skoppe/spasm/blob/master/webidl/source/webidl/binding/test.d#L177,L192

May 28, 2019
On Tuesday, 28 May 2019 at 18:19:14 UTC, Sebastiaan Koppe wrote:
> Somehow LLVM expands array arguments into two u32's. Dunno why.

It's analogous to the other target ABIs - pointer-sized length and pointer are passed as 2 separate arguments, usually in 2 registers.

> And for return types it adds an u32 as first argument (on the js side) that points to the return value on the stack. Pretty rad.

If the return type is a struct or static array, yes. This is the behaviour of LDC's UnknownTargetABI [1], which is currently selected for wasm targets.

This could of course all be tweaked, e.g., packing a slice arg/return value into a i64 (=> single JS number, although probably limited to 53 bits).

[1]: https://github.com/ldc-developers/ldc/blob/9de916b8f63653d6836273d7336615f2e5e9a85e/gen/abi.cpp#L304-L325
May 28, 2019
On Tuesday, 28 May 2019 at 18:54:24 UTC, kinke wrote:
> On Tuesday, 28 May 2019 at 18:19:14 UTC, Sebastiaan Koppe wrote:
>> Somehow LLVM expands array arguments into two u32's. Dunno why.
>
> It's analogous to the other target ABIs - pointer-sized length and pointer are passed as 2 separate arguments, usually in 2 registers.

Makes sense.

>> And for return types it adds an u32 as first argument (on the js side) that points to the return value on the stack. Pretty rad.
>
> If the return type is a struct or static array, yes. This is the behaviour of LDC's UnknownTargetABI [1], which is currently selected for wasm targets.

Ok, cool. I like it. I suppose it'll stay unknown for now?
1 2 3
Next ›   Last »