diff options
author | Alon Zakai <alonzakai@gmail.com> | 2016-08-19 09:49:38 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2016-09-07 09:55:03 -0700 |
commit | 266e922cddf0a5c78ed22f046eeebc053a9305c0 (patch) | |
tree | 2dec707b00304b1a6c888efb8f2c1b9a19ce38f3 /src | |
parent | 9660c200eff60c10266a85aae0637b495c4cba39 (diff) | |
download | binaryen-266e922cddf0a5c78ed22f046eeebc053a9305c0.tar.gz binaryen-266e922cddf0a5c78ed22f046eeebc053a9305c0.tar.bz2 binaryen-266e922cddf0a5c78ed22f046eeebc053a9305c0.zip |
use globals in asm2wasm
Diffstat (limited to 'src')
-rw-r--r-- | src/asm2wasm.h | 94 | ||||
-rw-r--r-- | src/js/wasm.js-post.js | 28 | ||||
-rw-r--r-- | src/passes/Print.cpp | 6 | ||||
-rw-r--r-- | src/passes/Vacuum.cpp | 2 | ||||
-rw-r--r-- | src/shell-interface.h | 8 | ||||
-rw-r--r-- | src/tools/asm2wasm.cpp | 12 | ||||
-rw-r--r-- | src/wasm-binary.h | 49 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 18 | ||||
-rw-r--r-- | src/wasm-js.cpp | 42 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 15 |
10 files changed, 131 insertions, 143 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h index 48c52080d..a85fd4676 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -143,15 +143,13 @@ class Asm2WasmBuilder { // globals - unsigned nextGlobal; // next place to put a global - unsigned maxGlobal; // highest address we can put a global struct MappedGlobal { - unsigned address; WasmType type; bool import; // if true, this is an import - we should read the value, not just set a zero IString module, base; - MappedGlobal() : address(0), type(none), import(false) {} - MappedGlobal(unsigned address, WasmType type, bool import, IString module, IString base) : address(address), type(type), import(import), module(module), base(base) {} + MappedGlobal() : type(none), import(false) {} + MappedGlobal(WasmType type) : type(type), import(false) {} + MappedGlobal(WasmType type, bool import, IString module, IString base) : type(type), import(import), module(module), base(base) {} }; // function table @@ -165,31 +163,20 @@ 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()) { + void allocateGlobal(IString name, WasmType type) { assert(mappedGlobals.find(name) == mappedGlobals.end()); - mappedGlobals.emplace(name, MappedGlobal(nextGlobal, type, import, module, base)); - nextGlobal += 8; - assert(nextGlobal < maxGlobal); + mappedGlobals.emplace(name, MappedGlobal(type)); + auto global = new Global(); + global->name = name; + global->type = type; + Literal value; + if (type == i32) value = Literal(uint32_t(0)); + else if (type == f32) value = Literal(float(0)); + else if (type == f64) value = Literal(double(0)); + else WASM_UNREACHABLE(); + global->init = wasm.allocator.alloc<Const>()->set(value); + wasm.addGlobal(global); } struct View { @@ -278,8 +265,6 @@ public: : wasm(wasm), allocator(wasm.allocator), builder(wasm), - nextGlobal(8), - maxGlobal(1000), memoryGrowth(memoryGrowth), debug(debug), imprecise(imprecise), @@ -520,13 +505,13 @@ void Asm2WasmBuilder::processAsm(Ref ast) { type = WasmType::f64; } if (type != WasmType::none) { - // wasm has no imported constants, so allocate a global, and we need to write the value into that - allocateGlobal(name, type, true, import->module, import->base); - delete import; + import->kind = Import::Global; + import->globalType = type; + mappedGlobals.emplace(name, type); } else { import->kind = Import::Function; - wasm.addImport(import); } + wasm.addImport(import); }; IString Int8Array, Int16Array, Int32Array, UInt8Array, UInt16Array, UInt32Array, Float32Array, Float64Array; @@ -554,7 +539,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) { if (value[0] == NUM) { // global int assert(value[1]->getNumber() == 0); - allocateGlobal(name, WasmType::i32, false); + allocateGlobal(name, WasmType::i32); } else if (value[0] == BINARY) { // int import assert(value[1] == OR && value[3][0] == NUM && value[3][1]->getNumber() == 0); @@ -567,14 +552,14 @@ void Asm2WasmBuilder::processAsm(Ref ast) { if (import[0] == NUM) { // global assert(import[1]->getNumber() == 0); - allocateGlobal(name, WasmType::f64, false); + allocateGlobal(name, WasmType::f64); } else { // import addImport(name, import, WasmType::f64); } } else if (value[0] == CALL) { assert(value[1][0] == NAME && value[1][1] == Math_fround && value[2][0][0] == NUM && value[2][0][1]->getNumber() == 0); - allocateGlobal(name, WasmType::f32, false); + allocateGlobal(name, WasmType::f32); } else if (value[0] == DOT) { // simple module.base import. can be a view, or a function. if (value[1][0] == NAME) { @@ -721,11 +706,9 @@ void Asm2WasmBuilder::processAsm(Ref ast) { if (optimize) { optimizingBuilder->finish(); - if (maxGlobal < 1024) { - PassRunner passRunner(&wasm); - passRunner.add("post-emscripten"); - passRunner.run(); - } + PassRunner passRunner(&wasm); + passRunner.add("post-emscripten"); + passRunner.run(); } // second pass. first, function imports @@ -733,6 +716,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) { std::vector<IString> toErase; for (auto& import : wasm.imports) { + if (import->kind != Import::Function) continue; IString name = import->name; if (importedFunctionTypes.find(name) != importedFunctionTypes.end()) { // special math builtins @@ -1021,18 +1005,9 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { ret->finalize(); return ret; } - // global var, do a store to memory + // global var assert(mappedGlobals.find(name) != mappedGlobals.end()); - MappedGlobal global = mappedGlobals[name]; - auto ret = allocator.alloc<Store>(); - ret->bytes = getWasmTypeSize(global.type); - ret->offset = 0; - ret->align = ret->bytes; - ret->ptr = builder.makeConst(Literal(int32_t(global.address))); - ret->value = process(ast[3]); - ret->valueType = global.type; - ret->finalize(); - return ret; + return builder.makeSetGlobal(name, process(ast[3])); } else if (ast[2][0] == SUB) { Ref target = ast[2]; assert(target[1][0] == NAME); @@ -1158,17 +1133,10 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { } return call; } - // global var, do a load from memory + // global var assert(mappedGlobals.find(name) != mappedGlobals.end()); - MappedGlobal global = mappedGlobals[name]; - auto ret = allocator.alloc<Load>(); - ret->bytes = getWasmTypeSize(global.type); - ret->signed_ = true; // but doesn't matter - ret->offset = 0; - ret->align = ret->bytes; - ret->ptr = builder.makeConst(Literal(int32_t(global.address))); - ret->type = global.type; - return ret; + MappedGlobal& global = mappedGlobals[name]; + return builder.makeGetGlobal(name, global.type); } else if (what == SUB) { Ref target = ast[1]; assert(target[0] == NAME); diff --git a/src/js/wasm.js-post.js b/src/js/wasm.js-post.js index ae42ef175..1c207b3f3 100644 --- a/src/js/wasm.js-post.js +++ b/src/js/wasm.js-post.js @@ -123,26 +123,6 @@ function integrateWasmJS(Module) { f64: 4 }; - // wasm lacks globals, so asm2wasm maps them into locations in memory. that information cannot - // be present in the wasm output of asm2wasm, so we store it in a side file. If we load asm2wasm - // output, either generated ahead of time or on the client, we need to apply those mapped - // globals after loading the module. - function applyMappedGlobals(globalsFileBase) { - var mappedGlobals = JSON.parse(Module['read'](globalsFileBase + '.mappedGlobals')); - 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 = lookupImport(global.module, global.base); - var address = global.address; - switch (global.type) { - case WasmTypes.i32: Module['HEAP32'][address >> 2] = value; break; - case WasmTypes.f32: Module['HEAPF32'][address >> 2] = value; break; - case WasmTypes.f64: Module['HEAPF64'][address >> 3] = value; break; - default: abort(); - } - } - } - function fixImports(imports) { if (!{{{ WASM_BACKEND }}}) return imports; var ret = {}; @@ -208,8 +188,6 @@ function integrateWasmJS(Module) { exports = instance.exports; mergeMemory(exports.memory); - applyMappedGlobals(wasmBinaryFile); - Module["usingWasm"] = true; return exports; @@ -271,12 +249,6 @@ function integrateWasmJS(Module) { Module['newBuffer'] = null; } - if (method == 'interpret-s-expr') { - applyMappedGlobals(wasmTextFile); - } else if (method == 'interpret-binary') { - applyMappedGlobals(wasmBinaryFile); - } - exports = wasmJS['asmExports']; return exports; diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index fcd155650..fe125234d 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -531,6 +531,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> { } void visitImport(Import *curr) { printOpening(o, "import "); + printName(curr->name) << ' '; switch (curr->kind) { case Export::Function: break; case Export::Table: o << "table "; break; @@ -538,14 +539,13 @@ struct PrintSExpression : public Visitor<PrintSExpression> { case Export::Global: o << "global "; break; default: WASM_UNREACHABLE(); } - printName(curr->name) << ' '; printText(o, curr->module.str) << ' '; printText(o, curr->base.str); switch (curr->kind) { case Export::Function: if (curr->functionType) visitFunctionType(curr->functionType); break; case Export::Table: break; case Export::Memory: break; - case Export::Global: o << printWasmType(curr->globalType); break; + case Export::Global: o << ' ' << printWasmType(curr->globalType); break; default: WASM_UNREACHABLE(); } o << ')'; @@ -564,7 +564,7 @@ struct PrintSExpression : public Visitor<PrintSExpression> { } void visitGlobal(Global *curr) { printOpening(o, "global "); - printName(curr->name) << ' ' << printWasmType(curr->type); + printName(curr->name) << ' ' << printWasmType(curr->type) << ' '; visit(curr->init); o << ')'; } diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp index bb005e36c..150593713 100644 --- a/src/passes/Vacuum.cpp +++ b/src/passes/Vacuum.cpp @@ -50,6 +50,8 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum, Visitor<Vacuum>> case Expression::Id::LoadId: case Expression::Id::StoreId: case Expression::Id::ReturnId: + case Expression::Id::GetGlobalId: + case Expression::Id::SetGlobalId: case Expression::Id::HostId: case Expression::Id::UnreachableId: return curr; // always needed diff --git a/src/shell-interface.h b/src/shell-interface.h index f9afe21fb..ee9ff166a 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -90,11 +90,11 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface { ShellExternalInterface() : memory() {} - void init(Module& wasm) override { + void init(Module& wasm, ModuleInstance& instance) override { memory.resize(wasm.memory.initial * wasm::Memory::kPageSize); // apply memory segments for (auto& segment : wasm.memory.segments) { - Address offset = ConstantExpressionRunner().visit(segment.offset).value.geti32(); + Address offset = ConstantExpressionRunner(instance.globals).visit(segment.offset).value.geti32(); assert(offset + segment.data.size() <= wasm.memory.initial * wasm::Memory::kPageSize); for (size_t i = 0; i != segment.data.size(); ++i) { memory.set(offset + i, segment.data[i]); @@ -103,7 +103,7 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface { table.resize(wasm.table.initial); for (auto& segment : wasm.table.segments) { - Address offset = ConstantExpressionRunner().visit(segment.offset).value.geti32(); + Address offset = ConstantExpressionRunner(instance.globals).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]; @@ -111,6 +111,8 @@ struct ShellExternalInterface : ModuleInstance::ExternalInterface { } } + void importGlobals(std::map<Name, Literal>& globals, Module& wasm) override {} + Literal callImport(Import *import, LiteralList& arguments) override { if (import->module == SPECTEST && import->base == PRINT) { for (auto argument : arguments) { diff --git a/src/tools/asm2wasm.cpp b/src/tools/asm2wasm.cpp index 7f1a07d1d..beacc884c 100644 --- a/src/tools/asm2wasm.cpp +++ b/src/tools/asm2wasm.cpp @@ -42,7 +42,7 @@ int main(int argc, const char *argv[]) { }) .add("--mapped-globals", "-m", "Mapped globals", Options::Arguments::One, [](Options *o, const std::string &argument) { - o->extra["mapped globals"] = argument; + std::cerr << "warning: the --mapped-globals/-m option is deprecated (a mapped globals file is no longer needed as we use wasm globals)" << std::endl; }) .add("--total-memory", "-m", "Total memory size", Options::Arguments::One, [](Options *o, const std::string &argument) { @@ -62,10 +62,6 @@ int main(int argc, const char *argv[]) { }); options.parse(argc, argv); - const auto &mg_it = options.extra.find("mapped globals"); - const char *mappedGlobals = - mg_it == options.extra.end() ? nullptr : mg_it->second.c_str(); - const auto &tm_it = options.extra.find("total memory"); size_t totalMemory = tm_it == options.extra.end() ? 16 * 1024 * 1024 : atoi(tm_it->second.c_str()); @@ -99,11 +95,5 @@ int main(int argc, const char *argv[]) { Output output(options.extra["output"], Flags::Text, options.debug ? Flags::Debug : Flags::Release); WasmPrinter::printModule(&wasm, output.getStream()); - if (mappedGlobals) { - if (options.debug) - std::cerr << "serializing mapped globals..." << std::endl; - asm2wasm.serializeMappedGlobals(mappedGlobals); - } - if (options.debug) std::cerr << "done." << std::endl; } diff --git a/src/wasm-binary.h b/src/wasm-binary.h index d6671be01..40671b082 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -741,7 +741,7 @@ public: return mappedImports[name]; } - std::map<Name, uint32_t> mappedFunctions; // name of the Function => index + std::map<Name, uint32_t> mappedFunctions; // name of the Function => index uint32_t getFunctionIndex(Name name) { if (!mappedFunctions.size()) { // Create name => index mapping. @@ -754,13 +754,20 @@ public: return mappedFunctions[name]; } - std::map<Name, uint32_t> mappedGlobals; // name of the Global => index + std::map<Name, uint32_t> mappedGlobals; // name of the Global => index. first imported globals, then internal globals uint32_t getGlobalIndex(Name name) { if (!mappedGlobals.size()) { // Create name => index mapping. + for (auto& import : wasm->imports) { + if (import->kind != Import::Global) continue; + assert(mappedGlobals.count(import->name) == 0); + auto index = mappedGlobals.size(); + mappedGlobals[import->name] = index; + } for (size_t i = 0; i < wasm->globals.size(); i++) { assert(mappedGlobals.count(wasm->globals[i]->name) == 0); - mappedGlobals[wasm->globals[i]->name] = i; + auto index = mappedGlobals.size(); + mappedGlobals[wasm->globals[i]->name] = index; } } assert(mappedGlobals.count(name)); @@ -1664,6 +1671,24 @@ public: return ret; } + std::map<Index, Name> mappedGlobals; // index of the Global => name. first imported globals, then internal globals + Name getGlobalName(Index index) { + if (!mappedGlobals.size()) { + // Create name => index mapping. + for (auto& import : wasm.imports) { + if (import->kind != Import::Global) continue; + auto index = mappedGlobals.size(); + mappedGlobals[index] = import->name; + } + for (size_t i = 0; i < wasm.globals.size(); i++) { + auto index = mappedGlobals.size(); + mappedGlobals[index] = wasm.globals[i]->name; + } + } + assert(mappedGlobals.count(index)); + return mappedGlobals[index]; + } + void processFunctions() { for (auto& func : functions) { wasm.addFunction(func); @@ -1680,7 +1705,7 @@ public: case Export::Function: curr->value = wasm.functions[iter.second]->name; break; case Export::Table: curr->value = Name::fromInt(0); break; case Export::Memory: curr->value = Name::fromInt(0); break; - case Export::Global: curr->value = wasm.globals[iter.second]->name; break; + case Export::Global: curr->value = getGlobalName(iter.second); break; default: WASM_UNREACHABLE(); } wasm.addExport(curr); @@ -1975,13 +2000,23 @@ public: void visitGetGlobal(GetGlobal *curr) { if (debug) std::cerr << "zz node: GetGlobal " << pos << std::endl; auto index = getU32LEB(); - curr->name = wasm.getGlobal(index)->name; - curr->type = wasm.getGlobal(index)->type; + curr->name = getGlobalName(index); + auto* global = wasm.checkGlobal(curr->name); + if (global) { + curr->type = global->type; + return; + } + auto* import = wasm.checkImport(curr->name); + if (import && import->kind == Import::Global) { + curr->type = import->globalType; + return; + } + throw ParseException("bad get_global"); } void visitSetGlobal(SetGlobal *curr) { if (debug) std::cerr << "zz node: SetGlobal" << std::endl; auto index = getU32LEB(); - curr->name = wasm.getGlobal(index)->name; + curr->name = getGlobalName(index); curr->value = popExpression(); } diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index db55cd143..292d6a521 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -485,14 +485,17 @@ public: // Execute an constant expression in a global init or memory offset class ConstantExpressionRunner : public ExpressionRunner<ConstantExpressionRunner> { + std::map<Name, Literal>& globals; public: + ConstantExpressionRunner(std::map<Name, Literal>& globals) : globals(globals) {} + Flow visitLoop(Loop* curr) { WASM_UNREACHABLE(); } Flow visitCall(Call* curr) { WASM_UNREACHABLE(); } Flow visitCallImport(CallImport* curr) { WASM_UNREACHABLE(); } Flow visitCallIndirect(CallIndirect* curr) { WASM_UNREACHABLE(); } Flow visitGetLocal(GetLocal *curr) { WASM_UNREACHABLE(); } Flow visitSetLocal(SetLocal *curr) { WASM_UNREACHABLE(); } - Flow visitGetGlobal(GetGlobal *curr) { WASM_UNREACHABLE(); } + Flow visitGetGlobal(GetGlobal *curr) { return Flow(globals[curr->name]); } Flow visitSetGlobal(SetGlobal *curr) { WASM_UNREACHABLE(); } Flow visitLoad(Load *curr) { WASM_UNREACHABLE(); } Flow visitStore(Store *curr) { WASM_UNREACHABLE(); } @@ -517,7 +520,8 @@ public: // an imported function or accessing memory. // struct ExternalInterface { - virtual void init(Module& wasm) {} + virtual void init(Module& wasm, ModuleInstance& instance) {} + virtual void importGlobals(std::map<Name, Literal>& globals, Module& wasm) = 0; virtual Literal callImport(Import* import, LiteralList& arguments) = 0; virtual Literal callTable(Index index, LiteralList& arguments, WasmType result, ModuleInstance& instance) = 0; virtual Literal load(Load* load, Address addr) = 0; @@ -532,11 +536,17 @@ public: std::map<Name, Literal> globals; ModuleInstance(Module& wasm, ExternalInterface* externalInterface) : wasm(wasm), externalInterface(externalInterface) { + // import globals from the outside + externalInterface->importGlobals(globals, wasm); + // prepare memory memorySize = wasm.memory.initial; + // generate internal (non-imported) globals for (auto& global : wasm.globals) { - globals[global->name] = ConstantExpressionRunner().visit(global->init).value; + globals[global->name] = ConstantExpressionRunner(globals).visit(global->init).value; } - externalInterface->init(wasm); + // initialize the rest of the external interface + externalInterface->init(wasm, *this); + // run start, if present if (wasm.start.is()) { LiteralList arguments; callFunction(wasm.start, arguments); diff --git a/src/wasm-js.cpp b/src/wasm-js.cpp index 3c3c4eec7..fc27bc37a 100644 --- a/src/wasm-js.cpp +++ b/src/wasm-js.cpp @@ -81,21 +81,6 @@ extern "C" void EMSCRIPTEN_KEEPALIVE load_asm2wasm(char *input) { if (wasmJSDebug) std::cerr << "wasming...\n"; asm2wasm = new Asm2WasmBuilder(*module, pre.memoryGrowth, debug, false /* TODO: support imprecise? */, false /* TODO: support optimizing? */); asm2wasm->processAsm(asmjs); - - 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); - uint32_t 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(); - } - } } void finalizeModule() { @@ -176,14 +161,14 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() { var mod = Pointer_stringify($0); var base = Pointer_stringify($1); var name = Pointer_stringify($2); - assert(Module['lookupImport'](mod, base), 'checking import ' + name + ' = ' + mod + '.' + base); + assert(Module['lookupImport'](mod, base) !== undefined, 'checking import ' + name + ' = ' + mod + '.' + base); }, import->module.str, import->base.str, import->name.str); } if (wasmJSDebug) std::cerr << "creating instance...\n"; struct JSExternalInterface : ModuleInstance::ExternalInterface { - void init(Module& wasm) override { + void init(Module& wasm, ModuleInstance& instance) override { // create a new buffer here, just like native wasm support would. EM_ASM_({ Module['outside']['newBuffer'] = new ArrayBuffer($0); @@ -193,7 +178,7 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() { var source = Module['HEAP8'].subarray($1, $1 + $2); var target = new Int8Array(Module['outside']['newBuffer']); target.set(source, $0); - }, ConstantExpressionRunner().visit(segment.offset).value.geti32(), &segment.data[0], segment.data.size()); + }, ConstantExpressionRunner(instance.globals).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? @@ -201,7 +186,7 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() { Module['outside']['wasmTable'] = new Array($0); }, wasm.table.initial); for (auto segment : wasm.table.segments) { - Address offset = ConstantExpressionRunner().visit(segment.offset).value.geti32(); + Address offset = ConstantExpressionRunner(instance.globals).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_({ @@ -238,6 +223,23 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() { } } + void importGlobals(std::map<Name, Literal>& globals, Module& wasm) override { + for (auto& import : wasm.imports) { + if (import->kind == Import::Global) { + double ret = EM_ASM_DOUBLE({ + var mod = Pointer_stringify($0); + var base = Pointer_stringify($1); + var lookup = Module['lookupImport'](mod, base); + return lookup; + }, import->module.str, import->base.str); + + if (wasmJSDebug) std::cout << "calling importGlobal for " << import->name << " returning " << ret << '\n'; + + globals[import->name] = getResultFromJS(ret, import->globalType); + } + } + } + Literal callImport(Import *import, LiteralList& arguments) override { if (wasmJSDebug) std::cout << "calling import " << import->name.str << '\n'; prepareTempArgments(arguments); @@ -252,7 +254,7 @@ extern "C" void EMSCRIPTEN_KEEPALIVE instantiate() { if (wasmJSDebug) std::cout << "calling import returning " << ret << '\n'; - return getResultFromJS(ret, import->type->result); + return getResultFromJS(ret, import->functionType->result); } Literal callTable(Index index, LiteralList& arguments, WasmType result, ModuleInstance& instance) override { diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index 60cc21e26..65335c1be 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -949,9 +949,16 @@ private: auto ret = allocator.alloc<GetGlobal>(); ret->name = s[1]->str(); auto* global = wasm.checkGlobal(ret->name); - if (!global) throw ParseException("bad get_global name", s.line, s.col); - ret->type = global->type; - return ret; + if (global) { + ret->type = global->type; + return ret; + } + auto* import = wasm.checkImport(ret->name); + if (import && import->kind == Import::Global) { + ret->type = import->globalType; + return ret; + } + throw ParseException("bad get_global name", s.line, s.col); } Expression* makeSetGlobal(Element& s) { @@ -1434,7 +1441,7 @@ private: } else if (s[2]->str() == TABLE) { im->kind = Import::Table; } else if (s[2]->str() == GLOBAL) { - im->kind = Import::Table; + im->kind = Import::Global; } else { WASM_UNREACHABLE(); } |