summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binaryen-c.cpp8
-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