| /* |
| * 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 <exception> |
| |
| #include "ir/trapping.h" |
| #include "optimization-options.h" |
| #include "support/colors.h" |
| #include "support/command-line.h" |
| #include "support/file.h" |
| #include "wasm-builder.h" |
| #include "wasm-io.h" |
| #include "wasm-printing.h" |
| #include "wasm-validator.h" |
| |
| #include "asm2wasm.h" |
| |
| using namespace cashew; |
| using namespace wasm; |
| |
| int main(int argc, const char* argv[]) { |
| bool legalizeJavaScriptFFI = true; |
| TrapMode trapMode = TrapMode::JS; |
| bool wasmOnly = false; |
| std::string sourceMapFilename; |
| std::string sourceMapUrl; |
| std::string symbolMap; |
| bool emitBinary = true; |
| |
| OptimizationOptions 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::setEnabled(false); |
| }) |
| .add( |
| "--mapped-globals", |
| "-n", |
| "Mapped globals", |
| Options::Arguments::One, |
| [](Options* o, const std::string& 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("--mem-init", |
| "-t", |
| "Import a memory initialization file into the output module", |
| Options::Arguments::One, |
| [](Options* o, const std::string& argument) { |
| o->extra["mem init"] = argument; |
| }) |
| .add("--mem-base", |
| "-mb", |
| "Set the location to write the memory initialization (--mem-init) " |
| "file (GLOBAL_BASE in emscripten). If not provided, the __memory_base " |
| "global import is used.", |
| Options::Arguments::One, |
| [](Options* o, const std::string& argument) { |
| o->extra["mem base"] = argument; |
| }) |
| .add("--mem-max", |
| "-mm", |
| "Set the maximum size of memory in the wasm module (in bytes). -1 " |
| "means no limit. Without this, TOTAL_MEMORY is used (as it is used " |
| "for the initial value), or if memory growth is enabled, no limit is " |
| "set. This overrides both of those.", |
| Options::Arguments::One, |
| [](Options* o, const std::string& argument) { |
| o->extra["mem max"] = argument; |
| }) |
| .add("--total-memory", |
| "-m", |
| "Total memory size", |
| Options::Arguments::One, |
| [](Options* o, const std::string& argument) { |
| o->extra["total memory"] = argument; |
| }) |
| .add("--table-max", |
| "-tM", |
| "Set the maximum size of the table. Without this, it is set depending " |
| "on how many functions are in the module. -1 means no limit", |
| Options::Arguments::One, |
| [](Options* o, const std::string& argument) { |
| o->extra["table max"] = argument; |
| }) |
| .add("--no-opts", |
| "-n", |
| "Disable optimization passes (deprecated)", |
| Options::Arguments::Zero, |
| [](Options* o, const std::string&) { |
| std::cerr << "--no-opts is deprecated (use -O0, etc.)\n"; |
| }) |
| .add("--trap-mode", |
| "", |
| "Strategy for handling potentially trapping instructions. Valid " |
| "values are \"allow\", \"js\", and \"clamp\"", |
| Options::Arguments::One, |
| [&trapMode](Options* o, const std::string& argument) { |
| try { |
| trapMode = trapModeFromString(argument); |
| } catch (std::invalid_argument& e) { |
| std::cerr << "Error: " << e.what() << "\n"; |
| exit(EXIT_FAILURE); |
| } |
| }) |
| .add("--wasm-only", |
| "-w", |
| "Input is in WebAssembly-only format, and not actually valid asm.js", |
| Options::Arguments::Zero, |
| [&wasmOnly](Options* o, const std::string&) { wasmOnly = true; }) |
| .add("--no-legalize-javascript-ffi", |
| "-nj", |
| "Do not fully legalize (i64->i32, f32->f64) the imports and exports " |
| "for interfacing with JS", |
| Options::Arguments::Zero, |
| [&legalizeJavaScriptFFI](Options* o, const std::string&) { |
| legalizeJavaScriptFFI = false; |
| }) |
| .add("--source-map", |
| "-sm", |
| "Emit source map (if using binary output) to the specified file", |
| Options::Arguments::One, |
| [&sourceMapFilename](Options* o, const std::string& argument) { |
| sourceMapFilename = argument; |
| }) |
| .add("--source-map-url", |
| "-su", |
| "Use specified string as source map URL", |
| Options::Arguments::One, |
| [&sourceMapUrl](Options* o, const std::string& argument) { |
| sourceMapUrl = argument; |
| }) |
| .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; |
| }); |
| options.parse(argc, argv); |
| |
| // finalize arguments |
| if (options.extra["output"].size() == 0) { |
| // when no output file is specified, we emit text to stdout |
| emitBinary = false; |
| } |
| |
| if (options.runningDefaultOptimizationPasses()) { |
| if (options.passes.size() > 1) { |
| Fatal() << "asm2wasm can only run default optimization passes (-O, -Ox, " |
| "etc.), and not specific additional passes"; |
| } |
| } |
| |
| const auto& tm_it = options.extra.find("total memory"); |
| size_t totalMemory = tm_it == options.extra.end() |
| ? 16 * 1024 * 1024 |
| : atoll(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; |
| // wasm binaries can contain a names section, but not full debug info -- |
| // debug info is disabled if a map file is not specified with wasm binary |
| pre.debugInfo = |
| options.passOptions.debugInfo && (!emitBinary || sourceMapFilename.size()); |
| auto input( |
| read_file<std::vector<char>>(options.extra["infile"], Flags::Text)); |
| 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 << "wasming..." << std::endl; |
| } |
| Module wasm; |
| |
| // set up memory |
| wasm.memory.initial = wasm.memory.max = totalMemory / Memory::kPageSize; |
| |
| // import mem init file, if provided (do this before compiling the module, |
| // since the optimizer should see the memory segments) |
| const auto& memInit = options.extra.find("mem init"); |
| if (memInit != options.extra.end()) { |
| auto filename = memInit->second.c_str(); |
| auto data(read_file<std::vector<char>>(filename, Flags::Binary)); |
| // create the memory segment |
| Expression* init; |
| const auto& memBase = options.extra.find("mem base"); |
| if (memBase == options.extra.end()) { |
| init = Builder(wasm).makeGlobalGet(MEMORY_BASE, Type::i32); |
| } else { |
| init = Builder(wasm).makeConst( |
| Literal(int32_t(atoi(memBase->second.c_str())))); |
| } |
| wasm.memory.segments.emplace_back(init, data); |
| } |
| |
| // set up the module's features, needed by optimization and validation passes |
| options.applyFeatures(wasm); |
| |
| // compile the code |
| Asm2WasmBuilder asm2wasm(wasm, |
| pre, |
| options.debug, |
| trapMode, |
| options.passOptions, |
| legalizeJavaScriptFFI, |
| options.runningDefaultOptimizationPasses(), |
| wasmOnly); |
| asm2wasm.processAsm(asmjs); |
| |
| // Set the max memory size, if requested |
| const auto& memMax = options.extra.find("mem max"); |
| if (memMax != options.extra.end()) { |
| uint64_t max = strtoull(memMax->second.c_str(), nullptr, 10); |
| if (max != uint64_t(-1)) { |
| wasm.memory.max = max / Memory::kPageSize; |
| } else { |
| wasm.memory.max = Memory::kUnlimitedSize; |
| } |
| } |
| // Set the table sizes, if requested |
| const auto& tableMax = options.extra.find("table max"); |
| if (tableMax != options.extra.end()) { |
| int max = atoi(tableMax->second.c_str()); |
| if (max >= 0) { |
| wasm.table.max = max; |
| } else { |
| wasm.table.max = Table::kUnlimitedSize; |
| } |
| } |
| |
| if (options.passOptions.validate) { |
| if (!WasmValidator().validate(wasm)) { |
| WasmPrinter::printModule(&wasm); |
| Fatal() << "error in validating output"; |
| } |
| } |
| |
| if (options.debug) { |
| std::cerr << "emitting..." << std::endl; |
| } |
| ModuleWriter writer; |
| writer.setDebugInfo(options.passOptions.debugInfo); |
| writer.setSymbolMap(symbolMap); |
| writer.setBinary(emitBinary); |
| if (emitBinary) { |
| writer.setSourceMapFilename(sourceMapFilename); |
| writer.setSourceMapUrl(sourceMapUrl); |
| } |
| writer.write(wasm, options.extra["output"]); |
| |
| if (options.debug) { |
| std::cerr << "done." << std::endl; |
| } |
| } |