Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

as-bind seems to not be able to handle proxies? #69

Open
surma opened this issue Mar 6, 2021 · 1 comment
Open

as-bind seems to not be able to handle proxies? #69

surma opened this issue Mar 6, 2021 · 1 comment

Comments

@surma
Copy link
Collaborator

surma commented Mar 6, 2021

I’m not 100% sure I dug out the very core issue here, but I put a sufficiently minimal repro in a gist, which will hopefully help analyze the bug.

I import a function which takes a string as a parameter, which is working fine with as-bind. However, some of my functions rely on this being the object the imported function is defined on. So I thought I’d bind() all functions before importing. as-bind handles that, too. Then I thought I should do the binding lazily, so I added a Proxy that does the binding on GET and caches it in a Map. Now, as-bind is failing to do its job and I just get a pointer.

import { AsBind } from "as-bind";
// Bundler magic compiles my ASC for me
import wasmUrl from "asc:./main.ts";

// Manually binds all methods found on `obj` to `obj.
function manualbind(obj) {
  const returnobj = {};
  for (const key of Object.keys(obj)) {
    if (typeof obj[key] === "function") {
      returnobj[key] = obj[key].bind(obj);
    }
    returnobj[key] = obj[key];
  }
  return returnobj;
}

// *Lazily* binds all methods found on `obj` to `obj.
function proxybind(obj) {
  const bindCache = new Map();
  return new Proxy(obj, {
    get(target, p) {
      if (bindCache.has(p)) {
        return bindCache.get(p);
      }
      if (typeof target?.[p] === "function") {
        const bound = target[p].bind(target);
        bindCache.set(p, bound);
        return bound;
      }
      return target[p];
    },
  });
}

function myalert(s) {
  alert(`message: ${JSON.stringify(s)}, has a this: ${this !== null}`);
}

async function main() {
  // Works fine!
  const instance = await AsBind.instantiate(fetch(wasmUrl), {
    main: { myalert },
  });
  instance.exports.run("vanilla");

  // Works fine!
  const instance2 = await AsBind.instantiate(fetch(wasmUrl), {
    main: manualbind({ myalert }),
  });
  instance2.exports.run("manualbind");

  // Breaks. I only get a pointer value and not the string.
  const instance3 = await AsBind.instantiate(fetch(wasmUrl), {
    main: proxybind({ myalert }),
  });
  instance3.exports.run("proxybind");
}
main();

Can you take a look and let me know if it’s something that I am doing wrong or something we can fix in as-bind?

@torch2424
Copy link
Owner

torch2424 commented Mar 15, 2021

@surma Thank you for the issue! So I took a look at this by:

  • Downloading your source
  • Importing as-bind from lib/lib.js directly
  • Added some logging in as-bind

And I was able to figure out, it seems like the proxy skips or overrides the bindImportFunction that AsBind does (I know this since the "functionThis" logs I added are never called): https://github.com/torch2424/as-bind/blob/master/lib/asbind-instance/bind-function.js#L7

Screenshot from 2021-03-15 12-11-42

So, I'll be honest, I'm not super strong at using Proxies. So I'm not quite sure where to start fixing this 😯 But! Perhaps it's because we aren't using arrow functions to bind our stuff? But, we need that so we can set function properties 🤔

Let me know if this helps, or if you need me to poke around a bit more 😯 I can buckle down and try to figure out how Proxies work haha! 😂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants