summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/js/post.js9
-rw-r--r--src/wasm-interpreter.h4
-rw-r--r--src/wasm-js.cpp50
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();
}