diff options
-rw-r--r-- | src/js/post.js | 9 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 4 | ||||
-rw-r--r-- | src/wasm-js.cpp | 50 |
3 files changed, 54 insertions, 9 deletions
diff --git a/src/js/post.js b/src/js/post.js index 2ee7b20b1..78fad1fc8 100644 --- a/src/js/post.js +++ b/src/js/post.js @@ -18,14 +18,14 @@ var temp = wasmJS._malloc(code.length + 1); wasmJS.writeAsciiToMemory(code, temp); - var instance = wasmJS._load_asm(temp); + wasmJS._load_asm(temp); wasmJS._free(temp); // Generate memory XXX TODO get the right size var theBuffer = Module['buffer'] = new ArrayBuffer(16*1024*1024); // Information for the instance of the module. - var instance = wasmJS['instance'] = { + var info = wasmJS['info'] = { global: null, env: null, parent: Module // Module inside wasm-js.cpp refers to wasm-js.cpp; this allows access to the outside program. @@ -35,8 +35,9 @@ Module['asm'] = function(global, env, buffer) { assert(buffer === theBuffer); // we should not even need to pass it as a 3rd arg for wasm, but that's the asm.js way. // write the provided data to a location the wasm instance can get at it. - instance.global = global; - instance.env = env; + info.global = global; + info.env = env; + return wasmJS['asmExports']; }; })(); diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 55caecaaa..d9beb0a95 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -273,11 +273,11 @@ public: return ExpressionRunner(*this, scope).visit(function->body).value; } + std::map<IString, Function*> functions; + private: Module& wasm; ExternalInterface* externalInterface; - - std::map<IString, Function*> functions; }; } // namespace wasm diff --git a/src/wasm-js.cpp b/src/wasm-js.cpp index cd9e427a3..a0c9a0f13 100644 --- a/src/wasm-js.cpp +++ b/src/wasm-js.cpp @@ -15,11 +15,15 @@ using namespace cashew; using namespace wasm; +ModuleInstance* instance = nullptr; + // receives asm.js code, parses into wasm and returns an instance handle. // this creates a module, an external interface, and a module instance, // all of which are then the responsibility of the caller to free. // note: this modifies the input. -extern "C" ModuleInstance* EMSCRIPTEN_KEEPALIVE load_asm(char *input) { +extern "C" void EMSCRIPTEN_KEEPALIVE load_asm(char *input) { + assert(instance == nullptr); // singleton + // emcc --separate-asm modules look like // // Module["asm"] = (function(global, env, buffer) { @@ -54,7 +58,21 @@ extern "C" ModuleInstance* EMSCRIPTEN_KEEPALIVE load_asm(char *input) { if (debug) std::cerr << "optimizing...\n"; asm2wasm.optimize(); - if (debug) std::cerr << "returning instance.\n"; + if (debug) std::cerr << "generating exports...\n"; + EM_ASM({ + Module['asmExports'] = {}; + }); + for (auto& curr : wasm->exports) { + EM_ASM_({ + var name = Pointer_stringify($0); + Module['asmExports'][name] = function() { + Module['tempArguments'] = Array.prototype.slice.call(arguments); + return Module['_call_from_js']($0); + }; + }, curr.name.str); + } + + if (debug) std::cerr << "creating instance...\n"; struct JSExternalInterface : ModuleInstance::ExternalInterface { Literal callImport(Import *import, ModuleInstance::LiteralList& arguments) override { @@ -136,6 +154,32 @@ extern "C" ModuleInstance* EMSCRIPTEN_KEEPALIVE load_asm(char *input) { } }; - return new ModuleInstance(*wasm, new JSExternalInterface()); + instance = new ModuleInstance(*wasm, new JSExternalInterface()); +} + +// Does a call from js into an export of the module. +extern "C" double EMSCRIPTEN_KEEPALIVE call_from_js(const char *target) { + IString name(target); + assert(instance->functions.find(name) != instance->functions.end()); + Function *function = instance->functions[name]; + size_t num = EM_ASM_INT_V({ return Module['tempArguments'].length }); + assert(num == function->params.size()); // TODO: fake missing/extra args? + + ModuleInstance::LiteralList arguments; + for (size_t i = 0; i < num; i++) { + WasmType type = function->params[i].type; + if (type == i32) { + arguments.push_back(Literal(EM_ASM_INT({ return Module['tempArguments'][$0] }, i))); + } else if (type == f64) { + arguments.push_back(Literal(EM_ASM_DOUBLE({ return Module['tempArguments'][$0] }, i))); + } else { + abort(); + } + } + + Literal ret = instance->callFunction(name, arguments); + if (ret.type == i32) return ret.i32; + if (ret.type == f64) return ret.f64; + abort(); } |