diff options
author | Alon Zakai <alonzakai@gmail.com> | 2016-05-12 17:50:44 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2016-05-12 17:50:44 -0700 |
commit | 4a720eca42c463d53db1c81f9957a3e5d9011836 (patch) | |
tree | b6810b5161b7a6835a468f63403080e26799cfad /src/tools | |
parent | f518f097c80c0659fbacf11fe12f89955093282b (diff) | |
download | binaryen-4a720eca42c463d53db1c81f9957a3e5d9011836.tar.gz binaryen-4a720eca42c463d53db1c81f9957a3e5d9011836.tar.bz2 binaryen-4a720eca42c463d53db1c81f9957a3e5d9011836.zip |
move console tool sources into src/tools (#490)
Diffstat (limited to 'src/tools')
-rw-r--r-- | src/tools/asm2wasm.cpp | 114 | ||||
-rw-r--r-- | src/tools/binaryen-shell.cpp | 252 | ||||
-rw-r--r-- | src/tools/s2wasm.cpp | 140 | ||||
-rw-r--r-- | src/tools/wasm-as.cpp | 69 | ||||
-rw-r--r-- | src/tools/wasm-dis.cpp | 62 |
5 files changed, 637 insertions, 0 deletions
diff --git a/src/tools/asm2wasm.cpp b/src/tools/asm2wasm.cpp new file mode 100644 index 000000000..e18f78de9 --- /dev/null +++ b/src/tools/asm2wasm.cpp @@ -0,0 +1,114 @@ +/* + * Copyright 2015 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// asm2wasm console tool +// + +#include "support/colors.h" +#include "support/command-line.h" +#include "support/file.h" +#include "wasm-printing.h" + +#include "asm2wasm.h" + +using namespace cashew; +using namespace wasm; + +int main(int argc, const char *argv[]) { + bool opts = true; + bool imprecise = false; + + Options options("asm2wasm", "Translate asm.js files to .wast files"); + options + .add("--output", "-o", "Output file (stdout if not specified)", + Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["output"] = argument; + Colors::disable(); + }) + .add("--mapped-globals", "-m", "Mapped globals", Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["mapped globals"] = argument; + }) + .add("--total-memory", "-m", "Total memory size", Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["total memory"] = argument; + }) + .add("--no-opts", "-n", "Disable optimization passes", Options::Arguments::Zero, + [&opts](Options *o, const std::string &) { + opts = false; + }) + .add("--imprecise", "-i", "Imprecise optimizations", Options::Arguments::Zero, + [&imprecise](Options *o, const std::string &) { + imprecise = true; + }) + .add_positional("INFILE", Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["infile"] = argument; + }); + 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()); + if (totalMemory & ~Memory::kPageMask) { + std::cerr << "Error: total memory size " << totalMemory << + " is not a multiple of the 64k wasm page size\n"; + exit(EXIT_FAILURE); + } + + Asm2WasmPreProcessor pre; + auto input( + read_file<std::vector<char>>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release)); + char *start = pre.process(input.data()); + + if (options.debug) std::cerr << "parsing..." << std::endl; + cashew::Parser<Ref, DotZeroValueBuilder> builder; + Ref asmjs = builder.parseToplevel(start); + if (options.debug) { + std::cerr << "parsed:" << std::endl; + asmjs->stringify(std::cerr, true); + std::cerr << std::endl; + } + + if (options.debug) std::cerr << "wasming..." << std::endl; + Module wasm; + wasm.memory.initial = wasm.memory.max = totalMemory / Memory::kPageSize; + Asm2WasmBuilder asm2wasm(wasm, pre.memoryGrowth, options.debug, imprecise); + asm2wasm.processAsm(asmjs); + + if (opts) { + if (options.debug) std::cerr << "optimizing..." << std::endl; + asm2wasm.optimize(); + } + + if (options.debug) std::cerr << "printing..." << std::endl; + 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/tools/binaryen-shell.cpp b/src/tools/binaryen-shell.cpp new file mode 100644 index 000000000..360b576c8 --- /dev/null +++ b/src/tools/binaryen-shell.cpp @@ -0,0 +1,252 @@ +/* + * Copyright 2015 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// A WebAssembly shell, loads a .wast file (WebAssembly in S-Expression format) +// and executes it. This provides similar functionality as the reference +// interpreter, like assert_* calls, so it can run the spec test suite. +// + +#include <memory> + +#include "pass.h" +#include "shell-interface.h" +#include "support/command-line.h" +#include "support/file.h" +#include "wasm-interpreter.h" +#include "wasm-printing.h" +#include "wasm-s-parser.h" +#include "wasm-validator.h" + +using namespace cashew; +using namespace wasm; + +// +// An invocation into a module +// + +struct Invocation { + ModuleInstance* instance; + IString name; + ModuleInstance::LiteralList arguments; + + Invocation(Element& invoke, ModuleInstance* instance, SExpressionWasmBuilder& builder) : instance(instance) { + assert(invoke[0]->str() == INVOKE); + name = invoke[1]->str(); + for (size_t j = 2; j < invoke.size(); j++) { + Expression* argument = builder.parseExpression(*invoke[j]); + arguments.push_back(argument->dynCast<Const>()->value); + } + } + + Literal invoke() { + return instance->callExport(name, arguments); + } +}; + +static void verify_result(Literal a, Literal b) { + if (a == b) return; + // accept equal nans if equal in all bits + assert(a.type == b.type); + if (a.type == f32) { + assert(a.reinterpreti32() == b.reinterpreti32()); + } else if (a.type == f64) { + assert(a.reinterpreti64() == b.reinterpreti64()); + } else { + abort(); + } +} + +static void run_asserts(size_t* i, bool* checked, Module* wasm, + Element* root, + std::unique_ptr<SExpressionWasmBuilder>* builder, + Name entry) { + std::unique_ptr<ShellExternalInterface> interface; + std::unique_ptr<ModuleInstance> instance; + if (wasm) { + interface = make_unique<ShellExternalInterface>(); + instance = make_unique<ModuleInstance>(*wasm, interface.get()); + if (entry.is()) { + Function* function = wasm->getFunction(entry); + if (!function) { + std::cerr << "Unknown entry " << entry << std::endl; + } else { + ModuleInstance::LiteralList arguments; + for (WasmType param : function->params) { + arguments.push_back(Literal(param)); + } + try { + instance->callExport(entry, arguments); + } catch (ExitException&) { + } + } + } + } + while (*i < root->size()) { + Element& curr = *(*root)[*i]; + IString id = curr[0]->str(); + if (id == MODULE) break; + *checked = true; + Colors::red(std::cerr); + std::cerr << *i << '/' << (root->size() - 1); + Colors::green(std::cerr); + std::cerr << " CHECKING: "; + Colors::normal(std::cerr); + std::cerr << curr << '\n'; + if (id == ASSERT_INVALID) { + // a module invalidity test + Module wasm; + bool invalid = false; + std::unique_ptr<SExpressionWasmBuilder> builder; + try { + builder = std::unique_ptr<SExpressionWasmBuilder>( + new SExpressionWasmBuilder(wasm, *curr[1]) + ); + } catch (const ParseException&) { + invalid = true; + } + if (!invalid) { + // maybe parsed ok, but otherwise incorrect + invalid = !WasmValidator().validate(wasm); + } + assert(invalid); + } else if (id == INVOKE) { + assert(wasm); + Invocation invocation(curr, instance.get(), *builder->get()); + invocation.invoke(); + } else { + // an invoke test + assert(wasm); + bool trapped = false; + Literal result; + try { + Invocation invocation(*curr[1], instance.get(), *builder->get()); + result = invocation.invoke(); + } catch (const TrapException&) { + trapped = true; + } + if (id == ASSERT_RETURN) { + assert(!trapped); + if (curr.size() >= 3) { + Literal expected = builder->get() + ->parseExpression(*curr[2]) + ->dynCast<Const>() + ->value; + std::cerr << "seen " << result << ", expected " << expected << '\n'; + verify_result(expected, result); + } else { + Literal expected; + std::cerr << "seen " << result << ", expected " << expected << '\n'; + verify_result(expected, result); + } + } + if (id == ASSERT_TRAP) assert(trapped); + } + *i += 1; + } +} + +// +// main +// + +int main(int argc, const char* argv[]) { + Name entry; + std::vector<std::string> passes; + + Options options("binaryen-shell", "Execute .wast files"); + options + .add("--output", "-o", "Output file (stdout if not specified)", + Options::Arguments::One, + [](Options* o, const std::string& argument) { + o->extra["output"] = argument; + Colors::disable(); + }) + .add( + "--entry", "-e", "call the entry point after parsing the module", + Options::Arguments::One, + [&entry](Options*, const std::string& argument) { entry = argument; }) + .add("", "-O", "execute default optimization passes", + Options::Arguments::Zero, + [&passes](Options*, const std::string&) { + passes.push_back("O"); + }) + .add_positional("INFILE", Options::Arguments::One, + [](Options* o, const std::string& argument) { + o->extra["infile"] = argument; + }); + for (const auto& p : PassRegistry::get()->getRegisteredNames()) { + options.add( + std::string("--") + p, "", PassRegistry::get()->getPassDescription(p), + Options::Arguments::Zero, + [&passes, p](Options*, const std::string&) { passes.push_back(p); }); + } + options.parse(argc, argv); + + auto input(read_file<std::vector<char>>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release)); + + if (options.debug) std::cerr << "parsing text to s-expressions...\n"; + SExpressionParser parser(input.data()); + Element& root = *parser.root; + + // A .wast may have multiple modules, with some asserts after them + bool checked = false; + size_t i = 0; + while (i < root.size()) { + Element& curr = *root[i]; + IString id = curr[0]->str(); + if (id == MODULE) { + if (options.debug) std::cerr << "parsing s-expressions to wasm...\n"; + Module wasm; + std::unique_ptr<SExpressionWasmBuilder> builder; + try { + builder = make_unique<SExpressionWasmBuilder>(wasm, *root[i]); + } catch (ParseException& p) { + p.dump(std::cerr); + abort(); + } + i++; + assert(WasmValidator().validate(wasm)); + + MixedArena moreModuleAllocations; + + if (passes.size() > 0) { + if (options.debug) std::cerr << "running passes...\n"; + PassRunner passRunner(&wasm); + if (options.debug) passRunner.setDebug(true); + for (auto& passName : passes) { + if (passName == "O") { + passRunner.addDefaultOptimizationPasses(); + } else { + passRunner.add(passName); + } + } + passRunner.run(); + } + + run_asserts(&i, &checked, &wasm, &root, &builder, entry); + } else { + run_asserts(&i, &checked, nullptr, &root, nullptr, entry); + } + } + + if (checked) { + Colors::green(std::cerr); + Colors::bold(std::cerr); + std::cerr << "all checks passed.\n"; + Colors::normal(std::cerr); + } +} diff --git a/src/tools/s2wasm.cpp b/src/tools/s2wasm.cpp new file mode 100644 index 000000000..9688f6696 --- /dev/null +++ b/src/tools/s2wasm.cpp @@ -0,0 +1,140 @@ +/* + * Copyright 2015 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// wasm2asm console tool +// + +#include "support/colors.h" +#include "support/command-line.h" +#include "support/file.h" +#include "s2wasm.h" +#include "wasm-linker.h" +#include "wasm-printing.h" + +using namespace cashew; +using namespace wasm; + +int main(int argc, const char *argv[]) { + bool ignoreUnknownSymbols = false; + bool generateEmscriptenGlue = false; + std::string startFunction; + std::vector<std::string> archiveLibraries; + Options options("s2wasm", "Link .s file into .wast"); + options + .add("--output", "-o", "Output file (stdout if not specified)", + Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["output"] = argument; + Colors::disable(); + }) + .add("--ignore-unknown", "", "Ignore unknown symbols", + Options::Arguments::Zero, + [&ignoreUnknownSymbols](Options *, const std::string &) { + ignoreUnknownSymbols = true; + }) + .add("--start", "", "Generate the start method (default: main)", + Options::Arguments::Optional, + [&startFunction](Options *, const std::string &argument) { + startFunction = argument.size() ? argument : "main"; + }) + .add("--global-base", "-g", "Where to start to place globals", + Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["global-base"] = argument; + }) + .add("--allocate-stack", "-s", "Size of the user stack in linear memory", + Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["stack-allocation"] = argument; + }) + .add("--initial-memory", "-i", "Initial size of the linear memory", + Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["initial-memory"] = argument; + }) + .add("--max-memory", "-m", "Maximum size of the linear memory", + Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["max-memory"] = argument; + }) + .add("--emscripten-glue", "-e", "Generate emscripten glue", + Options::Arguments::Zero, + [&generateEmscriptenGlue](Options *, const std::string &) { + generateEmscriptenGlue = true; + }) + .add("--library", "-l", "Add archive library", + Options::Arguments::N, + [&archiveLibraries](Options *o, const std::string &argument) { + archiveLibraries.push_back(argument); + }) + .add_positional("INFILE", Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["infile"] = argument; + }); + options.parse(argc, argv); + + auto debugFlag = options.debug ? Flags::Debug : Flags::Release; + auto input(read_file<std::string>(options.extra["infile"], Flags::Text, debugFlag)); + + if (options.debug) std::cerr << "Parsing and wasming..." << std::endl; + uint64_t globalBase = options.extra.find("global-base") != options.extra.end() + ? std::stoull(options.extra["global-base"]) + : 0; + uint64_t stackAllocation = + options.extra.find("stack-allocation") != options.extra.end() + ? std::stoull(options.extra["stack-allocation"]) + : 0; + uint64_t initialMem = + options.extra.find("initial-memory") != options.extra.end() + ? std::stoull(options.extra["initial-memory"]) + : 0; + uint64_t maxMem = + options.extra.find("max-memory") != options.extra.end() + ? std::stoull(options.extra["max-memory"]) + : 0; + if (options.debug) std::cerr << "Global base " << globalBase << '\n'; + + Linker linker(globalBase, stackAllocation, initialMem, maxMem, + ignoreUnknownSymbols, startFunction, options.debug); + + S2WasmBuilder mainbuilder(input.c_str(), options.debug); + linker.linkObject(mainbuilder); + + for (const auto& m : archiveLibraries) { + auto archiveFile(read_file<std::vector<char>>(m, Flags::Binary, debugFlag)); + bool error; + Archive lib(archiveFile, error); + if (error) Fatal() << "Error opening archive " << m << "\n"; + linker.linkArchive(lib); + } + + linker.layout(); + + std::stringstream meta; + if (generateEmscriptenGlue) { + if (options.debug) std::cerr << "Emscripten gluing..." << std::endl; + // dyncall thunks + linker.emscriptenGlue(meta); + } + + if (options.debug) std::cerr << "Printing..." << std::endl; + Output output(options.extra["output"], Flags::Text, options.debug ? Flags::Debug : Flags::Release); + WasmPrinter::printModule(&linker.getOutput().wasm, output.getStream()); + output << meta.str() << std::endl; + + if (options.debug) std::cerr << "Done." << std::endl; +} diff --git a/src/tools/wasm-as.cpp b/src/tools/wasm-as.cpp new file mode 100644 index 000000000..40839ea55 --- /dev/null +++ b/src/tools/wasm-as.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// wasm2asm console tool +// + +#include "support/colors.h" +#include "support/command-line.h" +#include "support/file.h" +#include "wasm-binary.h" +#include "wasm-s-parser.h" + +using namespace cashew; +using namespace wasm; + +int main(int argc, const char *argv[]) { + Options options("wasm-as", "Assemble a .wast (WebAssembly text format) into a .wasm (WebAssembly binary format)"); + options.add("--output", "-o", "Output file (stdout if not specified)", + Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["output"] = argument; + Colors::disable(); + }) + .add_positional("INFILE", Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["infile"] = argument; + }); + options.parse(argc, argv); + + auto input(read_file<std::string>(options.extra["infile"], Flags::Text, options.debug ? Flags::Debug : Flags::Release)); + + Module wasm; + + try{ + if (options.debug) std::cerr << "s-parsing..." << std::endl; + SExpressionParser parser(const_cast<char*>(input.c_str())); + Element& root = *parser.root; + if (options.debug) std::cerr << "w-parsing..." << std::endl; + SExpressionWasmBuilder builder(wasm, *root[0]); + } catch (ParseException& p) { + p.dump(std::cerr); + Fatal() << "error in parsing wasm binary"; + } + + if (options.debug) std::cerr << "binarification..." << std::endl; + BufferWithRandomAccess buffer(options.debug); + WasmBinaryWriter writer(&wasm, buffer, options.debug); + writer.write(); + + if (options.debug) std::cerr << "writing to output..." << std::endl; + Output output(options.extra["output"], Flags::Binary, options.debug ? Flags::Debug : Flags::Release); + buffer.writeTo(output); + + if (options.debug) std::cerr << "Done." << std::endl; +} diff --git a/src/tools/wasm-dis.cpp b/src/tools/wasm-dis.cpp new file mode 100644 index 000000000..93c286913 --- /dev/null +++ b/src/tools/wasm-dis.cpp @@ -0,0 +1,62 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// wasm2asm console tool +// + +#include "support/colors.h" +#include "support/command-line.h" +#include "support/file.h" +#include "wasm-binary.h" +#include "wasm-printing.h" + +using namespace cashew; +using namespace wasm; + +int main(int argc, const char *argv[]) { + Options options("wasm-dis", "Un-assemble a .wasm (WebAssembly binary format) into a .wast (WebAssembly text format)"); + options.add("--output", "-o", "Output file (stdout if not specified)", + Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["output"] = argument; + Colors::disable(); + }) + .add_positional("INFILE", Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["infile"] = argument; + }); + options.parse(argc, argv); + + auto input(read_file<std::vector<char>>(options.extra["infile"], Flags::Binary, options.debug ? Flags::Debug : Flags::Release)); + + if (options.debug) std::cerr << "parsing binary..." << std::endl; + Module wasm; + try { + WasmBinaryBuilder parser(wasm, input, options.debug); + parser.read(); + } catch (ParseException& p) { + p.dump(std::cerr); + Fatal() << "error in parsing wasm binary"; + } + + if (options.debug) std::cerr << "Printing..." << std::endl; + Output output(options.extra["output"], Flags::Text, options.debug ? Flags::Debug : Flags::Release); + WasmPrinter::printModule(&wasm, output.getStream()); + output << '\n'; + + if (options.debug) std::cerr << "Done." << std::endl; +} |