diff options
-rw-r--r-- | src/asm2wasm-main.cpp | 6 | ||||
-rw-r--r-- | src/asm2wasm.h | 19 | ||||
-rw-r--r-- | src/js/post.js | 9 | ||||
-rw-r--r-- | src/wasm-js.cpp | 54 |
4 files changed, 65 insertions, 23 deletions
diff --git a/src/asm2wasm-main.cpp b/src/asm2wasm-main.cpp index c8a5a4c30..b2b490965 100644 --- a/src/asm2wasm-main.cpp +++ b/src/asm2wasm-main.cpp @@ -15,6 +15,7 @@ int main(int argc, char **argv) { debug = getenv("ASM2WASM_DEBUG") ? getenv("ASM2WASM_DEBUG")[0] - '0' : 0; char *infile = argv[1]; + char *mappedGlobals = argc < 3 ? nullptr : argv[2]; if (debug) std::cerr << "loading '" << infile << "'...\n"; FILE *f = fopen(argv[1], "r"); @@ -50,6 +51,11 @@ int main(int argc, char **argv) { if (debug) std::cerr << "printing...\n"; std::cout << wasm; + if (mappedGlobals) { + if (debug) std::cerr << "serializing mapped globals...\n"; + asm2wasm.serializeMappedGlobals(mappedGlobals); + } + if (debug) std::cerr << "done.\n"; } diff --git a/src/asm2wasm.h b/src/asm2wasm.h index ed376f576..8dcefec0e 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -143,6 +143,25 @@ class Asm2WasmBuilder { public: std::map<IString, MappedGlobal> mappedGlobals; + // the global mapping info is not present in the output wasm. We need to save it on the side + // if we intend to load and run this module's wasm. + void serializeMappedGlobals(const char *filename) { + FILE *f = fopen(filename, "w"); + assert(f); + fprintf(f, "{\n"); + bool first = true; + for (auto& pair : mappedGlobals) { + auto name = pair.first; + auto& global = pair.second; + if (first) first = false; + else fprintf(f, ","); + fprintf(f, "\"%s\": { \"address\": %d, \"type\": %d, \"import\": %d, \"module\": \"%s\", \"base\": \"%s\" }\n", + name.str, global.address, global.type, global.import, global.module.str, global.base.str); + } + fprintf(f, "}"); + fclose(f); + } + private: void allocateGlobal(IString name, WasmType type, bool import, IString module = IString(), IString base = IString()) { assert(mappedGlobals.find(name) == mappedGlobals.end()); diff --git a/src/js/post.js b/src/js/post.js index 4377ed797..2ef25e30c 100644 --- a/src/js/post.js +++ b/src/js/post.js @@ -84,6 +84,9 @@ function integrateWasmJS(Module) { Module['asm'] = function(global, env, providedBuffer) { assert(providedBuffer === Module['buffer']); // we should not even need to pass it as a 3rd arg for wasm, but that's the asm.js way. + info.global = global; + info.env = env; + // wasm code would create its own buffer, at this time. But static init code might have // written to the buffer already, and we must copy it over. We could just avoid // this copy in wasm.js polyfilling, but to be as close as possible to real wasm, @@ -112,16 +115,12 @@ function integrateWasmJS(Module) { if (method == 'asm2wasm') { wasmJS['_load_asm2wasm'](temp); } else { - wasmJS['_load_s_expr2wasm'](temp); + wasmJS['_load_s_expr2wasm'](temp, Module['read'](Module['wasmCodeFile'] + '.mappedGlobals')); } wasmJS['_free'](temp); wasmJS['_instantiate'](temp); - // write the provided data to a location the wasm instance can get at it. - info.global = global; - info.env = env; - wasmJS['_load_mapped_globals'](); // now that we have global and env, we can ready the provided imported globals, copying them to their mapped locations. return wasmJS['asmExports']; }; } diff --git a/src/wasm-js.cpp b/src/wasm-js.cpp index e822da66a..fb3d5dd5a 100644 --- a/src/wasm-js.cpp +++ b/src/wasm-js.cpp @@ -62,10 +62,25 @@ extern "C" void EMSCRIPTEN_KEEPALIVE load_asm2wasm(char *input) { if (wasmJSDebug) std::cerr << "optimizing...\n"; asm2wasm->optimize(); + + if (wasmJSDebug) std::cerr << "mapping globals...\n"; + for (auto& pair : asm2wasm->mappedGlobals) { + auto name = pair.first; + auto& global = pair.second; + if (!global.import) continue; // non-imports are initialized to zero in the typed array anyhow, so nothing to do here + double value = EM_ASM_DOUBLE({ return Module['lookupImport'](Pointer_stringify($0), Pointer_stringify($1)) }, global.module.str, global.base.str); + unsigned address = global.address; + switch (global.type) { + case i32: EM_ASM_({ Module['info'].parent['HEAP32'][$0 >> 2] = $1 }, address, value); break; + case f32: EM_ASM_({ Module['info'].parent['HEAPF32'][$0 >> 2] = $1 }, address, value); break; + case f64: EM_ASM_({ Module['info'].parent['HEAPF64'][$0 >> 3] = $1 }, address, value); break; + default: abort(); + } + } } // loads wasm code in s-expression format -extern "C" void EMSCRIPTEN_KEEPALIVE load_s_expr2wasm(char *input) { +extern "C" void EMSCRIPTEN_KEEPALIVE load_s_expr2wasm(char *input, char *mappedGlobals) { prepare2wasm(); if (wasmJSDebug) std::cerr << "wasm-s-expression parsing...\n"; @@ -82,6 +97,26 @@ extern "C" void EMSCRIPTEN_KEEPALIVE load_s_expr2wasm(char *input) { std::cerr << "error in parsing s-expressions to wasm\n"; abort(); }); + + if (wasmJSDebug) std::cerr << "mapping globals...\n"; + EM_ASM_({ + var mappedGlobals = JSON.parse($0); + var i32 = $1; + var f32 = $2; + var f64 = $3; + for (var name in mappedGlobals) { + var global = mappedGlobals[name]; + if (!global.import) continue; // non-imports are initialized to zero in the typed array anyhow, so nothing to do here + var value = Module['lookupImport'](global.module, global.base); + var address = global.address; + switch (global.type) { + case i32: Module['info'].parent['HEAP32'][address >> 2] = value; break; + case f32: Module['info'].parent['HEAPF32'][address >> 2] = value; break; + case f64: Module['info'].parent['HEAPF64'][address >> 3] = value; break; + default: abort(); + } + } + }, mappedGlobals, i32, f32, f64); } // instantiates the loaded wasm (which might be from asm2wasm, or @@ -228,23 +263,6 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() { instance = new ModuleInstance(*module, new JSExternalInterface()); } -// Ready the provided imported globals, copying them to their mapped locations. -extern "C" void EMSCRIPTEN_KEEPALIVE load_mapped_globals() { - for (auto& pair : asm2wasm->mappedGlobals) { - auto name = pair.first; - auto& global = pair.second; - if (!global.import) continue; // non-imports are initialized to zero in the typed array anyhow, so nothing to do here - double value = EM_ASM_DOUBLE({ return Module['lookupImport'](Pointer_stringify($0), Pointer_stringify($1)) }, global.module.str, global.base.str); - unsigned address = global.address; - switch (global.type) { - case i32: EM_ASM_({ Module['info'].parent['HEAP32'][$0 >> 2] = $1 }, address, value); break; - case f32: EM_ASM_({ Module['info'].parent['HEAPF32'][$0 >> 2] = $1 }, address, value); break; - case f64: EM_ASM_({ Module['info'].parent['HEAPF64'][$0 >> 3] = $1 }, address, value); break; - default: abort(); - } - } -} - // Does a call from js into an export of the module. extern "C" void EMSCRIPTEN_KEEPALIVE call_from_js(const char *target) { if (wasmJSDebug) std::cout << "call_from_js " << target << '\n'; |