Skip to content

RFE: _name_ the function created by -sMODULARIZE #18071

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

Open
sgbeal opened this issue Oct 19, 2022 · 2 comments
Open

RFE: _name_ the function created by -sMODULARIZE #18071

sgbeal opened this issue Oct 19, 2022 · 2 comments

Comments

@sgbeal
Copy link

sgbeal commented Oct 19, 2022

i have a conundrum...

-sMODULARIZE=foo lets me name my module init function foo(), but the current implementation has two shortcomings:

  1. It reuses that name for 2 distinct purposes in the generated code:
var sqlite3InitModule = (() => {
  var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
  
  return (
function(sqlite3InitModule) {
  sqlite3InitModule = sqlite3InitModule || {};
...

Note that sqlite3InitModule is a distinctly different object in the inner function than in the outer declaration.

  1. it provides no way for --extern-post-js-injected code to attach state to that function in such a way that --pre-js-injected code can access it.

What i'm trying to do is, in my --extern-post-js, attach some state to sqlite3InitModule so that i can reach it from my customized Module['locateFile'] (which is injected via --pre-js). The problem is that the Module['locateFile'] impl cannot access the outer sqlite3InitModule object. The state in question is only available when the script is loaded, not when the module init function is called, so it has to be stashed via --extern-post-js in either the global scope (boo!!!) or as a property of the init function itself (yeah!!!).

My request is that the the inner function get a well-defined name:

  return (
function HERE(sqlite3InitModule) {
  sqlite3InitModule = sqlite3InitModule || {};

so that --pre-js-injected code can access the outer -sMODULARIZE-defined symbol via that name. Whatever that name is is unimportant to me.

Note that we cannot work around this using:

  return (
function (sqlite3InitModule) {
  sqlite3InitModule = sqlite3InitModule || {};
// --pre-js-injected code:
const myfunc = arguments.callee;

To quote the MDN docs with emphasis added:

Warning: Accessing arguments.callee in strict mode will throw a TypeError. If a function must reference itself, either give the function expression a name or use a function declaration.

That name is precisely what i'm asking for.

Please?

@sbc100
Copy link
Collaborator

sbc100 commented Oct 19, 2022

Regarding using the same name in two different contexts I agree that is ugly, we should fix that if we can.

For passing data to the init function, the normal way that we that is via its first argument. Is there some reason you can add attributes to this first argument?

Also, isn't that initial initialization function already inside its own scope? (i.e. isn't it invisible to --extern-pre-js regardless of whether it is names).

If this data you trying to attach is only available when the script it loaded then it seems like reasonable use a global variable no? Its not going to vary per-instance in that case right?

@sgbeal
Copy link
Author

sgbeal commented Oct 19, 2022

For passing data to the init function, the normal way that we that is via its first argument. Is there some reason you can add attributes to this first argument?

Order of operations won't let us add it to the Module object (the init func's argument). This library-level init is happening during the --extern-post-js phase, and the init function is not called until long after that, from client-level code after the amalgamated JS file has been imported. It's transparent to the client, and we can't impose on every client to add the state we're trying to inject. In fact, the Emscripten module itself is abstracted away from client-level code insofar as possible so that we can eventually support arbitrary wasm environments once the other wasm runtimes catch up to Emscripten (in particular its POSIX I/O emulation layer). The only Emscripten-level options we expose to clients are those used for feeding back the wasm-load progress.

If this data you trying to attach is only available when the script it loaded then it seems like reasonable use a global variable no?

That's my current workaround, but polluting the global scope always makes me queasy :/. My preference would be to attach the state to the module init function. We can do that, but the problem then is that any inner functions, like our Module.locateFile() override, do not have access to that function object because of the symbol collision with the named parameter to that very function.

Its not going to vary per-instance in that case right?

Correct. The state is just as much information as we can collect about the current script location so that we can dynamically determine, in our Module.locateFile() override, the path to use for loading the wasm file.

Background: the problem revolves around the Emscripten-generated .js file not being able to find its corresponding .wasm file if the .js file is loaded from any dir other than the client-level app's dir (due to quirks of relative URI resolution in JS, not any Emscripten shortcoming), and this differs depending on whether our code gets loaded in the main thread or a worker (both are legal), and whether it's loaded via a Worker's constructor argument or via importScripts() in a Worker's body. Since we're delivering a library, which we expect to be able to use from arbitrarily many applications in any given HTTP origin, it "just won't do" to host the .js/.wasm files in each application's directory. Collecting this state at load-time gives us a way such that apps A and B and C can (with only a small amount of acrobatics) all load some/dir/our.js, and our.js can still find our.wasm regardless of how our.js actually gets loaded.

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