Skip to content

Instantly share code, notes, and snippets.

@j100002ben
Forked from elct9620/app-tinygo.js
Created October 5, 2020 15:10
Show Gist options
  • Save j100002ben/2c40e5e6b57302ca337d08f7dccbfc0a to your computer and use it in GitHub Desktop.
Save j100002ben/2c40e5e6b57302ca337d08f7dccbfc0a to your computer and use it in GitHub Desktop.

Revisions

  1. @elct9620 elct9620 revised this gist Oct 4, 2020. 3 changed files with 79 additions and 9 deletions.
    41 changes: 41 additions & 0 deletions app-tinygo.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,41 @@
    import 'vendor/tinygo'

    const go = new Go();

    go.importObject.env['main.defineClass'] = function(namePtr, nameLen, cPtr, cGcPtr, pPtr/*, pGcPtr*/) {
    const mem = new DataView(go._inst.exports.memory.buffer)
    const decoder = new TextDecoder("utf-8");

    const name = decoder.decode(new DataView(go._inst.exports.memory.buffer, namePtr, nameLen));
    const constructorID = mem.getUint32(cPtr, true)
    const constructor = go._values[constructorID]

    const prototypeID = mem.getUint32(pPtr, true)
    const prototypes = go._values[prototypeID]

    window[name] = (new Function(
    'constructor', 'prototypes',
    `
    function ${name}() {
    if(!(this instanceof ${name})) {
    throw new TypeError("Cannot call a class as a function")
    }
    return constructor.apply(this, arguments)
    }
    prototypes.call(${name}.prototype)
    return ${name}
    `
    ))(constructor, prototypes);
    }

    WebAssembly
    .instantiateStreaming(
    fetch(require('./main.wasm')),
    go.importObject,
    )
    .then(result => {
    go.run(result.instance);
    });
    42 changes: 33 additions & 9 deletions app.js
    Original file line number Diff line number Diff line change
    @@ -1,17 +1,41 @@
    import 'vendor/tinygo'
    import 'vendor/golang'

    const go = new Go();

    go.importObject.env['main.defineClass'] = function(namePtr, nameLen, cPtr, cGcPtr, pPtr/*, pGcPtr*/) {
    const mem = new DataView(go._inst.exports.memory.buffer)
    const decoder = new TextDecoder("utf-8");
    const decoder = new TextDecoder("utf-8");

    const name = decoder.decode(new DataView(go._inst.exports.memory.buffer, namePtr, nameLen));
    const constructorID = mem.getUint32(cPtr, true)
    const constructor = go._values[constructorID]
    const getInt64 = (mem, addr) => {
    const low = mem.getUint32(addr + 0, true);
    const high = mem.getInt32(addr + 4, true);
    return low + high * 4294967296;
    }

    const loadString = (mem, addr) => {
    const saddr = getInt64(mem, addr + 0);
    const len = getInt64(mem, addr + 8);
    return decoder.decode(new DataView(mem.buffer, saddr, len));
    }

    const loadValue = (mem, addr) => {
    const f = mem.getFloat64(addr, true);
    if (f === 0) {
    return undefined;
    }
    if (!isNaN(f)) {
    return f;
    }

    const id = mem.getUint32(addr, true);
    return go._values[id];
    }

    go.importObject.go['main.defineClass'] = function(sp) {
    const mem = new DataView(go._inst.exports.mem.buffer)

    const name = loadString(mem, sp + 8);

    const prototypeID = mem.getUint32(pPtr, true)
    const prototypes = go._values[prototypeID]
    const constructor = loadValue(mem, sp + 24)
    const prototypes = loadValue(mem, sp + 40)

    window[name] = (new Function(
    'constructor', 'prototypes',
    5 changes: 5 additions & 0 deletions main_js.s
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    #include "textflag.h"

    TEXT ·defineClass(SB), NOSPLIT, $0
    CallImport
    RET
  2. @elct9620 elct9620 revised this gist Oct 4, 2020. 2 changed files with 22 additions and 13 deletions.
    25 changes: 12 additions & 13 deletions app.js
    Original file line number Diff line number Diff line change
    @@ -2,34 +2,33 @@ import 'vendor/tinygo'

    const go = new Go();

    go.importObject.env['main.defineClass'] = function(namePtr, nameLen, funcAddr) {
    go.importObject.env['main.defineClass'] = function(namePtr, nameLen, cPtr, cGcPtr, pPtr/*, pGcPtr*/) {
    const mem = new DataView(go._inst.exports.memory.buffer)
    const decoder = new TextDecoder("utf-8");

    const name = decoder.decode(new DataView(go._inst.exports.memory.buffer, namePtr, nameLen));
    const f = mem.getFloat64(funcAddr, true)
    if (f === 0) {
    throw new TypeError("Constructor not defined")
    }
    if(!isNaN(f)) {
    throw new TypeError("Constructor not defined")
    }
    const constructorID = mem.getUint32(cPtr, true)
    const constructor = go._values[constructorID]

    const id = mem.getUint32(funcAddr, true)
    const constructor = go._values[id]
    const prototypeID = mem.getUint32(pPtr, true)
    const prototypes = go._values[prototypeID]

    window[name] = (new Function(
    'constructor',
    'constructor', 'prototypes',
    `
    return function ${name}() {
    function ${name}() {
    if(!(this instanceof ${name})) {
    throw new TypeError("Cannot call a class as a function")
    }
    return constructor.apply(this, arguments)
    }
    prototypes.call(${name}.prototype)
    return ${name}
    `
    ))(constructor);
    ))(constructor, prototypes);
    }

    WebAssembly
    10 changes: 10 additions & 0 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -2,13 +2,23 @@ package main

    func defineClass(name string, constructor js.Value)

    func pointGetX(this js.Value, []inputs js.Value) interface{} {
    return this.Get("x")
    }

    func pointConstructor(this js.Value, []inputs js.Value) interface{} {
    this.Set("x", inputs[0])
    this.Set("y", inputs[1])

    return this;
    }

    func pointPrototype(this js.Value, []inputs js.Value) interface{} {
    this.Set("getX", js.FuncOf(pointGetX))

    return nil
    }

    func main() {
    defineClass("Point", js.FuncOf(pointConstructor).Value)

  3. @elct9620 elct9620 created this gist Oct 4, 2020.
    42 changes: 42 additions & 0 deletions app.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,42 @@
    import 'vendor/tinygo'

    const go = new Go();

    go.importObject.env['main.defineClass'] = function(namePtr, nameLen, funcAddr) {
    const mem = new DataView(go._inst.exports.memory.buffer)
    const decoder = new TextDecoder("utf-8");

    const name = decoder.decode(new DataView(go._inst.exports.memory.buffer, namePtr, nameLen));
    const f = mem.getFloat64(funcAddr, true)
    if (f === 0) {
    throw new TypeError("Constructor not defined")
    }
    if(!isNaN(f)) {
    throw new TypeError("Constructor not defined")
    }

    const id = mem.getUint32(funcAddr, true)
    const constructor = go._values[id]

    window[name] = (new Function(
    'constructor',
    `
    return function ${name}() {
    if(!(this instanceof ${name})) {
    throw new TypeError("Cannot call a class as a function")
    }
    return constructor.apply(this, arguments)
    }
    `
    ))(constructor);
    }

    WebAssembly
    .instantiateStreaming(
    fetch(require('./main.wasm')),
    go.importObject,
    )
    .then(result => {
    go.run(result.instance);
    });
    17 changes: 17 additions & 0 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    package main

    func defineClass(name string, constructor js.Value)

    func pointConstructor(this js.Value, []inputs js.Value) interface{} {
    this.Set("x", inputs[0])
    this.Set("y", inputs[1])

    return this;
    }

    func main() {
    defineClass("Point", js.FuncOf(pointConstructor).Value)

    // Keep Golang running
    <-make(chan bool)
    }