Skip to content

closure inconsistencies with pre/post scripts  #704

@agordon

Description

@agordon

Hello,

I've found two inconsistencies with the closure code.
The problem is due to mixing calling functions by name, or as a key to a hash.

Test-case:

The c program (test.c) for all the tests below:

int main() { return 0; }

Problem 1: the "run" function is incorrectly closure'd.

The "post" code (post.js) calls "run"

console.log("The command below is Module.run()");
Module.run();

Compile and test

$ emcc -O2 --closure 1 --minify 0 -s INVOKE_RUN=0 --post-js post.js -o test

# run
$ node test.js 
The command below is Module.run()

node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
TypeError: Object #<Object> has no method 'j'
    at Object.<anonymous> (/home/gordon/temp/emcc_bug/test.js:550:8)
    at Module._compile (module.js:432:26)
    at Object..js (module.js:450:10)
    at Module.load (module.js:351:31)
    at Function._load (module.js:310:12)
    at Array.0 (module.js:470:10)
    at EventEmitter._tickCallback (node.js:192:40)

The end of the compiled "test.js" reveals the problem:

$ tail test.js
  }
}
W([]);
var la = i;
Module.noInitialRun && (la = i);
la && $();
console.log("The command below is Module.run()");
Module.j();

The "run()" function in the post was renamed to "j()", but in the generated javascript, it's actually different:

$ grep "^Module\.run" test.js
Module.run = $;

Problem 2: The important config keys in "Module" are incorrectly closure'd

The pre code (pre.js) sets a preRun callback:

var Module = {
    "The Key below is PreRun": true,
    preRun: function() {
        console.log("Hello from preRun");
    }
};

Compile and test

# Compile without closure
$ emcc -O2 --closure 0 --minify 0 --pre-js pre.js -o test.js test.c 
# Test without closure
$ node test.js 
Hello from preRun

# Compile with closure
$ emcc -O2 --closure 1 --minify 0 --pre-js pre.js -o test.js test.c 
# Test with closure
$ node test.js 
# [nothing is printed, "preRun" was not called]

The reason: the pre-script's "preRun" was renamed to "j":

$ head test.js
var b = !0, i = null, j = !1, k = {
  "The Key below is PreRun": b,
  j: (function() {
    console.log("Hello from preRun");
  })
};
try {
  this.Module = k;
} catch (aa) {
  this.Module = k = {};

but the rest of the generated code still looks for a "preRun" function:

$ grep preRun test.js
    console.log("Hello from preRun");
k.preRun || (k.preRun = []);
  if (k.preRun) {
    typeof k.preRun == "function" && (k.preRun = [ k.preRun ]);
    var d = k.preRun;
    k.preRun = [];

Same thing happens with "noInitialRun" and other configuration keys.

temporary workaround:

  1. for the initialization keys, always use strings as keys:
var Module = {
  "preRun" : function (...)
  "NoInitialRun" : true }
  1. For the "run", a hack like this would work in the post.js script:
var f = Module['run'];
f();

Regards,
-gordon

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions