diff options
-rwxr-xr-x | auto_update_tests.py | 2 | ||||
-rwxr-xr-x | check.py | 30 | ||||
-rw-r--r-- | scripts/test/shared.py | 22 | ||||
-rw-r--r-- | src/tools/asm2wasm.cpp | 21 | ||||
-rw-r--r-- | src/tools/wasm-opt.cpp | 31 | ||||
-rw-r--r-- | src/wasm-io.h | 68 | ||||
-rw-r--r-- | src/wasm/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/wasm/wasm-io.cpp | 86 |
8 files changed, 231 insertions, 30 deletions
diff --git a/auto_update_tests.py b/auto_update_tests.py index 294bad750..7a14f6521 100755 --- a/auto_update_tests.py +++ b/auto_update_tests.py @@ -92,7 +92,7 @@ for t in sorted(os.listdir(os.path.join('test', 'passes'))): print '\n[ checking wasm-opt -o notation... ]\n' wast = os.path.join('test', 'hello_world.wast') -cmd = [os.path.join('bin', 'wasm-opt'), wast, '-o', 'a.wast'] +cmd = [os.path.join('bin', 'wasm-opt'), wast, '-o', 'a.wast', '-S'] run_command(cmd) open(wast, 'w').write(open('a.wast').read()) @@ -57,10 +57,20 @@ print '\n[ checking wasm-opt -o notation... ]\n' wast = os.path.join(options.binaryen_test, 'hello_world.wast') delete_from_orbit('a.wast') -cmd = WASM_OPT + [wast, '-o', 'a.wast'] +cmd = WASM_OPT + [wast, '-o', 'a.wast', '-S'] run_command(cmd) fail_if_not_identical(open('a.wast').read(), open(wast).read()) +print '\n[ checking wasm-opt binary reading/writing... ]\n' + +shutil.copyfile(os.path.join(options.binaryen_test, 'hello_world.wast'), 'a.wast') +delete_from_orbit('a.wasm') +delete_from_orbit('b.wast') +run_command(WASM_OPT + ['a.wast', '-o', 'a.wasm']) +assert open('a.wasm', 'rb').read()[0] == '\0', 'we emit binary by default' +run_command(WASM_OPT + ['a.wasm', '-o', 'b.wast', '-S']) +assert open('b.wast', 'rb').read()[0] != '\0', 'we emit text with -S' + print '\n[ checking wasm-opt passes... ]\n' for t in sorted(os.listdir(os.path.join(options.binaryen_test, 'passes'))): @@ -141,6 +151,16 @@ for asm in tests: fail_with_error('wasm interpreter error: ' + err) # failed to pretty-print fail_with_error('wasm interpreter error') +print '\n[ checking asm2wasm binary reading/writing... ]\n' + +asmjs = os.path.join(options.binaryen_test, 'hello_world.asm.js') +delete_from_orbit('a.wasm') +delete_from_orbit('b.wast') +run_command(ASM2WASM + [asmjs, '-o', 'a.wasm']) +assert open('a.wasm', 'rb').read()[0] == '\0', 'we emit binary by default' +run_command(ASM2WASM + [asmjs, '-o', 'b.wast', '-S']) +assert open('b.wast', 'rb').read()[0] != '\0', 'we emit text with -S' + print '\n[ checking wasm-opt parsing & printing... ]\n' for t in sorted(os.listdir(os.path.join(options.binaryen_test, 'print'))): @@ -478,7 +498,7 @@ if EMCC: asm = asm.replace("'almost asm'", '"use asm"; var not_in_asm = [].length + (true || { x: 5 }.x);') with open('a.wasm.asm.js', 'w') as o: o.write(asm) if method.startswith('interpret-asm2wasm'): - os.unlink('a.wasm.wast') # we should not need the .wast + delete_from_orbit('a.wasm.wast') # we should not need the .wast if not success: break_cashew() # we need cashew elif method.startswith('interpret-s-expr'): @@ -486,12 +506,12 @@ if EMCC: if not success: os.unlink('a.wasm.wast') elif method.startswith('asmjs'): - os.unlink('a.wasm.wast') # we should not need the .wast + delete_from_orbit('a.wasm.wast') # we should not need the .wast break_cashew() # we don't use cashew, so ok to break it if not success: os.unlink('a.wasm.js') elif method.startswith('interpret-binary'): - os.unlink('a.wasm.wast') # we should not need the .wast + delete_from_orbit('a.wasm.wast') # we should not need the .wast os.unlink('a.wasm.asm.js') # we should not need the .asm.js if not success: os.unlink('a.wasm.wasm') @@ -551,7 +571,7 @@ if EMCC: execute() - if method in ['interpret-asm2wasm', 'interpret-s-expr']: + if method in ['interpret-s-expr']: # binary and back shutil.copyfile('a.wasm.wast', 'a.wasm.original.wast') recreated = binary_format_check('a.wasm.wast', verify_final_result=False) diff --git a/scripts/test/shared.py b/scripts/test/shared.py index 5aff20091..d899cc1de 100644 --- a/scripts/test/shared.py +++ b/scripts/test/shared.py @@ -389,18 +389,18 @@ def minify_check(wast, verify_final_result=True): print ' ', ' '.join(cmd) subprocess.check_call( WASM_OPT + [wast, '--print-minified'], - stdout=open('a.wasm', 'w'), stderr=subprocess.PIPE) - assert os.path.exists('a.wasm') + stdout=open('a.wast', 'w'), stderr=subprocess.PIPE) + assert os.path.exists('a.wast') subprocess.check_call( - WASM_OPT + ['a.wasm', '--print-minified'], - stdout=open('b.wasm', 'w'), stderr=subprocess.PIPE) - assert os.path.exists('b.wasm') + WASM_OPT + ['a.wast', '--print-minified'], + stdout=open('b.wast', 'w'), stderr=subprocess.PIPE) + assert os.path.exists('b.wast') if verify_final_result: - expected = open('a.wasm').read() - actual = open('b.wasm').read() + expected = open('a.wast').read() + actual = open('b.wast').read() if actual != expected: fail(actual, expected) - if os.path.exists('a.wasm'): - os.unlink('a.wasm') - if os.path.exists('b.wasm'): - os.unlink('b.wasm') + if os.path.exists('a.wast'): + os.unlink('a.wast') + if os.path.exists('b.wast'): + os.unlink('b.wast') diff --git a/src/tools/asm2wasm.cpp b/src/tools/asm2wasm.cpp index 9ba6062ea..c880e7459 100644 --- a/src/tools/asm2wasm.cpp +++ b/src/tools/asm2wasm.cpp @@ -23,6 +23,7 @@ #include "support/file.h" #include "wasm-builder.h" #include "wasm-printing.h" +#include "wasm-io.h" #include "asm2wasm.h" @@ -34,6 +35,9 @@ int main(int argc, const char *argv[]) { bool runOptimizationPasses = false; bool imprecise = false; bool wasmOnly = false; + bool debugInfo = false; + std::string symbolMap; + bool emitBinary = true; Options options("asm2wasm", "Translate asm.js files to .wast files"); options @@ -80,6 +84,15 @@ int main(int argc, const char *argv[]) { [&wasmOnly](Options *o, const std::string &) { wasmOnly = true; }) + .add("--debuginfo", "-g", "Emit names section and debug info", + Options::Arguments::Zero, + [&](Options *o, const std::string &arguments) { debugInfo = true; }) + .add("--symbolmap", "-s", "Emit a symbol map (indexes => names)", + Options::Arguments::One, + [&](Options *o, const std::string &argument) { symbolMap = argument; }) + .add("--emit-text", "-S", "Emit text instead of binary for the output file", + Options::Arguments::Zero, + [&](Options *o, const std::string &argument) { emitBinary = false; }) .add_positional("INFILE", Options::Arguments::One, [](Options *o, const std::string &argument) { o->extra["infile"] = argument; @@ -153,8 +166,12 @@ int main(int argc, const char *argv[]) { } 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()); + ModuleWriter writer; + writer.setDebug(options.debug); + writer.setDebugInfo(debugInfo); + writer.setSymbolMap(symbolMap); + writer.setBinary(emitBinary); + writer.write(wasm, options.extra["output"]); if (options.debug) std::cerr << "done." << std::endl; } diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index 1da038b8e..93d8f5baa 100644 --- a/src/tools/wasm-opt.cpp +++ b/src/tools/wasm-opt.cpp @@ -27,6 +27,7 @@ #include "wasm-printing.h" #include "wasm-s-parser.h" #include "wasm-validator.h" +#include "wasm-io.h" using namespace wasm; @@ -39,6 +40,7 @@ int main(int argc, const char* argv[]) { std::vector<std::string> passes; bool runOptimizationPasses = false; PassOptions passOptions; + bool emitBinary = true; Options options("wasm-opt", "Optimize .wast files"); options @@ -49,6 +51,9 @@ int main(int argc, const char* argv[]) { Colors::disable(); }) #include "optimization-options.h" + .add("--emit-text", "-S", "Emit text instead of binary for the output file", + Options::Arguments::Zero, + [&](Options *o, const std::string &argument) { emitBinary = false; }) .add_positional("INFILE", Options::Arguments::One, [](Options* o, const std::string& argument) { o->extra["infile"] = argument; @@ -71,15 +76,17 @@ int main(int argc, const char* argv[]) { 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 input"; + { + if (options.debug) std::cerr << "reading...\n"; + ModuleReader reader; + reader.setDebug(options.debug); + + try { + reader.read(options.extra["infile"], wasm); + } catch (ParseException& p) { + p.dump(std::cerr); + Fatal() << "error in parsing input"; + } } if (!WasmValidator().validate(wasm)) { @@ -103,7 +110,9 @@ int main(int argc, const char* argv[]) { if (options.extra.count("output") > 0) { if (options.debug) std::cerr << "writing..." << std::endl; - Output output(options.extra["output"], Flags::Text, options.debug ? Flags::Debug : Flags::Release); - WasmPrinter::printModule(&wasm, output.getStream()); + ModuleWriter writer; + writer.setDebug(options.debug); + writer.setBinary(emitBinary); + writer.write(wasm, options.extra["output"]); } } diff --git a/src/wasm-io.h b/src/wasm-io.h new file mode 100644 index 000000000..7d7358f9c --- /dev/null +++ b/src/wasm-io.h @@ -0,0 +1,68 @@ +/* + * Copyright 2017 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. + */ + +// +// Abstracts reading and writing, supporting both text and binary. +// + +#ifndef wasm_wasm_io_h +#define wasm_wasm_io_h + +#include "wasm.h" + +namespace wasm { + +class ModuleIO { +protected: + bool debug = false; + +public: + void setDebug(bool debug_) { debug = debug_; } +}; + +class ModuleReader : public ModuleIO { +public: + // read text + void readText(std::string filename, Module& wasm); + // read binary + void readBinary(std::string filename, Module& wasm); + // read text or binary, checking the contents for what it is + void read(std::string filename, Module& wasm); +}; + +class ModuleWriter : public ModuleIO { + bool binary = true; + bool debugInfo = false; + std::string symbolMap; + +public: + void setBinary(bool binary_) { binary = binary_; } + void setDebugInfo(bool debugInfo_) { debugInfo = debugInfo_; } + void setSymbolMap(std::string symbolMap_) { symbolMap = symbolMap_; } + + // write text + void writeText(Module& wasm, std::string filename); + // write binary + void writeBinary(Module& wasm, std::string filename); + // write text or binary, defaulting to binary unless setBinary(false), + // and unless there is no output file (in which case we write text + // to stdout). + void write(Module& wasm, std::string filename); +}; + +} + +#endif // wasm_wasm_io_h diff --git a/src/wasm/CMakeLists.txt b/src/wasm/CMakeLists.txt index 65b626c25..e1b1aac33 100644 --- a/src/wasm/CMakeLists.txt +++ b/src/wasm/CMakeLists.txt @@ -1,6 +1,7 @@ SET(wasm_SOURCES wasm.cpp wasm-binary.cpp + wasm-io.cpp wasm-s-parser.cpp ) ADD_LIBRARY(wasm STATIC ${wasm_SOURCES}) diff --git a/src/wasm/wasm-io.cpp b/src/wasm/wasm-io.cpp new file mode 100644 index 000000000..2380f7447 --- /dev/null +++ b/src/wasm/wasm-io.cpp @@ -0,0 +1,86 @@ +/* + * Copyright 2017 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. + */ + +// +// Abstracts reading and writing, supporting both text and binary +// depending on the suffix. +// +// When the suffix is unclear, writing defaults to text (this +// allows odd suffixes, which we use in the test suite), while +// reading will check the magic number and default to text if not +// binary. +// + +#include "wasm-io.h" +#include "wasm-s-parser.h" +#include "wasm-binary.h" +#include "support/file.h" + +namespace wasm { + +void ModuleReader::readText(std::string filename, Module& wasm) { + if (debug) std::cerr << "reading text from " << filename << "\n"; + auto input(read_file<std::string>(filename, Flags::Text, debug ? Flags::Debug : Flags::Release)); + SExpressionParser parser(const_cast<char*>(input.c_str())); + Element& root = *parser.root; + SExpressionWasmBuilder builder(wasm, *root[0]); +} + +void ModuleReader::readBinary(std::string filename, Module& wasm) { + if (debug) std::cerr << "reading binary from " << filename << "\n"; + auto input(read_file<std::vector<char>>(filename, Flags::Binary, debug ? Flags::Debug : Flags::Release)); + WasmBinaryBuilder parser(wasm, input, debug); + parser.read(); +} + +void ModuleReader::read(std::string filename, Module& wasm) { + // see if this is a binary + auto contents = read_file<std::vector<char>>(filename, Flags::Binary, debug ? Flags::Debug : Flags::Release); + if (contents.size() >= 4 && contents[0] == '\0' && contents[1] == 'a' && contents[2] == 's' && contents[3] == 'm') { + readBinary(filename, wasm); + } else { + // default to text + readText(filename, wasm); + } +} + +void ModuleWriter::writeText(Module& wasm, std::string filename) { + if (debug) std::cerr << "writing text to " << filename << "\n"; + Output output(filename, Flags::Text, debug ? Flags::Debug : Flags::Release); + WasmPrinter::printModule(&wasm, output.getStream()); +} + +void ModuleWriter::writeBinary(Module& wasm, std::string filename) { + if (debug) std::cerr << "writing binary to " << filename << "\n"; + BufferWithRandomAccess buffer(debug); + WasmBinaryWriter writer(&wasm, buffer, debug); + writer.setDebugInfo(debugInfo); + if (symbolMap.size() > 0) writer.setSymbolMap(symbolMap); + writer.write(); + Output output(filename, Flags::Binary, debug ? Flags::Debug : Flags::Release); + buffer.writeTo(output); +} + +void ModuleWriter::write(Module& wasm, std::string filename) { + if (binary && filename.size() > 0) { + writeBinary(wasm, filename); + } else { + writeText(wasm, filename); + } +} + +} + |