Skip to content

Instantly share code, notes, and snippets.

@kripken
Created August 15, 2016 18:04
Show Gist options
  • Save kripken/8b7b87030aa4c841a03667da2fde74b8 to your computer and use it in GitHub Desktop.
Save kripken/8b7b87030aa4c841a03667da2fde74b8 to your computer and use it in GitHub Desktop.
diff --git a/src/shell-interface.h b/src/shell-interface.h
index 55f9b2a..db2f033 100644
--- a/src/shell-interface.h
+++ b/src/shell-interface.h
@@ -86,6 +86,8 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
}
} memory;
+ std::vector<Name> table;
+
ShellExternalInterface() : memory() {}
void init(Module& wasm) override {
@@ -98,6 +100,15 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
memory.set(offset + i, segment.data[i]);
}
}
+
+ table.resize(wasm.table.initial);
+ for (auto& segment : wasm.table.segments) {
+ Address offset = ConstantExpressionRunner().visit(segment.offset).value.geti32();
+ assert(offset + segment.data.size() <= wasm.table.initial);
+ for (size_t i = 0; i != segment.data.size(); ++i) {
+ table[offset + i] = segment.data[i];
+ }
+ }
}
Literal callImport(Import *import, LiteralList& arguments) override {
@@ -115,6 +126,19 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface {
abort();
}
+ Literal callTable(Index index, FunctionType* type, LiteralList& arguments, ModuleInstance& instance) override {
+ if (index >= table.size()) trap("callTable overflow");
+ auto* func = table[index];
+ if (func->type.is() && func->type != type) trap("callIndirect: bad type");
+ if (func->params.size() != arguments.size()) trap("callIndirect: bad # of arguments");
+ for (size_t i = 0; i < func->params.size(); i++) {
+ if (func->params[i] != arguments[i].type) {
+ trap("callIndirect: bad argument type");
+ }
+ }
+ return instance.callFunctionInternal(name, arguments);
+ }
+
Literal load(Load* load, Address addr) override {
switch (load->type) {
case i32: {
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 0be36a6..6fc4c59 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -533,6 +533,7 @@ public:
struct ExternalInterface {
virtual void init(Module& wasm) {}
virtual Literal callImport(Import* import, LiteralList& arguments) = 0;
+ virtual Literal callTable(Index index, FunctionType* type, LiteralList& arguments, ModuleInstance& instance) = 0;
virtual Literal load(Load* load, Address addr) = 0;
virtual void store(Store* store, Address addr, Literal value) = 0;
virtual void growMemory(Address oldSize, Address newSize) = 0;
@@ -672,18 +673,8 @@ private:
LiteralList arguments;
Flow flow = generateArguments(curr->operands, arguments);
if (flow.breaking()) return flow;
- size_t index = target.value.geti32();
- if (index >= instance.wasm.table.names.size()) trap("callIndirect: overflow");
- Name name = instance.wasm.table.names[index];
- Function *func = instance.wasm.getFunction(name);
- if (func->type.is() && func->type != curr->fullType) trap("callIndirect: bad type");
- if (func->params.size() != arguments.size()) trap("callIndirect: bad # of arguments");
- for (size_t i = 0; i < func->params.size(); i++) {
- if (func->params[i] != arguments[i].type) {
- trap("callIndirect: bad argument type");
- }
- }
- return instance.callFunctionInternal(name, arguments);
+ Index index = target.value.geti32();
+ return instance.externalInterface->callTable(index, curr->fullType, arguments, instance);
}
Flow visitGetLocal(GetLocal *curr) {
diff --git a/src/wasm-js.cpp b/src/wasm-js.cpp
index 2aacd94..742bd93 100644
--- a/src/wasm-js.cpp
+++ b/src/wasm-js.cpp
@@ -195,10 +195,23 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() {
target.set(source, $0);
}, ConstantExpressionRunner().visit(segment.offset).value.geti32(), &segment.data[0], segment.data.size());
}
+ // Table support is in a JS array. If the entry is a number, it's a function pointer. If not, it's a JS method to be called directly
+ // TODO: make them all JS methods, wrapping a dynCall where necessary?
+ EM_ASM_({
+ Module['outside']['wasmTable'] = new Array($0);
+ }, wasm.table.initial);
+ for (auto segment : wasm.table.segments) {
+ Address offset = ConstantExpressionRunner().visit(segment.offset).value.geti32();
+ assert(offset + segment.data.size() <= wasm.table.initial);
+ for (size_t i = 0; i != segment.data.size(); ++i) {
+ EM_ASM_({
+ Module['outside']['wasmTable'][$0] = $1;
+ }, offset + i, wasm.getFunction(segment.data[i]));
+ }
+ }
}
- Literal callImport(Import *import, LiteralList& arguments) override {
- if (wasmJSDebug) std::cout << "calling import " << import->name.str << '\n';
+ void prepareTempArgments(LiteralList& arguments) {
EM_ASM({
Module['tempArguments'] = [];
});
@@ -213,6 +226,21 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() {
abort();
}
}
+ }
+
+ Literal getResultFromJS(double ret) {
+ switch (import->type->result) {
+ case none: return Literal(0);
+ case i32: return Literal((int32_t)ret);
+ case f32: return Literal((float)ret);
+ case f64: return Literal((double)ret);
+ default: abort();
+ }
+ }
+
+ Literal callImport(Import *import, LiteralList& arguments) override {
+ if (wasmJSDebug) std::cout << "calling import " << import->name.str << '\n';
+ prepareTempArgments(arguments);
double ret = EM_ASM_DOUBLE({
var mod = Pointer_stringify($0);
var base = Pointer_stringify($1);
@@ -224,12 +252,36 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() {
if (wasmJSDebug) std::cout << "calling import returning " << ret << '\n';
- switch (import->type->result) {
- case none: return Literal(0);
- case i32: return Literal((int32_t)ret);
- case f32: return Literal((float)ret);
- case f64: return Literal((double)ret);
- default: abort();
+ return getResultFromJS(ret);
+ }
+
+ Literal callTable(Index index, FunctionType* type, LiteralList& arguments, ModuleInstance& instance) override {
+ void* ptr = EM_ASM_INT({
+ var value = Module['outside']['wasmTable'][$0];
+ return typeof value === "number" ? value : -1;
+ }, index);
+ if (ptr == nullptr) trap("callTable overflow");
+ if (ptr != (void*)-1) {
+ // a Function we can call
+ Function* func = (Function*)ptr;
+ if (func->type.is() && func->type != type) trap("callIndirect: bad type");
+ if (func->params.size() != arguments.size()) trap("callIndirect: bad # of arguments");
+ for (size_t i = 0; i < func->params.size(); i++) {
+ if (func->params[i] != arguments[i].type) {
+ trap("callIndirect: bad argument type");
+ }
+ }
+ return instance.callFunctionInternal(name, arguments);
+ } else {
+ // A JS function JS can call
+ prepareTempArgments(arguments);
+ double ret = EM_ASM_DOUBLE({
+ var func = Module['outside']['wasmTable'][$0];
+ var tempArguments = Module['tempArguments'];
+ Module['tempArguments'] = null;
+ return func.apply(null, tempArguments);
+ }, index);
+ return getResultFromJS(ret);
}
}
diff --git a/src/wasm.h b/src/wasm.h
index 82933bd..c41ff23 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -1434,8 +1434,19 @@ class Table {
public:
static const Index kMaxSize = Index(-1);
+ struct Segment {
+ Expression* offset;
+ std::vector<Name> data;
+ Segment() {}
+ Segment(Expression* offset) : offset(offset) {
+ }
+ Segment(Expression* offset, std::vector<Name>& init) : offset(offset) {
+ data.swap(init);
+ }
+ };
+
Address initial, max;
- std::vector<Name> names;
+ std::vector<Name> segments;
Table() : initial(0), max(kMaxSize) {}
};
@@ -1445,6 +1456,7 @@ public:
static const Address::address_t kPageSize = 64 * 1024;
static const Address::address_t kMaxSize = ~Address::address_t(0) / kPageSize;
static const Address::address_t kPageMask = ~(kPageSize - 1);
+
struct Segment {
Expression* offset;
std::vector<char> data; // TODO: optimize
diff --git a/test/spec b/test/spec
--- a/test/spec
+++ b/test/spec
@@ -1 +1 @@
-Subproject commit d4b150ce7268f903757ebdf1c7c001c99607da7a
+Subproject commit d4b150ce7268f903757ebdf1c7c001c99607da7a-dirty
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment