blob: c880e74599737987f7b408f9b56f0149cefd8742 [file] [log] [blame]
/*
* 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-builder.h"
#include "wasm-printing.h"
#include "wasm-io.h"
#include "asm2wasm.h"
using namespace cashew;
using namespace wasm;
int main(int argc, const char *argv[]) {
PassOptions passOptions;
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
.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", "-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 memoryBase 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;
})
#include "optimization-options.h"
.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("--imprecise", "-i", "Imprecise optimizations", Options::Arguments::Zero,
[&imprecise](Options *o, const std::string &) {
imprecise = true;
})
.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("--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;
});
options.parse(argc, argv);
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 << "wasming..." << std::endl;
Module wasm;
wasm.memory.initial = wasm.memory.max = totalMemory / Memory::kPageSize;
Asm2WasmBuilder asm2wasm(wasm, pre.memoryGrowth, options.debug, imprecise, passOptions, runOptimizationPasses, wasmOnly);
asm2wasm.processAsm(asmjs);
// import mem init file, if provided
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, options.debug ? Flags::Debug : Flags::Release));
// create the memory segment
Expression* init;
const auto &memBase = options.extra.find("mem base");
if (memBase == options.extra.end()) {
init = Builder(wasm).makeGetGlobal(Name("memoryBase"), i32);
} else {
init = Builder(wasm).makeConst(Literal(int32_t(atoi(memBase->second.c_str()))));
}
wasm.memory.segments.emplace_back(init, data);
if (runOptimizationPasses) {
PassRunner runner(&wasm);
runner.add("memory-packing");
runner.run();
}
}
// Set the max memory size, if requested
const auto &memMax = options.extra.find("mem max");
if (memMax != options.extra.end()) {
int max = atoi(memMax->second.c_str());
if (max >= 0) {
wasm.memory.max = max / Memory::kPageSize;
} else {
wasm.memory.max = Memory::kMaxSize;
}
}
// 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::kMaxSize;
}
}
if (options.debug) std::cerr << "printing..." << std::endl;
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;
}