diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/s2wasm-main.cpp | 21 | ||||
-rw-r--r-- | src/s2wasm.h | 63 |
2 files changed, 75 insertions, 9 deletions
diff --git a/src/s2wasm-main.cpp b/src/s2wasm-main.cpp index d7a18f547..752494aac 100644 --- a/src/s2wasm-main.cpp +++ b/src/s2wasm-main.cpp @@ -58,6 +58,16 @@ int main(int argc, const char *argv[]) { [](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_positional("INFILE", Options::Arguments::One, [](Options *o, const std::string &argument) { o->extra["infile"] = argument; @@ -75,9 +85,18 @@ int main(int argc, const char *argv[]) { options.extra.find("stack-allocation") != options.extra.end() ? std::stoull(options.extra["stack-allocation"]) : 0; + size_t initialMem = + options.extra.find("initial-memory") != options.extra.end() + ? std::stoull(options.extra["initial-memory"]) + : 0; + size_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'; S2WasmBuilder s2wasm(wasm, input.c_str(), options.debug, globalBase, - stackAllocation, ignoreUnknownSymbols, startFunction); + stackAllocation, initialMem, maxMem, ignoreUnknownSymbols, + startFunction); if (options.debug) std::cerr << "Emscripten gluing..." << std::endl; std::stringstream meta; diff --git a/src/s2wasm.h b/src/s2wasm.h index 6725e305b..87c0c2881 100644 --- a/src/s2wasm.h +++ b/src/s2wasm.h @@ -49,6 +49,7 @@ class S2WasmBuilder { public: S2WasmBuilder(AllocatingModule& wasm, const char* input, bool debug, size_t globalBase, size_t stackAllocation, + size_t userInitialMemory, size_t userMaxMemory, bool ignoreUnknownSymbols, Name startFunction) : wasm(wasm), allocator(wasm.allocator), @@ -57,7 +58,19 @@ class S2WasmBuilder { startFunction(startFunction), globalBase(globalBase), nextStatic(globalBase), - initialMemory(0) { + minInitialMemory(0), + userInitialMemory(userInitialMemory), + userMaxMemory(userMaxMemory) { + if (userMaxMemory && userMaxMemory < userInitialMemory) { + Fatal() << "Specified max memory " << userMaxMemory << + " is < specified initial memory " << userInitialMemory; + } + if (roundUpToPageSize(userMaxMemory) != userMaxMemory) { + Fatal() << "Specified max memory " << userMaxMemory << " is not a multiple of 64k"; + } + if (roundUpToPageSize(userInitialMemory) != userInitialMemory) { + Fatal() << "Specified initial memory " << userInitialMemory << " is not a multiple of 64k"; + } s = input; scan(); s = input; @@ -77,7 +90,10 @@ class S2WasmBuilder { size_t globalBase, // where globals can start to be statically allocated, i.e., the data segment nextStatic; // location of next static allocation std::map<Name, int32_t> staticAddresses; // name => address - size_t initialMemory; // Initial size (in bytes) of memory (after linking, this is rounded and set on the wasm object in pages) + size_t minInitialMemory; // Minimum initial size (in bytes) of memory. + size_t userInitialMemory; // Initial memory size (in bytes) specified by the user. + size_t userMaxMemory; // Max memory size (in bytes) specified by the user. + //(after linking, this is rounded and set on the wasm object in pages) struct Relocation { uint32_t* data; @@ -96,6 +112,23 @@ class S2WasmBuilder { // utilities + // For fatal errors which could arise from input (i.e. not assertion failures) + class Fatal { + public: + Fatal() { + std::cerr << "Fatal: "; + } + template<typename T> + Fatal &operator<<(T arg) { + std::cerr << std::forward<T>(arg); + return *this; + } + ~Fatal() { + std::cerr << "\n"; + exit(1); + } + }; + void skipWhitespace() { while (1) { while (*s && isspace(*s)) s++; @@ -399,7 +432,7 @@ class S2WasmBuilder { addressSegments[nextStatic] = wasm.memory.segments.size(); wasm.memory.segments.emplace_back( nextStatic, reinterpret_cast<char*>(raw), pointerSize); - initialMemory = nextStatic + pointerSize; + minInitialMemory = nextStatic + pointerSize; } nextStatic += pointerSize; } @@ -410,7 +443,7 @@ class S2WasmBuilder { nextStatic = (nextStatic + 15) & static_cast<size_t>(-16); staticAddresses[".stack"] = nextStatic; nextStatic += stackAllocation; - initialMemory = nextStatic; + minInitialMemory = nextStatic; } void process() { @@ -1155,7 +1188,7 @@ class S2WasmBuilder { wasm.memory.segments.emplace_back(nextStatic, (const char*)&(*raw)[0], size); } nextStatic += size; - initialMemory = nextStatic; + minInitialMemory = nextStatic; } void parseLcomm(Name name, size_t align=1) { @@ -1169,7 +1202,7 @@ class S2WasmBuilder { while (nextStatic % align) nextStatic++; staticAddresses[name] = nextStatic; nextStatic += size; - initialMemory = nextStatic; + minInitialMemory = nextStatic; } void skipImports() { @@ -1183,11 +1216,25 @@ class S2WasmBuilder { } } + static size_t roundUpToPageSize(size_t size) { + return (size + Memory::kPageSize - 1) & Memory::kPageMask; + } + void fix() { // Round the memory size up to a page, and update the page-increment versions // of initial and max - wasm.memory.initial = ((initialMemory + Memory::kPageSize - 1) & Memory::kPageMask) / - Memory::kPageSize; + size_t initialMem = roundUpToPageSize(minInitialMemory); + if (userInitialMemory) { + if (initialMem > userInitialMemory) { + Fatal() << "Specified initial memory size " << userInitialMemory << + " is smaller than required size " << initialMem; + } + wasm.memory.initial = userInitialMemory / Memory::kPageSize; + } else { + wasm.memory.initial = initialMem / Memory::kPageSize; + } + + if (userMaxMemory) wasm.memory.max = userMaxMemory / Memory::kPageSize; wasm.memory.exportName = MEMORY; // XXX For now, export all functions marked .globl. |