diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binaryen-c.cpp | 8 | ||||
-rw-r--r-- | src/tools/wasm2js.cpp (renamed from src/tools/wasm2asm.cpp) | 57 | ||||
-rw-r--r-- | src/wasm2js.h (renamed from src/wasm2asm.h) | 340 |
3 files changed, 296 insertions, 109 deletions
diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 33281ff82..903a179c6 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -29,7 +29,7 @@ #include "wasm-printing.h" #include "wasm-s-parser.h" #include "wasm-validator.h" -#include "wasm2asm.h" +#include "wasm2js.h" #include "cfg/Relooper.h" #include "ir/utils.h" #include "shell-interface.h" @@ -2008,9 +2008,9 @@ void BinaryenModulePrintAsmjs(BinaryenModuleRef module) { } Module* wasm = (Module*)module; - Wasm2AsmBuilder::Flags builderFlags; - Wasm2AsmBuilder wasm2asm(builderFlags); - Ref asmjs = wasm2asm.processWasm(wasm); + Wasm2JSBuilder::Flags builderFlags; + Wasm2JSBuilder wasm2js(builderFlags); + Ref asmjs = wasm2js.processWasm(wasm); JSPrinter jser(true, true, asmjs); jser.printAst(); diff --git a/src/tools/wasm2asm.cpp b/src/tools/wasm2js.cpp index fd65ca5e6..8a57a5a1a 100644 --- a/src/tools/wasm2asm.cpp +++ b/src/tools/wasm2js.cpp @@ -15,21 +15,21 @@ */ // -// wasm2asm console tool +// wasm2js console tool // #include "support/colors.h" #include "support/command-line.h" #include "support/file.h" #include "wasm-s-parser.h" -#include "wasm2asm.h" +#include "wasm2js.h" using namespace cashew; using namespace wasm; int main(int argc, const char *argv[]) { - Wasm2AsmBuilder::Flags builderFlags; - Options options("wasm2asm", "Transform .wast files to asm.js"); + Wasm2JSBuilder::Flags builderFlags; + Options options("wasm2js", "Transform .wasm/.wast files to asm.js"); options .add("--output", "-o", "Output file (stdout if not specified)", Options::Arguments::One, @@ -55,28 +55,49 @@ int main(int argc, const char *argv[]) { options.parse(argc, argv); if (options.debug) builderFlags.debug = true; - auto input( - read_file<std::vector<char>>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release)); - Element* root; Module wasm; Ref asmjs; try { - if (options.debug) std::cerr << "s-parsing..." << std::endl; - SExpressionParser parser(input.data()); - root = parser.root; + // If the input filename ends in `.wasm`, then parse it in binary form, + // otherwise assume it's a `*.wast` file and go from there. + // + // Note that we're not using the built-in `ModuleReader` which will also do + // similar logic here because when testing JS files we use the + // `--allow-asserts` flag which means we need to parse the extra + // s-expressions that come at the end of the `*.wast` file after the module + // is defined. + auto &input = options.extra["infile"]; + std::string suffix(".wasm"); + if (input.size() >= suffix.size() && + input.compare(input.size() - suffix.size(), suffix.size(), suffix) == 0) { + ModuleReader reader; + reader.setDebug(options.debug); + reader.read(input, wasm, ""); + + if (options.debug) std::cerr << "asming..." << std::endl; + Wasm2JSBuilder wasm2js(builderFlags); + asmjs = wasm2js.processWasm(&wasm); + + } else { + auto input( + read_file<std::vector<char>>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release)); + if (options.debug) std::cerr << "s-parsing..." << std::endl; + SExpressionParser parser(input.data()); + root = parser.root; - if (options.debug) std::cerr << "w-parsing..." << std::endl; - SExpressionWasmBuilder builder(wasm, *(*root)[0]); + if (options.debug) std::cerr << "w-parsing..." << std::endl; + SExpressionWasmBuilder builder(wasm, *(*root)[0]); - if (options.debug) std::cerr << "asming..." << std::endl; - Wasm2AsmBuilder wasm2asm(builderFlags); - asmjs = wasm2asm.processWasm(&wasm); + if (options.debug) std::cerr << "asming..." << std::endl; + Wasm2JSBuilder wasm2js(builderFlags); + asmjs = wasm2js.processWasm(&wasm); - if (options.extra["asserts"] == "1") { - if (options.debug) std::cerr << "asserting..." << std::endl; - flattenAppend(asmjs, wasm2asm.processAsserts(&wasm, *root, builder)); + if (options.extra["asserts"] == "1") { + if (options.debug) std::cerr << "asserting..." << std::endl; + flattenAppend(asmjs, wasm2js.processAsserts(&wasm, *root, builder)); + } } } catch (ParseException& p) { p.dump(std::cerr); diff --git a/src/wasm2asm.h b/src/wasm2js.h index e89352432..40f8e3057 100644 --- a/src/wasm2asm.h +++ b/src/wasm2js.h @@ -19,8 +19,8 @@ // infrastructure. // -#ifndef wasm_wasm2asm_h -#define wasm_wasm2asm_h +#ifndef wasm_wasm2js_h +#define wasm_wasm2js_h #include <cmath> #include <numeric> @@ -45,8 +45,8 @@ using namespace cashew; IString ASM_FUNC("asmFunc"), ABORT_FUNC("abort"), FUNCTION_TABLE("FUNCTION_TABLE"), - NO_RESULT("wasm2asm$noresult"), // no result at all - EXPRESSION_RESULT("wasm2asm$expresult"); // result in an expression, no temp var + NO_RESULT("wasm2js$noresult"), // no result at all + EXPRESSION_RESULT("wasm2js$expresult"); // result in an expression, no temp var // Appends extra to block, flattening out if extra is a block as well void flattenAppend(Ref ast, Ref extra) { @@ -73,8 +73,9 @@ enum class NameScope { Max, }; -static uint64_t constOffset(Table::Segment &segment) { - auto* c = segment.offset->dynCast<Const>(); +template<typename T> +static uint64_t constOffset(const T& segment) { + auto* c = segment.offset->template dynCast<Const>(); if (!c) { Fatal() << "non-constant offsets aren't supported yet\n"; abort(); @@ -83,7 +84,7 @@ static uint64_t constOffset(Table::Segment &segment) { } // -// Wasm2AsmBuilder - converts a WebAssembly module into asm.js +// Wasm2JSBuilder - converts a WebAssembly module into asm.js // // In general, asm.js => wasm is very straightforward, as can // be seen in asm2wasm.h. Just a single pass, plus a little @@ -111,7 +112,7 @@ static uint64_t constOffset(Table::Segment &segment) { // can easily show bad behavior here, with many unnecessary // temp vars. We could rely on optimization passes like // Emscripten's eliminate/registerize pair, but we want -// wasm2asm to be fairly fast to run, as it might run on +// wasm2js to be fairly fast to run, as it might run on // the client. // // The approach taken here therefore performs 2 passes on @@ -129,7 +130,7 @@ static uint64_t constOffset(Table::Segment &segment) { // optimizing away unnecessary forwarding. -class Wasm2AsmBuilder { +class Wasm2JSBuilder { MixedArena allocator; public: @@ -139,7 +140,7 @@ public: bool allowAsserts = false; }; - Wasm2AsmBuilder(Flags f) : flags(f) {} + Wasm2JSBuilder(Flags f) : flags(f) {} Ref processWasm(Module* wasm, Name funcName = ASM_FUNC); Ref processFunction(Module* wasm, Function* func); @@ -166,7 +167,7 @@ public: frees[type].pop_back(); } else { size_t index = temps[type]++; - ret = IString((std::string("wasm2asm_") + printType(type) + "$" + + ret = IString((std::string("wasm2js_") + printType(type) + "$" + std::to_string(index)).c_str(), false); } if (func->localIndices.find(ret) == func->localIndices.end()) { @@ -268,6 +269,8 @@ private: bool almostASM = false; + void addEsmImports(Ref ast, Module* wasm); + void addEsmExportsAndInstantiate(Ref ast, Module* wasm, Name funcName); void addBasics(Ref ast); void addImport(Ref ast, Import* import); void addTables(Ref ast, Module* wasm); @@ -294,12 +297,12 @@ private: Element& e, Name testFuncName, Name asmModule); - Wasm2AsmBuilder() = delete; - Wasm2AsmBuilder(const Wasm2AsmBuilder &) = delete; - Wasm2AsmBuilder &operator=(const Wasm2AsmBuilder&) = delete; + Wasm2JSBuilder() = delete; + Wasm2JSBuilder(const Wasm2JSBuilder &) = delete; + Wasm2JSBuilder &operator=(const Wasm2JSBuilder&) = delete; }; -Ref Wasm2AsmBuilder::processWasm(Module* wasm, Name funcName) { +Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) { PassRunner runner(wasm); runner.add<AutoDrop>(); // First up remove as many non-JS operations we can, including things like @@ -328,8 +331,10 @@ Ref Wasm2AsmBuilder::processWasm(Module* wasm, Name funcName) { #endif Ref ret = ValueBuilder::makeToplevel(); + addEsmImports(ret, wasm); Ref asmFunc = ValueBuilder::makeFunction(funcName); ret[1]->push_back(asmFunc); + addEsmExportsAndInstantiate(ret, wasm, funcName); ValueBuilder::appendArgumentToFunction(asmFunc, GLOBAL); ValueBuilder::appendArgumentToFunction(asmFunc, ENV); ValueBuilder::appendArgumentToFunction(asmFunc, BUFFER); @@ -397,7 +402,207 @@ Ref Wasm2AsmBuilder::processWasm(Module* wasm, Name funcName) { return ret; } -void Wasm2AsmBuilder::addBasics(Ref ast) { +void Wasm2JSBuilder::addEsmImports(Ref ast, Module *wasm) { + std::unordered_map<Name, Name> nameMap; + + for (auto& import : wasm->imports) { + // Only function imports are supported for now, but eventually imported + // memories can probably be supported at least. + switch (import->kind) { + case ExternalKind::Function: break; + default: + Fatal() << "non-function imports aren't supported yet\n"; + abort(); + } + + // Right now codegen requires a flat namespace going into the module, + // meaning we don't importing the same name from multiple namespaces yet. + if (nameMap.count(import->base) && nameMap[import->base] != import->module) { + Fatal() << "the name " << import->base << " cannot be imported from " + << "two different modules yet\n"; + abort(); + } + + nameMap[import->base] = import->module; + + std::ostringstream out; + out << "import { " + << import->base.str + << " } from '" + << import->module.str + << "'"; + std::string os = out.str(); + IString name(os.c_str(), false); + flattenAppend(ast, ValueBuilder::makeName(name)); + } +} + +static std::string base64Encode(std::vector<char> &data) { + std::string ret; + size_t i = 0; + + const char* alphabet = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + while (i + 3 <= data.size()) { + int bits = + (((int) data[i + 0]) << 16) | + (((int) data[i + 1]) << 8) | + (((int) data[i + 2]) << 0); + ret += alphabet[(bits >> 18) & 0x3f]; + ret += alphabet[(bits >> 12) & 0x3f]; + ret += alphabet[(bits >> 6) & 0x3f]; + ret += alphabet[(bits >> 0) & 0x3f]; + i += 3; + } + + if (i + 2 == data.size()) { + int bits = + (((int) data[i + 0]) << 8) | + (((int) data[i + 1]) << 0); + ret += alphabet[(bits >> 10) & 0x3f]; + ret += alphabet[(bits >> 4) & 0x3f]; + ret += alphabet[(bits << 2) & 0x3f]; + ret += '='; + } else if (i + 1 == data.size()) { + int bits =(int) data[i + 0]; + ret += alphabet[(bits >> 2) & 0x3f]; + ret += alphabet[(bits << 4) & 0x3f]; + ret += '='; + ret += '='; + } else { + assert(i == data.size()); + } + + return ret; +} + +void Wasm2JSBuilder::addEsmExportsAndInstantiate(Ref ast, Module *wasm, Name funcName) { + // Create an initial `ArrayBuffer` and populate it with static data. + // Currently we use base64 encoding to encode static data and we decode it at + // instantiation time. + // + // Note that the translation here expects that the lower values of this memory + // can be used for conversions, so make sure there's at least one page. + { + auto pages = wasm->memory.initial == 0 ? 1 : wasm->memory.initial.addr; + std::ostringstream out; + out << "const mem" << funcName.str << " = new ArrayBuffer(" + << pages * Memory::kPageSize + << ")"; + std::string os = out.str(); + IString name(os.c_str(), false); + flattenAppend(ast, ValueBuilder::makeName(name)); + } + + if (wasm->memory.segments.size() > 0) { + auto expr = R"( + function(mem) { + const _mem = new Uint8Array(mem); + return function(offset, s) { + if (typeof Buffer === 'undefined') { + const bytes = atob(s); + for (let i = 0; i < bytes.length; i++) + _mem[offset + i] = bytes.charCodeAt(i); + } else { + const bytes = Buffer.from(s, 'base64'); + for (let i = 0; i < bytes.length; i++) + _mem[offset + i] = bytes[i]; + } + } + } + )"; + + // const assign$name = ($expr)(mem$name); + std::ostringstream out; + out << "const assign" << funcName.str + << " = (" << expr << ")(mem" << funcName.str << ")"; + std::string os = out.str(); + IString name(os.c_str(), false); + flattenAppend(ast, ValueBuilder::makeName(name)); + } + for (auto& seg : wasm->memory.segments) { + std::ostringstream out; + out << "assign" << funcName.str << "(" + << constOffset(seg) + << ", \"" + << base64Encode(seg.data) + << "\")"; + std::string os = out.str(); + IString name(os.c_str(), false); + flattenAppend(ast, ValueBuilder::makeName(name)); + } + + // Actually invoke the `asmFunc` generated function, passing in all global + // values followed by all imports (imported via addEsmImports above) + std::ostringstream construct; + construct << "const ret" << funcName.str << " = " << funcName.str << "({" + << "Math," + << "Int8Array," + << "Uint8Array," + << "Int16Array," + << "Uint16Array," + << "Int32Array," + << "Uint32Array," + << "Float32Array," + << "Float64Array," + << "NaN," + << "Infinity" + << "}, {"; + + construct << "abort:function() { throw new Error('abort'); }"; + for (auto& import : wasm->imports) { + switch (import->kind) { + case ExternalKind::Function: break; + default: continue; + } + construct << "," << import->base.str; + } + construct << "},mem" << funcName.str << ")"; + std::string sconstruct = construct.str(); + IString name(sconstruct.c_str(), false); + flattenAppend(ast, ValueBuilder::makeName(name)); + + if (flags.allowAsserts) { + return; + } + + // And now that we have our returned instance, export all our functions + // that are hanging off it. + for (auto& exp : wasm->exports) { + switch (exp->kind) { + case ExternalKind::Function: + case ExternalKind::Memory: + break; + + // Exported globals and function tables aren't supported yet + default: + continue; + } + std::ostringstream export_name; + for (auto *ptr = exp->name.str; *ptr; ptr++) { + if (*ptr == '-') { + export_name << '_'; + } else { + export_name << *ptr; + } + } + std::ostringstream out; + out << "export const " + << fromName(exp->name, NameScope::Top).str + << " = ret" + << funcName.str + << "." + << fromName(exp->name, NameScope::Top).str; + std::string os = out.str(); + IString name(os.c_str(), false); + flattenAppend(ast, ValueBuilder::makeName(name)); + } +} + +void Wasm2JSBuilder::addBasics(Ref ast) { // heaps, var HEAP8 = new global.Int8Array(buffer); etc auto addHeap = [&](IString name, IString view) { Ref theVar = ValueBuilder::makeVar(); @@ -473,7 +678,7 @@ void Wasm2AsmBuilder::addBasics(Ref ast) { ); } -void Wasm2AsmBuilder::addImport(Ref ast, Import* import) { +void Wasm2JSBuilder::addImport(Ref ast, Import* import) { Ref theVar = ValueBuilder::makeVar(); ast->push_back(theVar); Ref module = ValueBuilder::makeName(ENV); // TODO: handle nested module imports @@ -486,7 +691,7 @@ void Wasm2AsmBuilder::addImport(Ref ast, Import* import) { ); } -void Wasm2AsmBuilder::addTables(Ref ast, Module* wasm) { +void Wasm2JSBuilder::addTables(Ref ast, Module* wasm) { std::map<std::string, std::vector<IString>> tables; // asm.js tables, sig => contents of table for (Table::Segment& seg : wasm->table.segments) { for (size_t i = 0; i < seg.data.size(); i++) { @@ -521,7 +726,7 @@ void Wasm2AsmBuilder::addTables(Ref ast, Module* wasm) { } } -void Wasm2AsmBuilder::addExports(Ref ast, Module* wasm) { +void Wasm2JSBuilder::addExports(Ref ast, Module* wasm) { Ref exports = ValueBuilder::makeObject(); for (auto& export_ : wasm->exports) { if (export_->kind == ExternalKind::Function) { @@ -576,7 +781,7 @@ void Wasm2AsmBuilder::addExports(Ref ast, Module* wasm) { ast->push_back(ValueBuilder::makeStatement(ValueBuilder::makeReturn(exports))); } -void Wasm2AsmBuilder::addGlobal(Ref ast, Global* global) { +void Wasm2JSBuilder::addGlobal(Ref ast, Global* global) { if (auto* const_ = global->init->dynCast<Const>()) { Ref theValue; switch (const_->type) { @@ -620,7 +825,7 @@ static bool expressionEndsInReturn(Expression *e) { return expressionEndsInReturn((*stats)[stats->size()-1]); } -Ref Wasm2AsmBuilder::processFunction(Module* m, Function* func) { +Ref Wasm2JSBuilder::processFunction(Module* m, Function* func) { if (flags.debug) { static int fns = 0; std::cerr << "processFunction " << (fns++) << " " << func->name @@ -704,11 +909,11 @@ Ref Wasm2AsmBuilder::processFunction(Module* m, Function* func) { return ret; } -void Wasm2AsmBuilder::scanFunctionBody(Expression* curr) { +void Wasm2JSBuilder::scanFunctionBody(Expression* curr) { struct ExpressionScanner : public PostWalker<ExpressionScanner> { - Wasm2AsmBuilder* parent; + Wasm2JSBuilder* parent; - ExpressionScanner(Wasm2AsmBuilder* parent) : parent(parent) {} + ExpressionScanner(Wasm2JSBuilder* parent) : parent(parent) {} // Visitors @@ -792,26 +997,26 @@ void Wasm2AsmBuilder::scanFunctionBody(Expression* curr) { ExpressionScanner(this).walk(curr); } -Ref Wasm2AsmBuilder::processFunctionBody(Module* m, Function* func, IString result) { +Ref Wasm2JSBuilder::processFunctionBody(Module* m, Function* func, IString result) { struct ExpressionProcessor : public Visitor<ExpressionProcessor, Ref> { - Wasm2AsmBuilder* parent; + Wasm2JSBuilder* parent; IString result; Function* func; Module* module; MixedArena allocator; - ExpressionProcessor(Wasm2AsmBuilder* parent, Module* m, Function* func) + ExpressionProcessor(Wasm2JSBuilder* parent, Module* m, Function* func) : parent(parent), func(func), module(m) {} // A scoped temporary variable. struct ScopedTemp { - Wasm2AsmBuilder* parent; + Wasm2JSBuilder* parent; Type type; IString temp; bool needFree; // @param possible if provided, this is a variable we can use as our temp. it has already been // allocated in a higher scope, and we can just assign to it as our result is // going there anyhow. - ScopedTemp(Type type, Wasm2AsmBuilder* parent, Function* func, + ScopedTemp(Type type, Wasm2JSBuilder* parent, Function* func, IString possible = NO_RESULT) : parent(parent), type(type) { assert(possible != EXPRESSION_RESULT); if (possible == NO_RESULT) { @@ -1839,16 +2044,11 @@ Ref Wasm2AsmBuilder::processFunctionBody(Module* m, Function* func, IString resu return ExpressionProcessor(this, m, func).visit(func->body, result); } -static void makeInstantiation(Ref ret, Name funcName, Name moduleName, bool first) { - Name buffer("__array_buffer"); +static void makeHelpers(Ref ret, Name funcName, Name moduleName, bool first) { if (first) { // TODO: nan and infinity shouldn't be needed once literal asm.js code isn't // generated flattenAppend(ret, ValueBuilder::makeName(R"( - var __array_buffer = new ArrayBuffer(65536) - var HEAP32 = new Int32Array(__array_buffer); - var HEAPF32 = new Float32Array(__array_buffer); - var HEAPF64 = new Float64Array(__array_buffer); var nan = NaN; var infinity = Infinity; )")); @@ -1885,48 +2085,12 @@ static void makeInstantiation(Ref ret, Name funcName, Name moduleName, bool firs return (isNaN(a) && isNaN(b)) || (ai1 == bi1 && ai2 == bi2); } + + function i64Equal(actual_lo, actual_hi, expected_lo, expected_hi) { + return actual_lo == (expected_lo | 0) && actual_hi == (expected_hi | 0); + } )")); } - - Ref lib = ValueBuilder::makeObject(); - auto insertItem = [&](IString item) { - ValueBuilder::appendToObject(lib, item, ValueBuilder::makeName(item)); - }; - insertItem(MATH); - insertItem(INT8ARRAY); - insertItem(INT16ARRAY); - insertItem(INT32ARRAY); - insertItem(UINT8ARRAY); - insertItem(UINT16ARRAY); - insertItem(UINT32ARRAY); - insertItem(FLOAT32ARRAY); - insertItem(FLOAT64ARRAY); - // TODO: these shouldn't be necessary once we don't generate literal asm.js - // code - insertItem("Infinity"); - insertItem("NaN"); - Ref env = ValueBuilder::makeObject(); - Ref abortFunc = ValueBuilder::makeFunction("abort"); - abortFunc[3]->push_back(ValueBuilder::makeCall("unreachable")); - ValueBuilder::appendToObject(env, "abort", abortFunc); - - Ref printFunc = ValueBuilder::makeFunction("print"); - abortFunc[3]->push_back(ValueBuilder::makeCall("console_log")); - ValueBuilder::appendToObject(env, "print", printFunc); - Ref call = ValueBuilder::makeCall(IString(funcName), lib, env, - ValueBuilder::makeName(buffer)); - Ref module = ValueBuilder::makeVar(); - ValueBuilder::appendToVar(module, moduleName, call); - flattenAppend(ret, module); - - // 64-bit numbers get a different ABI w/ wasm2asm, and in general you can't - // actually export them from wasm at the boundary. We hack around this though - // to get the spec tests working. - flattenAppend(ret, ValueBuilder::makeName(R"( - function i64Equal(actual_lo, actual_hi, expected_lo, expected_hi) { - return actual_lo == (expected_lo | 0) && actual_hi == (expected_hi | 0); - } - )")); } static void prefixCalls(Ref asmjs, Name asmModule) { @@ -1961,7 +2125,7 @@ static void prefixCalls(Ref asmjs, Name asmModule) { } } -Ref Wasm2AsmBuilder::makeAssertReturnFunc(SExpressionWasmBuilder& sexpBuilder, +Ref Wasm2JSBuilder::makeAssertReturnFunc(SExpressionWasmBuilder& sexpBuilder, Module* wasm, Builder& wasmBuilder, Element& e, @@ -2026,7 +2190,7 @@ Ref Wasm2AsmBuilder::makeAssertReturnFunc(SExpressionWasmBuilder& sexpBuilder, return jsFunc; } -Ref Wasm2AsmBuilder::makeAssertReturnNanFunc(SExpressionWasmBuilder& sexpBuilder, +Ref Wasm2JSBuilder::makeAssertReturnNanFunc(SExpressionWasmBuilder& sexpBuilder, Module* wasm, Builder& wasmBuilder, Element& e, @@ -2048,7 +2212,7 @@ Ref Wasm2AsmBuilder::makeAssertReturnNanFunc(SExpressionWasmBuilder& sexpBuilder return jsFunc; } -Ref Wasm2AsmBuilder::makeAssertTrapFunc(SExpressionWasmBuilder& sexpBuilder, +Ref Wasm2JSBuilder::makeAssertTrapFunc(SExpressionWasmBuilder& sexpBuilder, Module* wasm, Builder& wasmBuilder, Element& e, @@ -2092,14 +2256,14 @@ Ref Wasm2AsmBuilder::makeAssertTrapFunc(SExpressionWasmBuilder& sexpBuilder, return outerFunc; } -void Wasm2AsmBuilder::setNeedsAlmostASM(const char *reason) { +void Wasm2JSBuilder::setNeedsAlmostASM(const char *reason) { if (!almostASM) { almostASM = true; std::cerr << "Switching to \"almost asm\" mode, reason: " << reason << std::endl; } } -void Wasm2AsmBuilder::addMemoryGrowthFuncs(Ref ast) { +void Wasm2JSBuilder::addMemoryGrowthFuncs(Ref ast) { Ref growMemoryFunc = ValueBuilder::makeFunction(WASM_GROW_MEMORY); ValueBuilder::appendArgumentToFunction(growMemoryFunc, IString("pagesToAdd")); @@ -2250,7 +2414,7 @@ void Wasm2AsmBuilder::addMemoryGrowthFuncs(Ref ast) { ast->push_back(currentMemoryFunc); } -bool Wasm2AsmBuilder::isAssertHandled(Element& e) { +bool Wasm2JSBuilder::isAssertHandled(Element& e) { return e.isList() && e.size() >= 2 && e[0]->isStr() && (e[0]->str() == Name("assert_return") || e[0]->str() == Name("assert_return_nan") || @@ -2259,26 +2423,28 @@ bool Wasm2AsmBuilder::isAssertHandled(Element& e) { && (*e[1])[0]->str() == Name("invoke"); } -Ref Wasm2AsmBuilder::processAsserts(Module* wasm, +Ref Wasm2JSBuilder::processAsserts(Module* wasm, Element& root, SExpressionWasmBuilder& sexpBuilder) { Builder wasmBuilder(sexpBuilder.getAllocator()); Ref ret = ValueBuilder::makeBlock(); - Name asmModule = ASM_MODULE; - makeInstantiation(ret, ASM_FUNC, asmModule, true); + std::stringstream asmModuleS; + asmModuleS << "ret" << ASM_FUNC.c_str(); + Name asmModule(asmModuleS.str().c_str()); + makeHelpers(ret, ASM_FUNC, asmModule, true); for (size_t i = 1; i < root.size(); ++i) { Element& e = *root[i]; if (e.isList() && e.size() >= 1 && e[0]->isStr() && e[0]->str() == Name("module")) { std::stringstream funcNameS; funcNameS << ASM_FUNC.c_str() << i; std::stringstream moduleNameS; - moduleNameS << ASM_MODULE.c_str() << i; + moduleNameS << "ret" << ASM_FUNC.c_str() << i; Name funcName(funcNameS.str().c_str()); asmModule = Name(moduleNameS.str().c_str()); Module wasm; SExpressionWasmBuilder builder(wasm, e); flattenAppend(ret, processWasm(&wasm, funcName)); - makeInstantiation(ret, funcName, asmModule, false); + makeHelpers(ret, funcName, asmModule, false); continue; } if (!isAssertHandled(e)) { @@ -2319,4 +2485,4 @@ Ref Wasm2AsmBuilder::processAsserts(Module* wasm, } // namespace wasm -#endif // wasm_wasm2asm_h +#endif // wasm_wasm2js_h |